diff options
Diffstat (limited to 'drivers/media/dvb/dvb-usb')
33 files changed, 3163 insertions, 1300 deletions
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 75824b77198..ad52143602c 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -26,6 +26,7 @@ config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB select DVB_DIB3000MC + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. @@ -33,24 +34,13 @@ config DVB_USB_DIBUSB_MB tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" depends on DVB_USB select DVB_DIB3000MB + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator. - Devices supported by this driver: - Artec T1 USB1.1 boxes - Avermedia AverTV DVBT USB1.1 - Compro Videomate DVB-U2000 - DVB-T USB - DiBcom USB1.1 reference devices (non-public) - Grandtec DVB-T USB - Hama DVB-T USB1.1-Box - KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0 - TwinhanDTV Magic Box (VP7041e) - TwinhanDTV USB-Ter (VP7041) - Ultima Electronic/Artec T1 USB TVBOX - - The VP7041 seems to be identical to "CTS Portable" (Chinese - Television System). + For an up-to-date list of devices supported by this driver, have a look + on the Linux-DVB Wiki at www.linuxtv.org. Say Y if you own such a device and want to use it. You should build it as a module. @@ -65,13 +55,32 @@ config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB select DVB_DIB3000MC + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help - Support for 2.0 DVB-T receivers based on reference designs made by + Support for USB2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator. - Devices supported by this driver: - Artec T1 USB2.0 boxes - DiBcom USB2.0 reference devices (non-public) + For an up-to-date list of devices supported by this driver, have a look + on the Linux-DVB Wiki at www.linuxtv.org. + + Say Y if you own such a device and want to use it. You should build it as + a module. + +config DVB_USB_DIB0700 + tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" + depends on DVB_USB + select DVB_DIB7000P + select DVB_DIB7000M + select DVB_DIB3000MC + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + help + Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The + USB bridge is also present in devices having the DiB7700 DVB-T-USB + silicon. This chip can be found in devices offered by Hauppauge, + Avermedia and other big and small companies. + + For an up-to-date list of devices supported by this driver, have a look + on the Linux-DVB Wiki at www.linuxtv.org. Say Y if you own such a device and want to use it. You should build it as a module. @@ -80,16 +89,18 @@ config DVB_USB_UMT_010 tristate "HanfTek UMT-010 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. config DVB_USB_CXUSB tristate "Conexant USB2.0 hybrid reference design support" depends on DVB_USB - select DVB_CX22702 - select DVB_LGDT330X - select DVB_MT352 - select DVB_ZL10353 + select DVB_CX22702 if !DVB_FE_CUSTOMISE + select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -101,8 +112,8 @@ config DVB_USB_CXUSB config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB - select DVB_NXT6000 - select DVB_MT352 + select DVB_NXT6000 if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE help Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. @@ -145,9 +156,21 @@ config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC + select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. +config DVB_USB_TTUSB2 + tristate "Pinnacle 400e DVB-S USB2.0 support" + depends on DVB_USB + select DVB_TDA10086 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_TDA826X if !DVB_FE_CUSTOMISE + help + Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The + firmware protocol used by this module is similar to the one used by the + old ttusb-driver - that's why the module is called dvb-usb-ttusb2.ko. + config DVB_USB_DTT200U tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" depends on DVB_USB diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 9643f56c7fe..154d593bbb0 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -1,4 +1,4 @@ -dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o +dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o obj-$(CONFIG_DVB_USB) += dvb-usb.o dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o @@ -36,4 +36,10 @@ obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o dvb-usb-cxusb-objs = cxusb.o obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o +dvb-usb-ttusb2-objs = ttusb2.o +obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o + +dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o +obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o + EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index ce44aa6bbb8..a6c5f19f680 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -26,6 +26,14 @@ static int a800_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } +/* assure to put cold to 0 for iManufacturer == 1 */ +static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + *cold = udev->descriptor.iManufacturer != 1; + return 0; +} + static struct dvb_usb_rc_key a800_rc_keys[] = { { 0x02, 0x01, KEY_PROG1 }, /* SOURCE */ { 0x02, 0x00, KEY_POWER }, /* POWER */ @@ -81,7 +89,7 @@ static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) } /* USB Driver stuff */ -static struct dvb_usb_properties a800_properties; +static struct dvb_usb_device_properties a800_properties; static int a800_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -97,22 +105,42 @@ static struct usb_device_id a800_table [] = { }; MODULE_DEVICE_TABLE (usb, a800_table); -static struct dvb_usb_properties a800_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, - .pid_filter_count = 32, +static struct dvb_usb_device_properties a800_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-avertv-a800-02.fw", - .size_of_priv = sizeof(struct dibusb_state), + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .size_of_priv = sizeof(struct dibusb_state), + }, + }, - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, .power_ctrl = a800_power_ctrl, - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, + .identify_state = a800_identify_state, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = a800_rc_keys, @@ -122,18 +150,6 @@ static struct dvb_usb_properties a800_properties = { .i2c_algo = &dibusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .num_device_descs = 1, .devices = { { "AVerMedia AverTV DVB-T USB 2.0 (A800)", diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index ae23bdde42a..15d12fce34d 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -14,12 +14,12 @@ * TODO: Use the cx25840-driver for the analogue part * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) - * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net) + * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au) * - * 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. + * 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 */ @@ -27,29 +27,29 @@ #include "cx22702.h" #include "lgdt330x.h" -#include "lg_h06xf.h" +#include "lgh06xf.h" #include "mt352.h" #include "mt352_priv.h" #include "zl10353.h" /* debug */ int dvb_usb_cxusb_debug; -module_param_named(debug,dvb_usb_cxusb_debug, int, 0644); +module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); static int cxusb_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) { int wo = (rbuf == NULL || rlen == 0); /* write-only */ u8 sndbuf[1+wlen]; - memset(sndbuf,0,1+wlen); + memset(sndbuf, 0, 1+wlen); sndbuf[0] = cmd; - memcpy(&sndbuf[1],wbuf,wlen); + memcpy(&sndbuf[1], wbuf, wlen); if (wo) - dvb_usb_generic_write(d,sndbuf,1+wlen); + dvb_usb_generic_write(d, sndbuf, 1+wlen); else - dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0); + dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); return 0; } @@ -58,14 +58,14 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d, static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) { struct cxusb_state *st = d->priv; - u8 o[2],i; + u8 o[2], i; if (st->gpio_write_state[GPIO_TUNER] == onoff) return; o[0] = GPIO_TUNER; o[1] = onoff; - cxusb_ctrl_msg(d,CMD_GPIO_WRITE,o,2,&i,1); + cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); if (i != 0x01) deb_info("gpio_write failed.\n"); @@ -74,7 +74,8 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) } /* I2C */ -static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; @@ -89,12 +90,12 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) if (d->udev->descriptor.idVendor == USB_VID_MEDION) switch (msg[i].addr) { - case 0x63: - cxusb_gpio_tuner(d,0); - break; - default: - cxusb_gpio_tuner(d,1); - break; + case 0x63: + cxusb_gpio_tuner(d, 0); + break; + default: + cxusb_gpio_tuner(d, 1); + break; } /* read request */ @@ -103,26 +104,27 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) obuf[0] = msg[i].len; obuf[1] = msg[i+1].len; obuf[2] = msg[i].addr; - memcpy(&obuf[3],msg[i].buf,msg[i].len); + memcpy(&obuf[3], msg[i].buf, msg[i].len); if (cxusb_ctrl_msg(d, CMD_I2C_READ, - obuf, 3+msg[i].len, - ibuf, 1+msg[i+1].len) < 0) + obuf, 3+msg[i].len, + ibuf, 1+msg[i+1].len) < 0) break; if (ibuf[0] != 0x08) deb_i2c("i2c read may have failed\n"); - memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len); + memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); i++; } else { /* write */ u8 obuf[2+msg[i].len], ibuf; obuf[0] = msg[i].addr; obuf[1] = msg[i].len; - memcpy(&obuf[2],msg[i].buf,msg[i].len); + memcpy(&obuf[2], msg[i].buf, msg[i].len); - if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0) + if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf, + 2+msg[i].len, &ibuf,1) < 0) break; if (ibuf != 0x08) deb_i2c("i2c write may have failed\n"); @@ -161,13 +163,13 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } -static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) +static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 buf[2] = { 0x03, 0x00 }; if (onoff) - cxusb_ctrl_msg(d,CMD_STREAMING_ON, buf, 2, NULL, 0); + cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0); else - cxusb_ctrl_msg(d,CMD_STREAMING_OFF, NULL, 0, NULL, 0); + cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); return 0; } @@ -324,16 +326,8 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe) return 0; } -static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_device *d = fe->dvb->priv; - return lg_h06xf_pll_set(fe, &d->i2c_adap, fep); -} - static struct cx22702_config cxusb_cx22702_config = { .demod_address = 0x63, - .output_mode = CX22702_PARALLEL_OUTPUT, }; @@ -349,6 +343,7 @@ static struct mt352_config cxusb_dee1601_config = { static struct zl10353_config cxusb_zl10353_dee1601_config = { .demod_address = 0x0f, + .parallel_ts = 1, }; static struct mt352_config cxusb_mt352_config = { @@ -358,98 +353,101 @@ static struct mt352_config cxusb_mt352_config = { }; /* Callbacks for DVB USB */ -static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d) +static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; - d->pll_addr = 0x61; - memcpy(d->pll_init, bpll, 4); - d->pll_desc = &dvb_pll_fmd1216me; + adap->pll_addr = 0x61; + memcpy(adap->pll_init, bpll, 4); + adap->pll_desc = &dvb_pll_fmd1216me; - d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; - d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; + adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; + adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; return 0; } -static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d) +static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) { - d->pll_addr = 0x61; - d->pll_desc = &dvb_pll_thomson_dtt7579; - d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; + dvb_attach(dvb_pll_attach, adap->fe, 0x61, + NULL, &dvb_pll_thomson_dtt7579); return 0; } -static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d) +static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) { - d->pll_addr = 0x61; - d->pll_desc = &dvb_pll_lg_z201; - d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; + dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201); return 0; } -static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d) +static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) { - d->pll_addr = 0x60; - d->pll_desc = &dvb_pll_thomson_dtt7579; - d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; + dvb_attach(dvb_pll_attach, adap->fe, 0x60, + NULL, &dvb_pll_thomson_dtt7579); return 0; } -static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d) +static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) { - d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params; + dvb_attach(lgh06xf_attach, adap->fe, &adap->dev->i2c_adap); return 0; } -static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d) +static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) { u8 b; - if (usb_set_interface(d->udev,0,6) < 0) + if (usb_set_interface(adap->dev->udev, 0, 6) < 0) err("set interface failed"); - cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, &b, 1); + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); - if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL) + if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, + &adap->dev->i2c_adap)) != NULL) return 0; return -EIO; } -static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_device *d) +static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) { - if (usb_set_interface(d->udev,0,7) < 0) + if (usb_set_interface(adap->dev->udev, 0, 7) < 0) err("set interface failed"); - cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((d->fe = lgdt330x_attach(&cxusb_lgdt3303_config, &d->i2c_adap)) != NULL) + if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, + &adap->dev->i2c_adap)) != NULL) return 0; return -EIO; } -static int cxusb_mt352_frontend_attach(struct dvb_usb_device *d) -{ /* used in both lgz201 and th7579 */ - if (usb_set_interface(d->udev,0,0) < 0) +static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) +{ + /* used in both lgz201 and th7579 */ + if (usb_set_interface(adap->dev->udev, 0, 0) < 0) err("set interface failed"); - cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((d->fe = mt352_attach(&cxusb_mt352_config, &d->i2c_adap)) != NULL) + if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, + &adap->dev->i2c_adap)) != NULL) return 0; return -EIO; } -static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d) +static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) { - if (usb_set_interface(d->udev,0,0) < 0) + if (usb_set_interface(adap->dev->udev, 0, 0) < 0) err("set interface failed"); - cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) || - ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL)) + if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, + &adap->dev->i2c_adap)) != NULL) || + ((adap->fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_dee1601_config, + &adap->dev->i2c_adap)) != NULL)) return 0; return -EIO; @@ -461,7 +459,8 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d) */ #define BLUEBIRD_01_ID_OFFSET 6638 -static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw) +static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, + const struct firmware *fw) { if (fw->size < BLUEBIRD_01_ID_OFFSET + 4) return -EINVAL; @@ -469,24 +468,26 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) && fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) { - fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1; - fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8; + fw->data[BLUEBIRD_01_ID_OFFSET + 2] = + udev->descriptor.idProduct + 1; + fw->data[BLUEBIRD_01_ID_OFFSET + 3] = + udev->descriptor.idProduct >> 8; - return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2); + return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2); } return -EINVAL; } /* DVB USB Driver stuff */ -static struct dvb_usb_properties cxusb_medion_properties; -static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties; -static struct dvb_usb_properties cxusb_bluebird_dee1601_properties; -static struct dvb_usb_properties cxusb_bluebird_lgz201_properties; -static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties; +static struct dvb_usb_device_properties cxusb_medion_properties; +static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; +static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; static int cxusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) + const struct usb_device_id *id) { if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 || @@ -500,47 +501,55 @@ static int cxusb_probe(struct usb_interface *intf, } static struct usb_device_id cxusb_table [] = { - { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_WARM) }, - {} /* Terminating entry */ + { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, + {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); -static struct dvb_usb_properties cxusb_medion_properties = { +static struct dvb_usb_device_properties cxusb_medion_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, .size_of_priv = sizeof(struct cxusb_state), - .streaming_ctrl = cxusb_streaming_ctrl, + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_cx22702_frontend_attach, + .tuner_attach = cxusb_fmd1216me_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + }, + }, .power_ctrl = cxusb_power_ctrl, - .frontend_attach = cxusb_cx22702_frontend_attach, - .tuner_attach = cxusb_fmd1216me_tuner_attach, .i2c_algo = &cxusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, .num_device_descs = 1, .devices = { @@ -551,7 +560,7 @@ static struct dvb_usb_properties cxusb_medion_properties = { } }; -static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { +static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, @@ -562,10 +571,28 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { .size_of_priv = sizeof(struct cxusb_state), - .streaming_ctrl = cxusb_streaming_ctrl, + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_lgdt3303_frontend_attach, + .tuner_attach = cxusb_lgh064f_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + .power_ctrl = cxusb_bluebird_power_ctrl, - .frontend_attach = cxusb_lgdt3303_frontend_attach, - .tuner_attach = cxusb_lgdt3303_tuner_attach, .i2c_algo = &cxusb_i2c_algo, @@ -575,17 +602,6 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { .rc_query = cxusb_rc_query, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, .num_device_descs = 1, .devices = { @@ -596,7 +612,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { } }; -static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = { +static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, @@ -607,10 +623,27 @@ static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = { .size_of_priv = sizeof(struct cxusb_state), - .streaming_ctrl = cxusb_streaming_ctrl, + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dee1601_frontend_attach, + .tuner_attach = cxusb_dee1601_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + .power_ctrl = cxusb_bluebird_power_ctrl, - .frontend_attach = cxusb_dee1601_frontend_attach, - .tuner_attach = cxusb_dee1601_tuner_attach, .i2c_algo = &cxusb_i2c_algo, @@ -620,19 +653,8 @@ static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = { .rc_query = cxusb_rc_query, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { { "DViCO FusionHDTV DVB-T Dual USB", { &cxusb_table[3], NULL }, @@ -642,10 +664,14 @@ static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = { { &cxusb_table[9], NULL }, { &cxusb_table[10], NULL }, }, + { "DViCO FusionHDTV DVB-T Dual Digital 2", + { &cxusb_table[11], NULL }, + { &cxusb_table[12], NULL }, + }, } }; -static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = { +static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, @@ -656,10 +682,27 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = { .size_of_priv = sizeof(struct cxusb_state), - .streaming_ctrl = cxusb_streaming_ctrl, + .num_adapters = 2, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_lgz201_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, .power_ctrl = cxusb_bluebird_power_ctrl, - .frontend_attach = cxusb_mt352_frontend_attach, - .tuner_attach = cxusb_lgz201_tuner_attach, .i2c_algo = &cxusb_i2c_algo, @@ -669,18 +712,6 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = { .rc_query = cxusb_rc_query, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - .num_device_descs = 1, .devices = { { "DViCO FusionHDTV DVB-T USB (LGZ201)", @@ -690,7 +721,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = { } }; -static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = { +static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, @@ -701,10 +732,27 @@ static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = { .size_of_priv = sizeof(struct cxusb_state), - .streaming_ctrl = cxusb_streaming_ctrl, + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_dtt7579_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, .power_ctrl = cxusb_bluebird_power_ctrl, - .frontend_attach = cxusb_mt352_frontend_attach, - .tuner_attach = cxusb_dtt7579_tuner_attach, .i2c_algo = &cxusb_i2c_algo, @@ -714,17 +762,6 @@ static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = { .rc_query = cxusb_rc_query, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 5, - .endpoint = 0x04, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, .num_device_descs = 1, .devices = { @@ -738,7 +775,7 @@ static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = { static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, - .disconnect = dvb_usb_device_exit, + .disconnect = dvb_usb_device_exit, .id_table = cxusb_table, }; @@ -764,7 +801,7 @@ module_init (cxusb_module_init); module_exit (cxusb_module_exit); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); -MODULE_AUTHOR("Michael Krufky <mkrufky@m1k.net>"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); MODULE_VERSION("1.0-alpha"); diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h new file mode 100644 index 00000000000..cda3adea24f --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -0,0 +1,54 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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. + * + * Copyright (C) 2005-6 DiBcom, SA + */ +#ifndef _DIB0700_H_ +#define _DIB0700_H_ + +#define DVB_USB_LOG_PREFIX "dib0700" +#include "dvb-usb.h" + +#include "dib07x0.h" + +extern int dvb_usb_dib0700_debug; +#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args) +#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args) +#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) +#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) + +#define REQUEST_I2C_READ 0x2 +#define REQUEST_I2C_WRITE 0x3 +#define REQUEST_POLL_RC 0x4 +#define REQUEST_JUMPRAM 0x8 +#define REQUEST_SET_CLOCK 0xB +#define REQUEST_SET_GPIO 0xC +#define REQUEST_ENABLE_VIDEO 0xF + // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) + // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) + // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) +#define REQUEST_GET_VERSION 0x15 + +struct dib0700_state { + u8 channel_state; + u16 mt2060_if1[2]; + + u8 is_dib7000pc; +}; + +extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); +extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); +extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); +extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); +extern struct i2c_algorithm dib0700_i2c_algo; +extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold); + +extern int dib0700_device_count; +extern struct dvb_usb_device_properties dib0700_devices[]; +extern struct usb_device_id dib0700_usb_id_table[]; + +#endif diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c new file mode 100644 index 00000000000..6a4d150784a --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -0,0 +1,311 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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. + * + * Copyright (C) 2005-6 DiBcom, SA + */ +#include "dib0700.h" + +/* debug */ +int dvb_usb_dib0700_debug; +module_param_named(debug,dvb_usb_dib0700_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS); + +/* expecting rx buffer: request data[0] data[1] ... data[2] */ +static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen) +{ + int status; + + deb_data(">>> "); + debug_dump(tx,txlen,deb_data); + + status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), + tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen, + USB_CTRL_GET_TIMEOUT); + + if (status != txlen) + deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen); + + return status < 0 ? status : 0; +} + +/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */ +static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +{ + u16 index, value; + int status; + + if (txlen < 2) { + err("tx buffer length is smaller than 2. Makes no sense."); + return -EINVAL; + } + if (txlen > 4) { + err("tx buffer length is larger than 4. Not supported."); + return -EINVAL; + } + + deb_data(">>> "); + debug_dump(tx,txlen,deb_data); + + value = ((txlen - 2) << 8) | tx[1]; + index = 0; + if (txlen > 2) + index |= (tx[2] << 8); + if (txlen > 3) + index |= tx[3]; + + /* think about swapping here */ + value = le16_to_cpu(value); + index = le16_to_cpu(index); + + status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0], + USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen, + USB_CTRL_GET_TIMEOUT); + + if (status < 0) + deb_info("ep 0 read error (status = %d)\n",status); + + deb_data("<<< "); + debug_dump(rx,rxlen,deb_data); + + return status; /* length in case of success */ +} + +int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) +{ + u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) }; + return dib0700_ctrl_wr(d,buf,3); +} + +/* + * I2C master xfer function + */ +static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i,len; + u8 buf[255]; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + /* fill in the address */ + buf[1] = (msg[i].addr << 1); + /* fill the buffer */ + memcpy(&buf[2], msg[i].buf, msg[i].len); + + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + buf[0] = REQUEST_I2C_READ; + buf[1] |= 1; + + /* special thing in the current firmware: when length is zero the read-failed */ + if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) { + deb_info("I2C read failed on address %x\n", msg[i].addr); + break; + } + + msg[i+1].len = len; + + i++; + } else { + buf[0] = REQUEST_I2C_WRITE; + if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0) + break; + } + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 dib0700_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +struct i2c_algorithm dib0700_i2c_algo = { + .master_xfer = dib0700_i2c_xfer, + .functionality = dib0700_i2c_func, +}; + +int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + u8 b[16]; + s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0), + REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT); + + deb_info("FW GET_VERSION length: %d\n",ret); + + *cold = ret <= 0; + + deb_info("cold: %d\n", *cold); + return 0; +} + +static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, + u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv, + u16 pll_loopdiv, u16 free_div, u16 dsuScaler) +{ + u8 b[10]; + b[0] = REQUEST_SET_CLOCK; + b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4); + b[2] = (pll_prediv >> 8) & 0xff; // MSB + b[3] = pll_prediv & 0xff; // LSB + b[4] = (pll_loopdiv >> 8) & 0xff; // MSB + b[5] = pll_loopdiv & 0xff; // LSB + b[6] = (free_div >> 8) & 0xff; // MSB + b[7] = free_div & 0xff; // LSB + b[8] = (dsuScaler >> 8) & 0xff; // MSB + b[9] = dsuScaler & 0xff; // LSB + + return dib0700_ctrl_wr(d, b, 10); +} + +int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3) +{ + switch (clk_MHz) { + case 72: dib0700_set_clock(d, 1, 0, 1, clock_out_gp3, 2, 24, 0, 0x4c); break; + default: return -EINVAL; + } + return 0; +} + +static int dib0700_jumpram(struct usb_device *udev, u32 address) +{ + int ret, actlen; + u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0, + (address >> 24) & 0xff, + (address >> 16) & 0xff, + (address >> 8) & 0xff, + address & 0xff }; + + if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) { + deb_fw("jumpram to 0x%x failed\n",address); + return ret; + } + if (actlen != 8) { + deb_fw("jumpram to 0x%x failed\n",address); + return -EIO; + } + return 0; +} + +int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) +{ + struct hexline hx; + int pos = 0, ret, act_len; + + u8 buf[260]; + + while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) { + deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk); + + buf[0] = hx.len; + buf[1] = (hx.addr >> 8) & 0xff; + buf[2] = hx.addr & 0xff; + buf[3] = hx.type; + memcpy(&buf[4],hx.data,hx.len); + buf[4+hx.len] = hx.chk; + + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x01), + buf, + hx.len + 5, + &act_len, + 1000); + + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); + return ret; + } + } + + if (ret == 0) { + /* start the firmware */ + if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) { + info("firmware started successfully."); + msleep(500); + } + } else + ret = -EIO; + + return ret; +} + +int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dib0700_state *st = adap->dev->priv; + u8 b[4]; + + b[0] = REQUEST_ENABLE_VIDEO; + b[1] = 0x00; + b[2] = (0x01 << 4); /* Master mode */ + b[3] = 0x00; + + deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); + + if (onoff) + st->channel_state |= 1 << adap->id; + else + st->channel_state &= ~(1 << adap->id); + + b[2] |= st->channel_state; + + if (st->channel_state) /* if at least one channel is active */ + b[1] = (0x01 << 4) | 0x00; + + deb_info("data for streaming: %x %x\n",b[1],b[2]); + + return dib0700_ctrl_wr(adap->dev, b, 4); +} + +static int dib0700_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int i; + + for (i = 0; i < dib0700_device_count; i++) + if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0) + return 0; + + return -ENODEV; +} + +static struct usb_driver dib0700_driver = { + .name = "dvb_usb_dib0700", + .probe = dib0700_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dib0700_usb_id_table, +}; + +/* module stuff */ +static int __init dib0700_module_init(void) +{ + int result; + info("loaded with support for %d different device-types", dib0700_device_count); + if ((result = usb_register(&dib0700_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit dib0700_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&dib0700_driver); +} + +module_init (dib0700_module_init); +module_exit (dib0700_module_exit); + +MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); +MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c new file mode 100644 index 00000000000..2208757d901 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -0,0 +1,378 @@ +/* Linux driver for devices based on the DiBcom DiB0700 USB bridge + * + * 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. + * + * Copyright (C) 2005-6 DiBcom, SA + */ +#include "dib0700.h" + +#include "dib3000mc.h" +#include "dib7000m.h" +#include "dib7000p.h" +#include "mt2060.h" + +static int force_lna_activation; +module_param(force_lna_activation, int, 0644); +MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " + "if applicable for the device (default: 0=automatic/off)."); + +/* Hauppauge Nova-T 500 + * has a LNA on GPIO0 which is enabled by setting 1 */ +static struct mt2060_config bristol_mt2060_config[2] = { + { + .i2c_address = 0x60, + .clock_out = 3, + }, { + .i2c_address = 0x61, + } +}; + +static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 42598, + .agc1_min = 17694, + .agc2_max = 45875, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 59, + + .agc1_slope1 = 0, + .agc1_slope2 = 69, + + .agc2_pt1 = 0, + .agc2_pt2 = 59, + + .agc2_slope1 = 111, + .agc2_slope2 = 28, +}; + +static struct dib3000mc_config bristol_dib3000mc_config[2] = { + { .agc = &bristol_dib3000p_mt2060_agc_config, + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + .output_mpeg2_in_188_bytes = 1, + }, + { .agc = &bristol_dib3000p_mt2060_agc_config, + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + .output_mpeg2_in_188_bytes = 1, + } +}; + +static int bristol_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); + + if (force_lna_activation) + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + else + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); + + if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10); + return -ENODEV; + } + } + st->mt2060_if1[adap->id] = 1220; + return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, + (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; +} + +static int bristol_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); + return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id], + st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; +} + +/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ +static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { + BAND_UHF | BAND_VHF, // band_caps + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + + 712, // inv_gain + 41, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 4095, // wbd_ref + 0, // wbd_sel + 0, // wbd_alpha + + 42598, // agc1_max + 17694, // agc1_min + 45875, // agc2_max + 2621, // agc2_min + 0, // agc1_pt1 + 76, // agc1_pt2 + 139, // agc1_pt3 + 52, // agc1_slope1 + 59, // agc1_slope2 + 107, // agc2_pt1 + 172, // agc2_pt2 + 57, // agc2_slope1 + 70, // agc2_slope2 + + 21, // alpha_mant + 25, // alpha_exp + 28, // beta_mant + 48, // beta_exp + + 1, // perform_agc_softsplit + { 0, // split_min + 107, // split_max + 51800, // global_split_min + 24700 // global_split_max + }, +}; + +static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { + BAND_UHF | BAND_VHF, + + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + + 712, // inv_gain + 41, // time_stabiliz + + 0, // alpha_level + 118, // thlock + + 0, // wbd_inv + 4095, // wbd_ref + 0, // wbd_sel + 0, // wbd_alpha + + 42598, // agc1_max + 16384, // agc1_min + 42598, // agc2_max + 0, // agc2_min + + 0, // agc1_pt1 + 137, // agc1_pt2 + 255, // agc1_pt3 + + 0, // agc1_slope1 + 255, // agc1_slope2 + + 0, // agc2_pt1 + 0, // agc2_pt2 + + 0, // agc2_slope1 + 41, // agc2_slope2 + + 15, // alpha_mant + 25, // alpha_exp + + 28, // beta_mant + 48, // beta_exp + + 0, // perform_agc_softsplit +}; + +static struct dibx000_bandwidth_config stk7700p_pll_config = { + 60000, 30000, // internal, sampling + 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + 60258167, // ifreq + 20452225, // timf +}; + +static struct dib7000m_config stk7700p_dib7000m_config = { + .dvbt_mode = 1, + .output_mpeg2_in_188_bytes = 1, + .quartz_direct = 1, + + .agc_config_count = 1, + .agc = &stk7700p_7000m_mt2060_agc_config, + .bw = &stk7700p_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +static struct dib7000p_config stk7700p_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc = &stk7700p_7000p_mt2060_agc_config, + .bw = &stk7700p_pll_config, + + .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS, +}; + +static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + /* unless there is no real power management in DVB - we leave the device on GPIO6 */ + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(50); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10); + dib0700_ctrl_clock(adap->dev, 72, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100); + + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + st->mt2060_if1[0] = 1220; + + if (dib7000pc_detection(&adap->dev->i2c_adap)) { + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); + st->is_dib7000pc = 1; + } else + adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static struct mt2060_config stk7700p_mt2060_config = { + 0x60 +}; + +static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *tun_i2c; + + if (st->is_dib7000pc) + tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + else + tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config, + st->mt2060_if1[0]) == NULL ? -ENODEV : 0; +} + +struct usb_device_id dib0700_usb_id_table[] = { + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, + + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, + { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); + +#define DIB0700_DEFAULT_DEVICE_PROPERTIES \ + .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ + .usb_ctrl = DEVICE_SPECIFIC, \ + .firmware = "dvb-usb-dib0700-01.fw", \ + .download_firmware = dib0700_download_firmware, \ + .no_reconnect = 1, \ + .size_of_priv = sizeof(struct dib0700_state), \ + .i2c_algo = &dib0700_i2c_algo, \ + .identify_state = dib0700_identify_state + +#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \ + .streaming_ctrl = dib0700_streaming_ctrl, \ + .stream = { \ + .type = USB_BULK, \ + .count = 4, \ + .endpoint = ep, \ + .u = { \ + .bulk = { \ + .buffersize = 39480, \ + } \ + } \ + } + +struct dvb_usb_device_properties dib0700_devices[] = { + { + DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = stk7700p_frontend_attach, + .tuner_attach = stk7700p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, + }, + + .num_device_descs = 6, + .devices = { + { "DiBcom STK7700P reference design", + { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, + { NULL }, + }, + { "Hauppauge Nova-T Stick", + { &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL }, + { NULL }, + }, + { "AVerMedia AVerTV DVB-T Volar", + { &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] }, + { NULL }, + }, + { "Compro Videomate U500", + { &dib0700_usb_id_table[6], NULL }, + { NULL }, + }, + { "Uniwill STK7700P based (Hama and others)", + { &dib0700_usb_id_table[7], NULL }, + { NULL }, + }, + { "Leadtek Winfast DTV Dongle (STK7700P based)", + { &dib0700_usb_id_table[8], NULL }, + { NULL }, + } + } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 2, + .adapter = { + { + .frontend_attach = bristol_frontend_attach, + .tuner_attach = bristol_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, { + .frontend_attach = bristol_frontend_attach, + .tuner_attach = bristol_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } + }, + + .num_device_descs = 1, + .devices = { + { "Hauppauge Nova-T 500 Dual DVB-T", + { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, + { NULL }, + }, + } + } +}; + +int dib0700_device_count = ARRAY_SIZE(dib0700_devices); diff --git a/drivers/media/dvb/dvb-usb/dib07x0.h b/drivers/media/dvb/dvb-usb/dib07x0.h new file mode 100644 index 00000000000..7e62c101852 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dib07x0.h @@ -0,0 +1,21 @@ +#ifndef _DIB07X0_H_ +#define _DIB07X0_H_ + +enum dib07x0_gpios { + GPIO0 = 0, + GPIO1 = 2, + GPIO2 = 3, + GPIO3 = 4, + GPIO4 = 5, + GPIO5 = 6, + GPIO6 = 8, + GPIO7 = 10, + GPIO8 = 11, + GPIO9 = 14, + GPIO10 = 15, +}; + +#define GPIO_IN 0 +#define GPIO_OUT 1 + +#endif diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index abd75b4a350..5143e426d28 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -18,12 +18,12 @@ MODULE_LICENSE("GPL"); #define deb_info(args...) dprintk(debug,0x01,args) /* common stuff used by the different dibusb modules */ -int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) +int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { - if (d->priv != NULL) { - struct dibusb_state *st = d->priv; + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; if (st->ops.fifo_ctrl != NULL) - if (st->ops.fifo_ctrl(d->fe,onoff)) { + if (st->ops.fifo_ctrl(adap->fe,onoff)) { err("error while controlling the fifo of the demod."); return -ENODEV; } @@ -32,23 +32,23 @@ int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) } EXPORT_SYMBOL(dibusb_streaming_ctrl); -int dibusb_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff) +int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { - if (d->priv != NULL) { - struct dibusb_state *st = d->priv; + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; if (st->ops.pid_ctrl != NULL) - st->ops.pid_ctrl(d->fe,index,pid,onoff); + st->ops.pid_ctrl(adap->fe,index,pid,onoff); } return 0; } EXPORT_SYMBOL(dibusb_pid_filter); -int dibusb_pid_filter_ctrl(struct dvb_usb_device *d, int onoff) +int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - if (d->priv != NULL) { - struct dibusb_state *st = d->priv; + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; if (st->ops.pid_parse != NULL) - if (st->ops.pid_parse(d->fe,onoff) < 0) + if (st->ops.pid_parse(adap->fe,onoff) < 0) err("could not handle pid_parser"); } return 0; @@ -68,24 +68,24 @@ int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff) } EXPORT_SYMBOL(dibusb_power_ctrl); -int dibusb2_0_streaming_ctrl(struct dvb_usb_device *d, int onoff) +int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 b[3] = { 0 }; int ret; - if ((ret = dibusb_streaming_ctrl(d,onoff)) < 0) + if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0) return ret; if (onoff) { b[0] = DIBUSB_REQ_SET_STREAMING_MODE; b[1] = 0x00; - if ((ret = dvb_usb_generic_write(d,b,2)) < 0) + if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0) return ret; } b[0] = DIBUSB_REQ_SET_IOCTL; b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; - return dvb_usb_generic_write(d,b,3); + return dvb_usb_generic_write(adap->dev,b,3); } EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); @@ -131,9 +131,6 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; - if (num > 2) - warn("more than 2 i2c messages at a time is not handled yet. TODO."); - for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { @@ -168,31 +165,143 @@ int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) } EXPORT_SYMBOL(dibusb_read_eeprom_byte); -int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d) +/* 3000MC/P stuff */ +// Config Adjacent channels Perf -cal22 +static struct dibx000_agc_config dib3000p_mt2060_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 48497, + .agc1_min = 23593, + .agc2_max = 46531, + .agc2_min = 24904, + + .agc1_pt1 = 0x65, + .agc1_pt2 = 0x69, + + .agc1_slope1 = 0x51, + .agc1_slope2 = 0x27, + + .agc2_pt1 = 0, + .agc2_pt2 = 0x33, + + .agc2_slope1 = 0x35, + .agc2_slope2 = 0x37, +}; + +static struct dib3000mc_config stk3000p_dib3000p_config = { + &dib3000p_mt2060_agc_config, + + .max_time = 0x196, + .ln_adc_level = 0x1cc7, + + .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, +}; + +static struct dibx000_agc_config dib3000p_panasonic_agc_config = { + .band_caps = BAND_VHF | BAND_UHF, + .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0), + + .agc1_max = 56361, + .agc1_min = 22282, + .agc2_max = 47841, + .agc2_min = 36045, + + .agc1_pt1 = 0x3b, + .agc1_pt2 = 0x6b, + + .agc1_slope1 = 0x55, + .agc1_slope2 = 0x1d, + + .agc2_pt1 = 0, + .agc2_pt2 = 0x0a, + + .agc2_slope1 = 0x95, + .agc2_slope2 = 0x1e, +}; + +static struct dib3000mc_config mod3000p_dib3000p_config = { + &dib3000p_panasonic_agc_config, + + .max_time = 0x51, + .ln_adc_level = 0x1cc7, + + .output_mpeg2_in_188_bytes = 1, + + .agc_command1 = 1, + .agc_command2 = 1, +}; + +int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) { - struct dib3000_config demod_cfg; - struct dibusb_state *st = d->priv; - - for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++) - if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) { - d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; - d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; - d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl; - return 0; + if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || + (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { + if (adap->priv != NULL) { + struct dibusb_state *st = adap->priv; + st->ops.pid_parse = dib3000mc_pid_parse; + st->ops.pid_ctrl = dib3000mc_pid_control; } - + return 0; + } return -ENODEV; } EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach); -int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d) -{ - d->pll_addr = 0x60; - d->pll_desc = &dvb_pll_env57h1xd5; +static struct mt2060_config stk3000p_mt2060_config = { + 0x60 +}; - d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; - d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; +int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dibusb_state *st = adap->priv; + u8 a,b; + u16 if1 = 1220; + struct i2c_adapter *tun_i2c; + + // First IF calibration for Liteon Sticks + if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && + adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) { + + dibusb_read_eeprom_byte(adap->dev,0x7E,&a); + dibusb_read_eeprom_byte(adap->dev,0x7F,&b); + + if (a == 0x00) + if1 += b; + else if (a == 0x80) + if1 -= b; + else + warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b); + + } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM && + adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) { + u8 desc; + dibusb_read_eeprom_byte(adap->dev, 7, &desc); + if (desc == 2) { + a = 127; + do { + dibusb_read_eeprom_byte(adap->dev, a, &desc); + a--; + } while (a > 7 && (desc == 0xff || desc == 0x00)); + if (desc & 0x80) + if1 -= (0xff - desc); + else + if1 += desc; + } + } + tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); + if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { + /* not found - use panasonic pll parameters */ + if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL) + return -ENOMEM; + } else { + st->mt2060_present = 1; + /* set the correct parameters for the dib3000p */ + dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config); + } return 0; } EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); @@ -267,6 +376,67 @@ struct dvb_usb_rc_key dibusb_rc_keys[] = { { 0x86, 0x1e, KEY_DOWN }, { 0x86, 0x1f, KEY_LEFT }, { 0x86, 0x1b, KEY_RIGHT }, + + /* Key codes for the DiBcom MOD3000 remote. */ + { 0x80, 0x00, KEY_MUTE }, + { 0x80, 0x01, KEY_TEXT }, + { 0x80, 0x02, KEY_HOME }, + { 0x80, 0x03, KEY_POWER }, + + { 0x80, 0x04, KEY_RED }, + { 0x80, 0x05, KEY_GREEN }, + { 0x80, 0x06, KEY_YELLOW }, + { 0x80, 0x07, KEY_BLUE }, + + { 0x80, 0x08, KEY_DVD }, + { 0x80, 0x09, KEY_AUDIO }, + { 0x80, 0x0a, KEY_MEDIA }, /* Pictures */ + { 0x80, 0x0b, KEY_VIDEO }, + + { 0x80, 0x0c, KEY_BACK }, + { 0x80, 0x0d, KEY_UP }, + { 0x80, 0x0e, KEY_RADIO }, + { 0x80, 0x0f, KEY_EPG }, + + { 0x80, 0x10, KEY_LEFT }, + { 0x80, 0x11, KEY_OK }, + { 0x80, 0x12, KEY_RIGHT }, + { 0x80, 0x13, KEY_UNKNOWN }, /* SAP */ + + { 0x80, 0x14, KEY_TV }, + { 0x80, 0x15, KEY_DOWN }, + { 0x80, 0x16, KEY_MENU }, /* DVD Menu */ + { 0x80, 0x17, KEY_LAST }, + + { 0x80, 0x18, KEY_RECORD }, + { 0x80, 0x19, KEY_STOP }, + { 0x80, 0x1a, KEY_PAUSE }, + { 0x80, 0x1b, KEY_PLAY }, + + { 0x80, 0x1c, KEY_PREVIOUS }, + { 0x80, 0x1d, KEY_REWIND }, + { 0x80, 0x1e, KEY_FASTFORWARD }, + { 0x80, 0x1f, KEY_NEXT}, + + { 0x80, 0x40, KEY_1 }, + { 0x80, 0x41, KEY_2 }, + { 0x80, 0x42, KEY_3 }, + { 0x80, 0x43, KEY_CHANNELUP }, + + { 0x80, 0x44, KEY_4 }, + { 0x80, 0x45, KEY_5 }, + { 0x80, 0x46, KEY_6 }, + { 0x80, 0x47, KEY_CHANNELDOWN }, + + { 0x80, 0x48, KEY_7 }, + { 0x80, 0x49, KEY_8 }, + { 0x80, 0x4a, KEY_9 }, + { 0x80, 0x4b, KEY_VOLUMEUP }, + + { 0x80, 0x4c, KEY_CLEAR }, + { 0x80, 0x4d, KEY_0 }, + { 0x80, 0x4e, KEY_ENTER }, + { 0x80, 0x4f, KEY_VOLUMEDOWN }, }; EXPORT_SYMBOL(dibusb_rc_keys); diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index f4c45f386eb..7a6ae8f482e 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -14,35 +14,35 @@ */ #include "dibusb.h" -static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d) +static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) { struct dib3000_config demod_cfg; - struct dibusb_state *st = d->priv; + struct dibusb_state *st = adap->priv; demod_cfg.demod_address = 0x8; - if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) { - d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; - d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; + if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL) return -ENODEV; - } - d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl; + adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; + adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; + + adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl; return 0; } -static int dibusb_thomson_tuner_attach(struct dvb_usb_device *d) +static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) { - d->pll_addr = 0x61; - d->pll_desc = &dvb_pll_tua6010xs; + adap->pll_addr = 0x61; + adap->pll_desc = &dvb_pll_tua6010xs; return 0; } /* Some of the Artec 1.1 device aren't equipped with the default tuner * (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures * this out. */ -static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d) +static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) { u8 b[2] = { 0,0 }, b2[1]; int ret = 0; @@ -54,36 +54,36 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d) /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ msg[0].addr = msg[1].addr = 0x60; - if (d->tuner_pass_ctrl) - d->tuner_pass_ctrl(d->fe,1,msg[0].addr); + if (adap->tuner_pass_ctrl) + adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr); - if (i2c_transfer (&d->i2c_adap, msg, 2) != 2) { + if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { err("tuner i2c write failed."); ret = -EREMOTEIO; } - if (d->tuner_pass_ctrl) - d->tuner_pass_ctrl(d->fe,0,msg[0].addr); + if (adap->tuner_pass_ctrl) + adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr); if (b2[0] == 0xfe) { info("This device has the Thomson Cable onboard. Which is default."); - dibusb_thomson_tuner_attach(d); + dibusb_thomson_tuner_attach(adap); } else { u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab }; info("This device has the Panasonic ENV77H11D5 onboard."); - d->pll_addr = 0x60; - memcpy(d->pll_init,bpll,4); - d->pll_desc = &dvb_pll_tda665x; + adap->pll_addr = 0x60; + memcpy(adap->pll_init,bpll,4); + adap->pll_desc = &dvb_pll_tda665x; } return ret; } /* USB Driver stuff */ -static struct dvb_usb_properties dibusb1_1_properties; -static struct dvb_usb_properties dibusb1_1_an2235_properties; -static struct dvb_usb_properties dibusb2_0b_properties; -static struct dvb_usb_properties artec_t1_usb2_properties; +static struct dvb_usb_device_properties dibusb1_1_properties; +static struct dvb_usb_device_properties dibusb1_1_an2235_properties; +static struct dvb_usb_device_properties dibusb2_0b_properties; +static struct dvb_usb_device_properties artec_t1_usb2_properties; static int dibusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -150,42 +150,50 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { }; MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); -static struct dvb_usb_properties dibusb1_1_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, - .pid_filter_count = 16, +static struct dvb_usb_device_properties dibusb1_1_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_AN2135, .firmware = "dvb-usb-dibusb-5.0.0.11.fw", - .size_of_priv = sizeof(struct dibusb_state), + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + } + }, - .streaming_ctrl = dibusb_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, .power_ctrl = dibusb_power_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, - .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ .rc_query = dibusb_rc_query, .i2c_algo = &dibusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, .num_device_descs = 9, .devices = { @@ -228,42 +236,48 @@ static struct dvb_usb_properties dibusb1_1_properties = { } }; -static struct dvb_usb_properties dibusb1_1_an2235_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, - .pid_filter_count = 16, - +static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_AN2235, .firmware = "dvb-usb-dibusb-an2235-01.fw", - .size_of_priv = sizeof(struct dibusb_state), - - .streaming_ctrl = dibusb_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + }, + }, .power_ctrl = dibusb_power_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, - .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ .rc_query = dibusb_rc_query, .i2c_algo = &dibusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY .num_device_descs = 2, @@ -272,8 +286,8 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { #endif .devices = { { "Artec T1 USB1.1 TVBOX with AN2235", - { &dibusb_dib3000mb_table[20], NULL }, { &dibusb_dib3000mb_table[21], NULL }, + { &dibusb_dib3000mb_table[22], NULL }, }, #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", @@ -285,42 +299,49 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { } }; -static struct dvb_usb_properties dibusb2_0b_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, - .pid_filter_count = 16, +static struct dvb_usb_device_properties dibusb2_0b_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-adstech-usb2-02.fw", - .size_of_priv = sizeof(struct dibusb_state), - - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_thomson_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + } + }, .power_ctrl = dibusb2_0_power_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_thomson_tuner_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, - .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ .rc_query = dibusb_rc_query, .i2c_algo = &dibusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, .num_device_descs = 2, .devices = { @@ -336,42 +357,48 @@ static struct dvb_usb_properties dibusb2_0b_properties = { } }; -static struct dvb_usb_properties artec_t1_usb2_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, - .pid_filter_count = 16, +static struct dvb_usb_device_properties artec_t1_usb2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-dibusb-6.0.0.8.fw", - .size_of_priv = sizeof(struct dibusb_state), - - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 16, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + } + }, .power_ctrl = dibusb2_0_power_ctrl, - .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_tuner_probe_and_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, - .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */ .rc_query = dibusb_rc_query, .i2c_algo = &dibusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, .num_device_descs = 1, .devices = { diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c index 55802fba3c2..e7ea3e753d6 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mc.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c @@ -15,7 +15,7 @@ #include "dibusb.h" /* USB Driver stuff */ -static struct dvb_usb_properties dibusb_mc_properties; +static struct dvb_usb_device_properties dibusb_mc_properties; static int dibusb_mc_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -28,56 +28,95 @@ static struct usb_device_id dibusb_dib3000mc_table [] = { /* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, /* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, /* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, +/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? ) +/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) }, +/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) }, +/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) }, +/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) }, +/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) }, +/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) }, +/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) }, +/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) }, +/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) }, +/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table); -static struct dvb_usb_properties dibusb_mc_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, - .pid_filter_count = 32, +static struct dvb_usb_device_properties dibusb_mc_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-dibusb-6.0.0.8.fw", - .size_of_priv = sizeof(struct dibusb_state), + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct dibusb_state), + } + }, .power_ctrl = dibusb2_0_power_ctrl, - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, - .rc_key_map_size = 63, /* FIXME */ + .rc_key_map_size = 111, /* FIXME */ .rc_query = dibusb_rc_query, .i2c_algo = &dibusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .num_device_descs = 2, + .num_device_descs = 7, .devices = { { "DiBcom USB2.0 DVB-T reference design (MOD3000P)", { &dibusb_dib3000mc_table[0], NULL }, { &dibusb_dib3000mc_table[1], NULL }, }, - { "Artec T1 USB2.0 TVBOX (please report the warm ID)", + { "Artec T1 USB2.0 TVBOX (please check the warm ID)", { &dibusb_dib3000mc_table[2], NULL }, - { NULL }, + { &dibusb_dib3000mc_table[3], NULL }, + }, + { "LITE-ON USB2.0 DVB-T Tuner", + /* Also rebranded as Intuix S800, Toshiba */ + { &dibusb_dib3000mc_table[4], NULL }, + { &dibusb_dib3000mc_table[5], NULL }, + }, + { "MSI Digivox Mini SL", + { &dibusb_dib3000mc_table[6], NULL }, + { &dibusb_dib3000mc_table[7], NULL }, + }, + { "GRAND - USB2.0 DVB-T adapter", + { &dibusb_dib3000mc_table[8], NULL }, + { &dibusb_dib3000mc_table[9], NULL }, + }, + { "Artec T14 - USB2.0 DVB-T", + { &dibusb_dib3000mc_table[10], NULL }, + { &dibusb_dib3000mc_table[11], NULL }, + }, + { "Leadtek - USB2.0 Winfast DTV dongle", + { &dibusb_dib3000mc_table[12], NULL }, + { &dibusb_dib3000mc_table[13], NULL }, }, + { NULL }, } }; diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h index 2d99d05c7ea..b6078103274 100644 --- a/drivers/media/dvb/dvb-usb/dibusb.h +++ b/drivers/media/dvb/dvb-usb/dibusb.h @@ -17,6 +17,8 @@ #include "dvb-usb.h" #include "dib3000.h" +#include "dib3000mc.h" +#include "mt2060.h" /* * protocol of all dibusb related devices @@ -96,7 +98,10 @@ struct dibusb_state { struct dib_fe_xfer_ops ops; + int mt2060_present; +}; +struct dibusb_device_state { /* for RC5 remote control */ int old_toggle; int last_repeat_count; @@ -104,14 +109,15 @@ struct dibusb_state { extern struct i2c_algorithm dibusb_i2c_algo; -extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *); -extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *); +extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *); +extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *); + +extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int); +extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int); +extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int); +extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int); -extern int dibusb_streaming_ctrl(struct dvb_usb_device *, int); -extern int dibusb_pid_filter(struct dvb_usb_device *, int, u16, int); -extern int dibusb_pid_filter_ctrl(struct dvb_usb_device *, int); extern int dibusb_power_ctrl(struct dvb_usb_device *, int); -extern int dibusb2_0_streaming_ctrl(struct dvb_usb_device *, int); extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int); #define DEFAULT_RC_INTERVAL 150 diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index c14d9efb48f..4a198d4755b 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -83,7 +83,7 @@ static struct i2c_algorithm digitv_i2c_algo = { /* Callbacks for DVB USB */ static int digitv_identify_state (struct usb_device *udev, struct - dvb_usb_properties *props, struct dvb_usb_device_description **desc, + dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, int *cold) { *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; @@ -116,59 +116,129 @@ static struct mt352_config digitv_mt352_config = { static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { - struct dvb_usb_device *d = fe->dvb->priv; + struct dvb_usb_adapter *adap = fe->dvb->priv; u8 b[5]; dvb_usb_tuner_calc_regs(fe,fep,b, 5); - return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0); + return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); } static struct nxt6000_config digitv_nxt6000_config = { .clock_inversion = 1, }; -static int digitv_frontend_attach(struct dvb_usb_device *d) +static int digitv_frontend_attach(struct dvb_usb_adapter *adap) { - if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) { - d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; + if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { + adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; return 0; } - if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) { - d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { + adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; return 0; } return -EIO; } -static int digitv_tuner_attach(struct dvb_usb_device *d) +static int digitv_tuner_attach(struct dvb_usb_adapter *adap) { - d->pll_addr = 0x60; - d->pll_desc = &dvb_pll_tded4; + adap->pll_addr = 0x60; + adap->pll_desc = &dvb_pll_tded4; return 0; } static struct dvb_usb_rc_key digitv_rc_keys[] = { - { 0x00, 0x16, KEY_POWER }, /* dummy key */ + { 0x5f, 0x55, KEY_0 }, + { 0x6f, 0x55, KEY_1 }, + { 0x9f, 0x55, KEY_2 }, + { 0xaf, 0x55, KEY_3 }, + { 0x5f, 0x56, KEY_4 }, + { 0x6f, 0x56, KEY_5 }, + { 0x9f, 0x56, KEY_6 }, + { 0xaf, 0x56, KEY_7 }, + { 0x5f, 0x59, KEY_8 }, + { 0x6f, 0x59, KEY_9 }, + { 0x9f, 0x59, KEY_TV }, + { 0xaf, 0x59, KEY_AUX }, + { 0x5f, 0x5a, KEY_DVD }, + { 0x6f, 0x5a, KEY_POWER }, + { 0x9f, 0x5a, KEY_MHP }, /* labelled 'Picture' */ + { 0xaf, 0x5a, KEY_AUDIO }, + { 0x5f, 0x65, KEY_INFO }, + { 0x6f, 0x65, KEY_F13 }, /* 16:9 */ + { 0x9f, 0x65, KEY_F14 }, /* 14:9 */ + { 0xaf, 0x65, KEY_EPG }, + { 0x5f, 0x66, KEY_EXIT }, + { 0x6f, 0x66, KEY_MENU }, + { 0x9f, 0x66, KEY_UP }, + { 0xaf, 0x66, KEY_DOWN }, + { 0x5f, 0x69, KEY_LEFT }, + { 0x6f, 0x69, KEY_RIGHT }, + { 0x9f, 0x69, KEY_ENTER }, + { 0xaf, 0x69, KEY_CHANNELUP }, + { 0x5f, 0x6a, KEY_CHANNELDOWN }, + { 0x6f, 0x6a, KEY_VOLUMEUP }, + { 0x9f, 0x6a, KEY_VOLUMEDOWN }, + { 0xaf, 0x6a, KEY_RED }, + { 0x5f, 0x95, KEY_GREEN }, + { 0x6f, 0x95, KEY_YELLOW }, + { 0x9f, 0x95, KEY_BLUE }, + { 0xaf, 0x95, KEY_SUBTITLE }, + { 0x5f, 0x96, KEY_F15 }, /* AD */ + { 0x6f, 0x96, KEY_TEXT }, + { 0x9f, 0x96, KEY_MUTE }, + { 0xaf, 0x96, KEY_REWIND }, + { 0x5f, 0x99, KEY_STOP }, + { 0x6f, 0x99, KEY_PLAY }, + { 0x9f, 0x99, KEY_FASTFORWARD }, + { 0xaf, 0x99, KEY_F16 }, /* chapter */ + { 0x5f, 0x9a, KEY_PAUSE }, + { 0x6f, 0x9a, KEY_PLAY }, + { 0x9f, 0x9a, KEY_RECORD }, + { 0xaf, 0x9a, KEY_F17 }, /* picture in picture */ + { 0x5f, 0xa5, KEY_KPPLUS }, /* zoom in */ + { 0x6f, 0xa5, KEY_KPMINUS }, /* zoom out */ + { 0x9f, 0xa5, KEY_F18 }, /* capture */ + { 0xaf, 0xa5, KEY_F19 }, /* web */ + { 0x5f, 0xa6, KEY_EMAIL }, + { 0x6f, 0xa6, KEY_PHONE }, + { 0x9f, 0xa6, KEY_PC }, }; -/* TODO is it really the NEC protocol ? */ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { + int i; u8 key[5]; + u8 b[4] = { 0 }; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4); - /* TODO state, maybe it is VV ? */ + + /* Tell the device we've read the remote. Not sure how necessary + this is, but the Nebula SDK does it. */ + digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + + /* if something is inside the buffer, simulate key press */ if (key[1] != 0) - key[0] = 0x01; /* if something is inside the buffer, simulate key press */ + { + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (d->props.rc_key_map[i].custom == key[1] && + d->props.rc_key_map[i].data == key[2]) { + *event = d->props.rc_key_map[i].event; + *state = REMOTE_KEY_PRESSED; + return 0; + } + } + } - /* call the universal NEC remote processor, to find out the key's state and event */ - dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); return 0; } /* DVB USB Driver stuff */ -static struct dvb_usb_properties digitv_properties; +static struct dvb_usb_device_properties digitv_properties; static int digitv_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -195,38 +265,41 @@ static struct usb_device_id digitv_table [] = { }; MODULE_DEVICE_TABLE (usb, digitv_table); -static struct dvb_usb_properties digitv_properties = { +static struct dvb_usb_device_properties digitv_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-digitv-02.fw", - .size_of_priv = 0, - - .frontend_attach = digitv_frontend_attach, - .tuner_attach = digitv_tuner_attach, + .num_adapters = 1, + .adapter = { + { + .frontend_attach = digitv_frontend_attach, + .tuner_attach = digitv_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .identify_state = digitv_identify_state, .rc_interval = 1000, .rc_key_map = digitv_rc_keys, .rc_key_map_size = ARRAY_SIZE(digitv_rc_keys), .rc_query = digitv_rc_query, - .identify_state = digitv_identify_state, - .i2c_algo = &digitv_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, .num_device_descs = 1, .devices = { diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 70afcfd141c..7dbe1432101 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -28,19 +28,19 @@ static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } -static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff) +static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 b_streaming[2] = { SET_STREAMING, onoff }; u8 b_rst_pid = RESET_PID_FILTER; - dvb_usb_generic_write(d,b_streaming,2); + dvb_usb_generic_write(adap->dev, b_streaming, 2); if (onoff == 0) - dvb_usb_generic_write(d,&b_rst_pid,1); + dvb_usb_generic_write(adap->dev, &b_rst_pid, 1); return 0; } -static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff) +static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { u8 b_pid[4]; pid = onoff ? pid : 0; @@ -50,7 +50,7 @@ static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int b_pid[2] = pid & 0xff; b_pid[3] = (pid >> 8) & 0x1f; - return dvb_usb_generic_write(d,b_pid,4); + return dvb_usb_generic_write(adap->dev, b_pid, 4); } /* remote control */ @@ -86,21 +86,23 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } -static int dtt200u_frontend_attach(struct dvb_usb_device *d) +static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) { - d->fe = dtt200u_fe_attach(d); + adap->fe = dtt200u_fe_attach(adap->dev); return 0; } -static struct dvb_usb_properties dtt200u_properties; -static struct dvb_usb_properties wt220u_properties; -static struct dvb_usb_properties wt220u_zl0353_properties; +static struct dvb_usb_device_properties dtt200u_properties; +static struct dvb_usb_device_properties wt220u_fc_properties; +static struct dvb_usb_device_properties wt220u_properties; +static struct dvb_usb_device_properties wt220u_zl0353_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0) return 0; @@ -114,32 +116,29 @@ static struct usb_device_id dtt200u_usb_table [] = { { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); -static struct dvb_usb_properties dtt200u_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, - .pid_filter_count = 15, - +static struct dvb_usb_device_properties dtt200u_properties = { .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-dtt200u-01.fw", - .power_ctrl = dtt200u_power_ctrl, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + .streaming_ctrl = dtt200u_streaming_ctrl, .pid_filter = dtt200u_pid_filter, .frontend_attach = dtt200u_frontend_attach, - - .rc_interval = 300, - .rc_key_map = dtt200u_rc_keys, - .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys), - .rc_query = dtt200u_rc_query, - - .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, + .stream = { + .type = USB_BULK, .count = 7, .endpoint = 0x02, .u = { @@ -148,6 +147,16 @@ static struct dvb_usb_properties dtt200u_properties = { } } }, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc_interval = 300, + .rc_key_map = dtt200u_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys), + .rc_query = dtt200u_rc_query, + + .generic_bulk_ctrl_endpoint = 0x01, .num_device_descs = 1, .devices = { @@ -159,17 +168,33 @@ static struct dvb_usb_properties dtt200u_properties = { } }; -static struct dvb_usb_properties wt220u_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, - .pid_filter_count = 15, - +static struct dvb_usb_device_properties wt220u_properties = { .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-wt220u-02.fw", - .power_ctrl = dtt200u_power_ctrl, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + .streaming_ctrl = dtt200u_streaming_ctrl, .pid_filter = dtt200u_pid_filter, .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .power_ctrl = dtt200u_power_ctrl, .rc_interval = 300, .rc_key_map = dtt200u_rc_keys, @@ -178,39 +203,88 @@ static struct dvb_usb_properties wt220u_properties = { .generic_bulk_ctrl_endpoint = 0x01, + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", + .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL }, + .warm_ids = { &dtt200u_usb_table[3], NULL }, + }, + { NULL }, + } +}; + +static struct dvb_usb_device_properties wt220u_fc_properties = { + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-fc03.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, + .stream = { + .type = USB_BULK, .count = 7, - .endpoint = 0x02, + .endpoint = 0x06, .u = { .bulk = { .buffersize = 4096, } } }, + } + }, + .power_ctrl = dtt200u_power_ctrl, + + .rc_interval = 300, + .rc_key_map = dtt200u_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys), + .rc_query = dtt200u_rc_query, + + .generic_bulk_ctrl_endpoint = 0x01, .num_device_descs = 1, .devices = { { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", - .cold_ids = { &dtt200u_usb_table[2], NULL }, - .warm_ids = { &dtt200u_usb_table[3], NULL }, + .cold_ids = { &dtt200u_usb_table[6], NULL }, + .warm_ids = { &dtt200u_usb_table[7], NULL }, }, { NULL }, } }; -static struct dvb_usb_properties wt220u_zl0353_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, - .pid_filter_count = 15, - +static struct dvb_usb_device_properties wt220u_zl0353_properties = { .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-wt220u-zl0353-01.fw", + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, .power_ctrl = dtt200u_power_ctrl, - .streaming_ctrl = dtt200u_streaming_ctrl, - .pid_filter = dtt200u_pid_filter, - .frontend_attach = dtt200u_frontend_attach, .rc_interval = 300, .rc_key_map = dtt200u_rc_keys, @@ -219,18 +293,6 @@ static struct dvb_usb_properties wt220u_zl0353_properties = { .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .num_device_descs = 1, .devices = { { .name = "WideView WT-220U PenType Receiver (based on ZL353)", @@ -271,6 +333,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h index a3460bf2d9f..35ab68f6dcf 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h @@ -14,31 +14,36 @@ extern int dvb_usb_debug; extern int dvb_usb_disable_rc_polling; -#define deb_info(args...) dprintk(dvb_usb_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args) -#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args) -#define deb_ts(args...) dprintk(dvb_usb_debug,0x08,args) -#define deb_err(args...) dprintk(dvb_usb_debug,0x10,args) -#define deb_rc(args...) dprintk(dvb_usb_debug,0x20,args) -#define deb_fw(args...) dprintk(dvb_usb_debug,0x40,args) -#define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args) +#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args) +#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args) +#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args) +#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args) +#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args) +#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args) +#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args) +#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args) +#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args) /* commonly used methods */ -extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *); +extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *); -extern int dvb_usb_urb_submit(struct dvb_usb_device *); -extern int dvb_usb_urb_kill(struct dvb_usb_device *); -extern int dvb_usb_urb_init(struct dvb_usb_device *); -extern int dvb_usb_urb_exit(struct dvb_usb_device *); +extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); + +extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); +extern int usb_urb_exit(struct usb_data_stream *stream); +extern int usb_urb_submit(struct usb_data_stream *stream); +extern int usb_urb_kill(struct usb_data_stream *stream); + +extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); extern int dvb_usb_i2c_init(struct dvb_usb_device *); extern int dvb_usb_i2c_exit(struct dvb_usb_device *); -extern int dvb_usb_dvb_init(struct dvb_usb_device *); -extern int dvb_usb_dvb_exit(struct dvb_usb_device *); - -extern int dvb_usb_fe_init(struct dvb_usb_device *); -extern int dvb_usb_fe_exit(struct dvb_usb_device *); +extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap); extern int dvb_usb_remote_init(struct dvb_usb_device *); extern int dvb_usb_remote_exit(struct dvb_usb_device *); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index ec631708c39..4561a672da9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -1,6 +1,6 @@ /* dvb-usb-dvb.c is part of the DVB USB library. * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * * This file contains functions for initializing and handling the @@ -8,55 +8,55 @@ */ #include "dvb-usb-common.h" +/* does the complete input transfer handling */ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) { - struct dvb_usb_device *d = dvbdmxfeed->demux->priv; + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; int newfeedcount,ret; - if (d == NULL) + if (adap == NULL) return -ENODEV; - newfeedcount = d->feedcount + (onoff ? 1 : -1); + newfeedcount = adap->feedcount + (onoff ? 1 : -1); - /* - * stop feed before setting a new pid if there will be no pid anymore - */ + /* stop feed before setting a new pid if there will be no pid anymore */ if (newfeedcount == 0) { deb_ts("stop feeding\n"); - dvb_usb_urb_kill(d); + usb_urb_kill(&adap->stream); - if (d->props.streaming_ctrl != NULL) - if ((ret = d->props.streaming_ctrl(d,0))) + if (adap->props.streaming_ctrl != NULL) + if ((ret = adap->props.streaming_ctrl(adap,0))) err("error while stopping stream."); - } - d->feedcount = newfeedcount; + adap->feedcount = newfeedcount; /* activate the pid on the device specific pid_filter */ - deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off"); - if (d->props.caps & DVB_USB_HAS_PID_FILTER && - d->pid_filtering && - d->props.pid_filter != NULL) - d->props.pid_filter(d,dvbdmxfeed->index,dvbdmxfeed->pid,onoff); + deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ? + "yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? + "on" : "off"); + if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->pid_filtering && + adap->props.pid_filter != NULL) + adap->props.pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid,onoff); /* start the feed if this was the first feed and there is still a feed * for reception. */ - if (d->feedcount == onoff && d->feedcount > 0) { + if (adap->feedcount == onoff && adap->feedcount > 0) { deb_ts("submitting all URBs\n"); - dvb_usb_urb_submit(d); + usb_urb_submit(&adap->stream); deb_ts("controlling pid parser\n"); - if (d->props.caps & DVB_USB_HAS_PID_FILTER && - d->props.caps & DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF && - d->props.pid_filter_ctrl != NULL) - if (d->props.pid_filter_ctrl(d,d->pid_filtering) < 0) + if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props.pid_filter_ctrl != NULL) + if (adap->props.pid_filter_ctrl(adap,adap->pid_filtering) < 0) err("could not handle pid_parser"); deb_ts("start feeding\n"); - if (d->props.streaming_ctrl != NULL) - if (d->props.streaming_ctrl(d,1)) { + if (adap->props.streaming_ctrl != NULL) + if (adap->props.streaming_ctrl(adap,1)) { err("error while enabling fifo."); return -ENODEV; } @@ -77,134 +77,130 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return dvb_usb_ctrl_feed(dvbdmxfeed,0); } -int dvb_usb_dvb_init(struct dvb_usb_device *d) +int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) { int ret; - if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name, - d->owner, &d->udev->dev)) < 0) { + if ((ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, + adap->dev->owner, &adap->dev->udev->dev)) < 0) { deb_info("dvb_register_adapter failed: error %d", ret); goto err; } - d->dvb_adap.priv = d; - - if (d->props.read_mac_address) { - if (d->props.read_mac_address(d,d->dvb_adap.proposed_mac) == 0) - info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",d->dvb_adap.proposed_mac[0], - d->dvb_adap.proposed_mac[1],d->dvb_adap.proposed_mac[2], - d->dvb_adap.proposed_mac[3],d->dvb_adap.proposed_mac[4], - d->dvb_adap.proposed_mac[5]); + adap->dvb_adap.priv = adap; + + if (adap->dev->props.read_mac_address) { + if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) + info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",adap->dvb_adap.proposed_mac[0], + adap->dvb_adap.proposed_mac[1], adap->dvb_adap.proposed_mac[2], + adap->dvb_adap.proposed_mac[3], adap->dvb_adap.proposed_mac[4], + adap->dvb_adap.proposed_mac[5]); else err("MAC address reading failed."); } - d->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - d->demux.priv = d; + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; - d->demux.feednum = d->demux.filternum = d->max_feed_count; - d->demux.start_feed = dvb_usb_start_feed; - d->demux.stop_feed = dvb_usb_stop_feed; - d->demux.write_to_decoder = NULL; - if ((ret = dvb_dmx_init(&d->demux)) < 0) { + adap->demux.feednum = adap->demux.filternum = adap->max_feed_count; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + if ((ret = dvb_dmx_init(&adap->demux)) < 0) { err("dvb_dmx_init failed: error %d",ret); goto err_dmx; } - d->dmxdev.filternum = d->demux.filternum; - d->dmxdev.demux = &d->demux.dmx; - d->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&d->dmxdev, &d->dvb_adap)) < 0) { + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) { err("dvb_dmxdev_init failed: error %d",ret); goto err_dmx_dev; } - dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx); + dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); - d->state |= DVB_USB_STATE_DVB; + adap->state |= DVB_USB_ADAP_STATE_DVB; return 0; err_dmx_dev: - dvb_dmx_release(&d->demux); + dvb_dmx_release(&adap->demux); err_dmx: - dvb_unregister_adapter(&d->dvb_adap); + dvb_unregister_adapter(&adap->dvb_adap); err: return ret; } -int dvb_usb_dvb_exit(struct dvb_usb_device *d) +int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) { - if (d->state & DVB_USB_STATE_DVB) { + if (adap->state & DVB_USB_ADAP_STATE_DVB) { deb_info("unregistering DVB part\n"); - dvb_net_release(&d->dvb_net); - d->demux.dmx.close(&d->demux.dmx); - dvb_dmxdev_release(&d->dmxdev); - dvb_dmx_release(&d->demux); - dvb_unregister_adapter(&d->dvb_adap); - d->state &= ~DVB_USB_STATE_DVB; + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + adap->state &= ~DVB_USB_ADAP_STATE_DVB; } return 0; } static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) { - struct dvb_usb_device *d = fe->dvb->priv; + struct dvb_usb_adapter *adap = fe->dvb->priv; - if (d->props.power_ctrl) - d->props.power_ctrl(d,1); + dvb_usb_device_power_ctrl(adap->dev, 1); - if (d->fe_init) - d->fe_init(fe); + if (adap->fe_init) + adap->fe_init(fe); return 0; } static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { - struct dvb_usb_device *d = fe->dvb->priv; + struct dvb_usb_adapter *adap = fe->dvb->priv; - if (d->fe_sleep) - d->fe_sleep(fe); + if (adap->fe_sleep) + adap->fe_sleep(fe); - if (d->props.power_ctrl) - d->props.power_ctrl(d,0); - - return 0; + return dvb_usb_device_power_ctrl(adap->dev, 0); } -int dvb_usb_fe_init(struct dvb_usb_device* d) +int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) { - if (d->props.frontend_attach == NULL) { - err("strange '%s' doesn't want to attach a frontend.",d->desc->name); + if (adap->props.frontend_attach == NULL) { + err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id); return 0; } - d->props.frontend_attach(d); - /* re-assign sleep and wakeup functions */ - if (d->fe != NULL) { - d->fe_init = d->fe->ops.init; d->fe->ops.init = dvb_usb_fe_wakeup; - d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep; + if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) { + adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep; - if (dvb_register_frontend(&d->dvb_adap, d->fe)) { + if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { err("Frontend registration failed."); - if (d->fe->ops.release) - d->fe->ops.release(d->fe); - d->fe = NULL; + dvb_frontend_detach(adap->fe); + adap->fe = NULL; return -ENODEV; } - } else - err("no frontend was attached by '%s'",d->desc->name); - if (d->props.tuner_attach != NULL) - d->props.tuner_attach(d); + /* only attach the tuner if the demod is there */ + if (adap->props.tuner_attach != NULL) + adap->props.tuner_attach(adap); + } else + err("no frontend was attached by '%s'",adap->dev->desc->name); return 0; } -int dvb_usb_fe_exit(struct dvb_usb_device *d) +int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) { - if (d->fe != NULL) - dvb_unregister_frontend(d->fe); + if (adap->fe != NULL) { + dvb_unregister_frontend(adap->fe); + dvb_frontend_detach(adap->fe); + } return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c index 9222b0a81f7..e1112e39fb6 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c @@ -1,6 +1,6 @@ /* dvb-usb-firmware.c is part of the DVB USB library. * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices. @@ -24,9 +24,6 @@ static struct usb_cypress_controller cypress[] = { { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, }; -static int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, - int *pos); - /* * load a firmware packet to the device */ @@ -78,7 +75,7 @@ int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw } EXPORT_SYMBOL(usb_cypress_load_firmware); -int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props) +int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props) { int ret; const struct firmware *fw = NULL; @@ -115,7 +112,7 @@ int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties return ret; } -static int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, +int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos) { u8 *b = (u8 *) &fw->data[*pos]; @@ -146,3 +143,4 @@ static int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, return *pos; } +EXPORT_SYMBOL(dvb_usb_get_hexline); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 6b611a72509..55ba020386c 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -1,6 +1,6 @@ /* dvb-usb-i2c.c is part of the DVB USB library. * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * * This file contains functions for (de-)initializing an I2C adapter. @@ -48,48 +48,48 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d) int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe) { - struct dvb_usb_device *d = fe->dvb->priv; - struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 }; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 }; int ret = 0; /* if pll_desc is not used */ - if (d->pll_desc == NULL) + if (adap->pll_desc == NULL) return 0; - if (d->tuner_pass_ctrl) - d->tuner_pass_ctrl(fe,1,d->pll_addr); + if (adap->tuner_pass_ctrl) + adap->tuner_pass_ctrl(fe, 1, adap->pll_addr); - deb_pll("pll init: %x\n",d->pll_addr); - deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1], - d->pll_init[2],d->pll_init[3]); + deb_pll("pll init: %x\n",adap->pll_addr); + deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1], + adap->pll_init[2], adap->pll_init[3]); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) { + if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) { err("tuner i2c write failed for pll_init."); ret = -EREMOTEIO; } msleep(1); - if (d->tuner_pass_ctrl) - d->tuner_pass_ctrl(fe,0,d->pll_addr); + if (adap->tuner_pass_ctrl) + adap->tuner_pass_ctrl(fe,0,adap->pll_addr); return ret; } EXPORT_SYMBOL(dvb_usb_tuner_init_i2c); int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len) { - struct dvb_usb_device *d = fe->dvb->priv; + struct dvb_usb_adapter *adap = fe->dvb->priv; if (buf_len != 5) return -EINVAL; - if (d->pll_desc == NULL) + if (adap->pll_desc == NULL) return 0; - deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc); + deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc); - b[0] = d->pll_addr; - dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth); + b[0] = adap->pll_addr; + dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth); deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]); @@ -99,26 +99,27 @@ EXPORT_SYMBOL(dvb_usb_tuner_calc_regs); int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { - struct dvb_usb_device *d = fe->dvb->priv; + struct dvb_usb_adapter *adap = fe->dvb->priv; int ret = 0; u8 b[5]; - struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 }; + struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 }; dvb_usb_tuner_calc_regs(fe,fep,b,5); - if (d->tuner_pass_ctrl) - d->tuner_pass_ctrl(fe,1,d->pll_addr); + if (adap->tuner_pass_ctrl) + adap->tuner_pass_ctrl(fe, 1, adap->pll_addr); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) { + + if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) { err("tuner i2c write failed for pll_set."); ret = -EREMOTEIO; } msleep(1); - if (d->tuner_pass_ctrl) - d->tuner_pass_ctrl(fe,0,d->pll_addr); + if (adap->tuner_pass_ctrl) + adap->tuner_pass_ctrl(fe, 0, adap->pll_addr); return ret; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 95698918bc1..299382dcb81 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -10,51 +10,56 @@ #define _DVB_USB_IDS_H_ /* Vendor IDs */ -#define USB_VID_ADSTECH 0x06e1 -#define USB_VID_ANCHOR 0x0547 -#define USB_VID_WIDEVIEW 0x14aa -#define USB_VID_AVERMEDIA 0x07ca -#define USB_VID_COMPRO 0x185b -#define USB_VID_COMPRO_UNK 0x145f -#define USB_VID_CYPRESS 0x04b4 -#define USB_VID_DIBCOM 0x10b8 -#define USB_VID_DVICO 0x0fe9 -#define USB_VID_EMPIA 0xeb1a -#define USB_VID_GRANDTEC 0x5032 -#define USB_VID_HANFTEK 0x15f4 -#define USB_VID_HAUPPAUGE 0x2040 -#define USB_VID_HYPER_PALTEK 0x1025 -#define USB_VID_KWORLD 0xeb2a -#define USB_VID_KYE 0x0458 -#define USB_VID_MEDION 0x1660 -#define USB_VID_PINNACLE 0x2304 -#define USB_VID_VISIONPLUS 0x13d3 -#define USB_VID_TWINHAN 0x1822 -#define USB_VID_ULTIMA_ELECTRONIC 0x05d8 -#define USB_VID_GENPIX 0x09c0 +#define USB_VID_ADSTECH 0x06e1 +#define USB_VID_ANCHOR 0x0547 +#define USB_VID_AVERMEDIA 0x07ca +#define USB_VID_COMPRO 0x185b +#define USB_VID_COMPRO_UNK 0x145f +#define USB_VID_CYPRESS 0x04b4 +#define USB_VID_DIBCOM 0x10b8 +#define USB_VID_DVICO 0x0fe9 +#define USB_VID_EMPIA 0xeb1a +#define USB_VID_GENPIX 0x09c0 +#define USB_VID_GRANDTEC 0x5032 +#define USB_VID_HANFTEK 0x15f4 +#define USB_VID_HAUPPAUGE 0x2040 +#define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_KWORLD 0xeb2a +#define USB_VID_KYE 0x0458 +#define USB_VID_LEADTEK 0x0413 +#define USB_VID_LITEON 0x04ca +#define USB_VID_MEDION 0x1660 +#define USB_VID_PINNACLE 0x2304 +#define USB_VID_VISIONPLUS 0x13d3 +#define USB_VID_TWINHAN 0x1822 +#define USB_VID_ULTIMA_ELECTRONIC 0x05d8 +#define USB_VID_UNIWILL 0x1584 +#define USB_VID_WIDEVIEW 0x14aa /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 #define USB_PID_ADSTECH_USB2_WARM 0xa334 -#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 -#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 -#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 -#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801 -#define USB_PID_COMPRO_DVBU2000_COLD 0xd000 -#define USB_PID_COMPRO_DVBU2000_WARM 0xd001 -#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c -#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d +#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 +#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 +#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 +#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801 +#define USB_PID_COMPRO_DVBU2000_COLD 0xd000 +#define USB_PID_COMPRO_DVBU2000_WARM 0xd001 +#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c +#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d +#define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 -#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 +#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 #define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9 #define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6 #define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 -#define USB_PID_DIBCOM_STK7700 0x1e14 -#define USB_PID_DIBCOM_STK7700_REENUM 0x1e15 -#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 -#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 -#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 +#define USB_PID_DIBCOM_STK7700P 0x1e14 +#define USB_PID_DIBCOM_STK7700P_PC 0x1e78 +#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 +#define USB_PID_UNIWILL_STK7700P 0x6003 +#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 +#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df #define USB_PID_TWINHAN_VP7041_COLD 0x3201 @@ -69,25 +74,36 @@ #define USB_PID_DNTV_TINYUSB2_WARM 0x3224 #define USB_PID_ULTIMA_TVBOX_COLD 0x8105 #define USB_PID_ULTIMA_TVBOX_WARM 0x8106 -#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107 -#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108 -#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235 -#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109 -#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a -#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 -#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 -#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e -#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f -#define USB_PID_HANFTEK_UMT_010_COLD 0x0001 -#define USB_PID_HANFTEK_UMT_010_WARM 0x0015 +#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107 +#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108 +#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235 +#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109 +#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a +#define USB_PID_ARTEC_T14_COLD 0x810b +#define USB_PID_ARTEC_T14_WARM 0x810c +#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 +#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 +#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e +#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f +#define USB_PID_HANFTEK_UMT_010_COLD 0x0001 +#define USB_PID_HANFTEK_UMT_010_WARM 0x0015 #define USB_PID_DTT200U_COLD 0x0201 #define USB_PID_DTT200U_WARM 0x0301 -#define USB_PID_WT220U_COLD 0x0222 -#define USB_PID_WT220U_WARM 0x0221 +#define USB_PID_WT220U_ZAP250_COLD 0x0220 +#define USB_PID_WT220U_COLD 0x0222 +#define USB_PID_WT220U_WARM 0x0221 +#define USB_PID_WT220U_FC_COLD 0x0225 +#define USB_PID_WT220U_FC_WARM 0x0226 #define USB_PID_WT220U_ZL0353_COLD 0x022a #define USB_PID_WT220U_ZL0353_WARM 0x022b -#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 -#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 +#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 +#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 +#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941 +#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 +#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 +#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_AVERMEDIA_VOLAR 0xa807 +#define USB_PID_AVERMEDIA_VOLAR_2 0xb808 #define USB_PID_NEBULA_DIGITV 0x0201 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 @@ -96,15 +112,28 @@ #define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01 #define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10 #define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11 -#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD 0xdb50 -#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM 0xdb51 -#define USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_COLD 0xdb54 -#define USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_WARM 0xdb55 +#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD 0xdb50 +#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51 +#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 +#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 +#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_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f -#define USB_PID_PCTV_200E 0x020e -#define USB_PID_PCTV_400E 0x020f -#define USB_PID_GENPIX_8PSK_COLD 0x0200 -#define USB_PID_GENPIX_8PSK_WARM 0x0201 +#define USB_PID_PCTV_200E 0x020e +#define USB_PID_PCTV_400E 0x020f +#define USB_PID_LITEON_DVB_T_COLD 0xf000 +#define USB_PID_LITEON_DVB_T_WARM 0xf001 +#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360 +#define USB_PID_DIGIVOX_MINI_SL_WARM 0xe361 +#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6 +#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7 +#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 +#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 +#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 +#define USB_PID_GENPIX_8PSK_COLD 0x0200 +#define USB_PID_GENPIX_8PSK_WARM 0x0201 + + #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index a1705ecb9a5..ffdde83d1e7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -3,7 +3,7 @@ * * dvb-usb-init.c * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * * 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 @@ -16,21 +16,105 @@ /* debug */ int dvb_usb_debug; module_param_named(debug,dvb_usb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS); int dvb_usb_disable_rc_polling; module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); +static int dvb_usb_force_pid_filter_usage; +module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); +MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); + +static int dvb_usb_adapter_init(struct dvb_usb_device *d) +{ + struct dvb_usb_adapter *adap; + int ret,n; + + for (n = 0; n < d->props.num_adapters; n++) { + adap = &d->adapter[n]; + adap->dev = d; + adap->id = n; + + memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); + +/* speed - when running at FULL speed we need a HW PID filter */ + if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); + return -ENODEV; + } + + if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props.pid_filter_count; + } else { + info("will pass the complete MPEG2 transport stream to the software demuxer."); + adap->pid_filtering = 0; + adap->max_feed_count = 255; + } + + if (!adap->pid_filtering && + dvb_usb_force_pid_filter_usage && + adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) { + info("pid filter enabled by module option."); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props.pid_filter_count; + } + + if (adap->props.size_of_priv > 0) { + adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL); + if (adap->priv == NULL) { + err("no memory for priv for adapter %d.",n); + return -ENOMEM; + } + } + + if ((ret = dvb_usb_adapter_stream_init(adap)) || + (ret = dvb_usb_adapter_dvb_init(adap)) || + (ret = dvb_usb_adapter_frontend_init(adap))) { + return ret; + } + + d->num_adapters_initialized++; + d->state |= DVB_USB_STATE_DVB; + } + + /* + * when reloading the driver w/o replugging the device + * sometimes a timeout occures, this helps + */ + if (d->props.generic_bulk_ctrl_endpoint != 0) { + usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint)); + } + + return 0; +} + +static int dvb_usb_adapter_exit(struct dvb_usb_device *d) +{ + int n; + for (n = 0; n < d->num_adapters_initialized; n++) { + dvb_usb_adapter_frontend_exit(&d->adapter[n]); + dvb_usb_adapter_dvb_exit(&d->adapter[n]); + dvb_usb_adapter_stream_exit(&d->adapter[n]); + kfree(d->adapter[n].priv); + } + d->num_adapters_initialized = 0; + d->state &= ~DVB_USB_STATE_DVB; + return 0; +} + + /* general initialization functions */ static int dvb_usb_exit(struct dvb_usb_device *d) { deb_info("state before exiting everything: %x\n",d->state); dvb_usb_remote_exit(d); - dvb_usb_fe_exit(d); + dvb_usb_adapter_exit(d); dvb_usb_i2c_exit(d); - dvb_usb_dvb_exit(d); - dvb_usb_urb_exit(d); deb_info("state should be zero now: %x\n",d->state); d->state = DVB_USB_STATE_INIT; kfree(d->priv); @@ -47,32 +131,19 @@ static int dvb_usb_init(struct dvb_usb_device *d) d->state = DVB_USB_STATE_INIT; -/* check the capabilities and set appropriate variables */ - -/* speed - when running at FULL speed we need a HW PID filter */ - if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) { - err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); - return -ENODEV; - } - - if ((d->udev->speed == USB_SPEED_FULL && d->props.caps & DVB_USB_HAS_PID_FILTER) || - (d->props.caps & DVB_USB_NEED_PID_FILTERING)) { - info("will use the device's hardware PID filter (table count: %d).",d->props.pid_filter_count); - d->pid_filtering = 1; - d->max_feed_count = d->props.pid_filter_count; - } else { - info("will pass the complete MPEG2 transport stream to the software demuxer."); - d->pid_filtering = 0; - d->max_feed_count = 255; + if (d->props.size_of_priv > 0) { + d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL); + if (d->priv == NULL) { + err("no memory for priv in 'struct dvb_usb_device'"); + return -ENOMEM; + } } - if (d->props.power_ctrl) - d->props.power_ctrl(d,1); +/* check the capabilities and set appropriate variables */ + dvb_usb_device_power_ctrl(d, 1); - if ((ret = dvb_usb_urb_init(d)) || - (ret = dvb_usb_dvb_init(d)) || - (ret = dvb_usb_i2c_init(d)) || - (ret = dvb_usb_fe_init(d))) { + if ((ret = dvb_usb_i2c_init(d)) || + (ret = dvb_usb_adapter_init(d))) { dvb_usb_exit(d); return ret; } @@ -80,14 +151,13 @@ static int dvb_usb_init(struct dvb_usb_device *d) if ((ret = dvb_usb_remote_init(d))) err("could not initialize remote control."); - if (d->props.power_ctrl) - d->props.power_ctrl(d,0); + dvb_usb_device_power_ctrl(d, 0); return 0; } /* determine the name and the state of the just found USB device */ -static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_properties *props, int *cold) +static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold) { int i,j; struct dvb_usb_device_description *desc = NULL; @@ -125,11 +195,25 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device return desc; } +int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + if (onoff) + d->powered++; + else + d->powered--; + + if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1 + deb_info("power control: %d\n", onoff); + if (d->props.power_ctrl) + return d->props.power_ctrl(d, onoff); + } + return 0; +} + /* * USB */ - -int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties +int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_device_properties *props, struct module *owner,struct dvb_usb_device **du) { struct usb_device *udev = interface_to_usbdev(intf); @@ -149,7 +233,7 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties if (cold) { info("found a '%s' in cold state, will try to load a firmware",desc->name); ret = dvb_usb_download_firmware(udev,props); - if (!props->no_reconnect) + if (!props->no_reconnect || ret != 0) return ret; } @@ -161,19 +245,10 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties } d->udev = udev; - memcpy(&d->props,props,sizeof(struct dvb_usb_properties)); + memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties)); d->desc = desc; d->owner = owner; - if (d->props.size_of_priv > 0) { - d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL); - if (d->priv == NULL) { - err("no memory for priv in 'struct dvb_usb_device'"); - kfree(d); - return -ENOMEM; - } - } - usb_set_intfdata(intf, d); if (du != NULL) @@ -204,7 +279,7 @@ void dvb_usb_device_exit(struct usb_interface *intf) } EXPORT_SYMBOL(dvb_usb_device_exit); -MODULE_VERSION("0.3"); +MODULE_VERSION("1.0"); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index e5c6d9835e0..19ff5978bc9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -1,20 +1,22 @@ /* dvb-usb-remote.c is part of the DVB USB library. * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * * This file contains functions for initializing the the input-device and for handling remote-control-queries. */ #include "dvb-usb-common.h" +#include <linux/usb/input.h> /* Remote-control poll function - called every dib->rc_query_interval ms to see * whether the remote control has received anything. * * TODO: Fix the repeat rate of the input device. */ -static void dvb_usb_read_remote_control(void *data) +static void dvb_usb_read_remote_control(struct work_struct *work) { - struct dvb_usb_device *d = data; + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); u32 event; int state; @@ -88,7 +90,9 @@ schedule: int dvb_usb_remote_init(struct dvb_usb_device *d) { + struct input_dev *input_dev; int i; + int err; if (d->props.rc_key_map == NULL || d->props.rc_query == NULL || @@ -96,23 +100,26 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) return 0; usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcpy(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - d->rc_input_dev = input_allocate_device(); - if (!d->rc_input_dev) + input_dev = input_allocate_device(); + if (!input_dev) return -ENOMEM; - d->rc_input_dev->evbit[0] = BIT(EV_KEY); - d->rc_input_dev->keycodesize = sizeof(unsigned char); - d->rc_input_dev->keycodemax = KEY_MAX; - d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver"; - d->rc_input_dev->phys = d->rc_phys; + input_dev->evbit[0] = BIT(EV_KEY); + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = KEY_MAX; + input_dev->name = "IR-receiver inside an USB DVB receiver"; + input_dev->phys = d->rc_phys; + usb_to_input_id(d->udev, &input_dev->id); + input_dev->cdev.dev = &d->udev->dev; /* set the bits for the keys */ deb_rc("key map size: %d\n", d->props.rc_key_map_size); for (i = 0; i < d->props.rc_key_map_size; i++) { - deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i); - set_bit(d->props.rc_key_map[i].event, d->rc_input_dev->keybit); + deb_rc("setting bit for event %d item %d\n", + d->props.rc_key_map[i].event, i); + set_bit(d->props.rc_key_map[i].event, input_dev->keybit); } /* Start the remote-control polling. */ @@ -120,12 +127,18 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) d->props.rc_interval = 100; /* default */ /* setting these two values to non-zero, we have to manage key repeats */ - d->rc_input_dev->rep[REP_PERIOD] = d->props.rc_interval; - d->rc_input_dev->rep[REP_DELAY] = d->props.rc_interval + 150; + input_dev->rep[REP_PERIOD] = d->props.rc_interval; + input_dev->rep[REP_DELAY] = d->props.rc_interval + 150; - input_register_device(d->rc_input_dev); + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + + d->rc_input_dev = input_dev; - INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d); + INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); info("schedule remote query interval to %d msecs.", d->props.rc_interval); schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index 9002f35aa95..5cef12a07f7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -1,9 +1,9 @@ /* dvb-usb-urb.c is part of the DVB USB library. * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * - * This file contains functions for initializing and handling the + * This file keeps functions for initializing and handling the * USB and URB stuff. */ #include "dvb-usb-common.h" @@ -64,261 +64,32 @@ int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) } EXPORT_SYMBOL(dvb_usb_generic_write); - -/* URB stuff for streaming */ -static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) -{ - struct dvb_usb_device *d = urb->context; - int ptype = usb_pipetype(urb->pipe); - int i; - u8 *b; - - deb_ts("'%s' urb completed. feedcount: %d, status: %d, length: %d/%d, pack_num: %d, errors: %d\n", - ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", d->feedcount, - urb->status,urb->actual_length,urb->transfer_buffer_length, - urb->number_of_packets,urb->error_count); - - switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - deb_ts("urb completition error %d.", urb->status); - break; - } - - if (d->feedcount > 0) { - if (d->state & DVB_USB_STATE_DVB) { - switch (ptype) { - case PIPE_ISOCHRONOUS: - b = (u8 *) urb->transfer_buffer; - for (i = 0; i < urb->number_of_packets; i++) { - if (urb->iso_frame_desc[i].status != 0) - deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); - else if (urb->iso_frame_desc[i].actual_length > 0) { - dvb_dmx_swfilter(&d->demux,b + urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - } - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - debug_dump(b,20,deb_ts); - break; - case PIPE_BULK: - if (urb->actual_length > 0) - dvb_dmx_swfilter(&d->demux, (u8 *) urb->transfer_buffer,urb->actual_length); - break; - default: - err("unkown endpoint type in completition handler."); - return; - } - } - } - - usb_submit_urb(urb,GFP_ATOMIC); -} - -int dvb_usb_urb_kill(struct dvb_usb_device *d) -{ - int i; - for (i = 0; i < d->urbs_submitted; i++) { - deb_ts("killing URB no. %d.\n",i); - - /* stop the URB */ - usb_kill_urb(d->urb_list[i]); - } - d->urbs_submitted = 0; - return 0; -} - -int dvb_usb_urb_submit(struct dvb_usb_device *d) -{ - int i,ret; - for (i = 0; i < d->urbs_initialized; i++) { - deb_ts("submitting URB no. %d\n",i); - if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) { - err("could not submit URB no. %d - get them all back",i); - dvb_usb_urb_kill(d); - return ret; - } - d->urbs_submitted++; - } - return 0; -} - -static int dvb_usb_free_stream_buffers(struct dvb_usb_device *d) -{ - if (d->state & DVB_USB_STATE_URB_BUF) { - while (d->buf_num) { - d->buf_num--; - deb_mem("freeing buffer %d\n",d->buf_num); - usb_buffer_free(d->udev, d->buf_size, - d->buf_list[d->buf_num], d->dma_addr[d->buf_num]); - } - kfree(d->buf_list); - kfree(d->dma_addr); - } - - d->state &= ~DVB_USB_STATE_URB_BUF; - - return 0; -} - -static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, unsigned long size) -{ - d->buf_num = 0; - d->buf_size = size; - - deb_mem("all in all I will use %lu bytes for streaming\n",num*size); - - if ((d->buf_list = kcalloc(num, sizeof(u8 *), GFP_ATOMIC)) == NULL) - return -ENOMEM; - - if ((d->dma_addr = kcalloc(num, sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) { - kfree(d->buf_list); - return -ENOMEM; - } - - d->state |= DVB_USB_STATE_URB_BUF; - - for (d->buf_num = 0; d->buf_num < num; d->buf_num++) { - deb_mem("allocating buffer %d\n",d->buf_num); - if (( d->buf_list[d->buf_num] = - usb_buffer_alloc(d->udev, size, SLAB_ATOMIC, - &d->dma_addr[d->buf_num]) ) == NULL) { - deb_mem("not enough memory for urb-buffer allocation.\n"); - dvb_usb_free_stream_buffers(d); - return -ENOMEM; - } - deb_mem("buffer %d: %p (dma: %llu)\n", - d->buf_num, d->buf_list[d->buf_num], - (unsigned long long)d->dma_addr[d->buf_num]); - memset(d->buf_list[d->buf_num],0,size); - } - deb_mem("allocation successful\n"); - - return 0; -} - -static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d) +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length) { - int i; - - if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count, - d->props.urb.u.bulk.buffersize)) < 0) - return i; - - /* allocate the URBs */ - for (i = 0; i < d->props.urb.count; i++) { - if ((d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL) - return -ENOMEM; - - usb_fill_bulk_urb( d->urb_list[i], d->udev, - usb_rcvbulkpipe(d->udev,d->props.urb.endpoint), - d->buf_list[i], - d->props.urb.u.bulk.buffersize, - dvb_usb_urb_complete, d); - - d->urb_list[i]->transfer_flags = 0; - d->urbs_initialized++; - } - return 0; + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter(&adap->demux, buffer, length); } -static int dvb_usb_isoc_urb_init(struct dvb_usb_device *d) +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length) { - int i,j; - - if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count, - d->props.urb.u.isoc.framesize*d->props.urb.u.isoc.framesperurb)) < 0) - return i; - - /* allocate the URBs */ - for (i = 0; i < d->props.urb.count; i++) { - struct urb *urb; - int frame_offset = 0; - if ((d->urb_list[i] = - usb_alloc_urb(d->props.urb.u.isoc.framesperurb,GFP_ATOMIC)) == NULL) - return -ENOMEM; - - urb = d->urb_list[i]; - - urb->dev = d->udev; - urb->context = d; - urb->complete = dvb_usb_urb_complete; - urb->pipe = usb_rcvisocpipe(d->udev,d->props.urb.endpoint); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = d->props.urb.u.isoc.interval; - urb->number_of_packets = d->props.urb.u.isoc.framesperurb; - urb->transfer_buffer_length = d->buf_size; - urb->transfer_buffer = d->buf_list[i]; - urb->transfer_dma = d->dma_addr[i]; - - for (j = 0; j < d->props.urb.u.isoc.framesperurb; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = d->props.urb.u.isoc.framesize; - frame_offset += d->props.urb.u.isoc.framesize; - } - - d->urbs_initialized++; - } - return 0; - + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_204(&adap->demux, buffer, length); } -int dvb_usb_urb_init(struct dvb_usb_device *d) +int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) { - /* - * when reloading the driver w/o replugging the device - * sometimes a timeout occures, this helps - */ - if (d->props.generic_bulk_ctrl_endpoint != 0) { - usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint)); - } - usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.urb.endpoint)); - - /* allocate the array for the data transfer URBs */ - d->urb_list = kzalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL); - if (d->urb_list == NULL) - return -ENOMEM; - d->state |= DVB_USB_STATE_URB_LIST; - - switch (d->props.urb.type) { - case DVB_USB_BULK: - return dvb_usb_bulk_urb_init(d); - case DVB_USB_ISOC: - return dvb_usb_isoc_urb_init(d); - default: - err("unkown URB-type for data transfer."); - return -EINVAL; - } + adap->stream.udev = adap->dev->udev; + if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) + adap->stream.complete = dvb_usb_data_complete_204; + else + adap->stream.complete = dvb_usb_data_complete; + adap->stream.user_priv = adap; + return usb_urb_init(&adap->stream, &adap->props.stream); } -int dvb_usb_urb_exit(struct dvb_usb_device *d) +int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) { - int i; - - dvb_usb_urb_kill(d); - - if (d->state & DVB_USB_STATE_URB_LIST) { - for (i = 0; i < d->urbs_initialized; i++) { - if (d->urb_list[i] != NULL) { - deb_mem("freeing URB no. %d.\n",i); - /* free the URBs */ - usb_free_urb(d->urb_list[i]); - } - } - d->urbs_initialized = 0; - /* free the urb array */ - kfree(d->urb_list); - d->state &= ~DVB_USB_STATE_URB_LIST; - } - - dvb_usb_free_stream_buffers(d); - return 0; + return usb_urb_exit(&adap->stream); } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 97f8ea96243..0d721731a52 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -1,9 +1,11 @@ /* dvb-usb.h is part of the DVB USB library. * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * * the headerfile, all dvb-usb-drivers have to include. + * + * TODO: clean-up the structures for unused fields and update the comments */ #ifndef __DVB_USB_H__ #define __DVB_USB_H__ @@ -84,36 +86,84 @@ struct dvb_usb_rc_key { }; struct dvb_usb_device; +struct dvb_usb_adapter; +struct usb_data_stream; + +/** + * Properties of USB streaming - TODO this structure should be somewhere else + * describes the kind of USB transfer used for data-streaming. + * (BULK or ISOC) + */ +struct usb_data_stream_properties { +#define USB_BULK 1 +#define USB_ISOC 2 + int type; + int count; + int endpoint; + + union { + struct { + int buffersize; /* per URB */ + } bulk; + struct { + int framesperurb; + int framesize; + int interval; + } isoc; + } u; +}; /** - * struct dvb_usb_properties - properties of a dvb-usb-device + * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. + * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. * @caps: capabilities of the DVB USB device. * @pid_filter_count: number of PID filter position in the optional hardware * PID-filter. - * + * @streaming_crtl: called to start and stop the MPEG2-TS streaming of the + * device (not URB submitting/killing). + * @pid_filter_ctrl: called to en/disable the PID filter, if any. + * @pid_filter: called to set/unset a PID for filtering. + * @frontend_attach: called to attach the possible frontends (fill fe-field + * of struct dvb_usb_device). + * @tuner_attach: called to attach the correct tuner and to fill pll_addr, + * pll_desc and pll_init_buf of struct dvb_usb_device). + * @stream: configuration of the USB streaming + */ +struct dvb_usb_adapter_properties { +#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 +#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 +#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 +#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 + int caps; + int pid_filter_count; + + int (*streaming_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); + + int (*frontend_attach) (struct dvb_usb_adapter *); + int (*tuner_attach) (struct dvb_usb_adapter *); + + struct usb_data_stream_properties stream; + + int size_of_priv; +}; + +/** + * struct dvb_usb_device_properties - properties of a dvb-usb-device * @usb_ctrl: which USB device-side controller is in use. Needed for firmware * download. * @firmware: name of the firmware file. * @download_firmware: called to download the firmware when the usb_ctrl is * DEVICE_SPECIFIC. * @no_reconnect: device doesn't do a reconnect after downloading the firmware, - so do the warm initialization right after it - + * so do the warm initialization right after it + * * @size_of_priv: how many bytes shall be allocated for the private field * of struct dvb_usb_device. * * @power_ctrl: called to enable/disable power of the device. - * @streaming_crtl: called to start and stop the MPEG2-TS streaming of the - * device (not URB submitting/killing). - * @pid_filter_ctrl: called to en/disable the PID filter, if any. - * @pid_filter: called to set/unset a PID for filtering. - * * @read_mac_address: called to read the MAC address of the device. - * - * @frontend_attach: called to attach the possible frontends (fill fe-field - * of struct dvb_usb_device). - * @tuner_attach: called to attach the correct tuner and to fill pll_addr, - * pll_desc and pll_init_buf of struct dvb_usb_device). * @identify_state: called to determine the state (cold or warm), when it * is not distinguishable by the USB IDs. * @@ -130,50 +180,40 @@ struct dvb_usb_device; * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write- * helper functions. * - * @urb: describes the kind of USB transfer used for MPEG2-TS-streaming. - * (BULK or ISOC) - * * @num_device_descs: number of struct dvb_usb_device_description in @devices * @devices: array of struct dvb_usb_device_description compatibles with these * properties. */ -struct dvb_usb_properties { +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 +struct dvb_usb_device_properties { -#define DVB_USB_HAS_PID_FILTER 0x01 -#define DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF 0x02 -#define DVB_USB_NEED_PID_FILTERING 0x04 -#define DVB_USB_IS_AN_I2C_ADAPTER 0x08 +#define DVB_USB_IS_AN_I2C_ADAPTER 0x01 int caps; - int pid_filter_count; #define DEVICE_SPECIFIC 0 #define CYPRESS_AN2135 1 #define CYPRESS_AN2235 2 #define CYPRESS_FX2 3 - int usb_ctrl; + int usb_ctrl; + int (*download_firmware) (struct usb_device *, const struct firmware *); const char firmware[FIRMWARE_NAME_MAX]; - int (*download_firmware) (struct usb_device *, const struct firmware *); - int no_reconnect; + int no_reconnect; int size_of_priv; - int (*power_ctrl) (struct dvb_usb_device *, int); - int (*streaming_ctrl) (struct dvb_usb_device *, int); - int (*pid_filter_ctrl) (struct dvb_usb_device *, int); - int (*pid_filter) (struct dvb_usb_device *, int, u16, int); + int num_adapters; + struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + int (*power_ctrl) (struct dvb_usb_device *, int); int (*read_mac_address) (struct dvb_usb_device *, u8 []); - int (*frontend_attach) (struct dvb_usb_device *); - int (*tuner_attach) (struct dvb_usb_device *); - - int (*identify_state) (struct usb_device *, struct dvb_usb_properties *, + int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *, struct dvb_usb_device_description **, int *); /* remote control properties */ #define REMOTE_NO_KEY_PRESSED 0x00 #define REMOTE_KEY_PRESSED 0x01 #define REMOTE_KEY_REPEAT 0x02 - struct dvb_usb_rc_key *rc_key_map; + struct dvb_usb_rc_key *rc_key_map; int rc_key_map_size; int (*rc_query) (struct dvb_usb_device *, u32 *, int *); int rc_interval; @@ -182,40 +222,12 @@ struct dvb_usb_properties { int generic_bulk_ctrl_endpoint; - struct { -#define DVB_USB_BULK 1 -#define DVB_USB_ISOC 2 - int type; - int count; - int endpoint; - - union { - struct { - int buffersize; /* per URB */ - } bulk; - struct { - int framesperurb; - int framesize; - int interval; - } isoc; - } u; - } urb; - int num_device_descs; struct dvb_usb_device_description devices[9]; }; - /** - * struct dvb_usb_device - object of a DVB USB device - * @props: copy of the struct dvb_usb_properties this device belongs to. - * @desc: pointer to the device's struct dvb_usb_device_description. - * @state: initialization and runtime state of the device. - * - * @udev: pointer to the device's struct usb_device. - * @urb_list: array of dynamically allocated struct urb for the MPEG2-TS- - * streaming. - * + * struct usb_data_stream - generic object of an USB stream * @buf_num: number of buffer allocated. * @buf_size: size of each buffer in buf_list. * @buf_list: array containing all allocate buffers for streaming. @@ -223,18 +235,40 @@ struct dvb_usb_properties { * * @urbs_initialized: number of URBs initialized. * @urbs_submitted: number of URBs submitted. + */ +#define MAX_NO_URBS_FOR_DATA_STREAM 10 +struct usb_data_stream { + struct usb_device *udev; + struct usb_data_stream_properties props; + +#define USB_STATE_INIT 0x00 +#define USB_STATE_URB_BUF 0x01 + int state; + + void (*complete) (struct usb_data_stream *, u8 *, size_t); + + struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; + dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; + + int urbs_initialized; + int urbs_submitted; + + void *user_priv; +}; + +/** + * struct dvb_usb_adapter - a DVB adapter on a USB device + * @id: index of this adapter (starting with 0). * * @feedcount: number of reqested feeds (used for streaming-activation) * @pid_filtering: is hardware pid_filtering used or not. * - * @usb_mutex: semaphore of USB control messages (reading needs two messages) - * @i2c_mutex: semaphore for i2c-transfers - * - * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB * @pll_addr: I2C address of the tuner for programming * @pll_init: array containing the initialization buffer * @pll_desc: pointer to the appropriate struct dvb_pll_desc - * * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board * * @dvb_adap: device's dvb_adapter. @@ -244,8 +278,62 @@ struct dvb_usb_properties { * @dvb_frontend: device's frontend. * @max_feed_count: how many feeds can be handled simultaneously by this * device + * + * @fe_init: rerouted frontend-init (wakeup) function. * @fe_sleep: rerouted frontend-sleep function. - * @fe_init: rerouted frontend-init (wakeup) function. + * + * @stream: the usb data stream. + */ +struct dvb_usb_adapter { + struct dvb_usb_device *dev; + struct dvb_usb_adapter_properties props; + +#define DVB_USB_ADAP_STATE_INIT 0x000 +#define DVB_USB_ADAP_STATE_DVB 0x001 + int state; + + u8 id; + + int feedcount; + int pid_filtering; + + /* tuner programming information */ + u8 pll_addr; + u8 pll_init[4]; + struct dvb_pll_desc *pll_desc; + int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8); + + /* dvb */ + struct dvb_adapter dvb_adap; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvb_net; + struct dvb_frontend *fe; + int max_feed_count; + + int (*fe_init) (struct dvb_frontend *); + int (*fe_sleep) (struct dvb_frontend *); + + struct usb_data_stream stream; + + void *priv; +}; + +/** + * struct dvb_usb_device - object of a DVB USB device + * @props: copy of the struct dvb_usb_properties this device belongs to. + * @desc: pointer to the device's struct dvb_usb_device_description. + * @state: initialization and runtime state of the device. + * + * @powered: indicated whether the device is power or not. + * Powered is in/decremented for each call to modify the state. + * @udev: pointer to the device's struct usb_device. + * + * @usb_mutex: semaphore of USB control messages (reading needs two messages) + * @i2c_mutex: semaphore for i2c-transfers + * + * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB + * * @rc_input_dev: input device for the remote control. * @rc_query_work: struct work_struct frequent rc queries * @last_event: last triggered event @@ -255,32 +343,18 @@ struct dvb_usb_properties { * in size_of_priv of dvb_usb_properties). */ struct dvb_usb_device { - struct dvb_usb_properties props; + struct dvb_usb_device_properties props; struct dvb_usb_device_description *desc; -#define DVB_USB_STATE_INIT 0x000 -#define DVB_USB_STATE_URB_LIST 0x001 -#define DVB_USB_STATE_URB_BUF 0x002 -#define DVB_USB_STATE_DVB 0x004 -#define DVB_USB_STATE_I2C 0x008 -#define DVB_USB_STATE_REMOTE 0x010 -#define DVB_USB_STATE_URB_SUBMIT 0x020 - int state; - - /* usb */ struct usb_device *udev; - struct urb **urb_list; - int buf_num; - unsigned long buf_size; - u8 **buf_list; - dma_addr_t *dma_addr; - - int urbs_initialized; - int urbs_submitted; +#define DVB_USB_STATE_INIT 0x000 +#define DVB_USB_STATE_I2C 0x001 +#define DVB_USB_STATE_DVB 0x002 +#define DVB_USB_STATE_REMOTE 0x004 + int state; - int feedcount; - int pid_filtering; + int powered; /* locking */ struct mutex usb_mutex; @@ -289,27 +363,13 @@ struct dvb_usb_device { struct mutex i2c_mutex; struct i2c_adapter i2c_adap; - /* tuner programming information */ - u8 pll_addr; - u8 pll_init[4]; - struct dvb_pll_desc *pll_desc; - int (*tuner_pass_ctrl)(struct dvb_frontend *, int, u8); - - /* dvb */ - struct dvb_adapter dvb_adap; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; - struct dvb_frontend* fe; - int max_feed_count; - - int (*fe_sleep) (struct dvb_frontend *); - int (*fe_init) (struct dvb_frontend *); + int num_adapters_initialized; + struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; /* remote control */ struct input_dev *rc_input_dev; char rc_phys[64]; - struct work_struct rc_query_work; + struct delayed_work rc_query_work; u32 last_event; int last_state; @@ -318,7 +378,7 @@ struct dvb_usb_device { void *priv; }; -extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *, struct dvb_usb_device **); +extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_device_properties *, struct module *, struct dvb_usb_device **); extern void dvb_usb_device_exit(struct usb_interface *); /* the generic read/write method for device control */ @@ -342,5 +402,7 @@ struct hexline { u8 chk; }; extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type); +extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos); + #endif diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 9a98f3fdae3..518d67fca5e 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -161,19 +161,18 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) } -static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff) +static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { - return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0); + return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); } -static int gp8psk_frontend_attach(struct dvb_usb_device *d) +static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) { - d->fe = gp8psk_fe_attach(d); - + adap->fe = gp8psk_fe_attach(adap->dev); return 0; } -static struct dvb_usb_properties gp8psk_properties; +static struct dvb_usb_device_properties gp8psk_properties; static int gp8psk_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -188,28 +187,31 @@ static struct usb_device_id gp8psk_usb_table [] = { }; MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); -static struct dvb_usb_properties gp8psk_properties = { - .caps = 0, - +static struct dvb_usb_device_properties gp8psk_properties = { .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-gp8psk-01.fw", - .streaming_ctrl = gp8psk_streaming_ctrl, + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = gp8psk_streaming_ctrl, + .frontend_attach = gp8psk_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + } + }, .power_ctrl = gp8psk_power_ctrl, - .frontend_attach = gp8psk_frontend_attach, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, .num_device_descs = 1, .devices = { @@ -217,7 +219,7 @@ static struct dvb_usb_properties gp8psk_properties = { .cold_ids = { &gp8psk_usb_table[0], NULL }, .warm_ids = { &gp8psk_usb_table[1], NULL }, }, - { 0 }, + { NULL }, } }; diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index 412039d8dba..d48622e76b1 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -75,7 +75,7 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom; u16 raw; int i; - struct dibusb_state *st = d->priv; + struct dibusb_device_state *st = d->priv; dvb_usb_generic_rw(d,cmd,2,key,5,0); @@ -135,7 +135,7 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) } /* USB Driver stuff */ -static struct dvb_usb_properties nova_t_properties; +static struct dvb_usb_device_properties nova_t_properties; static int nova_t_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -151,21 +151,42 @@ static struct usb_device_id nova_t_table [] = { }; MODULE_DEVICE_TABLE(usb, nova_t_table); -static struct dvb_usb_properties nova_t_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, - .pid_filter_count = 32, +static struct dvb_usb_device_properties nova_t_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-nova-t-usb2-01.fw", + .firmware = "dvb-usb-nova-t-usb2-02.fw", + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .frontend_attach = dibusb_dib3000mc_frontend_attach, + .tuner_attach = dibusb_dib3000mc_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, - .size_of_priv = sizeof(struct dibusb_state), + .size_of_priv = sizeof(struct dibusb_state), + } + }, + .size_of_priv = sizeof(struct dibusb_device_state), - .streaming_ctrl = dibusb2_0_streaming_ctrl, - .pid_filter = dibusb_pid_filter, - .pid_filter_ctrl = dibusb_pid_filter_ctrl, .power_ctrl = dibusb2_0_power_ctrl, - .frontend_attach = dibusb_dib3000mc_frontend_attach, - .tuner_attach = dibusb_dib3000mc_tuner_attach, .read_mac_address = nova_t_read_mac_address, .rc_interval = 100, @@ -176,17 +197,6 @@ static struct dvb_usb_properties nova_t_properties = { .i2c_algo = &dibusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, .num_device_descs = 1, .devices = { diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c new file mode 100644 index 00000000000..95d29976ed7 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -0,0 +1,270 @@ +/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones + * (e.g. Pinnacle 400e DVB-S USB2.0). + * + * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes. + * + * TDA8263 + TDA10086 + * + * I2C addresses: + * 0x08 - LNBP21PD - LNB power supply + * 0x0e - TDA10086 - Demodulator + * 0x50 - FX2 eeprom + * 0x60 - TDA8263 - Tuner + * 0x78 ??? + * + * Copyright (c) 2002 Holger Waechtler <holger@convergence.de> + * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net> + * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.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 + */ +#define DVB_USB_LOG_PREFIX "ttusb2" +#include "dvb-usb.h" + +#include "ttusb2.h" + +#include "tda826x.h" +#include "tda10086.h" +#include "lnbp21.h" + +/* debug */ +static int dvb_usb_ttusb2_debug; +#define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) +module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); + +struct ttusb2_state { + u8 id; +}; + +static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, + u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct ttusb2_state *st = d->priv; + u8 s[wlen+4],r[64] = { 0 }; + int ret = 0; + + memset(s,0,wlen+4); + + s[0] = 0xaa; + s[1] = ++st->id; + s[2] = cmd; + s[3] = wlen; + memcpy(&s[4],wbuf,wlen); + + ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0); + + if (ret != 0 || + r[0] != 0x55 || + r[1] != s[1] || + r[2] != cmd || + (rlen > 0 && r[3] != rlen)) { + warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); + return -EIO; + } + + if (rlen > 0) + memcpy(rbuf, &r[4], rlen); + + return 0; +} + +static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + static u8 obuf[60], ibuf[60]; + int i,read; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + read = i+1 < num && (msg[i+1].flags & I2C_M_RD); + + obuf[0] = (msg[i].addr << 1) | read; + obuf[1] = msg[i].len; + + /* read request */ + if (read) + obuf[2] = msg[i+1].len; + else + obuf[2] = 0; + + memcpy(&obuf[3],msg[i].buf,msg[i].len); + + if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) { + err("i2c transfer failed."); + break; + } + + if (read) { + memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len); + i++; + } + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm ttusb2_i2c_algo = { + .master_xfer = ttusb2_i2c_xfer, + .functionality = ttusb2_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int ttusb2_identify_state (struct usb_device *udev, struct + dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, + int *cold) +{ + *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; + return 0; +} + +static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = onoff; + ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0); + return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0); +} + + +static struct tda10086_config tda10086_config = { + .demod_address = 0x0e, + .invert = 0, +}; + +static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev,0,3) < 0) + err("set interface to alts=3 failed"); + + if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { + deb_info("TDA10086 attach failed\n"); + return -ENODEV; + } + + return 0; +} + +static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap) +{ + if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { + deb_info("TDA8263 attach failed\n"); + return -ENODEV; + } + + if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) { + deb_info("LNBP21 attach failed\n"); + return -ENODEV; + } + return 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties ttusb2_properties; + +static int ttusb2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf,&ttusb2_properties,THIS_MODULE,NULL); +} + +static struct usb_device_id ttusb2_table [] = { + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, ttusb2_table); + +static struct dvb_usb_device_properties ttusb2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-pctv-400e-01.fw", + + .size_of_priv = sizeof(struct ttusb2_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, + + .frontend_attach = ttusb2_frontend_attach, + .tuner_attach = ttusb2_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 4, + .framesize = 940, + .interval = 1, + } + } + } + } + }, + + .power_ctrl = ttusb2_power_ctrl, + .identify_state = ttusb2_identify_state, + + .i2c_algo = &ttusb2_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .num_device_descs = 1, + .devices = { + { "Pinnacle 400e DVB-S USB2.0", + { &ttusb2_table[0], NULL }, + { NULL }, + }, + } +}; + +static struct usb_driver ttusb2_driver = { + .name = "dvb_usb_ttusb2", + .probe = ttusb2_probe, + .disconnect = dvb_usb_device_exit, + .id_table = ttusb2_table, +}; + +/* module stuff */ +static int __init ttusb2_module_init(void) +{ + int result; + if ((result = usb_register(&ttusb2_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit ttusb2_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&ttusb2_driver); +} + +module_init (ttusb2_module_init); +module_exit (ttusb2_module_exit); + +MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); +MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/ttusb2.h b/drivers/media/dvb/dvb-usb/ttusb2.h new file mode 100644 index 00000000000..52a63af4089 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/ttusb2.h @@ -0,0 +1,70 @@ +/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones + * (e.g. Pinnacle 400e DVB-S USB2.0). + * + * Copyright (c) 2002 Holger Waechtler <holger@convergence.de> + * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net> + * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.de> + * + * 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 + */ +#ifndef _DVB_USB_TTUSB2_H_ +#define _DVB_USB_TTUSB2_H_ + +/* TTUSB protocol + * + * always to messages (out/in) + * out message: + * 0xaa <id> <cmdbyte> <datalen> <data...> + * + * in message (complete block is always 0x40 bytes long) + * 0x55 <id> <cmdbyte> <datalen> <data...> + * + * id is incremented for each transaction + */ + +#define CMD_DSP_DOWNLOAD 0x13 +/* out data: <byte>[28] + * last block must be empty */ + +#define CMD_DSP_BOOT 0x14 +/* out data: nothing */ + +#define CMD_POWER 0x15 +/* out data: <on=1/off=0> */ + +#define CMD_LNB 0x16 +/* out data: <power=1> <18V=0,13V=1> <tone> <??=1> <??=1> */ + +#define CMD_GET_VERSION 0x17 +/* in data: <version_byte>[5] */ + +#define CMD_DISEQC 0x18 +/* out data: <master=0xff/burst=??> <cmdlen> <cmdbytes>[cmdlen] */ + +#define CMD_PID_ENABLE 0x22 +/* out data: <index> <type: ts=1/sec=2> <pid msb> <pid lsb> */ + +#define CMD_PID_DISABLE 0x23 +/* out data: <index> */ + +#define CMD_FILTER_ENABLE 0x24 +/* out data: <index> <pid_idx> <filter>[12] <mask>[12] */ + +#define CMD_FILTER_DISABLE 0x25 +/* out data: <index> */ + +#define CMD_GET_DSP_VERSION 0x26 +/* in data: <version_byte>[28] */ + +#define CMD_I2C_XFER 0x31 +/* out data: <addr << 1> <sndlen> <rcvlen> <data>[sndlen] + * in data: <addr << 1> <sndlen> <rcvlen> <data>[rcvlen] */ + +#define CMD_I2C_BITRATE 0x32 +/* out data: <default=0> */ + +#endif diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index 97d74da0dad..f77b48f7658 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -50,7 +50,7 @@ static int umt_mt352_demod_init(struct dvb_frontend *fe) return 0; } -static int umt_mt352_frontend_attach(struct dvb_usb_device *d) +static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) { struct mt352_config umt_config; @@ -58,21 +58,21 @@ static int umt_mt352_frontend_attach(struct dvb_usb_device *d) umt_config.demod_init = umt_mt352_demod_init; umt_config.demod_address = 0xf; - d->fe = mt352_attach(&umt_config, &d->i2c_adap); + adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); return 0; } -static int umt_tuner_attach (struct dvb_usb_device *d) +static int umt_tuner_attach (struct dvb_usb_adapter *adap) { - d->pll_addr = 0x61; - d->pll_desc = &dvb_pll_tua6034; - d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; + adap->pll_addr = 0x61; + adap->pll_desc = &dvb_pll_tua6034; + adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; return 0; } /* USB Driver stuff */ -static struct dvb_usb_properties umt_properties; +static struct dvb_usb_device_properties umt_properties; static int umt_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -90,33 +90,39 @@ static struct usb_device_id umt_table [] = { }; MODULE_DEVICE_TABLE (usb, umt_table); -static struct dvb_usb_properties umt_properties = { +static struct dvb_usb_device_properties umt_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-umt-010-02.fw", - .size_of_priv = sizeof(struct dibusb_state), - - .streaming_ctrl = dibusb2_0_streaming_ctrl, + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .frontend_attach = umt_mt352_frontend_attach, + .tuner_attach = umt_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 20, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + + .size_of_priv = sizeof(struct dibusb_state), + } + }, .power_ctrl = dibusb_power_ctrl, - .frontend_attach = umt_mt352_frontend_attach, - .tuner_attach = umt_tuner_attach, .i2c_algo = &dibusb_i2c_algo, .generic_bulk_ctrl_endpoint = 0x01, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 20, - .endpoint = 0x06, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, .num_device_descs = 1, .devices = { diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c new file mode 100644 index 00000000000..397f51a7b2a --- /dev/null +++ b/drivers/media/dvb/dvb-usb/usb-urb.c @@ -0,0 +1,243 @@ +/* usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * BULK and ISOC USB data transfers in a generic way. + * Can be used for DVB-only and also, that's the plan, for + * Hybrid USB devices (analog and DVB). + */ +#include "dvb-usb-common.h" + +/* URB stuff for streaming */ +static void usb_urb_complete(struct urb *urb) +{ + struct usb_data_stream *stream = urb->context; + int ptype = usb_pipetype(urb->pipe); + int i; + u8 *b; + + deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n", + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", + urb->status,urb->actual_length,urb->transfer_buffer_length, + urb->number_of_packets,urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + deb_ts("urb completition error %d.\n", urb->status); + break; + } + + b = (u8 *) urb->transfer_buffer; + switch (ptype) { + case PIPE_ISOCHRONOUS: + for (i = 0; i < urb->number_of_packets; i++) { + + if (urb->iso_frame_desc[i].status != 0) + deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); + else if (urb->iso_frame_desc[i].actual_length > 0) + stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); + + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + debug_dump(b,20,deb_uxfer); + break; + case PIPE_BULK: + if (urb->actual_length > 0) + stream->complete(stream, b, urb->actual_length); + break; + default: + err("unkown endpoint type in completition handler."); + return; + } + usb_submit_urb(urb,GFP_ATOMIC); +} + +int usb_urb_kill(struct usb_data_stream *stream) +{ + int i; + for (i = 0; i < stream->urbs_submitted; i++) { + deb_ts("killing URB no. %d.\n",i); + + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + return 0; +} + +int usb_urb_submit(struct usb_data_stream *stream) +{ + int i,ret; + for (i = 0; i < stream->urbs_initialized; i++) { + deb_ts("submitting URB no. %d\n",i); + if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) { + err("could not submit URB no. %d - get them all back",i); + usb_urb_kill(stream); + return ret; + } + stream->urbs_submitted++; + } + return 0; +} + +static int usb_free_stream_buffers(struct usb_data_stream *stream) +{ + if (stream->state & USB_STATE_URB_BUF) { + while (stream->buf_num) { + stream->buf_num--; + deb_mem("freeing buffer %d\n",stream->buf_num); + usb_buffer_free(stream->udev, stream->buf_size, + stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]); + } + } + + stream->state &= ~USB_STATE_URB_BUF; + + return 0; +} + +static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) +{ + stream->buf_num = 0; + stream->buf_size = size; + + deb_mem("all in all I will use %lu bytes for streaming\n",num*size); + + for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { + deb_mem("allocating buffer %d\n",stream->buf_num); + if (( stream->buf_list[stream->buf_num] = + usb_buffer_alloc(stream->udev, size, GFP_ATOMIC, + &stream->dma_addr[stream->buf_num]) ) == NULL) { + deb_mem("not enough memory for urb-buffer allocation.\n"); + usb_free_stream_buffers(stream); + return -ENOMEM; + } + deb_mem("buffer %d: %p (dma: %Lu)\n", + stream->buf_num, +stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); + memset(stream->buf_list[stream->buf_num],0,size); + stream->state |= USB_STATE_URB_BUF; + } + deb_mem("allocation successful\n"); + + return 0; +} + +static int usb_bulk_urb_init(struct usb_data_stream *stream) +{ + int i; + + if ((i = usb_allocate_stream_buffers(stream,stream->props.count, + stream->props.u.bulk.buffersize)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + if ((stream->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL) + return -ENOMEM; + + usb_fill_bulk_urb( stream->urb_list[i], stream->udev, + usb_rcvbulkpipe(stream->udev,stream->props.endpoint), + stream->buf_list[i], + stream->props.u.bulk.buffersize, + usb_urb_complete, stream); + + stream->urb_list[i]->transfer_flags = 0; + stream->urbs_initialized++; + } + return 0; +} + +static int usb_isoc_urb_init(struct usb_data_stream *stream) +{ + int i,j; + + if ((i = usb_allocate_stream_buffers(stream,stream->props.count, + stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + struct urb *urb; + int frame_offset = 0; + if ((stream->urb_list[i] = + usb_alloc_urb(stream->props.u.isoc.framesperurb,GFP_ATOMIC)) == NULL) + return -ENOMEM; + + urb = stream->urb_list[i]; + + urb->dev = stream->udev; + urb->context = stream; + urb->complete = usb_urb_complete; + urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = stream->props.u.isoc.interval; + urb->number_of_packets = stream->props.u.isoc.framesperurb; + urb->transfer_buffer_length = stream->buf_size; + urb->transfer_buffer = stream->buf_list[i]; + urb->transfer_dma = stream->dma_addr[i]; + + for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize; + frame_offset += stream->props.u.isoc.framesize; + } + + stream->urbs_initialized++; + } + return 0; +} + +int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) +{ + if (stream == NULL || props == NULL) + return -EINVAL; + + memcpy(&stream->props, props, sizeof(*props)); + + usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint)); + + if (stream->complete == NULL) { + err("there is no data callback - this doesn't make sense."); + return -EINVAL; + } + + switch (stream->props.type) { + case USB_BULK: + return usb_bulk_urb_init(stream); + case USB_ISOC: + return usb_isoc_urb_init(stream); + default: + err("unkown URB-type for data transfer."); + return -EINVAL; + } +} + +int usb_urb_exit(struct usb_data_stream *stream) +{ + int i; + + usb_urb_kill(stream); + + for (i = 0; i < stream->urbs_initialized; i++) { + if (stream->urb_list[i] != NULL) { + deb_mem("freeing URB no. %d.\n",i); + /* free the URBs */ + usb_free_urb(stream->urb_list[i]); + } + } + stream->urbs_initialized = 0; + + usb_free_stream_buffers(stream); + return 0; +} diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c index d4da494132e..3ecb2e0ce80 100644 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -24,6 +24,8 @@ struct vp702x_fe_state { struct dvb_frontend fe; struct dvb_usb_device *d; + struct dvb_frontend_ops ops; + fe_sec_voltage_t voltage; fe_sec_tone_mode_t tone_mode; @@ -72,9 +74,6 @@ static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) else *status = 0; - deb_fe("real state: %x\n",*status); - *status = 0x1f; - if (*status & FE_HAS_LOCK) st->status_check_interval = 1000; else @@ -171,8 +170,6 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe, st->status_check_interval = 250; st->next_status_check = jiffies; - vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); - msleep(30); vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); if (ibuf[2] == 0 && ibuf[3] == 0) @@ -183,6 +180,20 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe, return 0; } +static int vp702x_fe_init(struct dvb_frontend *fe) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + deb_fe("%s\n",__FUNCTION__); + vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); + return 0; +} + +static int vp702x_fe_sleep(struct dvb_frontend *fe) +{ + deb_fe("%s\n",__FUNCTION__); + return 0; +} + static int vp702x_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { @@ -193,8 +204,8 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe, static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *m) { - struct vp702x_fe_state *st = fe->demodulator_priv; - u8 cmd[8],ibuf[10]; + //struct vp702x_fe_state *st = fe->demodulator_priv; + u8 cmd[8];//,ibuf[10]; memset(cmd,0,8); deb_fe("%s\n",__FUNCTION__); @@ -207,12 +218,12 @@ static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, memcpy(&cmd[3], m->msg, m->msg_len); cmd[7] = vp702x_chksum(cmd,0,7); - vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); +// vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); - if (ibuf[2] == 0 && ibuf[3] == 0) - deb_fe("diseqc cmd failed.\n"); - else - deb_fe("diseqc cmd succeeded.\n"); +// if (ibuf[2] == 0 && ibuf[3] == 0) +// deb_fe("diseqc cmd failed.\n"); +// else +// deb_fe("diseqc cmd succeeded.\n"); return 0; } @@ -318,8 +329,8 @@ static struct dvb_frontend_ops vp702x_fe_ops = { }, .release = vp702x_fe_release, - .init = NULL, - .sleep = NULL, + .init = vp702x_fe_init, + .sleep = vp702x_fe_sleep, .set_frontend = vp702x_fe_set_frontend, .get_frontend = vp702x_fe_get_frontend, diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index b2f098a2d5f..16533b31a82 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -22,50 +22,54 @@ module_param_named(debug,dvb_usb_vp702x_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); struct vp702x_state { - u8 pid_table[17]; /* [16] controls the pid_table state */ + int pid_filter_count; + int pid_filter_can_bypass; + u8 pid_filter_state; +}; + +struct vp702x_device_state { + u8 power_state; }; /* check for mutex FIXME */ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) { - int ret = 0,try = 0; + int ret = -1; - while (ret >= 0 && ret != blen && try < 3) { ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), req, USB_TYPE_VENDOR | USB_DIR_IN, value,index,b,blen, 2000); - deb_info("reading number %d (ret: %d)\n",try,ret); - try++; - } - if (ret < 0 || ret != blen) { - warn("usb in operation failed."); + if (ret < 0) { + warn("usb in operation failed. (%d)", ret); ret = -EIO; } else ret = 0; - deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + + deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); debug_dump(b,blen,deb_xfer); return ret; } -static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, +int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) { - deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + int ret; + deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); debug_dump(b,blen,deb_xfer); - if (usb_control_msg(d->udev, + if ((ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), req, USB_TYPE_VENDOR | USB_DIR_OUT, value,index,b,blen, - 2000) != blen) { - warn("usb out operation failed."); + 2000)) != blen) { + warn("usb out operation failed. (%d)",ret); return -EIO; } else return 0; @@ -78,12 +82,10 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il if ((ret = mutex_lock_interruptible(&d->usb_mutex))) return ret; - if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0) - goto unlock; + ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen); msleep(msec); ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen); -unlock: mutex_unlock(&d->usb_mutex); return ret; @@ -108,29 +110,65 @@ static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, return ret; } -static int vp702x_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff) +static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass) +{ + u8 buf[16] = { 0 }; + return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16); +} + +static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state) +{ + u8 buf[16] = { 0 }; + return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16); +} + +static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff) { - struct vp702x_state *st = d->priv; - u8 buf[9]; - - if (onoff) { - st->pid_table[16] |= 1 << index; - st->pid_table[index*2] = (pid >> 8) & 0xff; - st->pid_table[index*2+1] = pid & 0xff; - } else { - st->pid_table[16] &= ~(1 << index); - st->pid_table[index*2] = st->pid_table[index*2+1] = 0; + struct vp702x_state *st = adap->priv; + u8 buf[16] = { 0 }; + + if (onoff) + st->pid_filter_state |= (1 << id); + else { + st->pid_filter_state &= ~(1 << id); + pid = 0xffff; } - return vp702x_usb_inout_cmd(d,SET_PID_FILTER,st->pid_table,17,buf,9,10); + id = 0x10 + id*2; + + vp702x_set_pld_state(adap, st->pid_filter_state); + vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16); + vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16); + return 0; } -static int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff) + +static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap) { - vp702x_usb_in_op(d,RESET_TUNER,0,0,NULL,0); + struct vp702x_state *st = adap->priv; + int i; + u8 b[10] = { 0 }; + + st->pid_filter_count = 8; + st->pid_filter_can_bypass = 1; + st->pid_filter_state = 0x00; + + vp702x_set_pld_mode(adap, 1); // bypass + + for (i = 0; i < st->pid_filter_count; i++) + vp702x_set_pid(adap, 0xffff, i, 1); + + vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10); + vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10); + vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10); + + //vp702x_set_pld_mode(d, 0); // filter + return 0; +} - vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0); - return vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0); +static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + return 0; } /* keys for the enclosed remote control */ @@ -166,61 +204,93 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } +int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + struct vp702x_device_state *st = d->priv; + + if (st->power_state == 0 && onoff) + vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); + else if (st->power_state == 1 && onoff == 0) + vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); + + st->power_state = onoff; + + return 0; +} + static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { - u8 macb[9]; - if (vp702x_usb_inout_cmd(d, GET_MAC_ADDRESS, NULL, 0, macb, 9, 10)) - return -EIO; - memcpy(mac,&macb[3],6); + u8 i; + for (i = 6; i < 12; i++) + vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1); return 0; } -static int vp702x_frontend_attach(struct dvb_usb_device *d) +static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) { - u8 buf[9] = { 0 }; + u8 buf[10] = { 0 }; + + vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); - if (vp702x_usb_inout_cmd(d, GET_SYSTEM_STRING, NULL, 0, buf, 9, 10)) + if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10)) return -EIO; - buf[8] = '\0'; + buf[9] = '\0'; info("system string: %s",&buf[1]); - d->fe = vp702x_fe_attach(d); + vp702x_init_pid_filter(adap); + + adap->fe = vp702x_fe_attach(adap->dev); + vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); + return 0; } -static struct dvb_usb_properties vp702x_properties; +static struct dvb_usb_device_properties vp702x_properties; static int vp702x_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev(intf); - - usb_clear_halt(udev,usb_sndctrlpipe(udev,0)); - usb_clear_halt(udev,usb_rcvctrlpipe(udev,0)); - return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE,NULL); } static struct usb_device_id vp702x_usb_table [] = { { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_WARM) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, +// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, +// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, vp702x_usb_table); -static struct dvb_usb_properties vp702x_properties = { - .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, - .pid_filter_count = 8, /* !!! */ - +static struct dvb_usb_device_properties vp702x_properties = { .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-vp702x-01.fw", - - .pid_filter = vp702x_pid_filter, - .power_ctrl = vp702x_power_ctrl, - .frontend_attach = vp702x_frontend_attach, + .firmware = "dvb-usb-vp702x-02.fw", + .no_reconnect = 1, + + .size_of_priv = sizeof(struct vp702x_device_state), + + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS, + + .streaming_ctrl = vp702x_streaming_ctrl, + .frontend_attach = vp702x_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 10, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + .size_of_priv = sizeof(struct vp702x_state), + } + }, .read_mac_address = vp702x_read_mac_addr, .rc_key_map = vp702x_rc_keys, @@ -228,37 +298,23 @@ static struct dvb_usb_properties vp702x_properties = { .rc_interval = 400, .rc_query = vp702x_rc_query, - .size_of_priv = sizeof(struct vp702x_state), - - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - - .num_device_descs = 2, + .num_device_descs = 1, .devices = { { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)", .cold_ids = { &vp702x_usb_table[0], NULL }, - .warm_ids = { &vp702x_usb_table[1], NULL }, + .warm_ids = { NULL }, }, - { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", +/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", .cold_ids = { &vp702x_usb_table[2], NULL }, .warm_ids = { &vp702x_usb_table[3], NULL }, }, - { 0 }, +*/ { NULL }, } }; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver vp702x_usb_driver = { - .name = "dvb-usb-vp702x", + .name = "dvb_usb_vp702x", .probe = vp702x_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = vp702x_usb_table, @@ -287,5 +343,5 @@ module_exit(vp702x_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones"); -MODULE_VERSION("1.0-alpha"); +MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h index c2f97f96c21..25a9dee4c82 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.h +++ b/drivers/media/dvb/dvb-usb/vp702x.h @@ -102,5 +102,7 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff); #endif diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 8ea3834a6cf..69a46b3607a 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -125,7 +125,25 @@ static struct dvb_usb_rc_key vp7045_rc_keys[] = { { 0x00, 0x00, KEY_TAB }, /* Tab */ { 0x00, 0x48, KEY_INFO }, /* Preview */ { 0x00, 0x04, KEY_LIST }, /* RecordList */ - { 0x00, 0x0f, KEY_TEXT } /* Teletext */ + { 0x00, 0x0f, KEY_TEXT }, /* Teletext */ + { 0x00, 0x41, KEY_PREVIOUSSONG }, + { 0x00, 0x42, KEY_NEXTSONG }, + { 0x00, 0x4b, KEY_UP }, + { 0x00, 0x51, KEY_DOWN }, + { 0x00, 0x4e, KEY_LEFT }, + { 0x00, 0x52, KEY_RIGHT }, + { 0x00, 0x4f, KEY_ENTER }, + { 0x00, 0x13, KEY_CANCEL }, + { 0x00, 0x4a, KEY_CLEAR }, + { 0x00, 0x54, KEY_PRINT }, /* Capture */ + { 0x00, 0x43, KEY_SUBTITLE }, /* Subtitle/CC */ + { 0x00, 0x08, KEY_VIDEO }, /* A/V */ + { 0x00, 0x07, KEY_SLEEP }, /* Hibernate */ + { 0x00, 0x45, KEY_ZOOM }, /* Zoom+ */ + { 0x00, 0x18, KEY_RED}, + { 0x00, 0x53, KEY_GREEN}, + { 0x00, 0x5e, KEY_YELLOW}, + { 0x00, 0x5f, KEY_BLUE} }; static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) @@ -169,31 +187,31 @@ static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR); } -static int vp7045_frontend_attach(struct dvb_usb_device *d) +static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) { u8 buf[255] = { 0 }; - vp7045_usb_op(d,VENDOR_STRING_READ,NULL,0,buf,20,0); + vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0); buf[10] = '\0'; deb_info("firmware says: %s ",buf); - vp7045_usb_op(d,PRODUCT_STRING_READ,NULL,0,buf,20,0); + vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0); buf[10] = '\0'; deb_info("%s ",buf); - vp7045_usb_op(d,FW_VERSION_READ,NULL,0,buf,20,0); + vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0); buf[10] = '\0'; deb_info("v%s\n",buf); /* Dump the EEPROM */ /* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ - d->fe = vp7045_fe_attach(d); + adap->fe = vp7045_fe_attach(adap->dev); return 0; } -static struct dvb_usb_properties vp7045_properties; +static struct dvb_usb_device_properties vp7045_properties; static int vp7045_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -210,14 +228,28 @@ static struct usb_device_id vp7045_usb_table [] = { }; MODULE_DEVICE_TABLE(usb, vp7045_usb_table); -static struct dvb_usb_properties vp7045_properties = { - .caps = 0, - +static struct dvb_usb_device_properties vp7045_properties = { .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-vp7045-01.fw", + .num_adapters = 1, + .adapter = { + { + .frontend_attach = vp7045_frontend_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, .power_ctrl = vp7045_power_ctrl, - .frontend_attach = vp7045_frontend_attach, .read_mac_address = vp7045_read_mac_addr, .rc_interval = 400, @@ -225,18 +257,6 @@ static struct dvb_usb_properties vp7045_properties = { .rc_key_map_size = ARRAY_SIZE(vp7045_rc_keys), .rc_query = vp7045_rc_query, - /* parameter for the MPEG2-data transfer */ - .urb = { - .type = DVB_USB_BULK, - .count = 7, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - .num_device_descs = 2, .devices = { { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)", |