Skip to content

Commit be7fd3c

Browse files
b-rad-NDimchehab
authored andcommitted
media: em28xx: Hauppauge DualHD second tuner functionality
Implement use of secondary TS port on em28xx. Adds has_dual_ts field, allows secondary demod/tuner to be added to a single em28xx device. Hauppauge DualHD models are configured to use this feature. [mchehab@s-opensource.com: em28xx_duplicate_dev() should be static] Signed-off-by: Brad Love <brad@nextdimension.cc> Reviewed-by: Michael Ira Krufky <mkrufky@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
1 parent 7aa92c4 commit be7fd3c

File tree

4 files changed

+196
-17
lines changed

4 files changed

+196
-17
lines changed

drivers/media/usb/em28xx/em28xx-cards.c

+124-2
Original file line numberDiff line numberDiff line change
@@ -2402,6 +2402,7 @@ struct em28xx_board em28xx_boards[] = {
24022402
.tuner_type = TUNER_ABSENT,
24032403
.tuner_gpio = hauppauge_dualhd_dvb,
24042404
.has_dvb = 1,
2405+
.has_dual_ts = 1,
24052406
.ir_codes = RC_MAP_HAUPPAUGE,
24062407
.leds = hauppauge_dualhd_leds,
24072408
},
@@ -2417,6 +2418,7 @@ struct em28xx_board em28xx_boards[] = {
24172418
.tuner_type = TUNER_ABSENT,
24182419
.tuner_gpio = hauppauge_dualhd_dvb,
24192420
.has_dvb = 1,
2421+
.has_dual_ts = 1,
24202422
.ir_codes = RC_MAP_HAUPPAUGE,
24212423
.leds = hauppauge_dualhd_leds,
24222424
},
@@ -3239,7 +3241,8 @@ static void em28xx_release_resources(struct em28xx *dev)
32393241
em28xx_i2c_unregister(dev, 1);
32403242
em28xx_i2c_unregister(dev, 0);
32413243

3242-
usb_put_dev(udev);
3244+
if (dev->ts == PRIMARY_TS)
3245+
usb_put_dev(udev);
32433246

32443247
/* Mark device as unused */
32453248
clear_bit(dev->devno, em28xx_devused);
@@ -3432,6 +3435,35 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
34323435
return 0;
34333436
}
34343437

3438+
int em28xx_duplicate_dev(struct em28xx *dev)
3439+
{
3440+
int nr;
3441+
struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL);
3442+
3443+
if (sec_dev == NULL) {
3444+
dev->dev_next = NULL;
3445+
return -ENOMEM;
3446+
}
3447+
memcpy(sec_dev, dev, sizeof(sizeof(*sec_dev)));
3448+
/* Check to see next free device and mark as used */
3449+
do {
3450+
nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
3451+
if (nr >= EM28XX_MAXBOARDS) {
3452+
/* No free device slots */
3453+
dev_warn(&dev->intf->dev, ": Supports only %i em28xx boards.\n",
3454+
EM28XX_MAXBOARDS);
3455+
kfree(sec_dev);
3456+
dev->dev_next = NULL;
3457+
return -ENOMEM;
3458+
}
3459+
} while (test_and_set_bit(nr, em28xx_devused));
3460+
sec_dev->devno = nr;
3461+
snprintf(sec_dev->name, 28, "em28xx #%d", nr);
3462+
sec_dev->dev_next = NULL;
3463+
dev->dev_next = sec_dev;
3464+
return 0;
3465+
}
3466+
34353467
/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
34363468
#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
34373469

@@ -3551,6 +3583,17 @@ static int em28xx_usb_probe(struct usb_interface *interface,
35513583
}
35523584
}
35533585
break;
3586+
case 0x85:
3587+
if (usb_endpoint_xfer_isoc(e)) {
3588+
if (size > dev->dvb_max_pkt_size_isoc_ts2) {
3589+
dev->dvb_ep_isoc_ts2 = e->bEndpointAddress;
3590+
dev->dvb_max_pkt_size_isoc_ts2 = size;
3591+
dev->dvb_alt_isoc = i;
3592+
}
3593+
} else {
3594+
dev->dvb_ep_bulk_ts2 = e->bEndpointAddress;
3595+
}
3596+
break;
35543597
}
35553598
}
35563599
/* NOTE:
@@ -3565,6 +3608,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
35653608
* 0x83 isoc* => audio
35663609
* 0x84 isoc => digital
35673610
* 0x84 bulk => analog or digital**
3611+
* 0x85 isoc => digital TS2
3612+
* 0x85 bulk => digital TS2
35683613
* (*: audio should always be isoc)
35693614
* (**: analog, if ep 0x82 is isoc, otherwise digital)
35703615
*
@@ -3632,6 +3677,10 @@ static int em28xx_usb_probe(struct usb_interface *interface,
36323677
dev->has_video = has_video;
36333678
dev->ifnum = ifnum;
36343679

3680+
dev->ts = PRIMARY_TS;
3681+
snprintf(dev->name, 28, "em28xx");
3682+
dev->dev_next = NULL;
3683+
36353684
if (has_vendor_audio) {
36363685
dev_err(&interface->dev,
36373686
"Audio interface %i found (Vendor Class)\n", ifnum);
@@ -3711,6 +3760,65 @@ static int em28xx_usb_probe(struct usb_interface *interface,
37113760
dev->dvb_xfer_bulk ? "bulk" : "isoc");
37123761
}
37133762

3763+
if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) {
3764+
dev->dev_next->ts = SECONDARY_TS;
3765+
dev->dev_next->alt = -1;
3766+
dev->dev_next->is_audio_only = has_vendor_audio &&
3767+
!(has_video || has_dvb);
3768+
dev->dev_next->has_video = false;
3769+
dev->dev_next->ifnum = ifnum;
3770+
dev->dev_next->model = id->driver_info;
3771+
3772+
mutex_init(&dev->dev_next->lock);
3773+
retval = em28xx_init_dev(dev->dev_next, udev, interface,
3774+
dev->dev_next->devno);
3775+
if (retval)
3776+
goto err_free;
3777+
3778+
dev->dev_next->board.ir_codes = NULL; /* No IR for 2nd tuner */
3779+
dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */
3780+
3781+
if (usb_xfer_mode < 0) {
3782+
if (dev->dev_next->board.is_webcam)
3783+
try_bulk = 1;
3784+
else
3785+
try_bulk = 0;
3786+
} else {
3787+
try_bulk = usb_xfer_mode > 0;
3788+
}
3789+
3790+
/* Select USB transfer types to use */
3791+
if (has_dvb) {
3792+
if (!dev->dvb_ep_isoc_ts2 ||
3793+
(try_bulk && dev->dvb_ep_bulk_ts2))
3794+
dev->dev_next->dvb_xfer_bulk = 1;
3795+
dev_info(&dev->intf->dev, "dvb ts2 set to %s mode.\n",
3796+
dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc");
3797+
}
3798+
3799+
dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2;
3800+
dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2;
3801+
dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2;
3802+
dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc;
3803+
3804+
/* Configuare hardware to support TS2*/
3805+
if (dev->dvb_xfer_bulk) {
3806+
/* The ep4 and ep5 are configuared for BULK */
3807+
em28xx_write_reg(dev, 0x0b, 0x96);
3808+
mdelay(100);
3809+
em28xx_write_reg(dev, 0x0b, 0x80);
3810+
mdelay(100);
3811+
} else {
3812+
/* The ep4 and ep5 are configuared for ISO */
3813+
em28xx_write_reg(dev, 0x0b, 0x96);
3814+
mdelay(100);
3815+
em28xx_write_reg(dev, 0x0b, 0x82);
3816+
mdelay(100);
3817+
}
3818+
3819+
kref_init(&dev->dev_next->ref);
3820+
}
3821+
37143822
kref_init(&dev->ref);
37153823

37163824
request_modules(dev);
@@ -3753,15 +3861,29 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
37533861
if (!dev)
37543862
return;
37553863

3864+
if (dev->dev_next != NULL) {
3865+
dev->dev_next->disconnected = 1;
3866+
dev_info(&dev->intf->dev, "Disconnecting %s\n",
3867+
dev->dev_next->name);
3868+
flush_request_modules(dev->dev_next);
3869+
}
3870+
37563871
dev->disconnected = 1;
37573872

3758-
dev_err(&dev->intf->dev, "Disconnecting\n");
3873+
dev_err(&dev->intf->dev, "Disconnecting %s\n", dev->name);
37593874

37603875
flush_request_modules(dev);
37613876

37623877
em28xx_close_extension(dev);
37633878

3879+
if (dev->dev_next != NULL)
3880+
em28xx_release_resources(dev->dev_next);
37643881
em28xx_release_resources(dev);
3882+
3883+
if (dev->dev_next != NULL) {
3884+
kref_put(&dev->dev_next->ref, em28xx_free_device);
3885+
dev->dev_next = NULL;
3886+
}
37653887
kref_put(&dev->ref, em28xx_free_device);
37663888
}
37673889

drivers/media/usb/em28xx/em28xx-core.c

+34-8
Original file line numberDiff line numberDiff line change
@@ -638,10 +638,18 @@ int em28xx_capture_start(struct em28xx *dev, int start)
638638
dev->chip_id == CHIP_ID_EM28174 ||
639639
dev->chip_id == CHIP_ID_EM28178) {
640640
/* The Transport Stream Enable Register moved in em2874 */
641-
rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
642-
start ?
643-
EM2874_TS1_CAPTURE_ENABLE : 0x00,
644-
EM2874_TS1_CAPTURE_ENABLE);
641+
if (dev->ts == PRIMARY_TS)
642+
rc = em28xx_write_reg_bits(dev,
643+
EM2874_R5F_TS_ENABLE,
644+
start ?
645+
EM2874_TS1_CAPTURE_ENABLE : 0x00,
646+
EM2874_TS1_CAPTURE_ENABLE);
647+
else
648+
rc = em28xx_write_reg_bits(dev,
649+
EM2874_R5F_TS_ENABLE,
650+
start ?
651+
EM2874_TS2_CAPTURE_ENABLE : 0x00,
652+
EM2874_TS2_CAPTURE_ENABLE);
645653
} else {
646654
/* FIXME: which is the best order? */
647655
/* video registers are sampled by VREF */
@@ -1077,7 +1085,11 @@ int em28xx_register_extension(struct em28xx_ops *ops)
10771085
mutex_lock(&em28xx_devlist_mutex);
10781086
list_add_tail(&ops->next, &em28xx_extension_devlist);
10791087
list_for_each_entry(dev, &em28xx_devlist, devlist) {
1080-
ops->init(dev);
1088+
if (ops->init) {
1089+
ops->init(dev);
1090+
if (dev->dev_next != NULL)
1091+
ops->init(dev->dev_next);
1092+
}
10811093
}
10821094
mutex_unlock(&em28xx_devlist_mutex);
10831095
pr_info("em28xx: Registered (%s) extension\n", ops->name);
@@ -1091,7 +1103,11 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
10911103

10921104
mutex_lock(&em28xx_devlist_mutex);
10931105
list_for_each_entry(dev, &em28xx_devlist, devlist) {
1094-
ops->fini(dev);
1106+
if (ops->fini) {
1107+
if (dev->dev_next != NULL)
1108+
ops->fini(dev->dev_next);
1109+
ops->fini(dev);
1110+
}
10951111
}
10961112
list_del(&ops->next);
10971113
mutex_unlock(&em28xx_devlist_mutex);
@@ -1106,8 +1122,11 @@ void em28xx_init_extension(struct em28xx *dev)
11061122
mutex_lock(&em28xx_devlist_mutex);
11071123
list_add_tail(&dev->devlist, &em28xx_devlist);
11081124
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
1109-
if (ops->init)
1125+
if (ops->init) {
11101126
ops->init(dev);
1127+
if (dev->dev_next != NULL)
1128+
ops->init(dev->dev_next);
1129+
}
11111130
}
11121131
mutex_unlock(&em28xx_devlist_mutex);
11131132
}
@@ -1118,8 +1137,11 @@ void em28xx_close_extension(struct em28xx *dev)
11181137

11191138
mutex_lock(&em28xx_devlist_mutex);
11201139
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
1121-
if (ops->fini)
1140+
if (ops->fini) {
1141+
if (dev->dev_next != NULL)
1142+
ops->fini(dev->dev_next);
11221143
ops->fini(dev);
1144+
}
11231145
}
11241146
list_del(&dev->devlist);
11251147
mutex_unlock(&em28xx_devlist_mutex);
@@ -1134,6 +1156,8 @@ int em28xx_suspend_extension(struct em28xx *dev)
11341156
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
11351157
if (ops->suspend)
11361158
ops->suspend(dev);
1159+
if (dev->dev_next != NULL)
1160+
ops->suspend(dev->dev_next);
11371161
}
11381162
mutex_unlock(&em28xx_devlist_mutex);
11391163
return 0;
@@ -1148,6 +1172,8 @@ int em28xx_resume_extension(struct em28xx *dev)
11481172
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
11491173
if (ops->resume)
11501174
ops->resume(dev);
1175+
if (dev->dev_next != NULL)
1176+
ops->resume(dev->dev_next);
11511177
}
11521178
mutex_unlock(&em28xx_devlist_mutex);
11531179
return 0;

drivers/media/usb/em28xx/em28xx-dvb.c

+26-7
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
199199
int rc;
200200
struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
201201
struct em28xx *dev = i2c_bus->dev;
202-
struct usb_device *udev = interface_to_usbdev(dev->intf);
203202
int dvb_max_packet_size, packet_multiplier, dvb_alt;
204203

205204
if (dev->dvb_xfer_bulk) {
@@ -218,7 +217,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
218217
dvb_alt = dev->dvb_alt_isoc;
219218
}
220219

221-
usb_set_interface(udev, dev->ifnum, dvb_alt);
222220
rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
223221
if (rc < 0)
224222
return rc;
@@ -1128,8 +1126,9 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
11281126

11291127
static int em28xx_dvb_init(struct em28xx *dev)
11301128
{
1131-
int result = 0;
1129+
int result = 0, dvb_alt = 0;
11321130
struct em28xx_dvb *dvb;
1131+
struct usb_device *udev;
11331132

11341133
if (dev->is_audio_only) {
11351134
/* Shouldn't initialize IR for this interface */
@@ -1914,7 +1913,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
19141913
si2168_config.ts_mode = SI2168_TS_SERIAL;
19151914
memset(&info, 0, sizeof(struct i2c_board_info));
19161915
strlcpy(info.type, "si2168", I2C_NAME_SIZE);
1917-
info.addr = 0x64;
1916+
if (dev->ts == PRIMARY_TS)
1917+
info.addr = 0x64;
1918+
else
1919+
info.addr = 0x67;
19181920
info.platform_data = &si2168_config;
19191921
request_module(info.type);
19201922
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
@@ -1940,7 +1942,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
19401942
#endif
19411943
memset(&info, 0, sizeof(struct i2c_board_info));
19421944
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
1943-
info.addr = 0x60;
1945+
if (dev->ts == PRIMARY_TS)
1946+
info.addr = 0x60;
1947+
else
1948+
info.addr = 0x63;
19441949
info.platform_data = &si2157_config;
19451950
request_module(info.type);
19461951
client = i2c_new_device(adapter, &info);
@@ -1976,7 +1981,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
19761981
lgdt3306a_config.fe = &dvb->fe[0];
19771982
lgdt3306a_config.i2c_adapter = &adapter;
19781983
strlcpy(info.type, "lgdt3306a", sizeof(info.type));
1979-
info.addr = 0x59;
1984+
if (dev->ts == PRIMARY_TS)
1985+
info.addr = 0x59;
1986+
else
1987+
info.addr = 0x0e;
19801988
info.platform_data = &lgdt3306a_config;
19811989
request_module(info.type);
19821990
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
@@ -2003,7 +2011,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
20032011
#endif
20042012
memset(&info, 0, sizeof(struct i2c_board_info));
20052013
strlcpy(info.type, "si2157", sizeof(info.type));
2006-
info.addr = 0x60;
2014+
if (dev->ts == PRIMARY_TS)
2015+
info.addr = 0x60;
2016+
else
2017+
info.addr = 0x62;
20072018
info.platform_data = &si2157_config;
20082019
request_module(info.type);
20092020

@@ -2046,6 +2057,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
20462057
if (result < 0)
20472058
goto out_free;
20482059

2060+
if (dev->dvb_xfer_bulk) {
2061+
dvb_alt = 0;
2062+
} else { /* isoc */
2063+
dvb_alt = dev->dvb_alt_isoc;
2064+
}
2065+
2066+
udev = interface_to_usbdev(dev->intf);
2067+
usb_set_interface(udev, dev->ifnum, dvb_alt);
20492068
dev_info(&dev->intf->dev, "DVB extension successfully initialized\n");
20502069

20512070
kref_get(&dev->ref);

0 commit comments

Comments
 (0)