Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: cxusb: implement Medion MD95700 digital / analog coexistence

This patch prepares cxusb driver for supporting the analog part of
Medion 95700 (previously only the digital - DVB - mode was supported).

Specifically, it adds support for:
* switching the device between analog and digital modes of operation,
* enforcing that only one mode is active at the same time due to hardware
limitations.

Actual implementation of the analog mode will be provided by the next
commit.

Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>

authored by

Maciej S. Szmigiero and committed by
Mauro Carvalho Chehab
d525e5c2 65efeca0

+472 -53
+399 -50
drivers/media/usb/dvb-usb/cxusb.c
··· 16 16 * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de) 17 17 * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) 18 18 * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) 19 + * Copyright (C) 2011, 2017 Maciej S. Szmigiero (mail@maciej.szmigiero.name) 19 20 * 20 21 * This program is free software; you can redistribute it and/or modify it 21 22 * under the terms of the GNU General Public License as published by the Free ··· 25 24 * see Documentation/media/dvb-drivers/dvb-usb.rst for more information 26 25 */ 27 26 #include <media/tuner.h> 28 - #include <linux/vmalloc.h> 29 - #include <linux/slab.h> 27 + #include <linux/delay.h> 28 + #include <linux/device.h> 30 29 #include <linux/kernel.h> 30 + #include <linux/slab.h> 31 + #include <linux/string.h> 32 + #include <linux/vmalloc.h> 31 33 32 34 #include "cxusb.h" 33 35 ··· 51 47 #include "si2157.h" 52 48 53 49 /* debug */ 54 - static int dvb_usb_cxusb_debug; 50 + int dvb_usb_cxusb_debug; 55 51 module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); 56 - MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); 52 + MODULE_PARM_DESC(debug, "set debugging level (see cxusb.h)." 53 + DVB_USB_DEBUG_STATUS); 57 54 58 55 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 59 56 60 - #define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args) 61 - #define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args) 57 + #define deb_info(args...) dprintk(dvb_usb_cxusb_debug, CXUSB_DBG_MISC, args) 58 + #define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, CXUSB_DBG_I2C, args) 62 59 63 - static int cxusb_ctrl_msg(struct dvb_usb_device *d, 64 - u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen) 60 + enum cxusb_table_index { 61 + MEDION_MD95700, 62 + DVICO_BLUEBIRD_LG064F_COLD, 63 + DVICO_BLUEBIRD_LG064F_WARM, 64 + DVICO_BLUEBIRD_DUAL_1_COLD, 65 + DVICO_BLUEBIRD_DUAL_1_WARM, 66 + DVICO_BLUEBIRD_LGZ201_COLD, 67 + DVICO_BLUEBIRD_LGZ201_WARM, 68 + DVICO_BLUEBIRD_TH7579_COLD, 69 + DVICO_BLUEBIRD_TH7579_WARM, 70 + DIGITALNOW_BLUEBIRD_DUAL_1_COLD, 71 + DIGITALNOW_BLUEBIRD_DUAL_1_WARM, 72 + DVICO_BLUEBIRD_DUAL_2_COLD, 73 + DVICO_BLUEBIRD_DUAL_2_WARM, 74 + DVICO_BLUEBIRD_DUAL_4, 75 + DVICO_BLUEBIRD_DVB_T_NANO_2, 76 + DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM, 77 + AVERMEDIA_VOLAR_A868R, 78 + DVICO_BLUEBIRD_DUAL_4_REV_2, 79 + CONEXANT_D680_DMB, 80 + MYGICA_D689, 81 + MYGICA_T230, 82 + NR__cxusb_table_index 83 + }; 84 + 85 + static struct usb_device_id cxusb_table[]; 86 + 87 + int cxusb_ctrl_msg(struct dvb_usb_device *d, 88 + u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen) 65 89 { 66 90 struct cxusb_state *st = d->priv; 67 91 int ret; ··· 121 89 struct cxusb_state *st = d->priv; 122 90 u8 o[2], i; 123 91 124 - if (st->gpio_write_state[GPIO_TUNER] == onoff) 92 + if (st->gpio_write_state[GPIO_TUNER] == onoff && 93 + !st->gpio_write_refresh[GPIO_TUNER]) 125 94 return; 126 95 127 96 o[0] = GPIO_TUNER; ··· 133 100 deb_info("gpio_write failed.\n"); 134 101 135 102 st->gpio_write_state[GPIO_TUNER] = onoff; 103 + st->gpio_write_refresh[GPIO_TUNER] = false; 136 104 } 137 105 138 106 static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, ··· 293 259 294 260 static u32 cxusb_i2c_func(struct i2c_adapter *adapter) 295 261 { 296 - return I2C_FUNC_I2C; 262 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 297 263 } 298 264 299 265 static struct i2c_algorithm cxusb_i2c_algo = { ··· 301 267 .functionality = cxusb_i2c_func, 302 268 }; 303 269 304 - static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) 270 + static int _cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) 305 271 { 306 272 u8 b = 0; 273 + 274 + deb_info("setting power %s\n", onoff ? "ON" : "OFF"); 275 + 307 276 if (onoff) 308 277 return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); 309 278 else 310 279 return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); 280 + } 281 + 282 + static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) 283 + { 284 + bool is_medion = d->props.devices[0].warm_ids[0] == 285 + &cxusb_table[MEDION_MD95700]; 286 + int ret; 287 + 288 + if (is_medion && !onoff) { 289 + struct cxusb_medion_dev *cxdev = d->priv; 290 + 291 + mutex_lock(&cxdev->open_lock); 292 + 293 + if (cxdev->open_type == CXUSB_OPEN_ANALOG) { 294 + deb_info("preventing DVB core from setting power OFF while we are in analog mode\n"); 295 + ret = -EBUSY; 296 + goto ret_unlock; 297 + } 298 + } 299 + 300 + ret = _cxusb_power_ctrl(d, onoff); 301 + 302 + ret_unlock: 303 + if (is_medion && !onoff) { 304 + struct cxusb_medion_dev *cxdev = d->priv; 305 + 306 + mutex_unlock(&cxdev->open_lock); 307 + } 308 + 309 + return ret; 311 310 } 312 311 313 312 static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) ··· 420 353 421 354 static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) 422 355 { 356 + struct dvb_usb_device *dvbdev = adap->dev; 357 + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == 358 + &cxusb_table[MEDION_MD95700]; 423 359 u8 buf[2] = { 0x03, 0x00 }; 360 + 361 + if (is_medion && onoff) { 362 + int ret; 363 + 364 + ret = cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL); 365 + if (ret != 0) 366 + return ret; 367 + } 368 + 424 369 if (onoff) 425 - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0); 370 + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_ON, buf, 2, NULL, 0); 426 371 else 427 - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); 372 + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); 373 + 374 + if (is_medion && !onoff) 375 + cxusb_medion_put(dvbdev); 428 376 429 377 return 0; 430 378 } ··· 712 630 /* Callbacks for DVB USB */ 713 631 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) 714 632 { 633 + struct dvb_usb_device *dvbdev = adap->dev; 634 + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == 635 + &cxusb_table[MEDION_MD95700]; 636 + 715 637 dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, 716 - &adap->dev->i2c_adap, 0x61, 638 + &dvbdev->i2c_adap, 0x61, 717 639 TUNER_PHILIPS_FMD1216ME_MK3); 640 + 641 + if (is_medion && adap->fe_adap[0].fe != NULL) 642 + /* 643 + * make sure that DVB core won't put to sleep (reset, really) 644 + * tuner when we might be open in analog mode 645 + */ 646 + adap->fe_adap[0].fe->ops.tuner_ops.sleep = NULL; 647 + 718 648 return 0; 719 649 } 720 650 ··· 830 736 return (fe == NULL) ? -EIO : 0; 831 737 } 832 738 739 + static int cxusb_medion_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) 740 + { 741 + struct dvb_usb_adapter *adap = fe->dvb->priv; 742 + struct dvb_usb_device *dvbdev = adap->dev; 743 + 744 + if (acquire) 745 + return cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL); 746 + 747 + cxusb_medion_put(dvbdev); 748 + 749 + return 0; 750 + } 751 + 752 + static int cxusb_medion_set_mode(struct dvb_usb_device *dvbdev, bool digital) 753 + { 754 + struct cxusb_state *st = dvbdev->priv; 755 + int ret; 756 + u8 b; 757 + unsigned int i; 758 + 759 + /* 760 + * switching mode while doing an I2C transaction often causes 761 + * the device to crash 762 + */ 763 + mutex_lock(&dvbdev->i2c_mutex); 764 + 765 + if (digital) { 766 + ret = usb_set_interface(dvbdev->udev, 0, 6); 767 + if (ret != 0) { 768 + dev_err(&dvbdev->udev->dev, 769 + "digital interface selection failed (%d)\n", 770 + ret); 771 + goto ret_unlock; 772 + } 773 + } else { 774 + ret = usb_set_interface(dvbdev->udev, 0, 1); 775 + if (ret != 0) { 776 + dev_err(&dvbdev->udev->dev, 777 + "analog interface selection failed (%d)\n", 778 + ret); 779 + goto ret_unlock; 780 + } 781 + } 782 + 783 + /* pipes need to be cleared after setting interface */ 784 + ret = usb_clear_halt(dvbdev->udev, usb_rcvbulkpipe(dvbdev->udev, 1)); 785 + if (ret != 0) 786 + dev_warn(&dvbdev->udev->dev, 787 + "clear halt on IN pipe failed (%d)\n", 788 + ret); 789 + 790 + ret = usb_clear_halt(dvbdev->udev, usb_sndbulkpipe(dvbdev->udev, 1)); 791 + if (ret != 0) 792 + dev_warn(&dvbdev->udev->dev, 793 + "clear halt on OUT pipe failed (%d)\n", 794 + ret); 795 + 796 + ret = cxusb_ctrl_msg(dvbdev, digital ? CMD_DIGITAL : CMD_ANALOG, 797 + NULL, 0, &b, 1); 798 + if (ret != 0) { 799 + dev_err(&dvbdev->udev->dev, "mode switch failed (%d)\n", 800 + ret); 801 + goto ret_unlock; 802 + } 803 + 804 + /* mode switch seems to reset GPIO states */ 805 + for (i = 0; i < ARRAY_SIZE(st->gpio_write_refresh); i++) 806 + st->gpio_write_refresh[i] = true; 807 + 808 + ret_unlock: 809 + mutex_unlock(&dvbdev->i2c_mutex); 810 + 811 + return ret; 812 + } 813 + 833 814 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) 834 815 { 835 - u8 b; 836 - if (usb_set_interface(adap->dev->udev, 0, 6) < 0) 837 - err("set interface failed"); 816 + struct dvb_usb_device *dvbdev = adap->dev; 817 + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == 818 + &cxusb_table[MEDION_MD95700]; 838 819 839 - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); 820 + if (is_medion) { 821 + int ret; 822 + 823 + ret = cxusb_medion_set_mode(dvbdev, true); 824 + if (ret) 825 + return ret; 826 + } 840 827 841 828 adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, 842 - &adap->dev->i2c_adap); 843 - if ((adap->fe_adap[0].fe) != NULL) 844 - return 0; 829 + &dvbdev->i2c_adap); 830 + if (adap->fe_adap[0].fe == NULL) 831 + return -EIO; 845 832 846 - return -EIO; 833 + if (is_medion) 834 + adap->fe_adap[0].fe->ops.ts_bus_ctrl = 835 + cxusb_medion_fe_ts_bus_ctrl; 836 + 837 + return 0; 847 838 } 848 839 849 840 static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) ··· 1491 1312 return -EINVAL; 1492 1313 } 1493 1314 1315 + int cxusb_medion_get(struct dvb_usb_device *dvbdev, 1316 + enum cxusb_open_type open_type) 1317 + { 1318 + struct cxusb_medion_dev *cxdev = dvbdev->priv; 1319 + int ret = 0; 1320 + 1321 + mutex_lock(&cxdev->open_lock); 1322 + 1323 + if (WARN_ON((cxdev->open_type == CXUSB_OPEN_INIT || 1324 + cxdev->open_type == CXUSB_OPEN_NONE) && 1325 + cxdev->open_ctr != 0)) { 1326 + ret = -EINVAL; 1327 + goto ret_unlock; 1328 + } 1329 + 1330 + if (cxdev->open_type == CXUSB_OPEN_INIT) { 1331 + ret = -EAGAIN; 1332 + goto ret_unlock; 1333 + } 1334 + 1335 + if (cxdev->open_ctr == 0) { 1336 + if (cxdev->open_type != open_type) { 1337 + deb_info("will acquire and switch to %s\n", 1338 + open_type == CXUSB_OPEN_ANALOG ? 1339 + "analog" : "digital"); 1340 + 1341 + if (open_type == CXUSB_OPEN_ANALOG) { 1342 + ret = _cxusb_power_ctrl(dvbdev, 1); 1343 + if (ret != 0) 1344 + dev_warn(&dvbdev->udev->dev, 1345 + "powerup for analog switch failed (%d)\n", 1346 + ret); 1347 + 1348 + ret = cxusb_medion_set_mode(dvbdev, false); 1349 + if (ret != 0) 1350 + goto ret_unlock; 1351 + 1352 + ret = cxusb_medion_analog_init(dvbdev); 1353 + if (ret != 0) 1354 + goto ret_unlock; 1355 + } else { /* digital */ 1356 + ret = _cxusb_power_ctrl(dvbdev, 1); 1357 + if (ret != 0) 1358 + dev_warn(&dvbdev->udev->dev, 1359 + "powerup for digital switch failed (%d)\n", 1360 + ret); 1361 + 1362 + ret = cxusb_medion_set_mode(dvbdev, true); 1363 + if (ret != 0) 1364 + goto ret_unlock; 1365 + } 1366 + 1367 + cxdev->open_type = open_type; 1368 + } else 1369 + deb_info("reacquired idle %s\n", 1370 + open_type == CXUSB_OPEN_ANALOG ? 1371 + "analog" : "digital"); 1372 + 1373 + cxdev->open_ctr = 1; 1374 + } else if (cxdev->open_type == open_type) { 1375 + cxdev->open_ctr++; 1376 + deb_info("acquired %s\n", open_type == CXUSB_OPEN_ANALOG ? 1377 + "analog" : "digital"); 1378 + } else 1379 + ret = -EBUSY; 1380 + 1381 + ret_unlock: 1382 + mutex_unlock(&cxdev->open_lock); 1383 + 1384 + return ret; 1385 + } 1386 + 1387 + void cxusb_medion_put(struct dvb_usb_device *dvbdev) 1388 + { 1389 + struct cxusb_medion_dev *cxdev = dvbdev->priv; 1390 + 1391 + mutex_lock(&cxdev->open_lock); 1392 + 1393 + if (cxdev->open_type == CXUSB_OPEN_INIT) { 1394 + WARN_ON(cxdev->open_ctr != 0); 1395 + cxdev->open_type = CXUSB_OPEN_NONE; 1396 + goto unlock; 1397 + } 1398 + 1399 + if (!WARN_ON(cxdev->open_ctr < 1)) { 1400 + cxdev->open_ctr--; 1401 + 1402 + deb_info("release %s\n", cxdev->open_type == 1403 + CXUSB_OPEN_ANALOG ? "analog" : "digital"); 1404 + } 1405 + 1406 + unlock: 1407 + mutex_unlock(&cxdev->open_lock); 1408 + } 1409 + 1494 1410 /* DVB USB Driver stuff */ 1495 1411 static struct dvb_usb_device_properties cxusb_medion_properties; 1496 1412 static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; ··· 1601 1327 static struct dvb_usb_device_properties cxusb_mygica_d689_properties; 1602 1328 static struct dvb_usb_device_properties cxusb_mygica_t230_properties; 1603 1329 1330 + static int cxusb_medion_priv_init(struct dvb_usb_device *dvbdev) 1331 + { 1332 + struct cxusb_medion_dev *cxdev = dvbdev->priv; 1333 + 1334 + cxdev->dvbdev = dvbdev; 1335 + cxdev->open_type = CXUSB_OPEN_INIT; 1336 + mutex_init(&cxdev->open_lock); 1337 + 1338 + return 0; 1339 + } 1340 + 1341 + static void cxusb_medion_priv_destroy(struct dvb_usb_device *dvbdev) 1342 + { 1343 + struct cxusb_medion_dev *cxdev = dvbdev->priv; 1344 + 1345 + mutex_destroy(&cxdev->open_lock); 1346 + } 1347 + 1348 + static bool cxusb_medion_check_altsetting(struct usb_host_interface *as) 1349 + { 1350 + unsigned int ctr; 1351 + 1352 + for (ctr = 0; ctr < as->desc.bNumEndpoints; ctr++) { 1353 + if ((as->endpoint[ctr].desc.bEndpointAddress & 1354 + USB_ENDPOINT_NUMBER_MASK) != 2) 1355 + continue; 1356 + 1357 + if (as->endpoint[ctr].desc.bEndpointAddress & USB_DIR_IN && 1358 + ((as->endpoint[ctr].desc.bmAttributes & 1359 + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) 1360 + return true; 1361 + 1362 + break; 1363 + } 1364 + 1365 + return false; 1366 + } 1367 + 1368 + static bool cxusb_medion_check_intf(struct usb_interface *intf) 1369 + { 1370 + unsigned int ctr; 1371 + 1372 + if (intf->num_altsetting < 2) { 1373 + dev_err(intf->usb_dev, "no alternate interface"); 1374 + 1375 + return false; 1376 + } 1377 + 1378 + for (ctr = 0; ctr < intf->num_altsetting; ctr++) { 1379 + if (intf->altsetting[ctr].desc.bAlternateSetting != 1) 1380 + continue; 1381 + 1382 + if (cxusb_medion_check_altsetting(&intf->altsetting[ctr])) 1383 + return true; 1384 + 1385 + break; 1386 + } 1387 + 1388 + dev_err(intf->usb_dev, "no iso interface"); 1389 + 1390 + return false; 1391 + } 1392 + 1604 1393 static int cxusb_probe(struct usb_interface *intf, 1605 1394 const struct usb_device_id *id) 1606 1395 { 1396 + struct dvb_usb_device *dvbdev; 1397 + int ret; 1398 + 1399 + /* Medion 95700 */ 1607 1400 if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties, 1608 - THIS_MODULE, NULL, adapter_nr) || 1609 - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, 1401 + THIS_MODULE, &dvbdev, adapter_nr)) { 1402 + if (!cxusb_medion_check_intf(intf)) { 1403 + ret = -ENODEV; 1404 + goto ret_uninit; 1405 + } 1406 + 1407 + _cxusb_power_ctrl(dvbdev, 1); 1408 + ret = cxusb_medion_set_mode(dvbdev, false); 1409 + if (ret) 1410 + goto ret_uninit; 1411 + 1412 + ret = cxusb_medion_register_analog(dvbdev); 1413 + 1414 + cxusb_medion_set_mode(dvbdev, true); 1415 + _cxusb_power_ctrl(dvbdev, 0); 1416 + 1417 + if (ret != 0) 1418 + goto ret_uninit; 1419 + 1420 + /* release device from INIT mode to normal operation */ 1421 + cxusb_medion_put(dvbdev); 1422 + 1423 + return 0; 1424 + } else if (0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, 1610 1425 THIS_MODULE, NULL, adapter_nr) || 1611 1426 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties, 1612 1427 THIS_MODULE, NULL, adapter_nr) || ··· 1725 1362 return 0; 1726 1363 1727 1364 return -EINVAL; 1365 + 1366 + ret_uninit: 1367 + dvb_usb_device_exit(intf); 1368 + 1369 + return ret; 1728 1370 } 1729 1371 1730 1372 static void cxusb_disconnect(struct usb_interface *intf) ··· 1737 1369 struct dvb_usb_device *d = usb_get_intfdata(intf); 1738 1370 struct cxusb_state *st = d->priv; 1739 1371 struct i2c_client *client; 1372 + 1373 + if (d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700]) 1374 + cxusb_medion_unregister_analog(d); 1740 1375 1741 1376 /* remove I2C client for tuner */ 1742 1377 client = st->i2c_client_tuner; ··· 1757 1386 1758 1387 dvb_usb_device_exit(intf); 1759 1388 } 1760 - 1761 - enum cxusb_table_index { 1762 - MEDION_MD95700, 1763 - DVICO_BLUEBIRD_LG064F_COLD, 1764 - DVICO_BLUEBIRD_LG064F_WARM, 1765 - DVICO_BLUEBIRD_DUAL_1_COLD, 1766 - DVICO_BLUEBIRD_DUAL_1_WARM, 1767 - DVICO_BLUEBIRD_LGZ201_COLD, 1768 - DVICO_BLUEBIRD_LGZ201_WARM, 1769 - DVICO_BLUEBIRD_TH7579_COLD, 1770 - DVICO_BLUEBIRD_TH7579_WARM, 1771 - DIGITALNOW_BLUEBIRD_DUAL_1_COLD, 1772 - DIGITALNOW_BLUEBIRD_DUAL_1_WARM, 1773 - DVICO_BLUEBIRD_DUAL_2_COLD, 1774 - DVICO_BLUEBIRD_DUAL_2_WARM, 1775 - DVICO_BLUEBIRD_DUAL_4, 1776 - DVICO_BLUEBIRD_DVB_T_NANO_2, 1777 - DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM, 1778 - AVERMEDIA_VOLAR_A868R, 1779 - DVICO_BLUEBIRD_DUAL_4_REV_2, 1780 - CONEXANT_D680_DMB, 1781 - MYGICA_D689, 1782 - MYGICA_T230, 1783 - NR__cxusb_table_index 1784 - }; 1785 1389 1786 1390 static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { 1787 1391 [MEDION_MD95700] = { ··· 1831 1485 1832 1486 .usb_ctrl = CYPRESS_FX2, 1833 1487 1834 - .size_of_priv = sizeof(struct cxusb_state), 1488 + .size_of_priv = sizeof(struct cxusb_medion_dev), 1489 + .priv_init = cxusb_medion_priv_init, 1490 + .priv_destroy = cxusb_medion_priv_destroy, 1835 1491 1836 1492 .num_adapters = 1, 1837 1493 .adapter = { ··· 2546 2198 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 2547 2199 MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); 2548 2200 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); 2201 + MODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>"); 2549 2202 MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); 2550 2203 MODULE_VERSION("1.0-alpha"); 2551 2204 MODULE_LICENSE("GPL");
+48
drivers/media/usb/dvb-usb/cxusb.h
··· 2 2 #ifndef _DVB_USB_CXUSB_H_ 3 3 #define _DVB_USB_CXUSB_H_ 4 4 5 + #include <linux/i2c.h> 6 + #include <linux/mutex.h> 7 + 5 8 #define DVB_USB_LOG_PREFIX "cxusb" 6 9 #include "dvb-usb.h" 7 10 ··· 37 34 38 35 struct cxusb_state { 39 36 u8 gpio_write_state[3]; 37 + bool gpio_write_refresh[3]; 40 38 struct i2c_client *i2c_client_demod; 41 39 struct i2c_client *i2c_client_tuner; 42 40 ··· 48 44 int (*fe_read_status)(struct dvb_frontend *fe, 49 45 enum fe_status *status); 50 46 }; 47 + 48 + enum cxusb_open_type { 49 + CXUSB_OPEN_INIT, CXUSB_OPEN_NONE, 50 + CXUSB_OPEN_ANALOG, CXUSB_OPEN_DIGITAL 51 + }; 52 + 53 + struct cxusb_medion_dev { 54 + /* has to be the first one */ 55 + struct cxusb_state state; 56 + 57 + struct dvb_usb_device *dvbdev; 58 + 59 + enum cxusb_open_type open_type; 60 + unsigned int open_ctr; 61 + struct mutex open_lock; 62 + }; 63 + 64 + /* defines for "debug" module parameter */ 65 + #define CXUSB_DBG_RC BIT(0) 66 + #define CXUSB_DBG_I2C BIT(1) 67 + #define CXUSB_DBG_MISC BIT(2) 68 + 69 + extern int dvb_usb_cxusb_debug; 70 + 71 + int cxusb_ctrl_msg(struct dvb_usb_device *d, 72 + u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen); 73 + 74 + static inline int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) 75 + { 76 + return -EINVAL; 77 + } 78 + 79 + static inline int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev) 80 + { 81 + return 0; 82 + } 83 + 84 + static inline void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev) 85 + { 86 + } 87 + 88 + int cxusb_medion_get(struct dvb_usb_device *dvbdev, 89 + enum cxusb_open_type open_type); 90 + void cxusb_medion_put(struct dvb_usb_device *dvbdev); 51 91 52 92 #endif
+2 -3
drivers/media/usb/dvb-usb/dvb-usb-dvb.c
··· 56 56 * for reception. 57 57 */ 58 58 if (adap->feedcount == onoff && adap->feedcount > 0) { 59 - deb_ts("submitting all URBs\n"); 60 - usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); 61 - 62 59 deb_ts("controlling pid parser\n"); 63 60 if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && 64 61 adap->props.fe[adap->active_fe].caps & ··· 77 80 } 78 81 } 79 82 83 + deb_ts("submitting all URBs\n"); 84 + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); 80 85 } 81 86 return 0; 82 87 }
+13
drivers/media/usb/dvb-usb/dvb-usb-init.c
··· 133 133 dvb_usb_i2c_exit(d); 134 134 deb_info("state should be zero now: %x\n", d->state); 135 135 d->state = DVB_USB_STATE_INIT; 136 + 137 + if (d->priv != NULL && d->props.priv_destroy != NULL) 138 + d->props.priv_destroy(d); 139 + 136 140 kfree(d->priv); 137 141 kfree(d); 138 142 return 0; ··· 157 153 if (d->priv == NULL) { 158 154 err("no memory for priv in 'struct dvb_usb_device'"); 159 155 return -ENOMEM; 156 + } 157 + 158 + if (d->props.priv_init != NULL) { 159 + ret = d->props.priv_init(d); 160 + if (ret != 0) { 161 + kfree(d->priv); 162 + d->priv = NULL; 163 + return ret; 164 + } 160 165 } 161 166 } 162 167
+10
drivers/media/usb/dvb-usb/dvb-usb.h
··· 129 129 * @frontend_ctrl: called to power on/off active frontend. 130 130 * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the 131 131 * device (not URB submitting/killing). 132 + * This callback will be called without data URBs being active - data URBs 133 + * will be submitted only after streaming_ctrl(1) returns successfully and 134 + * they will be killed before streaming_ctrl(0) gets called. 132 135 * @pid_filter_ctrl: called to en/disable the PID filter, if any. 133 136 * @pid_filter: called to set/unset a PID for filtering. 134 137 * @frontend_attach: called to attach the possible frontends (fill fe-field ··· 237 234 * 238 235 * @size_of_priv: how many bytes shall be allocated for the private field 239 236 * of struct dvb_usb_device. 237 + * @priv_init: optional callback to initialize the variable that private field 238 + * of struct dvb_usb_device has pointer to just after it had been allocated and 239 + * zeroed. 240 + * @priv_destroy: just like priv_init, only called before deallocating 241 + * the memory pointed by private field of struct dvb_usb_device. 240 242 * 241 243 * @power_ctrl: called to enable/disable power of the device. 242 244 * @read_mac_address: called to read the MAC address of the device. ··· 283 275 int no_reconnect; 284 276 285 277 int size_of_priv; 278 + int (*priv_init)(struct dvb_usb_device *); 279 + void (*priv_destroy)(struct dvb_usb_device *); 286 280 287 281 int num_adapters; 288 282 struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];