diff options
Diffstat (limited to 'linux/drivers')
34 files changed, 1774 insertions, 325 deletions
diff --git a/linux/drivers/media/dvb/cinergyT2/cinergyT2.c b/linux/drivers/media/dvb/cinergyT2/cinergyT2.c index 9c0eff865..0de98c3eb 100644 --- a/linux/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/linux/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -864,6 +864,11 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) set_bit(rc_keys[i + 2], input_dev->keybit); input_dev->keycodesize = 0; input_dev->keycodemax = 0; + input_dev->id.bustype = BUS_USB; + input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor; + input_dev->id.product = cinergyt2->udev->descriptor.idProduct; + input_dev->id.version = 1; + input_dev->cdev.dev = &cinergyt2->udev->dev; err = input_register_device(input_dev); if (err) { diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index ad5214360..861a02939 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -109,6 +109,17 @@ config DVB_USB_CXUSB Medion MD95700 hybrid USB2.0 device. DViCO FusionHDTV (Bluebird) USB2.0 devices +config DVB_USB_M920X + tristate "Uli m920x DVB-T USB2.0 support" + depends on DVB_USB + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + help + Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. + Currently, only devices with a product id of + "DTV USB MINI" (in cold state) are supported. + Firmware required. + config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB diff --git a/linux/drivers/media/dvb/dvb-usb/Makefile b/linux/drivers/media/dvb/dvb-usb/Makefile index 154d593bb..815e27898 100644 --- a/linux/drivers/media/dvb/dvb-usb/Makefile +++ b/linux/drivers/media/dvb/dvb-usb/Makefile @@ -30,6 +30,9 @@ obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2 dvb-usb-umt-010-objs = umt-010.o obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o +dvb-usb-m920x-objs = m920x.o +obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o + dvb-usb-digitv-objs = digitv.o obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 299382dcb..713ec5a82 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -29,6 +29,7 @@ #define USB_VID_LEADTEK 0x0413 #define USB_VID_LITEON 0x04ca #define USB_VID_MEDION 0x1660 +#define USB_VID_MSI 0x0db0 #define USB_VID_PINNACLE 0x2304 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 @@ -119,6 +120,7 @@ #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 #define USB_PID_MEDION_MD95700 0x0932 +#define USB_PID_MSI_MEGASKY580 0x5580 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f #define USB_PID_PCTV_200E 0x020e diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 1a86adbfa..1bee5dfad 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -125,6 +125,9 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) input_dev->keycodemax = KEY_MAX; input_dev->name = "IR-receiver inside an USB DVB receiver"; input_dev->phys = d->rc_phys; + input_dev->id.bustype = BUS_USB; + input_dev->id.vendor = d->udev->descriptor.idVendor; + input_dev->id.product = d->udev->descriptor.idProduct; usb_to_input_id(d->udev, &input_dev->id); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) input_dev->cdev.dev = &d->udev->dev; diff --git a/linux/drivers/media/dvb/dvb-usb/m920x.c b/linux/drivers/media/dvb/dvb-usb/m920x.c new file mode 100644 index 000000000..1a411316f --- /dev/null +++ b/linux/drivers/media/dvb/dvb-usb/m920x.c @@ -0,0 +1,551 @@ +/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver + * + * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ + +#include "m920x.h" + +#include "mt352.h" +#include "mt352_priv.h" +#include "qt1010.h" + +/* debug */ +static int dvb_usb_m920x_debug; +module_param_named(debug,dvb_usb_m920x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +static struct dvb_usb_rc_key megasky_rc_keys [] = { + { 0x0, 0x12, KEY_POWER }, + { 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */ + { 0x0, 0x02, KEY_CHANNELUP }, + { 0x0, 0x05, KEY_CHANNELDOWN }, + { 0x0, 0x03, KEY_VOLUMEUP }, + { 0x0, 0x06, KEY_VOLUMEDOWN }, + { 0x0, 0x04, KEY_MUTE }, + { 0x0, 0x07, KEY_OK }, /* TS */ + { 0x0, 0x08, KEY_STOP }, + { 0x0, 0x09, KEY_MENU }, /* swap */ + { 0x0, 0x0a, KEY_REWIND }, + { 0x0, 0x1b, KEY_PAUSE }, + { 0x0, 0x1f, KEY_FASTFORWARD }, + { 0x0, 0x0c, KEY_RECORD }, + { 0x0, 0x0d, KEY_CAMERA }, /* screenshot */ + { 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */ +}; + +static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\ + u16 index, void *data, int size) +{ + int ret; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + request, USB_TYPE_VENDOR | USB_DIR_IN, + value, index, data, size, 2000); + if (ret < 0) + return ret; + + if (ret != size) + return -EIO; + + return 0; +} + +static inline int m9206_write(struct usb_device *udev, u8 request, + u16 value, u16 index) +{ + int ret; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + request, USB_TYPE_VENDOR | USB_DIR_OUT, + value, index, NULL, 0, 2000); + return ret; +} + +static int m9206_rc_init(struct usb_device *udev) +{ + int ret = 0; + + /* Remote controller init. */ + if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0) + return ret; + + if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0) + return ret; + + return ret; +} + +static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct m9206_state *m = d->priv; + int i, ret = 0; + u8 rc_state[2]; + +#if 0 + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; +#endif + + if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0) + goto unlock; + + if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0) + goto unlock; + + for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++) + if (megasky_rc_keys[i].data == rc_state[1]) { + *event = megasky_rc_keys[i].event; + + switch(rc_state[0]) { + case 0x80: + *state = REMOTE_NO_KEY_PRESSED; + goto unlock; + + case 0x93: + case 0x92: + m->rep_count = 0; + *state = REMOTE_KEY_PRESSED; + goto unlock; + + case 0x91: + /* For comfort. */ + if (++m->rep_count > 2) + *state = REMOTE_KEY_REPEAT; + goto unlock; + + default: + deb_rc("Unexpected rc response %x\n", rc_state[0]); + *state = REMOTE_NO_KEY_PRESSED; + goto unlock; + } + } + + if (rc_state[1] != 0) + deb_rc("Unknown rc key %x\n", rc_state[1]); + + *state = REMOTE_NO_KEY_PRESSED; + + unlock: +#if 0 + mutex_unlock(&d->i2c_mutex); +#endif + + return ret; +} + +/* I2C */ +static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct m9206_state *m = d->priv; + int i; + int ret = 0; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + return -EINVAL; + + for (i = 0; i < num; i++) { + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0) + goto unlock; + + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0) + goto unlock; + + if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) { + int i2c_i; + + for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++) + if (msg[i].addr == m->i2c_r[i2c_i].addr) + break; + + if (i2c_i >= M9206_I2C_MAX) { + deb_rc("No magic for i2c addr!\n"); + ret = -EINVAL; + goto unlock; + } + + if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0) + goto unlock; + + if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0) + goto unlock; + + i++; + } else { + if (msg[i].len != 2) + return -EINVAL; + + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0) + goto unlock; + } + } + ret = i; + unlock: + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 m9206_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm m9206_i2c_algo = { + .master_xfer = m9206_i2c_xfer, + .functionality = m9206_i2c_func, +}; + + +static int m9206_set_filter(struct dvb_usb_adapter *adap, int type, int idx, + int pid) +{ + int ret = 0; + + if (pid >= 0x8000) + return -EINVAL; + + pid |= 0x8000; + + if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0) + return ret; + + if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0) + return ret; + + return ret; +} + +static int m9206_update_filters(struct dvb_usb_adapter *adap) +{ + struct m9206_state *m = adap->dev->priv; + int enabled = m->filtering_enabled; + int i, ret = 0, filter = 0; + + for (i = 0; i < M9206_MAX_FILTERS; i++) + if (m->filters[i] == 8192) + enabled = 0; + + /* Disable all filters */ + if ((ret = m9206_set_filter(adap, 0x81, 1, enabled)) != 0) + return ret; + + for (i = 0; i < M9206_MAX_FILTERS; i++) + if ((ret = m9206_set_filter(adap, 0x81, i + 2, 0)) != 0) + return ret; + + if ((ret = m9206_set_filter(adap, 0x82, 0, 0x0)) != 0) + return ret; + + /* Set */ + if (enabled) { + for (i = 0; i < M9206_MAX_FILTERS; i++) { + if (m->filters[i] == 0) + continue; + + if ((ret = m9206_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0) + return ret; + + filter++; + } + } + + if ((ret = m9206_set_filter(adap, 0x82, 0, 0x02f5)) != 0) + return ret; + + return ret; +} + +static int m9206_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct m9206_state *m = adap->dev->priv; + + m->filtering_enabled = onoff ? 1 : 0; + + return m9206_update_filters(adap); +} + +static int m9206_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + struct m9206_state *m = adap->dev->priv; + + m->filters[index] = onoff ? pid : 0; + + return m9206_update_filters(adap); +} + +static int m9206_firmware_download(struct usb_device *udev, + const struct firmware *fw) +{ + u16 value, index, size; + u8 read[4], *buff; + int i, pass, ret = 0; + + buff = kmalloc(65536, GFP_KERNEL); + + if ((ret = m9206_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) + goto done; + deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]); + + if ((ret = m9206_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0) + goto done; + deb_rc("%x\n", read[0]); + + for (pass = 0; pass < 2; pass++) { + for (i = 0; i + (sizeof(u16) * 3) < fw->size;) { + value = le16_to_cpu(*(u16 *)(fw->data + i)); + i += sizeof(u16); + + index = le16_to_cpu(*(u16 *)(fw->data + i)); + i += sizeof(u16); + + size = le16_to_cpu(*(u16 *)(fw->data + i)); + i += sizeof(u16); + + if (pass == 1) { + /* Will stall if using fw->data ... */ + memcpy(buff, fw->data + i, size); + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), + M9206_FW, + USB_TYPE_VENDOR | USB_DIR_OUT, + value, index, buff, size, 20); + if (ret != size) { + deb_rc("error while uploading fw!\n"); + ret = -EIO; + goto done; + } + msleep(3); + } + i += size; + } + if (i != fw->size) { + ret = -EINVAL; + goto done; + } + } + + msleep(36); + + /* m9206 will disconnect itself from the bus after this. */ + (void) m9206_write(udev, M9206_CORE, 0x01, M9206_FW_GO); + deb_rc("firmware uploaded!\n"); + + done: + kfree(buff); + + return ret; +} + +/* Callbacks for DVB USB */ +static int megasky_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + struct usb_host_interface *alt; + + alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1); + *cold = (alt == NULL) ? 1 : 0; + + return 0; +} + +static int megasky_mt352_demod_init(struct dvb_frontend *fe) +{ + u8 config[] = { CONFIG, 0x3d }; + u8 clock[] = { CLOCK_CTL, 0x30 }; + u8 reset[] = { RESET, 0x80 }; + u8 adc_ctl[] = { ADC_CTL_1, 0x40 }; + u8 agc[] = { AGC_TARGET, 0x1c, 0x20 }; + u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 }; + u8 unk1[] = { 0x93, 0x1a }; + u8 unk2[] = { 0xb5, 0x7a }; + + mt352_write(fe, config, ARRAY_SIZE(config)); + mt352_write(fe, clock, ARRAY_SIZE(clock)); + mt352_write(fe, reset, ARRAY_SIZE(reset)); + mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl)); + mt352_write(fe, agc, ARRAY_SIZE(agc)); + mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc)); + mt352_write(fe, unk1, ARRAY_SIZE(unk1)); + mt352_write(fe, unk2, ARRAY_SIZE(unk2)); + + deb_rc("Demod init!\n"); + + return 0; +} + +static struct mt352_config megasky_mt352_config = { + .demod_address = 0x1e, + .no_tuner = 1, + .demod_init = megasky_mt352_demod_init, +}; + +static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct m9206_state *m = adap->dev->priv; + + deb_rc("megasky_frontend_attach!\n"); + + m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address; + m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f; + + if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL) + return -EIO; + + return 0; +} + +static struct qt1010_config megasky_qt1010_config = { + .i2c_address = 0xc4 +}; + +static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct m9206_state *m = adap->dev->priv; + + m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address; + m->i2c_r[M9206_I2C_TUNER].magic = 0xc5; + + if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, + &megasky_qt1010_config) == NULL) + return -ENODEV; + + return 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties megasky_properties; + +static int m920x_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *d; + struct usb_host_interface *alt; + int ret; + + if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) { + deb_rc("probed!\n"); + + alt = usb_altnum_to_altsetting(intf, 1); + if (alt == NULL) { + deb_rc("not alt found!\n"); + return -ENODEV; + } + + ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (ret < 0) + return ret; + + deb_rc("Changed to alternate setting!\n"); + + if ((ret = m9206_rc_init(d->udev)) != 0) + return ret; + } + return ret; +} + +static struct usb_device_id m920x_table [] = { + { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, m920x_table); + +static struct dvb_usb_device_properties megasky_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-megasky-02.fw", + .download_firmware = m9206_firmware_download, + + .rc_interval = 100, + .rc_key_map = megasky_rc_keys, + .rc_key_map_size = ARRAY_SIZE(megasky_rc_keys), + .rc_query = m9206_rc_query, + + .size_of_priv = sizeof(struct m9206_state), + + .identify_state = megasky_identify_state, + .num_adapters = 1, + .adapter = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 8, + .pid_filter = m9206_pid_filter, + .pid_filter_ctrl = m9206_pid_filter_ctrl, + + .frontend_attach = megasky_mt352_frontend_attach, + .tuner_attach = megasky_qt1010_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + }}, + .i2c_algo = &m9206_i2c_algo, + + .num_device_descs = 1, + .devices = { + { "MSI Mega Sky 580 DVB-T USB2.0", + { &m920x_table[0], NULL }, + { NULL }, + }, + } +}; + +static struct usb_driver m920x_driver = { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) + .owner = THIS_MODULE, +#endif + .name = "dvb_usb_m920x", + .probe = m920x_probe, + .disconnect = dvb_usb_device_exit, + .id_table = m920x_table, +}; + +/* module stuff */ +static int __init m920x_module_init(void) +{ + int ret; + + if ((ret = usb_register(&m920x_driver))) { + err("usb_register failed. Error number %d", ret); + return ret; + } + + return 0; +} + +static void __exit m920x_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&m920x_driver); +} + +module_init (m920x_module_init); +module_exit (m920x_module_exit); + +MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>"); +MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / Uli m920x"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/dvb-usb/m920x.h b/linux/drivers/media/dvb/dvb-usb/m920x.h new file mode 100644 index 000000000..c354196ff --- /dev/null +++ b/linux/drivers/media/dvb/dvb-usb/m920x.h @@ -0,0 +1,35 @@ +#ifndef _DVB_USB_M920X_H_ +#define _DVB_USB_M920X_H_ + +#define DVB_USB_LOG_PREFIX "m920x" +#include "dvb-usb.h" + +#define deb_rc(args...) dprintk(dvb_usb_m920x_debug,0x01,args) + +#define M9206_CORE 0x22 +#define M9206_RC_STATE 0xff51 +#define M9206_RC_KEY 0xff52 +#define M9206_RC_INIT1 0xff54 +#define M9206_RC_INIT2 0xff55 +#define M9206_FW_GO 0xff69 + +#define M9206_I2C 0x23 +#define M9206_FILTER 0x25 +#define M9206_FW 0x30 + +#define M9206_MAX_FILTERS 8 + +#define M9206_I2C_TUNER 0 +#define M9206_I2C_DEMOD 1 +#define M9206_I2C_MAX 2 + +struct m9206_state { + u16 filters[M9206_MAX_FILTERS]; + int filtering_enabled; + int rep_count; + struct { + unsigned char addr; + unsigned char magic; + }i2c_r[M9206_I2C_MAX]; +}; +#endif diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig index af314bb1d..22c2cf2ce 100644 --- a/linux/drivers/media/dvb/frontends/Kconfig +++ b/linux/drivers/media/dvb/frontends/Kconfig @@ -290,6 +290,13 @@ config DVB_TDA826X help A DVB-S silicon tuner module. Say Y when you want to support this tuner. +config DVB_TUNER_QT1010 + tristate "Quantek QT1010 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner QT1010 from Quantek. + config DVB_TUNER_MT2060 tristate "Microtune MT2060 silicon IF tuner" depends on I2C diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index 3fa6e5d32..a646d9969 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -38,5 +38,6 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o diff --git a/linux/drivers/media/dvb/frontends/qt1010.c b/linux/drivers/media/dvb/frontends/qt1010.c new file mode 100644 index 000000000..60931f83f --- /dev/null +++ b/linux/drivers/media/dvb/frontends/qt1010.c @@ -0,0 +1,455 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> + * Aapo Tahkola <aet@rasterburn.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "qt1010.h" +#include "qt1010_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "QT1010: " args); printk("\n"); }} while (0) + +/* read single register */ +static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val) +{ + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "qt1010 I2C read failed\n"); + return -EREMOTEIO; + } + return 0; +} + +/* write single register */ +static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + struct i2c_msg msg = { + .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 + }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "qt1010 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +/* dump all registers */ +static void qt1010_dump_regs(struct qt1010_priv *priv) +{ + char buf[52], buf2[4]; + u8 reg, val; + + for (reg = 0; ; reg++) { + if (reg % 16 == 0) { + if (reg) + printk("%s\n", buf); + sprintf(buf, "%02x: ", reg); + } + if (qt1010_readreg(priv, reg, &val) == 0) + sprintf(buf2, "%02x ", val); + else + strcpy(buf2, "-- "); + strcat(buf, buf2); + if (reg == 0x2f) + break; + } + printk("%s\n", buf); +} + +static int qt1010_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct qt1010_priv *priv; + int err; + u32 freq, div, mod1, mod2; + u8 i, tmpval, reg05; + qt1010_i2c_oper_t rd[48] = { + { QT1010_WR, 0x01, 0x80 }, + { QT1010_WR, 0x02, 0x3f }, + { QT1010_WR, 0x05, 0xff }, /* 02 c write */ + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x07, 0xff }, /* 04 c write */ + { QT1010_WR, 0x08, 0x08 }, + { QT1010_WR, 0x09, 0xff }, /* 06 c write */ + { QT1010_WR, 0x0a, 0xff }, /* 07 c write */ + { QT1010_WR, 0x0b, 0xff }, /* 08 c write */ + { QT1010_WR, 0x0c, 0xe1 }, + { QT1010_WR, 0x1a, 0xff }, /* 10 c write */ + { QT1010_WR, 0x1b, 0x00 }, + { QT1010_WR, 0x1c, 0x89 }, + { QT1010_WR, 0x11, 0xff }, /* 13 c write */ + { QT1010_WR, 0x12, 0xff }, /* 14 c write */ + { QT1010_WR, 0x22, 0xff }, /* 15 c write */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xd0 }, + { QT1010_RD, 0x22, 0xff }, /* 16 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_RD, 0x05, 0xff }, /* 20 c read */ + { QT1010_RD, 0x22, 0xff }, /* 21 c read */ + { QT1010_WR, 0x23, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xe0 }, + { QT1010_RD, 0x23, 0xff }, /* 25 c read */ + { QT1010_RD, 0x23, 0xff }, /* 26 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x24, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xf0 }, + { QT1010_RD, 0x24, 0xff }, /* 31 c read */ + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x14, 0x7f }, + { QT1010_WR, 0x15, 0x7f }, + { QT1010_WR, 0x05, 0xff }, /* 35 c write */ + { QT1010_WR, 0x06, 0x00 }, + { QT1010_WR, 0x15, 0x1f }, + { QT1010_WR, 0x16, 0xff }, + { QT1010_WR, 0x18, 0xff }, + { QT1010_WR, 0x1f, 0xff }, /* 40 c write */ + { QT1010_WR, 0x20, 0xff }, /* 41 c write */ + { QT1010_WR, 0x21, 0x53 }, + { QT1010_WR, 0x25, 0xff }, /* 43 c write */ + { QT1010_WR, 0x26, 0x15 }, + { QT1010_WR, 0x00, 0xff }, /* 45 c write */ + { QT1010_WR, 0x02, 0x00 }, + { QT1010_WR, 0x01, 0x00 } + }; + +#define FREQ1 32000000 /* 32 MHz */ +#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ + + priv = fe->tuner_priv; + freq = params->frequency; + div = (freq + QT1010_OFFSET) / QT1010_STEP; + freq = (div * QT1010_STEP) - QT1010_OFFSET; + mod1 = (freq + QT1010_OFFSET) % FREQ1; + mod2 = (freq + QT1010_OFFSET) % FREQ2; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = freq; + + /* reg 05 base value */ + if (freq < 290000000) reg05 = 0x14; /* 290 MHz */ + else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */ + else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */ + else reg05 = 0x74; + + /* 0x5 */ + rd[2].val = reg05; + + /* 07 - set frequency: 32 MHz scale */ + rd[4].val = (freq + QT1010_OFFSET) / FREQ1; + + /* 09 - changes every 8/24 MHz */ + if (mod1 < 8000000) rd[6].val = 0x1d; + else rd[6].val = 0x1c; + + /* 0a - set frequency: 4 MHz scale (max 28 MHz) */ + if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */ + else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */ + else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */ + else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */ + else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */ + else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */ + else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */ + else rd[7].val = 0x0a; /* +28 MHz */ + + /* 0b - changes every 2/2 MHz */ + if (mod2 < 2000000) rd[8].val = 0x45; + else rd[8].val = 0x44; + + /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/ + tmpval = 0x78; /* byte, overflows intentionally */ + rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08); + + /* 11 */ + rd[13].val = 0xfd; /* TODO: correct value calculation */ + + /* 12 */ + rd[14].val = 0x91; /* TODO: correct value calculation */ + + /* 22 */ + if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */ + else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */ + else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */ + else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */ + else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */ + else rd[15].val = 0xd0; + + /* 05 */ + rd[35].val = (reg05 & 0xf0); + + /* 1f */ + if (mod1 < 8000000) tmpval = 0x00; + else if (mod1 < 12000000) tmpval = 0x01; + else if (mod1 < 16000000) tmpval = 0x02; + else if (mod1 < 24000000) tmpval = 0x03; + else if (mod1 < 28000000) tmpval = 0x04; + else tmpval = 0x05; + rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval); + + /* 20 */ + if (mod1 < 8000000) tmpval = 0x00; + else if (mod1 < 12000000) tmpval = 0x01; + else if (mod1 < 20000000) tmpval = 0x02; + else if (mod1 < 24000000) tmpval = 0x03; + else if (mod1 < 28000000) tmpval = 0x04; + else tmpval = 0x05; + rd[41].val = (priv->reg20_init_val + 0x0d + tmpval); + + /* 25 */ + rd[43].val = priv->reg25_init_val; + + /* 00 */ + rd[45].val = 0x92; /* TODO: correct value calculation */ + + dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x 1a:%02x 11:%02x " \ + "12:%02x 22:%02x 05:%02x 1f:%02x 20:%02x 25:%02x 00:%02x", \ + freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \ + rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \ + rd[40].val, rd[41].val, rd[43].val, rd[45].val); + + for (i = 0; i < sizeof(rd) / sizeof(*rd); i++) { + if (rd[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, rd[i].reg, rd[i].val); + } else { /* read is required to proper locking */ + err = qt1010_readreg(priv, rd[i].reg, &tmpval); + } + if (err) return err; + } + + if (debug) + qt1010_dump_regs(priv); + + return 0; +} + +static int qt1010_init_meas1(struct qt1010_priv *priv, u8 oper, u8 reg, u8 reg_init_val, u8 *retval) +{ + u8 i, val1, val2; + int err; + + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, reg, reg_init_val }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, oper }, + { QT1010_RD, reg, 0xff } + }; + + for (i = 0; i < sizeof(i2c_data) / sizeof(*i2c_data); i++) { + if (i2c_data[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, i2c_data[i].reg, i2c_data[i].val); + } else { + err = qt1010_readreg(priv, i2c_data[i].reg, &val2); + } + if (err) return err; + } + + do { + val1 = val2; + err = qt1010_readreg(priv, reg, &val2); + if (err) return err; + dprintk("compare reg:%02x %02x %02x", reg, val1, val2); + } while (val1 != val2); + *retval = val1; + + return qt1010_writereg(priv, 0x1e, 0x00); +} + + +static u8 qt1010_init_meas2(struct qt1010_priv *priv, u8 reg_init_val, u8 *retval) +{ + u8 i, val; + int err; + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, 0x07, reg_init_val }, + { QT1010_WR, 0x22, 0xd0 }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x1e, 0xd0 }, + { QT1010_RD, 0x22, 0xff }, + { QT1010_WR, 0x1e, 0x00 }, + { QT1010_WR, 0x22, 0xff } + }; + for (i = 0; i < sizeof(i2c_data) / sizeof(*i2c_data); i++) { + if (i2c_data[i].oper == QT1010_WR) { + err = qt1010_writereg(priv, i2c_data[i].reg, i2c_data[i].val); + } else { + err = qt1010_readreg(priv, i2c_data[i].reg, &val); + } + if (err) return err; + } + *retval = val; + return 0; +} + +static int qt1010_init(struct dvb_frontend *fe) +{ + struct qt1010_priv *priv = fe->tuner_priv; + struct dvb_frontend_parameters params; + int err; + u8 i, tmpval, *valptr = NULL; + + qt1010_i2c_oper_t i2c_data[] = { + { QT1010_WR, 0x01, 0x80 }, + { QT1010_WR, 0x0d, 0x84 }, + { QT1010_WR, 0x0e, 0xb7 }, + { QT1010_WR, 0x2a, 0x23 }, + { QT1010_WR, 0x2c, 0xdc }, + { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */ + { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */ + { QT1010_WR, 0x2b, 0x70 }, + { QT1010_WR, 0x2a, 0x23 }, + { QT1010_M1, 0x26, 0x08 }, + { QT1010_M1, 0x82, 0xff }, + { QT1010_WR, 0x05, 0x14 }, + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x07, 0x28 }, + { QT1010_WR, 0x08, 0x0b }, + { QT1010_WR, 0x11, 0xfd }, + { QT1010_M1, 0x22, 0x0d }, + { QT1010_M1, 0xd0, 0xff }, + { QT1010_WR, 0x06, 0x40 }, + { QT1010_WR, 0x16, 0xf0 }, + { QT1010_WR, 0x02, 0x38 }, + { QT1010_WR, 0x03, 0x18 }, + { QT1010_WR, 0x20, 0xe0 }, + { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */ + { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */ + { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */ + { QT1010_WR, 0x03, 0x19 }, + { QT1010_WR, 0x02, 0x3f }, + { QT1010_WR, 0x21, 0x53 }, + { QT1010_RD, 0x21, 0xff }, + { QT1010_WR, 0x11, 0xfd }, + { QT1010_WR, 0x05, 0x34 }, + { QT1010_WR, 0x06, 0x44 }, + { QT1010_WR, 0x08, 0x08 } + }; + + for (i = 0; i < sizeof(i2c_data) / sizeof(*i2c_data); i++) { + switch (i2c_data[i].oper) { + case QT1010_WR: + err = qt1010_writereg(priv, i2c_data[i].reg, i2c_data[i].val); + break; + case QT1010_RD: + if (i2c_data[i].val == 0x20) valptr = &priv->reg20_init_val; + else valptr = &tmpval; + err = qt1010_readreg(priv, i2c_data[i].reg, valptr); + break; + case QT1010_M1: + if (i2c_data[i].val == 0x25) valptr = &priv->reg25_init_val; + else if (i2c_data[i].val == 0x1f) valptr = &priv->reg1f_init_val; + else valptr = &tmpval; + err = qt1010_init_meas1(priv, i2c_data[i+1].reg, i2c_data[i].reg, + i2c_data[i].val, valptr); + i++; + break; + } + if (err) return err; + } + + for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */ + if ((err = qt1010_init_meas2(priv, i, &tmpval))) + return err; + + params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */ + /* MSI Megasky 580 GL861 533000000 */ + return qt1010_set_params(fe, ¶ms); +} + +static int qt1010_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct qt1010_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct qt1010_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static const struct dvb_tuner_ops qt1010_tuner_ops = { + .info = { + .name = "Quantek QT1010", + .frequency_min = QT1010_MIN_FREQ, + .frequency_max = QT1010_MAX_FREQ, + .frequency_step = QT1010_STEP, + }, + + .release = qt1010_release, + .init = qt1010_init, + /* TODO: implement sleep */ + + .set_params = qt1010_set_params, + .get_frequency = qt1010_get_frequency, + .get_bandwidth = qt1010_get_bandwidth +}; + +struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg) +{ + struct qt1010_priv *priv = NULL; + u8 id; + + priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->i2c = i2c; + +#if 0 + qt1010_dump_regs(priv); +#endif + + /* Try to detect tuner chip. Probably this is not correct register. */ + if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) { + kfree(priv); + return NULL; + } + + printk(KERN_INFO "Quantek QT1010 successfully identified.\n"); + memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops, sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + return fe; +} +EXPORT_SYMBOL(qt1010_attach); + +MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/qt1010.h b/linux/drivers/media/dvb/frontends/qt1010.h new file mode 100644 index 000000000..3ab4aa045 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/qt1010.h @@ -0,0 +1,53 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> + * Aapo Tahkola <aet@rasterburn.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef QT1010_H +#define QT1010_H + +#include "dvb_frontend.h" + +struct qt1010_config { + u8 i2c_address; +}; + +/** + * Attach a qt1010 tuner to the supplied frontend structure. + * + * @param fe frontend to attach to + * @param i2c i2c adapter to use + * @param cfg tuner hw based configuration + * @return fe pointer on success, NULL on failure + */ +#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE)) +extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg); +#else +static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct qt1010_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_QT1010 + +#endif diff --git a/linux/drivers/media/dvb/frontends/qt1010_priv.h b/linux/drivers/media/dvb/frontends/qt1010_priv.h new file mode 100644 index 000000000..090cf475f --- /dev/null +++ b/linux/drivers/media/dvb/frontends/qt1010_priv.h @@ -0,0 +1,105 @@ +/* + * Driver for Quantek QT1010 silicon tuner + * + * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> + * Aapo Tahkola <aet@rasterburn.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef QT1010_PRIV_H +#define QT1010_PRIV_H + +/* +reg def meaning +=== === ======= +00 00 ? +01 a0 ? operation start/stop; start=80, stop=00 +02 00 ? +03 19 ? +04 00 ? +05 00 ? maybe band selection +06 00 ? +07 2b set frequency: 32 MHz scale, n*32 MHz +08 0b ? +09 10 ? changes every 8/24 MHz; values 1d/1c +0a 08 set frequency: 4 MHz scale, n*4 MHz +0b 41 ? changes every 2/2 MHz; values 45/45 +0c e1 ? +0d 94 ? +0e b6 ? +0f 2c ? +10 10 ? +11 f1 ? maybe device specified adjustment +12 11 ? maybe device specified adjustment +13 3f ? +14 1f ? +15 3f ? +16 ff ? +17 ff ? +18 f7 ? +19 80 ? +1a d0 set frequency: 125 kHz scale, n*125 kHz +1b 00 ? +1c 89 ? +1d 00 ? +1e 00 ? looks like operation register; write cmd here, read result from 1f-26 +1f 20 ? chip initialization +20 e0 ? chip initialization +21 20 ? +22 d0 ? +23 d0 ? +24 d0 ? +25 40 ? chip initialization +26 08 ? +27 29 ? +28 55 ? +29 39 ? +2a 13 ? +2b 01 ? +2c ea ? +2d 00 ? +2e 00 ? not used? +2f 00 ? not used? +*/ + +#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers, + hw could be more precise but we don't + know how to use */ +#define QT1010_MIN_FREQ 48000000 /* 48 MHz */ +#define QT1010_MAX_FREQ 860000000 /* 860 MHz */ +#define QT1010_OFFSET 1246000000 /* 1246 MHz */ + +#define QT1010_WR 0 +#define QT1010_RD 1 +#define QT1010_M1 3 + +typedef struct { + u8 oper, reg, val; +} qt1010_i2c_oper_t; + +struct qt1010_priv { + struct qt1010_config *cfg; + struct i2c_adapter *i2c; + + u8 reg1f_init_val; + u8 reg20_init_val; + u8 reg25_init_val; + + u32 frequency; + u32 bandwidth; +}; + +#endif diff --git a/linux/drivers/media/dvb/ttpci/av7110.h b/linux/drivers/media/dvb/ttpci/av7110.h index c1fe289d3..5fcdaa402 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.h +++ b/linux/drivers/media/dvb/ttpci/av7110.h @@ -39,7 +39,6 @@ #define ANALOG_TUNER_VES1820 1 #define ANALOG_TUNER_STV0297 2 -#define ANALOG_TUNER_VBI 0x100 extern int av7110_debug; diff --git a/linux/drivers/media/dvb/ttpci/av7110_ir.c b/linux/drivers/media/dvb/ttpci/av7110_ir.c index e4544ea2b..344ec1243 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_ir.c +++ b/linux/drivers/media/dvb/ttpci/av7110_ir.c @@ -16,6 +16,7 @@ static int av_cnt; static struct av7110 *av_list[4]; static struct input_dev *input_dev; +static char input_phys[32]; static u8 delay_timer_finished; @@ -231,8 +232,28 @@ int __devinit av7110_ir_init(struct av7110 *av7110) if (!input_dev) return -ENOMEM; + snprintf(input_phys, sizeof(input_phys), + "pci-%s/ir0", pci_name(av7110->dev->pci)); + input_dev->name = "DVB on-card IR receiver"; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + input_dev->phys = input_phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; + if (av7110->dev->pci->subsystem_vendor) { + input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; + input_dev->id.product = av7110->dev->pci->subsystem_device; + } else { + input_dev->id.vendor = av7110->dev->pci->vendor; + input_dev->id.product = av7110->dev->pci->device; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) + input_dev->cdev.dev = &av7110->dev->pci->dev; +#else + input_dev->dev = &av7110->dev->pci->dev; +#endif +#endif set_bit(EV_KEY, input_dev->evbit); set_bit(EV_REP, input_dev->evbit); input_register_keys(); diff --git a/linux/drivers/media/dvb/ttpci/av7110_v4l.c b/linux/drivers/media/dvb/ttpci/av7110_v4l.c index 10cfe3131..3c6f5fcdc 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/linux/drivers/media/dvb/ttpci/av7110_v4l.c @@ -818,20 +818,15 @@ int av7110_init_v4l(struct av7110 *av7110) saa7146_vv_release(dev); return -ENODEV; } - if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) { + if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) ERR(("cannot register vbi v4l2 device. skipping.\n")); - } else { - if (av7110->analog_tuner_flags) - av7110->analog_tuner_flags |= ANALOG_TUNER_VBI; - } return 0; } int av7110_exit_v4l(struct av7110 *av7110) { saa7146_unregister_device(&av7110->v4l_dev, av7110->dev); - if (av7110->analog_tuner_flags & ANALOG_TUNER_VBI) - saa7146_unregister_device(&av7110->vbi_dev, av7110->dev); + saa7146_unregister_device(&av7110->vbi_dev, av7110->dev); return 0; } diff --git a/linux/drivers/media/radio/radio-aztech.c b/linux/drivers/media/radio/radio-aztech.c index a59a6d209..e622f3c91 100644 --- a/linux/drivers/media/radio/radio-aztech.c +++ b/linux/drivers/media/radio/radio-aztech.c @@ -185,136 +185,163 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency) return 0; } -static int az_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int vidioc_querycap (struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-aztech", sizeof (v->driver)); + strlcpy(v->card, "Aztech Radio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_g_tuner (struct file *file, void *priv, + struct v4l2_tuner *v) { struct video_device *dev = video_devdata(file); struct az_device *az = dev->priv; - switch(cmd) - { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *v = arg; - memset(v,0,sizeof(*v)); - strlcpy(v->driver, "radio-aztech", sizeof (v->driver)); - strlcpy(v->card, "Aztech Radio", sizeof (v->card)); - sprintf(v->bus_info,"ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + if (v->index > 0) + return -EINVAL; - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *v = arg; - - if (v->index > 0) - return -EINVAL; - - memset(v,0,sizeof(*v)); - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; - - v->rangelow=(87*16000); - v->rangehigh=(108*16000); - v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability=V4L2_TUNER_CAP_LOW; - if(az_getstereo(az)) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal=0xFFFF*az_getsigstr(az); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *v = arg; + v->rangelow=(87*16000); + v->rangehigh=(108*16000); + v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->capability=V4L2_TUNER_CAP_LOW; + if(az_getstereo(az)) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=0xFFFF*az_getsigstr(az); - if (v->index > 0) - return -EINVAL; + return 0; +} - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - az->curfreq = f->frequency; - az_setfreq(az, az->curfreq); - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; +static int vidioc_s_tuner (struct file *file, void *priv, + struct v4l2_tuner *v) +{ + if (v->index > 0) + return -EINVAL; - f->type = V4L2_TUNER_RADIO; - f->frequency = az->curfreq; + return 0; +} - return 0; - } +static int vidioc_g_audio (struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index > 1) + return -EINVAL; - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return (0); - } - } - return -EINVAL; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl= arg; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (az->curvol==0) - ctrl->value=1; - else - ctrl->value=0; - return (0); - case V4L2_CID_AUDIO_VOLUME: - ctrl->value=az->curvol * 6554; - return (0); - } - return -EINVAL; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl= arg; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) { - az_setvol(az,0); - } else { - az_setvol(az,az->curvol); - } - return (0); - case V4L2_CID_AUDIO_VOLUME: - az_setvol(az,ctrl->value); - return (0); - } - return -EINVAL; + strcpy(a->name, "Radio"); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + return 0; +} + + +static int vidioc_s_audio (struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index != 0) + return -EINVAL; + + return 0; +} + +static int vidioc_s_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct video_device *dev = video_devdata(file); + struct az_device *az = dev->priv; + + az->curfreq = f->frequency; + az_setfreq(az, az->curfreq); + return 0; +} + +static int vidioc_g_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct video_device *dev = video_devdata(file); + struct az_device *az = dev->priv; + + f->type = V4L2_TUNER_RADIO; + f->frequency = az->curfreq; + + return 0; +} + +static int vidioc_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), + sizeof(*qc)); + return (0); } + } + return -EINVAL; +} + +static int vidioc_g_ctrl (struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct video_device *dev = video_devdata(file); + struct az_device *az = dev->priv; - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - az_do_ioctl); + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (az->curvol==0) + ctrl->value=1; + else + ctrl->value=0; + return (0); + case V4L2_CID_AUDIO_VOLUME: + ctrl->value=az->curvol * 6554; + return (0); } + return -EINVAL; } -static int az_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int vidioc_s_ctrl (struct file *file, void *priv, + struct v4l2_control *ctrl) { - return video_usercopy(inode, file, cmd, arg, az_do_ioctl); + struct video_device *dev = video_devdata(file); + struct az_device *az = dev->priv; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) { + az_setvol(az,0); + } else { + az_setvol(az,az->curvol); + } + return (0); + case V4L2_CID_AUDIO_VOLUME: + az_setvol(az,ctrl->value); + return (0); + } + return -EINVAL; } static struct az_device aztech_unit; @@ -323,20 +350,35 @@ static struct file_operations aztech_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = az_ioctl, + .ioctl = video_ioctl2, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; static struct video_device aztech_radio= { - .owner = THIS_MODULE, - .name = "Aztech radio", - .type = VID_TYPE_TUNER, - .hardware = 0, - .fops = &aztech_fops, + .owner = THIS_MODULE, + .name = "Aztech radio", + .type = VID_TYPE_TUNER, + .hardware = 0, + .fops = &aztech_fops, + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, }; +module_param_named(debug,aztech_radio.debug, int, 0644); +MODULE_PARM_DESC(debug,"activates debug info"); + static int __init aztech_init(void) { if(io==-1) diff --git a/linux/drivers/media/radio/radio-maxiradio.c b/linux/drivers/media/radio/radio-maxiradio.c index 151f14232..05d6aaef2 100644 --- a/linux/drivers/media/radio/radio-maxiradio.c +++ b/linux/drivers/media/radio/radio-maxiradio.c @@ -27,7 +27,9 @@ * BUGS: * - card unmutes if you change frequency * - * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> + * (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@infradead.org>: + * - Conversion to V4L2 API + * - Uses video_ioctl2 for parsing and to add debug support */ @@ -47,10 +49,18 @@ #include <linux/videodev2.h> #include <media/v4l2-common.h> -#define DRIVER_VERSION "0.76" +#define DRIVER_VERSION "0.77" #include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,7,6) +#define RADIO_VERSION KERNEL_VERSION(0,7,7) + +static struct video_device maxiradio_radio; + +#define dprintk(num, fmt, arg...) \ + do { \ + if (maxiradio_radio.debug >= num) \ + printk(KERN_DEBUG "%s: " fmt, \ + maxiradio_radio.name, ## arg); } while (0) static struct v4l2_queryctrl radio_qctrl[] = { { @@ -85,30 +95,21 @@ module_param(radio_nr, int, 0); #define FREQ_IF 171200 /* 10.7*16000 */ #define FREQ_STEP 200 /* 12.5*16 */ -#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\ - /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */ +/* (x==fmhz*16*1000) -> bits */ +#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \ + /(FREQ_STEP<<2))<<2) #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) -static int radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); - static struct file_operations maxiradio_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, - .ioctl = radio_ioctl, + .ioctl = video_ioctl2, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; -static struct video_device maxiradio_radio = -{ - .owner = THIS_MODULE, - .name = "Maxi Radio FM2000 radio", - .type = VID_TYPE_TUNER, - .fops = &maxiradio_fops, -}; static struct radio_device { @@ -124,12 +125,14 @@ static struct radio_device #else struct semaphore lock; #endif -} radio_unit = {0, 0, 0, 0, }; - +} radio_unit = { + .muted =1, + .freq = FREQ_LO, +}; static void outbit(unsigned long bit, __u16 io) { - if(bit != 0) + if (bit != 0) { outb( power|wren|data ,io); udelay(4); outb( power|wren|data|clk ,io); udelay(4); @@ -145,14 +148,20 @@ static void outbit(unsigned long bit, __u16 io) static void turn_power(__u16 io, int p) { - if(p != 0) outb(power, io); else outb(0,io); + if (p != 0) { + dprintk(1, "Radio powered on\n"); + outb(power, io); + } else { + dprintk(1, "Radio powered off\n"); + outb(0,io); + } } - -static void set_freq(__u16 io, __u32 data) +static void set_freq(__u16 io, __u32 freq) { unsigned long int si; int bl; + int data = FREQ2BITS(freq); /* TEA5757 shift register bits (see pdf) */ @@ -171,173 +180,225 @@ static void set_freq(__u16 io, __u32 data) outbit(0,io); // 16 search level si = 0x8000; - for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; } + for (bl = 1; bl <= 16 ; bl++) { + outbit(data & si,io); + si >>=1; + } - outb(power,io); + dprintk(1, "Radio freq set to %d.%02d MHz\n", + freq / 16000, + freq % 16000 * 100 / 16000); + + turn_power(io, 1); } static int get_stereo(__u16 io) { - outb(power,io); udelay(4); + outb(power,io); + udelay(4); + return !(inb(io) & mo_st); } static int get_tune(__u16 io) { - outb(power+clk,io); udelay(4); + outb(power+clk,io); + udelay(4); + return !(inb(io) & mo_st); } -static inline int radio_function(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int vidioc_querycap (struct file *file, void *priv, + struct v4l2_capability *v) +{ + strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver)); + strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card)); + sprintf(v->bus_info,"ISA"); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER; + + return 0; +} + +static int vidioc_g_tuner (struct file *file, void *priv, + struct v4l2_tuner *v) { struct video_device *dev = video_devdata(file); struct radio_device *card=dev->priv; - switch(cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *v = arg; - memset(v,0,sizeof(*v)); - strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver)); - strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card)); - sprintf(v->bus_info,"ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + if (v->index > 0) + return -EINVAL; - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *v = arg; + memset(v,0,sizeof(*v)); + strcpy(v->name, "FM"); + v->type = V4L2_TUNER_RADIO; - if (v->index > 0) - return -EINVAL; + v->rangelow=FREQ_LO; + v->rangehigh=FREQ_HI; + v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->capability=V4L2_TUNER_CAP_LOW; + if(get_stereo(card->io)) + v->audmode = V4L2_TUNER_MODE_STEREO; + else + v->audmode = V4L2_TUNER_MODE_MONO; + v->signal=0xffff*get_tune(card->io); - memset(v,0,sizeof(*v)); - strcpy(v->name, "FM"); - v->type = V4L2_TUNER_RADIO; + return 0; +} - v->rangelow=FREQ_LO; - v->rangehigh=FREQ_HI; - v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability=V4L2_TUNER_CAP_LOW; - if(get_stereo(card->io)) - v->audmode = V4L2_TUNER_MODE_STEREO; - else - v->audmode = V4L2_TUNER_MODE_MONO; - v->signal=0xffff*get_tune(card->io); +static int vidioc_s_tuner (struct file *file, void *priv, + struct v4l2_tuner *v) +{ + if (v->index > 0) + return -EINVAL; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *v = arg; + return 0; +} - if (v->index > 0) - return -EINVAL; +static int vidioc_g_audio (struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index > 1) + return -EINVAL; - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; + strcpy(a->name, "FM"); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} - if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) - return -EINVAL; +static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; - card->freq = f->frequency; - set_freq(card->io, FREQ2BITS(card->freq)); - msleep(125); - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + return 0; +} - f->type = V4L2_TUNER_RADIO; - f->frequency = card->freq; +static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; - return 0; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return (0); - } - } - return -EINVAL; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl= arg; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value=card->muted; - return (0); - } - return -EINVAL; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl= arg; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - card->muted = ctrl->value; - if(card->muted) - turn_power(card->io, 0); - else - set_freq(card->io, FREQ2BITS(card->freq)); - return 0; - } - return -EINVAL; - } + return 0; +} - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - radio_function); -#if 0 /* Probably, this is useless */ - case VIDIOCGUNIT: { - struct video_unit *v = arg; +static int vidioc_s_audio (struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (a->index != 0) + return -EINVAL; - v->video=VIDEO_NO_UNIT; - v->vbi=VIDEO_NO_UNIT; - v->radio=dev->minor; - v->audio=0; - v->teletext=VIDEO_NO_UNIT; - return 0; + return 0; +} + +static int vidioc_s_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct video_device *dev = video_devdata(file); + struct radio_device *card=dev->priv; + + if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { + dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", + f->frequency / 16000, + f->frequency % 16000 * 100 / 16000, + FREQ_LO / 16000, FREQ_HI / 16000); + + return -EINVAL; + } + + card->freq = f->frequency; + set_freq(card->io, card->freq); + msleep(125); + + return 0; +} + +static int vidioc_g_frequency (struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct video_device *dev = video_devdata(file); + struct radio_device *card=dev->priv; + + f->type = V4L2_TUNER_RADIO; + f->frequency = card->freq; + + dprintk(4, "radio freq is %d.%02d MHz", + f->frequency / 16000, + f->frequency % 16000 * 100 / 16000); + + return 0; +} + +static int vidioc_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { + if (qc->id && qc->id == radio_qctrl[i].id) { + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); + return (0); } -#endif } + + return -EINVAL; } -static int radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int vidioc_g_ctrl (struct file *file, void *priv, + struct v4l2_control *ctrl) { struct video_device *dev = video_devdata(file); struct radio_device *card=dev->priv; - int ret; - mutex_lock(&card->lock); - ret = video_usercopy(inode, file, cmd, arg, radio_function); - mutex_unlock(&card->lock); - return ret; + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=card->muted; + return (0); + } + + return -EINVAL; } -MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); -MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); -MODULE_LICENSE("GPL"); +static int vidioc_s_ctrl (struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct video_device *dev = video_devdata(file); + struct radio_device *card=dev->priv; + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + card->muted = ctrl->value; + if(card->muted) + turn_power(card->io, 0); + else + set_freq(card->io, card->freq); + return 0; + } + + return -EINVAL; +} + +static struct video_device maxiradio_radio = +{ + .owner = THIS_MODULE, + .name = "Maxi Radio FM2000 radio", + .type = VID_TYPE_TUNER, + .fops = &maxiradio_fops, + + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -354,7 +415,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d mutex_init(&radio_unit.lock); maxiradio_radio.priv = &radio_unit; - if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) { + if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) { printk("radio-maxiradio: can't register device!"); goto err_out_free_region; } @@ -409,3 +470,10 @@ static void __exit maxiradio_radio_exit(void) module_init(maxiradio_radio_init); module_exit(maxiradio_radio_exit); + +MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); +MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); +MODULE_LICENSE("GPL"); + +module_param_named(debug,maxiradio_radio.debug, int, 0644); +MODULE_PARM_DESC(debug,"activates debug info"); diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index 118c6e800..4c813a4da 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -1905,7 +1905,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv_fh *fh = q->priv_data; - bttv_dma_free(&fh->cap,fh->btv,buf); + bttv_dma_free(q,fh->btv,buf); } static struct videobuf_queue_ops bttv_video_qops = { diff --git a/linux/drivers/media/video/bt8xx/bttv-vbi.c b/linux/drivers/media/video/bt8xx/bttv-vbi.c index cac2273f7..689d79404 100644 --- a/linux/drivers/media/video/bt8xx/bttv-vbi.c +++ b/linux/drivers/media/video/bt8xx/bttv-vbi.c @@ -225,7 +225,7 @@ static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); dprintk("free %p\n",vb); - bttv_dma_free(&fh->cap,fh->btv,buf); + bttv_dma_free(q,fh->btv,buf); } struct videobuf_queue_ops bttv_vbi_qops = { diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c index bd6a3d8fb..9aaaa482d 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.c +++ b/linux/drivers/media/video/cx25840/cx25840-core.c @@ -639,7 +639,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, #ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct access to the * cx25840 registers for testing */ - case VIDIOC_INT_G_REGISTER: + case VIDIOC_DBG_G_REGISTER: { struct v4l2_register *reg = arg; @@ -649,7 +649,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, break; } - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *reg = arg; diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c index 8a33b7e16..ee3ef610e 100644 --- a/linux/drivers/media/video/cx88/cx88-video.c +++ b/linux/drivers/media/video/cx88/cx88-video.c @@ -1666,10 +1666,12 @@ static int vidioc_s_frequency (struct file *file, void *priv, cx88_set_freq (core,f); } -#if 0 //ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register (struct file *file, void *priv, - v4l2_register *reg) +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register (struct file *file, void *fh, + struct v4l2_register *reg) { + struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; + if (reg->i2c_id != 0) return -EINVAL; /* cx2388x has a 24-bit register space */ @@ -1678,13 +1680,12 @@ static int vidioc_g_register (struct file *file, void *priv, } static int vidioc_s_register (struct file *file, void *fh, - v4l2_register *reg) + struct v4l2_register *reg) { + struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; if (reg->i2c_id != 0) return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; cx_write(reg->reg&0xffffff, reg->val); return 0; } @@ -1966,8 +1967,12 @@ static struct video_device cx8800_video_template = .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, }; static struct file_operations radio_fops = diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 589c094f1..87384848b 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3392,7 +3392,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) int pvr2_hdw_register_access(struct pvr2_hdw *hdw, - u32 chip_id,unsigned long reg_id, + u32 chip_id, u32 reg_id, int setFl,u32 *val_ptr) { #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -3410,8 +3410,8 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, cp = list_entry(item,struct pvr2_i2c_client,list); if (cp->client->driver->id != chip_id) continue; stat = pvr2_i2c_client_cmd( - cp,(setFl ? VIDIOC_INT_S_REGISTER : - VIDIOC_INT_G_REGISTER),&req); + cp,(setFl ? VIDIOC_DBG_S_REGISTER : + VIDIOC_DBG_G_REGISTER),&req); if (!setFl) *val_ptr = req.val; okFl = !0; break; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h index ab99bea88..9785ffcce 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -231,7 +231,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *, setFl - true to set the register, false to read it val_ptr - storage location for source / result. */ int pvr2_hdw_register_access(struct pvr2_hdw *, - u32 chip_id,unsigned long reg_id, + u32 chip_id,u32 reg_id, int setFl,u32 *val_ptr); /* The following entry points are all lower level things you normally don't diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index ac7ead462..9bc03cfda 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -738,16 +738,20 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, break; } #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_INT_G_REGISTER: - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_S_REGISTER: + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + break; + } /* fall through */ + case VIDIOC_DBG_G_REGISTER: { u32 val; struct v4l2_register *req = (struct v4l2_register *)arg; - if (cmd == VIDIOC_INT_S_REGISTER) val = req->val; + if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val; ret = pvr2_hdw_register_access( hdw,req->i2c_id,req->reg, - cmd == VIDIOC_INT_S_REGISTER,&val); - if (cmd == VIDIOC_INT_G_REGISTER) req->val = val; + cmd == VIDIOC_DBG_S_REGISTER,&val); + if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val; break; } #endif diff --git a/linux/drivers/media/video/saa7115.c b/linux/drivers/media/video/saa7115.c index 462c5dd7f..cc8ea90fd 100644 --- a/linux/drivers/media/video/saa7115.c +++ b/linux/drivers/media/video/saa7115.c @@ -1428,7 +1428,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar } #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_INT_G_REGISTER: + case VIDIOC_DBG_G_REGISTER: { struct v4l2_register *reg = arg; @@ -1438,7 +1438,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar break; } - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *reg = arg; diff --git a/linux/drivers/media/video/saa7127.c b/linux/drivers/media/video/saa7127.c index f23f2799b..70d898697 100644 --- a/linux/drivers/media/video/saa7127.c +++ b/linux/drivers/media/video/saa7127.c @@ -626,7 +626,7 @@ static int saa7127_command(struct i2c_client *client, break; #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_INT_G_REGISTER: + case VIDIOC_DBG_G_REGISTER: { struct v4l2_register *reg = arg; @@ -636,7 +636,7 @@ static int saa7127_command(struct i2c_client *client, break; } - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *reg = arg; diff --git a/linux/drivers/media/video/tvp5150.c b/linux/drivers/media/video/tvp5150.c index 1eb6e96bd..582c8542f 100644 --- a/linux/drivers/media/video/tvp5150.c +++ b/linux/drivers/media/video/tvp5150.c @@ -1046,7 +1046,7 @@ static int tvp5150_command(struct i2c_client *c, #endif #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_INT_G_REGISTER: + case VIDIOC_DBG_G_REGISTER: { struct v4l2_register *reg = arg; @@ -1056,7 +1056,7 @@ static int tvp5150_command(struct i2c_client *c, break; } - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *reg = arg; diff --git a/linux/drivers/media/video/upd64031a.c b/linux/drivers/media/video/upd64031a.c index 66254bad4..a35a21301 100644 --- a/linux/drivers/media/video/upd64031a.c +++ b/linux/drivers/media/video/upd64031a.c @@ -170,7 +170,7 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * break; #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_INT_G_REGISTER: + case VIDIOC_DBG_G_REGISTER: { struct v4l2_register *reg = arg; @@ -180,7 +180,7 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * break; } - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *reg = arg; u8 addr = reg->reg & 0xff; diff --git a/linux/drivers/media/video/upd64083.c b/linux/drivers/media/video/upd64083.c index 861d9b114..6b512c5d6 100644 --- a/linux/drivers/media/video/upd64083.c +++ b/linux/drivers/media/video/upd64083.c @@ -147,7 +147,7 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a break; #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_INT_G_REGISTER: + case VIDIOC_DBG_G_REGISTER: { struct v4l2_register *reg = arg; @@ -157,7 +157,7 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a break; } - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *reg = arg; u8 addr = reg->reg & 0xff; diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c index d5e1b6b21..f23abaa27 100644 --- a/linux/drivers/media/video/usbvision/usbvision-video.c +++ b/linux/drivers/media/video/usbvision/usbvision-video.c @@ -560,7 +560,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, #ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct acces to the NT100x registers */ - case VIDIOC_INT_G_REGISTER: + case VIDIOC_DBG_G_REGISTER: { struct v4l2_register *reg = arg; int errCode; @@ -570,17 +570,17 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, /* NT100x has a 8-bit register space */ errCode = usbvision_read_reg(usbvision, reg->reg&0xff); if (errCode < 0) { - err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode); + err("%s: VIDIOC_DBG_G_REGISTER failed: error %d", __FUNCTION__, errCode); } else { reg->val=(unsigned char)errCode; - PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X", + PDEBUG(DBG_IOCTL, "VIDIOC_DBG_G_REGISTER reg=0x%02X, value=0x%02X", (unsigned int)reg->reg, reg->val); errCode = 0; // No error } return errCode; } - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *reg = arg; int errCode; @@ -591,10 +591,10 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, return -EPERM; errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val); if (errCode < 0) { - err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode); + err("%s: VIDIOC_DBG_S_REGISTER failed: error %d", __FUNCTION__, errCode); } else { - PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X", + PDEBUG(DBG_IOCTL, "VIDIOC_DBG_S_REGISTER reg=0x%02X, value=0x%02X", (unsigned int)reg->reg, reg->val); errCode = 0; } diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 8fa62d5b4..231e671c1 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -421,9 +421,10 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG", + [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", + [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", + [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", - [_IOC_NR(VIDIOC_INT_S_REGISTER)] = "VIDIOC_INT_S_REGISTER", - [_IOC_NR(VIDIOC_INT_G_REGISTER)] = "VIDIOC_INT_G_REGISTER", [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", @@ -785,11 +786,11 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) p->id,p->index,p->name); break; } - case VIDIOC_INT_G_REGISTER: - case VIDIOC_INT_S_REGISTER: + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *p=arg; - printk ("%s: i2c_id=%d, reg=%lu, val=%d\n", s, + printk ("%s: i2c_id=%d, reg=%d, val=%d\n", s, p->i2c_id,p->reg,p->val); break; diff --git a/linux/drivers/media/video/video-buf.c b/linux/drivers/media/video/video-buf.c index 6d6a74c60..a2251c7e3 100644 --- a/linux/drivers/media/video/video-buf.c +++ b/linux/drivers/media/video/video-buf.c @@ -149,6 +149,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", data,size,dma->nr_pages); + dma->varea = (void *) data; + down_read(¤t->mm->mmap_sem); err = get_user_pages(current,current->mm, data & PAGE_MASK, dma->nr_pages, @@ -286,6 +288,7 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) vfree(dma->vmalloc); dma->vmalloc = NULL; + dma->varea = NULL; if (dma->bus_addr) { dma->bus_addr = 0; @@ -706,6 +709,7 @@ videobuf_qbuf(struct videobuf_queue *q, goto done; } if (buf->state == STATE_QUEUED || + buf->state == STATE_PREPARED || buf->state == STATE_ACTIVE) { dprintk(1,"qbuf: buffer is already queued or active.\n"); goto done; diff --git a/linux/drivers/media/video/videodev.c b/linux/drivers/media/video/videodev.c index b0009fe0f..476b3c143 100644 --- a/linux/drivers/media/video/videodev.c +++ b/linux/drivers/media/video/videodev.c @@ -1477,6 +1477,24 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_log_status(file, fh); break; } +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + { + struct v4l2_register *p=arg; + if (vfd->vidioc_g_register) + ret=vfd->vidioc_g_register(file, fh, p); + break; + } + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *p=arg; + if (!capable(CAP_SYS_ADMIN)) + ret=-EPERM; + else if (vfd->vidioc_s_register) + ret=vfd->vidioc_s_register(file, fh, p); + break; + } +#endif } /* switch */ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c index ddedd7fbb..1756ff277 100644 --- a/linux/drivers/media/video/vivi.c +++ b/linux/drivers/media/video/vivi.c @@ -150,7 +150,9 @@ struct vivi_buffer { struct vivi_fmt *fmt; +#ifdef CONFIG_VIVI_SCATTER struct sg_to_addr *to_addr; +#endif }; struct vivi_dmaqueue { @@ -239,6 +241,7 @@ static u8 bars[8][3] = { #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 +#ifdef CONFIG_VIVI_SCATTER static void prep_to_addr(struct sg_to_addr to_addr[], struct videobuf_buffer *vb) { @@ -271,14 +274,24 @@ static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[]) return (p1); } +#endif +#ifdef CONFIG_VIVI_SCATTER static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, int hmax, int line, char *timestr) +#else +static void gen_line(char *basep,int inipos,int wmax, + int hmax, int line, char *timestr) +#endif { - int w,i,j,pos=inipos,pgpos,oldpg,y; - char *p,*s,*basep; - struct page *pg; + int w,i,j,pos=inipos,y; + char *p,*s; u8 chr,r,g,b,color; +#ifdef CONFIG_VIVI_SCATTER + int pgpos,oldpg; + char *basep; + struct page *pg; + unsigned long flags; spinlock_t spinlock; @@ -289,6 +302,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); spin_lock_irqsave(&spinlock,flags); basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; +#endif /* We will just duplicate the second pixel at the packet */ wmax/=2; @@ -300,6 +314,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, b=bars[w*7/wmax][2]; for (color=0;color<4;color++) { +#ifdef CONFIG_VIVI_SCATTER pgpos=get_addr_pos(pos,pages,to_addr); if (pgpos!=oldpg) { pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); @@ -308,6 +323,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, oldpg=pgpos; } p=basep+pos-to_addr[pgpos].pos; +#else + p=basep+pos; +#endif switch (color) { case 0: @@ -352,6 +370,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, pos=inipos+j*2; for (color=0;color<4;color++) { +#ifdef CONFIG_VIVI_SCATTER pgpos=get_addr_pos(pos,pages,to_addr); if (pgpos!=oldpg) { pg=pfn_to_page(sg_dma_address( @@ -365,6 +384,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, oldpg=pgpos; } p=basep+pos-to_addr[pgpos].pos; +#else + p=basep+pos; +#endif y=TO_Y(r,g,b); @@ -401,19 +423,27 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, #endif end: +#ifdef CONFIG_VIVI_SCATTER kunmap_atomic(basep, KM_BOUNCE_READ); spin_unlock_irqrestore(&spinlock,flags); - +#else + return; +#endif } static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) { int h,pos=0; int hmax = buf->vb.height; int wmax = buf->vb.width; - struct videobuf_buffer *vb=&buf->vb; - struct sg_to_addr *to_addr=buf->to_addr; struct timeval ts; +#ifdef CONFIG_VIVI_SCATTER + struct sg_to_addr *to_addr=buf->to_addr; + struct videobuf_buffer *vb=&buf->vb; +#else + char *tmpbuf; +#endif +#ifdef CONFIG_VIVI_SCATTER /* Test if DMA mapping is ready */ if (!sg_dma_address(&vb->dma.sglist[0])) return; @@ -422,9 +452,27 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) /* Check if there is enough memory */ BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2); +#else + if (buf->vb.dma.varea) { + tmpbuf=kmalloc (wmax*2, GFP_KERNEL); + } else { + tmpbuf=buf->vb.dma.vmalloc; + } + +#endif for (h=0;h<hmax;h++) { +#ifdef CONFIG_VIVI_SCATTER gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr); +#else + if (buf->vb.dma.varea) { + gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); + /* FIXME: replacing to __copy_to_user */ + copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2); + } else { + gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); + } +#endif pos += wmax*2; } @@ -450,7 +498,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) dev->h,dev->m,dev->s,(dev->us+500)/1000); dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)buf->vb.dma.vmalloc,pos); + (unsigned long)buf->vb.dma.varea,pos); /* Advice that buffer was filled */ buf->vb.state = STATE_DONE; @@ -753,9 +801,11 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) if (in_interrupt()) BUG(); +#ifdef CONFIG_VIVI_SCATTER /*FIXME: Maybe a spinlock is required here */ kfree(buf->to_addr); buf->to_addr=NULL; +#endif videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(vq, &buf->vb.dma); @@ -801,11 +851,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, buf->vb.state = STATE_PREPARED; +#ifdef CONFIG_VIVI_SCATTER if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) { rc=-ENOMEM; goto fail; } - +#endif return 0; fail: @@ -870,6 +921,7 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb free_buffer(vq,buf); } +#ifdef CONFIG_VIVI_SCATTER static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, int direction) { @@ -902,6 +954,7 @@ static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages, // flush_write_buffers(); return 0; } +#endif static struct videobuf_queue_ops vivi_video_qops = { .buf_setup = buffer_setup, @@ -910,9 +963,9 @@ static struct videobuf_queue_ops vivi_video_qops = { .buf_release = buffer_release, /* Non-pci handling routines */ - .vb_map_sg = vivi_map_sg, - .vb_dma_sync_sg = vivi_dma_sync_sg, - .vb_unmap_sg = vivi_unmap_sg, +// .vb_map_sg = vivi_map_sg, +// .vb_dma_sync_sg = vivi_dma_sync_sg, +// .vb_unmap_sg = vivi_unmap_sg, }; /* ------------------------------------------------------------------ @@ -1296,11 +1349,19 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); +#ifdef CONFIG_VIVI_SCATTER + videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops, + NULL, NULL, + fh->type, + V4L2_FIELD_INTERLACED, + sizeof(struct vivi_buffer),fh); +#else videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); +#endif return 0; } |