From 59f8b0bf3c12598cf4a5b333b0287774dbbdbe1f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 5 Sep 2010 07:03:48 -0300 Subject: V4L/DVB: gspca_xirlink_cit: support bandwidth changing for devices with 1 alt setting Some xirlink_cit models have only 1 alt setting, but the actual used bandwidth can be programmed through a register use this to allow streaming while other isoc streams (for example sound) are active at the same time. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/xirlink_cit.c | 54 ++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) (limited to 'drivers/media/video/gspca/xirlink_cit.c') diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c index b13ecbaf3e68..c4e9b8c2eefc 100644 --- a/drivers/media/video/gspca/xirlink_cit.c +++ b/drivers/media/video/gspca/xirlink_cit.c @@ -2758,6 +2758,25 @@ static int sd_start(struct gspca_dev *gspca_dev) return 0; } +static int sd_isoc_nego(struct gspca_dev *gspca_dev) +{ + int ret, packet_size; + struct usb_host_interface *alt; + + alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); + packet_size -= 100; + if (packet_size < 300) + return -EIO; + alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size); + + ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); + if (ret < 0) + PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret); + + return ret; +} + static void sd_stopN(struct gspca_dev *gspca_dev) { cit_write_reg(gspca_dev, 0x0000, 0x010c); @@ -2766,12 +2785,15 @@ static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + struct usb_host_interface *alt; /* We cannot use gspca_dev->present here as that is not set when sd_init gets called and we get called from sd_init */ if (!gspca_dev->dev) return; + alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + switch (sd->model) { case CIT_MODEL0: /* HDG windows does this, but it causes the cams autogain to @@ -2826,6 +2848,10 @@ static void sd_stop0(struct gspca_dev *gspca_dev) restarting the stream after this */ /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */ cit_write_reg(gspca_dev, 0x00c0, 0x0100); + + /* Start isoc bandwidth "negotiation" at max isoc bandwith + next stream start */ + alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(1022); break; } } @@ -3135,6 +3161,19 @@ static const struct sd_desc sd_desc = { .pkt_scan = sd_pkt_scan, }; +static const struct sd_desc sd_desc_isoc_nego = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .isoc_nego = sd_isoc_nego, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .pkt_scan = sd_pkt_scan, +}; + /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { { USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 }, @@ -3152,6 +3191,8 @@ MODULE_DEVICE_TABLE(usb, device_table); static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { + const struct sd_desc *desc = &sd_desc; + switch (id->driver_info) { case CIT_MODEL0: case CIT_MODEL1: @@ -3159,16 +3200,21 @@ static int sd_probe(struct usb_interface *intf, return -ENODEV; break; case CIT_MODEL2: - case CIT_MODEL3: case CIT_MODEL4: - case CIT_IBM_NETCAM_PRO: if (intf->cur_altsetting->desc.bInterfaceNumber != 0) return -ENODEV; break; + case CIT_MODEL3: + if (intf->cur_altsetting->desc.bInterfaceNumber != 0) + return -ENODEV; + /* FIXME this likely applies to all model3 cams and probably + to other models too. */ + if (ibm_netcam_pro) + desc = &sd_desc_isoc_nego; + break; } - return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); + return gspca_dev_probe2(intf, id, desc, sizeof(struct sd), THIS_MODULE); } static struct usb_driver sd_driver = { -- cgit v1.2.3