diff options
Diffstat (limited to 'drivers/media/usb')
161 files changed, 6464 insertions, 12396 deletions
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index cfe8056b91a..39d824e2bb6 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -17,7 +17,6 @@ source "drivers/media/usb/cpia2/Kconfig" source "drivers/media/usb/zr364xx/Kconfig" source "drivers/media/usb/stkwebcam/Kconfig" source "drivers/media/usb/s2255/Kconfig" -source "drivers/media/usb/sn9c102/Kconfig" source "drivers/media/usb/usbtv/Kconfig" endif diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index 0935f47497a..7ac4b143dce 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ obj-$(CONFIG_USB_GSPCA) += gspca/ obj-$(CONFIG_USB_PWC) += pwc/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ -obj-$(CONFIG_USB_SN9C102) += sn9c102/ obj-$(CONFIG_VIDEO_AU0828) += au0828/ obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index dd32decb237..7fdadf9bc90 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -108,7 +108,7 @@ struct au0828_board au0828_boards[] = { .name = "DViCO FusionHDTV USB", .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, - .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, + .i2c_clk_divider = AU0828_I2C_CLK_20KHZ, }, [AU0828_BOARD_HAUPPAUGE_WOODBURY] = { .name = "Hauppauge Woodbury", @@ -270,18 +270,25 @@ void au0828_gpio_setup(struct au0828_dev *dev) * 9 - XC5000 Tuner */ - /* Into reset */ + /* Set relevant GPIOs as outputs (leave the EEPROM W/P + as an input since we will never touch it and it has + a pullup) */ au0828_write(dev, REG_003, 0x02); au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10); + + /* Into reset */ au0828_write(dev, REG_001, 0x0); au0828_write(dev, REG_000, 0x0); - msleep(100); + msleep(50); - /* Out of reset (leave the cs5340 in reset until needed) */ - au0828_write(dev, REG_003, 0x02); - au0828_write(dev, REG_001, 0x02); - au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10); - au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20); + /* Bring power supply out of reset */ + au0828_write(dev, REG_000, 0x80); + msleep(50); + + /* Bring xc5000 and au8522 out of reset (leave the + cs5340 in reset until needed) */ + au0828_write(dev, REG_001, 0x02); /* xc5000 */ + au0828_write(dev, REG_000, 0x80 | 0x20); /* PS + au8522 */ msleep(250); break; diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index bd9d19a73ef..ab45a6f9dcc 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -173,9 +173,8 @@ static int au0828_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) { int ifnum; -#ifdef CONFIG_VIDEO_AU0828_V4L2 - int retval; -#endif + int retval = 0; + struct au0828_dev *dev; struct usb_device *usbdev = interface_to_usbdev(interface); @@ -257,7 +256,11 @@ static int au0828_usb_probe(struct usb_interface *interface, #endif /* Digital TV */ - au0828_dvb_register(dev); + retval = au0828_dvb_register(dev); + if (retval) + pr_err("%s() au0282_dev_register failed\n", + __func__); + /* Store the pointer to the au0828_dev so it can be accessed in au0828_usb_disconnect */ @@ -268,7 +271,7 @@ static int au0828_usb_probe(struct usb_interface *interface, mutex_unlock(&dev->lock); - return 0; + return retval; } static struct usb_driver au0828_usb_driver = { diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 9a6f15613a3..d8b5d948027 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -33,6 +33,10 @@ #include "mxl5007t.h" #include "tda18271.h" +static int preallocate_big_buffers; +module_param_named(preallocate_big_buffers, preallocate_big_buffers, int, 0644); +MODULE_PARM_DESC(preallocate_big_buffers, "Preallocate the larger transfer buffers at module load time"); + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define _AU0828_BULKPIPE 0x83 @@ -110,16 +114,20 @@ static void urb_completion(struct urb *purb) int ptype = usb_pipetype(purb->pipe); unsigned char *ptr; - dprintk(2, "%s()\n", __func__); + dprintk(2, "%s: %d\n", __func__, purb->actual_length); - if (!dev) + if (!dev) { + dprintk(2, "%s: no dev!\n", __func__); return; + } - if (dev->urb_streaming == 0) + if (dev->urb_streaming == 0) { + dprintk(2, "%s: not streaming!\n", __func__); return; + } if (ptype != PIPE_BULK) { - printk(KERN_ERR "%s() Unsupported URB type %d\n", + printk(KERN_ERR "%s: Unsupported URB type %d\n", __func__, ptype); return; } @@ -153,9 +161,13 @@ static int stop_urb_transfer(struct au0828_dev *dev) dev->urb_streaming = 0; for (i = 0; i < URB_COUNT; i++) { - usb_kill_urb(dev->urbs[i]); - kfree(dev->urbs[i]->transfer_buffer); - usb_free_urb(dev->urbs[i]); + if (dev->urbs[i]) { + usb_kill_urb(dev->urbs[i]); + if (!preallocate_big_buffers) + kfree(dev->urbs[i]->transfer_buffer); + + usb_free_urb(dev->urbs[i]); + } } return 0; @@ -181,10 +193,18 @@ static int start_urb_transfer(struct au0828_dev *dev) purb = dev->urbs[i]; - purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL); + if (preallocate_big_buffers) + purb->transfer_buffer = dev->dig_transfer_buffer[i]; + else + purb->transfer_buffer = kzalloc(URB_BUFSIZE, + GFP_KERNEL); + if (!purb->transfer_buffer) { usb_free_urb(purb); dev->urbs[i] = NULL; + printk(KERN_ERR + "%s: failed big buffer allocation, err = %d\n", + __func__, ret); goto err; } @@ -217,6 +237,25 @@ err: return ret; } +static void au0828_start_transport(struct au0828_dev *dev) +{ + au0828_write(dev, 0x608, 0x90); + au0828_write(dev, 0x609, 0x72); + au0828_write(dev, 0x60a, 0x71); + au0828_write(dev, 0x60b, 0x01); + +} + +static void au0828_stop_transport(struct au0828_dev *dev, int full_stop) +{ + if (full_stop) { + au0828_write(dev, 0x608, 0x00); + au0828_write(dev, 0x609, 0x00); + au0828_write(dev, 0x60a, 0x00); + } + au0828_write(dev, 0x60b, 0x00); +} + static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; @@ -231,13 +270,17 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed) if (dvb) { mutex_lock(&dvb->lock); + dvb->start_count++; + dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__, + dvb->start_count, dvb->stop_count); if (dvb->feeding++ == 0) { /* Start transport */ - au0828_write(dev, 0x608, 0x90); - au0828_write(dev, 0x609, 0x72); - au0828_write(dev, 0x60a, 0x71); - au0828_write(dev, 0x60b, 0x01); + au0828_start_transport(dev); ret = start_urb_transfer(dev); + if (ret < 0) { + au0828_stop_transport(dev, 0); + dvb->feeding--; /* We ran out of memory... */ + } } mutex_unlock(&dvb->lock); } @@ -255,11 +298,19 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed) dprintk(1, "%s()\n", __func__); if (dvb) { + cancel_work_sync(&dev->restart_streaming); + mutex_lock(&dvb->lock); - if (--dvb->feeding == 0) { - /* Stop transport */ - ret = stop_urb_transfer(dev); - au0828_write(dev, 0x60b, 0x00); + dvb->stop_count++; + dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__, + dvb->start_count, dvb->stop_count); + if (dvb->feeding > 0) { + dvb->feeding--; + if (dvb->feeding == 0) { + /* Stop transport */ + ret = stop_urb_transfer(dev); + au0828_stop_transport(dev, 0); + } } mutex_unlock(&dvb->lock); } @@ -282,21 +333,50 @@ static void au0828_restart_dvb_streaming(struct work_struct *work) /* Stop transport */ stop_urb_transfer(dev); - au0828_write(dev, 0x608, 0x00); - au0828_write(dev, 0x609, 0x00); - au0828_write(dev, 0x60a, 0x00); - au0828_write(dev, 0x60b, 0x00); + au0828_stop_transport(dev, 1); /* Start transport */ - au0828_write(dev, 0x608, 0x90); - au0828_write(dev, 0x609, 0x72); - au0828_write(dev, 0x60a, 0x71); - au0828_write(dev, 0x60b, 0x01); + au0828_start_transport(dev); start_urb_transfer(dev); mutex_unlock(&dvb->lock); } +static int au0828_set_frontend(struct dvb_frontend *fe) +{ + struct au0828_dev *dev = fe->dvb->priv; + struct au0828_dvb *dvb = &dev->dvb; + int ret, was_streaming; + + mutex_lock(&dvb->lock); + was_streaming = dev->urb_streaming; + if (was_streaming) { + au0828_stop_transport(dev, 1); + + /* + * We can't hold a mutex here, as the restart_streaming + * kthread may also hold it. + */ + mutex_unlock(&dvb->lock); + cancel_work_sync(&dev->restart_streaming); + mutex_lock(&dvb->lock); + + stop_urb_transfer(dev); + } + mutex_unlock(&dvb->lock); + + ret = dvb->set_frontend(fe); + + if (was_streaming) { + mutex_lock(&dvb->lock); + au0828_start_transport(dev); + start_urb_transfer(dev); + mutex_unlock(&dvb->lock); + } + + return ret; +} + static int dvb_register(struct au0828_dev *dev) { struct au0828_dvb *dvb = &dev->dvb; @@ -304,6 +384,23 @@ static int dvb_register(struct au0828_dev *dev) dprintk(1, "%s()\n", __func__); + if (preallocate_big_buffers) { + int i; + for (i = 0; i < URB_COUNT; i++) { + dev->dig_transfer_buffer[i] = kzalloc(URB_BUFSIZE, + GFP_KERNEL); + + if (!dev->dig_transfer_buffer[i]) { + result = -ENOMEM; + + printk(KERN_ERR + "%s: failed buffer allocation (errno = %d)\n", + DRIVER_NAME, result); + goto fail_adapter; + } + } + } + INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming); /* register adapter */ @@ -324,6 +421,10 @@ static int dvb_register(struct au0828_dev *dev) goto fail_frontend; } + /* Hook dvb frontend */ + dvb->set_frontend = dvb->frontend->ops.set_frontend; + dvb->frontend->ops.set_frontend = au0828_set_frontend; + /* register demux stuff */ dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | @@ -375,6 +476,9 @@ static int dvb_register(struct au0828_dev *dev) /* register network adapter */ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); + + dvb->start_count = 0; + dvb->stop_count = 0; return 0; fail_fe_conn: @@ -391,6 +495,13 @@ fail_frontend: dvb_frontend_detach(dvb->frontend); dvb_unregister_adapter(&dvb->adapter); fail_adapter: + + if (preallocate_big_buffers) { + int i; + for (i = 0; i < URB_COUNT; i++) + kfree(dev->dig_transfer_buffer[i]); + } + return result; } @@ -403,6 +514,8 @@ void au0828_dvb_unregister(struct au0828_dev *dev) if (dvb->frontend == NULL) return; + cancel_work_sync(&dev->restart_streaming); + dvb_net_release(&dvb->net); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); @@ -411,6 +524,14 @@ void au0828_dvb_unregister(struct au0828_dev *dev) dvb_unregister_frontend(dvb->frontend); dvb_frontend_detach(dvb->frontend); dvb_unregister_adapter(&dvb->adapter); + + if (preallocate_big_buffers) { + int i; + for (i = 0; i < URB_COUNT; i++) + kfree(dev->dig_transfer_buffer[i]); + } + + } /* All the DVB attach calls go here, this function get's modified diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index f6154546b5c..9038194513c 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1109,7 +1109,7 @@ static void au0828_init_tuner(struct au0828_dev *dev) /* If we've never sent the standard in tuner core, do so now. We don't do this at device probe because we don't want to incur the cost of a firmware load */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->std); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->std); v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); i2c_gate_ctrl(dev, 0); } @@ -1368,7 +1368,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) have to make the au0828 bridge adjust the size of its capture buffer, which is currently hardcoded at 720x480 */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, norm); i2c_gate_ctrl(dev, 0); diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index ef1f57f22be..7112b9d956f 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -102,6 +102,10 @@ struct au0828_dvb { struct dmx_frontend fe_mem; struct dvb_net net; int feeding; + int start_count; + int stop_count; + + int (*set_frontend)(struct dvb_frontend *fe); }; enum au0828_stream_state { @@ -260,6 +264,10 @@ struct au0828_dev { /* USB / URB Related */ int urb_streaming; struct urb *urbs[URB_COUNT]; + + /* Preallocated transfer digital transfer buffers */ + + char *dig_transfer_buffer[URB_COUNT]; }; /* ----------------------------------------------------------- */ diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index 8b6275f8590..0bd96906339 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -390,7 +390,7 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) } if (fc_usb->iso_buffer != NULL) - pci_free_consistent(NULL, + usb_free_coherent(fc_usb->udev, fc_usb->buffer_size, fc_usb->iso_buffer, fc_usb->dma_addr); } @@ -407,8 +407,8 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize); - fc_usb->iso_buffer = pci_alloc_consistent(NULL, - bufsize, &fc_usb->dma_addr); + fc_usb->iso_buffer = usb_alloc_coherent(fc_usb->udev, + bufsize, GFP_KERNEL, &fc_usb->dma_addr); if (fc_usb->iso_buffer == NULL) return -ENOMEM; diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index be171928360..351a78a84c3 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -209,7 +209,7 @@ static void cpia2_usb_complete(struct urb *urb) { int i; unsigned char *cdata; - static int frame_ready = false; + static bool frame_ready = false; struct camera_data *cam = (struct camera_data *) urb->context; if (urb->status!=0) { diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 86feeeaf61c..f14c5e89a56 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig @@ -45,6 +45,8 @@ config VIDEO_CX231XX_DVB select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT ---help--- This adds support for DVB cards based on the diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 2f63029e7a3..30a0c69fb42 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1516,7 +1516,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) dev->ts1.height = 576; cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, true); } - call_all(dev, core, s_std, dev->norm); + call_all(dev, video, s_std, dev->norm); /* do mode control overrides */ cx231xx_do_mode_ctrl_overrides(dev); diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index 81a1d971d79..9b925874d39 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -665,8 +665,8 @@ static int cx231xx_audio_init(struct cx231xx *dev) cx231xx_info("cx231xx-audio.c: probing for cx231xx " "non standard usbaudio\n"); - err = snd_card_create(index[devnr], "Cx231xx Audio", THIS_MODULE, - 0, &card); + err = snd_card_new(&dev->udev->dev, index[devnr], "Cx231xx Audio", + THIS_MODULE, 0, &card); if (err < 0) return err; @@ -682,7 +682,6 @@ static int cx231xx_audio_init(struct cx231xx *dev) pcm->info_flags = 0; pcm->private_data = dev; strcpy(pcm->name, "Conexant cx231xx Capture"); - snd_card_set_dev(card, &dev->udev->dev); strcpy(card->driver, "Cx231xx-Audio"); strcpy(card->shortname, "Cx231xx Audio"); strcpy(card->longname, "Conexant cx231xx Audio"); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index a384f80f595..2ee03e4ddd8 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -709,6 +709,8 @@ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); /* table of devices that work with this driver */ struct usb_device_id cx231xx_id_table[] = { + {USB_DEVICE(0x1D19, 0x6109), + .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, {USB_DEVICE(0x0572, 0x5A3C), .driver_info = CX231XX_BOARD_UNKNOWN}, {USB_DEVICE(0x0572, 0x58A2), @@ -978,7 +980,6 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, int minor) { int retval = -ENOMEM; - int errCode; unsigned int maxh, maxw; dev->udev = udev; @@ -1014,8 +1015,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, /* Cx231xx pre card setup */ cx231xx_pre_card_setup(dev); - errCode = cx231xx_config(dev); - if (errCode) { + retval = cx231xx_config(dev); + if (retval) { cx231xx_errdev("error configuring device\n"); return -ENOMEM; } @@ -1024,12 +1025,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, dev->norm = dev->board.norm; /* register i2c bus */ - errCode = cx231xx_dev_init(dev); - if (errCode < 0) { - cx231xx_dev_uninit(dev); + retval = cx231xx_dev_init(dev); + if (retval) { cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n", - __func__, errCode); - return errCode; + __func__, retval); + goto err_dev_init; } /* Do board specific init */ @@ -1047,11 +1047,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, dev->interlaced = 0; dev->video_input = 0; - errCode = cx231xx_config(dev); - if (errCode < 0) { + retval = cx231xx_config(dev); + if (retval) { cx231xx_errdev("%s: cx231xx_config - errCode [%d]!\n", - __func__, errCode); - return errCode; + __func__, retval); + goto err_dev_init; } /* init video dma queues */ @@ -1075,9 +1075,9 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, } retval = cx231xx_register_analog_devices(dev); - if (retval < 0) { - cx231xx_release_resources(dev); - return retval; + if (retval) { + cx231xx_release_analog_resources(dev); + goto err_analog; } cx231xx_ir_init(dev); @@ -1085,6 +1085,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, cx231xx_init_extension(dev); return 0; +err_analog: + cx231xx_remove_from_devlist(dev); +err_dev_init: + cx231xx_dev_uninit(dev); + return retval; } #if defined(CONFIG_MODULES) && defined(MODULE) @@ -1132,7 +1137,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, char *speed; struct usb_interface_assoc_descriptor *assoc_desc; - udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; /* @@ -1161,6 +1165,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, return -ENOMEM; } + udev = usb_get_dev(interface_to_usbdev(interface)); + snprintf(dev->name, 29, "cx231xx #%d", nr); dev->devno = nr; dev->model = id->driver_info; @@ -1223,10 +1229,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (assoc_desc->bFirstInterface != ifnum) { cx231xx_err(DRIVER_NAME ": Not found " "matching IAD interface\n"); - clear_bit(dev->devno, &cx231xx_devused); - kfree(dev); - dev = NULL; - return -ENODEV; + retval = -ENODEV; + goto err_if; } cx231xx_info("registering interface %d\n", ifnum); @@ -1242,22 +1246,13 @@ static int cx231xx_usb_probe(struct usb_interface *interface, retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); if (retval) { cx231xx_errdev("v4l2_device_register failed\n"); - clear_bit(dev->devno, &cx231xx_devused); - kfree(dev); - dev = NULL; - return -EIO; + retval = -EIO; + goto err_v4l2; } /* allocate device struct */ retval = cx231xx_init_dev(dev, udev, nr); - if (retval) { - clear_bit(dev->devno, &cx231xx_devused); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - usb_set_intfdata(interface, NULL); - - return retval; - } + if (retval) + goto err_init; /* compute alternate max packet sizes for video */ uif = udev->actconfig->interface[dev->current_pcb_config. @@ -1275,11 +1270,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->video_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - clear_bit(dev->devno, &cx231xx_devused); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - return -ENOMEM; + retval = -ENOMEM; + goto err_video_alt; } for (i = 0; i < dev->video_mode.num_alt; i++) { @@ -1309,11 +1301,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->vbi_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - clear_bit(dev->devno, &cx231xx_devused); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - return -ENOMEM; + retval = -ENOMEM; + goto err_vbi_alt; } for (i = 0; i < dev->vbi_mode.num_alt; i++) { @@ -1344,11 +1333,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - clear_bit(dev->devno, &cx231xx_devused); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - return -ENOMEM; + retval = -ENOMEM; + goto err_sliced_cc_alt; } for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) { @@ -1380,11 +1366,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->ts1_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - clear_bit(dev->devno, &cx231xx_devused); - v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); - dev = NULL; - return -ENOMEM; + retval = -ENOMEM; + goto err_ts1_alt; } for (i = 0; i < dev->ts1_mode.num_alt; i++) { @@ -1411,6 +1394,29 @@ static int cx231xx_usb_probe(struct usb_interface *interface, request_modules(dev); return 0; +err_ts1_alt: + kfree(dev->sliced_cc_mode.alt_max_pkt_size); +err_sliced_cc_alt: + kfree(dev->vbi_mode.alt_max_pkt_size); +err_vbi_alt: + kfree(dev->video_mode.alt_max_pkt_size); +err_video_alt: + /* cx231xx_uninit_dev: */ + cx231xx_close_extension(dev); + cx231xx_ir_exit(dev); + cx231xx_release_analog_resources(dev); + cx231xx_417_unregister(dev); + cx231xx_remove_from_devlist(dev); + cx231xx_dev_uninit(dev); +err_init: + v4l2_device_unregister(&dev->v4l2_dev); +err_v4l2: + usb_set_intfdata(interface, NULL); +err_if: + usb_put_dev(udev); + clear_bit(dev->devno, &cx231xx_devused); + kfree(dev); + return retval; } /* diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index 96a5a096539..7c0f797f105 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c @@ -371,9 +371,9 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, mutex_lock(&dev->i2c_lock); for (i = 0; i < num; i++) { - addr = msgs[i].addr >> 1; + addr = msgs[i].addr; - dprintk2(2, "%s %s addr=%x len=%d:", + dprintk2(2, "%s %s addr=0x%x len=%d:", (msgs[i].flags & I2C_M_RD) ? "read" : "write", i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); if (!msgs[i].len) { @@ -390,32 +390,41 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap, rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]); if (i2c_debug >= 2) { for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); + printk(KERN_CONT " %02x", msgs[i].buf[byte]); } } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && msgs[i].addr == msgs[i + 1].addr && (msgs[i].len <= 2) && (bus->nr < 3)) { + /* write bytes */ + if (i2c_debug >= 2) { + for (byte = 0; byte < msgs[i].len; byte++) + printk(KERN_CONT " %02x", msgs[i].buf[byte]); + printk(KERN_CONT "\n"); + } /* read bytes */ + dprintk2(2, "plus %s %s addr=0x%x len=%d:", + (msgs[i+1].flags & I2C_M_RD) ? "read" : "write", + i+1 == num - 1 ? "stop" : "nonstop", addr, msgs[i+1].len); rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap, &msgs[i], &msgs[i + 1]); if (i2c_debug >= 2) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); + for (byte = 0; byte < msgs[i+1].len; byte++) + printk(KERN_CONT " %02x", msgs[i+1].buf[byte]); } i++; } else { /* write bytes */ if (i2c_debug >= 2) { for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); + printk(KERN_CONT " %02x", msgs[i].buf[byte]); } rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]); } if (rc < 0) goto err; if (i2c_debug >= 2) - printk("\n"); + printk(KERN_CONT "\n"); } mutex_unlock(&dev->i2c_lock); return num; diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c index 0f7b4244682..46d52fac868 100644 --- a/drivers/media/usb/cx231xx/cx231xx-input.c +++ b/drivers/media/usb/cx231xx/cx231xx-input.c @@ -1,7 +1,7 @@ /* * cx231xx IR glue driver * - * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com> + * Copyright (C) 2010 Mauro Carvalho Chehab * * Polaris (cx231xx) has its support for IR's with a design close to MCE. * however, a few designs are using an external I2C chip for IR, instead diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c index d7308ab7a90..2a34ceee480 100644 --- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c +++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c @@ -28,7 +28,7 @@ MODULE_PARM_DESC(pcb_debug, "enable pcb config debug messages [video]"); /******************************************************************************/ -struct pcb_config cx231xx_Scenario[] = { +static struct pcb_config cx231xx_Scenario[] = { { INDEX_SELFPOWER_DIGITAL_ONLY, /* index */ USB_SELF_POWER, /* power_type */ @@ -672,7 +672,7 @@ u32 initialize_cx231xx(struct cx231xx *dev) pcb config it is related to */ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4); - config_info = le32_to_cpu(*((u32 *) data)); + config_info = le32_to_cpu(*((__le32 *)data)); usb_speed = (u8) (config_info & 0x1); /* Verify this device belongs to Bus power or Self power device */ diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 99062610171..1f8751379e2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1009,7 +1009,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) dev->width = 720; dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480; - call_all(dev, core, s_std, dev->norm); + call_all(dev, video, s_std, dev->norm); /* We need to reset basic properties in the decoder related to resolution (since a standard change effects things like the number @@ -1108,7 +1108,7 @@ int cx231xx_s_input(struct file *file, void *priv, unsigned int i) /* There's a tuner, so reset the standard and put it on the last known frequency (since it was probably powered down until now */ - call_all(dev, core, s_std, dev->norm); + call_all(dev, video, s_std, dev->norm); } return 0; @@ -2099,7 +2099,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) /* Set the initial input */ video_mux(dev, dev->video_input); - call_all(dev, core, s_std, dev->norm); + call_all(dev, video, s_std, dev->norm); v4l2_ctrl_handler_init(&dev->ctrl_handler, 10); v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5); diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 2059d0c86ad..037e519bbaa 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -100,13 +100,6 @@ config DVB_USB_GL861 Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 receiver with USB ID 0db0:5581. -config DVB_USB_IT913X - tristate "ITE IT913X DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_IT913X_FE - help - Say Y here to support the ITE IT913X DVB-T USB2.0 - config DVB_USB_LME2510 tristate "LME DM04/QQBOX DVB-S USB2.0 support" depends on DVB_USB_V2 @@ -133,7 +126,7 @@ config DVB_USB_MXL111SF config DVB_USB_RTL28XXU tristate "Realtek RTL28xxU DVB USB support" - depends on DVB_USB_V2 + depends on DVB_USB_V2 && I2C_MUX select DVB_RTL2830 select DVB_RTL2832 select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile index 2c06714b9ef..bc38f03394c 100644 --- a/drivers/media/usb/dvb-usb-v2/Makefile +++ b/drivers/media/usb/dvb-usb-v2/Makefile @@ -22,9 +22,6 @@ obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o dvb-usb-ec168-objs := ec168.o obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o -dvb-usb-it913x-objs := it913x.o -obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o - dvb-usb-lmedm04-objs := lmedm04.o obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index d556042cf31..da47d2392f2 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -397,12 +397,13 @@ error: return ret; } +#define AF9015_EEPROM_SIZE 256 + /* hash (and dump) eeprom */ static int af9015_eeprom_hash(struct dvb_usb_device *d) { struct af9015_state *state = d_to_priv(d); int ret, i; - static const unsigned int AF9015_EEPROM_SIZE = 256; u8 buf[AF9015_EEPROM_SIZE]; struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, NULL}; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1ea17dc2a76..7b9b75f6077 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -21,6 +21,9 @@ #include "af9035.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static u16 af9035_checksum(const u8 *buf, size_t len) @@ -126,9 +129,15 @@ exit: /* write multiple registers */ static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) { - u8 wbuf[6 + len]; + u8 wbuf[MAX_XFER_SIZE]; u8 mbox = (reg >> 16) & 0xff; - struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL }; + struct usb_req req = { CMD_MEM_WR, mbox, 6 + len, wbuf, 0, NULL }; + + if (6 + len > sizeof(wbuf)) { + dev_warn(&d->udev->dev, "%s: i2c wr: len=%d is too big!\n", + KBUILD_MODNAME, len); + return -EOPNOTSUPP; + } wbuf[0] = len; wbuf[1] = 2; @@ -228,9 +237,17 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, msg[1].len); } else { /* I2C */ - u8 buf[5 + msg[0].len]; - struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf), + u8 buf[MAX_XFER_SIZE]; + struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len, buf, msg[1].len, msg[1].buf }; + + if (5 + msg[0].len > sizeof(buf)) { + dev_warn(&d->udev->dev, + "%s: i2c xfer: len=%d is too big!\n", + KBUILD_MODNAME, msg[0].len); + ret = -EOPNOTSUPP; + goto unlock; + } req.mbox |= ((msg[0].addr & 0x80) >> 3); buf[0] = msg[1].len; buf[1] = msg[0].addr << 1; @@ -257,9 +274,17 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, msg[0].len - 3); } else { /* I2C */ - u8 buf[5 + msg[0].len]; - struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf, - 0, NULL }; + u8 buf[MAX_XFER_SIZE]; + struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len, + buf, 0, NULL }; + + if (5 + msg[0].len > sizeof(buf)) { + dev_warn(&d->udev->dev, + "%s: i2c xfer: len=%d is too big!\n", + KBUILD_MODNAME, msg[0].len); + ret = -EOPNOTSUPP; + goto unlock; + } req.mbox |= ((msg[0].addr & 0x80) >> 3); buf[0] = msg[0].len; buf[1] = msg[0].addr << 1; @@ -296,6 +321,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, ret = -EOPNOTSUPP; } +unlock: mutex_unlock(&d->i2c_mutex); if (ret < 0) @@ -549,6 +575,10 @@ static int af9035_download_firmware(struct dvb_usb_device *d, if (ret < 0) goto err; + /* use default I2C address if eeprom has no address set */ + if (!tmp) + tmp = 0x3a; + if (state->chip_type == 0x9135) { ret = af9035_wr_reg(d, 0x004bfb, tmp); if (ret < 0) @@ -611,6 +641,7 @@ static int af9035_read_config(struct dvb_usb_device *d) /* demod I2C "address" */ state->af9033_config[0].i2c_addr = 0x38; + state->af9033_config[1].i2c_addr = 0x3a; state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; @@ -658,7 +689,9 @@ static int af9035_read_config(struct dvb_usb_device *d) if (ret < 0) goto err; - state->af9033_config[1].i2c_addr = tmp; + if (tmp) + state->af9033_config[1].i2c_addr = tmp; + dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n", __func__, tmp); } @@ -671,15 +704,41 @@ static int af9035_read_config(struct dvb_usb_device *d) if (ret < 0) goto err; - if (tmp == 0x00) - dev_dbg(&d->udev->dev, - "%s: [%d]tuner not set, using default\n", - __func__, i); - else + dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n", + __func__, i, tmp); + + /* tuner sanity check */ + if (state->chip_type == 0x9135) { + if (state->chip_version == 0x02) { + /* IT9135 BX (v2) */ + switch (tmp) { + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + state->af9033_config[i].tuner = tmp; + break; + } + } else { + /* IT9135 AX (v1) */ + switch (tmp) { + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + state->af9033_config[i].tuner = tmp; + break; + } + } + } else { + /* AF9035 */ state->af9033_config[i].tuner = tmp; + } - dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n", - __func__, i, state->af9033_config[i].tuner); + if (state->af9033_config[i].tuner != tmp) { + dev_info(&d->udev->dev, + "%s: [%d] overriding tuner from %02x to %02x\n", + KBUILD_MODNAME, i, tmp, + state->af9033_config[i].tuner); + } switch (state->af9033_config[i].tuner) { case AF9033_TUNER_TUA9001: @@ -912,12 +971,7 @@ static int af9035_frontend_callback(void *adapter_priv, int component, static int af9035_get_adapter_count(struct dvb_usb_device *d) { struct state *state = d_to_priv(d); - - /* disable 2nd adapter as we don't have PID filters implemented */ - if (d->udev->speed == USB_SPEED_FULL) - return 1; - else - return state->dual_mode + 1; + return state->dual_mode + 1; } static int af9035_frontend_attach(struct dvb_usb_adapter *adap) @@ -935,7 +989,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) /* attach demodulator */ adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id], - &d->i2c_adap); + &d->i2c_adap, &state->ops); if (adap->fe[0] == NULL) { ret = -ENODEV; goto err; @@ -1343,58 +1397,19 @@ static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, return 0; } -/* - * FIXME: PID filter is property of demodulator and should be moved to the - * correct driver. Also we support only adapter #0 PID filter and will - * disable adapter #1 if USB1.1 is used. - */ static int af9035_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - - dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); - - ret = af9035_wr_reg_mask(d, 0x80f993, onoff, 0x01); - if (ret < 0) - goto err; - - return 0; - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + struct state *state = adap_to_priv(adap); - return ret; + return state->ops.pid_filter_ctrl(adap->fe[0], onoff); } static int af9035_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - int ret; - u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; - - dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n", - __func__, index, pid, onoff); - - ret = af9035_wr_regs(d, 0x80f996, wbuf, 2); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0x80f994, onoff); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0x80f995, index); - if (ret < 0) - goto err; - - return 0; - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + struct state *state = adap_to_priv(adap); - return ret; + return state->ops.pid_filter(adap->fe[0], index, pid, onoff); } static int af9035_probe(struct usb_interface *intf, @@ -1468,6 +1483,13 @@ static const struct dvb_usb_device_properties af9035_props = { .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter_ctrl = af9035_pid_filter_ctrl, + .pid_filter = af9035_pid_filter, + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), }, }, @@ -1502,15 +1524,37 @@ static const struct usb_device_id af9035_id_table[] = { { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa, &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) }, /* IT9135 devices */ -#if 0 - { DVB_USB_DEVICE(0x048d, 0x9135, - &af9035_props, "IT9135 reference design", NULL) }, - { DVB_USB_DEVICE(0x048d, 0x9006, - &af9035_props, "IT9135 reference design", NULL) }, -#endif + { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135, + &af9035_props, "ITE 9135 Generic", RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005, + &af9035_props, "ITE 9135(9005) Generic", RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006, + &af9035_props, "ITE 9135(9006) Generic", RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_1835, + &af9035_props, "Avermedia A835B(1835)", RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_2835, + &af9035_props, "Avermedia A835B(2835)", RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_3835, + &af9035_props, "Avermedia A835B(3835)", RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835, + &af9035_props, "Avermedia A835B(4835)", RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335, + &af9035_props, "Avermedia H335", RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09, + &af9035_props, "Kworld UB499-2T T09", RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137, + &af9035_props, "Sveon STV22 Dual DVB-T HDTV", + RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, + &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2", + RC_MAP_IT913X_V1) }, /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099, &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a05, + &af9035_props, "Leadtek WinFast DTV Dongle Dual", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xf900, + &af9035_props, "Hauppauge WinTV-MiniStick 2", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index a1c68d829b8..c21902fdd4c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -62,6 +62,8 @@ struct state { u8 dual_mode:1; u16 eeprom_addr; struct af9033_config af9033_config[2]; + + struct af9033_ops ops; }; static const u32 clock_lut_af9035[] = { diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 90cfa35ef6e..eeab79bdd2a 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -442,6 +442,7 @@ static struct cxd2820r_config anysee_cxd2820r_config = { * IOD[0] ZL10353 1=enabled * IOE[0] tuner 0=enabled * tuner is behind ZL10353 I2C-gate + * tuner is behind TDA10023 I2C-gate * * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)" * PCB: 508TC (rev0.6) @@ -956,7 +957,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) if (fe && adap->fe[1]) { /* attach tuner for 2nd FE */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], + fe = dvb_attach(dvb_pll_attach, adap->fe[1], (0xc0 >> 1), &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); } diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index 44c64ef361b..c3c4b98733b 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -7,7 +7,7 @@ * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz * The original driver's license is GPL, as declared with MODULE_LICENSE() * - * Copyright (c) 2010-2012 Mauro Carvalho Chehab <mchehab@redhat.com> + * Copyright (c) 2010-2012 Mauro Carvalho Chehab * Driver modified by in order to work with upstream drxk driver, and * tons of bugs got fixed, and converted to use dvb-usb-v2. * @@ -68,6 +68,19 @@ static struct drxk_config terratec_h7_drxk = { .microcode_name = "dvb-usb-terratec-h7-drxk.fw", }; +static struct drxk_config cablestar_hdci_drxk = { + .adr = 0x29, + .parallel_ts = true, + .dynamic_clk = true, + .single_master = true, + .enable_merr_cfg = true, + .no_i2c_bridge = false, + .chunk_size = 64, + .mpeg_out_clk_strength = 0x02, + .qam_demod_parameter_count = 2, + .microcode_name = "dvb-usb-technisat-cablestar-hdci-drxk.fw", +}; + static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct az6007_device_state *st = fe_to_priv(fe); @@ -630,6 +643,27 @@ static int az6007_frontend_attach(struct dvb_usb_adapter *adap) return 0; } +static int az6007_cablestar_hdci_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct az6007_device_state *st = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); + + pr_debug("attaching demod drxk\n"); + + adap->fe[0] = dvb_attach(drxk_attach, &cablestar_hdci_drxk, + &d->i2c_adap); + if (!adap->fe[0]) + return -EINVAL; + + adap->fe[0]->sec_priv = adap; + st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl; + adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; + + az6007_ci_init(adap); + + return 0; +} + static int az6007_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap_to_d(adap); @@ -868,6 +902,29 @@ static struct dvb_usb_device_properties az6007_props = { } }; +static struct dvb_usb_device_properties az6007_cablestar_hdci_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .firmware = AZ6007_FIRMWARE, + + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct az6007_device_state), + .i2c_algo = &az6007_i2c_algo, + .tuner_attach = az6007_tuner_attach, + .frontend_attach = az6007_cablestar_hdci_frontend_attach, + .streaming_ctrl = az6007_streaming_ctrl, +/* ditch get_rc_config as it can't work (TS35 remote, I believe it's rc5) */ + .get_rc_config = NULL, + .read_mac_address = az6007_read_mac_addr, + .download_firmware = az6007_download_firmware, + .identify_state = az6007_identify_state, + .power_ctrl = az6007_power_ctrl, + .num_adapters = 1, + .adapter = { + { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), } + } +}; + static struct usb_device_id az6007_usb_table[] = { {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007, &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)}, @@ -875,6 +932,8 @@ static struct usb_device_id az6007_usb_table[] = { &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2, &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, + {DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI, + &az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)}, {0}, }; @@ -916,7 +975,7 @@ static struct usb_driver az6007_usb_driver = { module_usb_driver(az6007_usb_driver); MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones"); MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 8a054d66e70..e3558061893 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -164,7 +164,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) dev->driver_name = (char *) d->props->driver_name; dev->map_name = d->rc.map_name; dev->driver_type = d->rc.driver_type; - dev->allowed_protos = d->rc.allowed_protos; + rc_set_allowed_protocols(dev, d->rc.allowed_protos); dev->change_protocol = d->rc.change_protocol; dev->priv = d; @@ -399,7 +399,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) /* clear 'streaming' status bit */ clear_bit(ADAP_STREAMING, &adap->state_bits); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&adap->state_bits, ADAP_STREAMING); skip_feed_stop: @@ -550,7 +550,7 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe) err: if (!adap->suspend_resume_active) { clear_bit(ADAP_INIT, &adap->state_bits); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&adap->state_bits, ADAP_INIT); } @@ -591,7 +591,7 @@ err: if (!adap->suspend_resume_active) { adap->active_fe = -1; clear_bit(ADAP_SLEEP, &adap->state_bits); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); wake_up_bit(&adap->state_bits, ADAP_SLEEP); } diff --git a/drivers/media/usb/dvb-usb-v2/ec168.c b/drivers/media/usb/dvb-usb-v2/ec168.c index 5c68f3918bc..0c2b377704f 100644 --- a/drivers/media/usb/dvb-usb-v2/ec168.c +++ b/drivers/media/usb/dvb-usb-v2/ec168.c @@ -170,7 +170,7 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], error: mutex_unlock(&d->i2c_mutex); - return i; + return ret; } static u32 ec168_i2c_func(struct i2c_adapter *adapter) diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c deleted file mode 100644 index 1cb6899cf79..00000000000 --- a/drivers/media/usb/dvb-usb-v2/it913x.c +++ /dev/null @@ -1,825 +0,0 @@ -/* - * DVB USB compliant linux driver for ITE IT9135 and IT9137 - * - * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) - * IT9135 (C) ITE Tech Inc. - * IT9137 (C) ITE Tech Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * see Documentation/dvb/README.dvb-usb for more information - * see Documentation/dvb/it9137.txt for firmware information - * - */ -#define DVB_USB_LOG_PREFIX "it913x" - -#include <linux/usb.h> -#include <linux/usb/input.h> -#include <media/rc-core.h> - -#include "dvb_usb.h" -#include "it913x-fe.h" - -/* debug */ -static int dvb_usb_it913x_debug; -#define it_debug(var, level, args...) \ - do { if ((var & level)) pr_debug(DVB_USB_LOG_PREFIX": " args); \ -} while (0) -#define deb_info(level, args...) it_debug(dvb_usb_it913x_debug, level, args) -#define info(args...) pr_info(DVB_USB_LOG_PREFIX": " args) - -module_param_named(debug, dvb_usb_it913x_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); - -static int dvb_usb_it913x_firmware; -module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644); -MODULE_PARM_DESC(firmware, "set firmware 0=auto "\ - "1=IT9137 2=IT9135 V1 3=IT9135 V2"); -#define FW_IT9137 "dvb-usb-it9137-01.fw" -#define FW_IT9135_V1 "dvb-usb-it9135-01.fw" -#define FW_IT9135_V2 "dvb-usb-it9135-02.fw" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct it913x_state { - struct ite_config it913x_config; - u8 pid_filter_onoff; - bool proprietary_ir; - int cmd_counter; -}; - -static u16 check_sum(u8 *p, u8 len) -{ - u16 sum = 0; - u8 i = 1; - while (i < len) - sum += (i++ & 1) ? (*p++) << 8 : *p++; - return ~sum; -} - -static int it913x_io(struct dvb_usb_device *d, u8 mode, u8 pro, - u8 cmd, u32 reg, u8 addr, u8 *data, u8 len) -{ - struct it913x_state *st = d->priv; - int ret = 0, i, buf_size = 1; - u8 *buff; - u8 rlen; - u16 chk_sum; - - buff = kzalloc(256, GFP_KERNEL); - if (!buff) { - info("USB Buffer Failed"); - return -ENOMEM; - } - - buff[buf_size++] = pro; - buff[buf_size++] = cmd; - buff[buf_size++] = st->cmd_counter; - - switch (mode) { - case READ_LONG: - case WRITE_LONG: - buff[buf_size++] = len; - buff[buf_size++] = 2; - buff[buf_size++] = (reg >> 24); - buff[buf_size++] = (reg >> 16) & 0xff; - buff[buf_size++] = (reg >> 8) & 0xff; - buff[buf_size++] = reg & 0xff; - break; - case READ_SHORT: - buff[buf_size++] = addr; - break; - case WRITE_SHORT: - buff[buf_size++] = len; - buff[buf_size++] = addr; - buff[buf_size++] = (reg >> 8) & 0xff; - buff[buf_size++] = reg & 0xff; - break; - case READ_DATA: - case WRITE_DATA: - break; - case WRITE_CMD: - mode = 7; - break; - default: - kfree(buff); - return -EINVAL; - } - - if (mode & 1) { - for (i = 0; i < len ; i++) - buff[buf_size++] = data[i]; - } - chk_sum = check_sum(&buff[1], buf_size); - - buff[buf_size++] = chk_sum >> 8; - buff[0] = buf_size; - buff[buf_size++] = (chk_sum & 0xff); - - ret = dvb_usbv2_generic_rw(d, buff, buf_size, buff, (mode & 1) ? - 5 : len + 5); - if (ret < 0) - goto error; - - rlen = (mode & 0x1) ? 0x1 : len; - - if (mode & 1) - ret = buff[2]; - else - memcpy(data, &buff[3], rlen); - - st->cmd_counter++; - -error: kfree(buff); - - return ret; -} - -static int it913x_wr_reg(struct dvb_usb_device *d, u8 pro, u32 reg , u8 data) -{ - int ret; - u8 b[1]; - b[0] = data; - ret = it913x_io(d, WRITE_LONG, pro, - CMD_DEMOD_WRITE, reg, 0, b, sizeof(b)); - - return ret; -} - -static int it913x_read_reg(struct dvb_usb_device *d, u32 reg) -{ - int ret; - u8 data[1]; - - ret = it913x_io(d, READ_LONG, DEV_0, - CMD_DEMOD_READ, reg, 0, &data[0], sizeof(data)); - - return (ret < 0) ? ret : data[0]; -} - -static int it913x_query(struct dvb_usb_device *d, u8 pro) -{ - struct it913x_state *st = d->priv; - int ret, i; - u8 data[4]; - u8 ver; - - for (i = 0; i < 5; i++) { - ret = it913x_io(d, READ_LONG, pro, CMD_DEMOD_READ, - 0x1222, 0, &data[0], 3); - ver = data[0]; - if (ver > 0 && ver < 3) - break; - msleep(100); - } - - if (ver < 1 || ver > 2) { - info("Failed to identify chip version applying 1"); - st->it913x_config.chip_ver = 0x1; - st->it913x_config.chip_type = 0x9135; - return 0; - } - - st->it913x_config.chip_ver = ver; - st->it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; - - info("Chip Version=%02x Chip Type=%04x", st->it913x_config.chip_ver, - st->it913x_config.chip_type); - - ret = it913x_io(d, READ_SHORT, pro, - CMD_QUERYINFO, 0, 0x1, &data[0], 4); - - st->it913x_config.firmware = (data[0] << 24) | (data[1] << 16) | - (data[2] << 8) | data[3]; - - return ret; -} - -static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct it913x_state *st = adap_to_priv(adap); - int ret; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - - mutex_lock(&d->i2c_mutex); - - deb_info(1, "PID_C (%02x)", onoff); - - st->pid_filter_onoff = adap->pid_filtering; - ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff); - - mutex_unlock(&d->i2c_mutex); - return ret; -} - -static int it913x_pid_filter(struct dvb_usb_adapter *adap, - int index, u16 pid, int onoff) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct it913x_state *st = adap_to_priv(adap); - int ret; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - - mutex_lock(&d->i2c_mutex); - - deb_info(1, "PID_F (%02x)", onoff); - - ret = it913x_wr_reg(d, pro, PID_LSB, (u8)(pid & 0xff)); - - ret |= it913x_wr_reg(d, pro, PID_MSB, (u8)(pid >> 8)); - - ret |= it913x_wr_reg(d, pro, PID_INX_EN, (u8)onoff); - - ret |= it913x_wr_reg(d, pro, PID_INX, (u8)(index & 0x1f)); - - if (d->udev->speed == USB_SPEED_HIGH && pid == 0x2000) { - ret |= it913x_wr_reg(d , pro, PID_EN, !onoff); - st->pid_filter_onoff = !onoff; - } else - st->pid_filter_onoff = - adap->pid_filtering; - - mutex_unlock(&d->i2c_mutex); - return 0; -} - - -static int it913x_return_status(struct dvb_usb_device *d) -{ - struct it913x_state *st = d->priv; - int ret = it913x_query(d, DEV_0); - if (st->it913x_config.firmware > 0) - info("Firmware Version %d", st->it913x_config.firmware); - - return ret; -} - -static int it913x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - static u8 data[256]; - int ret; - u32 reg; - u8 pro; - - mutex_lock(&d->i2c_mutex); - - deb_info(2, "num of messages %d address %02x", num, msg[0].addr); - - pro = (msg[0].addr & 0x2) ? DEV_0_DMOD : 0x0; - pro |= (msg[0].addr & 0x20) ? DEV_1 : DEV_0; - memcpy(data, msg[0].buf, msg[0].len); - reg = (data[0] << 24) + (data[1] << 16) + - (data[2] << 8) + data[3]; - if (num == 2) { - ret = it913x_io(d, READ_LONG, pro, - CMD_DEMOD_READ, reg, 0, data, msg[1].len); - memcpy(msg[1].buf, data, msg[1].len); - } else - ret = it913x_io(d, WRITE_LONG, pro, CMD_DEMOD_WRITE, - reg, 0, &data[4], msg[0].len - 4); - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static u32 it913x_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm it913x_i2c_algo = { - .master_xfer = it913x_i2c_xfer, - .functionality = it913x_i2c_func, -}; - -/* Callbacks for DVB USB */ -#if IS_ENABLED(CONFIG_RC_CORE) -static int it913x_rc_query(struct dvb_usb_device *d) -{ - u8 ibuf[4]; - int ret; - u32 key; - /* Avoid conflict with frontends*/ - mutex_lock(&d->i2c_mutex); - - ret = it913x_io(d, READ_LONG, PRO_LINK, CMD_IR_GET, - 0, 0, &ibuf[0], sizeof(ibuf)); - - if ((ibuf[2] + ibuf[3]) == 0xff) { - key = ibuf[2]; - key += ibuf[0] << 16; - key += ibuf[1] << 8; - deb_info(1, "NEC Extended Key =%08x", key); - if (d->rc_dev != NULL) - rc_keydown(d->rc_dev, key, 0); - } - - mutex_unlock(&d->i2c_mutex); - - return ret; -} - -static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -{ - struct it913x_state *st = d->priv; - - if (st->proprietary_ir == false) { - rc->map_name = NULL; - return 0; - } - - rc->allowed_protos = RC_BIT_NEC; - rc->query = it913x_rc_query; - rc->interval = 250; - - return 0; -} -#else - #define it913x_get_rc_config NULL -#endif - -/* Firmware sets raw */ -static const char fw_it9135_v1[] = FW_IT9135_V1; -static const char fw_it9135_v2[] = FW_IT9135_V2; -static const char fw_it9137[] = FW_IT9137; - -static void ite_get_firmware_name(struct dvb_usb_device *d, - const char **name) -{ - struct it913x_state *st = d->priv; - int sw; - /* auto switch */ - if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_KWORLD_2) - sw = IT9137_FW; - else if (st->it913x_config.chip_ver == 1) - sw = IT9135_V1_FW; - else - sw = IT9135_V2_FW; - - /* force switch */ - if (dvb_usb_it913x_firmware != IT9135_AUTO) - sw = dvb_usb_it913x_firmware; - - switch (sw) { - case IT9135_V1_FW: - st->it913x_config.firmware_ver = 1; - st->it913x_config.adc_x2 = 1; - st->it913x_config.read_slevel = false; - *name = fw_it9135_v1; - break; - case IT9135_V2_FW: - st->it913x_config.firmware_ver = 1; - st->it913x_config.adc_x2 = 1; - st->it913x_config.read_slevel = false; - *name = fw_it9135_v2; - switch (st->it913x_config.tuner_id_0) { - case IT9135_61: - case IT9135_62: - break; - default: - info("Unknown tuner ID applying default 0x60"); - case IT9135_60: - st->it913x_config.tuner_id_0 = IT9135_60; - } - break; - case IT9137_FW: - default: - st->it913x_config.firmware_ver = 0; - st->it913x_config.adc_x2 = 0; - st->it913x_config.read_slevel = true; - *name = fw_it9137; - } - - return; -} - -#define TS_MPEG_PKT_SIZE 188 -#define EP_LOW 21 -#define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) -#define EP_HIGH 348 -#define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) - -static int it913x_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, - struct usb_data_stream_properties *stream) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - if (adap->pid_filtering) - stream->u.bulk.buffersize = TS_BUFFER_SIZE_PID; - else - stream->u.bulk.buffersize = TS_BUFFER_SIZE_MAX; - - return 0; -} - -static int it913x_select_config(struct dvb_usb_device *d) -{ - struct it913x_state *st = d->priv; - int ret, reg; - - ret = it913x_return_status(d); - if (ret < 0) - return ret; - - if (st->it913x_config.chip_ver == 0x02 - && st->it913x_config.chip_type == 0x9135) - reg = it913x_read_reg(d, 0x461d); - else - reg = it913x_read_reg(d, 0x461b); - - if (reg < 0) - return reg; - - if (reg == 0) { - st->it913x_config.dual_mode = 0; - st->it913x_config.tuner_id_0 = IT9135_38; - st->proprietary_ir = true; - } else { - /* TS mode */ - reg = it913x_read_reg(d, 0x49c5); - if (reg < 0) - return reg; - st->it913x_config.dual_mode = reg; - - /* IR mode type */ - reg = it913x_read_reg(d, 0x49ac); - if (reg < 0) - return reg; - if (reg == 5) { - info("Remote propriety (raw) mode"); - st->proprietary_ir = true; - } else if (reg == 1) { - info("Remote HID mode NOT SUPPORTED"); - st->proprietary_ir = false; - } - - /* Tuner_id */ - reg = it913x_read_reg(d, 0x49d0); - if (reg < 0) - return reg; - st->it913x_config.tuner_id_0 = reg; - } - - info("Dual mode=%x Tuner Type=%x", st->it913x_config.dual_mode, - st->it913x_config.tuner_id_0); - - return ret; -} - -static int it913x_streaming_ctrl(struct dvb_frontend *fe, int onoff) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - struct it913x_state *st = fe_to_priv(fe); - int ret = 0; - u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - - deb_info(1, "STM (%02x)", onoff); - - if (!onoff) { - mutex_lock(&d->i2c_mutex); - - ret = it913x_wr_reg(d, pro, PID_RST, 0x1); - - mutex_unlock(&d->i2c_mutex); - st->pid_filter_onoff = - adap->pid_filtering; - - } - - return ret; -} - -static int it913x_identify_state(struct dvb_usb_device *d, const char **name) -{ - struct it913x_state *st = d->priv; - int ret; - u8 reg; - - /* Read and select config */ - ret = it913x_select_config(d); - if (ret < 0) - return ret; - - ite_get_firmware_name(d, name); - - if (st->it913x_config.firmware > 0) - return WARM; - - if (st->it913x_config.dual_mode) { - st->it913x_config.tuner_id_1 = it913x_read_reg(d, 0x49e0); - ret = it913x_wr_reg(d, DEV_0, GPIOH1_EN, 0x1); - ret |= it913x_wr_reg(d, DEV_0, GPIOH1_ON, 0x1); - ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1); - msleep(50); - ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x0); - msleep(50); - reg = it913x_read_reg(d, GPIOH1_O); - if (reg == 0) { - ret |= it913x_wr_reg(d, DEV_0, GPIOH1_O, 0x1); - ret |= it913x_return_status(d); - if (ret != 0) - ret = it913x_wr_reg(d, DEV_0, - GPIOH1_O, 0x0); - } - } - - reg = it913x_read_reg(d, IO_MUX_POWER_CLK); - - if (st->it913x_config.dual_mode) { - ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); - if (st->it913x_config.firmware_ver == 1) - ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x1); - else - ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x1); - } else { - ret |= it913x_wr_reg(d, DEV_0, 0x4bfb, 0x0); - if (st->it913x_config.firmware_ver == 1) - ret |= it913x_wr_reg(d, DEV_0, 0xcfff, 0x0); - else - ret |= it913x_wr_reg(d, DEV_0, CLK_O_EN, 0x0); - } - - ret |= it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100); - - return (ret < 0) ? ret : COLD; -} - -static int it913x_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - struct it913x_state *st = d->priv; - int ret = 0, i = 0, pos = 0; - u8 packet_size, min_pkt; - u8 *fw_data; - - ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_100); - - info("FRM Starting Firmware Download"); - - /* Multi firmware loader */ - /* This uses scatter write firmware headers */ - /* The firmware must start with 03 XX 00 */ - /* and be the extact firmware length */ - - if (st->it913x_config.chip_ver == 2) - min_pkt = 0x11; - else - min_pkt = 0x19; - - while (i <= fw->size) { - if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0)) - || (i == fw->size)) { - packet_size = i - pos; - if ((packet_size > min_pkt) || (i == fw->size)) { - fw_data = (u8 *)(fw->data + pos); - pos += packet_size; - if (packet_size > 0) { - ret = it913x_io(d, WRITE_DATA, - DEV_0, CMD_SCATTER_WRITE, 0, - 0, fw_data, packet_size); - if (ret < 0) - break; - } - udelay(1000); - } - } - i++; - } - - if (ret < 0) - info("FRM Firmware Download Failed (%d)" , ret); - else - info("FRM Firmware Download Completed - Resetting Device"); - - msleep(30); - - ret = it913x_io(d, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); - if (ret < 0) - info("FRM Device not responding to reboot"); - - ret = it913x_return_status(d); - if (st->it913x_config.firmware == 0) { - info("FRM Failed to reboot device"); - return -ENODEV; - } - - msleep(30); - - ret = it913x_wr_reg(d, DEV_0, I2C_CLK, I2C_CLK_400); - - msleep(30); - - /* Tuner function */ - if (st->it913x_config.dual_mode) - ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0xa0); - else - ret |= it913x_wr_reg(d, DEV_0_DMOD , 0xec4c, 0x68); - - if ((st->it913x_config.chip_ver == 1) && - (st->it913x_config.chip_type == 0x9135)) { - ret |= it913x_wr_reg(d, DEV_0, PADODPU, 0x0); - ret |= it913x_wr_reg(d, DEV_0, AGC_O_D, 0x0); - if (st->it913x_config.dual_mode) { - ret |= it913x_wr_reg(d, DEV_1, PADODPU, 0x0); - ret |= it913x_wr_reg(d, DEV_1, AGC_O_D, 0x0); - } - } - - return (ret < 0) ? -ENODEV : 0; -} - -static int it913x_name(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - const char *desc = d->name; - char *fe_name[] = {"_1", "_2", "_3", "_4"}; - char *name = adap->fe[0]->ops.info.name; - - strlcpy(name, desc, 128); - strlcat(name, fe_name[adap->id], 128); - - return 0; -} - -static int it913x_frontend_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_usb_device *d = adap_to_d(adap); - struct it913x_state *st = d->priv; - int ret = 0; - u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); - u16 ep_size = (adap->pid_filtering) ? TS_BUFFER_SIZE_PID / 4 : - TS_BUFFER_SIZE_MAX / 4; - u8 pkt_size = 0x80; - - if (d->udev->speed != USB_SPEED_HIGH) - pkt_size = 0x10; - - st->it913x_config.adf = it913x_read_reg(d, IO_MUX_POWER_CLK); - - adap->fe[0] = dvb_attach(it913x_fe_attach, - &d->i2c_adap, adap_addr, &st->it913x_config); - - if (adap->id == 0 && adap->fe[0]) { - it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x1); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x1); - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x0f); - it913x_wr_reg(d, DEV_0, EP0_TX_NAK, 0x1b); - if (st->proprietary_ir == false) /* Enable endpoint 3 */ - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x3f); - else - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f); - it913x_wr_reg(d, DEV_0, EP4_TX_LEN_LSB, - ep_size & 0xff); - it913x_wr_reg(d, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8); - ret = it913x_wr_reg(d, DEV_0, EP4_MAX_PKT, pkt_size); - } else if (adap->id == 1 && adap->fe[0]) { - if (st->proprietary_ir == false) - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x7f); - else - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f); - it913x_wr_reg(d, DEV_0, EP5_TX_LEN_LSB, - ep_size & 0xff); - it913x_wr_reg(d, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8); - it913x_wr_reg(d, DEV_0, EP5_MAX_PKT, pkt_size); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_EN, 0x1); - it913x_wr_reg(d, DEV_1_DMOD, MP2IF_SERIAL, 0x1); - it913x_wr_reg(d, DEV_1, TOP_HOSTB_SER_MODE, 0x1); - it913x_wr_reg(d, DEV_0_DMOD, TSIS_ENABLE, 0x1); - it913x_wr_reg(d, DEV_0_DMOD, MP2_SW_RST, 0x0); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x0); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_HALF_PSB, 0x0); - it913x_wr_reg(d, DEV_0_DMOD, MP2IF_STOP_EN, 0x1); - it913x_wr_reg(d, DEV_1_DMOD, MPEG_FULL_SPEED, 0x0); - ret = it913x_wr_reg(d, DEV_1_DMOD, MP2IF_STOP_EN, 0x0); - } else - return -ENODEV; - - ret |= it913x_name(adap); - - return ret; -} - -/* DVB USB Driver */ -static int it913x_get_adapter_count(struct dvb_usb_device *d) -{ - struct it913x_state *st = d->priv; - if (st->it913x_config.dual_mode) - return 2; - return 1; -} - -static struct dvb_usb_device_properties it913x_properties = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .bInterfaceNumber = 0, - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct it913x_state), - - .identify_state = it913x_identify_state, - .i2c_algo = &it913x_i2c_algo, - - .download_firmware = it913x_download_firmware, - - .frontend_attach = it913x_frontend_attach, - .get_rc_config = it913x_get_rc_config, - .get_stream_config = it913x_get_stream_config, - .get_adapter_count = it913x_get_adapter_count, - .streaming_ctrl = it913x_streaming_ctrl, - - - .adapter = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER| - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = it913x_pid_filter, - .pid_filter_ctrl = it913x_pid_filter_ctrl, - .stream = - DVB_USB_STREAM_BULK(0x84, 10, TS_BUFFER_SIZE_MAX), - }, - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER| - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = it913x_pid_filter, - .pid_filter_ctrl = it913x_pid_filter_ctrl, - .stream = - DVB_USB_STREAM_BULK(0x85, 10, TS_BUFFER_SIZE_MAX), - } - } -}; - -static const struct usb_device_id it913x_id_table[] = { - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09, - &it913x_properties, "Kworld UB499-2T T09(IT9137)", - RC_MAP_IT913X_V1) }, - { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135, - &it913x_properties, "ITE 9135 Generic", - RC_MAP_IT913X_V1) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137, - &it913x_properties, "Sveon STV22 Dual DVB-T HDTV(IT9137)", - RC_MAP_IT913X_V1) }, - { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005, - &it913x_properties, "ITE 9135(9005) Generic", - RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006, - &it913x_properties, "ITE 9135(9006) Generic", - RC_MAP_IT913X_V1) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_1835, - &it913x_properties, "Avermedia A835B(1835)", - RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_2835, - &it913x_properties, "Avermedia A835B(2835)", - RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_3835, - &it913x_properties, "Avermedia A835B(3835)", - RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835, - &it913x_properties, "Avermedia A835B(4835)", - RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, - &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2", - RC_MAP_IT913X_V1) }, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, it913x_id_table); - -static struct usb_driver it913x_driver = { - .name = KBUILD_MODNAME, - .probe = dvb_usbv2_probe, - .disconnect = dvb_usbv2_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, - .id_table = it913x_id_table, -}; - -module_usb_driver(it913x_driver); - -MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); -MODULE_DESCRIPTION("it913x USB 2 Driver"); -MODULE_VERSION("1.33"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(FW_IT9135_V1); -MODULE_FIRMWARE(FW_IT9135_V2); -MODULE_FIRMWARE(FW_IT9137); - diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c index d83df4bb72d..0a98d04c53e 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c @@ -1,7 +1,7 @@ /* * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 @@ -601,7 +601,7 @@ struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); -MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h index 3f3f8bfd190..2d4530f5be5 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h @@ -1,7 +1,7 @@ /* * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c index e4121cb8f5e..a619410adde 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c @@ -1,7 +1,7 @@ /* * mxl111sf-gpio.c - driver for the MaxLinear MXL111SF * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h index 0220f54299a..b85a5772d77 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h @@ -1,7 +1,7 @@ /* * mxl111sf-gpio.h - driver for the MaxLinear MXL111SF * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c index 34434557ef6..a101d06eb14 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c @@ -1,7 +1,7 @@ /* * mxl111sf-i2c.c - driver for the MaxLinear MXL111SF * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h index a57a45ffb9e..465762145ad 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h @@ -1,7 +1,7 @@ /* * mxl111sf-i2c.h - driver for the MaxLinear MXL111SF * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c index b741b3a7a32..f6b348024be 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c @@ -1,7 +1,7 @@ /* * mxl111sf-phy.c - driver for the MaxLinear MXL111SF * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h index f0756071d34..0643738de7d 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h @@ -1,7 +1,7 @@ /* * mxl111sf-phy.h - driver for the MaxLinear MXL111SF * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h index 17831b0fb9d..89bf115e927 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h @@ -1,7 +1,7 @@ /* * mxl111sf-reg.h - driver for the MaxLinear MXL111SF * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c index 879c529640f..a8d2c705367 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c @@ -1,7 +1,7 @@ /* * mxl111sf-tuner.c - driver for the MaxLinear MXL111SF CMOS tuner * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 @@ -512,7 +512,7 @@ struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, EXPORT_SYMBOL_GPL(mxl111sf_tuner_attach); MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver"); -MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1"); diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h index 90f583e5d6a..2046db22519 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h @@ -1,7 +1,7 @@ /* * mxl111sf-tuner.h - driver for the MaxLinear MXL111SF CMOS tuner * - * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> + * Copyright (C) 2010-2014 Michael Krufky <mkrufky@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 @@ -68,7 +68,7 @@ struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, #else static inline struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, - struct mxl111sf_state *mxl_state + struct mxl111sf_state *mxl_state, struct mxl111sf_tuner_config *cfg) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index e97964ef7f5..c7304fa8ab7 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) + * Copyright (C) 2010-2014 Michael Krufky (mkrufky@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 @@ -23,6 +23,9 @@ #include "lgdt3305.h" #include "lg2160.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + int dvb_usb_mxl111sf_debug; module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level " @@ -57,7 +60,12 @@ int mxl111sf_ctrl_msg(struct dvb_usb_device *d, { int wo = (rbuf == NULL || rlen == 0); /* write-only */ int ret; - u8 sndbuf[1+wlen]; + u8 sndbuf[MAX_XFER_SIZE]; + + if (1 + wlen > sizeof(sndbuf)) { + pr_warn("%s: len=%d is too big!\n", __func__, wlen); + return -EOPNOTSUPP; + } pr_debug("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen); @@ -97,7 +105,7 @@ int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data) ret = -EINVAL; } - pr_debug("R: (0x%02x, 0x%02x)\n", addr, *data); + pr_debug("R: (0x%02x, 0x%02x)\n", addr, buf[1]); fail: return ret; } @@ -258,7 +266,7 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; int err; - /* exit if we didnt initialize the driver yet */ + /* exit if we didn't initialize the driver yet */ if (!state->chip_id) { mxl_debug("driver not yet initialized, exit."); goto fail; @@ -314,7 +322,7 @@ static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; int err; - /* exit if we didnt initialize the driver yet */ + /* exit if we didn't initialize the driver yet */ if (!state->chip_id) { mxl_debug("driver not yet initialized, exit."); goto fail; @@ -1413,7 +1421,7 @@ static struct usb_driver mxl111sf_usb_driver = { module_usb_driver(mxl111sf_usb_driver); -MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h index 9816de86e48..8516c011b7c 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.com) + * Copyright (C) 2010-2014 Michael Krufky (mkrufky@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 diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index c0cd0848631..a676e445284 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -35,6 +35,48 @@ #include "tua9001.h" #include "r820t.h" +/* + * RTL2832_SDR module is in staging. That logic is added in order to avoid any + * hard dependency to drivers/staging/ directory as we want compile mainline + * driver even whole staging directory is missing. + */ +#include <media/v4l2-subdev.h> + +#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR) +struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct rtl2832_config *cfg, + struct v4l2_subdev *sd); +#else +static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, const struct rtl2832_config *cfg, + struct v4l2_subdev *sd) +{ + return NULL; +} +#endif + +#ifdef CONFIG_MEDIA_ATTACH +#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \ + void *__r = NULL; \ + typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ + if (__a) { \ + __r = (void *) __a(ARGS); \ + if (__r == NULL) \ + symbol_put(FUNCTION); \ + } \ + __r; \ +}) + +#else +#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \ + FUNCTION(ARGS); \ +}) + +#endif + +static int rtl28xxu_disable_rc; +module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644); +MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req) @@ -377,6 +419,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf}; + struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf}; dev_dbg(&d->udev->dev, "%s:\n", __func__); @@ -489,6 +532,15 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) goto found; } + /* check R828D ID register; reg=00 val=69 */ + ret = rtl28xxu_ctrl_msg(d, &req_r828d); + if (ret == 0 && buf[0] == 0x69) { + priv->tuner = TUNER_RTL2832_R828D; + priv->tuner_name = "R828D"; + goto found; + } + + found: dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name); @@ -503,7 +555,7 @@ err: return ret; } -static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { +static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .ts_mode = 0, @@ -514,7 +566,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = { }; -static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { +static const struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .ts_mode = 0, @@ -524,7 +576,7 @@ static struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = { .agc_targ_val = 0x2d, }; -static struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { +static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .ts_mode = 0, @@ -538,7 +590,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *d = adap_to_d(adap); struct rtl28xxu_priv *priv = d_to_priv(d); - struct rtl2830_config *rtl2830_config; + const struct rtl2830_config *rtl2830_config; int ret; dev_dbg(&d->udev->dev, "%s:\n", __func__); @@ -573,33 +625,31 @@ err: return ret; } -static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, - .if_dvbt = 0, .tuner = TUNER_RTL2832_FC0012 }; -static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, - .if_dvbt = 0, .tuner = TUNER_RTL2832_FC0013 }; -static struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .tuner = TUNER_RTL2832_TUA9001, }; -static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_e4000_config = { .i2c_addr = 0x10, /* 0x20 */ .xtal = 28800000, .tuner = TUNER_RTL2832_E4000, }; -static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = { +static const struct rtl2832_config rtl28xxu_rtl2832_r820t_config = { .i2c_addr = 0x10, .xtal = 28800000, .tuner = TUNER_RTL2832_R820T, @@ -723,7 +773,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) int ret; struct dvb_usb_device *d = adap_to_d(adap); struct rtl28xxu_priv *priv = d_to_priv(d); - struct rtl2832_config *rtl2832_config; + const struct rtl2832_config *rtl2832_config; dev_dbg(&d->udev->dev, "%s:\n", __func__); @@ -745,6 +795,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) rtl2832_config = &rtl28xxu_rtl2832_e4000_config; break; case TUNER_RTL2832_R820T: + case TUNER_RTL2832_R828D: rtl2832_config = &rtl28xxu_rtl2832_r820t_config; break; default: @@ -761,6 +812,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) goto err; } + /* RTL2832 I2C repeater */ + priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]); + /* set fe callback */ adap->fe[0]->callback = rtl2832u_frontend_callback; @@ -840,11 +894,6 @@ err: return ret; } -static const struct e4000_config rtl2832u_e4000_config = { - .i2c_addr = 0x64, - .clock = 28800000, -}; - static const struct fc2580_config rtl2832u_fc2580_config = { .i2c_addr = 0x56, .clock = 16384000, @@ -866,15 +915,26 @@ static const struct r820t_config rtl2832u_r820t_config = { .rafael_chip = CHIP_R820T, }; +static const struct r820t_config rtl2832u_r828d_config = { + .i2c_addr = 0x3a, + .xtal = 16000000, + .max_i2c_msg_len = 2, + .rafael_chip = CHIP_R828D, +}; + static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) { int ret; struct dvb_usb_device *d = adap_to_d(adap); struct rtl28xxu_priv *priv = d_to_priv(d); - struct dvb_frontend *fe; + struct dvb_frontend *fe = NULL; + struct i2c_board_info info; + struct i2c_client *client; dev_dbg(&d->udev->dev, "%s:\n", __func__); + memset(&info, 0, sizeof(struct i2c_board_info)); + switch (priv->tuner) { case TUNER_RTL2832_FC0012: fe = dvb_attach(fc0012_attach, adap->fe[0], @@ -884,7 +944,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) * that to the tuner driver */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; - return 0; + + /* attach SDR */ + dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + &rtl28xxu_rtl2832_fc0012_config, NULL); break; case TUNER_RTL2832_FC0013: fe = dvb_attach(fc0013_attach, adap->fe[0], @@ -893,10 +956,43 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) /* fc0013 also supports signal strength reading */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; - return 0; - case TUNER_RTL2832_E4000: - fe = dvb_attach(e4000_attach, adap->fe[0], &d->i2c_adap, - &rtl2832u_e4000_config); + + /* attach SDR */ + dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + &rtl28xxu_rtl2832_fc0013_config, NULL); + break; + case TUNER_RTL2832_E4000: { + struct v4l2_subdev *sd; + struct i2c_adapter *i2c_adap_internal = + rtl2832_get_private_i2c_adapter(adap->fe[0]); + struct e4000_config e4000_config = { + .fe = adap->fe[0], + .clock = 28800000, + }; + + strlcpy(info.type, "e4000", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &e4000_config; + + request_module(info.type); + client = i2c_new_device(priv->demod_i2c_adapter, &info); + if (client == NULL || client->dev.driver == NULL) + break; + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + break; + } + + priv->client = client; + sd = i2c_get_clientdata(client); + i2c_set_adapdata(i2c_adap_internal, d); + + /* attach SDR */ + dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], + i2c_adap_internal, + &rtl28xxu_rtl2832_e4000_config, sd); + } break; case TUNER_RTL2832_FC2580: fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap, @@ -922,14 +1018,38 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) /* Use tuner to get the signal strength */ adap->fe[0]->ops.read_signal_strength = adap->fe[0]->ops.tuner_ops.get_rf_strength; + + /* attach SDR */ + dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap, + &rtl28xxu_rtl2832_r820t_config, NULL); + break; + case TUNER_RTL2832_R828D: + /* power off mn88472 demod on GPIO0 */ + ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x01); + if (ret) + goto err; + + ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01); + if (ret) + goto err; + + ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01); + if (ret) + goto err; + + fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap, + &rtl2832u_r828d_config); + + /* Use tuner to get the signal strength */ + adap->fe[0]->ops.read_signal_strength = + adap->fe[0]->ops.tuner_ops.get_rf_strength; break; default: - fe = NULL; dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, priv->tuner); } - if (fe == NULL) { + if (fe == NULL && priv->client == NULL) { ret = -ENODEV; goto err; } @@ -974,6 +1094,22 @@ err: return ret; } +static void rtl28xxu_exit(struct dvb_usb_device *d) +{ + struct rtl28xxu_priv *priv = d->priv; + struct i2c_client *client = priv->client; + + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* remove I2C tuner */ + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + return; +} + static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; @@ -1283,6 +1419,10 @@ err: static int rtl2832u_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { + /* disable IR interrupts in order to avoid SDR sample loss */ + if (rtl28xxu_disable_rc) + return rtl28xx_wr_reg(d, IR_RX_IE, 0x00); + /* load empty to enable rc */ if (!rc->map_name) rc->map_name = RC_MAP_EMPTY; @@ -1332,6 +1472,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = { .frontend_attach = rtl2832u_frontend_attach, .tuner_attach = rtl2832u_tuner_attach, .init = rtl28xxu_init, + .exit = rtl28xxu_exit, .get_rc_config = rtl2832u_get_rc_config, .num_adapters = 1, @@ -1343,6 +1484,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = { }; static const struct usb_device_id rtl28xxu_id_table[] = { + /* RTL2831U devices: */ { DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U, &rtl2831u_props, "Realtek RTL2831U reference design", NULL) }, { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT, @@ -1350,6 +1492,7 @@ static const struct usb_device_id rtl28xxu_id_table[] = { { DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2, &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) }, + /* RTL2832U devices: */ { DVB_USB_DEVICE(USB_VID_REALTEK, 0x2832, &rtl2832u_props, "Realtek RTL2832U reference design", NULL) }, { DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838, @@ -1362,12 +1505,16 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl2832u_props, "TerraTec NOXON DAB Stick", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2, &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV3, + &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) }, { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0, &rtl2832u_props, "Trekstor DVB-T Stick Terres 2.0", NULL) }, { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101, &rtl2832u_props, "Dexatek DK DVB-T Dongle", NULL) }, { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6680, &rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID, + &rtl2832u_props, "Leadtek Winfast DTV Dongle Mini D", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3, &rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) }, { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102, @@ -1388,6 +1535,18 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) }, { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A, &rtl2832u_props, "Crypto ReDi PC 50 A", NULL) }, + { DVB_USB_DEVICE(USB_VID_KYE, 0x707f, + &rtl2832u_props, "Genius TVGo DVB-T03", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd395, + &rtl2832u_props, "Peak DVB-T USB", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_RTL2832U, + &rtl2832u_props, "Sveon STV20", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27, + &rtl2832u_props, "Sveon STV27", NULL) }, + + /* RTL2832P devices: */ + { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131, + &rtl2832u_props, "Astrometa DVB-T2", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h index 729b3540c2f..a26cab10f38 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h @@ -55,7 +55,9 @@ struct rtl28xxu_priv { u8 tuner; char *tuner_name; u8 page; /* integrated demod active register page */ + struct i2c_adapter *demod_i2c_adapter; bool rc_active; + struct i2c_client *client; }; enum rtl28xxu_chip_id { @@ -83,6 +85,7 @@ enum rtl28xxu_tuner { TUNER_RTL2832_TDA18272, TUNER_RTL2832_FC0013, TUNER_RTL2832_R820T, + TUNER_RTL2832_R828D, }; struct rtl28xxu_req { diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c index ea2d5ee8657..0df52ab32a7 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -254,7 +254,7 @@ static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = { -struct stb0899_config az6027_stb0899_config = { +static struct stb0899_config az6027_stb0899_config = { .init_dev = az6027_stb0899_s1_init_1, .init_s2_demod = stb0899_s2_init_2, .init_s1_demod = az6027_stb0899_s1_init_3, @@ -291,7 +291,7 @@ struct stb0899_config az6027_stb0899_config = { .tuner_set_rfsiggain = NULL, }; -struct stb6100_config az6027_stb6100_config = { +static struct stb6100_config az6027_stb6100_config = { .tuner_address = 0xc0, .refclock = 27000000, }; @@ -1088,6 +1088,7 @@ static struct usb_device_id az6027_usb_table[] = { { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) }, { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V2) }, { }, }; @@ -1136,7 +1137,7 @@ static struct dvb_usb_device_properties az6027_properties = { .i2c_algo = &az6027_i2c_algo, - .num_device_descs = 6, + .num_device_descs = 7, .devices = { { .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", @@ -1162,6 +1163,10 @@ static struct dvb_usb_device_properties az6027_properties = { .name = "Elgato EyeTV Sat", .cold_ids = { &az6027_usb_table[5], NULL }, .warm_ids = { NULL }, + }, { + .name = "Elgato EyeTV Sat", + .cold_ids = { &az6027_usb_table[6], NULL }, + .warm_ids = { NULL }, }, { NULL }, } diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 3940bb0f9ef..a1c641e1836 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -43,6 +43,9 @@ #include "lgs8gxx.h" #include "atbm8830.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + /* debug */ static int dvb_usb_cxusb_debug; module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); @@ -57,7 +60,14 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) { int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 sndbuf[1+wlen]; + u8 sndbuf[MAX_XFER_SIZE]; + + if (1 + wlen > sizeof(sndbuf)) { + warn("i2c wr: len=%d is too big!\n", + wlen); + return -EOPNOTSUPP; + } + memset(sndbuf, 0, 1+wlen); sndbuf[0] = cmd; @@ -139,6 +149,7 @@ 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 ret; int i; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) @@ -158,7 +169,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], if (msg[i].flags & I2C_M_RD) { /* read only */ - u8 obuf[3], ibuf[1+msg[i].len]; + u8 obuf[3], ibuf[MAX_XFER_SIZE]; + + if (1 + msg[i].len > sizeof(ibuf)) { + warn("i2c rd: len=%d is too big!\n", + msg[i].len); + ret = -EOPNOTSUPP; + goto unlock; + } obuf[0] = 0; obuf[1] = msg[i].len; obuf[2] = msg[i].addr; @@ -172,7 +190,20 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && msg[i].addr == msg[i+1].addr) { /* write to then read from same address */ - u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; + u8 obuf[MAX_XFER_SIZE], ibuf[MAX_XFER_SIZE]; + + if (3 + msg[i].len > sizeof(obuf)) { + warn("i2c wr: len=%d is too big!\n", + msg[i].len); + ret = -EOPNOTSUPP; + goto unlock; + } + if (1 + msg[i + 1].len > sizeof(ibuf)) { + warn("i2c rd: len=%d is too big!\n", + msg[i + 1].len); + ret = -EOPNOTSUPP; + goto unlock; + } obuf[0] = msg[i].len; obuf[1] = msg[i+1].len; obuf[2] = msg[i].addr; @@ -191,7 +222,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], i++; } else { /* write only */ - u8 obuf[2+msg[i].len], ibuf; + u8 obuf[MAX_XFER_SIZE], ibuf; + + if (2 + msg[i].len > sizeof(obuf)) { + warn("i2c wr: len=%d is too big!\n", + msg[i].len); + ret = -EOPNOTSUPP; + goto unlock; + } obuf[0] = msg[i].addr; obuf[1] = msg[i].len; memcpy(&obuf[2], msg[i].buf, msg[i].len); @@ -204,8 +242,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } } + if (i == num) + ret = num; + else + ret = -EREMOTEIO; + +unlock: mutex_unlock(&d->i2c_mutex); - return i == num ? num : -EREMOTEIO; + return ret; } static u32 cxusb_i2c_func(struct i2c_adapter *adapter) diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h index 637b6123f39..927617d9561 100644 --- a/drivers/media/usb/dvb-usb/dib0700.h +++ b/drivers/media/usb/dvb-usb/dib0700.h @@ -59,7 +59,7 @@ extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3); extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen); extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw); -extern int dib0700_rc_setup(struct dvb_usb_device *d); +extern int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf); 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, diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index bf2a908d74c..c14285fa827 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -754,17 +754,20 @@ resubmit: usb_submit_urb(purb, GFP_ATOMIC); } -int dib0700_rc_setup(struct dvb_usb_device *d) +int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) { struct dib0700_state *st = d->priv; struct urb *purb; - int ret; + const struct usb_endpoint_descriptor *e; + int ret, rc_ep = 1; + unsigned int pipe = 0; /* Poll-based. Don't initialize bulk mode */ - if (st->fw_version < 0x10200) + if (st->fw_version < 0x10200 || !intf) return 0; /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ + purb = usb_alloc_urb(0, GFP_KERNEL); if (purb == NULL) { err("rc usb alloc urb failed"); @@ -779,9 +782,35 @@ int dib0700_rc_setup(struct dvb_usb_device *d) } purb->status = -EINPROGRESS; - usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1), - purb->transfer_buffer, RC_MSG_SIZE_V1_20, - dib0700_rc_urb_completion, d); + + /* + * Some devices like the Hauppauge NovaTD model 52009 use an interrupt + * endpoint, while others use a bulk one. + */ + e = &intf->altsetting[0].endpoint[rc_ep].desc; + if (usb_endpoint_dir_in(e)) { + if (usb_endpoint_xfer_bulk(e)) { + pipe = usb_rcvbulkpipe(d->udev, rc_ep); + usb_fill_bulk_urb(purb, d->udev, pipe, + purb->transfer_buffer, + RC_MSG_SIZE_V1_20, + dib0700_rc_urb_completion, d); + + } else if (usb_endpoint_xfer_int(e)) { + pipe = usb_rcvintpipe(d->udev, rc_ep); + usb_fill_int_urb(purb, d->udev, pipe, + purb->transfer_buffer, + RC_MSG_SIZE_V1_20, + dib0700_rc_urb_completion, d, 1); + } + } + + if (!pipe) { + err("There's no endpoint for remote controller"); + kfree(purb->transfer_buffer); + usb_free_urb(purb); + return 0; + } ret = usb_submit_urb(purb, GFP_ATOMIC); if (ret) { @@ -820,7 +849,7 @@ static int dib0700_probe(struct usb_interface *intf, else dev->props.rc.core.bulk_mode = false; - dib0700_rc_setup(dev); + dib0700_rc_setup(dev, intf); return 0; } diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 829323e42ca..10e0db8d185 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -514,7 +514,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) /* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */ - dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */ + dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */ d->last_event = 0; switch (d->props.rc.core.protocol) { diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index c2dded92f1d..6d68af0c49c 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -12,6 +12,9 @@ #include <linux/kconfig.h> #include "dibusb.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS); @@ -105,11 +108,16 @@ EXPORT_SYMBOL(dibusb2_0_power_ctrl); static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) { - u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ + u8 sndbuf[MAX_XFER_SIZE]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ /* write only ? */ int wo = (rbuf == NULL || rlen == 0), len = 2 + wlen + (wo ? 0 : 2); + if (4 + wlen > sizeof(sndbuf)) { + warn("i2c wr: len=%d is too big!\n", wlen); + return -EOPNOTSUPP; + } + sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; sndbuf[1] = (addr << 1) | (wo ? 0 : 1); diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c index 41bacff2496..4058aea9272 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c @@ -272,7 +272,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) dev->driver_name = d->props.rc.core.module_name; dev->map_name = d->props.rc.core.rc_codes; dev->change_protocol = d->props.rc.core.change_protocol; - dev->allowed_protos = d->props.rc.core.allowed_protos; + rc_set_allowed_protocols(dev, d->props.rc.core.allowed_protos); dev->driver_type = d->props.rc.core.driver_type; usb_to_input_id(d->udev, &dev->input_id); dev->input_name = "IR-receiver inside an USB DVB receiver"; diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 6e237b6dd0a..ae0f56a32e4 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -2,7 +2,7 @@ * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, * TeVii S600, S630, S650, S660, S480, S421, S632 * Prof 1100, 7500, - * Geniatech SU3000 Cards + * Geniatech SU3000, T220 Cards * Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by) * * This program is free software; you can redistribute it and/or modify it @@ -29,6 +29,11 @@ #include "stb6100.h" #include "stb6100_proc.h" #include "m88rs2000.h" +#include "tda18271.h" +#include "cxd2820r.h" + +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 #ifndef USB_PID_DW2102 #define USB_PID_DW2102 0x2102 @@ -107,11 +112,6 @@ "Please see linux/Documentation/dvb/ for more details " \ "on firmware-problems." -struct rc_map_dvb_usb_table_table { - struct rc_map_table *rc_keys; - int rc_keys_size; -}; - struct su3000_state { u8 initialized; }; @@ -126,12 +126,6 @@ module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." DVB_USB_DEBUG_STATUS); -/* keymaps */ -static int ir_keymap; -module_param_named(keymap, ir_keymap, int, 0644); -MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..." - " 256=none"); - /* demod probe */ static int demod_probe = 1; module_param_named(demod, demod_probe, int, 0644); @@ -298,6 +292,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret; if (!d) return -ENODEV; @@ -308,7 +303,15 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms case 2: { /* read */ /* first write first register number */ - u8 ibuf[msg[1].len + 2], obuf[3]; + u8 ibuf[MAX_XFER_SIZE], obuf[3]; + + if (2 + msg[1].len > sizeof(ibuf)) { + warn("i2c rd: len=%d is too big!\n", + msg[1].len); + ret = -EOPNOTSUPP; + goto unlock; + } + obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; @@ -325,7 +328,15 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms switch (msg[0].addr) { case 0x68: { /* write to register */ - u8 obuf[msg[0].len + 2]; + u8 obuf[MAX_XFER_SIZE]; + + if (2 + msg[0].len > sizeof(obuf)) { + warn("i2c wr: len=%d is too big!\n", + msg[1].len); + ret = -EOPNOTSUPP; + goto unlock; + } + obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); @@ -335,7 +346,15 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms } case 0x61: { /* write to tuner */ - u8 obuf[msg[0].len + 2]; + u8 obuf[MAX_XFER_SIZE]; + + if (2 + msg[0].len > sizeof(obuf)) { + warn("i2c wr: len=%d is too big!\n", + msg[1].len); + ret = -EOPNOTSUPP; + goto unlock; + } + obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); @@ -362,15 +381,17 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms break; } + ret = num; +unlock: mutex_unlock(&d->i2c_mutex); - return num; + return ret; } static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int len, i, j; + int len, i, j, ret; if (!d) return -ENODEV; @@ -401,7 +422,15 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i default: { if (msg[j].flags == I2C_M_RD) { /* read registers */ - u8 ibuf[msg[j].len + 2]; + u8 ibuf[MAX_XFER_SIZE]; + + if (2 + msg[j].len > sizeof(ibuf)) { + warn("i2c rd: len=%d is too big!\n", + msg[j].len); + ret = -EOPNOTSUPP; + goto unlock; + } + dw210x_op_rw(d->udev, 0xc3, (msg[j].addr << 1) + 1, 0, ibuf, msg[j].len + 2, @@ -430,7 +459,15 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i } while (len > 0); } else { /* write registers */ - u8 obuf[msg[j].len + 2]; + u8 obuf[MAX_XFER_SIZE]; + + if (2 + msg[j].len > sizeof(obuf)) { + warn("i2c wr: len=%d is too big!\n", + msg[j].len); + ret = -EOPNOTSUPP; + goto unlock; + } + obuf[0] = msg[j].addr << 1; obuf[1] = msg[j].len; memcpy(obuf + 2, msg[j].buf, msg[j].len); @@ -443,15 +480,18 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i } } + ret = num; +unlock: mutex_unlock(&d->i2c_mutex); - return num; + return ret; } static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret; int i; if (!d) @@ -463,7 +503,14 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], case 2: { /* read */ /* first write first register number */ - u8 ibuf[msg[1].len + 2], obuf[3]; + u8 ibuf[MAX_XFER_SIZE], obuf[3]; + + if (2 + msg[1].len > sizeof(ibuf)) { + warn("i2c rd: len=%d is too big!\n", + msg[1].len); + ret = -EOPNOTSUPP; + goto unlock; + } obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; @@ -481,7 +528,14 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], case 0x60: case 0x0c: { /* write to register */ - u8 obuf[msg[0].len + 2]; + u8 obuf[MAX_XFER_SIZE]; + + if (2 + msg[0].len > sizeof(obuf)) { + warn("i2c wr: len=%d is too big!\n", + msg[0].len); + ret = -EOPNOTSUPP; + goto unlock; + } obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); @@ -506,9 +560,11 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], msg[i].flags == 0 ? ">>>" : "<<<"); debug_dump(msg[i].buf, msg[i].len, deb_xfer); } + ret = num; +unlock: mutex_unlock(&d->i2c_mutex); - return num; + return ret; } static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], @@ -516,7 +572,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct usb_device *udev; - int len, i, j; + int len, i, j, ret; if (!d) return -ENODEV; @@ -563,7 +619,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], default: { if (msg[j].flags == I2C_M_RD) { /* read registers */ - u8 ibuf[msg[j].len]; + u8 ibuf[MAX_XFER_SIZE]; + + if (msg[j].len > sizeof(ibuf)) { + warn("i2c rd: len=%d is too big!\n", + msg[j].len); + ret = -EOPNOTSUPP; + goto unlock; + } + dw210x_op_rw(d->udev, 0x91, 0, 0, ibuf, msg[j].len, DW210X_READ_MSG); @@ -590,7 +654,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], } while (len > 0); } else if (j < (num - 1)) { /* write register addr before read */ - u8 obuf[msg[j].len + 2]; + u8 obuf[MAX_XFER_SIZE]; + + if (2 + msg[j].len > sizeof(obuf)) { + warn("i2c wr: len=%d is too big!\n", + msg[j].len); + ret = -EOPNOTSUPP; + goto unlock; + } + obuf[0] = msg[j + 1].len; obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); @@ -602,7 +674,14 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], break; } else { /* write registers */ - u8 obuf[msg[j].len + 2]; + u8 obuf[MAX_XFER_SIZE]; + + if (2 + msg[j].len > sizeof(obuf)) { + warn("i2c wr: len=%d is too big!\n", + msg[j].len); + ret = -EOPNOTSUPP; + goto unlock; + } obuf[0] = msg[j].len + 1; obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); @@ -615,9 +694,11 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], } } } + ret = num; +unlock: mutex_unlock(&d->i2c_mutex); - return num; + return ret; } static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], @@ -955,9 +1036,10 @@ static struct ds3000_config dw2104_ds3000_config = { .demod_address = 0x68, }; -static struct ts2020_config dw2104_ts2020_config = { +static struct ts2020_config dw2104_ts2020_config = { .tuner_address = 0x60, .clk_out_div = 1, + .frequency_div = 1060000, }; static struct ds3000_config s660_ds3000_config = { @@ -966,6 +1048,12 @@ static struct ds3000_config s660_ds3000_config = { .set_lock_led = dw210x_led_ctrl, }; +static struct ts2020_config s660_ts2020_config = { + .tuner_address = 0x60, + .clk_out_div = 1, + .frequency_div = 1146000, +}; + static struct stv0900_config dw2104a_stv0900_config = { .demod_address = 0x6a, .demod_mode = 0, @@ -1018,6 +1106,16 @@ static struct ds3000_config su3000_ds3000_config = { .set_lock_led = dw210x_led_ctrl, }; +static struct cxd2820r_config cxd2820r_config = { + .i2c_address = 0x6c, /* (0xd8 >> 1) */ + .ts_mode = 0x38, +}; + +static struct tda18271_config tda18271_config = { + .output_opt = TDA18271_OUTPUT_LT_OFF, + .gate = TDA18271_GATE_DIGITAL, +}; + static u8 m88rs2000_inittab[] = { DEMOD_WRITE, 0x9a, 0x30, DEMOD_WRITE, 0x00, 0x01, @@ -1205,7 +1303,7 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d) if (d->fe_adap[0].fe == NULL) return -EIO; - dvb_attach(ts2020_attach, d->fe_adap[0].fe, &dw2104_ts2020_config, + dvb_attach(ts2020_attach, d->fe_adap[0].fe, &s660_ts2020_config, &d->dev->i2c_adap); st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage; @@ -1213,7 +1311,7 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d) dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); - info("Attached ds3000+ds2020!\n"); + info("Attached ds3000+ts2020!\n"); return 0; } @@ -1287,6 +1385,49 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d) return -EIO; } +static int t220_frontend_attach(struct dvb_usb_adapter *d) +{ + u8 obuf[3] = { 0xe, 0x80, 0 }; + u8 ibuf[] = { 0 }; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 0; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + msleep(100); + + obuf[0] = 0xe; + obuf[1] = 0x80; + obuf[2] = 1; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0x51; + + if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) + err("command 0x51 transfer failed."); + + d->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config, + &d->dev->i2c_adap, NULL); + if (d->fe_adap[0].fe != NULL) { + if (dvb_attach(tda18271_attach, d->fe_adap[0].fe, 0x60, + &d->dev->i2c_adap, &tda18271_config)) { + info("Attached TDA18271HD/CXD2820R!\n"); + return 0; + } + } + + info("Failed to attach TDA18271HD/CXD2820R!\n"); + return -EIO; +} + static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d) { u8 obuf[] = { 0x51 }; @@ -1327,174 +1468,29 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static struct rc_map_table rc_map_dw210x_table[] = { - { 0xf80a, KEY_POWER2 }, /*power*/ - { 0xf80c, KEY_MUTE }, /*mute*/ - { 0xf811, KEY_1 }, - { 0xf812, KEY_2 }, - { 0xf813, KEY_3 }, - { 0xf814, KEY_4 }, - { 0xf815, KEY_5 }, - { 0xf816, KEY_6 }, - { 0xf817, KEY_7 }, - { 0xf818, KEY_8 }, - { 0xf819, KEY_9 }, - { 0xf810, KEY_0 }, - { 0xf81c, KEY_CHANNELUP }, /*ch+*/ - { 0xf80f, KEY_CHANNELDOWN }, /*ch-*/ - { 0xf81a, KEY_VOLUMEUP }, /*vol+*/ - { 0xf80e, KEY_VOLUMEDOWN }, /*vol-*/ - { 0xf804, KEY_RECORD }, /*rec*/ - { 0xf809, KEY_FAVORITES }, /*fav*/ - { 0xf808, KEY_REWIND }, /*rewind*/ - { 0xf807, KEY_FASTFORWARD }, /*fast*/ - { 0xf80b, KEY_PAUSE }, /*pause*/ - { 0xf802, KEY_ESC }, /*cancel*/ - { 0xf803, KEY_TAB }, /*tab*/ - { 0xf800, KEY_UP }, /*up*/ - { 0xf81f, KEY_OK }, /*ok*/ - { 0xf801, KEY_DOWN }, /*down*/ - { 0xf805, KEY_CAMERA }, /*cap*/ - { 0xf806, KEY_STOP }, /*stop*/ - { 0xf840, KEY_ZOOM }, /*full*/ - { 0xf81e, KEY_TV }, /*tvmode*/ - { 0xf81b, KEY_LAST }, /*recall*/ -}; - -static struct rc_map_table rc_map_tevii_table[] = { - { 0xf80a, KEY_POWER }, - { 0xf80c, KEY_MUTE }, - { 0xf811, KEY_1 }, - { 0xf812, KEY_2 }, - { 0xf813, KEY_3 }, - { 0xf814, KEY_4 }, - { 0xf815, KEY_5 }, - { 0xf816, KEY_6 }, - { 0xf817, KEY_7 }, - { 0xf818, KEY_8 }, - { 0xf819, KEY_9 }, - { 0xf810, KEY_0 }, - { 0xf81c, KEY_MENU }, - { 0xf80f, KEY_VOLUMEDOWN }, - { 0xf81a, KEY_LAST }, - { 0xf80e, KEY_OPEN }, - { 0xf804, KEY_RECORD }, - { 0xf809, KEY_VOLUMEUP }, - { 0xf808, KEY_CHANNELUP }, - { 0xf807, KEY_PVR }, - { 0xf80b, KEY_TIME }, - { 0xf802, KEY_RIGHT }, - { 0xf803, KEY_LEFT }, - { 0xf800, KEY_UP }, - { 0xf81f, KEY_OK }, - { 0xf801, KEY_DOWN }, - { 0xf805, KEY_TUNER }, - { 0xf806, KEY_CHANNELDOWN }, - { 0xf840, KEY_PLAYPAUSE }, - { 0xf81e, KEY_REWIND }, - { 0xf81b, KEY_FAVORITES }, - { 0xf81d, KEY_BACK }, - { 0xf84d, KEY_FASTFORWARD }, - { 0xf844, KEY_EPG }, - { 0xf84c, KEY_INFO }, - { 0xf841, KEY_AB }, - { 0xf843, KEY_AUDIO }, - { 0xf845, KEY_SUBTITLE }, - { 0xf84a, KEY_LIST }, - { 0xf846, KEY_F1 }, - { 0xf847, KEY_F2 }, - { 0xf85e, KEY_F3 }, - { 0xf85c, KEY_F4 }, - { 0xf852, KEY_F5 }, - { 0xf85a, KEY_F6 }, - { 0xf856, KEY_MODE }, - { 0xf858, KEY_SWITCHVIDEOMODE }, -}; - -static struct rc_map_table rc_map_tbs_table[] = { - { 0xf884, KEY_POWER }, - { 0xf894, KEY_MUTE }, - { 0xf887, KEY_1 }, - { 0xf886, KEY_2 }, - { 0xf885, KEY_3 }, - { 0xf88b, KEY_4 }, - { 0xf88a, KEY_5 }, - { 0xf889, KEY_6 }, - { 0xf88f, KEY_7 }, - { 0xf88e, KEY_8 }, - { 0xf88d, KEY_9 }, - { 0xf892, KEY_0 }, - { 0xf896, KEY_CHANNELUP }, - { 0xf891, KEY_CHANNELDOWN }, - { 0xf893, KEY_VOLUMEUP }, - { 0xf88c, KEY_VOLUMEDOWN }, - { 0xf883, KEY_RECORD }, - { 0xf898, KEY_PAUSE }, - { 0xf899, KEY_OK }, - { 0xf89a, KEY_SHUFFLE }, - { 0xf881, KEY_UP }, - { 0xf890, KEY_LEFT }, - { 0xf882, KEY_RIGHT }, - { 0xf888, KEY_DOWN }, - { 0xf895, KEY_FAVORITES }, - { 0xf897, KEY_SUBTITLE }, - { 0xf89d, KEY_ZOOM }, - { 0xf89f, KEY_EXIT }, - { 0xf89e, KEY_MENU }, - { 0xf89c, KEY_EPG }, - { 0xf880, KEY_PREVIOUS }, - { 0xf89b, KEY_MODE } -}; +static int dw2102_rc_query(struct dvb_usb_device *d) +{ + u8 key[2]; + struct i2c_msg msg = { + .addr = DW2102_RC_QUERY, + .flags = I2C_M_RD, + .buf = key, + .len = 2 + }; -static struct rc_map_table rc_map_su3000_table[] = { - { 0x25, KEY_POWER }, /* right-bottom Red */ - { 0x0a, KEY_MUTE }, /* -/-- */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x00, KEY_0 }, - { 0x20, KEY_UP }, /* CH+ */ - { 0x21, KEY_DOWN }, /* CH+ */ - { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ - { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */ - { 0x1f, KEY_RECORD }, - { 0x17, KEY_PLAY }, - { 0x16, KEY_PAUSE }, - { 0x0b, KEY_STOP }, - { 0x27, KEY_FASTFORWARD },/* >> */ - { 0x26, KEY_REWIND }, /* << */ - { 0x0d, KEY_OK }, /* Mute */ - { 0x11, KEY_LEFT }, /* VOL- */ - { 0x10, KEY_RIGHT }, /* VOL+ */ - { 0x29, KEY_BACK }, /* button under 9 */ - { 0x2c, KEY_MENU }, /* TTX */ - { 0x2b, KEY_EPG }, /* EPG */ - { 0x1e, KEY_RED }, /* OSD */ - { 0x0e, KEY_GREEN }, /* Window */ - { 0x2d, KEY_YELLOW }, /* button under << */ - { 0x0f, KEY_BLUE }, /* bottom yellow button */ - { 0x14, KEY_AUDIO }, /* Snapshot */ - { 0x38, KEY_TV }, /* TV/Radio */ - { 0x0c, KEY_ESC } /* upper Red button */ -}; + if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { + if (msg.buf[0] != 0xff) { + deb_rc("%s: rc code: %x, %x\n", + __func__, key[0], key[1]); + rc_keydown(d->rc_dev, key[0], 1); + } + } -static struct rc_map_dvb_usb_table_table keys_tables[] = { - { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) }, - { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) }, - { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) }, - { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) }, -}; + return 0; +} -static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int prof_rc_query(struct dvb_usb_device *d) { - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - int keymap_size = d->props.rc.legacy.rc_map_size; u8 key[2]; struct i2c_msg msg = { .addr = DW2102_RC_QUERY, @@ -1502,32 +1498,34 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) .buf = key, .len = 2 }; - int i; - /* override keymap */ - if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { - keymap = keys_tables[ir_keymap - 1].rc_keys ; - keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; - } else if (ir_keymap > ARRAY_SIZE(keys_tables)) - return 0; /* none */ - - *state = REMOTE_NO_KEY_PRESSED; - if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { - for (i = 0; i < keymap_size ; i++) { - if (rc5_data(&keymap[i]) == msg.buf[0]) { - *state = REMOTE_KEY_PRESSED; - *event = keymap[i].keycode; - break; - } + if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { + if (msg.buf[0] != 0xff) { + deb_rc("%s: rc code: %x, %x\n", + __func__, key[0], key[1]); + rc_keydown(d->rc_dev, key[0]^0xff, 1); } + } - if ((*state) == REMOTE_KEY_PRESSED) - deb_rc("%s: found rc key: %x, %x, event: %x\n", - __func__, key[0], key[1], (*event)); - else if (key[0] != 0xff) - deb_rc("%s: unknown rc key: %x, %x\n", - __func__, key[0], key[1]); + return 0; +} +static int su3000_rc_query(struct dvb_usb_device *d) +{ + u8 key[2]; + struct i2c_msg msg = { + .addr = DW2102_RC_QUERY, + .flags = I2C_M_RD, + .buf = key, + .len = 2 + }; + + if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { + if (msg.buf[0] != 0xff) { + deb_rc("%s: rc code: %x, %x\n", + __func__, key[0], key[1]); + rc_keydown(d->rc_dev, key[1] << 8 | key[0], 1); + } } return 0; @@ -1553,6 +1551,7 @@ enum dw2102_table_entry { TEVII_S632, TERRATEC_CINERGY_S2_R2, GOTVIEW_SAT_HD, + GENIATECH_T220, }; static struct usb_device_id dw2102_table[] = { @@ -1575,6 +1574,7 @@ static struct usb_device_id dw2102_table[] = { [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)}, [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, + [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, { } }; @@ -1634,9 +1634,7 @@ static int dw2102_load_firmware(struct usb_device *dev, /* init registers */ switch (dev->descriptor.idProduct) { case USB_PID_TEVII_S650: - dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table; - dw2104_properties.rc.legacy.rc_map_size = - ARRAY_SIZE(rc_map_tevii_table); + dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC; case USB_PID_DW2104: reset = 1; dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, @@ -1700,10 +1698,11 @@ static struct dvb_usb_device_properties dw2102_properties = { .i2c_algo = &dw2102_serit_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc.core = { .rc_interval = 150, + .rc_codes = RC_MAP_DM1105_NEC, + .module_name = "dw2102", + .allowed_protos = RC_BIT_NEC, .rc_query = dw2102_rc_query, }, @@ -1754,10 +1753,11 @@ static struct dvb_usb_device_properties dw2104_properties = { .no_reconnect = 1, .i2c_algo = &dw2104_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc.core = { .rc_interval = 150, + .rc_codes = RC_MAP_DM1105_NEC, + .module_name = "dw2102", + .allowed_protos = RC_BIT_NEC, .rc_query = dw2102_rc_query, }, @@ -1804,10 +1804,11 @@ static struct dvb_usb_device_properties dw3101_properties = { .no_reconnect = 1, .i2c_algo = &dw3101_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_dw210x_table, - .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table), + .rc.core = { .rc_interval = 150, + .rc_codes = RC_MAP_DM1105_NEC, + .module_name = "dw2102", + .allowed_protos = RC_BIT_NEC, .rc_query = dw2102_rc_query, }, @@ -1852,10 +1853,11 @@ static struct dvb_usb_device_properties s6x0_properties = { .no_reconnect = 1, .i2c_algo = &s6x0_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_tevii_table, - .rc_map_size = ARRAY_SIZE(rc_map_tevii_table), + .rc.core = { .rc_interval = 150, + .rc_codes = RC_MAP_TEVII_NEC, + .module_name = "dw2102", + .allowed_protos = RC_BIT_NEC, .rc_query = dw2102_rc_query, }, @@ -1945,11 +1947,12 @@ static struct dvb_usb_device_properties su3000_properties = { .identify_state = su3000_identify_state, .i2c_algo = &su3000_i2c_algo, - .rc.legacy = { - .rc_map_table = rc_map_su3000_table, - .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), + .rc.core = { .rc_interval = 150, - .rc_query = dw2102_rc_query, + .rc_codes = RC_MAP_SU3000, + .module_name = "dw2102", + .allowed_protos = RC_BIT_RC5, + .rc_query = su3000_rc_query, }, .read_mac_address = su3000_read_mac_address, @@ -2000,6 +2003,55 @@ static struct dvb_usb_device_properties su3000_properties = { } }; +static struct dvb_usb_device_properties t220_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct su3000_state), + .power_ctrl = su3000_power_ctrl, + .num_adapters = 1, + .identify_state = su3000_identify_state, + .i2c_algo = &su3000_i2c_algo, + + .rc.core = { + .rc_interval = 150, + .rc_codes = RC_MAP_SU3000, + .module_name = "dw2102", + .allowed_protos = RC_BIT_RC5, + .rc_query = su3000_rc_query, + }, + + .read_mac_address = su3000_read_mac_address, + + .generic_bulk_ctrl_endpoint = 0x01, + + .adapter = { + { + .num_frontends = 1, + .fe = { { + .streaming_ctrl = su3000_streaming_ctrl, + .frontend_attach = t220_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + } + } }, + } + }, + .num_device_descs = 1, + .devices = { + { "Geniatech T220 DVB-T/T2 USB2.0", + { &dw2102_table[GENIATECH_T220], NULL }, + { NULL }, + }, + } +}; + static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -2011,8 +2063,8 @@ static int dw2102_probe(struct usb_interface *intf, /* fill only different fields */ p1100->firmware = P1100_FIRMWARE; p1100->devices[0] = d1100; - p1100->rc.legacy.rc_map_table = rc_map_tbs_table; - p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); + p1100->rc.core.rc_query = prof_rc_query; + p1100->rc.core.rc_codes = RC_MAP_TBS_NEC; p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; s660 = kmemdup(&s6x0_properties, @@ -2037,8 +2089,8 @@ static int dw2102_probe(struct usb_interface *intf, } p7500->firmware = P7500_FIRMWARE; p7500->devices[0] = d7500; - p7500->rc.legacy.rc_map_table = rc_map_tbs_table; - p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); + p7500->rc.core.rc_query = prof_rc_query; + p7500->rc.core.rc_codes = RC_MAP_TBS_NEC; p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach; @@ -2072,7 +2124,9 @@ static int dw2102_probe(struct usb_interface *intf, 0 == dvb_usb_device_init(intf, s421, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &su3000_properties, - THIS_MODULE, NULL, adapter_nr)) + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &t220_properties, + THIS_MODULE, NULL, adapter_nr)) return 0; return -ENODEV; @@ -2092,7 +2146,7 @@ MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," " DVB-C 3101 USB2.0," " TeVii S600, S630, S650, S660, S480, S421, S632" " Prof 1100, 7500 USB2.0," - " Geniatech SU3000 devices"); + " Geniatech SU3000, T220 devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(DW2101_FIRMWARE); diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index 40832a1aef6..d947e037900 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -102,7 +102,7 @@ static int technisat_usb2_i2c_access(struct usb_device *udev, if (rxlen > 62) { err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)", device_addr); - txlen = 62; + rxlen = 62; } b[0] = I2C_SPEED_100KHZ_BIT; @@ -214,10 +214,10 @@ static void technisat_usb2_frontend_reset(struct usb_device *udev) /* LED control */ enum technisat_usb2_led_state { - LED_OFF, - LED_BLINK, - LED_ON, - LED_UNDEFINED + TECH_LED_OFF, + TECH_LED_BLINK, + TECH_LED_ON, + TECH_LED_UNDEFINED }; static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state) @@ -229,14 +229,14 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni 0 }; - if (disable_led_control && state != LED_OFF) + if (disable_led_control && state != TECH_LED_OFF) return 0; switch (state) { - case LED_ON: + case TECH_LED_ON: led[1] = 0x82; break; - case LED_BLINK: + case TECH_LED_BLINK: led[1] = 0x82; if (red) { led[2] = 0x02; @@ -251,7 +251,7 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni break; default: - case LED_OFF: + case TECH_LED_OFF: led[1] = 0x80; break; } @@ -310,11 +310,11 @@ static void technisat_usb2_green_led_control(struct work_struct *work) goto schedule; if (ber > 1000) - technisat_usb2_set_led(state->dev, 0, LED_BLINK); + technisat_usb2_set_led(state->dev, 0, TECH_LED_BLINK); else - technisat_usb2_set_led(state->dev, 0, LED_ON); + technisat_usb2_set_led(state->dev, 0, TECH_LED_ON); } else - technisat_usb2_set_led(state->dev, 0, LED_OFF); + technisat_usb2_set_led(state->dev, 0, TECH_LED_OFF); } schedule: @@ -365,9 +365,9 @@ static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level) return 0; /* green led is turned off in any case - will be turned on when tuning */ - technisat_usb2_set_led(d, 0, LED_OFF); + technisat_usb2_set_led(d, 0, TECH_LED_OFF); /* red led is turned on all the time */ - technisat_usb2_set_led(d, 1, LED_ON); + technisat_usb2_set_led(d, 1, TECH_LED_ON); return 0; } @@ -667,7 +667,7 @@ static int technisat_usb2_rc_query(struct dvb_usb_device *d) return 0; if (!disable_led_control) - technisat_usb2_set_led(d, 1, LED_BLINK); + technisat_usb2_set_led(d, 1, TECH_LED_BLINK); return 0; } diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index ca5ee6aceb6..f5d7198753c 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -1,8 +1,12 @@ config VIDEO_EM28XX - tristate "Empia EM28xx USB video capture support" + tristate "Empia EM28xx USB devices support" depends on VIDEO_DEV && I2C select VIDEO_TUNER select VIDEO_TVEEPROM + +config VIDEO_EM28XX_V4L2 + tristate "Empia EM28xx analog TV, video capture and/or webcam support" + depends on VIDEO_EM28XX select VIDEOBUF2_VMALLOC select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT @@ -49,6 +53,12 @@ config VIDEO_EM28XX_DVB select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT + select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT + select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT ---help--- This adds support for DVB cards based on the Empiatech em28xx chips. diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile index ad6d4855794..3f850d5063d 100644 --- a/drivers/media/usb/em28xx/Makefile +++ b/drivers/media/usb/em28xx/Makefile @@ -1,10 +1,11 @@ -em28xx-y += em28xx-video.o em28xx-i2c.o em28xx-cards.o -em28xx-y += em28xx-core.o em28xx-vbi.o em28xx-camera.o +em28xx-y += em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o +em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o em28xx-alsa-objs := em28xx-audio.o em28xx-rc-objs := em28xx-input.o obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o +obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 2fdb66ee44a..e881ef7b644 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -3,7 +3,7 @@ * * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> * - * Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com> + * Copyright (C) 2007-2014 Mauro Carvalho Chehab * - Port to work with the in-kernel driver * - Cleanups, fixes, alsa-controls, etc. * @@ -50,6 +50,9 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "activates debug info"); +#define EM28XX_MAX_AUDIO_BUFS 5 +#define EM28XX_MIN_AUDIO_PACKETS 64 + #define dprintk(fmt, arg...) do { \ if (debug) \ printk(KERN_INFO "em28xx-audio %s: " fmt, \ @@ -63,17 +66,13 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev) int i; dprintk("Stopping isoc\n"); - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { + for (i = 0; i < dev->adev.num_urb; i++) { + struct urb *urb = dev->adev.urb[i]; + if (!irqs_disabled()) - usb_kill_urb(dev->adev.urb[i]); + usb_kill_urb(urb); else - usb_unlink_urb(dev->adev.urb[i]); - - usb_free_urb(dev->adev.urb[i]); - dev->adev.urb[i] = NULL; - - kfree(dev->adev.transfer_buffer[i]); - dev->adev.transfer_buffer[i] = NULL; + usb_unlink_urb(urb); } return 0; @@ -91,6 +90,12 @@ static void em28xx_audio_isocirq(struct urb *urb) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; + if (dev->disconnected) { + dprintk("device disconnected while streaming. URB status=%d.\n", urb->status); + atomic_set(&dev->adev.stream_started, 0); + return; + } + switch (urb->status) { case 0: /* success */ case -ETIMEDOUT: /* NAK */ @@ -104,7 +109,7 @@ static void em28xx_audio_isocirq(struct urb *urb) break; } - if (atomic_read(&dev->stream_started) == 0) + if (atomic_read(&dev->adev.stream_started) == 0) return; if (dev->adev.capture_pcm_substream) { @@ -158,65 +163,29 @@ static void em28xx_audio_isocirq(struct urb *urb) urb->status = 0; status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { + if (status < 0) em28xx_errdev("resubmit of audio urb failed (error=%i)\n", status); - } return; } static int em28xx_init_audio_isoc(struct em28xx *dev) { int i, errCode; - const int sb_size = EM28XX_NUM_AUDIO_PACKETS * - EM28XX_AUDIO_MAX_PACKET_SIZE; dprintk("Starting isoc transfers\n"); - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - struct urb *urb; - int j, k; - - dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); - if (!dev->adev.transfer_buffer[i]) - return -ENOMEM; + /* Start streaming */ + for (i = 0; i < dev->adev.num_urb; i++) { + memset(dev->adev.transfer_buffer[i], 0x80, + dev->adev.urb[i]->transfer_buffer_length); - memset(dev->adev.transfer_buffer[i], 0x80, sb_size); - urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); - if (!urb) { - em28xx_errdev("usb_alloc_urb failed!\n"); - for (j = 0; j < i; j++) { - usb_free_urb(dev->adev.urb[j]); - kfree(dev->adev.transfer_buffer[j]); - } - return -ENOMEM; - } - - urb->dev = dev->udev; - urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->adev.transfer_buffer[i]; - urb->interval = 1; - urb->complete = em28xx_audio_isocirq; - urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; - urb->transfer_buffer_length = sb_size; - - for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; - j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - EM28XX_AUDIO_MAX_PACKET_SIZE; - } - dev->adev.urb[i] = urb; - } - - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); if (errCode) { - em28xx_errdev("submit of audio urb failed\n"); + em28xx_errdev("submit of audio urb failed (error=%i)\n", + errCode); em28xx_deinit_isoc_audio(dev); - atomic_set(&dev->stream_started, 0); + atomic_set(&dev->adev.stream_started, 0); return errCode; } @@ -255,15 +224,26 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = { .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, + .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ - .period_bytes_min = 64, /* 12544/2, */ - .period_bytes_max = 12544, + + + /* + * The period is 12.288 bytes. Allow a 10% of variation along its + * value, in order to avoid overruns/underruns due to some clock + * drift. + * + * FIXME: This period assumes 64 packets, and a 48000 PCM rate. + * Calculate it dynamically. + */ + .period_bytes_min = 11059, + .period_bytes_max = 13516, + .periods_min = 2, .periods_max = 98, /* 12544, */ }; @@ -272,9 +252,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) { struct em28xx *dev = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - int ret = 0; - - dprintk("opening device and trying to acquire exclusive lock\n"); + int nonblock, ret = 0; if (!dev) { em28xx_err("BUG: em28xx can't find device struct." @@ -282,29 +260,59 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) return -ENODEV; } + if (dev->disconnected) + return -ENODEV; + + dprintk("opening device and trying to acquire exclusive lock\n"); + + nonblock = !!(substream->f_flags & O_NONBLOCK); + if (nonblock) { + if (!mutex_trylock(&dev->lock)) + return -EAGAIN; + } else + mutex_lock(&dev->lock); + runtime->hw = snd_em28xx_hw_capture; - if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) { - if (dev->audio_ifnum) - dev->alt = 1; - else - dev->alt = 7; - dprintk("changing alternate number on interface %d to %d\n", - dev->audio_ifnum, dev->alt); - usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt); + if (dev->adev.users == 0) { + if (dev->alt == 0 || dev->is_audio_only) { + if (dev->is_audio_only) + /* audio is on a separate interface */ + dev->alt = 1; + else + /* audio is on the same interface as video */ + dev->alt = 7; + /* + * FIXME: The intention seems to be to select + * the alt setting with the largest + * wMaxPacketSize for the video endpoint. + * At least dev->alt should be used instead, but + * we should probably not touch it at all if it + * is already >0, because wMaxPacketSize of the + * audio endpoints seems to be the same for all. + */ + dprintk("changing alternate number on interface %d to %d\n", + dev->ifnum, dev->alt); + usb_set_interface(dev->udev, dev->ifnum, dev->alt); + } /* Sets volume, mute, etc */ dev->mute = 0; - mutex_lock(&dev->lock); ret = em28xx_audio_analog_set(dev); if (ret < 0) goto err; - - dev->adev.users++; - mutex_unlock(&dev->lock); } + kref_get(&dev->ref); + dev->adev.users++; + mutex_unlock(&dev->lock); + + /* Dynamically adjust the period size */ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + dev->adev.period * 95 / 100, + dev->adev.period * 105 / 100); + dev->adev.capture_pcm_substream = substream; return 0; @@ -324,9 +332,9 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) dev->mute = 1; mutex_lock(&dev->lock); dev->adev.users--; - if (atomic_read(&dev->stream_started) > 0) { - atomic_set(&dev->stream_started, 0); - schedule_work(&dev->wq_trigger); + if (atomic_read(&dev->adev.stream_started) > 0) { + atomic_set(&dev->adev.stream_started, 0); + schedule_work(&dev->adev.wq_trigger); } em28xx_audio_analog_set(dev); @@ -336,6 +344,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) substream->runtime->dma_area = NULL; } mutex_unlock(&dev->lock); + kref_put(&dev->ref, em28xx_free_device); return 0; } @@ -344,6 +353,10 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { int ret; + struct em28xx *dev = snd_pcm_substream_chip(substream); + + if (dev->disconnected) + return -ENODEV; dprintk("Setting capture parameters\n"); @@ -368,12 +381,13 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) { struct em28xx *dev = snd_pcm_substream_chip(substream); + struct em28xx_audio *adev = &dev->adev; dprintk("Stop capture, if needed\n"); - if (atomic_read(&dev->stream_started) > 0) { - atomic_set(&dev->stream_started, 0); - schedule_work(&dev->wq_trigger); + if (atomic_read(&adev->stream_started) > 0) { + atomic_set(&adev->stream_started, 0); + schedule_work(&adev->wq_trigger); } return 0; @@ -383,6 +397,9 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream) { struct em28xx *dev = snd_pcm_substream_chip(substream); + if (dev->disconnected) + return -ENODEV; + dev->adev.hwptr_done_capture = 0; dev->adev.capture_transfer_done = 0; @@ -391,9 +408,11 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream) static void audio_trigger(struct work_struct *work) { - struct em28xx *dev = container_of(work, struct em28xx, wq_trigger); + struct em28xx_audio *adev = + container_of(work, struct em28xx_audio, wq_trigger); + struct em28xx *dev = container_of(adev, struct em28xx, adev); - if (atomic_read(&dev->stream_started)) { + if (atomic_read(&adev->stream_started)) { dprintk("starting capture"); em28xx_init_audio_isoc(dev); } else { @@ -408,21 +427,24 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, struct em28xx *dev = snd_pcm_substream_chip(substream); int retval = 0; + if (dev->disconnected) + return -ENODEV; + switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - atomic_set(&dev->stream_started, 1); + atomic_set(&dev->adev.stream_started, 1); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: - atomic_set(&dev->stream_started, 0); + atomic_set(&dev->adev.stream_started, 0); break; default: retval = -EINVAL; } - schedule_work(&dev->wq_trigger); + schedule_work(&dev->adev.wq_trigger); return retval; } @@ -434,6 +456,9 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream snd_pcm_uframes_t hwptr_done; dev = snd_pcm_substream_chip(substream); + if (dev->disconnected) + return SNDRV_PCM_POS_XRUN; + spin_lock_irqsave(&dev->adev.slock, flags); hwptr_done = dev->adev.hwptr_done_capture; spin_unlock_irqrestore(&dev->adev.slock, flags); @@ -455,6 +480,11 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, static int em28xx_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) { + struct em28xx *dev = snd_kcontrol_chip(kcontrol); + + if (dev->disconnected) + return -ENODEV; + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; info->count = 2; info->value.integer.min = 0; @@ -467,11 +497,22 @@ static int em28xx_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { struct em28xx *dev = snd_kcontrol_chip(kcontrol); + struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) | (0x1f - (value->value.integer.value[1] & 0x1f)) << 8; + int nonblock = 0; int rc; - mutex_lock(&dev->lock); + if (dev->disconnected) + return -ENODEV; + + if (substream) + nonblock = !!(substream->f_flags & O_NONBLOCK); + if (nonblock) { + if (!mutex_trylock(&dev->lock)) + return -EAGAIN; + } else + mutex_lock(&dev->lock); rc = em28xx_read_ac97(dev, kcontrol->private_value); if (rc < 0) goto err; @@ -496,9 +537,20 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { struct em28xx *dev = snd_kcontrol_chip(kcontrol); + struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; + int nonblock = 0; int val; - mutex_lock(&dev->lock); + if (dev->disconnected) + return -ENODEV; + + if (substream) + nonblock = !!(substream->f_flags & O_NONBLOCK); + if (nonblock) { + if (!mutex_trylock(&dev->lock)) + return -EAGAIN; + } else + mutex_lock(&dev->lock); val = em28xx_read_ac97(dev, kcontrol->private_value); mutex_unlock(&dev->lock); if (val < 0) @@ -520,9 +572,20 @@ static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol, { struct em28xx *dev = snd_kcontrol_chip(kcontrol); u16 val = value->value.integer.value[0]; + struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; + int nonblock = 0; int rc; - mutex_lock(&dev->lock); + if (dev->disconnected) + return -ENODEV; + + if (substream) + nonblock = !!(substream->f_flags & O_NONBLOCK); + if (nonblock) { + if (!mutex_trylock(&dev->lock)) + return -EAGAIN; + } else + mutex_lock(&dev->lock); rc = em28xx_read_ac97(dev, kcontrol->private_value); if (rc < 0) goto err; @@ -550,9 +613,20 @@ static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { struct em28xx *dev = snd_kcontrol_chip(kcontrol); + struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; + int nonblock = 0; int val; - mutex_lock(&dev->lock); + if (dev->disconnected) + return -ENODEV; + + if (substream) + nonblock = !!(substream->f_flags & O_NONBLOCK); + if (nonblock) { + if (!mutex_trylock(&dev->lock)) + return -EAGAIN; + } else + mutex_lock(&dev->lock); val = em28xx_read_ac97(dev, kcontrol->private_value); mutex_unlock(&dev->lock); if (val < 0) @@ -634,49 +708,230 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = { .page = snd_pcm_get_vmalloc_page, }; +static void em28xx_audio_free_urb(struct em28xx *dev) +{ + int i; + + for (i = 0; i < dev->adev.num_urb; i++) { + struct urb *urb = dev->adev.urb[i]; + + if (!urb) + continue; + + usb_free_coherent(dev->udev, urb->transfer_buffer_length, + dev->adev.transfer_buffer[i], + urb->transfer_dma); + + usb_free_urb(urb); + } + kfree(dev->adev.urb); + kfree(dev->adev.transfer_buffer); + dev->adev.num_urb = 0; +} + +/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ +static int em28xx_audio_ep_packet_size(struct usb_device *udev, + struct usb_endpoint_descriptor *e) +{ + int size = le16_to_cpu(e->wMaxPacketSize); + + if (udev->speed == USB_SPEED_HIGH) + return (size & 0x7ff) * (1 + (((size) >> 11) & 0x03)); + + return size & 0x7ff; +} + +static int em28xx_audio_urb_init(struct em28xx *dev) +{ + struct usb_interface *intf; + struct usb_endpoint_descriptor *e, *ep = NULL; + int i, ep_size, interval, num_urb, npackets; + int urb_size, bytes_per_transfer; + u8 alt; + + if (dev->ifnum) + alt = 1; + else + alt = 7; + + intf = usb_ifnum_to_if(dev->udev, dev->ifnum); + + if (intf->num_altsetting <= alt) { + em28xx_errdev("alt %d doesn't exist on interface %d\n", + dev->ifnum, alt); + return -ENODEV; + } + + for (i = 0; i < intf->altsetting[alt].desc.bNumEndpoints; i++) { + e = &intf->altsetting[alt].endpoint[i].desc; + if (!usb_endpoint_dir_in(e)) + continue; + if (e->bEndpointAddress == EM28XX_EP_AUDIO) { + ep = e; + break; + } + } + + if (!ep) { + em28xx_errdev("Couldn't find an audio endpoint"); + return -ENODEV; + } + + ep_size = em28xx_audio_ep_packet_size(dev->udev, ep); + interval = 1 << (ep->bInterval - 1); + + em28xx_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", + EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed), + dev->ifnum, alt, + interval, + ep_size); + + /* Calculate the number and size of URBs to better fit the audio samples */ + + /* + * Estimate the number of bytes per DMA transfer. + * + * This is given by the bit rate (for now, only 48000 Hz) multiplied + * by 2 channels and 2 bytes/sample divided by the number of microframe + * intervals and by the microframe rate (125 us) + */ + bytes_per_transfer = DIV_ROUND_UP(48000 * 2 * 2, 125 * interval); + + /* + * Estimate the number of transfer URBs. Don't let it go past the + * maximum number of URBs that is known to be supported by the device. + */ + num_urb = DIV_ROUND_UP(bytes_per_transfer, ep_size); + if (num_urb > EM28XX_MAX_AUDIO_BUFS) + num_urb = EM28XX_MAX_AUDIO_BUFS; + + /* + * Now that we know the number of bytes per transfer and the number of + * URBs, estimate the typical size of an URB, in order to adjust the + * minimal number of packets. + */ + urb_size = bytes_per_transfer / num_urb; + + /* + * Now, calculate the amount of audio packets to be filled on each + * URB. In order to preserve the old behaviour, use a minimal + * threshold for this value. + */ + npackets = EM28XX_MIN_AUDIO_PACKETS; + if (urb_size > ep_size * npackets) + npackets = DIV_ROUND_UP(urb_size, ep_size); + + em28xx_info("Number of URBs: %d, with %d packets and %d size", + num_urb, npackets, urb_size); + + /* Estimate the bytes per period */ + dev->adev.period = urb_size * npackets; + + /* Allocate space to store the number of URBs to be used */ + + dev->adev.transfer_buffer = kcalloc(num_urb, + sizeof(*dev->adev.transfer_buffer), + GFP_ATOMIC); + if (!dev->adev.transfer_buffer) { + return -ENOMEM; + } + + dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC); + if (!dev->adev.urb) { + kfree(dev->adev.transfer_buffer); + return -ENOMEM; + } + + /* Alloc memory for each URB and for each transfer buffer */ + dev->adev.num_urb = num_urb; + for (i = 0; i < num_urb; i++) { + struct urb *urb; + int j, k; + void *buf; + + urb = usb_alloc_urb(npackets, GFP_ATOMIC); + if (!urb) { + em28xx_errdev("usb_alloc_urb failed!\n"); + em28xx_audio_free_urb(dev); + return -ENOMEM; + } + dev->adev.urb[i] = urb; + + buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC, + &urb->transfer_dma); + if (!buf) { + em28xx_errdev("usb_alloc_coherent failed!\n"); + em28xx_audio_free_urb(dev); + return -ENOMEM; + } + dev->adev.transfer_buffer[i] = buf; + + urb->dev = dev->udev; + urb->context = dev; + urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->transfer_buffer = buf; + urb->interval = interval; + urb->complete = em28xx_audio_isocirq; + urb->number_of_packets = npackets; + urb->transfer_buffer_length = ep_size * npackets; + + for (j = k = 0; j < npackets; j++, k += ep_size) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = ep_size; + } + } + + return 0; +} + static int em28xx_audio_init(struct em28xx *dev) { struct em28xx_audio *adev = &dev->adev; struct snd_pcm *pcm; struct snd_card *card; static int devnr; - int err; + int err; - if (!dev->has_alsa_audio || dev->audio_ifnum < 0) { + if (!dev->has_alsa_audio) { /* This device does not support the extension (in this case the device is expecting the snd-usb-audio module or doesn't have analog audio support at all) */ return 0; } - printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n"); + em28xx_info("Binding audio extension\n"); + + kref_get(&dev->ref); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " "Rechberger\n"); - printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n"); + printk(KERN_INFO + "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n"); - err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0, - &card); + err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio", + THIS_MODULE, 0, &card); if (err < 0) return err; spin_lock_init(&adev->slock); + adev->sndcard = card; + adev->udev = dev->udev; + err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto card_free; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); pcm->info_flags = 0; pcm->private_data = dev; strcpy(pcm->name, "Empia 28xx Capture"); - snd_card_set_dev(card, &dev->udev->dev); strcpy(card->driver, "Em28xx-Audio"); strcpy(card->shortname, "Em28xx Audio"); strcpy(card->longname, "Empia Em28xx Audio"); - INIT_WORK(&dev->wq_trigger, audio_trigger); + INIT_WORK(&adev->wq_trigger, audio_trigger); if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { em28xx_cvol_new(card, dev, "Video", AC97_VIDEO); @@ -694,15 +949,25 @@ static int em28xx_audio_init(struct em28xx *dev) em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER); } + err = em28xx_audio_urb_init(dev); + if (err) + goto card_free; + err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } - adev->sndcard = card; - adev->udev = dev->udev; + if (err < 0) + goto urb_free; + em28xx_info("Audio extension successfully initialized\n"); return 0; + +urb_free: + em28xx_audio_free_urb(dev); + +card_free: + snd_card_free(card); + adev->sndcard = NULL; + + return err; } static int em28xx_audio_fini(struct em28xx *dev) @@ -710,18 +975,54 @@ static int em28xx_audio_fini(struct em28xx *dev) if (dev == NULL) return 0; - if (dev->has_alsa_audio != 1) { + if (!dev->has_alsa_audio) { /* This device does not support the extension (in this case the device is expecting the snd-usb-audio module or doesn't have analog audio support at all) */ return 0; } + em28xx_info("Closing audio extension"); + if (dev->adev.sndcard) { + snd_card_disconnect(dev->adev.sndcard); + flush_work(&dev->adev.wq_trigger); + + em28xx_audio_free_urb(dev); + snd_card_free(dev->adev.sndcard); dev->adev.sndcard = NULL; } + kref_put(&dev->ref, em28xx_free_device); + return 0; +} + +static int em28xx_audio_suspend(struct em28xx *dev) +{ + if (dev == NULL) + return 0; + + if (!dev->has_alsa_audio) + return 0; + + em28xx_info("Suspending audio extension"); + em28xx_deinit_isoc_audio(dev); + atomic_set(&dev->adev.stream_started, 0); + return 0; +} + +static int em28xx_audio_resume(struct em28xx *dev) +{ + if (dev == NULL) + return 0; + + if (!dev->has_alsa_audio) + return 0; + + em28xx_info("Resuming audio extension"); + /* Nothing to do other than schedule_work() ?? */ + schedule_work(&dev->adev.wq_trigger); return 0; } @@ -730,6 +1031,8 @@ static struct em28xx_ops audio_ops = { .name = "Em28xx Audio Extension", .init = em28xx_audio_init, .fini = em28xx_audio_fini, + .suspend = em28xx_audio_suspend, + .resume = em28xx_audio_resume, }; static int __init em28xx_alsa_register(void) @@ -744,8 +1047,9 @@ static void __exit em28xx_alsa_unregister(void) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); -MODULE_DESCRIPTION("Em28xx Audio driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION(DRIVER_DESC " - audio interface"); +MODULE_VERSION(EM28XX_VERSION); module_init(em28xx_alsa_register); module_exit(em28xx_alsa_unregister); diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 73cc50afa5e..12d4c0326e3 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -22,6 +22,7 @@ #include <linux/i2c.h> #include <media/soc_camera.h> #include <media/mt9v011.h> +#include <media/v4l2-clk.h> #include <media/v4l2-common.h> #include "em28xx.h" @@ -47,6 +48,7 @@ static struct soc_camera_link camlink = { .bus_id = 0, .flags = 0, .module_name = "em28xx", + .unbalanced_power = true, }; @@ -118,7 +120,7 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) reg = 0x00; ret = i2c_master_send(&client, ®, 1); if (ret < 0) { - if (ret != -ENODEV) + if (ret != -ENXIO) em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -216,7 +218,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x1c; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - if (ret != -ENODEV) + if (ret != -ENXIO) em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -325,18 +327,30 @@ int em28xx_detect_sensor(struct em28xx *dev) int em28xx_init_camera(struct em28xx *dev) { + char clk_name[V4L2_SUBDEV_NAME_SIZE]; + struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; + struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; + struct em28xx_v4l2 *v4l2 = dev->v4l2; + int ret = 0; + + v4l2_clk_name_i2c(clk_name, sizeof(clk_name), + i2c_adapter_id(adap), client->addr); + v4l2->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL); + if (IS_ERR(v4l2->clk)) + return PTR_ERR(v4l2->clk); + switch (dev->em28xx_sensor) { case EM28XX_MT9V011: { struct mt9v011_platform_data pdata; struct i2c_board_info mt9v011_info = { .type = "mt9v011", - .addr = dev->i2c_client[dev->def_i2c_bus].addr, + .addr = client->addr, .platform_data = &pdata, }; - dev->sensor_xres = 640; - dev->sensor_yres = 480; + v4l2->sensor_xres = 640; + v4l2->sensor_yres = 480; /* * FIXME: mt9v011 uses I2S speed as xtal clk - at least with @@ -349,40 +363,41 @@ int em28xx_init_camera(struct em28xx *dev) */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); - dev->sensor_xtal = 4300000; - pdata.xtal = dev->sensor_xtal; + v4l2->sensor_xtal = 4300000; + pdata.xtal = v4l2->sensor_xtal; if (NULL == - v4l2_i2c_new_subdev_board(&dev->v4l2_dev, - &dev->i2c_adap[dev->def_i2c_bus], - &mt9v011_info, NULL)) - return -ENODEV; + v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap, + &mt9v011_info, NULL)) { + ret = -ENODEV; + break; + } /* probably means GRGB 16 bit bayer */ - dev->vinmode = 0x0d; - dev->vinctl = 0x00; + v4l2->vinmode = 0x0d; + v4l2->vinctl = 0x00; break; } case EM28XX_MT9M001: - dev->sensor_xres = 1280; - dev->sensor_yres = 1024; + v4l2->sensor_xres = 1280; + v4l2->sensor_yres = 1024; em28xx_initialize_mt9m001(dev); /* probably means BGGR 16 bit bayer */ - dev->vinmode = 0x0c; - dev->vinctl = 0x00; + v4l2->vinmode = 0x0c; + v4l2->vinctl = 0x00; break; case EM28XX_MT9M111: - dev->sensor_xres = 640; - dev->sensor_yres = 512; + v4l2->sensor_xres = 640; + v4l2->sensor_yres = 512; dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); em28xx_initialize_mt9m111(dev); - dev->vinmode = 0x0a; - dev->vinctl = 0x00; + v4l2->vinmode = 0x0a; + v4l2->vinctl = 0x00; break; case EM28XX_OV2640: @@ -391,7 +406,7 @@ int em28xx_init_camera(struct em28xx *dev) struct i2c_board_info ov2640_info = { .type = "ov2640", .flags = I2C_CLIENT_SCCB, - .addr = dev->i2c_client[dev->def_i2c_bus].addr, + .addr = client->addr, .platform_data = &camlink, }; struct v4l2_mbus_framefmt fmt; @@ -404,13 +419,16 @@ int em28xx_init_camera(struct em28xx *dev) * - adjust bridge xclk * - disable 16 bit (12 bit) output formats on high resolutions */ - dev->sensor_xres = 640; - dev->sensor_yres = 480; + v4l2->sensor_xres = 640; + v4l2->sensor_yres = 480; subdev = - v4l2_i2c_new_subdev_board(&dev->v4l2_dev, - &dev->i2c_adap[dev->def_i2c_bus], + v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap, &ov2640_info, NULL); + if (NULL == subdev) { + ret = -ENODEV; + break; + } fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; fmt.width = 640; @@ -420,15 +438,21 @@ int em28xx_init_camera(struct em28xx *dev) /* NOTE: for UXGA=1600x1200 switch to 12MHz */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); - dev->vinmode = 0x08; - dev->vinctl = 0x00; + v4l2->vinmode = 0x08; + v4l2->vinctl = 0x00; break; } case EM28XX_NOSENSOR: default: - return -EINVAL; + ret = -EINVAL; } - return 0; + if (ret < 0) { + v4l2_clk_unregister_fixed(v4l2->clk); + v4l2->clk = NULL; + } + + return ret; } +EXPORT_SYMBOL_GPL(em28xx_init_camera); diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index dc65742c4bb..15ad4704555 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(usb_xfer_mode, /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */ -static unsigned long em28xx_devused; +static DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS); struct em28xx_hash_table { unsigned long hash; @@ -95,8 +95,8 @@ static struct em28xx_reg_seq default_digital[] = { /* Board Hauppauge WinTV HVR 900 analog */ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { {EM2820_R08_GPIO_CTRL, 0x2d, ~EM_GPIO_4, 10}, - {0x05, 0xff, 0x10, 10}, - { -1, -1, -1, -1}, + { 0x05, 0xff, 0x10, 10}, + { -1, -1, -1, -1}, }; /* Board Hauppauge WinTV HVR 900 digital */ @@ -104,20 +104,20 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { {EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x04, 0x0f, 10}, {EM2880_R04_GPO, 0x0c, 0x0f, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* Board Hauppauge WinTV HVR 900 (R2) digital */ static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = { {EM2820_R08_GPIO_CTRL, 0x2e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x0c, 0x0f, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { - {EM2820_R08_GPIO_CTRL, 0x69, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, + {EM2820_R08_GPIO_CTRL, 0x69, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, }; /* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ @@ -132,7 +132,7 @@ static struct em28xx_reg_seq em2882_kworld_315u_digital[] = { {EM2880_R04_GPO, 0x04, 0xff, 10}, {EM2880_R04_GPO, 0x0c, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0x7e, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { @@ -140,19 +140,19 @@ static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = { {EM2880_R04_GPO, 0x0c, 0xff, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, {EM2880_R04_GPO, 0x0c, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq kworld_330u_analog[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x00, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq kworld_330u_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* Evga inDtube @@ -170,11 +170,11 @@ static struct em28xx_reg_seq evga_indtube_digital[] = { {EM2820_R08_GPIO_CTRL, 0x7a, 0xff, 1}, {EM2880_R04_GPO, 0x04, 0xff, 10}, {EM2880_R04_GPO, 0x0c, 0xff, 1}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* - * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map: + * KWorld PlusTV 340U, UB435-Q and UB435-Q V2 (ATSC) GPIOs map: * EM_GPIO_0 - currently unknown * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on) * EM_GPIO_2 - currently unknown @@ -185,8 +185,16 @@ static struct em28xx_reg_seq evga_indtube_digital[] = { * EM_GPIO_7 - currently unknown */ static struct em28xx_reg_seq kworld_a340_digital[] = { - {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, + {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = { + {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100}, + {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100}, + {EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 100}, + {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100}, + { -1, -1, -1, -1}, }; /* Pinnacle Hybrid Pro eb1a:2881 */ @@ -205,13 +213,24 @@ static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = { static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = { {EM2820_R08_GPIO_CTRL, 0x6d, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x00, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, +}; + +/* PCTV HD Mini (80e) GPIOs + 0-5: not used + 6: demod reset, active low + 7: LED on, active high */ +static struct em28xx_reg_seq em2874_pctv_80e_digital[] = { + {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ + {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 100},/*Demod reset*/ + {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 10}, + { -1, -1, -1, -1}, }; /* eb1a:2868 Reddo DVB-C USB TV Box @@ -225,7 +244,7 @@ static struct em28xx_reg_seq reddo_dvb_c_usb_box[] = { {EM2820_R08_GPIO_CTRL, 0x7f, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0x6f, 0xff, 10}, {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, - {-1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* Callback for the most boards */ @@ -233,23 +252,23 @@ static struct em28xx_reg_seq default_tuner_gpio[] = { {EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10}, {EM2820_R08_GPIO_CTRL, 0, EM_GPIO_4, 10}, {EM2820_R08_GPIO_CTRL, EM_GPIO_4, EM_GPIO_4, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* Mute/unmute */ static struct em28xx_reg_seq compro_unmute_tv_gpio[] = { - {EM2820_R08_GPIO_CTRL, 5, 7, 10}, - { -1, -1, -1, -1}, + {EM2820_R08_GPIO_CTRL, 5, 7, 10}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq compro_unmute_svid_gpio[] = { - {EM2820_R08_GPIO_CTRL, 4, 7, 10}, - { -1, -1, -1, -1}, + {EM2820_R08_GPIO_CTRL, 4, 7, 10}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq compro_mute_gpio[] = { - {EM2820_R08_GPIO_CTRL, 6, 7, 10}, - { -1, -1, -1, -1}, + {EM2820_R08_GPIO_CTRL, 6, 7, 10}, + { -1, -1, -1, -1}, }; /* Terratec AV350 */ @@ -279,21 +298,21 @@ static struct em28xx_reg_seq vc211a_enable[] = { static struct em28xx_reg_seq dikom_dk300_digital[] = { {EM2820_R08_GPIO_CTRL, 0x6e, ~EM_GPIO_4, 10}, {EM2880_R04_GPO, 0x08, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* Reset for the most [digital] boards */ static struct em28xx_reg_seq leadership_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0x70, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq leadership_reset[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xb0, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xf0, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* 2013:024f PCTV nanoStick T2 290e @@ -304,7 +323,7 @@ static struct em28xx_reg_seq pctv_290e[] = { {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 80}, {EM2874_R80_GPIO_P0_CTRL, 0x40, 0xff, 80}, /* GPIO_6 = 1 */ {EM2874_R80_GPIO_P0_CTRL, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */ - {-1, -1, -1, -1}, + { -1, -1, -1, -1}, }; #if 0 @@ -313,14 +332,14 @@ static struct em28xx_reg_seq terratec_h5_gpio[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 50}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq terratec_h5_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; #endif @@ -335,12 +354,12 @@ static struct em28xx_reg_seq terratec_h5_digital[] = { * GPIO_7 - LED (green LED) */ static struct em28xx_reg_seq pctv_460e[] = { - {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff, 50}, - {0x0d, 0xff, 0xff, 50}, - {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff, 50}, /* GPIO_6=1 */ - {0x0d, 0x42, 0xff, 50}, - {EM2874_R80_GPIO_P0_CTRL, 0x61, 0xff, 50}, /* GPIO_5=1 */ - { -1, -1, -1, -1}, + {EM2874_R80_GPIO_P0_CTRL, 0x01, 0xff, 50}, + { 0x0d, 0xff, 0xff, 50}, + {EM2874_R80_GPIO_P0_CTRL, 0x41, 0xff, 50}, /* GPIO_6=1 */ + { 0x0d, 0x42, 0xff, 50}, + {EM2874_R80_GPIO_P0_CTRL, 0x61, 0xff, 50}, /* GPIO_5=1 */ + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq c3tech_digital_duo_digital[] = { @@ -352,7 +371,29 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 20}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, +}; + +/* + * 2013:0258 PCTV DVB-S2 Stick (461e) + * GPIO 0 = POWER_ON + * GPIO 1 = BOOST + * GPIO 2 = VUV_LNB (red LED) + * GPIO 3 = #EXT_12V + * GPIO 4 = INT_DEM + * GPIO 5 = INT_LNB + * GPIO 6 = #RESET_DEM + * GPIO 7 = P07_LED (green LED) + */ +static struct em28xx_reg_seq pctv_461e[] = { + {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 0}, + {0x0d, 0xff, 0xff, 0}, + {EM2874_R80_GPIO_P0_CTRL, 0x3f, 0xff, 100}, /* reset demod */ + {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 200}, /* reset demod */ + {0x0d, 0x42, 0xff, 0}, + {EM2874_R80_GPIO_P0_CTRL, 0xeb, 0xff, 0}, + {EM2874_R5F_TS_ENABLE, 0x84, 0x84, 0}, /* parallel? | null discard */ + { -1, -1, -1, -1}, }; #if 0 @@ -361,14 +402,14 @@ static struct em28xx_reg_seq hauppauge_930c_gpio[] = { {EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10}, /* xc5000 reset */ {EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0x4f, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; static struct em28xx_reg_seq hauppauge_930c_digital[] = { {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 10}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; #endif @@ -378,10 +419,10 @@ static struct em28xx_reg_seq hauppauge_930c_digital[] = { * GPIO_7 - LED, 0=active */ static struct em28xx_reg_seq maxmedia_ub425_tc[] = { - {EM2874_R80_GPIO_P0_CTRL, 0x83, 0xff, 100}, - {EM2874_R80_GPIO_P0_CTRL, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */ - {EM2874_R80_GPIO_P0_CTRL, 0x43, 0xff, 000}, /* GPIO_7 = 0 */ - {-1, -1, -1, -1}, + {EM2874_R80_GPIO_P0_CTRL, 0x83, 0xff, 100}, + {EM2874_R80_GPIO_P0_CTRL, 0xc3, 0xff, 100}, /* GPIO_6 = 1 */ + {EM2874_R80_GPIO_P0_CTRL, 0x43, 0xff, 000}, /* GPIO_7 = 0 */ + { -1, -1, -1, -1}, }; /* 2304:0242 PCTV QuatroStick (510e) @@ -391,10 +432,10 @@ static struct em28xx_reg_seq maxmedia_ub425_tc[] = { * GPIO_7: LED, 1=active */ static struct em28xx_reg_seq pctv_510e[] = { - {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100}, - {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ - {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ - { -1, -1, -1, -1}, + {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100}, + {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ + {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ + { -1, -1, -1, -1}, }; /* 2013:0251 PCTV QuatroStick nano (520e) @@ -404,14 +445,111 @@ static struct em28xx_reg_seq pctv_510e[] = { * GPIO_7: LED, 1=active */ static struct em28xx_reg_seq pctv_520e[] = { - {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100}, - {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ - {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ - {EM2874_R80_GPIO_P0_CTRL, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */ - { -1, -1, -1, -1}, + {EM2874_R80_GPIO_P0_CTRL, 0x10, 0xff, 100}, + {EM2874_R80_GPIO_P0_CTRL, 0x14, 0xff, 100}, /* GPIO_2 = 1 */ + {EM2874_R80_GPIO_P0_CTRL, 0x54, 0xff, 050}, /* GPIO_6 = 1 */ + {EM2874_R80_GPIO_P0_CTRL, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */ + { -1, -1, -1, -1}, +}; + +/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam + * reg 0x80/0x84: + * GPIO_0: capturing LED, 0=on, 1=off + * GPIO_2: AV mute button, 0=pressed, 1=unpressed + * GPIO 3: illumination button, 0=pressed, 1=unpressed + * GPIO_6: illumination/flash LED, 0=on, 1=off + * reg 0x81/0x85: + * GPIO_7: snapshot button, 0=pressed, 1=unpressed + */ +static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = { + {EM2820_R08_GPIO_CTRL, 0xf7, 0xff, 10}, + {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xb2, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq pctv_292e[] = { + {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0}, + {0x0d, 0xff, 0xff, 950}, + {EM2874_R80_GPIO_P0_CTRL, 0xbd, 0xff, 100}, + {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 410}, + {EM2874_R80_GPIO_P0_CTRL, 0x7d, 0xff, 300}, + {EM2874_R80_GPIO_P0_CTRL, 0x7c, 0xff, 60}, + {0x0d, 0x42, 0xff, 50}, + {EM2874_R5F_TS_ENABLE, 0x85, 0xff, 0}, + {-1, -1, -1, -1}, }; /* + * Button definitions + */ +static struct em28xx_button std_snapshot_button[] = { + { + .role = EM28XX_BUTTON_SNAPSHOT, + .reg_r = EM28XX_R0C_USBSUSP, + .reg_clearing = EM28XX_R0C_USBSUSP, + .mask = EM28XX_R0C_USBSUSP_SNAPSHOT, + .inverted = 0, + }, + {-1, 0, 0, 0, 0}, +}; + +static struct em28xx_button speedlink_vad_laplace_buttons[] = { + { + .role = EM28XX_BUTTON_SNAPSHOT, + .reg_r = EM2874_R85_GPIO_P1_STATE, + .mask = 0x80, + .inverted = 1, + }, + { + .role = EM28XX_BUTTON_ILLUMINATION, + .reg_r = EM2874_R84_GPIO_P0_STATE, + .mask = 0x08, + .inverted = 1, + }, + {-1, 0, 0, 0, 0}, +}; + +/* + * LED definitions + */ +static struct em28xx_led speedlink_vad_laplace_leds[] = { + { + .role = EM28XX_LED_ANALOG_CAPTURING, + .gpio_reg = EM2874_R80_GPIO_P0_CTRL, + .gpio_mask = 0x01, + .inverted = 1, + }, + { + .role = EM28XX_LED_ILLUMINATION, + .gpio_reg = EM2874_R80_GPIO_P0_CTRL, + .gpio_mask = 0x40, + .inverted = 1, + }, + {-1, 0, 0, 0}, +}; + +static struct em28xx_led kworld_ub435q_v3_leds[] = { + { + .role = EM28XX_LED_DIGITAL_CAPTURING, + .gpio_reg = EM2874_R80_GPIO_P0_CTRL, + .gpio_mask = 0x80, + .inverted = 1, + }, + {-1, 0, 0, 0}, +}; + +static struct em28xx_led pctv_80e_leds[] = { + { + .role = EM28XX_LED_DIGITAL_CAPTURING, + .gpio_reg = EM2874_R80_GPIO_P0_CTRL, + .gpio_mask = 0x80, + .inverted = 0, + }, + {-1, 0, 0, 0}, +}; + + +/* * Board definitions */ struct em28xx_board em28xx_boards[] = { @@ -1390,7 +1528,7 @@ struct em28xx_board em28xx_boards[] = { }, [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { .name = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0", - .has_snapshot_button = 1, + .buttons = std_snapshot_button, .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_YMEC_TVF_5533MF, .decoder = EM28XX_SAA711X, @@ -1412,7 +1550,7 @@ struct em28xx_board em28xx_boards[] = { }, [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = { .name = "EM2860/SAA711X Reference Design", - .has_snapshot_button = 1, + .buttons = std_snapshot_button, .tuner_type = TUNER_ABSENT, .decoder = EM28XX_SAA711X, .input = { { @@ -2019,7 +2157,7 @@ struct em28xx_board em28xx_boards[] = { }, /* 1b80:e1cc Delock 61959 * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 - * mostly the same as MaxMedia UB-425-TC but different remote */ + * mostly the same as MaxMedia UB-425-TC but different remote */ [EM2874_BOARD_DELOCK_61959] = { .name = "Delock 61959", .tuner_type = TUNER_ABSENT, @@ -2030,7 +2168,84 @@ struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, + /* + * 1b80:e346 KWorld USB ATSC TV Stick UB435-Q V2 + * Empia EM2874B + LG DT3305 + NXP TDA18271HDC2 + */ + [EM2874_BOARD_KWORLD_UB435Q_V2] = { + .name = "KWorld USB ATSC TV Stick UB435-Q V2", + .tuner_type = TUNER_ABSENT, + .has_dvb = 1, + .dvb_gpio = kworld_a340_digital, + .tuner_gpio = default_tuner_gpio, + .def_i2c_bus = 1, + }, + /* + * 1b80:e34c KWorld USB ATSC TV Stick UB435-Q V3 + * Empia EM2874B + LG DT3305 + NXP TDA18271HDC2 + */ + [EM2874_BOARD_KWORLD_UB435Q_V3] = { + .name = "KWorld USB ATSC TV Stick UB435-Q V3", + .tuner_type = TUNER_ABSENT, + .has_dvb = 1, + .tuner_gpio = kworld_ub435q_v3_digital, + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ, + .leds = kworld_ub435q_v3_leds, + }, + [EM2874_BOARD_PCTV_HD_MINI_80E] = { + .name = "Pinnacle PCTV HD Mini", + .tuner_type = TUNER_ABSENT, + .has_dvb = 1, + .dvb_gpio = em2874_pctv_80e_digital, + .decoder = EM28XX_NODECODER, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + .leds = pctv_80e_leds, + }, + /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam + * Empia EM2765 + OmniVision OV2640 */ + [EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = { + .name = "SpeedLink Vicious And Devine Laplace webcam", + .xclk = EM28XX_XCLK_FREQUENCY_24MHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ, + .def_i2c_bus = 1, + .tuner_type = TUNER_ABSENT, + .is_webcam = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .amux = EM28XX_AMUX_VIDEO, + .gpio = speedlink_vad_laplace_reg_seq, + } }, + .buttons = speedlink_vad_laplace_buttons, + .leds = speedlink_vad_laplace_leds, + }, + /* 2013:0258 PCTV DVB-S2 Stick (461e) + * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 */ + [EM28178_BOARD_PCTV_461E] = { + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .name = "PCTV DVB-S2 Stick (461e)", + .tuner_type = TUNER_ABSENT, + .tuner_gpio = pctv_461e, + .has_dvb = 1, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + }, + /* 2013:025f PCTV tripleStick (292e). + * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 */ + [EM28178_BOARD_PCTV_292E] = { + .name = "PCTV tripleStick (292e)", + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .tuner_type = TUNER_ABSENT, + .tuner_gpio = pctv_292e, + .has_dvb = 1, + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, + }, }; +EXPORT_SYMBOL_GPL(em28xx_boards); + const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); /* table of devices that work with this driver */ @@ -2161,6 +2376,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E }, { USB_DEVICE(0x2304, 0x0227), .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, + { USB_DEVICE(0x2304, 0x023f), + .driver_info = EM2874_BOARD_PCTV_HD_MINI_80E }, { USB_DEVICE(0x0413, 0x6023), .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, { USB_DEVICE(0x093b, 0xa003), @@ -2173,6 +2390,10 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2860_BOARD_GADMEI_UTV330 }, { USB_DEVICE(0x1b80, 0xa340), .driver_info = EM2870_BOARD_KWORLD_A340 }, + { USB_DEVICE(0x1b80, 0xe346), + .driver_info = EM2874_BOARD_KWORLD_UB435Q_V2 }, + { USB_DEVICE(0x1b80, 0xe34c), + .driver_info = EM2874_BOARD_KWORLD_UB435Q_V3 }, { USB_DEVICE(0x2013, 0x024f), .driver_info = EM28174_BOARD_PCTV_290E }, { USB_DEVICE(0x2013, 0x024c), @@ -2193,6 +2414,14 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2884_BOARD_PCTV_520E }, { USB_DEVICE(0x1b80, 0xe1cc), .driver_info = EM2874_BOARD_DELOCK_61959 }, + { USB_DEVICE(0x1ae7, 0x9003), + .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE }, + { USB_DEVICE(0x1ae7, 0x9004), + .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE }, + { USB_DEVICE(0x2013, 0x0258), + .driver_info = EM28178_BOARD_PCTV_461E }, + { USB_DEVICE(0x2013, 0x025f), + .driver_info = EM28178_BOARD_PCTV_292E }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -2224,24 +2453,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { }; /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */ -/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ -static unsigned short saa711x_addrs[] = { - 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ - 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ - I2C_CLIENT_END }; - -static unsigned short tvp5150_addrs[] = { - 0xb8 >> 1, - 0xba >> 1, - I2C_CLIENT_END -}; - -static unsigned short msp3400_addrs[] = { - 0x80 >> 1, - 0x88 >> 1, - I2C_CLIENT_END -}; - int em28xx_tuner_callback(void *ptr, int component, int command, int arg) { struct em28xx_i2c_bus *i2c_bus = ptr; @@ -2393,113 +2604,6 @@ static void em28xx_pre_card_setup(struct em28xx *dev) em28xx_set_mode(dev, EM28XX_SUSPEND); } -static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) -{ - memset(ctl, 0, sizeof(*ctl)); - - ctl->fname = XC2028_DEFAULT_FIRMWARE; - ctl->max_len = 64; - ctl->mts = em28xx_boards[dev->model].mts_firmware; - - switch (dev->model) { - case EM2880_BOARD_EMPIRE_DUAL_TV: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2882_BOARD_TERRATEC_HYBRID_XS: - ctl->demod = XC3028_FE_ZARLINK456; - break; - case EM2880_BOARD_TERRATEC_HYBRID_XS: - case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: - case EM2881_BOARD_PINNACLE_HYBRID_PRO: - ctl->demod = XC3028_FE_ZARLINK456; - break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: - ctl->demod = XC3028_FE_DEFAULT; - break; - case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: - ctl->demod = XC3028_FE_DEFAULT; - ctl->fname = XC3028L_DEFAULT_FIRMWARE; - break; - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: - /* FIXME: Better to specify the needed IF */ - ctl->demod = XC3028_FE_DEFAULT; - break; - case EM2883_BOARD_KWORLD_HYBRID_330U: - case EM2882_BOARD_DIKOM_DK300: - case EM2882_BOARD_KWORLD_VS_DVBT: - ctl->demod = XC3028_FE_CHINA; - ctl->fname = XC2028_DEFAULT_FIRMWARE; - break; - case EM2882_BOARD_EVGA_INDTUBE: - ctl->demod = XC3028_FE_CHINA; - ctl->fname = XC3028L_DEFAULT_FIRMWARE; - break; - default: - ctl->demod = XC3028_FE_OREN538; - } -} - -static void em28xx_tuner_setup(struct em28xx *dev) -{ - struct tuner_setup tun_setup; - struct v4l2_frequency f; - - if (dev->tuner_type == TUNER_ABSENT) - return; - - memset(&tun_setup, 0, sizeof(tun_setup)); - - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.tuner_callback = em28xx_tuner_callback; - - if (dev->board.radio.type) { - tun_setup.type = dev->board.radio.type; - tun_setup.addr = dev->board.radio_addr; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); - } - - if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup); - } - - if (dev->tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg); - } - - if (dev->tuner_type == TUNER_XC2028) { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); - memset(&ctl, 0, sizeof(ctl)); - - em28xx_setup_xc3028(dev, &ctl); - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg); - } - - /* configure tuner */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 9076; /* just a magic number */ - dev->ctl_freq = f.frequency; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); -} - static int em28xx_hint_board(struct em28xx *dev) { int i; @@ -2603,8 +2707,6 @@ static void em28xx_card_setup(struct em28xx *dev) if (dev->board.is_webcam) { if (em28xx_detect_sensor(dev) < 0) dev->board.is_webcam = 0; - else - dev->progressive = 1; } switch (dev->model) { @@ -2639,11 +2741,6 @@ static void em28xx_card_setup(struct em28xx *dev) dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; - if (em28xx_boards[dev->model].tuner_addr) - dev->tuner_addr = em28xx_boards[dev->model].tuner_addr; - - if (em28xx_boards[dev->model].tda9887_conf) - dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; /* request some modules */ switch (dev->model) { @@ -2753,57 +2850,56 @@ static void em28xx_card_setup(struct em28xx *dev) /* Allow override tuner type by a module parameter */ if (tuner >= 0) dev->tuner_type = tuner; +} - /* request some modules */ - if (dev->board.has_msp34xx) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], - "msp3400", 0, msp3400_addrs); - - if (dev->board.decoder == EM28XX_SAA711X) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], - "saa7115_auto", 0, saa711x_addrs); - - if (dev->board.decoder == EM28XX_TVP5150) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], - "tvp5150", 0, tvp5150_addrs); - - if (dev->board.adecoder == EM28XX_TVAUDIO) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], - "tvaudio", dev->board.tvaudio_addr, NULL); - - if (dev->board.tuner_type != TUNER_ABSENT) { - int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); - - if (dev->board.radio.type) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], - "tuner", dev->board.radio_addr, NULL); - - if (has_demod) - v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap[dev->def_i2c_bus], "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - if (dev->tuner_addr == 0) { - enum v4l2_i2c_tuner_type type = - has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; - struct v4l2_subdev *sd; - - sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap[dev->def_i2c_bus], "tuner", - 0, v4l2_i2c_tuner_addrs(type)); - - if (sd) - dev->tuner_addr = v4l2_i2c_subdev_addr(sd); - } else { - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], - "tuner", dev->tuner_addr, NULL); - } - } +void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) +{ + memset(ctl, 0, sizeof(*ctl)); - em28xx_tuner_setup(dev); + ctl->fname = XC2028_DEFAULT_FIRMWARE; + ctl->max_len = 64; + ctl->mts = em28xx_boards[dev->model].mts_firmware; - em28xx_init_camera(dev); + switch (dev->model) { + case EM2880_BOARD_EMPIRE_DUAL_TV: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2882_BOARD_TERRATEC_HYBRID_XS: + ctl->demod = XC3028_FE_ZARLINK456; + break; + case EM2880_BOARD_TERRATEC_HYBRID_XS: + case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: + case EM2881_BOARD_PINNACLE_HYBRID_PRO: + ctl->demod = XC3028_FE_ZARLINK456; + break; + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: + case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: + ctl->demod = XC3028_FE_DEFAULT; + break; + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: + ctl->demod = XC3028_FE_DEFAULT; + ctl->fname = XC3028L_DEFAULT_FIRMWARE; + break; + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + /* FIXME: Better to specify the needed IF */ + ctl->demod = XC3028_FE_DEFAULT; + break; + case EM2883_BOARD_KWORLD_HYBRID_330U: + case EM2882_BOARD_DIKOM_DK300: + case EM2882_BOARD_KWORLD_VS_DVBT: + ctl->demod = XC3028_FE_CHINA; + ctl->fname = XC2028_DEFAULT_FIRMWARE; + break; + case EM2882_BOARD_EVGA_INDTUBE: + ctl->demod = XC3028_FE_CHINA; + ctl->fname = XC3028L_DEFAULT_FIRMWARE; + break; + default: + ctl->demod = XC3028_FE_OREN538; + } } - +EXPORT_SYMBOL_GPL(em28xx_setup_xc3028); static void request_module_async(struct work_struct *work) { @@ -2816,17 +2912,30 @@ static void request_module_async(struct work_struct *work) * can be initialised right now. Otherwise, the module init * code will do it. */ + + /* + * Devicdes with an audio-only interface also have a V4L/DVB/RC + * interface. Don't register extensions twice on those devices. + */ + if (dev->is_audio_only) { +#if defined(CONFIG_MODULES) && defined(MODULE) + request_module("em28xx-alsa"); +#endif + return; + } + em28xx_init_extension(dev); #if defined(CONFIG_MODULES) && defined(MODULE) + if (dev->has_video) + request_module("em28xx-v4l"); if (dev->has_audio_class) request_module("snd-usb-audio"); else if (dev->has_alsa_audio) request_module("em28xx-alsa"); - if (dev->board.has_dvb) request_module("em28xx-dvb"); - if (dev->board.has_snapshot_button || + if (dev->board.buttons || ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir)) request_module("em28xx-rc"); #endif /* CONFIG_MODULES */ @@ -2848,26 +2957,45 @@ static void flush_request_modules(struct em28xx *dev) * unregisters the v4l2,i2c and usb devices * called when the device gets disconnected or at module unload */ -void em28xx_release_resources(struct em28xx *dev) +static void em28xx_release_resources(struct em28xx *dev) { /*FIXME: I2C IR should be disconnected */ - em28xx_release_analog_resources(dev); + mutex_lock(&dev->lock); if (dev->def_i2c_bus) em28xx_i2c_unregister(dev, 1); em28xx_i2c_unregister(dev, 0); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - - v4l2_device_unregister(&dev->v4l2_dev); - usb_put_dev(dev->udev); /* Mark device as unused */ - clear_bit(dev->devno, &em28xx_devused); + clear_bit(dev->devno, em28xx_devused); + + mutex_unlock(&dev->lock); }; +/** + * em28xx_free_device() - Free em28xx device + * + * @ref: struct kref for em28xx device + * + * This is called when all extensions and em28xx core unregisters a device + */ +void em28xx_free_device(struct kref *ref) +{ + struct em28xx *dev = kref_to_dev(ref); + + em28xx_info("Freeing device\n"); + + if (!dev->disconnected) + em28xx_release_resources(dev); + + kfree(dev->alt_max_pkt_size_isoc); + kfree(dev); +} +EXPORT_SYMBOL_GPL(em28xx_free_device); + /* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device @@ -2876,14 +3004,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, struct usb_interface *interface, int minor) { - struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; int retval; static const char *default_chip_name = "em28xx"; const char *chip_name = default_chip_name; dev->udev = udev; - mutex_init(&dev->vb_queue_lock); - mutex_init(&dev->vb_vbi_queue_lock); mutex_init(&dev->ctrl_urb_lock); spin_lock_init(&dev->slock); @@ -2951,6 +3076,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, dev->wait_after_write = 0; dev->eeprom_addrwidth_16bit = 1; break; + case CHIP_ID_EM28178: + chip_name = "em28178"; + dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; + break; case CHIP_ID_EM2883: chip_name = "em2882/3"; dev->wait_after_write = 0; @@ -2966,6 +3096,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, } } + if (dev->chip_id == CHIP_ID_EM2870 || + dev->chip_id == CHIP_ID_EM2874 || + dev->chip_id == CHIP_ID_EM28174 || + dev->chip_id == CHIP_ID_EM28178) { + /* Digital only device - don't load any alsa module */ + dev->audio_mode.has_audio = false; + dev->has_audio_class = false; + dev->has_alsa_audio = false; + } + if (chip_name != default_chip_name) printk(KERN_INFO DRIVER_NAME ": chip ID is %s\n", chip_name); @@ -2998,15 +3138,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, } } - retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); - if (retval < 0) { - em28xx_errdev("Call to v4l2_device_register() failed!\n"); - return retval; - } - - v4l2_ctrl_handler_init(hdl, 8); - dev->v4l2_dev.ctrl_handler = hdl; - rt_mutex_init(&dev->i2c_bus_lock); /* register i2c bus 0 */ @@ -3017,7 +3148,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, if (retval < 0) { em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n", __func__, retval); - goto unregister_dev; + return retval; } /* register i2c bus 1 */ @@ -3031,88 +3162,17 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, if (retval < 0) { em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n", __func__, retval); - goto unregister_dev; - } - } - - /* - * Default format, used for tvp5150 or saa711x output formats - */ - dev->vinmode = 0x10; - dev->vinctl = EM28XX_VINCTRL_INTERLACED | - EM28XX_VINCTRL_CCIR656_ENABLE; - - /* Do board specific init and eeprom reading */ - em28xx_card_setup(dev); - - /* Configure audio */ - retval = em28xx_audio_setup(dev); - if (retval < 0) { - em28xx_errdev("%s: Error while setting audio - error [%d]!\n", - __func__, retval); - goto fail; - } - if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { - v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); - v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f); - } else { - /* install the em28xx notify callback */ - v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE), - em28xx_ctrl_notify, dev); - v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME), - em28xx_ctrl_notify, dev); - } - - /* wake i2c devices */ - em28xx_wake_i2c(dev); - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vbiq.active); + em28xx_i2c_unregister(dev, 0); - if (dev->board.has_msp34xx) { - /* Send a reset to other chips via gpio */ - retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); - if (retval < 0) { - em28xx_errdev("%s: em28xx_write_reg - " - "msp34xx(1) failed! error [%d]\n", - __func__, retval); - goto fail; - } - msleep(3); - - retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); - if (retval < 0) { - em28xx_errdev("%s: em28xx_write_reg - " - "msp34xx(2) failed! error [%d]\n", - __func__, retval); - goto fail; + return retval; } - msleep(3); } - retval = em28xx_register_analog_devices(dev); - if (retval < 0) { - goto fail; - } - - /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); + /* Do board specific init and eeprom reading */ + em28xx_card_setup(dev); return 0; - -fail: - if (dev->def_i2c_bus) - em28xx_i2c_unregister(dev, 1); - em28xx_i2c_unregister(dev, 0); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - -unregister_dev: - v4l2_device_unregister(&dev->v4l2_dev); - - return retval; } /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ @@ -3137,7 +3197,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Check to see next free device and mark as used */ do { - nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); + nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); if (nr >= EM28XX_MAXBOARDS) { /* No free device slots */ printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", @@ -3145,7 +3205,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, retval = -ENOMEM; goto err_no_slot; } - } while (test_and_set_bit(nr, &em28xx_devused)); + } while (test_and_set_bit(nr, em28xx_devused)); /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { @@ -3315,7 +3375,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->alt = -1; dev->is_audio_only = has_audio && !(has_video || has_dvb); dev->has_alsa_audio = has_audio; - dev->audio_ifnum = ifnum; + dev->audio_mode.has_audio = has_audio; + dev->has_video = has_video; + dev->ifnum = ifnum; /* Checks if audio is provided by some interface */ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { @@ -3352,15 +3414,11 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); - /* initialize videobuf2 stuff */ - em28xx_vb2_setup(dev); - /* allocate device struct */ mutex_init(&dev->lock); - mutex_lock(&dev->lock); retval = em28xx_init_dev(dev, udev, interface, nr); if (retval) { - goto unlock_and_free; + goto err_free; } if (usb_xfer_mode < 0) { @@ -3374,57 +3432,34 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Select USB transfer types to use */ if (has_video) { - if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) - dev->analog_xfer_bulk = 1; + if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) + dev->analog_xfer_bulk = 1; em28xx_info("analog set to %s mode.\n", dev->analog_xfer_bulk ? "bulk" : "isoc"); } if (has_dvb) { - if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) - dev->dvb_xfer_bulk = 1; - + if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) + dev->dvb_xfer_bulk = 1; em28xx_info("dvb set to %s mode.\n", dev->dvb_xfer_bulk ? "bulk" : "isoc"); - - /* pre-allocate DVB usb transfer buffers */ - if (dev->dvb_xfer_bulk) { - retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, - dev->dvb_xfer_bulk, - EM28XX_DVB_NUM_BUFS, - 512, - EM28XX_DVB_BULK_PACKET_MULTIPLIER); - } else { - retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, - dev->dvb_xfer_bulk, - EM28XX_DVB_NUM_BUFS, - dev->dvb_max_pkt_size_isoc, - EM28XX_DVB_NUM_ISOC_PACKETS); - } - if (retval) { - printk(DRIVER_NAME - ": Failed to pre-allocate USB transfer buffers for DVB.\n"); - goto unlock_and_free; - } } + kref_init(&dev->ref); + request_modules(dev); /* Should be the last thing to do, to avoid newer udev's to open the device before fully initializing it */ - mutex_unlock(&dev->lock); return 0; -unlock_and_free: - mutex_unlock(&dev->lock); - err_free: kfree(dev->alt_max_pkt_size_isoc); kfree(dev); err: - clear_bit(nr, &em28xx_devused); + clear_bit(nr, em28xx_devused); err_no_slot: usb_put_dev(udev); @@ -3448,47 +3483,46 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) dev->disconnected = 1; - if (dev->is_audio_only) { - mutex_lock(&dev->lock); - em28xx_close_extension(dev); - mutex_unlock(&dev->lock); - return; - } - - em28xx_info("disconnecting %s\n", dev->vdev->name); + em28xx_info("Disconnecting %s\n", dev->name); flush_request_modules(dev); - mutex_lock(&dev->lock); - - v4l2_device_disconnect(&dev->v4l2_dev); - - if (dev->users) { - em28xx_warn("device %s is open! Deregistration and memory deallocation are deferred on close.\n", - video_device_node_name(dev->vdev)); + em28xx_close_extension(dev); - em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE); - em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); - } + em28xx_release_resources(dev); + kref_put(&dev->ref, em28xx_free_device); +} - em28xx_close_extension(dev); - /* NOTE: must be called BEFORE the resources are released */ +static int em28xx_usb_suspend(struct usb_interface *interface, + pm_message_t message) +{ + struct em28xx *dev; - if (!dev->users) - em28xx_release_resources(dev); + dev = usb_get_intfdata(interface); + if (!dev) + return 0; + em28xx_suspend_extension(dev); + return 0; +} - mutex_unlock(&dev->lock); +static int em28xx_usb_resume(struct usb_interface *interface) +{ + struct em28xx *dev; - if (!dev->users) { - kfree(dev->alt_max_pkt_size_isoc); - kfree(dev); - } + dev = usb_get_intfdata(interface); + if (!dev) + return 0; + em28xx_resume_extension(dev); + return 0; } static struct usb_driver em28xx_usb_driver = { .name = "em28xx", .probe = em28xx_usb_probe, .disconnect = em28xx_usb_disconnect, + .suspend = em28xx_usb_suspend, + .resume = em28xx_usb_resume, + .reset_resume = em28xx_usb_resume, .id_table = em28xx_id_table, }; diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index fc157af5234..523d7e92bf4 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -23,6 +23,7 @@ */ #include <linux/init.h> +#include <linux/jiffies.h> #include <linux/list.h> #include <linux/module.h> #include <linux/slab.h> @@ -33,6 +34,16 @@ #include "em28xx.h" +#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \ + "Markus Rechberger <mrechberger@gmail.com>, " \ + "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ + "Sascha Sommer <saschasommer@freenet.de>" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_VERSION(EM28XX_VERSION); + /* #define ENABLE_DEBUG_ISOC_FRAMES */ static unsigned int core_debug; @@ -53,14 +64,6 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); printk(KERN_INFO "%s %s :"fmt, \ dev->name, __func__ , ##arg); } while (0) -static int alt; -module_param(alt, int, 0644); -MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); - -static unsigned int disable_vbi; -module_param(disable_vbi, int, 0644); -MODULE_PARM_DESC(disable_vbi, "disable vbi support"); - /* FIXME */ #define em28xx_isocdbg(fmt, arg...) do {\ if (core_debug) \ @@ -226,21 +229,42 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, EXPORT_SYMBOL_GPL(em28xx_write_reg_bits); /* + * em28xx_toggle_reg_bits() + * toggles/inverts the bits (specified by bitmask) of a register + */ +int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask) +{ + int oldval; + u8 newval; + + oldval = em28xx_read_reg(dev, reg); + if (oldval < 0) + return oldval; + + newval = (~oldval & bitmask) | (oldval & ~bitmask); + + return em28xx_write_reg(dev, reg, newval); +} +EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits); + +/* * em28xx_is_ac97_ready() * Checks if ac97 is ready */ static int em28xx_is_ac97_ready(struct em28xx *dev) { - int ret, i; + unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_AC97_XFER_TIMEOUT); + int ret; /* Wait up to 50 ms for AC97 command to complete */ - for (i = 0; i < 10; i++, msleep(5)) { + while (time_is_after_jiffies(timeout)) { ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); if (ret < 0) return ret; if (!(ret & 0x01)) return 0; + msleep(5); } em28xx_warn("AC97 command still being executed: not handled properly!\n"); @@ -482,16 +506,8 @@ int em28xx_audio_setup(struct em28xx *dev) int vid1, vid2, feat, cfg; u32 vid; - if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874 - || dev->chip_id == CHIP_ID_EM28174) { - /* Digital only device - don't load any alsa module */ - dev->audio_mode.has_audio = false; - dev->has_audio_class = false; - dev->has_alsa_audio = false; + if (!dev->audio_mode.has_audio) return 0; - } - - dev->audio_mode.has_audio = true; /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); @@ -504,17 +520,19 @@ int em28xx_audio_setup(struct em28xx *dev) dev->has_alsa_audio = false; dev->audio_mode.has_audio = false; return 0; - } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == - EM28XX_CHIPCFG_I2S_3_SAMPRATES) { - em28xx_info("I2S Audio (3 sample rates)\n"); - dev->audio_mode.i2s_3rates = 1; - } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == - EM28XX_CHIPCFG_I2S_5_SAMPRATES) { - em28xx_info("I2S Audio (5 sample rates)\n"); - dev->audio_mode.i2s_5rates = 1; - } - - if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { + } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { + if (dev->chip_id < CHIP_ID_EM2860 && + (cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM2820_CHIPCFG_I2S_1_SAMPRATE) + dev->audio_mode.i2s_samplerates = 1; + else if (dev->chip_id >= CHIP_ID_EM2860 && + (cfg & EM28XX_CHIPCFG_AUDIOMASK) == + EM2860_CHIPCFG_I2S_5_SAMPRATES) + dev->audio_mode.i2s_samplerates = 5; + else + dev->audio_mode.i2s_samplerates = 3; + em28xx_info("I2S Audio (%d sample rate(s))\n", + dev->audio_mode.i2s_samplerates); /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; goto init_audio; @@ -582,295 +600,81 @@ init_audio: } EXPORT_SYMBOL_GPL(em28xx_audio_setup); -int em28xx_colorlevels_set_default(struct em28xx *dev) +const struct em28xx_led *em28xx_find_led(struct em28xx *dev, + enum em28xx_led_role role) { - em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT); - em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT); - em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT); - em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT); - em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT); - em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT); - - em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); - em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); - em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); - em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); - em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); - em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); - return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); + if (dev->board.leds) { + u8 k = 0; + while (dev->board.leds[k].role >= 0 && + dev->board.leds[k].role < EM28XX_NUM_LED_ROLES) { + if (dev->board.leds[k].role == role) + return &dev->board.leds[k]; + k++; + } + } + return NULL; } +EXPORT_SYMBOL_GPL(em28xx_find_led); int em28xx_capture_start(struct em28xx *dev, int start) { int rc; + const struct em28xx_led *led = NULL; if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM2884 || - dev->chip_id == CHIP_ID_EM28174) { + dev->chip_id == CHIP_ID_EM28174 || + dev->chip_id == CHIP_ID_EM28178) { /* The Transport Stream Enable Register moved in em2874 */ - if (!start) { - rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, - 0x00, - EM2874_TS1_CAPTURE_ENABLE); - return rc; - } - - /* Enable Transport Stream */ rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, - EM2874_TS1_CAPTURE_ENABLE, + start ? + EM2874_TS1_CAPTURE_ENABLE : 0x00, EM2874_TS1_CAPTURE_ENABLE); - return rc; - } - - - /* FIXME: which is the best order? */ - /* video registers are sampled by VREF */ - rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, - start ? 0x10 : 0x00, 0x10); - if (rc < 0) - return rc; - - if (!start) { - /* disable video capture */ - rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); - return rc; - } - - if (dev->board.is_webcam) - rc = em28xx_write_reg(dev, 0x13, 0x0c); - - /* enable video capture */ - rc = em28xx_write_reg(dev, 0x48, 0x00); - - if (dev->mode == EM28XX_ANALOG_MODE) - rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); - else - rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); - - msleep(6); - - return rc; -} - -int em28xx_vbi_supported(struct em28xx *dev) -{ - /* Modprobe option to manually disable */ - if (disable_vbi == 1) - return 0; - - if (dev->board.is_webcam) - return 0; - - /* FIXME: check subdevices for VBI support */ - - if (dev->chip_id == CHIP_ID_EM2860 || - dev->chip_id == CHIP_ID_EM2883) - return 1; + } else { + /* FIXME: which is the best order? */ + /* video registers are sampled by VREF */ + rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, + start ? 0x10 : 0x00, 0x10); + if (rc < 0) + return rc; - /* Version of em28xx that does not support VBI */ - return 0; -} + if (start) { + if (dev->board.is_webcam) + rc = em28xx_write_reg(dev, 0x13, 0x0c); -int em28xx_set_outfmt(struct em28xx *dev) -{ - int ret; - u8 fmt, vinctrl; - - fmt = dev->format->reg; - if (!dev->is_em25xx) - fmt |= 0x20; - /* - * NOTE: it's not clear if this is really needed ! - * The datasheets say bit 5 is a reserved bit and devices seem to work - * fine without it. But the Windows driver sets it for em2710/50+em28xx - * devices and we've always been setting it, too. - * - * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set, - * it's likely used for an additional (compressed ?) format there. - */ - ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt); - if (ret < 0) - return ret; + /* Enable video capture */ + rc = em28xx_write_reg(dev, 0x48, 0x00); + if (rc < 0) + return rc; - ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); - if (ret < 0) - return ret; + if (dev->mode == EM28XX_ANALOG_MODE) + rc = em28xx_write_reg(dev, + EM28XX_R12_VINENABLE, 0x67); + else + rc = em28xx_write_reg(dev, + EM28XX_R12_VINENABLE, 0x37); + if (rc < 0) + return rc; - vinctrl = dev->vinctl; - if (em28xx_vbi_supported(dev) == 1) { - vinctrl |= EM28XX_VINCTRL_VBI_RAW; - em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); - em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4); - em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height); - if (dev->norm & V4L2_STD_525_60) { - /* NTSC */ - em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); - } else if (dev->norm & V4L2_STD_625_50) { - /* PAL */ - em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07); + msleep(6); + } else { + /* disable video capture */ + rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); } } - return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); -} - -static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, - u8 ymin, u8 ymax) -{ - em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", - xmin, ymin, xmax, ymax); - - em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); - em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); - em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); - return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); -} - -static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, - u16 width, u16 height) -{ - u8 cwidth = width >> 2; - u8 cheight = height >> 2; - u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01); - /* NOTE: size limit: 2047x1023 = 2MPix */ - - em28xx_coredbg("capture area set to (%d,%d): %dx%d\n", - hstart, vstart, - ((overflow & 2) << 9 | cwidth << 2), - ((overflow & 1) << 10 | cheight << 2)); - - em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); - em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); - em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); - em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); - em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); - - /* FIXME: function/meaning of these registers ? */ - /* FIXME: align width+height to multiples of 4 ?! */ - if (dev->is_em25xx) { - em28xx_write_reg(dev, 0x34, width >> 4); - em28xx_write_reg(dev, 0x35, height >> 4); - } -} - -static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) -{ - u8 mode; - /* the em2800 scaler only supports scaling down to 50% */ - - if (dev->board.is_em2800) { - mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); - } else { - u8 buf[2]; - - buf[0] = h; - buf[1] = h >> 8; - em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); - - buf[0] = v; - buf[1] = v >> 8; - em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); - /* it seems that both H and V scalers must be active - to work correctly */ - mode = (h || v) ? 0x30 : 0x00; - } - return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); -} - -/* FIXME: this only function read values from dev */ -int em28xx_resolution_set(struct em28xx *dev) -{ - int width, height; - width = norm_maxw(dev); - height = norm_maxh(dev); - - /* Properly setup VBI */ - dev->vbi_width = 720; - if (dev->norm & V4L2_STD_525_60) - dev->vbi_height = 12; - else - dev->vbi_height = 18; - - em28xx_set_outfmt(dev); - - em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); - - /* If we don't set the start position to 2 in VBI mode, we end up - with line 20/21 being YUYV encoded instead of being in 8-bit - greyscale. The core of the issue is that line 21 (and line 23 for - PAL WSS) are inside of active video region, and as a result they - get the pixelformatting associated with that area. So by cropping - it out, we end up with the same format as the rest of the VBI - region */ - if (em28xx_vbi_supported(dev) == 1) - em28xx_capture_area_set(dev, 0, 2, width, height); + if (dev->mode == EM28XX_ANALOG_MODE) + led = em28xx_find_led(dev, EM28XX_LED_ANALOG_CAPTURING); else - em28xx_capture_area_set(dev, 0, 0, width, height); - - return em28xx_scaler_set(dev, dev->hscale, dev->vscale); -} + led = em28xx_find_led(dev, EM28XX_LED_DIGITAL_CAPTURING); -/* Set USB alternate setting for analog video */ -int em28xx_set_alternate(struct em28xx *dev) -{ - int errCode; - int i; - unsigned int min_pkt_size = dev->width * 2 + 4; - - /* NOTE: for isoc transfers, only alt settings > 0 are allowed - bulk transfers seem to work only with alt=0 ! */ - dev->alt = 0; - if ((alt > 0) && (alt < dev->num_alt)) { - em28xx_coredbg("alternate forced to %d\n", dev->alt); - dev->alt = alt; - goto set_alt; - } - if (dev->analog_xfer_bulk) - goto set_alt; + if (led) + em28xx_write_reg_bits(dev, led->gpio_reg, + (!start ^ led->inverted) ? + ~led->gpio_mask : led->gpio_mask, + led->gpio_mask); - /* When image size is bigger than a certain value, - the frame size should be increased, otherwise, only - green screen will be received. - */ - if (dev->width * 2 * dev->height > 720 * 240 * 2) - min_pkt_size *= 2; - - for (i = 0; i < dev->num_alt; i++) { - /* stop when the selected alt setting offers enough bandwidth */ - if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) { - dev->alt = i; - break; - /* otherwise make sure that we end up with the maximum bandwidth - because the min_pkt_size equation might be wrong... - */ - } else if (dev->alt_max_pkt_size_isoc[i] > - dev->alt_max_pkt_size_isoc[dev->alt]) - dev->alt = i; - } - -set_alt: - /* NOTE: for bulk transfers, we need to call usb_set_interface() - * even if the previous settings were the same. Otherwise streaming - * fails with all urbs having status = -EOVERFLOW ! */ - if (dev->analog_xfer_bulk) { - dev->max_pkt_size = 512; /* USB 2.0 spec */ - dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; - } else { /* isoc */ - em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", - min_pkt_size, dev->alt); - dev->max_pkt_size = - dev->alt_max_pkt_size_isoc[dev->alt]; - dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS; - } - em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", - dev->alt, dev->max_pkt_size); - errCode = usb_set_interface(dev->udev, 0, dev->alt); - if (errCode < 0) { - em28xx_errdev("cannot change alternate number to %d (error=%i)\n", - dev->alt, errCode); - return errCode; - } - return 0; + return rc; } int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) @@ -1238,18 +1042,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer); /* - * em28xx_wake_i2c() - * configure i2c attached devices - */ -void em28xx_wake_i2c(struct em28xx *dev) -{ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, - INPUT(dev->ctl_input)->vmux, 0, 0); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); -} - -/* * Device control list */ @@ -1272,7 +1064,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) ops->init(dev); } mutex_unlock(&em28xx_devlist_mutex); - printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); + printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name); return 0; } EXPORT_SYMBOL(em28xx_register_extension); @@ -1316,3 +1108,31 @@ void em28xx_close_extension(struct em28xx *dev) list_del(&dev->devlist); mutex_unlock(&em28xx_devlist_mutex); } + +int em28xx_suspend_extension(struct em28xx *dev) +{ + const struct em28xx_ops *ops = NULL; + + em28xx_info("Suspending extensions"); + mutex_lock(&em28xx_devlist_mutex); + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->suspend) + ops->suspend(dev); + } + mutex_unlock(&em28xx_devlist_mutex); + return 0; +} + +int em28xx_resume_extension(struct em28xx *dev) +{ + const struct em28xx_ops *ops = NULL; + + em28xx_info("Resuming extensions"); + mutex_lock(&em28xx_devlist_mutex); + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->resume) + ops->resume(dev); + } + mutex_unlock(&em28xx_devlist_mutex); + return 0; +} diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index bb1e8dca80c..a121ed9561f 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -41,6 +41,7 @@ #include "mt352.h" #include "mt352_priv.h" /* FIXME */ #include "tda1002x.h" +#include "drx39xyj/drx39xxj.h" #include "tda18271.h" #include "s921.h" #include "drxd.h" @@ -48,13 +49,20 @@ #include "tda18271c2dd.h" #include "drxk.h" #include "tda10071.h" +#include "tda18212.h" #include "a8293.h" #include "qt1010.h" #include "mb86a20s.h" +#include "m88ds3103.h" +#include "m88ts2022.h" +#include "si2168.h" +#include "si2157.h" -MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface"); +MODULE_VERSION(EM28XX_VERSION); + static unsigned int debug; module_param(debug, int, 0644); @@ -87,6 +95,8 @@ struct em28xx_dvb { struct semaphore pll_mutex; bool dont_attach_fe1; int lna_gpio; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; }; @@ -156,6 +166,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb) if (urb->status != -EPROTO) continue; } + if (!urb->actual_length) + continue; dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer, urb->actual_length); } else { @@ -165,6 +177,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb) if (urb->iso_frame_desc[i].status != -EPROTO) continue; } + if (!urb->iso_frame_desc[i].actual_length) + continue; dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer + urb->iso_frame_desc[i].offset, @@ -198,15 +212,15 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) dvb_alt = dev->dvb_alt_isoc; } - usb_set_interface(dev->udev, 0, dvb_alt); + usb_set_interface(dev->udev, dev->ifnum, dvb_alt); rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; - dprintk(1, "Using %d buffers each with %d x %d bytes\n", + dprintk(1, "Using %d buffers each with %d x %d bytes, alternate %d\n", EM28XX_DVB_NUM_BUFS, packet_multiplier, - dvb_max_packet_size); + dvb_max_packet_size, dvb_alt); return em28xx_init_usb_xfer(dev, EM28XX_DIGITAL_MODE, dev->dvb_xfer_bulk, @@ -271,7 +285,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed) static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) { struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; - struct em28xx *dev = i2c_bus->dev; + struct em28xx *dev = i2c_bus->dev; if (acquire) return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); @@ -298,6 +312,30 @@ static struct lgdt3305_config em2870_lgdt3304_dev = { .qam_if_khz = 4000, }; +static struct lgdt3305_config em2874_lgdt3305_dev = { + .i2c_addr = 0x0e, + .demod_chip = LGDT3305, + .spectral_inversion = 1, + .deny_i2c_rptr = 0, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .vsb_if_khz = 3250, + .qam_if_khz = 4000, +}; + +static struct lgdt3305_config em2874_lgdt3305_nogate_dev = { + .i2c_addr = 0x0e, + .demod_chip = LGDT3305, + .spectral_inversion = 1, + .deny_i2c_rptr = 1, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .vsb_if_khz = 3600, + .qam_if_khz = 3600, +}; + static struct s921_config sharp_isdbt = { .demod_address = 0x30 >> 1 }; @@ -329,6 +367,17 @@ static struct tda18271_config kworld_a340_config = { .std_map = &kworld_a340_std_map, }; +static struct tda18271_config kworld_ub435q_v2_config = { + .std_map = &kworld_a340_std_map, + .gate = TDA18271_GATE_DIGITAL, +}; + +static struct tda18212_config kworld_ub435q_v3_config = { + .i2c_address = 0x60, + .if_atsc_vsb = 3600, + .if_atsc_qam = 3600, +}; + static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = { .demod_address = (0x1e >> 1), .no_tuner = 1, @@ -353,7 +402,6 @@ static struct drxk_config terratec_h5_drxk = { .no_i2c_bridge = 1, .microcode_name = "dvb-usb-terratec-h5-drxk.fw", .qam_demod_parameter_count = 2, - .load_firmware_sync = true, }; static struct drxk_config hauppauge_930c_drxk = { @@ -363,7 +411,6 @@ static struct drxk_config hauppauge_930c_drxk = { .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw", .chunk_size = 56, .qam_demod_parameter_count = 2, - .load_firmware_sync = true, }; static struct drxk_config terratec_htc_stick_drxk = { @@ -377,14 +424,15 @@ static struct drxk_config terratec_htc_stick_drxk = { .antenna_dvbt = true, /* The windows driver uses the same. This will disable LNA. */ .antenna_gpio = 0x6, - .load_firmware_sync = true, }; static struct drxk_config maxmedia_ub425_tc_drxk = { .adr = 0x29, .single_master = 1, .no_i2c_bridge = 1, - .load_firmware_sync = true, + .microcode_name = "dvb-demod-drxk-01.fw", + .chunk_size = 62, + .qam_demod_parameter_count = 2, }; static struct drxk_config pctv_520e_drxk = { @@ -395,7 +443,6 @@ static struct drxk_config pctv_520e_drxk = { .chunk_size = 58, .antenna_dvbt = true, /* disable LNA */ .antenna_gpio = (1 << 2), /* disable LNA */ - .load_firmware_sync = true, }; static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) @@ -424,7 +471,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0x65}, {EM2874_R80_GPIO_P0_CTRL, 0xfb, 0xff, 0x32}, {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0xb8}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; struct em28xx_reg_seq hauppauge_hvr930c_end[] = { {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x01}, @@ -439,7 +486,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) {EM2874_R80_GPIO_P0_CTRL, 0xcf, 0xff, 0x0b}, {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x65}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; struct { @@ -491,13 +538,13 @@ static void terratec_h5_init(struct em28xx *dev) {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; struct em28xx_reg_seq terratec_h5_end[] = { {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; struct { unsigned char r[4]; @@ -547,12 +594,12 @@ static void terratec_htc_stick_init(struct em28xx *dev) {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; struct em28xx_reg_seq terratec_htc_stick_end[] = { {EM2874_R80_GPIO_P0_CTRL, 0xb6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 50}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* @@ -594,13 +641,13 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev) {EM2874_R80_GPIO_P0_CTRL, 0xb2, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xb2, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xb6, 0xff, 100}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; struct em28xx_reg_seq terratec_htc_usb_xs_end[] = { {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, - { -1, -1, -1, -1}, + { -1, -1, -1, -1}, }; /* @@ -673,7 +720,8 @@ static void pctv_520e_init(struct em28xx *dev) static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct em28xx *dev = fe->dvb->priv; + struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; + struct em28xx *dev = i2c_bus->dev; #ifdef CONFIG_GPIOLIB struct em28xx_dvb *dvb = dev->dvb; int ret; @@ -698,6 +746,21 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) #endif } +static int em28xx_pctv_292e_set_lna(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; + struct em28xx *dev = i2c_bus->dev; + u8 lna; + + if (c->lna == 1) + lna = 0x01; + else + lna = 0x00; + + return em28xx_write_reg_bits(dev, EM2874_R80_GPIO_P0_CTRL, lna, 0x01); +} + static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) { /* Values extracted from a USB trace of the Terratec Windows driver */ @@ -788,6 +851,28 @@ static struct tda18271_config c3tech_duo_tda18271_config = { .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, }; +static const struct m88ds3103_config pctv_461e_m88ds3103_config = { + .i2c_addr = 0x68, + .clock = 27000000, + .i2c_wr_max = 33, + .clock_out = 0, + .ts_mode = M88DS3103_TS_PARALLEL_16, + .agc = 0x99, +}; + + +static struct tda18271_std_map drx_j_std_map = { + .atsc_6 = { .if_freq = 5000, .agc_mode = 3, .std = 0, .if_lvl = 1, + .rfagc_top = 0x37, }, + .qam_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, .if_lvl = 1, + .rfagc_top = 0x37, }, +}; + +static struct tda18271_config pinnacle_80e_dvb_config = { + .std_map = &drx_j_std_map, + .gate = TDA18271_GATE_DIGITAL, + .role = TDA18271_MASTER, +}; /* ------------------------------------------------------------------ */ @@ -795,11 +880,16 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) { struct dvb_frontend *fe; struct xc2028_config cfg; + struct xc2028_ctrl ctl; memset(&cfg, 0, sizeof(cfg)); cfg.i2c_adap = &dev->i2c_adap[dev->def_i2c_bus]; cfg.i2c_addr = addr; + memset(&ctl, 0, sizeof(ctl)); + em28xx_setup_xc3028(dev, &ctl); + cfg.ctrl = &ctl; + if (!dev->dvb->fe[0]) { em28xx_errdev("/2: dvb frontend not attached. " "Can't attach xc3028\n"); @@ -959,14 +1049,19 @@ static int em28xx_dvb_init(struct em28xx *dev) int result = 0, mfe_shared = 0; struct em28xx_dvb *dvb; + if (dev->is_audio_only) { + /* Shouldn't initialize IR for this interface */ + return 0; + } + if (!dev->board.has_dvb) { /* This device does not support the extension */ - printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n"); return 0; } - dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); + em28xx_info("Binding DVB extension\n"); + dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); if (dvb == NULL) { em28xx_info("em28xx_dvb: memory allocation failed\n"); return -ENOMEM; @@ -974,6 +1069,27 @@ static int em28xx_dvb_init(struct em28xx *dev) dev->dvb = dvb; dvb->fe[0] = dvb->fe[1] = NULL; + /* pre-allocate DVB usb transfer buffers */ + if (dev->dvb_xfer_bulk) { + result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, + dev->dvb_xfer_bulk, + EM28XX_DVB_NUM_BUFS, + 512, + EM28XX_DVB_BULK_PACKET_MULTIPLIER); + } else { + result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE, + dev->dvb_xfer_bulk, + EM28XX_DVB_NUM_BUFS, + dev->dvb_max_pkt_size_isoc, + EM28XX_DVB_NUM_ISOC_PACKETS); + } + if (result) { + em28xx_errdev("em28xx_dvb: failed to pre-allocate USB transfer buffers for DVB.\n"); + kfree(dvb); + dev->dvb = NULL; + return result; + } + mutex_lock(&dev->lock); em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); /* init frontend */ @@ -1227,18 +1343,14 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->fe[0]->ops.i2c_gate_ctrl = NULL; /* attach tuner */ - if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], - &dev->i2c_adap[dev->def_i2c_bus], 0x60)) { + if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + &dev->i2c_adap[dev->def_i2c_bus], + &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; } } - - /* TODO: we need drx-3913k firmware in order to support DVB-T */ - em28xx_info("MaxMedia UB425-TC/Delock 61959: only DVB-C " \ - "supported by that driver version\n"); - break; case EM2884_BOARD_PCTV_510E: case EM2884_BOARD_PCTV_520E: @@ -1297,6 +1409,168 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2874_BOARD_KWORLD_UB435Q_V2: + dvb->fe[0] = dvb_attach(lgdt3305_attach, + &em2874_lgdt3305_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + + /* Attach the demodulator. */ + if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + &dev->i2c_adap[dev->def_i2c_bus], + &kworld_ub435q_v2_config)) { + result = -EINVAL; + goto out_free; + } + break; + case EM2874_BOARD_KWORLD_UB435Q_V3: + dvb->fe[0] = dvb_attach(lgdt3305_attach, + &em2874_lgdt3305_nogate_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + + /* Attach the demodulator. */ + if (!dvb_attach(tda18212_attach, dvb->fe[0], + &dev->i2c_adap[dev->def_i2c_bus], + &kworld_ub435q_v3_config)) { + result = -EINVAL; + goto out_free; + } + break; + case EM2874_BOARD_PCTV_HD_MINI_80E: + dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0] != NULL) { + dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + &dev->i2c_adap[dev->def_i2c_bus], + &pinnacle_80e_dvb_config); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + } + break; + case EM28178_BOARD_PCTV_461E: + { + /* demod I2C adapter */ + struct i2c_adapter *i2c_adapter; + struct i2c_client *client; + struct i2c_board_info info; + struct m88ts2022_config m88ts2022_config = { + .clock = 27000000, + }; + memset(&info, 0, sizeof(struct i2c_board_info)); + + /* attach demod */ + dvb->fe[0] = dvb_attach(m88ds3103_attach, + &pctv_461e_m88ds3103_config, + &dev->i2c_adap[dev->def_i2c_bus], + &i2c_adapter); + if (dvb->fe[0] == NULL) { + result = -ENODEV; + goto out_free; + } + + /* attach tuner */ + m88ts2022_config.fe = dvb->fe[0]; + strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &m88ts2022_config; + request_module("m88ts2022"); + client = i2c_new_device(i2c_adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + dvb_frontend_detach(dvb->fe[0]); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + dvb_frontend_detach(dvb->fe[0]); + result = -ENODEV; + goto out_free; + } + + /* delegate signal strength measurement to tuner */ + dvb->fe[0]->ops.read_signal_strength = + dvb->fe[0]->ops.tuner_ops.get_rf_strength; + + /* attach SEC */ + if (!dvb_attach(a8293_attach, dvb->fe[0], + &dev->i2c_adap[dev->def_i2c_bus], + &em28xx_a8293_config)) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + dvb_frontend_detach(dvb->fe[0]); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_tuner = client; + } + break; + case EM28178_BOARD_PCTV_292E: + { + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info info; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + + /* attach demod */ + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &dvb->fe[0]; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module(info.type); + client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info); + if (client == NULL || client->dev.driver == NULL) { + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_demod = client; + + /* attach tuner */ + si2157_config.fe = dvb->fe[0]; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module(info.type); + client = i2c_new_device(adapter, &info); + if (client == NULL || client->dev.driver == NULL) { + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + module_put(dvb->i2c_client_demod->dev.driver->owner); + i2c_unregister_device(dvb->i2c_client_demod); + result = -ENODEV; + goto out_free; + } + + dvb->i2c_client_tuner = client; + dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna; + } + break; default: em28xx_errdev("/2: The frontend of your DVB/ATSC card" " isn't supported yet\n"); @@ -1321,7 +1595,10 @@ static int em28xx_dvb_init(struct em28xx *dev) /* MFE lock */ dvb->adapter.mfe_shared = mfe_shared; - em28xx_info("Successfully loaded em28xx-dvb\n"); + em28xx_info("DVB extension successfully initialized\n"); + + kref_get(&dev->ref); + ret: em28xx_set_mode(dev, EM28XX_SUSPEND); mutex_unlock(&dev->lock); @@ -1342,21 +1619,121 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops) static int em28xx_dvb_fini(struct em28xx *dev) { + struct em28xx_dvb *dvb; + struct i2c_client *client; + + if (dev->is_audio_only) { + /* Shouldn't initialize IR for this interface */ + return 0; + } + if (!dev->board.has_dvb) { /* This device does not support the extension */ return 0; } + if (!dev->dvb) + return 0; + + em28xx_info("Closing DVB extension"); + + dvb = dev->dvb; + client = dvb->i2c_client_tuner; + + em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); + + if (dev->disconnected) { + /* We cannot tell the device to sleep + * once it has been unplugged. */ + if (dvb->fe[0]) + prevent_sleep(&dvb->fe[0]->ops); + if (dvb->fe[1]) + prevent_sleep(&dvb->fe[1]->ops); + } + + /* remove I2C tuner */ + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C demod */ + client = dvb->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + em28xx_unregister_dvb(dvb); + kfree(dvb); + dev->dvb = NULL; + kref_put(&dev->ref, em28xx_free_device); + + return 0; +} + +static int em28xx_dvb_suspend(struct em28xx *dev) +{ + int ret = 0; + + if (dev->is_audio_only) + return 0; + + if (!dev->board.has_dvb) + return 0; + + em28xx_info("Suspending DVB extension"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; - if (dev->disconnected) { - /* We cannot tell the device to sleep - * once it has been unplugged. */ - if (dvb->fe[0]) - prevent_sleep(&dvb->fe[0]->ops); - if (dvb->fe[1]) - prevent_sleep(&dvb->fe[1]->ops); + if (dvb->fe[0]) { + ret = dvb_frontend_suspend(dvb->fe[0]); + em28xx_info("fe0 suspend %d", ret); + } + if (dvb->fe[1]) { + dvb_frontend_suspend(dvb->fe[1]); + em28xx_info("fe1 suspend %d", ret); + } + } + + return 0; +} + +static int em28xx_dvb_resume(struct em28xx *dev) +{ + int ret = 0; + + if (dev->is_audio_only) + return 0; + + if (!dev->board.has_dvb) + return 0; + + em28xx_info("Resuming DVB extension"); + if (dev->dvb) { + struct em28xx_dvb *dvb = dev->dvb; + struct i2c_client *client = dvb->i2c_client_tuner; + + if (dvb->fe[0]) { + ret = dvb_frontend_resume(dvb->fe[0]); + em28xx_info("fe0 resume %d", ret); + } + + if (dvb->fe[1]) { + ret = dvb_frontend_resume(dvb->fe[1]); + em28xx_info("fe1 resume %d", ret); + } + /* remove I2C tuner */ + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C demod */ + client = dvb->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); } em28xx_unregister_dvb(dvb); @@ -1372,6 +1749,8 @@ static struct em28xx_ops dvb_ops = { .name = "Em28xx dvb Extension", .init = em28xx_dvb_init, .fini = em28xx_dvb_fini, + .suspend = em28xx_dvb_suspend, + .resume = em28xx_dvb_resume, }; static int __init em28xx_dvb_register(void) diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index c4ff9739a7a..b58d4ebf641 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -26,6 +26,7 @@ #include <linux/kernel.h> #include <linux/usb.h> #include <linux/i2c.h> +#include <linux/jiffies.h> #include "em28xx.h" #include "tuner-xc2028.h" @@ -40,7 +41,7 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); static unsigned int i2c_debug; module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); +MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)"); /* * em2800_i2c_send_bytes() @@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); */ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) { + unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); int ret; - int write_timeout; u8 b2[6]; if (len < 1 || len > 4) @@ -74,22 +75,26 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) return (ret < 0) ? ret : -EIO; } /* wait for completion */ - for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; - write_timeout -= 5) { + while (time_is_after_jiffies(timeout)) { ret = dev->em28xx_read_reg(dev, 0x05); - if (ret == 0x80 + len - 1) { + if (ret == 0x80 + len - 1) return len; - } else if (ret == 0x94 + len - 1) { - return -ENODEV; - } else if (ret < 0) { + if (ret == 0x94 + len - 1) { + if (i2c_debug == 1) + em28xx_warn("R05 returned 0x%02x: I2C ACK error\n", + ret); + return -ENXIO; + } + if (ret < 0) { em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } msleep(5); } - em28xx_warn("write to i2c device at 0x%x timed out\n", addr); - return -EIO; + if (i2c_debug) + em28xx_warn("write to i2c device at 0x%x timed out\n", addr); + return -ETIMEDOUT; } /* @@ -98,9 +103,9 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) */ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) { + unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); u8 buf2[4]; int ret; - int read_timeout; int i; if (len < 1 || len > 4) @@ -117,22 +122,28 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) } /* wait for completion */ - for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0; - read_timeout -= 5) { + while (time_is_after_jiffies(timeout)) { ret = dev->em28xx_read_reg(dev, 0x05); - if (ret == 0x84 + len - 1) { + if (ret == 0x84 + len - 1) break; - } else if (ret == 0x94 + len - 1) { - return -ENODEV; - } else if (ret < 0) { + if (ret == 0x94 + len - 1) { + if (i2c_debug == 1) + em28xx_warn("R05 returned 0x%02x: I2C ACK error\n", + ret); + return -ENXIO; + } + if (ret < 0) { em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } msleep(5); } - if (ret != 0x84 + len - 1) - em28xx_warn("read from i2c device at 0x%x timed out\n", addr); + if (ret != 0x84 + len - 1) { + if (i2c_debug) + em28xx_warn("read from i2c device at 0x%x timed out\n", + addr); + } /* get the received message */ ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); @@ -168,7 +179,8 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr) static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len, int stop) { - int write_timeout, ret; + unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT); + int ret; if (len < 1 || len > 64) return -EOPNOTSUPP; @@ -191,16 +203,19 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, } } - /* Check success of the i2c operation */ - for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; - write_timeout -= 5) { + /* wait for completion */ + while (time_is_after_jiffies(timeout)) { ret = dev->em28xx_read_reg(dev, 0x05); - if (ret == 0) { /* success */ + if (ret == 0) /* success */ return len; - } else if (ret == 0x10) { - return -ENODEV; - } else if (ret < 0) { - em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n", + if (ret == 0x10) { + if (i2c_debug == 1) + em28xx_warn("I2C ACK error on writing to addr 0x%02x\n", + addr); + return -ENXIO; + } + if (ret < 0) { + em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } @@ -211,7 +226,17 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, * (even with high payload) ... */ } - em28xx_warn("write to i2c device at 0x%x timed out\n", addr); + + if (ret == 0x02 || ret == 0x04) { + /* NOTE: these errors seem to be related to clock stretching */ + if (i2c_debug) + em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n", + addr, ret); + return -ETIMEDOUT; + } + + em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", + addr, ret); return -EIO; } @@ -242,26 +267,37 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) * bytes if we are on bus B AND there was no write attempt to the * specified slave address before AND no device is present at the * requested slave address. - * Anyway, the next check will fail with -ENODEV in this case, so avoid + * Anyway, the next check will fail with -ENXIO in this case, so avoid * spamming the system log on device probing and do nothing here. */ /* Check success of the i2c operation */ ret = dev->em28xx_read_reg(dev, 0x05); + if (ret == 0) /* success */ + return len; if (ret < 0) { - em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n", + em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } - if (ret > 0) { - if (ret == 0x10) { - return -ENODEV; - } else { - em28xx_warn("unknown i2c error (status=%i)\n", ret); - return -EIO; - } + if (ret == 0x10) { + if (i2c_debug == 1) + em28xx_warn("I2C ACK error on writing to addr 0x%02x\n", + addr); + return -ENXIO; } - return len; + + if (ret == 0x02 || ret == 0x04) { + /* NOTE: these errors seem to be related to clock stretching */ + if (i2c_debug) + em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n", + addr, ret); + return -ETIMEDOUT; + } + + em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", + addr, ret); + return -EIO; } /* @@ -316,8 +352,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, */ if (!ret) return len; - else if (ret > 0) - return -ENODEV; + else if (ret > 0) { + if (i2c_debug == 1) + em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", + ret); + return -ENXIO; + } return ret; /* @@ -355,7 +395,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, * bytes if we are on bus B AND there was no write attempt to the * specified slave address before AND no device is present at the * requested slave address. - * Anyway, the next check will fail with -ENODEV in this case, so avoid + * Anyway, the next check will fail with -ENXIO in this case, so avoid * spamming the system log on device probing and do nothing here. */ @@ -367,8 +407,12 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, */ if (!ret) return len; - else if (ret > 0) - return -ENODEV; + else if (ret > 0) { + if (i2c_debug == 1) + em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", + ret); + return -ENXIO; + } return ret; /* @@ -409,10 +453,6 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr) rc = em2800_i2c_check_for_device(dev, addr); else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) rc = em25xx_bus_B_check_for_device(dev, addr); - if (rc == -ENODEV) { - if (i2c_debug) - printk(" no device\n"); - } return rc; } @@ -421,7 +461,7 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus, { struct em28xx *dev = i2c_bus->dev; u16 addr = msg.addr << 1; - int byte, rc = -EOPNOTSUPP; + int rc = -EOPNOTSUPP; if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len); @@ -429,10 +469,6 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus, rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len); else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len); - if (i2c_debug) { - for (byte = 0; byte < msg.len; byte++) - printk(" %02x", msg.buf[byte]); - } return rc; } @@ -441,12 +477,8 @@ static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus, { struct em28xx *dev = i2c_bus->dev; u16 addr = msg.addr << 1; - int byte, rc = -EOPNOTSUPP; + int rc = -EOPNOTSUPP; - if (i2c_debug) { - for (byte = 0; byte < msg.len; byte++) - printk(" %02x", msg.buf[byte]); - } if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop); else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) @@ -491,33 +523,53 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, } for (i = 0; i < num; i++) { addr = msgs[i].addr << 1; - if (i2c_debug) + if (i2c_debug > 1) printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:", dev->name, __func__ , (msgs[i].flags & I2C_M_RD) ? "read" : "write", i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); - if (!msgs[i].len) { /* no len: check only for device presence */ + if (!msgs[i].len) { + /* + * no len: check only for device presence + * This code is only called during device probe. + */ rc = i2c_check_for_device(i2c_bus, addr); - if (rc == -ENODEV) { + if (rc < 0) { + if (rc == -ENXIO) { + if (i2c_debug > 1) + printk(KERN_CONT " no device\n"); + rc = -ENODEV; + } else { + if (i2c_debug > 1) + printk(KERN_CONT " ERROR: %i\n", rc); + } rt_mutex_unlock(&dev->i2c_bus_lock); return rc; } } else if (msgs[i].flags & I2C_M_RD) { /* read bytes */ rc = i2c_recv_bytes(i2c_bus, msgs[i]); + + if (i2c_debug > 1 && rc >= 0) + printk(KERN_CONT " %*ph", + msgs[i].len, msgs[i].buf); } else { + if (i2c_debug > 1) + printk(KERN_CONT " %*ph", + msgs[i].len, msgs[i].buf); + /* write bytes */ rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1); } if (rc < 0) { - if (i2c_debug) - printk(" ERROR: %i\n", rc); + if (i2c_debug > 1) + printk(KERN_CONT " ERROR: %i\n", rc); rt_mutex_unlock(&dev->i2c_bus_lock); return rc; } - if (i2c_debug) - printk("\n"); + if (i2c_debug > 1) + printk(KERN_CONT "\n"); } rt_mutex_unlock(&dev->i2c_bus_lock); @@ -600,7 +652,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, * calculation and returned device dataset. Simplifies the code a lot, * but we might have to deal with multiple sizes in the future ! */ - int i, err; + int err; struct em28xx_eeprom *dev_config; u8 buf, *data; @@ -631,20 +683,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, goto error; } - /* Display eeprom content */ - for (i = 0; i < len; i++) { - if (0 == (i % 16)) { - if (dev->eeprom_addrwidth_16bit) - em28xx_info("i2c eeprom %04x:", i); - else - em28xx_info("i2c eeprom %02x:", i); - } - printk(" %02x", data[i]); - if (15 == (i % 16)) - printk("\n"); + if (i2c_debug) { + /* Display eeprom content */ + print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET, + 16, 1, data, len, true); + + if (dev->eeprom_addrwidth_16bit) + em28xx_info("eeprom %06x: ... (skipped)\n", 256); } - if (dev->eeprom_addrwidth_16bit) - em28xx_info("i2c eeprom %04x: ... (skipped)\n", i); if (dev->eeprom_addrwidth_16bit && data[0] == 0x26 && data[3] == 0x00) { @@ -736,10 +782,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, em28xx_info("\tAC97 audio (5 sample rates)\n"); break; case 2: - em28xx_info("\tI2S audio, sample rate=32k\n"); + if (dev->chip_id < CHIP_ID_EM2860) + em28xx_info("\tI2S audio, sample rate=32k\n"); + else + em28xx_info("\tI2S audio, 3 sample rates\n"); break; case 3: - em28xx_info("\tI2S audio, 3 sample rates\n"); + if (dev->chip_id < CHIP_ID_EM2860) + em28xx_info("\tI2S audio, 3 sample rates\n"); + else + em28xx_info("\tI2S audio, 5 sample rates\n"); break; } @@ -887,7 +939,6 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, dev->i2c_bus[bus].algo_type = algo_type; dev->i2c_bus[bus].dev = dev; dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus]; - i2c_set_adapdata(&dev->i2c_adap[bus], &dev->v4l2_dev); retval = i2c_add_adapter(&dev->i2c_adap[bus]); if (retval < 0) { diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index ea181e4b68c..56ef49df4f8 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -30,8 +30,9 @@ #include "em28xx.h" -#define EM28XX_SNAPSHOT_KEY KEY_CAMERA -#define EM28XX_SBUTTON_QUERY_INTERVAL 500 +#define EM28XX_SNAPSHOT_KEY KEY_CAMERA +#define EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL 500 /* [ms] */ +#define EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL 100 /* [ms] */ static unsigned int ir_debug; module_param(ir_debug, int, 0644); @@ -442,6 +443,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) case CHIP_ID_EM2884: case CHIP_ID_EM2874: case CHIP_ID_EM28174: + case CHIP_ID_EM28178: return em2874_ir_change_protocol(rc_dev, rc_type); default: printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n", @@ -470,54 +472,98 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev) } /********************************************************** - Handle Webcam snapshot button + Handle buttons **********************************************************/ -static void em28xx_query_sbutton(struct work_struct *work) +static void em28xx_query_buttons(struct work_struct *work) { - /* Poll the register and see if the button is depressed */ struct em28xx *dev = - container_of(work, struct em28xx, sbutton_query_work.work); - int ret; - - ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP); - - if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) { - u8 cleared; - /* Button is depressed, clear the register */ - cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT; - em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1); - - /* Not emulate the keypress */ - input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, - 1); - /* Now unpress the key */ - input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, - 0); + container_of(work, struct em28xx, buttons_query_work.work); + u8 i, j; + int regval; + bool is_pressed, was_pressed; + const struct em28xx_led *led; + + /* Poll and evaluate all addresses */ + for (i = 0; i < dev->num_button_polling_addresses; i++) { + /* Read value from register */ + regval = em28xx_read_reg(dev, dev->button_polling_addresses[i]); + if (regval < 0) + continue; + /* Check states of the buttons and act */ + j = 0; + while (dev->board.buttons[j].role >= 0 && + dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) { + struct em28xx_button *button = &dev->board.buttons[j]; + /* Check if button uses the current address */ + if (button->reg_r != dev->button_polling_addresses[i]) { + j++; + continue; + } + /* Determine if button is and was pressed last time */ + is_pressed = regval & button->mask; + was_pressed = dev->button_polling_last_values[i] + & button->mask; + if (button->inverted) { + is_pressed = !is_pressed; + was_pressed = !was_pressed; + } + /* Clear button state (if needed) */ + if (is_pressed && button->reg_clearing) + em28xx_write_reg(dev, button->reg_clearing, + (~regval & button->mask) + | (regval & ~button->mask)); + /* Handle button state */ + if (!is_pressed || was_pressed) { + j++; + continue; + } + switch (button->role) { + case EM28XX_BUTTON_SNAPSHOT: + /* Emulate the keypress */ + input_report_key(dev->sbutton_input_dev, + EM28XX_SNAPSHOT_KEY, 1); + /* Unpress the key */ + input_report_key(dev->sbutton_input_dev, + EM28XX_SNAPSHOT_KEY, 0); + break; + case EM28XX_BUTTON_ILLUMINATION: + led = em28xx_find_led(dev, + EM28XX_LED_ILLUMINATION); + /* Switch illumination LED on/off */ + if (led) + em28xx_toggle_reg_bits(dev, + led->gpio_reg, + led->gpio_mask); + break; + default: + WARN_ONCE(1, "BUG: unhandled button role."); + } + /* Next button */ + j++; + } + /* Save current value for comparison during the next polling */ + dev->button_polling_last_values[i] = regval; } - /* Schedule next poll */ - schedule_delayed_work(&dev->sbutton_query_work, - msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); + schedule_delayed_work(&dev->buttons_query_work, + msecs_to_jiffies(dev->button_polling_interval)); } -static void em28xx_register_snapshot_button(struct em28xx *dev) +static int em28xx_register_snapshot_button(struct em28xx *dev) { struct input_dev *input_dev; int err; em28xx_info("Registering snapshot button...\n"); input_dev = input_allocate_device(); - if (!input_dev) { - em28xx_errdev("input_allocate_device failed\n"); - return; - } + if (!input_dev) + return -ENOMEM; usb_make_path(dev->udev, dev->snapshot_button_path, sizeof(dev->snapshot_button_path)); strlcat(dev->snapshot_button_path, "/sbutton", sizeof(dev->snapshot_button_path)); - INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton); input_dev->name = "em28xx snapshot button"; input_dev->phys = dev->snapshot_button_path; @@ -535,25 +581,86 @@ static void em28xx_register_snapshot_button(struct em28xx *dev) if (err) { em28xx_errdev("input_register_device failed\n"); input_free_device(input_dev); - return; + return err; } dev->sbutton_input_dev = input_dev; - schedule_delayed_work(&dev->sbutton_query_work, - msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); - return; + return 0; +} +static void em28xx_init_buttons(struct em28xx *dev) +{ + u8 i = 0, j = 0; + bool addr_new = 0; + + dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL; + while (dev->board.buttons[i].role >= 0 && + dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) { + struct em28xx_button *button = &dev->board.buttons[i]; + /* Check if polling address is already on the list */ + addr_new = 1; + for (j = 0; j < dev->num_button_polling_addresses; j++) { + if (button->reg_r == dev->button_polling_addresses[j]) { + addr_new = 0; + break; + } + } + /* Check if max. number of polling addresses is exceeded */ + if (addr_new && dev->num_button_polling_addresses + >= EM28XX_NUM_BUTTON_ADDRESSES_MAX) { + WARN_ONCE(1, "BUG: maximum number of button polling addresses exceeded."); + goto next_button; + } + /* Button role specific checks and actions */ + if (button->role == EM28XX_BUTTON_SNAPSHOT) { + /* Register input device */ + if (em28xx_register_snapshot_button(dev) < 0) + goto next_button; + } else if (button->role == EM28XX_BUTTON_ILLUMINATION) { + /* Check sanity */ + if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) { + em28xx_errdev("BUG: illumination button defined, but no illumination LED.\n"); + goto next_button; + } + } + /* Add read address to list of polling addresses */ + if (addr_new) { + unsigned int index = dev->num_button_polling_addresses; + dev->button_polling_addresses[index] = button->reg_r; + dev->num_button_polling_addresses++; + } + /* Reduce polling interval if necessary */ + if (!button->reg_clearing) + dev->button_polling_interval = + EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL; +next_button: + /* Next button */ + i++; + } + + /* Start polling */ + if (dev->num_button_polling_addresses) { + memset(dev->button_polling_last_values, 0, + EM28XX_NUM_BUTTON_ADDRESSES_MAX); + INIT_DELAYED_WORK(&dev->buttons_query_work, + em28xx_query_buttons); + schedule_delayed_work(&dev->buttons_query_work, + msecs_to_jiffies(dev->button_polling_interval)); + } } -static void em28xx_deregister_snapshot_button(struct em28xx *dev) +static void em28xx_shutdown_buttons(struct em28xx *dev) { + /* Cancel polling */ + cancel_delayed_work_sync(&dev->buttons_query_work); + /* Clear polling addresses list */ + dev->num_button_polling_addresses = 0; + /* Deregister input devices */ if (dev->sbutton_input_dev != NULL) { em28xx_info("Deregistering snapshot button\n"); - cancel_delayed_work_sync(&dev->sbutton_query_work); input_unregister_device(dev->sbutton_input_dev); dev->sbutton_input_dev = NULL; } - return; } static int em28xx_ir_init(struct em28xx *dev) @@ -564,8 +671,15 @@ static int em28xx_ir_init(struct em28xx *dev) u64 rc_type; u16 i2c_rc_dev_addr = 0; - if (dev->board.has_snapshot_button) - em28xx_register_snapshot_button(dev); + if (dev->is_audio_only) { + /* Shouldn't initialize IR for this interface */ + return 0; + } + + kref_get(&dev->ref); + + if (dev->board.buttons) + em28xx_init_buttons(dev); if (dev->board.has_ir_i2c) { i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev); @@ -583,6 +697,8 @@ static int em28xx_ir_init(struct em28xx *dev) return 0; } + em28xx_info("Registering input extension\n"); + ir = kzalloc(sizeof(*ir), GFP_KERNEL); rc = rc_allocate_device(); if (!ir || !rc) @@ -611,7 +727,7 @@ static int em28xx_ir_init(struct em28xx *dev) case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: rc->map_name = RC_MAP_HAUPPAUGE; ir->get_key_i2c = em28xx_get_key_em_haup; - rc->allowed_protos = RC_BIT_RC5; + rc_set_allowed_protocols(rc, RC_BIT_RC5); break; case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE: rc->map_name = RC_MAP_WINFAST_USBII_DELUXE; @@ -627,15 +743,16 @@ static int em28xx_ir_init(struct em28xx *dev) switch (dev->chip_id) { case CHIP_ID_EM2860: case CHIP_ID_EM2883: - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; + rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC); ir->get_key = default_polling_getkey; break; case CHIP_ID_EM2884: case CHIP_ID_EM2874: case CHIP_ID_EM28174: + case CHIP_ID_EM28178: ir->get_key = em2874_polling_getkey; - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC | - RC_BIT_RC6_0; + rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC | + RC_BIT_RC6_0); break; default: err = -ENODEV; @@ -675,6 +792,8 @@ static int em28xx_ir_init(struct em28xx *dev) if (err) goto error; + em28xx_info("Input extension successfully initalized\n"); + return 0; error: @@ -688,11 +807,18 @@ static int em28xx_ir_fini(struct em28xx *dev) { struct em28xx_IR *ir = dev->ir; - em28xx_deregister_snapshot_button(dev); + if (dev->is_audio_only) { + /* Shouldn't initialize IR for this interface */ + return 0; + } + + em28xx_info("Closing input extension"); + + em28xx_shutdown_buttons(dev); /* skip detach on non attached boards */ if (!ir) - return 0; + goto ref_put; if (ir->rc) rc_unregister_device(ir->rc); @@ -700,6 +826,45 @@ static int em28xx_ir_fini(struct em28xx *dev) /* done */ kfree(ir); dev->ir = NULL; + +ref_put: + kref_put(&dev->ref, em28xx_free_device); + + return 0; +} + +static int em28xx_ir_suspend(struct em28xx *dev) +{ + struct em28xx_IR *ir = dev->ir; + + if (dev->is_audio_only) + return 0; + + em28xx_info("Suspending input extension"); + if (ir) + cancel_delayed_work_sync(&ir->work); + cancel_delayed_work_sync(&dev->buttons_query_work); + /* is canceling delayed work sufficient or does the rc event + kthread needs stopping? kthread is stopped in + ir_raw_event_unregister() */ + return 0; +} + +static int em28xx_ir_resume(struct em28xx *dev) +{ + struct em28xx_IR *ir = dev->ir; + + if (dev->is_audio_only) + return 0; + + em28xx_info("Resuming input extension"); + /* if suspend calls ir_raw_event_unregister(), the should call + ir_raw_event_register() */ + if (ir) + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); + if (dev->num_button_polling_addresses) + schedule_delayed_work(&dev->buttons_query_work, + msecs_to_jiffies(dev->button_polling_interval)); return 0; } @@ -708,6 +873,8 @@ static struct em28xx_ops rc_ops = { .name = "Em28xx Input Extension", .init = em28xx_ir_init, .fini = em28xx_ir_fini, + .suspend = em28xx_ir_suspend, + .resume = em28xx_ir_resume, }; static int __init em28xx_rc_register(void) @@ -721,8 +888,9 @@ static void __exit em28xx_rc_unregister(void) } MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); -MODULE_DESCRIPTION("Em28xx Input driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); +MODULE_DESCRIPTION(DRIVER_DESC " - input interface"); +MODULE_VERSION(EM28XX_VERSION); module_init(em28xx_rc_register); module_exit(em28xx_rc_unregister); diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 0e047784796..311fb349daf 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -25,10 +25,12 @@ #define EM28XX_R00_CHIPCFG 0x00 /* em28xx Chip Configuration 0x00 */ -#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80 -#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 -#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x30 -#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x20 +#define EM2860_CHIPCFG_VENDOR_AUDIO 0x80 +#define EM2860_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 +#define EM2820_CHIPCFG_I2S_3_SAMPRATES 0x30 +#define EM2860_CHIPCFG_I2S_5_SAMPRATES 0x30 +#define EM2820_CHIPCFG_I2S_1_SAMPRATE 0x20 +#define EM2860_CHIPCFG_I2S_3_SAMPRATES 0x20 #define EM28XX_CHIPCFG_AC97 0x10 #define EM28XX_CHIPCFG_AUDIOMASK 0x30 @@ -245,6 +247,7 @@ enum em28xx_chip_id { CHIP_ID_EM2874 = 65, CHIP_ID_EM2884 = 68, CHIP_ID_EM28174 = 113, + CHIP_ID_EM28178 = 114, }; /* diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h new file mode 100644 index 00000000000..432862c20bb --- /dev/null +++ b/drivers/media/usb/em28xx/em28xx-v4l.h @@ -0,0 +1,20 @@ +/* + em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB + video capture devices + + Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@samsung.com> + + 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 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + */ + + +int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count); +void em28xx_stop_vbi_streaming(struct vb2_queue *vq); +extern struct vb2_ops em28xx_vbi_qops; diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index 39f39c527c1..6d7f657f6f5 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -27,6 +27,7 @@ #include <linux/init.h> #include "em28xx.h" +#include "em28xx-v4l.h" static unsigned int vbibufs = 5; module_param(vbibufs, int, 0644); @@ -46,12 +47,13 @@ static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int sizes[], void *alloc_ctxs[]) { struct em28xx *dev = vb2_get_drv_priv(vq); + struct em28xx_v4l2 *v4l2 = dev->v4l2; unsigned long size; if (fmt) size = fmt->fmt.pix.sizeimage; else - size = dev->vbi_width * dev->vbi_height * 2; + size = v4l2->vbi_width * v4l2->vbi_height * 2; if (0 == *nbuffers) *nbuffers = 32; @@ -68,11 +70,12 @@ static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, static int vbi_buffer_prepare(struct vb2_buffer *vb) { - struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue); - struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); + struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue); + struct em28xx_v4l2 *v4l2 = dev->v4l2; + struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); unsigned long size; - size = dev->vbi_width * dev->vbi_height * 2; + size = v4l2->vbi_width * v4l2->vbi_height * 2; if (vb2_plane_size(vb, 0) < size) { printk(KERN_INFO "%s data will not fit into plane (%lu < %lu)\n", diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 9d103344f34..f6b49c98e2c 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -38,9 +38,11 @@ #include <linux/slab.h> #include "em28xx.h" +#include "em28xx-v4l.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> +#include <media/v4l2-clk.h> #include <media/msp3400.h> #include <media/tuner.h> @@ -49,19 +51,23 @@ "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ "Sascha Sommer <saschasommer@freenet.de>" -#define DRIVER_DESC "Empia em28xx based USB video device driver" +static unsigned int isoc_debug; +module_param(isoc_debug, int, 0644); +MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); + +static unsigned int disable_vbi; +module_param(disable_vbi, int, 0644); +MODULE_PARM_DESC(disable_vbi, "disable vbi support"); -#define EM28XX_VERSION "0.2.0" +static int alt; +module_param(alt, int, 0644); +MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ printk(KERN_INFO "%s %s :"fmt, \ dev->name, __func__ , ##arg); } while (0) -static unsigned int isoc_debug; -module_param(isoc_debug, int, 0644); -MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); - #define em28xx_isocdbg(fmt, arg...) \ do {\ if (isoc_debug) { \ @@ -71,7 +77,7 @@ do {\ } while (0) MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface"); MODULE_LICENSE("GPL"); MODULE_VERSION(EM28XX_VERSION); @@ -135,6 +141,287 @@ static struct em28xx_fmt format[] = { }, }; +/*FIXME: maxw should be dependent of alt mode */ +static inline unsigned int norm_maxw(struct em28xx *dev) +{ + struct em28xx_v4l2 *v4l2 = dev->v4l2; + + if (dev->board.is_webcam) + return v4l2->sensor_xres; + + if (dev->board.max_range_640_480) + return 640; + + return 720; +} + +static inline unsigned int norm_maxh(struct em28xx *dev) +{ + struct em28xx_v4l2 *v4l2 = dev->v4l2; + + if (dev->board.is_webcam) + return v4l2->sensor_yres; + + if (dev->board.max_range_640_480) + return 480; + + return (v4l2->norm & V4L2_STD_625_50) ? 576 : 480; +} + +static int em28xx_vbi_supported(struct em28xx *dev) +{ + /* Modprobe option to manually disable */ + if (disable_vbi == 1) + return 0; + + if (dev->board.is_webcam) + return 0; + + /* FIXME: check subdevices for VBI support */ + + if (dev->chip_id == CHIP_ID_EM2860 || + dev->chip_id == CHIP_ID_EM2883) + return 1; + + /* Version of em28xx that does not support VBI */ + return 0; +} + +/* + * em28xx_wake_i2c() + * configure i2c attached devices + */ +static void em28xx_wake_i2c(struct em28xx *dev) +{ + struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev; + v4l2_device_call_all(v4l2_dev, 0, core, reset, 0); + v4l2_device_call_all(v4l2_dev, 0, video, s_routing, + INPUT(dev->ctl_input)->vmux, 0, 0); + v4l2_device_call_all(v4l2_dev, 0, video, s_stream, 0); +} + +static int em28xx_colorlevels_set_default(struct em28xx *dev) +{ + em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT); + em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT); + em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT); + em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT); + em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT); + em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT); + + em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); + em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); + em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); + return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); +} + +static int em28xx_set_outfmt(struct em28xx *dev) +{ + int ret; + u8 fmt, vinctrl; + struct em28xx_v4l2 *v4l2 = dev->v4l2; + + fmt = v4l2->format->reg; + if (!dev->is_em25xx) + fmt |= 0x20; + /* + * NOTE: it's not clear if this is really needed ! + * The datasheets say bit 5 is a reserved bit and devices seem to work + * fine without it. But the Windows driver sets it for em2710/50+em28xx + * devices and we've always been setting it, too. + * + * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set, + * it's likely used for an additional (compressed ?) format there. + */ + ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt); + if (ret < 0) + return ret; + + ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, v4l2->vinmode); + if (ret < 0) + return ret; + + vinctrl = v4l2->vinctl; + if (em28xx_vbi_supported(dev) == 1) { + vinctrl |= EM28XX_VINCTRL_VBI_RAW; + em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); + em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, v4l2->vbi_width/4); + em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, v4l2->vbi_height); + if (v4l2->norm & V4L2_STD_525_60) { + /* NTSC */ + em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); + } else if (v4l2->norm & V4L2_STD_625_50) { + /* PAL */ + em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07); + } + } + + return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); +} + +static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, + u8 ymin, u8 ymax) +{ + em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n", + xmin, ymin, xmax, ymax); + + em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); + em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); + em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); + return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); +} + +static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, + u16 width, u16 height) +{ + u8 cwidth = width >> 2; + u8 cheight = height >> 2; + u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01); + /* NOTE: size limit: 2047x1023 = 2MPix */ + + em28xx_videodbg("capture area set to (%d,%d): %dx%d\n", + hstart, vstart, + ((overflow & 2) << 9 | cwidth << 2), + ((overflow & 1) << 10 | cheight << 2)); + + em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); + em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); + em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); + em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); + em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); + + /* FIXME: function/meaning of these registers ? */ + /* FIXME: align width+height to multiples of 4 ?! */ + if (dev->is_em25xx) { + em28xx_write_reg(dev, 0x34, width >> 4); + em28xx_write_reg(dev, 0x35, height >> 4); + } +} + +static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) +{ + u8 mode = 0x00; + /* the em2800 scaler only supports scaling down to 50% */ + + if (dev->board.is_em2800) { + mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); + } else { + u8 buf[2]; + + buf[0] = h; + buf[1] = h >> 8; + em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); + + buf[0] = v; + buf[1] = v >> 8; + em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); + /* it seems that both H and V scalers must be active + to work correctly */ + mode = (h || v) ? 0x30 : 0x00; + } + return em28xx_write_reg(dev, EM28XX_R26_COMPR, mode); +} + +/* FIXME: this only function read values from dev */ +static int em28xx_resolution_set(struct em28xx *dev) +{ + struct em28xx_v4l2 *v4l2 = dev->v4l2; + int width = norm_maxw(dev); + int height = norm_maxh(dev); + + /* Properly setup VBI */ + v4l2->vbi_width = 720; + if (v4l2->norm & V4L2_STD_525_60) + v4l2->vbi_height = 12; + else + v4l2->vbi_height = 18; + + em28xx_set_outfmt(dev); + + em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); + + /* If we don't set the start position to 2 in VBI mode, we end up + with line 20/21 being YUYV encoded instead of being in 8-bit + greyscale. The core of the issue is that line 21 (and line 23 for + PAL WSS) are inside of active video region, and as a result they + get the pixelformatting associated with that area. So by cropping + it out, we end up with the same format as the rest of the VBI + region */ + if (em28xx_vbi_supported(dev) == 1) + em28xx_capture_area_set(dev, 0, 2, width, height); + else + em28xx_capture_area_set(dev, 0, 0, width, height); + + return em28xx_scaler_set(dev, v4l2->hscale, v4l2->vscale); +} + +/* Set USB alternate setting for analog video */ +static int em28xx_set_alternate(struct em28xx *dev) +{ + struct em28xx_v4l2 *v4l2 = dev->v4l2; + int errCode; + int i; + unsigned int min_pkt_size = v4l2->width * 2 + 4; + + /* NOTE: for isoc transfers, only alt settings > 0 are allowed + bulk transfers seem to work only with alt=0 ! */ + dev->alt = 0; + if ((alt > 0) && (alt < dev->num_alt)) { + em28xx_videodbg("alternate forced to %d\n", dev->alt); + dev->alt = alt; + goto set_alt; + } + if (dev->analog_xfer_bulk) + goto set_alt; + + /* When image size is bigger than a certain value, + the frame size should be increased, otherwise, only + green screen will be received. + */ + if (v4l2->width * 2 * v4l2->height > 720 * 240 * 2) + min_pkt_size *= 2; + + for (i = 0; i < dev->num_alt; i++) { + /* stop when the selected alt setting offers enough bandwidth */ + if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) { + dev->alt = i; + break; + /* otherwise make sure that we end up with the maximum bandwidth + because the min_pkt_size equation might be wrong... + */ + } else if (dev->alt_max_pkt_size_isoc[i] > + dev->alt_max_pkt_size_isoc[dev->alt]) + dev->alt = i; + } + +set_alt: + /* NOTE: for bulk transfers, we need to call usb_set_interface() + * even if the previous settings were the same. Otherwise streaming + * fails with all urbs having status = -EOVERFLOW ! */ + if (dev->analog_xfer_bulk) { + dev->max_pkt_size = 512; /* USB 2.0 spec */ + dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; + } else { /* isoc */ + em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n", + min_pkt_size, dev->alt); + dev->max_pkt_size = + dev->alt_max_pkt_size_isoc[dev->alt]; + dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS; + } + em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n", + dev->alt, dev->max_pkt_size); + errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt); + if (errCode < 0) { + em28xx_errdev("cannot change alternate number to %d (error=%i)\n", + dev->alt, errCode); + return errCode; + } + return 0; +} + /* ------------------------------------------------------------------ DMA and thread functions ------------------------------------------------------------------*/ @@ -147,7 +434,7 @@ static inline void finish_buffer(struct em28xx *dev, { em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field); - buf->vb.v4l2_buf.sequence = dev->field_count++; + buf->vb.v4l2_buf.sequence = dev->v4l2->field_count++; buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); @@ -162,9 +449,10 @@ static void em28xx_copy_video(struct em28xx *dev, unsigned char *usb_buf, unsigned long len) { + struct em28xx_v4l2 *v4l2 = dev->v4l2; void *fieldstart, *startwrite, *startread; int linesdone, currlinedone, offset, lencopy, remain; - int bytesperline = dev->width << 1; + int bytesperline = v4l2->width << 1; if (buf->pos + len > buf->length) len = buf->length - buf->pos; @@ -172,7 +460,7 @@ static void em28xx_copy_video(struct em28xx *dev, startread = usb_buf; remain = len; - if (dev->progressive || buf->top_field) + if (v4l2->progressive || buf->top_field) fieldstart = buf->vb_buf; else /* interlaced mode, even nr. of lines */ fieldstart = buf->vb_buf + bytesperline; @@ -180,7 +468,7 @@ static void em28xx_copy_video(struct em28xx *dev, linesdone = buf->pos / bytesperline; currlinedone = buf->pos % bytesperline; - if (dev->progressive) + if (v4l2->progressive) offset = linesdone * bytesperline + currlinedone; else offset = linesdone * bytesperline * 2 + currlinedone; @@ -204,7 +492,7 @@ static void em28xx_copy_video(struct em28xx *dev, remain -= lencopy; while (remain > 0) { - if (dev->progressive) + if (v4l2->progressive) startwrite += lencopy; else startwrite += lencopy + bytesperline; @@ -250,7 +538,7 @@ static void em28xx_copy_vbi(struct em28xx *dev, offset = buf->pos; /* Make sure the bottom field populates the second half of the frame */ if (buf->top_field == 0) - offset += dev->vbi_width * dev->vbi_height; + offset += dev->v4l2->vbi_width * dev->v4l2->vbi_height; memcpy(buf->vb_buf + offset, usb_buf, len); buf->pos += len; @@ -326,13 +614,15 @@ finish_field_prepare_next(struct em28xx *dev, struct em28xx_buffer *buf, struct em28xx_dmaqueue *dma_q) { - if (dev->progressive || dev->top_field) { /* Brand new frame */ + struct em28xx_v4l2 *v4l2 = dev->v4l2; + + if (v4l2->progressive || v4l2->top_field) { /* Brand new frame */ if (buf != NULL) finish_buffer(dev, buf); buf = get_next_buf(dev, dma_q); } if (buf != NULL) { - buf->top_field = dev->top_field; + buf->top_field = v4l2->top_field; buf->pos = 0; } @@ -346,6 +636,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, unsigned char *data_pkt, unsigned int data_len) { + struct em28xx_v4l2 *v4l2 = dev->v4l2; struct em28xx_buffer *buf = dev->usb_ctl.vid_buf; struct em28xx_buffer *vbi_buf = dev->usb_ctl.vbi_buf; struct em28xx_dmaqueue *dma_q = &dev->vidq; @@ -365,17 +656,17 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, data_len -= 4; } else if (data_pkt[0] == 0x33 && data_pkt[1] == 0x95) { /* Field start (VBI mode) */ - dev->capture_type = 0; - dev->vbi_read = 0; + v4l2->capture_type = 0; + v4l2->vbi_read = 0; em28xx_isocdbg("VBI START HEADER !!!\n"); - dev->top_field = !(data_pkt[2] & 1); + v4l2->top_field = !(data_pkt[2] & 1); data_pkt += 4; data_len -= 4; } else if (data_pkt[0] == 0x22 && data_pkt[1] == 0x5a) { /* Field start (VBI disabled) */ - dev->capture_type = 2; + v4l2->capture_type = 2; em28xx_isocdbg("VIDEO START HEADER !!!\n"); - dev->top_field = !(data_pkt[2] & 1); + v4l2->top_field = !(data_pkt[2] & 1); data_pkt += 4; data_len -= 4; } @@ -383,37 +674,37 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, /* NOTE: With bulk transfers, intermediate data packets * have no continuation header */ - if (dev->capture_type == 0) { + if (v4l2->capture_type == 0) { vbi_buf = finish_field_prepare_next(dev, vbi_buf, vbi_dma_q); dev->usb_ctl.vbi_buf = vbi_buf; - dev->capture_type = 1; + v4l2->capture_type = 1; } - if (dev->capture_type == 1) { - int vbi_size = dev->vbi_width * dev->vbi_height; - int vbi_data_len = ((dev->vbi_read + data_len) > vbi_size) ? - (vbi_size - dev->vbi_read) : data_len; + if (v4l2->capture_type == 1) { + int vbi_size = v4l2->vbi_width * v4l2->vbi_height; + int vbi_data_len = ((v4l2->vbi_read + data_len) > vbi_size) ? + (vbi_size - v4l2->vbi_read) : data_len; /* Copy VBI data */ if (vbi_buf != NULL) em28xx_copy_vbi(dev, vbi_buf, data_pkt, vbi_data_len); - dev->vbi_read += vbi_data_len; + v4l2->vbi_read += vbi_data_len; if (vbi_data_len < data_len) { /* Continue with copying video data */ - dev->capture_type = 2; + v4l2->capture_type = 2; data_pkt += vbi_data_len; data_len -= vbi_data_len; } } - if (dev->capture_type == 2) { + if (v4l2->capture_type == 2) { buf = finish_field_prepare_next(dev, buf, dma_q); dev->usb_ctl.vid_buf = buf; - dev->capture_type = 3; + v4l2->capture_type = 3; } - if (dev->capture_type == 3 && buf != NULL && data_len > 0) + if (v4l2->capture_type == 3 && buf != NULL && data_len > 0) em28xx_copy_video(dev, buf, data_pkt, data_len); } @@ -426,6 +717,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, { struct em28xx_buffer *buf = dev->usb_ctl.vid_buf; struct em28xx_dmaqueue *dmaq = &dev->vidq; + struct em28xx_v4l2 *v4l2 = dev->v4l2; bool frame_end = 0; /* Check for header */ @@ -434,7 +726,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev, if (data_len >= 2) { /* em25xx header is only 2 bytes long */ if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) && ((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) { - dev->top_field = !(data_pkt[1] & + v4l2->top_field = !(data_pkt[1] & EM25XX_FRMDATAHDR_BYTE2_FRAME_ID); frame_end = data_pkt[1] & EM25XX_FRMDATAHDR_BYTE2_FRAME_END; @@ -584,12 +876,14 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int sizes[], void *alloc_ctxs[]) { struct em28xx *dev = vb2_get_drv_priv(vq); + struct em28xx_v4l2 *v4l2 = dev->v4l2; unsigned long size; if (fmt) size = fmt->fmt.pix.sizeimage; else - size = (dev->width * dev->height * dev->format->depth + 7) >> 3; + size = + (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3; if (size == 0) return -EINVAL; @@ -607,12 +901,13 @@ static int buffer_prepare(struct vb2_buffer *vb) { struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue); + struct em28xx_v4l2 *v4l2 = dev->v4l2; struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); unsigned long size; em28xx_videodbg("%s, field=%d\n", __func__, vb->v4l2_buf.field); - size = (dev->width * dev->height * dev->format->depth + 7) >> 3; + size = (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3; if (vb2_plane_size(vb, 0) < size) { em28xx_videodbg("%s data will not fit into plane (%lu < %lu)\n", @@ -627,6 +922,7 @@ buffer_prepare(struct vb2_buffer *vb) int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) { struct em28xx *dev = vb2_get_drv_priv(vq); + struct em28xx_v4l2 *v4l2 = dev->v4l2; struct v4l2_frequency f; int rc = 0; @@ -638,7 +934,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) if (rc) return rc; - if (dev->streaming_users++ == 0) { + if (v4l2->streaming_users == 0) { /* First active streaming user, so allocate all the URBs */ /* Allocate the USB bandwidth */ @@ -649,7 +945,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) */ em28xx_wake_i2c(dev); - dev->capture_type = -1; + v4l2->capture_type = -1; rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE, dev->analog_xfer_bulk, EM28XX_NUM_BUFS, @@ -657,7 +953,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) dev->packet_multiplier, em28xx_urb_data_copy); if (rc < 0) - goto fail; + return rc; /* * djh: it's not clear whether this code is still needed. I'm @@ -667,21 +963,24 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) /* Ask tuner to go to analog or radio mode */ memset(&f, 0, sizeof(f)); - f.frequency = dev->ctl_freq; + f.frequency = v4l2->frequency; if (vq->owner && vq->owner->vdev->vfl_type == VFL_TYPE_RADIO) f.type = V4L2_TUNER_RADIO; else f.type = V4L2_TUNER_ANALOG_TV; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); + v4l2_device_call_all(&v4l2->v4l2_dev, + 0, tuner, s_frequency, &f); } -fail: + v4l2->streaming_users++; + return rc; } -static int em28xx_stop_streaming(struct vb2_queue *vq) +static void em28xx_stop_streaming(struct vb2_queue *vq) { struct em28xx *dev = vb2_get_drv_priv(vq); + struct em28xx_v4l2 *v4l2 = dev->v4l2; struct em28xx_dmaqueue *vidq = &dev->vidq; unsigned long flags = 0; @@ -689,7 +988,7 @@ static int em28xx_stop_streaming(struct vb2_queue *vq) res_free(dev, vq->type); - if (dev->streaming_users-- == 1) { + if (v4l2->streaming_users-- == 1) { /* Last active user, so shutdown all the URBS */ em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE); } @@ -703,13 +1002,12 @@ static int em28xx_stop_streaming(struct vb2_queue *vq) } dev->usb_ctl.vid_buf = NULL; spin_unlock_irqrestore(&dev->slock, flags); - - return 0; } -int em28xx_stop_vbi_streaming(struct vb2_queue *vq) +void em28xx_stop_vbi_streaming(struct vb2_queue *vq) { struct em28xx *dev = vb2_get_drv_priv(vq); + struct em28xx_v4l2 *v4l2 = dev->v4l2; struct em28xx_dmaqueue *vbiq = &dev->vbiq; unsigned long flags = 0; @@ -717,7 +1015,7 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq) res_free(dev, vq->type); - if (dev->streaming_users-- == 1) { + if (v4l2->streaming_users-- == 1) { /* Last active user, so shutdown all the URBS */ em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE); } @@ -731,8 +1029,6 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq) } dev->usb_ctl.vbi_buf = NULL; spin_unlock_irqrestore(&dev->slock, flags); - - return 0; } static void @@ -762,16 +1058,17 @@ static struct vb2_ops em28xx_video_qops = { .wait_finish = vb2_ops_wait_finish, }; -int em28xx_vb2_setup(struct em28xx *dev) +static int em28xx_vb2_setup(struct em28xx *dev) { int rc; struct vb2_queue *q; + struct em28xx_v4l2 *v4l2 = dev->v4l2; /* Setup Videobuf2 for Video capture */ - q = &dev->vb_vidq; + q = &v4l2->vb_vidq; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->drv_priv = dev; q->buf_struct_size = sizeof(struct em28xx_buffer); q->ops = &em28xx_video_qops; @@ -782,10 +1079,10 @@ int em28xx_vb2_setup(struct em28xx *dev) return rc; /* Setup Videobuf2 for VBI capture */ - q = &dev->vb_vbiq; + q = &v4l2->vb_vbiq; q->type = V4L2_BUF_TYPE_VBI_CAPTURE; q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->drv_priv = dev; q->buf_struct_size = sizeof(struct em28xx_buffer); q->ops = &em28xx_vbi_qops; @@ -802,6 +1099,7 @@ int em28xx_vb2_setup(struct em28xx *dev) static void video_mux(struct em28xx *dev, int index) { + struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev; dev->ctl_input = index; dev->ctl_ainput = INPUT(index)->amux; dev->ctl_aoutput = INPUT(index)->aout; @@ -809,28 +1107,28 @@ static void video_mux(struct em28xx *dev, int index) if (!dev->ctl_aoutput) dev->ctl_aoutput = EM28XX_AOUT_MASTER; - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, + v4l2_device_call_all(v4l2_dev, 0, video, s_routing, INPUT(index)->vmux, 0, 0); if (dev->board.has_msp34xx) { if (dev->i2s_speed) { - v4l2_device_call_all(&dev->v4l2_dev, 0, audio, + v4l2_device_call_all(v4l2_dev, 0, audio, s_i2s_clock_freq, dev->i2s_speed); } /* Note: this is msp3400 specific */ - v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, + v4l2_device_call_all(v4l2_dev, 0, audio, s_routing, dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0); } if (dev->board.adecoder != EM28XX_NOADECODER) { - v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, + v4l2_device_call_all(v4l2_dev, 0, audio, s_routing, dev->ctl_ainput, dev->ctl_aoutput, 0); } em28xx_audio_analog_set(dev); } -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv) +static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv) { struct em28xx *dev = priv; @@ -854,7 +1152,9 @@ void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv) static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl) { - struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler); + struct em28xx_v4l2 *v4l2 = + container_of(ctrl->handler, struct em28xx_v4l2, ctrl_handler); + struct em28xx *dev = v4l2->dev; int ret = -EINVAL; switch (ctrl->id) { @@ -889,7 +1189,7 @@ static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl) return (ret < 0) ? ret : 0; } -const struct v4l2_ctrl_ops em28xx_ctrl_ops = { +static const struct v4l2_ctrl_ops em28xx_ctrl_ops = { .s_ctrl = em28xx_s_ctrl, }; @@ -929,19 +1229,20 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.pixelformat = dev->format->fourcc; - f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height; + f->fmt.pix.width = v4l2->width; + f->fmt.pix.height = v4l2->height; + f->fmt.pix.pixelformat = v4l2->format->fourcc; + f->fmt.pix.bytesperline = (v4l2->width * v4l2->format->depth + 7) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * v4l2->height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - if (dev->progressive) + if (v4l2->progressive) f->fmt.pix.field = V4L2_FIELD_NONE; else - f->fmt.pix.field = dev->interlaced ? + f->fmt.pix.field = v4l2->interlaced_fieldmode ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; return 0; } @@ -962,6 +1263,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; unsigned int width = f->fmt.pix.width; unsigned int height = f->fmt.pix.height; unsigned int maxw = norm_maxw(dev); @@ -1003,10 +1305,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - if (dev->progressive) + if (v4l2->progressive) f->fmt.pix.field = V4L2_FIELD_NONE; else - f->fmt.pix.field = dev->interlaced ? + f->fmt.pix.field = v4l2->interlaced_fieldmode ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; f->fmt.pix.priv = 0; @@ -1017,17 +1319,19 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, unsigned width, unsigned height) { struct em28xx_fmt *fmt; + struct em28xx_v4l2 *v4l2 = dev->v4l2; fmt = format_by_fourcc(fourcc); if (!fmt) return -EINVAL; - dev->format = fmt; - dev->width = width; - dev->height = height; + v4l2->format = fmt; + v4l2->width = width; + v4l2->height = height; /* set new image size */ - size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + size_to_scale(dev, v4l2->width, v4l2->height, + &v4l2->hscale, &v4l2->vscale); em28xx_resolution_set(dev); @@ -1038,8 +1342,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct em28xx *dev = video_drvdata(file); + struct em28xx_v4l2 *v4l2 = dev->v4l2; - if (dev->streaming_users > 0) + if (v4l2->streaming_users > 0) return -EBUSY; vidioc_try_fmt_vid_cap(file, priv, f); @@ -1053,7 +1358,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - *norm = dev->norm; + *norm = dev->v4l2->norm; return 0; } @@ -1063,24 +1368,25 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm); + v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, video, querystd, norm); return 0; } static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; struct v4l2_format f; - if (norm == dev->norm) + if (norm == v4l2->norm) return 0; - if (dev->streaming_users > 0) + if (v4l2->streaming_users > 0) return -EBUSY; - dev->norm = norm; + v4l2->norm = norm; /* Adjusts width/height, if needed */ f.fmt.pix.width = 720; @@ -1088,12 +1394,13 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) vidioc_try_fmt_vid_cap(file, priv, &f); /* set new image size */ - dev->width = f.fmt.pix.width; - dev->height = f.fmt.pix.height; - size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + v4l2->width = f.fmt.pix.width; + v4l2->height = f.fmt.pix.height; + size_to_scale(dev, v4l2->width, v4l2->height, + &v4l2->hscale, &v4l2->vscale); em28xx_resolution_set(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); + v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm); return 0; } @@ -1101,16 +1408,17 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *p) { - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; int rc = 0; p->parm.capture.readbuffers = EM28XX_MIN_BUF; if (dev->board.is_webcam) - rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, + rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0, video, g_parm, p); else - v4l2_video_std_frame_period(dev->norm, + v4l2_video_std_frame_period(v4l2->norm, &p->parm.capture.timeperframe); return rc; @@ -1123,7 +1431,8 @@ static int vidioc_s_parm(struct file *file, void *priv, struct em28xx *dev = fh->dev; p->parm.capture.readbuffers = EM28XX_MIN_BUF; - return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p); + return v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, + 0, video, s_parm, p); } static const char *iname[] = { @@ -1160,7 +1469,7 @@ static int vidioc_enum_input(struct file *file, void *priv, (EM28XX_VMUX_CABLE == INPUT(n)->type)) i->type = V4L2_INPUT_TYPE_TUNER; - i->std = dev->vdev->tvnorms; + i->std = dev->v4l2->vdev->tvnorms; /* webcams do not have the STD API */ if (dev->board.is_webcam) i->capabilities = 0; @@ -1262,7 +1571,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, strcpy(t->name, "Tuner"); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t); return 0; } @@ -1275,7 +1584,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); + v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t); return 0; } @@ -1284,27 +1593,29 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; if (0 != f->tuner) return -EINVAL; - f->frequency = dev->ctl_freq; + f->frequency = v4l2->frequency; return 0; } static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct v4l2_frequency new_freq = *f; - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; + struct v4l2_frequency new_freq = *f; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; if (0 != f->tuner) return -EINVAL; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq); - dev->ctl_freq = new_freq.frequency; + v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_frequency, f); + v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, g_frequency, &new_freq); + v4l2->frequency = new_freq.frequency; return 0; } @@ -1321,7 +1632,8 @@ static int vidioc_g_chip_info(struct file *file, void *priv, if (chip->match.addr == 1) strlcpy(chip->name, "ac97", sizeof(chip->name)); else - strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name)); + strlcpy(chip->name, + dev->v4l2->v4l2_dev.name, sizeof(chip->name)); return 0; } @@ -1367,7 +1679,7 @@ static int vidioc_g_register(struct file *file, void *priv, reg->val = ret; } else { __le16 val = 0; - ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, + ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, reg->reg, (char *)&val, 2); if (ret < 0) return ret; @@ -1402,9 +1714,10 @@ static int vidioc_s_register(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; + struct video_device *vdev = video_devdata(file); + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); @@ -1426,9 +1739,9 @@ static int vidioc_querycap(struct file *file, void *priv, cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - if (dev->vbi_dev) + if (v4l2->vbi_dev) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; - if (dev->radio_dev) + if (v4l2->radio_dev) cap->capabilities |= V4L2_CAP_RADIO; return 0; } @@ -1493,24 +1806,25 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *format) { - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; - format->fmt.vbi.samples_per_line = dev->vbi_width; + format->fmt.vbi.samples_per_line = v4l2->vbi_width; format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; format->fmt.vbi.offset = 0; format->fmt.vbi.flags = 0; format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; - format->fmt.vbi.count[0] = dev->vbi_height; - format->fmt.vbi.count[1] = dev->vbi_height; + format->fmt.vbi.count[0] = v4l2->vbi_height; + format->fmt.vbi.count[1] = v4l2->vbi_height; memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved)); /* Varies by video standard (NTSC, PAL, etc.) */ - if (dev->norm & V4L2_STD_525_60) { + if (v4l2->norm & V4L2_STD_525_60) { /* NTSC */ format->fmt.vbi.start[0] = 10; format->fmt.vbi.start[1] = 273; - } else if (dev->norm & V4L2_STD_625_50) { + } else if (v4l2->norm & V4L2_STD_625_50) { /* PAL */ format->fmt.vbi.start[0] = 6; format->fmt.vbi.start[1] = 318; @@ -1533,7 +1847,7 @@ static int radio_g_tuner(struct file *file, void *priv, strcpy(t->name, "Radio"); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t); return 0; } @@ -1546,12 +1860,27 @@ static int radio_s_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); + v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t); return 0; } /* + * em28xx_free_v4l2() - Free struct em28xx_v4l2 + * + * @ref: struct kref for struct em28xx_v4l2 + * + * Called when all users of struct em28xx_v4l2 are gone + */ +static void em28xx_free_v4l2(struct kref *ref) +{ + struct em28xx_v4l2 *v4l2 = container_of(ref, struct em28xx_v4l2, ref); + + v4l2->dev->v4l2 = NULL; + kfree(v4l2); +} + +/* * em28xx_v4l2_open() * inits the device and starts isoc transfer */ @@ -1559,6 +1888,7 @@ static int em28xx_v4l2_open(struct file *filp) { struct video_device *vdev = video_devdata(filp); struct em28xx *dev = video_drvdata(filp); + struct em28xx_v4l2 *v4l2 = dev->v4l2; enum v4l2_buf_type fh_type = 0; struct em28xx_fh *fh; @@ -1569,12 +1899,15 @@ static int em28xx_v4l2_open(struct file *filp) case VFL_TYPE_VBI: fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; break; + case VFL_TYPE_RADIO: + break; + default: + return -EINVAL; } em28xx_videodbg("open dev=%s type=%s users=%d\n", video_device_node_name(vdev), v4l2_type_names[fh_type], - dev->users); - + v4l2->users); if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; @@ -1589,23 +1922,27 @@ static int em28xx_v4l2_open(struct file *filp) fh->type = fh_type; filp->private_data = fh; - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + if (v4l2->users == 0) { em28xx_set_mode(dev, EM28XX_ANALOG_MODE); - em28xx_resolution_set(dev); - /* Needed, since GPIO might have disabled power of - some i2c device + if (vdev->vfl_type != VFL_TYPE_RADIO) + em28xx_resolution_set(dev); + + /* + * Needed, since GPIO might have disabled power + * of some i2c devices */ em28xx_wake_i2c(dev); - } if (vdev->vfl_type == VFL_TYPE_RADIO) { em28xx_videodbg("video_open: setting radio device\n"); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); + v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_radio); } - dev->users++; + kref_get(&dev->ref); + kref_get(&v4l2->ref); + v4l2->users++; mutex_unlock(&dev->lock); v4l2_fh_add(&fh->fh); @@ -1614,40 +1951,92 @@ static int em28xx_v4l2_open(struct file *filp) } /* - * em28xx_realease_resources() + * em28xx_v4l2_fini() * unregisters the v4l2,i2c and usb devices * called when the device gets disconected or at module unload */ -void em28xx_release_analog_resources(struct em28xx *dev) +static int em28xx_v4l2_fini(struct em28xx *dev) { + struct em28xx_v4l2 *v4l2 = dev->v4l2; - /*FIXME: I2C IR should be disconnected */ + if (dev->is_audio_only) { + /* Shouldn't initialize IR for this interface */ + return 0; + } - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; + if (!dev->has_video) { + /* This device does not support the v4l2 extension */ + return 0; + } + + if (v4l2 == NULL) + return 0; + + em28xx_info("Closing video extension"); + + mutex_lock(&dev->lock); + + v4l2_device_disconnect(&v4l2->v4l2_dev); + + em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE); + + if (v4l2->radio_dev) { + em28xx_info("V4L2 device %s deregistered\n", + video_device_node_name(v4l2->radio_dev)); + video_unregister_device(v4l2->radio_dev); } - if (dev->vbi_dev) { + if (v4l2->vbi_dev) { em28xx_info("V4L2 device %s deregistered\n", - video_device_node_name(dev->vbi_dev)); - if (video_is_registered(dev->vbi_dev)) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; + video_device_node_name(v4l2->vbi_dev)); + video_unregister_device(v4l2->vbi_dev); } - if (dev->vdev) { + if (v4l2->vdev) { em28xx_info("V4L2 device %s deregistered\n", - video_device_node_name(dev->vdev)); - if (video_is_registered(dev->vdev)) - video_unregister_device(dev->vdev); - else - video_device_release(dev->vdev); - dev->vdev = NULL; + video_device_node_name(v4l2->vdev)); + video_unregister_device(v4l2->vdev); + } + + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); + v4l2_device_unregister(&v4l2->v4l2_dev); + + if (v4l2->clk) { + v4l2_clk_unregister_fixed(v4l2->clk); + v4l2->clk = NULL; } + + kref_put(&v4l2->ref, em28xx_free_v4l2); + + mutex_unlock(&dev->lock); + + kref_put(&dev->ref, em28xx_free_device); + + return 0; +} + +static int em28xx_v4l2_suspend(struct em28xx *dev) +{ + if (dev->is_audio_only) + return 0; + + if (!dev->has_video) + return 0; + + em28xx_info("Suspending video extension"); + em28xx_stop_urbs(dev); + return 0; +} + +static int em28xx_v4l2_resume(struct em28xx *dev) +{ + if (dev->is_audio_only) + return 0; + + if (!dev->has_video) + return 0; + + em28xx_info("Resuming video extension"); + /* what do we do here */ + return 0; } /* @@ -1657,28 +2046,23 @@ void em28xx_release_analog_resources(struct em28xx *dev) */ static int em28xx_v4l2_close(struct file *filp) { - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + struct em28xx_v4l2 *v4l2 = dev->v4l2; int errCode; - em28xx_videodbg("users=%d\n", dev->users); + em28xx_videodbg("users=%d\n", v4l2->users); - mutex_lock(&dev->lock); vb2_fop_release(filp); + mutex_lock(&dev->lock); - if (dev->users == 1) { - /* the device is already disconnect, - free the remaining resources */ - if (dev->disconnected) { - em28xx_release_resources(dev); - kfree(dev->alt_max_pkt_size_isoc); - mutex_unlock(&dev->lock); - kfree(dev); - return 0; - } + if (v4l2->users == 1) { + /* No sense to try to write to the device */ + if (dev->disconnected) + goto exit; /* Save some power by putting tuner to sleep */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); + v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); /* do this before setting alternate! */ em28xx_set_mode(dev, EM28XX_SUSPEND); @@ -1693,8 +2077,12 @@ static int em28xx_v4l2_close(struct file *filp) } } - dev->users--; +exit: + v4l2->users--; + kref_put(&v4l2->ref, em28xx_free_v4l2); mutex_unlock(&dev->lock); + kref_put(&dev->ref, em28xx_free_device); + return 0; } @@ -1752,11 +2140,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { }; static const struct video_device em28xx_video_template = { - .fops = &em28xx_v4l_fops, - .release = video_device_release_empty, - .ioctl_ops = &video_ioctl_ops, - - .tvnorms = V4L2_STD_ALL, + .fops = &em28xx_v4l_fops, + .ioctl_ops = &video_ioctl_ops, + .release = video_device_release, + .tvnorms = V4L2_STD_ALL, }; static const struct v4l2_file_operations radio_fops = { @@ -1782,14 +2169,30 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { }; static struct video_device em28xx_radio_template = { - .name = "em28xx-radio", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, + .release = video_device_release, }; -/******************************** usb interface ******************************/ +/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ +static unsigned short saa711x_addrs[] = { + 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ + 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ + I2C_CLIENT_END }; + +static unsigned short tvp5150_addrs[] = { + 0xb8 >> 1, + 0xba >> 1, + I2C_CLIENT_END +}; +static unsigned short msp3400_addrs[] = { + 0x80 >> 1, + 0x88 >> 1, + I2C_CLIENT_END +}; +/******************************** usb interface ******************************/ static struct video_device *em28xx_vdev_init(struct em28xx *dev, const struct video_device *template, @@ -1802,7 +2205,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return NULL; *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; + vfd->v4l2_dev = &dev->v4l2->v4l2_dev; vfd->debug = video_debug; vfd->lock = &dev->lock; set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); @@ -1816,22 +2219,232 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return vfd; } -int em28xx_register_analog_devices(struct em28xx *dev) +static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr) +{ + struct em28xx_v4l2 *v4l2 = dev->v4l2; + struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; + struct tuner_setup tun_setup; + struct v4l2_frequency f; + + memset(&tun_setup, 0, sizeof(tun_setup)); + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.tuner_callback = em28xx_tuner_callback; + + if (dev->board.radio.type) { + tun_setup.type = dev->board.radio.type; + tun_setup.addr = dev->board.radio_addr; + + v4l2_device_call_all(v4l2_dev, + 0, tuner, s_type_addr, &tun_setup); + } + + if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) { + tun_setup.type = dev->tuner_type; + tun_setup.addr = tuner_addr; + + v4l2_device_call_all(v4l2_dev, + 0, tuner, s_type_addr, &tun_setup); + } + + if (dev->board.tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->board.tda9887_conf; + + v4l2_device_call_all(v4l2_dev, + 0, tuner, s_config, &tda9887_cfg); + } + + if (dev->tuner_type == TUNER_XC2028) { + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + + memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); + memset(&ctl, 0, sizeof(ctl)); + + em28xx_setup_xc3028(dev, &ctl); + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + v4l2_device_call_all(v4l2_dev, 0, tuner, s_config, &xc2028_cfg); + } + + /* configure tuner */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 9076; /* just a magic number */ + v4l2->frequency = f.frequency; + v4l2_device_call_all(v4l2_dev, 0, tuner, s_frequency, &f); +} + +static int em28xx_v4l2_init(struct em28xx *dev) { u8 val; int ret; unsigned int maxw; + struct v4l2_ctrl_handler *hdl; + struct em28xx_v4l2 *v4l2; + + if (dev->is_audio_only) { + /* Shouldn't initialize IR for this interface */ + return 0; + } + + if (!dev->has_video) { + /* This device does not support the v4l2 extension */ + return 0; + } + + em28xx_info("Registering V4L2 extension\n"); + + mutex_lock(&dev->lock); - printk(KERN_INFO "%s: v4l2 driver version %s\n", - dev->name, EM28XX_VERSION); + v4l2 = kzalloc(sizeof(struct em28xx_v4l2), GFP_KERNEL); + if (v4l2 == NULL) { + em28xx_info("em28xx_v4l: memory allocation failed\n"); + mutex_unlock(&dev->lock); + return -ENOMEM; + } + kref_init(&v4l2->ref); + v4l2->dev = dev; + dev->v4l2 = v4l2; + + ret = v4l2_device_register(&dev->udev->dev, &v4l2->v4l2_dev); + if (ret < 0) { + em28xx_errdev("Call to v4l2_device_register() failed!\n"); + goto err; + } + + hdl = &v4l2->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 8); + v4l2->v4l2_dev.ctrl_handler = hdl; + + if (dev->board.is_webcam) + v4l2->progressive = 1; + + /* + * Default format, used for tvp5150 or saa711x output formats + */ + v4l2->vinmode = 0x10; + v4l2->vinctl = EM28XX_VINCTRL_INTERLACED | + EM28XX_VINCTRL_CCIR656_ENABLE; + + /* request some modules */ + + if (dev->board.has_msp34xx) + v4l2_i2c_new_subdev(&v4l2->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + "msp3400", 0, msp3400_addrs); + + if (dev->board.decoder == EM28XX_SAA711X) + v4l2_i2c_new_subdev(&v4l2->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + "saa7115_auto", 0, saa711x_addrs); + + if (dev->board.decoder == EM28XX_TVP5150) + v4l2_i2c_new_subdev(&v4l2->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + "tvp5150", 0, tvp5150_addrs); + + if (dev->board.adecoder == EM28XX_TVAUDIO) + v4l2_i2c_new_subdev(&v4l2->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + "tvaudio", dev->board.tvaudio_addr, NULL); + + /* Initialize tuner and camera */ + + if (dev->board.tuner_type != TUNER_ABSENT) { + unsigned short tuner_addr = dev->board.tuner_addr; + int has_demod = (dev->board.tda9887_conf & TDA9887_PRESENT); + + if (dev->board.radio.type) + v4l2_i2c_new_subdev(&v4l2->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + "tuner", dev->board.radio_addr, NULL); + + if (has_demod) + v4l2_i2c_new_subdev(&v4l2->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + if (tuner_addr == 0) { + enum v4l2_i2c_tuner_type type = + has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; + struct v4l2_subdev *sd; + + sd = v4l2_i2c_new_subdev(&v4l2->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], "tuner", + 0, v4l2_i2c_tuner_addrs(type)); + + if (sd) + tuner_addr = v4l2_i2c_subdev_addr(sd); + } else { + v4l2_i2c_new_subdev(&v4l2->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + "tuner", tuner_addr, NULL); + } + + em28xx_tuner_setup(dev, tuner_addr); + } + + if (dev->em28xx_sensor != EM28XX_NOSENSOR) + em28xx_init_camera(dev); + + /* Configure audio */ + ret = em28xx_audio_setup(dev); + if (ret < 0) { + em28xx_errdev("%s: Error while setting audio - error [%d]!\n", + __func__, ret); + goto unregister_dev; + } + if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { + v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f); + } else { + /* install the em28xx notify callback */ + v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE), + em28xx_ctrl_notify, dev); + v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME), + em28xx_ctrl_notify, dev); + } + + /* wake i2c devices */ + em28xx_wake_i2c(dev); + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vbiq.active); + + if (dev->board.has_msp34xx) { + /* Send a reset to other chips via gpio */ + ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); + if (ret < 0) { + em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", + __func__, ret); + goto unregister_dev; + } + msleep(3); + + ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); + if (ret < 0) { + em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", + __func__, ret); + goto unregister_dev; + } + msleep(3); + } /* set default norm */ - dev->norm = V4L2_STD_PAL; - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); - dev->interlaced = EM28XX_INTERLACED_DEFAULT; + v4l2->norm = V4L2_STD_PAL; + v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm); + v4l2->interlaced_fieldmode = EM28XX_INTERLACED_DEFAULT; /* Analog specific initialization */ - dev->format = &format[0]; + v4l2->format = &format[0]; maxw = norm_maxw(dev); /* MaxPacketSize for em2800 is too small to capture at full resolution @@ -1854,132 +2467,178 @@ int em28xx_register_analog_devices(struct em28xx *dev) (EM28XX_XCLK_AUDIO_UNMUTE | val)); em28xx_set_outfmt(dev); - em28xx_compression_disable(dev); /* Add image controls */ /* NOTE: at this point, the subdevices are already registered, so bridge * controls are only added/enabled when no subdevice provides them */ - if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_CONTRAST)) - v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST)) + v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_CONTRAST, 0, 0x1f, 1, CONTRAST_DEFAULT); - if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BRIGHTNESS)) - v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS)) + v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_BRIGHTNESS, -0x80, 0x7f, 1, BRIGHTNESS_DEFAULT); - if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SATURATION)) - v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SATURATION)) + v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_SATURATION, 0, 0x1f, 1, SATURATION_DEFAULT); - if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BLUE_BALANCE)) - v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE)) + v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, BLUE_BALANCE_DEFAULT); - if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RED_BALANCE)) - v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE)) + v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, RED_BALANCE_DEFAULT); - if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SHARPNESS)) - v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS)) + v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops, V4L2_CID_SHARPNESS, 0, 0x0f, 1, SHARPNESS_DEFAULT); /* Reset image controls */ em28xx_colorlevels_set_default(dev); - v4l2_ctrl_handler_setup(&dev->ctrl_handler); - if (dev->ctrl_handler.error) - return dev->ctrl_handler.error; + v4l2_ctrl_handler_setup(hdl); + ret = hdl->error; + if (ret) + goto unregister_dev; /* allocate and fill video video_device struct */ - dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); - if (!dev->vdev) { + v4l2->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); + if (!v4l2->vdev) { em28xx_errdev("cannot allocate video_device.\n"); - return -ENODEV; + ret = -ENODEV; + goto unregister_dev; } - dev->vdev->queue = &dev->vb_vidq; - dev->vdev->queue->lock = &dev->vb_queue_lock; + mutex_init(&v4l2->vb_queue_lock); + mutex_init(&v4l2->vb_vbi_queue_lock); + v4l2->vdev->queue = &v4l2->vb_vidq; + v4l2->vdev->queue->lock = &v4l2->vb_queue_lock; /* disable inapplicable ioctls */ if (dev->board.is_webcam) { - v4l2_disable_ioctl(dev->vdev, VIDIOC_QUERYSTD); - v4l2_disable_ioctl(dev->vdev, VIDIOC_G_STD); - v4l2_disable_ioctl(dev->vdev, VIDIOC_S_STD); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_QUERYSTD); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_STD); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_STD); } else { - v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM); } if (dev->tuner_type == TUNER_ABSENT) { - v4l2_disable_ioctl(dev->vdev, VIDIOC_G_TUNER); - v4l2_disable_ioctl(dev->vdev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(dev->vdev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(dev->vdev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY); } if (!dev->audio_mode.has_audio) { - v4l2_disable_ioctl(dev->vdev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(dev->vdev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO); } /* register v4l2 video video_device */ - ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + ret = video_register_device(v4l2->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); if (ret) { em28xx_errdev("unable to register video device (error=%i).\n", ret); - return ret; + goto unregister_dev; } /* Allocate and fill vbi video_device struct */ if (em28xx_vbi_supported(dev) == 1) { - dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, + v4l2->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); - dev->vbi_dev->queue = &dev->vb_vbiq; - dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock; + v4l2->vbi_dev->queue = &v4l2->vb_vbiq; + v4l2->vbi_dev->queue->lock = &v4l2->vb_vbi_queue_lock; /* disable inapplicable ioctls */ - v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM); + v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM); if (dev->tuner_type == TUNER_ABSENT) { - v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_TUNER); - v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY); } if (!dev->audio_mode.has_audio) { - v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO); } /* register v4l2 vbi video_device */ - ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + ret = video_register_device(v4l2->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); if (ret < 0) { em28xx_errdev("unable to register vbi device\n"); - return ret; + goto unregister_dev; } } if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, - "radio"); - if (!dev->radio_dev) { + v4l2->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, + "radio"); + if (!v4l2->radio_dev) { em28xx_errdev("cannot allocate video_device.\n"); - return -ENODEV; + ret = -ENODEV; + goto unregister_dev; } - ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + ret = video_register_device(v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { em28xx_errdev("can't register radio device\n"); - return ret; + goto unregister_dev; } em28xx_info("Registered radio device as %s\n", - video_device_node_name(dev->radio_dev)); + video_device_node_name(v4l2->radio_dev)); } em28xx_info("V4L2 video device registered as %s\n", - video_device_node_name(dev->vdev)); + video_device_node_name(v4l2->vdev)); - if (dev->vbi_dev) + if (v4l2->vbi_dev) em28xx_info("V4L2 VBI device registered as %s\n", - video_device_node_name(dev->vbi_dev)); + video_device_node_name(v4l2->vbi_dev)); + + /* Save some power by putting tuner to sleep */ + v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); + /* initialize videobuf2 stuff */ + em28xx_vb2_setup(dev); + + em28xx_info("V4L2 extension successfully initialized\n"); + + kref_get(&dev->ref); + + mutex_unlock(&dev->lock); return 0; + +unregister_dev: + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); + v4l2_device_unregister(&v4l2->v4l2_dev); +err: + dev->v4l2 = NULL; + kref_put(&v4l2->ref, em28xx_free_v4l2); + mutex_unlock(&dev->lock); + return ret; } + +static struct em28xx_ops v4l2_ops = { + .id = EM28XX_V4L2, + .name = "Em28xx v4l2 Extension", + .init = em28xx_v4l2_init, + .fini = em28xx_v4l2_fini, + .suspend = em28xx_v4l2_suspend, + .resume = em28xx_v4l2_resume, +}; + +static int __init em28xx_video_register(void) +{ + return em28xx_register_extension(&v4l2_ops); +} + +static void __exit em28xx_video_unregister(void) +{ + em28xx_unregister_extension(&v4l2_ops); +} + +module_init(em28xx_video_register); +module_exit(em28xx_video_unregister); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 205e9038b1c..b4c837d77e5 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -26,9 +26,13 @@ #ifndef _EM28XX_H #define _EM28XX_H +#define EM28XX_VERSION "0.2.1" +#define DRIVER_DESC "Empia em28xx device driver" + #include <linux/workqueue.h> #include <linux/i2c.h> #include <linux/mutex.h> +#include <linux/kref.h> #include <linux/videodev2.h> #include <media/videobuf2-vmalloc.h> @@ -101,6 +105,7 @@ #define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56 #define EM2883_BOARD_KWORLD_HYBRID_330U 57 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 +#define EM2874_BOARD_PCTV_HD_MINI_80E 59 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 #define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61 #define EM2820_BOARD_GADMEI_TVR200 62 @@ -131,6 +136,11 @@ #define EM2884_BOARD_TERRATEC_HTC_USB_XS 87 #define EM2884_BOARD_C3TECH_DIGITAL_DUO 88 #define EM2874_BOARD_DELOCK_61959 89 +#define EM2874_BOARD_KWORLD_UB435Q_V2 90 +#define EM2765_BOARD_SPEEDLINK_VAD_LAPLACE 91 +#define EM28178_BOARD_PCTV_461E 92 +#define EM2874_BOARD_KWORLD_UB435Q_V3 93 +#define EM28178_BOARD_PCTV_292E 94 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -177,8 +187,27 @@ #define EM28XX_INTERLACED_DEFAULT 1 -/* time in msecs to wait for i2c writes to finish */ -#define EM2800_I2C_XFER_TIMEOUT 20 +/* + * Time in msecs to wait for i2c xfers to finish. + * 35ms is the maximum time a SMBUS device could wait when + * clock stretching is used. As the transfer itself will take + * some time to happen, set it to 35 ms. + * + * Ok, I2C doesn't specify any limit. So, eventually, we may need + * to increase this timeout. + * + * FIXME: this assumes that an I2C message is not longer than 1ms. + * This is actually dependent on the I2C bus speed, although most + * devices use a 100kHz clock. So, this assumtion is true most of + * the time. + */ +#define EM28XX_I2C_XFER_TIMEOUT 36 + +/* time in msecs to wait for AC97 xfers to finish */ +#define EM28XX_AC97_XFER_TIMEOUT 100 + +/* max. number of button state polling addresses */ +#define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5 enum em28xx_mode { EM28XX_SUSPEND, @@ -286,8 +315,7 @@ struct em28xx_audio_mode { unsigned int has_audio:1; - unsigned int i2s_3rates:1; - unsigned int i2s_5rates:1; + u8 i2s_samplerates; }; /* em28xx has two audio inputs: tuner and line in. @@ -373,6 +401,34 @@ enum em28xx_adecoder { EM28XX_TVAUDIO, }; +enum em28xx_led_role { + EM28XX_LED_ANALOG_CAPTURING = 0, + EM28XX_LED_DIGITAL_CAPTURING, + EM28XX_LED_ILLUMINATION, + EM28XX_NUM_LED_ROLES, /* must be the last */ +}; + +struct em28xx_led { + enum em28xx_led_role role; + u8 gpio_reg; + u8 gpio_mask; + bool inverted; +}; + +enum em28xx_button_role { + EM28XX_BUTTON_SNAPSHOT = 0, + EM28XX_BUTTON_ILLUMINATION, + EM28XX_NUM_BUTTON_ROLES, /* must be the last */ +}; + +struct em28xx_button { + enum em28xx_button_role role; + u8 reg_r; + u8 reg_clearing; + u8 mask; + bool inverted; +}; + struct em28xx_board { char *name; int vchannels; @@ -394,7 +450,6 @@ struct em28xx_board { unsigned int mts_firmware:1; unsigned int max_range_640_480:1; unsigned int has_dvb:1; - unsigned int has_snapshot_button:1; unsigned int is_webcam:1; unsigned int valid:1; unsigned int has_ir_i2c:1; @@ -409,6 +464,12 @@ struct em28xx_board { struct em28xx_input input[MAX_EM28XX_INPUT]; struct em28xx_input radio; char *ir_codes; + + /* LEDs that need to be controlled explicitly */ + struct em28xx_led *leds; + + /* Buttons */ + struct em28xx_button *buttons; }; struct em28xx_eeprom { @@ -425,24 +486,77 @@ struct em28xx_eeprom { u8 string_idx_table; }; -#define EM28XX_AUDIO_BUFS 5 -#define EM28XX_NUM_AUDIO_PACKETS 64 -#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ #define EM28XX_CAPTURE_STREAM_EN 1 /* em28xx extensions */ #define EM28XX_AUDIO 0x10 #define EM28XX_DVB 0x20 #define EM28XX_RC 0x30 +#define EM28XX_V4L2 0x40 /* em28xx resource types (used for res_get/res_lock etc */ #define EM28XX_RESOURCE_VIDEO 0x01 #define EM28XX_RESOURCE_VBI 0x02 +struct em28xx_v4l2 { + struct kref ref; + struct em28xx *dev; + + struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_clk *clk; + + struct video_device *vdev; + struct video_device *vbi_dev; + struct video_device *radio_dev; + + /* Videobuf2 */ + struct vb2_queue vb_vidq; + struct vb2_queue vb_vbiq; + struct mutex vb_queue_lock; + struct mutex vb_vbi_queue_lock; + + u8 vinmode; + u8 vinctl; + + /* Camera specific fields */ + int sensor_xres; + int sensor_yres; + int sensor_xtal; + + int users; /* user count for exclusive use */ + int streaming_users; /* number of actively streaming users */ + + u32 frequency; /* selected tuner frequency */ + + struct em28xx_fmt *format; + v4l2_std_id norm; /* selected tv norm */ + + /* Progressive/interlaced mode */ + bool progressive; + int interlaced_fieldmode; /* 1=interlaced fields, 0=just top fields */ + /* FIXME: everything else than interlaced_fieldmode=1 doesn't work */ + + /* Frame properties */ + int width; /* current frame width */ + int height; /* current frame height */ + unsigned hscale; /* horizontal scale factor (see datasheet) */ + unsigned vscale; /* vertical scale factor (see datasheet) */ + unsigned int vbi_width; + unsigned int vbi_height; /* lines per field */ + + /* Capture state tracking */ + int capture_type; + bool top_field; + int vbi_read; + unsigned int field_count; +}; + struct em28xx_audio { char name[50]; - char *transfer_buffer[EM28XX_AUDIO_BUFS]; - struct urb *urb[EM28XX_AUDIO_BUFS]; + unsigned num_urb; + char **transfer_buffer; + struct urb **urb; struct usb_device *udev; unsigned int capture_transfer_done; struct snd_pcm_substream *capture_pcm_substream; @@ -450,8 +564,14 @@ struct em28xx_audio { unsigned int hwptr_done_capture; struct snd_card *sndcard; + size_t period; + int users; spinlock_t slock; + + /* Controls streaming */ + struct work_struct wq_trigger; /* trigger to start/stop audio */ + atomic_t stream_started; /* stream should be running if true */ }; struct em28xx; @@ -476,46 +596,32 @@ struct em28xx_i2c_bus { enum em28xx_i2c_algo_type algo_type; }; - /* main device struct */ struct em28xx { + struct kref ref; + + /* Sub-module data */ + struct em28xx_v4l2 *v4l2; + struct em28xx_dvb *dvb; + struct em28xx_audio adev; + struct em28xx_IR *ir; + /* generic device properties */ char name[30]; /* name (including minor) of the device */ int model; /* index in the device_data struct */ int devno; /* marks the number of this device */ enum em28xx_chip_id chip_id; - unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ + unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ unsigned char disconnected:1; /* device has been diconnected */ - - int audio_ifnum; - - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler ctrl_handler; - struct em28xx_board board; - - /* Webcam specific fields */ - enum em28xx_sensor em28xx_sensor; - int sensor_xres, sensor_yres; - int sensor_xtal; - - /* Progressive (non-interlaced) mode */ - int progressive; - - /* Vinmode/Vinctl used at the driver */ - int vinmode, vinctl; - + unsigned int has_video:1; unsigned int has_audio_class:1; unsigned int has_alsa_audio:1; unsigned int is_audio_only:1; - /* Controls audio streaming */ - struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ - atomic_t stream_started; /* stream should be running if true */ - - struct em28xx_fmt *format; + struct em28xx_board board; - struct em28xx_IR *ir; + enum em28xx_sensor em28xx_sensor; /* camera specific */ /* Some older em28xx chips needs a waiting time after writing */ unsigned int wait_after_write; @@ -527,8 +633,6 @@ struct em28xx { struct em28xx_audio_mode audio_mode; int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - int tda9887_conf; /* i2c i/o */ struct i2c_adapter i2c_adap[NUM_I2C_BUSES]; @@ -541,52 +645,21 @@ struct em28xx { struct rt_mutex i2c_bus_lock; /* video for linux */ - int users; /* user count for exclusive use */ - int streaming_users; /* Number of actively streaming users */ - struct video_device *vdev; /* video for linux device struct */ - v4l2_std_id norm; /* selected tv norm */ - int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ unsigned int ctl_ainput;/* selected audio input */ unsigned int ctl_aoutput;/* selected audio output */ int mute; int volume; - /* frame properties */ - int width; /* current frame width */ - int height; /* current frame height */ - unsigned hscale; /* horizontal scale factor (see datasheet) */ - unsigned vscale; /* vertical scale factor (see datasheet) */ - int interlaced; /* 1=interlace fileds, 0=just top fileds */ - unsigned int video_bytesread; /* Number of bytes read */ unsigned long hash; /* eeprom hash - for boards with generic ID */ unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ - struct em28xx_audio adev; - - /* capture state tracking */ - int capture_type; - unsigned char top_field:1; - int vbi_read; - unsigned int vbi_width; - unsigned int vbi_height; /* lines per field */ - struct work_struct request_module_wk; /* locks */ struct mutex lock; struct mutex ctrl_urb_lock; /* protects urb_buf */ - /* spinlock_t queue_lock; */ - struct list_head inqueue, outqueue; - struct video_device *vbi_dev; - struct video_device *radio_dev; - - /* Videobuf2 */ - struct vb2_queue vb_vidq; - struct vb2_queue vb_vbiq; - struct mutex vb_queue_lock; - struct mutex vb_vbi_queue_lock; /* resources in use */ unsigned int resources; @@ -601,11 +674,9 @@ struct em28xx { struct em28xx_usb_ctl usb_ctl; spinlock_t slock; - unsigned int field_count; - unsigned int vbi_field_count; - /* usb transfer */ struct usb_device *udev; /* the usb device */ + u8 ifnum; /* number of the assigned usb interface */ u8 analog_ep_isoc; /* address of isoc endpoint for analog */ u8 analog_ep_bulk; /* address of bulk endpoint for analog */ u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */ @@ -637,20 +708,27 @@ struct em28xx { enum em28xx_mode mode; - /* Snapshot button */ + /* Button state polling */ + struct delayed_work buttons_query_work; + u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX]; + u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX]; + u8 num_button_polling_addresses; + u16 button_polling_interval; /* [ms] */ + /* Snapshot button input device */ char snapshot_button_path[30]; /* path of the input dev */ struct input_dev *sbutton_input_dev; - struct delayed_work sbutton_query_work; - - struct em28xx_dvb *dvb; }; +#define kref_to_dev(d) container_of(d, struct em28xx, ref) + struct em28xx_ops { struct list_head next; char *name; int id; int (*init)(struct em28xx *); int (*fini)(struct em28xx *); + int (*suspend)(struct em28xx *); + int (*resume)(struct em28xx *); }; /* Provided by em28xx-i2c.c */ @@ -670,6 +748,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, u8 bitmask); +int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask); int em28xx_read_ac97(struct em28xx *dev, u8 reg); int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); @@ -677,12 +756,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); int em28xx_audio_analog_set(struct em28xx *dev); int em28xx_audio_setup(struct em28xx *dev); -int em28xx_colorlevels_set_default(struct em28xx *dev); +const struct em28xx_led *em28xx_find_led(struct em28xx *dev, + enum em28xx_led_role role); int em28xx_capture_start(struct em28xx *dev, int start); -int em28xx_vbi_supported(struct em28xx *dev); -int em28xx_set_outfmt(struct em28xx *dev); -int em28xx_resolution_set(struct em28xx *dev); -int em28xx_set_alternate(struct em28xx *dev); int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, int num_bufs, int max_pkt_size, int packet_multiplier); int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, @@ -694,29 +770,19 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode); void em28xx_stop_urbs(struct em28xx *dev); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); -void em28xx_wake_i2c(struct em28xx *dev); int em28xx_register_extension(struct em28xx_ops *dev); void em28xx_unregister_extension(struct em28xx_ops *dev); void em28xx_init_extension(struct em28xx *dev); void em28xx_close_extension(struct em28xx *dev); - -/* Provided by em28xx-video.c */ -int em28xx_vb2_setup(struct em28xx *dev); -int em28xx_register_analog_devices(struct em28xx *dev); -void em28xx_release_analog_resources(struct em28xx *dev); -void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv); -int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count); -int em28xx_stop_vbi_streaming(struct vb2_queue *vq); -extern const struct v4l2_ctrl_ops em28xx_ctrl_ops; +int em28xx_suspend_extension(struct em28xx *dev); +int em28xx_resume_extension(struct em28xx *dev); /* Provided by em28xx-cards.c */ extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; int em28xx_tuner_callback(void *ptr, int component, int command, int arg); -void em28xx_release_resources(struct em28xx *dev); - -/* Provided by em28xx-vbi.c */ -extern struct vb2_ops em28xx_vbi_qops; +void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl); +void em28xx_free_device(struct kref *ref); /* Provided by em28xx-camera.c */ int em28xx_detect_sensor(struct em28xx *dev); @@ -738,32 +804,4 @@ int em28xx_init_camera(struct em28xx *dev); printk(KERN_WARNING "%s: "fmt,\ dev->name , ##arg); } while (0) -static inline int em28xx_compression_disable(struct em28xx *dev) -{ - /* side effect of disabling scaler and mixer */ - return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00); -} - -/*FIXME: maxw should be dependent of alt mode */ -static inline unsigned int norm_maxw(struct em28xx *dev) -{ - if (dev->board.is_webcam) - return dev->sensor_xres; - - if (dev->board.max_range_640_480) - return 640; - - return 720; -} - -static inline unsigned int norm_maxh(struct em28xx *dev) -{ - if (dev->board.is_webcam) - return dev->sensor_yres; - - if (dev->board.max_range_640_480) - return 480; - - return (dev->norm & V4L2_STD_625_50) ? 576 : 480; -} #endif diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index 4f0c6d566c8..eed10d78253 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -50,6 +50,16 @@ config USB_GSPCA_CPIA1 To compile this driver as a module, choose M here: the module will be called gspca_cpia1. +config USB_GSPCA_DTCS033 + tristate "DTCS033 (Scopium) USB Astro-Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for the Scopium camera + for planetary astrophotography. + + To compile this driver as a module, choose M here: the + module will be called gspca_dtcs033. + config USB_GSPCA_ETOMS tristate "Etoms USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/usb/gspca/Makefile b/drivers/media/usb/gspca/Makefile index 5855131ab8b..f46975e4c82 100644 --- a/drivers/media/usb/gspca/Makefile +++ b/drivers/media/usb/gspca/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_USB_GSPCA) += gspca_main.o obj-$(CONFIG_USB_GSPCA_BENQ) += gspca_benq.o obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o +obj-$(CONFIG_USB_GSPCA_DTCS033) += gspca_dtcs033.o obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o @@ -48,6 +49,7 @@ gspca_main-objs := gspca.o autogain_functions.o gspca_benq-objs := benq.o gspca_conex-objs := conex.o gspca_cpia1-objs := cpia1.o +gspca_dtcs033-objs := dtcs033.o gspca_etoms-objs := etoms.o gspca_finepix-objs := finepix.o gspca_jeilinj-objs := jeilinj.o diff --git a/drivers/media/usb/gspca/conex.c b/drivers/media/usb/gspca/conex.c index 38714df31ac..2e15c80d6e3 100644 --- a/drivers/media/usb/gspca/conex.c +++ b/drivers/media/usb/gspca/conex.c @@ -783,7 +783,8 @@ static int sd_start(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, QUALITY); diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index 064b53043b1..f23df4a9d8c 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -1553,9 +1553,9 @@ static int sd_start(struct gspca_dev *gspca_dev) sd->params.format.videoSize = VIDEOSIZE_CIF; sd->params.roi.colEnd = sd->params.roi.colStart + - (gspca_dev->width >> 3); + (gspca_dev->pixfmt.width >> 3); sd->params.roi.rowEnd = sd->params.roi.rowStart + - (gspca_dev->height >> 2); + (gspca_dev->pixfmt.height >> 2); /* And now set the camera to a known state */ ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode, diff --git a/drivers/media/usb/gspca/dtcs033.c b/drivers/media/usb/gspca/dtcs033.c new file mode 100644 index 00000000000..96bfd4e0f0e --- /dev/null +++ b/drivers/media/usb/gspca/dtcs033.c @@ -0,0 +1,441 @@ +/* + * Subdriver for Scopium astro-camera (DTCS033, 0547:7303) + * + * Copyright (C) 2014 Robert Butora (robert.butora.fi@gmail.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#define MODULE_NAME "dtcs033" +#include "gspca.h" + +MODULE_AUTHOR("Robert Butora <robert.butora.fi@gmail.com>"); +MODULE_DESCRIPTION("Scopium DTCS033 astro-cam USB Camera Driver"); +MODULE_LICENSE("GPL"); + +struct dtcs033_usb_requests { + u8 bRequestType; + u8 bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +}; + +/* send a usb request */ +static void reg_rw(struct gspca_dev *gspca_dev, + u8 bRequestType, u8 bRequest, + u16 wValue, u16 wIndex, u16 wLength) +{ + struct usb_device *udev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + + ret = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + bRequest, + bRequestType, + wValue, wIndex, + gspca_dev->usb_buf, wLength, 500); + + if (ret < 0) { + gspca_dev->usb_err = ret; + pr_err("usb_control_msg error %d\n", ret); + } + + return; +} +/* send several usb in/out requests */ +static int reg_reqs(struct gspca_dev *gspca_dev, + const struct dtcs033_usb_requests *preqs, int n_reqs) +{ + int i = 0; + const struct dtcs033_usb_requests *preq; + + while ((i < n_reqs) && (gspca_dev->usb_err >= 0)) { + + preq = &preqs[i]; + + reg_rw(gspca_dev, preq->bRequestType, preq->bRequest, + preq->wValue, preq->wIndex, preq->wLength); + + if (gspca_dev->usb_err < 0) { + + PERR("usb error request no: %d / %d\n", + i, n_reqs); + } else if (preq->bRequestType & USB_DIR_IN) { + + PDEBUG(D_STREAM, + "USB IN (%d) returned[%d] %02X %02X %02X %s", + i, + preq->wLength, + gspca_dev->usb_buf[0], + gspca_dev->usb_buf[1], + gspca_dev->usb_buf[2], + preq->wLength > 3 ? "...\n" : "\n"); + } + + i++; + } + return gspca_dev->usb_err; +} + +/* -- subdriver interface implementation -- */ + +#define DT_COLS (640) +static const struct v4l2_pix_format dtcs033_mode[] = { + /* raw Bayer patterned output */ + {DT_COLS, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, + .bytesperline = DT_COLS, + .sizeimage = DT_COLS*480, + .colorspace = V4L2_COLORSPACE_SRGB, + }, + /* this mode will demosaic the Bayer pattern */ + {DT_COLS, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, + .bytesperline = DT_COLS, + .sizeimage = DT_COLS*480, + .colorspace = V4L2_COLORSPACE_SRGB, + } +}; + +/* config called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + gspca_dev->cam.cam_mode = dtcs033_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(dtcs033_mode); + + gspca_dev->cam.bulk = 1; + gspca_dev->cam.bulk_nurbs = 1; + gspca_dev->cam.bulk_size = DT_COLS*512; + + return 0; +} + +/* init called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +/* start stop the camera */ +static int dtcs033_start(struct gspca_dev *gspca_dev); +static void dtcs033_stopN(struct gspca_dev *gspca_dev); + +/* intercept camera image data */ +static void dtcs033_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* packet data */ + int len) /* packet data length */ +{ + /* drop incomplete frames */ + if (len != DT_COLS*512) { + gspca_dev->last_packet_type = DISCARD_PACKET; + /* gspca.c: discard invalidates the whole frame. */ + return; + } + + /* forward complete frames */ + gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, INTER_PACKET, + data + 16*DT_COLS, + len - 32*DT_COLS); /* skip first & last 16 lines */ + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + + return; +} + +/* -- controls: exposure and gain -- */ + +static void dtcs033_setexposure(struct gspca_dev *gspca_dev, + s32 expo, s32 gain) +{ + /* gain [dB] encoding */ + u16 sGain = (u16)gain; + u16 gainVal = 224+(sGain-14)*(768-224)/(33-14); + u16 wIndex = 0x0100|(0x00FF&gainVal); + u16 wValue = (0xFF00&gainVal)>>8; + + /* exposure time [msec] encoding */ + u16 sXTime = (u16)expo; + u16 xtimeVal = (524*(150-(sXTime-1)))/150; + + const u8 bRequestType = + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + const u8 bRequest = 0x18; + + reg_rw(gspca_dev, + bRequestType, bRequest, wValue, wIndex, 0); + if (gspca_dev->usb_err < 0) + PERR("usb error in setexposure(gain) sequence.\n"); + + reg_rw(gspca_dev, + bRequestType, bRequest, (xtimeVal<<4), 0x6300, 0); + if (gspca_dev->usb_err < 0) + PERR("usb error in setexposure(time) sequence.\n"); +} + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev;/* !! must be the first item */ + + /* exposure & gain controls */ + struct { + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + }; +}; + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, + struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + dtcs033_setexposure(gspca_dev, + ctrl->val, sd->gain->val); + break; + case V4L2_CID_GAIN: + dtcs033_setexposure(gspca_dev, + sd->exposure->val, ctrl->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int dtcs033_init_controls(struct gspca_dev *gspca_dev) +{ + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + struct sd *sd = (struct sd *) gspca_dev; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 2); + /* min max step default */ + sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, + 1, 150, 1, 75);/* [msec] */ + sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, + 14, 33, 1, 24);/* [dB] */ + if (hdl->error) { + PERR("Could not initialize controls: %d\n", + hdl->error); + return hdl->error; + } + + v4l2_ctrl_cluster(2, &sd->exposure); + return 0; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = dtcs033_start, + .stopN = dtcs033_stopN, + .pkt_scan = dtcs033_pkt_scan, + .init_controls = dtcs033_init_controls, +}; + +/* -- module initialisation -- */ + +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x0547, 0x7303)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* device connect */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, + .reset_resume = gspca_resume, +#endif +}; +module_usb_driver(sd_driver); + + +/* --------------------------------------------------------- + USB requests to start/stop the camera [USB 2.0 spec Ch.9]. + + bRequestType : + 0x40 = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0xC0 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, +*/ +static const struct dtcs033_usb_requests dtcs033_start_reqs[] = { +/* -- bRequest,wValue,wIndex,wLength */ +{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 }, +{ 0x40, 0x01, 0x0000, 0x000F, 0x0000 }, +{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x7F00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1001, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0004, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x7F01, 0x0000 }, +{ 0x40, 0x18, 0x30E0, 0x0009, 0x0000 }, +{ 0x40, 0x18, 0x0500, 0x012C, 0x0000 }, +{ 0x40, 0x18, 0x0380, 0x0200, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x035C, 0x0000 }, +{ 0x40, 0x18, 0x05C0, 0x0438, 0x0000 }, +{ 0x40, 0x18, 0x0440, 0x0500, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0668, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0700, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0800, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0900, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0A00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0B00, 0x0000 }, +{ 0x40, 0x18, 0x30E0, 0x6009, 0x0000 }, +{ 0x40, 0x18, 0x0500, 0x612C, 0x0000 }, +{ 0x40, 0x18, 0x2090, 0x6274, 0x0000 }, +{ 0x40, 0x18, 0x05C0, 0x6338, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6400, 0x0000 }, +{ 0x40, 0x18, 0x05C0, 0x6538, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6600, 0x0000 }, +{ 0x40, 0x18, 0x0680, 0x6744, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6800, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6900, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6A00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6B00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6C00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6D00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6E00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x808C, 0x0000 }, +{ 0x40, 0x18, 0x0010, 0x8101, 0x0000 }, +{ 0x40, 0x18, 0x30E0, 0x8200, 0x0000 }, +{ 0x40, 0x18, 0x0810, 0x832C, 0x0000 }, +{ 0x40, 0x18, 0x0680, 0x842B, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x8500, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x8600, 0x0000 }, +{ 0x40, 0x18, 0x0280, 0x8715, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x880C, 0x0000 }, +{ 0x40, 0x18, 0x0010, 0x8901, 0x0000 }, +{ 0x40, 0x18, 0x30E0, 0x8A00, 0x0000 }, +{ 0x40, 0x18, 0x0810, 0x8B2C, 0x0000 }, +{ 0x40, 0x18, 0x0680, 0x8C2B, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x8D00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x8E00, 0x0000 }, +{ 0x40, 0x18, 0x0280, 0x8F15, 0x0000 }, +{ 0x40, 0x18, 0x0010, 0xD040, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0xD100, 0x0000 }, +{ 0x40, 0x18, 0x00B0, 0xD20A, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0xD300, 0x0000 }, +{ 0x40, 0x18, 0x30E2, 0xD40D, 0x0000 }, +{ 0x40, 0x18, 0x0001, 0xD5C0, 0x0000 }, +{ 0x40, 0x18, 0x00A0, 0xD60A, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0xD700, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x7F00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 }, +{ 0x40, 0x18, 0x0001, 0x01FF, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0200, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0304, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1101, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1201, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1300, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1400, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1601, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1800, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1900, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1A00, 0x0000 }, +{ 0x40, 0x18, 0x2000, 0x1B00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1C00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x2100, 0x0000 }, +{ 0x40, 0x18, 0x00C0, 0x228E, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x3001, 0x0000 }, +{ 0x40, 0x18, 0x0010, 0x3101, 0x0000 }, +{ 0x40, 0x18, 0x0008, 0x3301, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x3400, 0x0000 }, +{ 0x40, 0x18, 0x0012, 0x3549, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x3620, 0x0000 }, +{ 0x40, 0x18, 0x0001, 0x3700, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x4000, 0x0000 }, +{ 0x40, 0x18, 0xFFFF, 0x41FF, 0x0000 }, +{ 0x40, 0x18, 0xFFFF, 0x42FF, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x500F, 0x0000 }, +{ 0x40, 0x18, 0x2272, 0x5108, 0x0000 }, +{ 0x40, 0x18, 0x2272, 0x5208, 0x0000 }, +{ 0x40, 0x18, 0xFFFF, 0x53FF, 0x0000 }, +{ 0x40, 0x18, 0xFFFF, 0x54FF, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6000, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6102, 0x0000 }, +{ 0x40, 0x18, 0x0010, 0x6214, 0x0000 }, +{ 0x40, 0x18, 0x0C80, 0x6300, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6401, 0x0000 }, +{ 0x40, 0x18, 0x0680, 0x6551, 0x0000 }, +{ 0x40, 0x18, 0xFFFF, 0x66FF, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6702, 0x0000 }, +{ 0x40, 0x18, 0x0010, 0x6800, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6900, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6A00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6B00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6C00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6D01, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6E00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x6F00, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x7000, 0x0000 }, +{ 0x40, 0x18, 0x0001, 0x7118, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x2001, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1101, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1301, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1300, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 }, +{ 0xC0, 0x11, 0x0000, 0x24C0, 0x0003 }, +{ 0x40, 0x18, 0x0000, 0x3000, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x3620, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 }, +{ 0x40, 0x18, 0x0010, 0x6300, 0x0000 }, +{ 0x40, 0x18, 0x0002, 0x01F0, 0x0000 }, +{ 0x40, 0x01, 0x0003, 0x000F, 0x0000 } +}; + +static const struct dtcs033_usb_requests dtcs033_stop_reqs[] = { +/* -- bRequest,wValue,wIndex,wLength */ +{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 }, +{ 0x40, 0x01, 0x0000, 0x000F, 0x0000 }, +{ 0x40, 0x18, 0x0000, 0x0003, 0x0000 } +}; +static int dtcs033_start(struct gspca_dev *gspca_dev) +{ + return reg_reqs(gspca_dev, dtcs033_start_reqs, + ARRAY_SIZE(dtcs033_start_reqs)); +} + +static void dtcs033_stopN(struct gspca_dev *gspca_dev) +{ + reg_reqs(gspca_dev, dtcs033_stop_reqs, + ARRAY_SIZE(dtcs033_stop_reqs)); + return; +} diff --git a/drivers/media/usb/gspca/gl860/gl860-mi2020.c b/drivers/media/usb/gspca/gl860/gl860-mi2020.c index 2edda6b7d65..a785828d4b9 100644 --- a/drivers/media/usb/gspca/gl860/gl860-mi2020.c +++ b/drivers/media/usb/gspca/gl860/gl860-mi2020.c @@ -35,32 +35,34 @@ static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03}; static u8 dat_hvflip6[] = {0x90, 0x00, 0x06}; static struct idxdata tbl_middle_hvflip_low[] = { - {0x33, "\x90\x00\x06"}, - {6, "\xff\xff\xff"}, - {0x33, "\x90\x00\x06"}, - {6, "\xff\xff\xff"}, - {0x33, "\x90\x00\x06"}, - {6, "\xff\xff\xff"}, - {0x33, "\x90\x00\x06"}, - {6, "\xff\xff\xff"}, + {0x33, {0x90, 0x00, 0x06}}, + {6, {0xff, 0xff, 0xff}}, + {0x33, {0x90, 0x00, 0x06}}, + {6, {0xff, 0xff, 0xff}}, + {0x33, {0x90, 0x00, 0x06}}, + {6, {0xff, 0xff, 0xff}}, + {0x33, {0x90, 0x00, 0x06}}, + {6, {0xff, 0xff, 0xff}}, }; static struct idxdata tbl_middle_hvflip_big[] = { - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, - {102, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"}, - {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}}, + {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}}, + {102, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}}, + {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}}, + {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}}, }; static struct idxdata tbl_end_hvflip[] = { - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, - {6, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, - {6, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, - {6, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, + {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}}, + {6, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}}, + {6, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}}, + {6, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}}, }; static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 }; @@ -82,197 +84,267 @@ static struct validx tbl_common_0B[] = { }; static struct idxdata tbl_common_3B[] = { - {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"}, - {2, "\xff\xff\xff"}, - {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"}, - {6, "\xff\xff\xff"}, /* 12 */ - {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, - {2, "\xff\xff\xff"}, /* - */ - {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\x22\x23"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0f"}, {0x33, "\x90\x00\x0d"}, - {0x33, "\x8c\xa2\x10"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x11"}, - {0x33, "\x90\x00\x07"}, {0x33, "\xf4\x03\x1d"}, {0x35, "\xa2\x00\xe2"}, - {0x33, "\x8c\xab\x05"}, {0x33, "\x90\x00\x01"}, {0x32, "\x6e\x00\x86"}, - {0x32, "\x70\x0f\xaa"}, {0x32, "\x72\x0f\xe4"}, {0x33, "\x8c\xa3\x4a"}, - {0x33, "\x90\x00\x5a"}, {0x33, "\x8c\xa3\x4b"}, {0x33, "\x90\x00\xa6"}, - {0x33, "\x8c\xa3\x61"}, {0x33, "\x90\x00\xc8"}, {0x33, "\x8c\xa3\x62"}, - {0x33, "\x90\x00\xe1"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, - {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, - {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, - {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, - {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, - {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, - {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, - {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, - {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, - {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, - {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, - {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, - {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, - {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, - {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, - {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, - {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, - {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, - {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, - {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, - {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, - {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, - {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, - {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, - {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, - {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, - {0x33, "\x78\x00\x00"}, - {2, "\xff\xff\xff"}, - {0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"}, - {0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"}, - {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"}, - {0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"}, - {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"}, - {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"}, - {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"}, - {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"}, - {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"}, - {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"}, - {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, - {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"}, - {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"}, - {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"}, - {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"}, - {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"}, - {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"}, - {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"}, - {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"}, - {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"}, - {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"}, - {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"}, - {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"}, - {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"}, - {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"}, - {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"}, - {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"}, - {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"}, - {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, - {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"}, - {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"}, - {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"}, - {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"}, - {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"}, - {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"}, - {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"}, - {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"}, - {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"}, - {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"}, - {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"}, - {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {3, "\xff\xff\xff"}, + {0x33, {0x86, 0x25, 0x01}}, {0x33, {0x86, 0x25, 0x00}}, + {2, {0xff, 0xff, 0xff}}, + {0x30, {0x1a, 0x0a, 0xcc}}, {0x32, {0x02, 0x00, 0x08}}, + {0x33, {0xf4, 0x03, 0x1d}}, + {6, {0xff, 0xff, 0xff}}, /* 12 */ + {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}}, + {0x34, {0x1e, 0x8f, 0x09}}, + {2, {0xff, 0xff, 0xff}}, /* - */ + {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}}, + {0x33, {0x8c, 0x22, 0x23}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0xa2, 0x0f}}, {0x33, {0x90, 0x00, 0x0d}}, + {0x33, {0x8c, 0xa2, 0x10}}, {0x33, {0x90, 0x00, 0x0b}}, + {0x33, {0x8c, 0xa2, 0x11}}, {0x33, {0x90, 0x00, 0x07}}, + {0x33, {0xf4, 0x03, 0x1d}}, {0x35, {0xa2, 0x00, 0xe2}}, + {0x33, {0x8c, 0xab, 0x05}}, {0x33, {0x90, 0x00, 0x01}}, + {0x32, {0x6e, 0x00, 0x86}}, {0x32, {0x70, 0x0f, 0xaa}}, + {0x32, {0x72, 0x0f, 0xe4}}, {0x33, {0x8c, 0xa3, 0x4a}}, + {0x33, {0x90, 0x00, 0x5a}}, {0x33, {0x8c, 0xa3, 0x4b}}, + {0x33, {0x90, 0x00, 0xa6}}, {0x33, {0x8c, 0xa3, 0x61}}, + {0x33, {0x90, 0x00, 0xc8}}, {0x33, {0x8c, 0xa3, 0x62}}, + {0x33, {0x90, 0x00, 0xe1}}, {0x34, {0xce, 0x01, 0xa8}}, + {0x34, {0xd0, 0x66, 0x33}}, {0x34, {0xd2, 0x31, 0x9a}}, + {0x34, {0xd4, 0x94, 0x63}}, {0x34, {0xd6, 0x4b, 0x25}}, + {0x34, {0xd8, 0x26, 0x70}}, {0x34, {0xda, 0x72, 0x4c}}, + {0x34, {0xdc, 0xff, 0x04}}, {0x34, {0xde, 0x01, 0x5b}}, + {0x34, {0xe6, 0x01, 0x13}}, {0x34, {0xee, 0x0b, 0xf0}}, + {0x34, {0xf6, 0x0b, 0xa4}}, {0x35, {0x00, 0xf6, 0xe7}}, + {0x35, {0x08, 0x0d, 0xfd}}, {0x35, {0x10, 0x25, 0x63}}, + {0x35, {0x18, 0x35, 0x6c}}, {0x35, {0x20, 0x42, 0x7e}}, + {0x35, {0x28, 0x19, 0x44}}, {0x35, {0x30, 0x39, 0xd4}}, + {0x35, {0x38, 0xf5, 0xa8}}, {0x35, {0x4c, 0x07, 0x90}}, + {0x35, {0x44, 0x07, 0xb8}}, {0x35, {0x5c, 0x06, 0x88}}, + {0x35, {0x54, 0x07, 0xff}}, {0x34, {0xe0, 0x01, 0x52}}, + {0x34, {0xe8, 0x00, 0xcc}}, {0x34, {0xf0, 0x0d, 0x83}}, + {0x34, {0xf8, 0x0c, 0xb3}}, {0x35, {0x02, 0xfe, 0xba}}, + {0x35, {0x0a, 0x04, 0xe0}}, {0x35, {0x12, 0x1c, 0x63}}, + {0x35, {0x1a, 0x2b, 0x5a}}, {0x35, {0x22, 0x32, 0x5e}}, + {0x35, {0x2a, 0x0d, 0x28}}, {0x35, {0x32, 0x2c, 0x02}}, + {0x35, {0x3a, 0xf4, 0xfa}}, {0x35, {0x4e, 0x07, 0xef}}, + {0x35, {0x46, 0x07, 0x88}}, {0x35, {0x5e, 0x07, 0xc1}}, + {0x35, {0x56, 0x04, 0x64}}, {0x34, {0xe4, 0x01, 0x15}}, + {0x34, {0xec, 0x00, 0x82}}, {0x34, {0xf4, 0x0c, 0xce}}, + {0x34, {0xfc, 0x0c, 0xba}}, {0x35, {0x06, 0x1f, 0x02}}, + {0x35, {0x0e, 0x02, 0xe3}}, {0x35, {0x16, 0x1a, 0x50}}, + {0x35, {0x1e, 0x24, 0x39}}, {0x35, {0x26, 0x23, 0x4c}}, + {0x35, {0x2e, 0xf9, 0x1b}}, {0x35, {0x36, 0x23, 0x19}}, + {0x35, {0x3e, 0x12, 0x08}}, {0x35, {0x52, 0x07, 0x22}}, + {0x35, {0x4a, 0x03, 0xd3}}, {0x35, {0x62, 0x06, 0x54}}, + {0x35, {0x5a, 0x04, 0x5d}}, {0x34, {0xe2, 0x01, 0x04}}, + {0x34, {0xea, 0x00, 0xa0}}, {0x34, {0xf2, 0x0c, 0xbc}}, + {0x34, {0xfa, 0x0c, 0x5b}}, {0x35, {0x04, 0x17, 0xf2}}, + {0x35, {0x0c, 0x02, 0x08}}, {0x35, {0x14, 0x28, 0x43}}, + {0x35, {0x1c, 0x28, 0x62}}, {0x35, {0x24, 0x2b, 0x60}}, + {0x35, {0x2c, 0x07, 0x33}}, {0x35, {0x34, 0x1f, 0xb0}}, + {0x35, {0x3c, 0xed, 0xcd}}, {0x35, {0x50, 0x00, 0x06}}, + {0x35, {0x48, 0x07, 0xff}}, {0x35, {0x60, 0x05, 0x89}}, + {0x35, {0x58, 0x07, 0xff}}, {0x35, {0x40, 0x00, 0xa0}}, + {0x35, {0x42, 0x00, 0x00}}, {0x32, {0x10, 0x01, 0xfc}}, + {0x33, {0x8c, 0xa1, 0x18}}, {0x33, {0x90, 0x00, 0x3c}}, + {0x33, {0x78, 0x00, 0x00}}, + {2, {0xff, 0xff, 0xff}}, + {0x35, {0xb8, 0x1f, 0x20}}, {0x33, {0x8c, 0xa2, 0x06}}, + {0x33, {0x90, 0x00, 0x10}}, {0x33, {0x8c, 0xa2, 0x07}}, + {0x33, {0x90, 0x00, 0x08}}, {0x33, {0x8c, 0xa2, 0x42}}, + {0x33, {0x90, 0x00, 0x0b}}, {0x33, {0x8c, 0xa2, 0x4a}}, + {0x33, {0x90, 0x00, 0x8c}}, {0x35, {0xba, 0xfa, 0x08}}, + {0x33, {0x8c, 0xa2, 0x02}}, {0x33, {0x90, 0x00, 0x22}}, + {0x33, {0x8c, 0xa2, 0x03}}, {0x33, {0x90, 0x00, 0xbb}}, + {0x33, {0x8c, 0xa4, 0x04}}, {0x33, {0x90, 0x00, 0x80}}, + {0x33, {0x8c, 0xa7, 0x9d}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0xa7, 0x9e}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0xa2, 0x0c}}, {0x33, {0x90, 0x00, 0x17}}, + {0x33, {0x8c, 0xa2, 0x15}}, {0x33, {0x90, 0x00, 0x04}}, + {0x33, {0x8c, 0xa2, 0x14}}, {0x33, {0x90, 0x00, 0x20}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x17}}, {0x33, {0x90, 0x21, 0x11}}, + {0x33, {0x8c, 0x27, 0x1b}}, {0x33, {0x90, 0x02, 0x4f}}, + {0x33, {0x8c, 0x27, 0x25}}, {0x33, {0x90, 0x06, 0x0f}}, + {0x33, {0x8c, 0x27, 0x39}}, {0x33, {0x90, 0x21, 0x11}}, + {0x33, {0x8c, 0x27, 0x3d}}, {0x33, {0x90, 0x01, 0x20}}, + {0x33, {0x8c, 0x27, 0x47}}, {0x33, {0x90, 0x09, 0x4c}}, + {0x33, {0x8c, 0x27, 0x03}}, {0x33, {0x90, 0x02, 0x84}}, + {0x33, {0x8c, 0x27, 0x05}}, {0x33, {0x90, 0x01, 0xe2}}, + {0x33, {0x8c, 0x27, 0x07}}, {0x33, {0x90, 0x06, 0x40}}, + {0x33, {0x8c, 0x27, 0x09}}, {0x33, {0x90, 0x04, 0xb0}}, + {0x33, {0x8c, 0x27, 0x0d}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x0f}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x11}}, {0x33, {0x90, 0x04, 0xbd}}, + {0x33, {0x8c, 0x27, 0x13}}, {0x33, {0x90, 0x06, 0x4d}}, + {0x33, {0x8c, 0x27, 0x15}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x17}}, {0x33, {0x90, 0x21, 0x11}}, + {0x33, {0x8c, 0x27, 0x19}}, {0x33, {0x90, 0x04, 0x6c}}, + {0x33, {0x8c, 0x27, 0x1b}}, {0x33, {0x90, 0x02, 0x4f}}, + {0x33, {0x8c, 0x27, 0x1d}}, {0x33, {0x90, 0x01, 0x02}}, + {0x33, {0x8c, 0x27, 0x1f}}, {0x33, {0x90, 0x02, 0x79}}, + {0x33, {0x8c, 0x27, 0x21}}, {0x33, {0x90, 0x01, 0x55}}, + {0x33, {0x8c, 0x27, 0x23}}, {0x33, {0x90, 0x02, 0x85}}, + {0x33, {0x8c, 0x27, 0x25}}, {0x33, {0x90, 0x06, 0x0f}}, + {0x33, {0x8c, 0x27, 0x27}}, {0x33, {0x90, 0x20, 0x20}}, + {0x33, {0x8c, 0x27, 0x29}}, {0x33, {0x90, 0x20, 0x20}}, + {0x33, {0x8c, 0x27, 0x2b}}, {0x33, {0x90, 0x10, 0x20}}, + {0x33, {0x8c, 0x27, 0x2d}}, {0x33, {0x90, 0x20, 0x07}}, + {0x33, {0x8c, 0x27, 0x2f}}, {0x33, {0x90, 0x00, 0x04}}, + {0x33, {0x8c, 0x27, 0x31}}, {0x33, {0x90, 0x00, 0x04}}, + {0x33, {0x8c, 0x27, 0x33}}, {0x33, {0x90, 0x04, 0xbb}}, + {0x33, {0x8c, 0x27, 0x35}}, {0x33, {0x90, 0x06, 0x4b}}, + {0x33, {0x8c, 0x27, 0x37}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x39}}, {0x33, {0x90, 0x21, 0x11}}, + {0x33, {0x8c, 0x27, 0x3b}}, {0x33, {0x90, 0x00, 0x24}}, + {0x33, {0x8c, 0x27, 0x3d}}, {0x33, {0x90, 0x01, 0x20}}, + {0x33, {0x8c, 0x27, 0x41}}, {0x33, {0x90, 0x01, 0x69}}, + {0x33, {0x8c, 0x27, 0x45}}, {0x33, {0x90, 0x04, 0xed}}, + {0x33, {0x8c, 0x27, 0x47}}, {0x33, {0x90, 0x09, 0x4c}}, + {0x33, {0x8c, 0x27, 0x51}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x53}}, {0x33, {0x90, 0x03, 0x20}}, + {0x33, {0x8c, 0x27, 0x55}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x57}}, {0x33, {0x90, 0x02, 0x58}}, + {0x33, {0x8c, 0x27, 0x5f}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x61}}, {0x33, {0x90, 0x06, 0x40}}, + {0x33, {0x8c, 0x27, 0x63}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x65}}, {0x33, {0x90, 0x04, 0xb0}}, + {0x33, {0x8c, 0x22, 0x2e}}, {0x33, {0x90, 0x00, 0xa1}}, + {0x33, {0x8c, 0xa4, 0x08}}, {0x33, {0x90, 0x00, 0x1f}}, + {0x33, {0x8c, 0xa4, 0x09}}, {0x33, {0x90, 0x00, 0x21}}, + {0x33, {0x8c, 0xa4, 0x0a}}, {0x33, {0x90, 0x00, 0x25}}, + {0x33, {0x8c, 0xa4, 0x0b}}, {0x33, {0x90, 0x00, 0x27}}, + {0x33, {0x8c, 0x24, 0x11}}, {0x33, {0x90, 0x00, 0xa1}}, + {0x33, {0x8c, 0x24, 0x13}}, {0x33, {0x90, 0x00, 0xc1}}, + {0x33, {0x8c, 0x24, 0x15}}, {0x33, {0x90, 0x00, 0x6a}}, + {0x33, {0x8c, 0x24, 0x17}}, {0x33, {0x90, 0x00, 0x80}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}}, + {3, {0xff, 0xff, 0xff}}, }; static struct idxdata tbl_init_post_alt_low1[] = { - {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"}, - {0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"}, - {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"}, - {0x33, "\x90\x00\x1d"}, {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x20"}, - {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\x81"}, {0x33, "\x8c\x24\x13"}, - {0x33, "\x90\x00\x9b"}, + {0x33, {0x8c, 0x27, 0x15}}, {0x33, {0x90, 0x00, 0x25}}, + {0x33, {0x8c, 0x22, 0x2e}}, {0x33, {0x90, 0x00, 0x81}}, + {0x33, {0x8c, 0xa4, 0x08}}, {0x33, {0x90, 0x00, 0x17}}, + {0x33, {0x8c, 0xa4, 0x09}}, {0x33, {0x90, 0x00, 0x1a}}, + {0x33, {0x8c, 0xa4, 0x0a}}, {0x33, {0x90, 0x00, 0x1d}}, + {0x33, {0x8c, 0xa4, 0x0b}}, {0x33, {0x90, 0x00, 0x20}}, + {0x33, {0x8c, 0x24, 0x11}}, {0x33, {0x90, 0x00, 0x81}}, + {0x33, {0x8c, 0x24, 0x13}}, {0x33, {0x90, 0x00, 0x9b}}, }; static struct idxdata tbl_init_post_alt_low2[] = { - {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"}, - {0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {2, "\xff\xff\xff"}, + {0x33, {0x8c, 0x27, 0x03}}, {0x33, {0x90, 0x03, 0x24}}, + {0x33, {0x8c, 0x27, 0x05}}, {0x33, {0x90, 0x02, 0x58}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}}, + {2, {0xff, 0xff, 0xff}}, }; static struct idxdata tbl_init_post_alt_low3[] = { - {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, - {2, "\xff\xff\xff"}, - {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, - {0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, - {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x95"}, {0x33, "\x90\x01\x00"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, + {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}}, + {0x34, {0x1e, 0x8f, 0x09}}, + {2, {0xff, 0xff, 0xff}}, + {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}}, + {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}}, + {0x33, {0x2e, 0x01, 0x00}}, {0x34, {0x04, 0x00, 0x2a}}, + {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0x27, 0x95}}, {0x33, {0x90, 0x01, 0x00}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}}, + {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}}, + {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}}, }; static struct idxdata tbl_init_post_alt_big[] = { - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {2, "\xff\xff\xff"}, - {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"}, - {2, "\xff\xff\xff"}, - {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"}, - {2, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {0x33, "\x8c\xa1\x20"}, - {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x30"}, {0x33, "\x90\x00\x03"}, - {0x33, "\x8c\xa1\x31"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x32"}, - {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"}, - {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"}, - {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, - {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"}, - {51, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"}, - {51, "\xff\xff\xff"}, - {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"}, - {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"}, - {51, "\xff\xff\xff"}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}}, + {2, {0xff, 0xff, 0xff}}, + {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}}, + {0x34, {0x1e, 0x8f, 0x09}}, + {2, {0xff, 0xff, 0xff}}, + {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}}, + {0x33, {0x8c, 0xa1, 0x03}}, + {0x33, {0x90, 0x00, 0x05}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}}, + {2, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}}, + {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}}, + {0x33, {0x8c, 0xa1, 0x30}}, {0x33, {0x90, 0x00, 0x03}}, + {0x33, {0x8c, 0xa1, 0x31}}, {0x33, {0x90, 0x00, 0x02}}, + {0x33, {0x8c, 0xa1, 0x32}}, {0x33, {0x90, 0x00, 0x03}}, + {0x33, {0x8c, 0xa1, 0x34}}, {0x33, {0x90, 0x00, 0x03}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}}, + {0x33, {0x2e, 0x01, 0x00}}, {0x34, {0x04, 0x00, 0x2a}}, + {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}}, + {0x33, {0x8c, 0x27, 0x97}}, {0x33, {0x90, 0x01, 0x00}}, + {51, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}}, + {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}}, + {51, {0xff, 0xff, 0xff}}, + {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}}, + {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}}, + {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}}, + {51, {0xff, 0xff, 0xff}}, }; static struct idxdata tbl_init_post_alt_3B[] = { - {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"}, - {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"}, - {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"}, - {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"}, - {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"}, - {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"}, - {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"}, - {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"}, - {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"}, - {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"}, - {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"}, - {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"}, - {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"}, - {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"}, - {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"}, - {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"}, - {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"}, - {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"}, - {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"}, - {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"}, - {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"}, - {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"}, - {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"}, - {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"}, - {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"}, - {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"}, + {0x32, {0x10, 0x01, 0xf8}}, {0x34, {0xce, 0x01, 0xa8}}, + {0x34, {0xd0, 0x66, 0x33}}, {0x34, {0xd2, 0x31, 0x9a}}, + {0x34, {0xd4, 0x94, 0x63}}, {0x34, {0xd6, 0x4b, 0x25}}, + {0x34, {0xd8, 0x26, 0x70}}, {0x34, {0xda, 0x72, 0x4c}}, + {0x34, {0xdc, 0xff, 0x04}}, {0x34, {0xde, 0x01, 0x5b}}, + {0x34, {0xe6, 0x01, 0x13}}, {0x34, {0xee, 0x0b, 0xf0}}, + {0x34, {0xf6, 0x0b, 0xa4}}, {0x35, {0x00, 0xf6, 0xe7}}, + {0x35, {0x08, 0x0d, 0xfd}}, {0x35, {0x10, 0x25, 0x63}}, + {0x35, {0x18, 0x35, 0x6c}}, {0x35, {0x20, 0x42, 0x7e}}, + {0x35, {0x28, 0x19, 0x44}}, {0x35, {0x30, 0x39, 0xd4}}, + {0x35, {0x38, 0xf5, 0xa8}}, {0x35, {0x4c, 0x07, 0x90}}, + {0x35, {0x44, 0x07, 0xb8}}, {0x35, {0x5c, 0x06, 0x88}}, + {0x35, {0x54, 0x07, 0xff}}, {0x34, {0xe0, 0x01, 0x52}}, + {0x34, {0xe8, 0x00, 0xcc}}, {0x34, {0xf0, 0x0d, 0x83}}, + {0x34, {0xf8, 0x0c, 0xb3}}, {0x35, {0x02, 0xfe, 0xba}}, + {0x35, {0x0a, 0x04, 0xe0}}, {0x35, {0x12, 0x1c, 0x63}}, + {0x35, {0x1a, 0x2b, 0x5a}}, {0x35, {0x22, 0x32, 0x5e}}, + {0x35, {0x2a, 0x0d, 0x28}}, {0x35, {0x32, 0x2c, 0x02}}, + {0x35, {0x3a, 0xf4, 0xfa}}, {0x35, {0x4e, 0x07, 0xef}}, + {0x35, {0x46, 0x07, 0x88}}, {0x35, {0x5e, 0x07, 0xc1}}, + {0x35, {0x56, 0x04, 0x64}}, {0x34, {0xe4, 0x01, 0x15}}, + {0x34, {0xec, 0x00, 0x82}}, {0x34, {0xf4, 0x0c, 0xce}}, + {0x34, {0xfc, 0x0c, 0xba}}, {0x35, {0x06, 0x1f, 0x02}}, + {0x35, {0x0e, 0x02, 0xe3}}, {0x35, {0x16, 0x1a, 0x50}}, + {0x35, {0x1e, 0x24, 0x39}}, {0x35, {0x26, 0x23, 0x4c}}, + {0x35, {0x2e, 0xf9, 0x1b}}, {0x35, {0x36, 0x23, 0x19}}, + {0x35, {0x3e, 0x12, 0x08}}, {0x35, {0x52, 0x07, 0x22}}, + {0x35, {0x4a, 0x03, 0xd3}}, {0x35, {0x62, 0x06, 0x54}}, + {0x35, {0x5a, 0x04, 0x5d}}, {0x34, {0xe2, 0x01, 0x04}}, + {0x34, {0xea, 0x00, 0xa0}}, {0x34, {0xf2, 0x0c, 0xbc}}, + {0x34, {0xfa, 0x0c, 0x5b}}, {0x35, {0x04, 0x17, 0xf2}}, + {0x35, {0x0c, 0x02, 0x08}}, {0x35, {0x14, 0x28, 0x43}}, + {0x35, {0x1c, 0x28, 0x62}}, {0x35, {0x24, 0x2b, 0x60}}, + {0x35, {0x2c, 0x07, 0x33}}, {0x35, {0x34, 0x1f, 0xb0}}, + {0x35, {0x3c, 0xed, 0xcd}}, {0x35, {0x50, 0x00, 0x06}}, + {0x35, {0x48, 0x07, 0xff}}, {0x35, {0x60, 0x05, 0x89}}, + {0x35, {0x58, 0x07, 0xff}}, {0x35, {0x40, 0x00, 0xa0}}, + {0x35, {0x42, 0x00, 0x00}}, {0x32, {0x10, 0x01, 0xfc}}, + {0x33, {0x8c, 0xa1, 0x18}}, {0x33, {0x90, 0x00, 0x3c}}, }; static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81"; diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c index cb1e64ca59c..cea8d7f51c3 100644 --- a/drivers/media/usb/gspca/gl860/gl860.c +++ b/drivers/media/usb/gspca/gl860/gl860.c @@ -438,7 +438,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, s32 nToSkip = sd->swapRB * (gspca_dev->cam.cam_mode[mode].bytesperline + 1); - /* Test only against 0202h, so endianess does not matter */ + /* Test only against 0202h, so endianness does not matter */ switch (*(s16 *) data) { case 0x0202: /* End of frame, start a new one */ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 048507b27bb..f3a7ace0fac 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -504,8 +504,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file, unsigned int frsz; int i; - i = gspca_dev->curr_mode; - frsz = gspca_dev->cam.cam_mode[i].sizeimage; + frsz = gspca_dev->pixfmt.sizeimage; PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz); frsz = PAGE_ALIGN(frsz); if (count >= GSPCA_MAX_FRAMES) @@ -627,16 +626,14 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, static u32 which_bandwidth(struct gspca_dev *gspca_dev) { u32 bandwidth; - int i; /* get the (max) image size */ - i = gspca_dev->curr_mode; - bandwidth = gspca_dev->cam.cam_mode[i].sizeimage; + bandwidth = gspca_dev->pixfmt.sizeimage; /* if the image is compressed, estimate its mean size */ if (!gspca_dev->cam.needs_full_bandwidth && - bandwidth < gspca_dev->cam.cam_mode[i].width * - gspca_dev->cam.cam_mode[i].height) + bandwidth < gspca_dev->pixfmt.width * + gspca_dev->pixfmt.height) bandwidth = bandwidth * 3 / 8; /* 0.375 */ /* estimate the frame rate */ @@ -650,7 +647,7 @@ static u32 which_bandwidth(struct gspca_dev *gspca_dev) /* don't hope more than 15 fps with USB 1.1 and * image resolution >= 640x480 */ - if (gspca_dev->width >= 640 + if (gspca_dev->pixfmt.width >= 640 && gspca_dev->dev->speed == USB_SPEED_FULL) bandwidth *= 15; /* 15 fps */ else @@ -982,9 +979,7 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev) i = gspca_dev->cam.nmodes - 1; /* take the highest mode */ gspca_dev->curr_mode = i; - gspca_dev->width = gspca_dev->cam.cam_mode[i].width; - gspca_dev->height = gspca_dev->cam.cam_mode[i].height; - gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat; + gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i]; /* does nothing if ctrl_handler == NULL */ v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler); @@ -1105,10 +1100,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - int mode; - mode = gspca_dev->curr_mode; - fmt->fmt.pix = gspca_dev->cam.cam_mode[mode]; + fmt->fmt.pix = gspca_dev->pixfmt; /* some drivers use priv internally, zero it before giving it to userspace */ fmt->fmt.pix.priv = 0; @@ -1140,6 +1133,12 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, mode = mode2; } fmt->fmt.pix = gspca_dev->cam.cam_mode[mode]; + if (gspca_dev->sd_desc->try_fmt) { + /* pass original resolution to subdriver try_fmt */ + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + gspca_dev->sd_desc->try_fmt(gspca_dev, fmt); + } /* some drivers use priv internally, zero it before giving it to userspace */ fmt->fmt.pix.priv = 0; @@ -1178,19 +1177,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, goto out; } - if (ret == gspca_dev->curr_mode) { - ret = 0; - goto out; /* same mode */ - } - if (gspca_dev->streaming) { ret = -EBUSY; goto out; } - gspca_dev->width = fmt->fmt.pix.width; - gspca_dev->height = fmt->fmt.pix.height; - gspca_dev->pixfmt = fmt->fmt.pix.pixelformat; gspca_dev->curr_mode = ret; + if (gspca_dev->sd_desc->try_fmt) + /* subdriver try_fmt can modify format parameters */ + gspca_dev->pixfmt = fmt->fmt.pix; + else + gspca_dev->pixfmt = gspca_dev->cam.cam_mode[ret]; ret = 0; out: @@ -1205,6 +1201,9 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, int i; __u32 index = 0; + if (gspca_dev->sd_desc->enum_framesizes) + return gspca_dev->sd_desc->enum_framesizes(gspca_dev, fsize); + for (i = 0; i < gspca_dev->cam.nmodes; i++) { if (fsize->pixel_format != gspca_dev->cam.cam_mode[i].pixelformat) @@ -1471,8 +1470,9 @@ static int vidioc_streamon(struct file *file, void *priv, if (ret < 0) goto out; } - PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK", gspca_dev->pixfmt, - gspca_dev->width, gspca_dev->height); + PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK", + gspca_dev->pixfmt.pixelformat, + gspca_dev->pixfmt.width, gspca_dev->pixfmt.height); ret = 0; out: mutex_unlock(&gspca_dev->queue_lock); diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index ac0b11f46f5..300642dc1a1 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -88,6 +88,10 @@ typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev, typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev, u8 *data, int len); +typedef void (*cam_format_op) (struct gspca_dev *gspca_dev, + struct v4l2_format *fmt); +typedef int (*cam_frmsize_op) (struct gspca_dev *gspca_dev, + struct v4l2_frmsizeenum *fsize); /* subdriver description */ struct sd_desc { @@ -109,6 +113,8 @@ struct sd_desc { cam_set_jpg_op set_jcomp; cam_streamparm_op get_streamparm; cam_streamparm_op set_streamparm; + cam_format_op try_fmt; + cam_frmsize_op enum_framesizes; #ifdef CONFIG_VIDEO_ADV_DEBUG cam_set_reg_op set_register; cam_get_reg_op get_register; @@ -183,9 +189,7 @@ struct gspca_dev { __u8 streaming; /* protected by both mutexes (*) */ __u8 curr_mode; /* current camera mode */ - __u32 pixfmt; /* current mode parameters */ - __u16 width; - __u16 height; + struct v4l2_pix_format pixfmt; /* current mode parameters */ __u32 sequence; /* frame sequence number */ wait_queue_head_t wq; /* wait queue */ diff --git a/drivers/media/usb/gspca/jeilinj.c b/drivers/media/usb/gspca/jeilinj.c index 8da3dde3838..19736e237b3 100644 --- a/drivers/media/usb/gspca/jeilinj.c +++ b/drivers/media/usb/gspca/jeilinj.c @@ -378,11 +378,12 @@ static int sd_start(struct gspca_dev *gspca_dev) struct sd *dev = (struct sd *) gspca_dev; /* create the JPEG header */ - jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(dev->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x21); /* JPEG 422 */ jpeg_set_qual(dev->jpeg_hdr, dev->quality); PDEBUG(D_STREAM, "Start streaming at %dx%d", - gspca_dev->height, gspca_dev->width); + gspca_dev->pixfmt.height, gspca_dev->pixfmt.width); jlj_start(gspca_dev); return gspca_dev->usb_err; } diff --git a/drivers/media/usb/gspca/jl2005bcd.c b/drivers/media/usb/gspca/jl2005bcd.c index fdaeeb14453..5b481fa4309 100644 --- a/drivers/media/usb/gspca/jl2005bcd.c +++ b/drivers/media/usb/gspca/jl2005bcd.c @@ -455,7 +455,7 @@ static int sd_start(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; sd->cap_mode = gspca_dev->cam.cam_mode; - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 640: PDEBUG(D_STREAM, "Start streaming at vga resolution"); jl2005c_stream_start_vga_lg(gspca_dev); diff --git a/drivers/media/usb/gspca/jpeg.h b/drivers/media/usb/gspca/jpeg.h index ab54910418b..0aa2b671faa 100644 --- a/drivers/media/usb/gspca/jpeg.h +++ b/drivers/media/usb/gspca/jpeg.h @@ -154,7 +154,9 @@ static void jpeg_set_qual(u8 *jpeg_hdr, { int i, sc; - if (quality < 50) + if (quality <= 0) + sc = 5000; + else if (quality < 50) sc = 5000 / quality; else sc = 200 - quality * 2; diff --git a/drivers/media/usb/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c index 3773a8a745d..081f0516280 100644 --- a/drivers/media/usb/gspca/kinect.c +++ b/drivers/media/usb/gspca/kinect.c @@ -155,10 +155,11 @@ static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, do { actual_len = kinect_read(udev, ibuf, 0x200); } while (actual_len == 0); - PDEBUG(D_USBO, "Control reply: %d", res); + PDEBUG(D_USBO, "Control reply: %d", actual_len); if (actual_len < sizeof(*rhdr)) { - pr_err("send_cmd: Input control transfer failed (%d)\n", res); - return res; + pr_err("send_cmd: Input control transfer failed (%d)\n", + actual_len); + return actual_len < 0 ? actual_len : -EREMOTEIO; } actual_len -= sizeof(*rhdr); diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c index cfa4663f893..27fcef11aef 100644 --- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c @@ -266,7 +266,7 @@ static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev) return err; data[0] = MT9M111_RMB_OVER_SIZED; - if (gspca_dev->width == 640) { + if (gspca_dev->pixfmt.width == 640) { data[1] = MT9M111_RMB_ROW_SKIP_2X | MT9M111_RMB_COLUMN_SKIP_2X | (hflip << 1) | vflip; diff --git a/drivers/media/usb/gspca/mars.c b/drivers/media/usb/gspca/mars.c index ff2c5abf115..779a8785f42 100644 --- a/drivers/media/usb/gspca/mars.c +++ b/drivers/media/usb/gspca/mars.c @@ -254,7 +254,8 @@ static int sd_start(struct gspca_dev *gspca_dev) int i; /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x21); /* JPEG 422 */ jpeg_set_qual(sd->jpeg_hdr, QUALITY); @@ -270,8 +271,8 @@ static int sd_start(struct gspca_dev *gspca_dev) data[0] = 0x00; /* address */ data[1] = 0x0c | 0x01; /* reg 0 */ data[2] = 0x01; /* reg 1 */ - data[3] = gspca_dev->width / 8; /* h_size , reg 2 */ - data[4] = gspca_dev->height / 8; /* v_size , reg 3 */ + data[3] = gspca_dev->pixfmt.width / 8; /* h_size , reg 2 */ + data[4] = gspca_dev->pixfmt.height / 8; /* v_size , reg 3 */ data[5] = 0x30; /* reg 4, MI, PAS5101 : * 0x30 for 24mhz , 0x28 for 12mhz */ data[6] = 0x02; /* reg 5, H start - was 0x04 */ diff --git a/drivers/media/usb/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c index 68bb2f35966..f006e29ca01 100644 --- a/drivers/media/usb/gspca/mr97310a.c +++ b/drivers/media/usb/gspca/mr97310a.c @@ -521,7 +521,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev) if (sd->sensor_type) data[5] = 0xbb; - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */ /* fall thru */ @@ -618,7 +618,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev) data[10] = 0x18; } - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: data[9] |= 0x0c; /* reg 8, 4:1 scale down */ /* fall thru */ @@ -847,7 +847,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 min_clockdiv) u8 clockdiv = (60 * expo + 7999) / 8000; /* Limit framerate to not exceed usb bandwidth */ - if (clockdiv < min_clockdiv && gspca_dev->width >= 320) + if (clockdiv < min_clockdiv && gspca_dev->pixfmt.width >= 320) clockdiv = min_clockdiv; else if (clockdiv < 2) clockdiv = 2; diff --git a/drivers/media/usb/gspca/nw80x.c b/drivers/media/usb/gspca/nw80x.c index 44c9964b1b3..599f755e75b 100644 --- a/drivers/media/usb/gspca/nw80x.c +++ b/drivers/media/usb/gspca/nw80x.c @@ -1708,7 +1708,7 @@ static void setautogain(struct gspca_dev *gspca_dev, s32 val) reg_r(gspca_dev, 0x1004, 1); if (gspca_dev->usb_buf[0] & 0x04) { /* if AE_FULL_FRM */ - sd->ae_res = gspca_dev->width * gspca_dev->height; + sd->ae_res = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height; } else { /* get the AE window size */ reg_r(gspca_dev, 0x1011, 8); w = (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0] @@ -1717,7 +1717,8 @@ static void setautogain(struct gspca_dev *gspca_dev, s32 val) - (gspca_dev->usb_buf[7] << 8) - gspca_dev->usb_buf[6]; sd->ae_res = h * w; if (sd->ae_res == 0) - sd->ae_res = gspca_dev->width * gspca_dev->height; + sd->ae_res = gspca_dev->pixfmt.width * + gspca_dev->pixfmt.height; } } @@ -1856,21 +1857,21 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w_buf(gspca_dev, cmd); switch (sd->webcam) { case P35u: - if (gspca_dev->width == 320) + if (gspca_dev->pixfmt.width == 320) reg_w_buf(gspca_dev, nw801_start_qvga); else reg_w_buf(gspca_dev, nw801_start_vga); reg_w_buf(gspca_dev, nw801_start_2); break; case Kr651us: - if (gspca_dev->width == 320) + if (gspca_dev->pixfmt.width == 320) reg_w_buf(gspca_dev, kr651_start_qvga); else reg_w_buf(gspca_dev, kr651_start_vga); reg_w_buf(gspca_dev, kr651_start_2); break; case Proscope: - if (gspca_dev->width == 320) + if (gspca_dev->pixfmt.width == 320) reg_w_buf(gspca_dev, proscope_start_qvga); else reg_w_buf(gspca_dev, proscope_start_vga); diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c index 8937d79fd17..c95f32a0c02 100644 --- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -3468,7 +3468,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) switch (sd->bridge) { case BRIDGE_OVFX2: - if (gspca_dev->width != 800) + if (gspca_dev->pixfmt.width != 800) gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE; else gspca_dev->cam.bulk_size = 7 * 4096; @@ -3507,8 +3507,8 @@ static void ov511_mode_init_regs(struct sd *sd) /* Here I'm assuming that snapshot size == image size. * I hope that's always true. --claudio */ - hsegs = (sd->gspca_dev.width >> 3) - 1; - vsegs = (sd->gspca_dev.height >> 3) - 1; + hsegs = (sd->gspca_dev.pixfmt.width >> 3) - 1; + vsegs = (sd->gspca_dev.pixfmt.height >> 3) - 1; reg_w(sd, R511_CAM_PXCNT, hsegs); reg_w(sd, R511_CAM_LNCNT, vsegs); @@ -3541,7 +3541,7 @@ static void ov511_mode_init_regs(struct sd *sd) case SEN_OV7640: case SEN_OV7648: case SEN_OV76BE: - if (sd->gspca_dev.width == 320) + if (sd->gspca_dev.pixfmt.width == 320) interlaced = 1; /* Fall through */ case SEN_OV6630: @@ -3551,7 +3551,7 @@ static void ov511_mode_init_regs(struct sd *sd) case 30: case 25: /* Not enough bandwidth to do 640x480 @ 30 fps */ - if (sd->gspca_dev.width != 640) { + if (sd->gspca_dev.pixfmt.width != 640) { sd->clockdiv = 0; break; } @@ -3584,7 +3584,8 @@ static void ov511_mode_init_regs(struct sd *sd) /* Check if we have enough bandwidth to disable compression */ fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1; - needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2; + needed = fps * sd->gspca_dev.pixfmt.width * + sd->gspca_dev.pixfmt.height * 3 / 2; /* 1000 isoc packets/sec */ if (needed > 1000 * packet_size) { /* Enable Y and UV quantization and compression */ @@ -3646,8 +3647,8 @@ static void ov518_mode_init_regs(struct sd *sd) reg_w(sd, 0x38, 0x80); } - hsegs = sd->gspca_dev.width / 16; - vsegs = sd->gspca_dev.height / 4; + hsegs = sd->gspca_dev.pixfmt.width / 16; + vsegs = sd->gspca_dev.pixfmt.height / 4; reg_w(sd, 0x29, hsegs); reg_w(sd, 0x2a, vsegs); @@ -3686,7 +3687,8 @@ static void ov518_mode_init_regs(struct sd *sd) * happened to be with revision < 2 cams using an * OV7620 and revision 2 cams using an OV7620AE. */ - if (sd->revision > 0 && sd->gspca_dev.width == 640) { + if (sd->revision > 0 && + sd->gspca_dev.pixfmt.width == 640) { reg_w(sd, 0x20, 0x60); reg_w(sd, 0x21, 0x1f); } else { @@ -3812,8 +3814,8 @@ static void ov519_mode_init_regs(struct sd *sd) break; } - reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4); - reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.height >> 3); + reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.pixfmt.width >> 4); + reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.pixfmt.height >> 3); if (sd->sensor == SEN_OV7670 && sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv) reg_w(sd, OV519_R12_X_OFFSETL, 0x04); @@ -3947,14 +3949,16 @@ static void mode_init_ov_sensor_regs(struct sd *sd) } case SEN_OV3610: if (qvga) { - xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4); - ystart = (776 - gspca_dev->height) / 2; + xstart = (1040 - gspca_dev->pixfmt.width) / 2 + + (0x1f << 4); + ystart = (776 - gspca_dev->pixfmt.height) / 2; } else { - xstart = (2076 - gspca_dev->width) / 2 + (0x10 << 4); - ystart = (1544 - gspca_dev->height) / 2; + xstart = (2076 - gspca_dev->pixfmt.width) / 2 + + (0x10 << 4); + ystart = (1544 - gspca_dev->pixfmt.height) / 2; } - xend = xstart + gspca_dev->width; - yend = ystart + gspca_dev->height; + xend = xstart + gspca_dev->pixfmt.width; + yend = ystart + gspca_dev->pixfmt.height; /* Writing to the COMH register resets the other windowing regs to their default values, so we must do this first. */ i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0xf0); @@ -4229,8 +4233,8 @@ static int sd_start(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; /* Default for most bridges, allow bridge_mode_init_regs to override */ - sd->sensor_width = sd->gspca_dev.width; - sd->sensor_height = sd->gspca_dev.height; + sd->sensor_width = sd->gspca_dev.pixfmt.width; + sd->sensor_height = sd->gspca_dev.pixfmt.height; switch (sd->bridge) { case BRIDGE_OV511: @@ -4345,12 +4349,13 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev, ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1); if (in[8] & 0x80) { /* Frame end */ - if ((in[9] + 1) * 8 != gspca_dev->width || - (in[10] + 1) * 8 != gspca_dev->height) { + if ((in[9] + 1) * 8 != gspca_dev->pixfmt.width || + (in[10] + 1) * 8 != gspca_dev->pixfmt.height) { PERR("Invalid frame size, got: %dx%d," " requested: %dx%d\n", (in[9] + 1) * 8, (in[10] + 1) * 8, - gspca_dev->width, gspca_dev->height); + gspca_dev->pixfmt.width, + gspca_dev->pixfmt.height); gspca_dev->last_packet_type = DISCARD_PACKET; return; } @@ -4470,7 +4475,8 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev, if (sd->first_frame) { sd->first_frame--; if (gspca_dev->image_len < - sd->gspca_dev.width * sd->gspca_dev.height) + sd->gspca_dev.pixfmt.width * + sd->gspca_dev.pixfmt.height) gspca_dev->last_packet_type = DISCARD_PACKET; } gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 03a33c46ca2..90f0d637cd9 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -1440,9 +1440,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* If this packet is marked as EOF, end the frame */ } else if (data[1] & UVC_STREAM_EOF) { sd->last_pts = 0; - if (gspca_dev->pixfmt == V4L2_PIX_FMT_YUYV + if (gspca_dev->pixfmt.pixelformat == V4L2_PIX_FMT_YUYV && gspca_dev->image_len + len - 12 != - gspca_dev->width * gspca_dev->height * 2) { + gspca_dev->pixfmt.width * + gspca_dev->pixfmt.height * 2) { PDEBUG(D_PACK, "wrong sized frame"); goto discard; } diff --git a/drivers/media/usb/gspca/ov534_9.c b/drivers/media/usb/gspca/ov534_9.c index c4cd028fe0b..47085cf2d72 100644 --- a/drivers/media/usb/gspca/ov534_9.c +++ b/drivers/media/usb/gspca/ov534_9.c @@ -59,6 +59,7 @@ enum sensors { SENSOR_OV965x, /* ov9657 */ SENSOR_OV971x, /* ov9712 */ SENSOR_OV562x, /* ov5621 */ + SENSOR_OV361x, /* ov3610 */ NSENSORS }; @@ -106,6 +107,274 @@ static const struct v4l2_pix_format ov562x_mode[] = { } }; +enum ov361x { + ov361x_2048 = 0, + ov361x_1600, + ov361x_1024, + ov361x_640, + ov361x_320, + ov361x_160, + ov361x_last +}; + +static const struct v4l2_pix_format ov361x_mode[] = { + {0x800, 0x600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 0x800, + .sizeimage = 0x800 * 0x600, + .colorspace = V4L2_COLORSPACE_SRGB}, + {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 1600, + .sizeimage = 1600 * 1200, + .colorspace = V4L2_COLORSPACE_SRGB}, + {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 768, + .sizeimage = 1024 * 768, + .colorspace = V4L2_COLORSPACE_SRGB}, + {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB}, + {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB}, + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB} +}; + +static const u8 ov361x_start_2048[][2] = { + {0x12, 0x80}, + {0x13, 0xcf}, + {0x14, 0x40}, + {0x15, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x04, 0x70}, + {0x0d, 0x40}, + {0x0f, 0x47}, + {0x11, 0x81}, + {0x32, 0x36}, + {0x33, 0x0c}, + {0x34, 0x00}, + {0x35, 0x90}, + {0x12, 0x00}, + {0x17, 0x10}, + {0x18, 0x90}, + {0x19, 0x00}, + {0x1a, 0xc0}, +}; +static const u8 ov361x_bridge_start_2048[][2] = { + {0xf1, 0x60}, + {0x88, 0x00}, + {0x89, 0x08}, + {0x8a, 0x00}, + {0x8b, 0x06}, + {0x8c, 0x01}, + {0x8d, 0x10}, + {0x1c, 0x00}, + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1c, 0x0a}, + {0x1d, 0x2e}, + {0x1d, 0x1e}, +}; + +static const u8 ov361x_start_1600[][2] = { + {0x12, 0x80}, + {0x13, 0xcf}, + {0x14, 0x40}, + {0x15, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x04, 0x70}, + {0x0d, 0x40}, + {0x0f, 0x47}, + {0x11, 0x81}, + {0x32, 0x36}, + {0x33, 0x0C}, + {0x34, 0x00}, + {0x35, 0x90}, + {0x12, 0x00}, + {0x17, 0x10}, + {0x18, 0x90}, + {0x19, 0x00}, + {0x1a, 0xc0}, +}; +static const u8 ov361x_bridge_start_1600[][2] = { + {0xf1, 0x60}, /* Hsize[7:0] */ + {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */ + {0x89, 0x08}, /* Vsize[7:0] */ + {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */ + {0x8b, 0x06}, /* for Iso */ + {0x8c, 0x01}, /* RAW input */ + {0x8d, 0x10}, + {0x1c, 0x00}, /* RAW output, Iso transfer */ + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1c, 0x0a}, /* turn off JPEG, Iso mode */ + {0x1d, 0x2e}, /* for Iso */ + {0x1d, 0x1e}, +}; + +static const u8 ov361x_start_1024[][2] = { + {0x12, 0x80}, + {0x13, 0xcf}, + {0x14, 0x40}, + {0x15, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x04, 0x70}, + {0x0d, 0x40}, + {0x0f, 0x47}, + {0x11, 0x81}, + {0x32, 0x36}, + {0x33, 0x0C}, + {0x34, 0x00}, + {0x35, 0x90}, + {0x12, 0x40}, + {0x17, 0x1f}, + {0x18, 0x5f}, + {0x19, 0x00}, + {0x1a, 0x68}, +}; +static const u8 ov361x_bridge_start_1024[][2] = { + {0xf1, 0x60}, /* Hsize[7:0] */ + {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */ + {0x89, 0x04}, /* Vsize[7:0] */ + {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */ + {0x8b, 0x03}, /* for Iso */ + {0x8c, 0x01}, /* RAW input */ + {0x8d, 0x10}, + {0x1c, 0x00}, /* RAW output, Iso transfer */ + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1c, 0x0a}, /* turn off JPEG, Iso mode */ + {0x1d, 0x2e}, /* for Iso */ + {0x1d, 0x1e}, +}; + +static const u8 ov361x_start_640[][2] = { + {0x12, 0x80}, + {0x13, 0xcf}, + {0x14, 0x40}, + {0x15, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x04, 0x70}, + {0x0d, 0x40}, + {0x0f, 0x47}, + {0x11, 0x81}, + {0x32, 0x36}, + {0x33, 0x0C}, + {0x34, 0x00}, + {0x35, 0x90}, + {0x12, 0x40}, + {0x17, 0x1f}, + {0x18, 0x5f}, + {0x19, 0x00}, + {0x1a, 0x68}, +}; + +static const u8 ov361x_bridge_start_640[][2] = { + {0xf1, 0x60}, /* Hsize[7:0]*/ + {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */ + {0x89, 0x04}, /* Vsize[7:0] */ + {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */ + {0x8b, 0x03}, /* for Iso */ + {0x8c, 0x01}, /* RAW input */ + {0x8d, 0x10}, + {0x1c, 0x00}, /* RAW output, Iso transfer */ + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1c, 0x0a}, /* turn off JPEG, Iso mode */ + {0x1d, 0x2e}, /* for Iso */ + {0x1d, 0x1e}, +}; + +static const u8 ov361x_start_320[][2] = { + {0x12, 0x80}, + {0x13, 0xcf}, + {0x14, 0x40}, + {0x15, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x04, 0x70}, + {0x0d, 0x40}, + {0x0f, 0x47}, + {0x11, 0x81}, + {0x32, 0x36}, + {0x33, 0x0C}, + {0x34, 0x00}, + {0x35, 0x90}, + {0x12, 0x40}, + {0x17, 0x1f}, + {0x18, 0x5f}, + {0x19, 0x00}, + {0x1a, 0x68}, +}; + +static const u8 ov361x_bridge_start_320[][2] = { + {0xf1, 0x60}, /* Hsize[7:0] */ + {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */ + {0x89, 0x04}, /* Vsize[7:0] */ + {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */ + {0x8b, 0x03}, /* for Iso */ + {0x8c, 0x01}, /* RAW input */ + {0x8d, 0x10}, + {0x1c, 0x00}, /* RAW output, Iso transfer; */ + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1c, 0x0a}, /* turn off JPEG, Iso mode */ + {0x1d, 0x2e}, /* for Iso */ + {0x1d, 0x1e}, +}; + +static const u8 ov361x_start_160[][2] = { + {0x12, 0x80}, + {0x13, 0xcf}, + {0x14, 0x40}, + {0x15, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x04, 0x70}, + {0x0d, 0x40}, + {0x0f, 0x47}, + {0x11, 0x81}, + {0x32, 0x36}, + {0x33, 0x0C}, + {0x34, 0x00}, + {0x35, 0x90}, + {0x12, 0x40}, + {0x17, 0x1f}, + {0x18, 0x5f}, + {0x19, 0x00}, + {0x1a, 0x68}, +}; + +static const u8 ov361x_bridge_start_160[][2] = { + {0xf1, 0x60}, /* Hsize[7:0] */ + {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */ + {0x89, 0x04}, /* Vsize[7:0] */ + {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */ + {0x8b, 0x03}, /* for Iso */ + {0x8c, 0x01}, /* RAW input */ + {0x8d, 0x10}, + {0x1c, 0x00}, /* RAW output, Iso transfer */ + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1c, 0x0a}, /* turn off JPEG, Iso mode */ + {0x1d, 0x2e}, /* for Iso */ + {0x1d, 0x1e}, +}; + static const u8 bridge_init[][2] = { {0x88, 0xf8}, {0x89, 0xff}, @@ -898,7 +1167,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev) int i; for (i = 0; i < 5; i++) { - msleep(10); + msleep(20); data = reg_r(gspca_dev, OV534_REG_STATUS); switch (data) { @@ -1221,6 +1490,13 @@ static int sd_init(struct gspca_dev *gspca_dev) sccb_w_array(gspca_dev, ov562x_init_2, ARRAY_SIZE(ov562x_init_2)); reg_w(gspca_dev, 0xe0, 0x00); + } else if ((sensor_id & 0xfff0) == 0x3610) { + sd->sensor = SENSOR_OV361x; + gspca_dev->cam.cam_mode = ov361x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov361x_mode); + reg_w(gspca_dev, 0xe7, 0x3a); + reg_w(gspca_dev, 0xf1, 0x60); + sccb_write(gspca_dev, 0x12, 0x80); } else { pr_err("Unknown sensor %04x", sensor_id); return -EINVAL; @@ -1229,6 +1505,53 @@ static int sd_init(struct gspca_dev *gspca_dev) return gspca_dev->usb_err; } +static int sd_start_ov361x(struct gspca_dev *gspca_dev) +{ + sccb_write(gspca_dev, 0x12, 0x80); + msleep(20); + switch (gspca_dev->curr_mode % (ov361x_last)) { + case ov361x_2048: + reg_w_array(gspca_dev, ov361x_bridge_start_2048, + ARRAY_SIZE(ov361x_bridge_start_2048)); + sccb_w_array(gspca_dev, ov361x_start_2048, + ARRAY_SIZE(ov361x_start_2048)); + break; + case ov361x_1600: + reg_w_array(gspca_dev, ov361x_bridge_start_1600, + ARRAY_SIZE(ov361x_bridge_start_1600)); + sccb_w_array(gspca_dev, ov361x_start_1600, + ARRAY_SIZE(ov361x_start_1600)); + break; + case ov361x_1024: + reg_w_array(gspca_dev, ov361x_bridge_start_1024, + ARRAY_SIZE(ov361x_bridge_start_1024)); + sccb_w_array(gspca_dev, ov361x_start_1024, + ARRAY_SIZE(ov361x_start_1024)); + break; + case ov361x_640: + reg_w_array(gspca_dev, ov361x_bridge_start_640, + ARRAY_SIZE(ov361x_bridge_start_640)); + sccb_w_array(gspca_dev, ov361x_start_640, + ARRAY_SIZE(ov361x_start_640)); + break; + case ov361x_320: + reg_w_array(gspca_dev, ov361x_bridge_start_320, + ARRAY_SIZE(ov361x_bridge_start_320)); + sccb_w_array(gspca_dev, ov361x_start_320, + ARRAY_SIZE(ov361x_start_320)); + break; + case ov361x_160: + reg_w_array(gspca_dev, ov361x_bridge_start_160, + ARRAY_SIZE(ov361x_bridge_start_160)); + sccb_w_array(gspca_dev, ov361x_start_160, + ARRAY_SIZE(ov361x_start_160)); + break; + } + reg_w(gspca_dev, 0xe0, 0x00); /* start transfer */ + + return gspca_dev->usb_err; +} + static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1237,6 +1560,8 @@ static int sd_start(struct gspca_dev *gspca_dev) return gspca_dev->usb_err; if (sd->sensor == SENSOR_OV562x) return gspca_dev->usb_err; + if (sd->sensor == SENSOR_OV361x) + return sd_start_ov361x(gspca_dev); switch (gspca_dev->curr_mode) { case QVGA_MODE: /* 320x240 */ @@ -1290,6 +1615,11 @@ static int sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { + if (((struct sd *)gspca_dev)->sensor == SENSOR_OV361x) { + reg_w(gspca_dev, 0xe0, 0x01); /* stop transfer */ + /* reg_w(gspca_dev, 0x31, 0x09); */ + return; + } reg_w(gspca_dev, 0xe0, 0x01); set_led(gspca_dev, 0); reg_w(gspca_dev, 0xe0, 0x00); @@ -1425,6 +1755,8 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) if (sd->sensor == SENSOR_OV971x) return 0; + if (sd->sensor == SENSOR_OV361x) + return 0; gspca_dev->vdev.ctrl_handler = hdl; v4l2_ctrl_handler_init(hdl, 7); if (sd->sensor == SENSOR_OV562x) { diff --git a/drivers/media/usb/gspca/pac207.c b/drivers/media/usb/gspca/pac207.c index 83519be94e5..07529e5a0c5 100644 --- a/drivers/media/usb/gspca/pac207.c +++ b/drivers/media/usb/gspca/pac207.c @@ -299,7 +299,7 @@ static int sd_start(struct gspca_dev *gspca_dev) pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8); /* Compression Balance */ - if (gspca_dev->width == 176) + if (gspca_dev->pixfmt.width == 176) pac207_write_reg(gspca_dev, 0x4a, 0xff); else pac207_write_reg(gspca_dev, 0x4a, 0x30); @@ -317,7 +317,7 @@ static int sd_start(struct gspca_dev *gspca_dev) mode = 0x00; else mode = 0x02; - if (gspca_dev->width == 176) { /* 176x144 */ + if (gspca_dev->pixfmt.width == 176) { /* 176x144 */ mode |= 0x01; PDEBUG(D_STREAM, "pac207_start mode 176x144"); } else { /* 352x288 */ @@ -416,7 +416,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, #if IS_ENABLED(CONFIG_INPUT) static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* interrupt packet data */ - int len) /* interrput packet length */ + int len) /* interrupt packet length */ { int ret = -EINVAL; diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c index a9150964356..339adce7c7a 100644 --- a/drivers/media/usb/gspca/pac7302.c +++ b/drivers/media/usb/gspca/pac7302.c @@ -874,7 +874,7 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev, #if IS_ENABLED(CONFIG_INPUT) static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* interrupt packet data */ - int len) /* interrput packet length */ + int len) /* interrupt packet length */ { int ret = -EINVAL; u8 data0, data1; @@ -928,6 +928,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2620)}, {USB_DEVICE(0x093a, 0x2621)}, {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, + {USB_DEVICE(0x093a, 0x2623), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2625)}, {USB_DEVICE(0x093a, 0x2626)}, diff --git a/drivers/media/usb/gspca/pac7311.c b/drivers/media/usb/gspca/pac7311.c index 1a5bdc853a8..25f86b1e74a 100644 --- a/drivers/media/usb/gspca/pac7311.c +++ b/drivers/media/usb/gspca/pac7311.c @@ -326,7 +326,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 val) * 640x480 mode and page 4 reg 2 <= 3 then it must be 9 */ reg_w(gspca_dev, 0xff, 0x01); - if (gspca_dev->width != 640 && val <= 3) + if (gspca_dev->pixfmt.width != 640 && val <= 3) reg_w(gspca_dev, 0x08, 0x09); else reg_w(gspca_dev, 0x08, 0x08); @@ -337,7 +337,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 val) * camera to use higher compression or we may run out of * bandwidth. */ - if (gspca_dev->width == 640 && val == 2) + if (gspca_dev->pixfmt.width == 640 && val == 2) reg_w(gspca_dev, 0x80, 0x01); else reg_w(gspca_dev, 0x80, 0x1c); @@ -615,7 +615,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* Start the new frame with the jpeg header */ pac_start_frame(gspca_dev, - gspca_dev->height, gspca_dev->width); + gspca_dev->pixfmt.height, gspca_dev->pixfmt.width); } gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } diff --git a/drivers/media/usb/gspca/se401.c b/drivers/media/usb/gspca/se401.c index 5f729b8aa2b..5102cea5047 100644 --- a/drivers/media/usb/gspca/se401.c +++ b/drivers/media/usb/gspca/se401.c @@ -354,9 +354,9 @@ static int sd_start(struct gspca_dev *gspca_dev) /* set size + mode */ se401_write_req(gspca_dev, SE401_REQ_SET_WIDTH, - gspca_dev->width * mult, 0); + gspca_dev->pixfmt.width * mult, 0); se401_write_req(gspca_dev, SE401_REQ_SET_HEIGHT, - gspca_dev->height * mult, 0); + gspca_dev->pixfmt.height * mult, 0); /* * HDG: disabled this as it does not seem to do anything * se401_write_req(gspca_dev, SE401_REQ_SET_OUTPUT_MODE, @@ -480,7 +480,7 @@ static void sd_complete_frame(struct gspca_dev *gspca_dev, u8 *data, int len) static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len) { struct sd *sd = (struct sd *)gspca_dev; - int imagesize = gspca_dev->width * gspca_dev->height; + int imagesize = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height; int i, plen, bits, pixels, info, count; if (sd->restart_stream) diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index f4453d52801..41a9a892f79 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -1955,7 +1955,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) return 0; } - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: /* 160x120 */ gspca_dev->alt = 2; break; @@ -1985,8 +1985,8 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - int width = gspca_dev->width; - int height = gspca_dev->height; + int width = gspca_dev->pixfmt.width; + int height = gspca_dev->pixfmt.height; u8 fmt, scale = 0; jpeg_define(sd->jpeg_hdr, height, width, @@ -2359,6 +2359,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)}, {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)}, {USB_DEVICE(0x0458, 0x7029), SN9C20X(HV7131R, 0x11, 0)}, + {USB_DEVICE(0x0458, 0x7045), SN9C20X(MT9M112, 0x5d, LED_REVERSE)}, {USB_DEVICE(0x0458, 0x704a), SN9C20X(MT9M112, 0x5d, 0)}, {USB_DEVICE(0x0458, 0x704c), SN9C20X(MT9M112, 0x5d, 0)}, {USB_DEVICE(0xa168, 0x0610), SN9C20X(HV7131R, 0x11, 0)}, diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index d7ff3b9687c..ecbcb39feb7 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -513,10 +513,7 @@ static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buf) if (gspca_dev->usb_buf[0] & 0x04) { if (gspca_dev->usb_buf[0] & 0x08) { dev_err(gspca_dev->v4l2_dev.dev, - "i2c error writing %02x %02x %02x %02x" - " %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); + "i2c error writing %8ph\n", buf); gspca_dev->usb_err = -EIO; } return; @@ -753,7 +750,7 @@ static void setexposure(struct gspca_dev *gspca_dev) /* In 640x480, if the reg11 has less than 4, the image is unstable (the bridge goes into a higher compression mode which we have not reverse engineered yet). */ - if (gspca_dev->width == 640 && reg11 < 4) + if (gspca_dev->pixfmt.width == 640 && reg11 < 4) reg11 = 4; /* frame exposure time in ms = 1000 * reg11 / 30 -> @@ -1433,10 +1430,8 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)}, {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)}, {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)}, -#if !IS_ENABLED(CONFIG_USB_SN9C102) {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)}, {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, -#endif {USB_DEVICE(0x0c45, 0x6027), SB(OV7630, 101)}, /* Genius Eye 310 */ {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index 3b5ccb1c4cd..c69b45d7cfb 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c @@ -2204,7 +2204,8 @@ static int sd_start(struct gspca_dev *gspca_dev) { 0x14, 0xe7, 0x1e, 0xdd }; /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x21); /* JPEG 422 */ /* initialize the bridge */ diff --git a/drivers/media/usb/gspca/spca1528.c b/drivers/media/usb/gspca/spca1528.c index 688592b289e..f38fd894960 100644 --- a/drivers/media/usb/gspca/spca1528.c +++ b/drivers/media/usb/gspca/spca1528.c @@ -255,7 +255,8 @@ static int sd_start(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; /* initialize the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x22); /* JPEG 411 */ /* the JPEG quality shall be 85% */ diff --git a/drivers/media/usb/gspca/spca500.c b/drivers/media/usb/gspca/spca500.c index 9f8bf51fd64..f011a309dd6 100644 --- a/drivers/media/usb/gspca/spca500.c +++ b/drivers/media/usb/gspca/spca500.c @@ -608,7 +608,8 @@ static int sd_start(struct gspca_dev *gspca_dev) __u8 xmult, ymult; /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, QUALITY); diff --git a/drivers/media/usb/gspca/sq905c.c b/drivers/media/usb/gspca/sq905c.c index acb19fb9a3d..aa21edc9502 100644 --- a/drivers/media/usb/gspca/sq905c.c +++ b/drivers/media/usb/gspca/sq905c.c @@ -272,7 +272,7 @@ static int sd_start(struct gspca_dev *gspca_dev) dev->cap_mode = gspca_dev->cam.cam_mode; /* "Open the shutter" and set size, to start capture */ - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 640: PDEBUG(D_STREAM, "Start streaming at high resolution"); dev->cap_mode++; diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c index b10d0821111..e274cf19a3e 100644 --- a/drivers/media/usb/gspca/sq930x.c +++ b/drivers/media/usb/gspca/sq930x.c @@ -906,7 +906,8 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */ sd->do_ctrl = 0; - gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8; + gspca_dev->cam.bulk_size = gspca_dev->pixfmt.width * + gspca_dev->pixfmt.height + 8; return 0; } diff --git a/drivers/media/usb/gspca/stk014.c b/drivers/media/usb/gspca/stk014.c index 8c0982607f2..b0c70fea760 100644 --- a/drivers/media/usb/gspca/stk014.c +++ b/drivers/media/usb/gspca/stk014.c @@ -250,7 +250,8 @@ static int sd_start(struct gspca_dev *gspca_dev) int ret, value; /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, QUALITY); @@ -261,7 +262,7 @@ static int sd_start(struct gspca_dev *gspca_dev) set_par(gspca_dev, 0x00000000); set_par(gspca_dev, 0x8002e001); set_par(gspca_dev, 0x14000000); - if (gspca_dev->width > 320) + if (gspca_dev->pixfmt.width > 320) value = 0x8002e001; /* 640x480 */ else value = 0x4001f000; /* 320x240 */ diff --git a/drivers/media/usb/gspca/stk1135.c b/drivers/media/usb/gspca/stk1135.c index 585868835ac..48234c9a8b6 100644 --- a/drivers/media/usb/gspca/stk1135.c +++ b/drivers/media/usb/gspca/stk1135.c @@ -48,42 +48,11 @@ struct sd { }; static const struct v4l2_pix_format stk1135_modes[] = { - {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 160, - .sizeimage = 160 * 120, - .colorspace = V4L2_COLORSPACE_SRGB}, - {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 176, - .sizeimage = 176 * 144, - .colorspace = V4L2_COLORSPACE_SRGB}, - {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 320, - .sizeimage = 320 * 240, - .colorspace = V4L2_COLORSPACE_SRGB}, - {352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 352, - .sizeimage = 352 * 288, - .colorspace = V4L2_COLORSPACE_SRGB}, + /* default mode (this driver supports variable resolution) */ {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 640, .sizeimage = 640 * 480, .colorspace = V4L2_COLORSPACE_SRGB}, - {720, 576, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 720, - .sizeimage = 720 * 576, - .colorspace = V4L2_COLORSPACE_SRGB}, - {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 800, - .sizeimage = 800 * 600, - .colorspace = V4L2_COLORSPACE_SRGB}, - {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 1024, - .sizeimage = 1024 * 768, - .colorspace = V4L2_COLORSPACE_SRGB}, - {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, - .bytesperline = 1280, - .sizeimage = 1280 * 1024, - .colorspace = V4L2_COLORSPACE_SRGB}, }; /* -- read a register -- */ @@ -347,16 +316,16 @@ static void stk1135_configure_mt9m112(struct gspca_dev *gspca_dev) sensor_write(gspca_dev, cfg[i].reg, cfg[i].val); /* set output size */ - width = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].width; - height = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].height; - if (width <= 640) { /* use context A (half readout speed by default) */ + width = gspca_dev->pixfmt.width; + height = gspca_dev->pixfmt.height; + if (width <= 640 && height <= 512) { /* context A (half readout speed)*/ sensor_write(gspca_dev, 0x1a7, width); sensor_write(gspca_dev, 0x1aa, height); /* set read mode context A */ sensor_write(gspca_dev, 0x0c8, 0x0000); /* set resize, read mode, vblank, hblank context A */ sensor_write(gspca_dev, 0x2c8, 0x0000); - } else { /* use context B (full readout speed by default) */ + } else { /* context B (full readout speed) */ sensor_write(gspca_dev, 0x1a1, width); sensor_write(gspca_dev, 0x1a4, height); /* set read mode context B */ @@ -392,6 +361,9 @@ static void stk1135_configure_clock(struct gspca_dev *gspca_dev) /* set serial interface clock divider (30MHz/0x1f*16+2) = 60240 kHz) */ reg_w(gspca_dev, STK1135_REG_SICTL + 2, 0x1f); + + /* wait a while for sensor to catch up */ + udelay(1000); } static void stk1135_camera_disable(struct gspca_dev *gspca_dev) @@ -484,8 +456,8 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, STK1135_REG_CISPO + 3, 0x00); /* set capture end position */ - width = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].width; - height = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].height; + width = gspca_dev->pixfmt.width; + height = gspca_dev->pixfmt.height; reg_w(gspca_dev, STK1135_REG_CIEPO + 0, width & 0xff); reg_w(gspca_dev, STK1135_REG_CIEPO + 1, width >> 8); reg_w(gspca_dev, STK1135_REG_CIEPO + 2, height & 0xff); @@ -643,6 +615,35 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) return 0; } +static void stk1135_try_fmt(struct gspca_dev *gspca_dev, struct v4l2_format *fmt) +{ + fmt->fmt.pix.width = clamp(fmt->fmt.pix.width, 32U, 1280U); + fmt->fmt.pix.height = clamp(fmt->fmt.pix.height, 32U, 1024U); + /* round up to even numbers */ + fmt->fmt.pix.width += (fmt->fmt.pix.width & 1); + fmt->fmt.pix.height += (fmt->fmt.pix.height & 1); + + fmt->fmt.pix.bytesperline = fmt->fmt.pix.width; + fmt->fmt.pix.sizeimage = fmt->fmt.pix.width * fmt->fmt.pix.height; +} + +static int stk1135_enum_framesizes(struct gspca_dev *gspca_dev, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index != 0 || fsize->pixel_format != V4L2_PIX_FMT_SBGGR8) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = 32; + fsize->stepwise.min_height = 32; + fsize->stepwise.max_width = 1280; + fsize->stepwise.max_height = 1024; + fsize->stepwise.step_width = 2; + fsize->stepwise.step_height = 2; + + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, @@ -653,6 +654,8 @@ static const struct sd_desc sd_desc = { .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, .dq_callback = stk1135_dq_callback, + .try_fmt = stk1135_try_fmt, + .enum_framesizes = stk1135_enum_framesizes, }; /* -- module initialisation -- */ diff --git a/drivers/media/usb/gspca/stv0680.c b/drivers/media/usb/gspca/stv0680.c index 9c0827631b9..7f94ec74282 100644 --- a/drivers/media/usb/gspca/stv0680.c +++ b/drivers/media/usb/gspca/stv0680.c @@ -139,7 +139,7 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct cam *cam = &gspca_dev->cam; - /* Give the camera some time to settle, otherwise initalization will + /* Give the camera some time to settle, otherwise initialization will fail on hotplug, and yes it really needs a full second. */ msleep(1000); diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c index 55ee7a61c67..49d209bbf9e 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -452,7 +452,7 @@ frame_data: NULL, 0); if (sd->bridge == BRIDGE_ST6422) - sd->to_skip = gspca_dev->width * 4; + sd->to_skip = gspca_dev->pixfmt.width * 4; if (chunk_len) PERR("Chunk length is " diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c index 8206b774330..8d785edcccf 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c @@ -421,7 +421,7 @@ static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val) /* Number of pixels counted by the sensor when subsampling the pixels. * Slightly larger than the real value to avoid oscillation */ - totalpixels = gspca_dev->width * gspca_dev->height; + totalpixels = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height; totalpixels = totalpixels/(8*8) + totalpixels/(64*64); brightpixels = (totalpixels * val) >> 8; diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c index bf3e5c317a2..e60cbb3aa60 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c @@ -178,7 +178,7 @@ static int vv6410_stop(struct sd *sd) PDEBUG(D_STREAM, "Halting stream"); - return (err < 0) ? err : 0; + return 0; } static int vv6410_dump(struct sd *sd) diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c index af8767a9bd4..46c9f2229a1 100644 --- a/drivers/media/usb/gspca/sunplus.c +++ b/drivers/media/usb/gspca/sunplus.c @@ -715,7 +715,8 @@ static int sd_start(struct gspca_dev *gspca_dev) int enable; /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x22); /* JPEG 411 */ jpeg_set_qual(sd->jpeg_hdr, QUALITY); @@ -1026,6 +1027,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)}, {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)}, {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)}, + {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)}, {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)}, {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)}, {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)}, diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c index 4cb511ccc5f..5fcd1eec200 100644 --- a/drivers/media/usb/gspca/topro.c +++ b/drivers/media/usb/gspca/topro.c @@ -3856,7 +3856,7 @@ static void setsharpness(struct gspca_dev *gspca_dev, s32 val) if (sd->bridge == BRIDGE_TP6800) { val |= 0x08; /* grid compensation enable */ - if (gspca_dev->width == 640) + if (gspca_dev->pixfmt.width == 640) reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */ else val |= 0x04; /* scaling down enable */ @@ -3880,7 +3880,7 @@ static void set_resolution(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00); - if (gspca_dev->width == 320) { + if (gspca_dev->pixfmt.width == 320) { reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x06); msleep(100); i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01); @@ -3924,7 +3924,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev) /* 640x480 * 30 fps does not work */ if (i == 6 /* if 30 fps */ - && gspca_dev->width == 640) + && gspca_dev->pixfmt.width == 640) i = 0x05; /* 15 fps */ } else { for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) { @@ -3935,7 +3935,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev) /* 640x480 * 30 fps does not work */ if (i == 7 /* if 30 fps */ - && gspca_dev->width == 640) + && gspca_dev->pixfmt.width == 640) i = 6; /* 15 fps */ i |= 0x80; /* clock * 1 */ } @@ -4554,7 +4554,8 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width); + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width); set_dqt(gspca_dev, sd->quality); if (sd->bridge == BRIDGE_TP6800) { if (sd->sensor == SENSOR_CX0342) @@ -4630,8 +4631,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } data++; len--; + if (len < 2) { + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } if (*data == 0xff && data[1] == 0xd8) { /*fixme: there may be information in the 4 high bits*/ + if (len < 7) { + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } if ((data[6] & 0x0f) != sd->quality) set_dqt(gspca_dev, data[6] & 0x0f); gspca_frame_add(gspca_dev, FIRST_PACKET, @@ -4671,7 +4680,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_dev->last_packet_type = DISCARD_PACKET; break; case 0xcc: - if (data[1] != 0xff || data[2] != 0xd8) + if (len >= 3 && (data[1] != 0xff || data[2] != 0xd8)) gspca_frame_add(gspca_dev, INTER_PACKET, data + 1, len - 1); else @@ -4737,7 +4746,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev) (gspca_dev->usb_buf[26] << 8) + gspca_dev->usb_buf[25] + (gspca_dev->usb_buf[29] << 8) + gspca_dev->usb_buf[28]) / 8; - if (gspca_dev->width == 640) + if (gspca_dev->pixfmt.width == 640) luma /= 4; reg_w(gspca_dev, 0x7d, 0x00); diff --git a/drivers/media/usb/gspca/tv8532.c b/drivers/media/usb/gspca/tv8532.c index 8591324a53e..d497ba38af0 100644 --- a/drivers/media/usb/gspca/tv8532.c +++ b/drivers/media/usb/gspca/tv8532.c @@ -268,7 +268,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, packet_type0 = packet_type1 = INTER_PACKET; if (gspca_dev->empty_packet) { gspca_dev->empty_packet = 0; - sd->packet = gspca_dev->height / 2; + sd->packet = gspca_dev->pixfmt.height / 2; packet_type0 = FIRST_PACKET; } else if (sd->packet == 0) return; /* 2 more lines in 352x288 ! */ @@ -284,9 +284,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, * - 4 bytes */ gspca_frame_add(gspca_dev, packet_type0, - data + 2, gspca_dev->width); + data + 2, gspca_dev->pixfmt.width); gspca_frame_add(gspca_dev, packet_type1, - data + gspca_dev->width + 5, gspca_dev->width); + data + gspca_dev->pixfmt.width + 5, + gspca_dev->pixfmt.width); } static int sd_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/usb/gspca/vicam.c b/drivers/media/usb/gspca/vicam.c index a2275cfe0b8..103f6c4236b 100644 --- a/drivers/media/usb/gspca/vicam.c +++ b/drivers/media/usb/gspca/vicam.c @@ -121,13 +121,13 @@ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) memset(req_data, 0, 16); req_data[0] = gain; - if (gspca_dev->width == 256) + if (gspca_dev->pixfmt.width == 256) req_data[1] |= 0x01; /* low nibble x-scale */ - if (gspca_dev->height <= 122) { + if (gspca_dev->pixfmt.height <= 122) { req_data[1] |= 0x10; /* high nibble y-scale */ - unscaled_height = gspca_dev->height * 2; + unscaled_height = gspca_dev->pixfmt.height * 2; } else - unscaled_height = gspca_dev->height; + unscaled_height = gspca_dev->pixfmt.height; req_data[2] = 0x90; /* unknown, does not seem to do anything */ if (unscaled_height <= 200) req_data[3] = 0x06; /* vend? */ diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c index 2165da0c7ce..fb9fe2ef3a6 100644 --- a/drivers/media/usb/gspca/w996Xcf.c +++ b/drivers/media/usb/gspca/w996Xcf.c @@ -430,11 +430,11 @@ static void w9968cf_set_crop_window(struct sd *sd) #define SC(x) ((x) << 10) /* Scaling factors */ - fw = SC(sd->gspca_dev.width) / max_width; - fh = SC(sd->gspca_dev.height) / max_height; + fw = SC(sd->gspca_dev.pixfmt.width) / max_width; + fh = SC(sd->gspca_dev.pixfmt.height) / max_height; - cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width) / fh; - ch = (fw >= fh) ? SC(sd->gspca_dev.height) / fw : max_height; + cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.pixfmt.width) / fh; + ch = (fw >= fh) ? SC(sd->gspca_dev.pixfmt.height) / fw : max_height; sd->sensor_width = max_width; sd->sensor_height = max_height; @@ -454,34 +454,34 @@ static void w9968cf_mode_init_regs(struct sd *sd) w9968cf_set_crop_window(sd); - reg_w(sd, 0x14, sd->gspca_dev.width); - reg_w(sd, 0x15, sd->gspca_dev.height); + reg_w(sd, 0x14, sd->gspca_dev.pixfmt.width); + reg_w(sd, 0x15, sd->gspca_dev.pixfmt.height); /* JPEG width & height */ - reg_w(sd, 0x30, sd->gspca_dev.width); - reg_w(sd, 0x31, sd->gspca_dev.height); + reg_w(sd, 0x30, sd->gspca_dev.pixfmt.width); + reg_w(sd, 0x31, sd->gspca_dev.pixfmt.height); /* Y & UV frame buffer strides (in WORD) */ if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == V4L2_PIX_FMT_JPEG) { - reg_w(sd, 0x2c, sd->gspca_dev.width / 2); - reg_w(sd, 0x2d, sd->gspca_dev.width / 4); + reg_w(sd, 0x2c, sd->gspca_dev.pixfmt.width / 2); + reg_w(sd, 0x2d, sd->gspca_dev.pixfmt.width / 4); } else - reg_w(sd, 0x2c, sd->gspca_dev.width); + reg_w(sd, 0x2c, sd->gspca_dev.pixfmt.width); reg_w(sd, 0x00, 0xbf17); /* reset everything */ reg_w(sd, 0x00, 0xbf10); /* normal operation */ /* Transfer size in WORDS (for UYVY format only) */ - val = sd->gspca_dev.width * sd->gspca_dev.height; + val = sd->gspca_dev.pixfmt.width * sd->gspca_dev.pixfmt.height; reg_w(sd, 0x3d, val & 0xffff); /* low bits */ reg_w(sd, 0x3e, val >> 16); /* high bits */ if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat == V4L2_PIX_FMT_JPEG) { /* We may get called multiple times (usb isoc bw negotiat.) */ - jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height, - sd->gspca_dev.width, 0x22); /* JPEG 420 */ + jpeg_define(sd->jpeg_hdr, sd->gspca_dev.pixfmt.height, + sd->gspca_dev.pixfmt.width, 0x22); /* JPEG 420 */ jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual)); w9968cf_upload_quantizationtables(sd); v4l2_ctrl_grab(sd->jpegqual, true); diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c index 7eaf64eb867..a41aa7817c5 100644 --- a/drivers/media/usb/gspca/xirlink_cit.c +++ b/drivers/media/usb/gspca/xirlink_cit.c @@ -1471,14 +1471,14 @@ static int cit_get_clock_div(struct gspca_dev *gspca_dev) while (clock_div > 3 && 1000 * packet_size > - gspca_dev->width * gspca_dev->height * + gspca_dev->pixfmt.width * gspca_dev->pixfmt.height * fps[clock_div - 1] * 3 / 2) clock_div--; PDEBUG(D_PROBE, "PacketSize: %d, res: %dx%d -> using clockdiv: %d (%d fps)", - packet_size, gspca_dev->width, gspca_dev->height, clock_div, - fps[clock_div]); + packet_size, gspca_dev->pixfmt.width, gspca_dev->pixfmt.height, + clock_div, fps[clock_div]); return clock_div; } @@ -1502,7 +1502,7 @@ static int cit_start_model0(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0x0002, 0x0426); cit_write_reg(gspca_dev, 0x0014, 0x0427); - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: /* 160x120 */ cit_write_reg(gspca_dev, 0x0004, 0x010b); cit_write_reg(gspca_dev, 0x0001, 0x010a); @@ -1643,7 +1643,7 @@ static int cit_start_model1(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0x00, 0x0101); cit_write_reg(gspca_dev, 0x00, 0x010a); - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 128: /* 128x96 */ cit_write_reg(gspca_dev, 0x80, 0x0103); cit_write_reg(gspca_dev, 0x60, 0x0105); @@ -1700,7 +1700,7 @@ static int cit_start_model1(struct gspca_dev *gspca_dev) } /* Assorted init */ - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 128: /* 128x96 */ cit_Packet_Format1(gspca_dev, 0x2b, 0x1e); cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */ @@ -1753,7 +1753,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0x0000, 0x0108); cit_write_reg(gspca_dev, 0x0001, 0x0133); cit_write_reg(gspca_dev, 0x0001, 0x0102); - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 176: /* 176x144 */ cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */ cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */ @@ -1792,7 +1792,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */ - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 176: /* 176x144 */ cit_write_reg(gspca_dev, 0x0050, 0x0111); cit_write_reg(gspca_dev, 0x00d0, 0x0111); @@ -1840,7 +1840,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) * Magic control of CMOS sensor. Only lower values like * 0-3 work, and picture shifts left or right. Don't change. */ - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 176: /* 176x144 */ cit_model2_Packet1(gspca_dev, 0x0014, 0x0002); cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */ @@ -1899,7 +1899,7 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) * does not allow arbitrary values and apparently is a bit mask, to * be activated only at appropriate time. Don't change it randomly! */ - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 176: /* 176x144 */ cit_model2_Packet1(gspca_dev, 0x0026, 0x00c2); break; @@ -2023,7 +2023,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev) cit_model3_Packet1(gspca_dev, 0x009e, 0x0096); cit_model3_Packet1(gspca_dev, 0x009f, 0x000a); - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */ cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */ @@ -2134,7 +2134,7 @@ static int cit_start_model3(struct gspca_dev *gspca_dev) like with the IBM netcam pro). */ cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */ - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */ cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */ @@ -2211,7 +2211,7 @@ static int cit_start_model4(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0xfffa, 0x0124); cit_model4_Packet1(gspca_dev, 0x0034, 0x0000); - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 128: /* 128x96 */ cit_write_reg(gspca_dev, 0x0070, 0x0119); cit_write_reg(gspca_dev, 0x00d0, 0x0111); @@ -2531,7 +2531,7 @@ static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */ cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */ - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: /* 160x120 */ cit_write_reg(gspca_dev, 0x0024, 0x010b); cit_write_reg(gspca_dev, 0x0089, 0x0119); @@ -2635,7 +2635,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) struct usb_host_interface *alt; int max_packet_size; - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: max_packet_size = 450; break; @@ -2659,7 +2659,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev) int ret, packet_size, min_packet_size; struct usb_host_interface *alt; - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: min_packet_size = 200; break; @@ -2780,7 +2780,7 @@ static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len) case CIT_MODEL1: case CIT_MODEL3: case CIT_IBM_NETCAM_PRO: - switch (gspca_dev->width) { + switch (gspca_dev->pixfmt.width) { case 160: /* 160x120 */ byte3 = 0x02; byte4 = 0x0a; @@ -2864,20 +2864,16 @@ static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len) if (data[i] == 0xff) { if (i >= 4) PDEBUG(D_FRAM, - "header found at offset: %d: %02x %02x 00 %02x %02x %02x\n", + "header found at offset: %d: %02x %02x 00 %3ph\n", i - 1, data[i - 4], data[i - 3], - data[i], - data[i + 1], - data[i + 2]); + &data[i]); else PDEBUG(D_FRAM, - "header found at offset: %d: 00 %02x %02x %02x\n", + "header found at offset: %d: 00 %3ph\n", i - 1, - data[i], - data[i + 1], - data[i + 2]); + &data[i]); return data + i + (sd->sof_len - 1); } break; diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c index cbfc2f92142..d3e1b6d8bf4 100644 --- a/drivers/media/usb/gspca/zc3xx.c +++ b/drivers/media/usb/gspca/zc3xx.c @@ -6700,7 +6700,8 @@ static int sd_start(struct gspca_dev *gspca_dev) }; /* create the JPEG header */ - jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, + jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, + gspca_dev->pixfmt.width, 0x21); /* JPEG 422 */ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; @@ -6904,7 +6905,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, #if IS_ENABLED(CONFIG_INPUT) static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* interrupt packet data */ - int len) /* interrput packet length */ + int len) /* interrupt packet length */ { if (len == 8 && data[4] == 1) { input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 6e5070774dc..c5638964c3f 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -78,7 +78,8 @@ void hdpvr_delete(struct hdpvr_device *dev) static void challenge(u8 *bytes) { - u64 *i64P, tmp64; + __le64 *i64P; + u64 tmp64; uint i, idx; for (idx = 0; idx < 32; ++idx) { @@ -106,10 +107,10 @@ static void challenge(u8 *bytes) for (i = 0; i < 3; i++) bytes[1] *= bytes[6] + 1; for (i = 0; i < 3; i++) { - i64P = (u64 *)bytes; + i64P = (__le64 *)bytes; tmp64 = le64_to_cpup(i64P); - tmp64 <<= bytes[7] & 0x0f; - *i64P += cpu_to_le64(tmp64); + tmp64 = tmp64 + (tmp64 << (bytes[7] & 0x0f)); + *i64P = cpu_to_le64(tmp64); } break; } @@ -197,7 +198,6 @@ static int device_authorization(struct hdpvr_device *dev) hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n", print_buf); - kfree(print_buf); #endif msleep(100); @@ -213,6 +213,9 @@ static int device_authorization(struct hdpvr_device *dev) retval = ret != 8; unlock: mutex_unlock(&dev->usbc_mutex); +#ifdef HDPVR_DEBUG + kfree(print_buf); +#endif return retval; } @@ -301,8 +304,6 @@ static int hdpvr_probe(struct usb_interface *interface, goto error; } - dev->workqueue = 0; - /* init video transfer queues first of all */ /* to prevent oops in hdpvr_delete() on error paths */ INIT_LIST_HEAD(&dev->free_buff_list); diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 0500c4175d5..6bce01a674f 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -82,7 +82,7 @@ static void hdpvr_read_bulk_callback(struct urb *urb) } /*=========================================================================*/ -/* bufffer bits */ +/* buffer bits */ /* function expects dev->io_mutex to be hold by caller */ int hdpvr_cancel_queue(struct hdpvr_device *dev) @@ -926,7 +926,7 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_AUDIO_ENCODING: if (dev->flags & HDPVR_FLAG_AC3_CAP) { opt->audio_codec = ctrl->val; - return hdpvr_set_audio(dev, opt->audio_input, + return hdpvr_set_audio(dev, opt->audio_input + 1, opt->audio_codec); } return 0; @@ -1198,7 +1198,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, V4L2_CID_MPEG_AUDIO_ENCODING, ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC, - 0x7, V4L2_MPEG_AUDIO_ENCODING_AAC); + 0x7, ac3 ? dev->options.audio_codec : V4L2_MPEG_AUDIO_ENCODING_AAC); v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, V4L2_CID_MPEG_VIDEO_ENCODING, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3, diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index c4d51d78f83..9623b621821 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -2868,7 +2868,7 @@ static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id, pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \ } -v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw) +static v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw) { v4l2_std_id std; std = (v4l2_std_id)hdw->std_mask_avail; @@ -2910,7 +2910,7 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw) v4l2_std_id vs; vs = hdw->std_mask_cur; v4l2_device_call_all(&hdw->v4l2_dev, 0, - core, s_std, vs); + video, s_std, vs); pvr2_hdw_cx25840_vbi_hack(hdw); } hdw->tuner_signal_stale = !0; diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 77bbf788965..a73b0bced96 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -614,17 +614,20 @@ static int buffer_prepare(struct vb2_buffer *vb) return 0; } -static int buffer_finish(struct vb2_buffer *vb) +static void buffer_finish(struct vb2_buffer *vb) { struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); - /* - * Application has called dqbuf and is getting back a buffer we've - * filled, take the pwc data we've stored in buf->data and decompress - * it into a usable format, storing the result in the vb2_buffer - */ - return pwc_decompress(pdev, buf); + if (vb->state == VB2_BUF_STATE_DONE) { + /* + * Application has called dqbuf and is getting back a buffer + * we've filled, take the pwc data we've stored in buf->data + * and decompress it into a usable format, storing the result + * in the vb2_buffer. + */ + pwc_decompress(pdev, buf); + } } static void buffer_cleanup(struct vb2_buffer *vb) @@ -678,12 +681,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) return r; } -static int stop_streaming(struct vb2_queue *vq) +static void stop_streaming(struct vb2_queue *vq) { struct pwc_device *pdev = vb2_get_drv_priv(vq); - if (mutex_lock_interruptible(&pdev->v4l2_lock)) - return -ERESTARTSYS; + mutex_lock(&pdev->v4l2_lock); if (pdev->udev) { pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); @@ -692,8 +694,6 @@ static int stop_streaming(struct vb2_queue *vq) pwc_cleanup_queued_bufs(pdev); mutex_unlock(&pdev->v4l2_lock); - - return 0; } static struct vb2_ops pwc_vb_queue_ops = { @@ -1001,7 +1001,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf); pdev->vb_queue.ops = &pwc_vb_queue_ops; pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; - pdev->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(&pdev->vb_queue); if (rc < 0) { PWC_ERROR("Oops, could not initialize vb2 queue.\n"); @@ -1039,7 +1039,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id /* Set the leds off */ pwc_set_leds(pdev, 0, 0); - /* Setup intial videomode */ + /* Setup initial videomode */ rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT, V4L2_PIX_FMT_YUV420, 30, &compression, 1); if (rc) @@ -1078,7 +1078,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id /* register webcam snapshot button input device */ pdev->button_dev = input_allocate_device(); if (!pdev->button_dev) { - PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); rc = -ENOMEM; goto err_video_unreg; } diff --git a/drivers/media/usb/s2255/Kconfig b/drivers/media/usb/s2255/Kconfig index 7e8ee1f864a..8c3fceef9a0 100644 --- a/drivers/media/usb/s2255/Kconfig +++ b/drivers/media/usb/s2255/Kconfig @@ -1,7 +1,7 @@ config USB_S2255 tristate "USB Sensoray 2255 video capture device" depends on VIDEO_V4L2 - select VIDEOBUF_VMALLOC + select VIDEOBUF2_VMALLOC default n help Say Y here if you want support for the Sensoray 2255 USB device. diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 6bc9b8e19e2..a44466bc7b8 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1,7 +1,7 @@ /* * s2255drv.c - a driver for the Sensoray 2255 USB video capture device * - * Copyright (C) 2007-2013 by Sensoray Company Inc. + * Copyright (C) 2007-2014 by Sensoray Company Inc. * Dean Anderson * * Some video buffer code based on vivi driver: @@ -45,14 +45,14 @@ #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/usb.h> -#include <media/videobuf-vmalloc.h> +#include <media/videobuf2-vmalloc.h> #include <media/v4l2-common.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-event.h> -#define S2255_VERSION "1.23.1" +#define S2255_VERSION "1.25.1" #define FIRMWARE_FILE_NAME "f2255usb.bin" /* default JPEG quality */ @@ -69,7 +69,7 @@ #define S2255_DSP_BOOTTIME 800 /* maximum time to wait for firmware to load (ms) */ #define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME) -#define S2255_DEF_BUFS 16 +#define S2255_MIN_BUFS 2 #define S2255_SETMODE_TIMEOUT 500 #define S2255_VIDSTATUS_TIMEOUT 350 #define S2255_MARKER_FRAME cpu_to_le32(0x2255DA4AL) @@ -178,11 +178,6 @@ struct s2255_bufferi { DEF_FDEC, DEF_BRIGHT, DEF_CONTRAST, DEF_SATURATION, \ DEF_HUE, 0, DEF_USB_BLOCK, 0} -struct s2255_dmaqueue { - struct list_head active; - struct s2255_dev *dev; -}; - /* for firmware loading, fw_state */ #define S2255_FW_NOTLOADED 0 #define S2255_FW_LOADED_DSPWAIT 1 @@ -217,12 +212,14 @@ struct s2255_pipeinfo { struct s2255_fmt; /*forward declaration */ struct s2255_dev; -struct s2255_channel { +/* 2255 video channel */ +struct s2255_vc { + struct s2255_dev *dev; struct video_device vdev; struct v4l2_ctrl_handler hdl; struct v4l2_ctrl *jpegqual_ctrl; int resources; - struct s2255_dmaqueue vidq; + struct list_head buf_list; struct s2255_bufferi buffer; struct s2255_mode mode; v4l2_std_id std; @@ -232,8 +229,6 @@ struct s2255_channel { struct v4l2_captureparm cap_parm; int cur_frame; int last_frame; - - int b_acquire; /* allocated image size */ unsigned long req_image_size; /* received packet size */ @@ -252,17 +247,22 @@ struct s2255_channel { int vidstatus_ready; unsigned int width; unsigned int height; + enum v4l2_field field; const struct s2255_fmt *fmt; int idx; /* channel number on device, 0-3 */ + struct vb2_queue vb_vidq; + struct mutex vb_lock; /* streaming lock */ + spinlock_t qlock; }; struct s2255_dev { - struct s2255_channel channel[MAX_CHANNELS]; - struct v4l2_device v4l2_dev; + struct s2255_vc vc[MAX_CHANNELS]; + struct v4l2_device v4l2_dev; atomic_t num_channels; int frames; struct mutex lock; /* channels[].vdev.lock */ + struct mutex cmdlock; /* protects cmdbuf */ struct usb_device *udev; struct usb_interface *interface; u8 read_endpoint; @@ -272,10 +272,11 @@ struct s2255_dev { u32 cc; /* current channel */ int frame_ready; int chn_ready; - spinlock_t slock; /* dsp firmware version (f2255usb.bin) */ int dsp_fw_ver; u16 pid; /* product id */ +#define S2255_CMDBUF_SIZE 512 + __le32 *cmdbuf; }; static inline struct s2255_dev *to_s2255_dev(struct v4l2_device *v4l2_dev) @@ -292,19 +293,10 @@ struct s2255_fmt { /* buffer for one video frame */ struct s2255_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - const struct s2255_fmt *fmt; + struct vb2_buffer vb; + struct list_head list; }; -struct s2255_fh { - /* this must be the first field in this struct */ - struct v4l2_fh fh; - struct s2255_dev *dev; - struct videobuf_queue vb_vidq; - enum v4l2_buf_type type; - struct s2255_channel *channel; - int resources; -}; /* current cypress EEPROM firmware version */ #define S2255_CUR_USB_FWVER ((3 << 8) | 12) @@ -352,15 +344,14 @@ struct s2255_fh { static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; static int debug; -static int *s2255_debug = &debug; static int s2255_start_readpipe(struct s2255_dev *dev); static void s2255_stop_readpipe(struct s2255_dev *dev); -static int s2255_start_acquire(struct s2255_channel *channel); -static int s2255_stop_acquire(struct s2255_channel *channel); -static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf, +static int s2255_start_acquire(struct s2255_vc *vc); +static int s2255_stop_acquire(struct s2255_vc *vc); +static void s2255_fillbuff(struct s2255_vc *vc, struct s2255_buffer *buf, int jpgsize); -static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode); +static int s2255_set_mode(struct s2255_vc *vc, struct s2255_mode *mode); static int s2255_board_shutdown(struct s2255_dev *dev); static void s2255_fwload_start(struct s2255_dev *dev, int reset); static void s2255_destroy(struct s2255_dev *dev); @@ -373,19 +364,11 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, #define s2255_dev_err(dev, fmt, arg...) \ dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg) -#define dprintk(level, fmt, arg...) \ - do { \ - if (*s2255_debug >= (level)) { \ - printk(KERN_DEBUG S2255_DRIVER_NAME \ - ": " fmt, ##arg); \ - } \ - } while (0) +#define dprintk(dev, level, fmt, arg...) \ + v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) static struct usb_driver s2255_driver; -/* Declare static vars that will be used as parameters */ -static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ - /* start video number */ static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ @@ -394,8 +377,6 @@ static int jpeg_enable = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level(0-100) default 0"); -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)"); module_param(video_nr, int, 0644); MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)"); module_param(jpeg_enable, int, 0644); @@ -444,27 +425,27 @@ static const struct s2255_fmt formats[] = { } }; -static int norm_maxw(struct s2255_channel *channel) +static int norm_maxw(struct s2255_vc *vc) { - return (channel->std & V4L2_STD_525_60) ? + return (vc->std & V4L2_STD_525_60) ? LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL; } -static int norm_maxh(struct s2255_channel *channel) +static int norm_maxh(struct s2255_vc *vc) { - return (channel->std & V4L2_STD_525_60) ? + return (vc->std & V4L2_STD_525_60) ? (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2); } -static int norm_minw(struct s2255_channel *channel) +static int norm_minw(struct s2255_vc *vc) { - return (channel->std & V4L2_STD_525_60) ? + return (vc->std & V4L2_STD_525_60) ? LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL; } -static int norm_minh(struct s2255_channel *channel) +static int norm_minh(struct s2255_vc *vc) { - return (channel->std & V4L2_STD_525_60) ? + return (vc->std & V4L2_STD_525_60) ? (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); } @@ -498,7 +479,7 @@ static void planar422p_to_yuv_packed(const unsigned char *in, static void s2255_reset_dsppower(struct s2255_dev *dev) { s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1); - msleep(10); + msleep(20); s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1); msleep(600); s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1); @@ -510,9 +491,8 @@ static void s2255_reset_dsppower(struct s2255_dev *dev) static void s2255_timer(unsigned long user_data) { struct s2255_fw *data = (struct s2255_fw *)user_data; - dprintk(100, "%s\n", __func__); if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { - printk(KERN_ERR "s2255: can't submit urb\n"); + pr_err("s2255: can't submit urb\n"); atomic_set(&data->fw_state, S2255_FW_FAILED); /* wake up anything waiting for the firmware */ wake_up(&data->wait_fw); @@ -532,7 +512,6 @@ static void s2255_fwchunk_complete(struct urb *urb) struct s2255_fw *data = urb->context; struct usb_device *udev = urb->dev; int len; - dprintk(100, "%s: udev %p urb %p", __func__, udev, urb); if (urb->status) { dev_err(&udev->dev, "URB failed with status %d\n", urb->status); atomic_set(&data->fw_state, S2255_FW_FAILED); @@ -559,9 +538,6 @@ static void s2255_fwchunk_complete(struct urb *urb) if (len < CHUNK_SIZE) memset(data->pfw_data, 0, CHUNK_SIZE); - dprintk(100, "completed len %d, loaded %d \n", len, - data->fw_loaded); - memcpy(data->pfw_data, (char *) data->fw->data + data->fw_loaded, len); @@ -576,36 +552,32 @@ static void s2255_fwchunk_complete(struct urb *urb) return; } data->fw_loaded += len; - } else { + } else atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); - dprintk(100, "%s: firmware upload complete\n", __func__); - } return; } -static int s2255_got_frame(struct s2255_channel *channel, int jpgsize) +static int s2255_got_frame(struct s2255_vc *vc, int jpgsize) { - struct s2255_dmaqueue *dma_q = &channel->vidq; struct s2255_buffer *buf; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); + struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); unsigned long flags = 0; int rc = 0; - spin_lock_irqsave(&dev->slock, flags); - if (list_empty(&dma_q->active)) { - dprintk(1, "No active queue to serve\n"); + spin_lock_irqsave(&vc->qlock, flags); + if (list_empty(&vc->buf_list)) { + dprintk(dev, 1, "No active queue to serve\n"); rc = -1; goto unlock; } - buf = list_entry(dma_q->active.next, - struct s2255_buffer, vb.queue); - list_del(&buf->vb.queue); - v4l2_get_timestamp(&buf->vb.ts); - s2255_fillbuff(channel, buf, jpgsize); - wake_up(&buf->vb.done); - dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i); + buf = list_entry(vc->buf_list.next, + struct s2255_buffer, list); + list_del(&buf->list); + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + s2255_fillbuff(vc, buf, jpgsize); + dprintk(dev, 2, "%s: [buf] [%p]\n", __func__, buf); unlock: - spin_unlock_irqrestore(&dev->slock, flags); + spin_unlock_irqrestore(&vc->qlock, flags); return rc; } @@ -615,9 +587,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc) for (i = 0; i < ARRAY_SIZE(formats); i++) { if (-1 == formats[i].fourcc) continue; - if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || - (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) - continue; + if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || + (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) + continue; if (formats[i].fourcc == fourcc) return formats + i; } @@ -632,56 +604,56 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc) * http://v4l.videotechnology.com/ * */ -static void s2255_fillbuff(struct s2255_channel *channel, +static void s2255_fillbuff(struct s2255_vc *vc, struct s2255_buffer *buf, int jpgsize) { int pos = 0; const char *tmpbuf; - char *vbuf = videobuf_to_vmalloc(&buf->vb); + char *vbuf = vb2_plane_vaddr(&buf->vb, 0); unsigned long last_frame; + struct s2255_dev *dev = vc->dev; if (!vbuf) return; - last_frame = channel->last_frame; + last_frame = vc->last_frame; if (last_frame != -1) { tmpbuf = - (const char *)channel->buffer.frame[last_frame].lpvbits; - switch (buf->fmt->fourcc) { + (const char *)vc->buffer.frame[last_frame].lpvbits; + switch (vc->fmt->fourcc) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: planar422p_to_yuv_packed((const unsigned char *)tmpbuf, - vbuf, buf->vb.width, - buf->vb.height, - buf->fmt->fourcc); + vbuf, vc->width, + vc->height, + vc->fmt->fourcc); break; case V4L2_PIX_FMT_GREY: - memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height); + memcpy(vbuf, tmpbuf, vc->width * vc->height); break; case V4L2_PIX_FMT_JPEG: case V4L2_PIX_FMT_MJPEG: - buf->vb.size = jpgsize; - memcpy(vbuf, tmpbuf, buf->vb.size); + buf->vb.v4l2_buf.length = jpgsize; + memcpy(vbuf, tmpbuf, jpgsize); break; case V4L2_PIX_FMT_YUV422P: memcpy(vbuf, tmpbuf, - buf->vb.width * buf->vb.height * 2); + vc->width * vc->height * 2); break; default: - printk(KERN_DEBUG "s2255: unknown format?\n"); + pr_info("s2255: unknown format?\n"); } - channel->last_frame = -1; + vc->last_frame = -1; } else { - printk(KERN_ERR "s2255: =======no frame\n"); + pr_err("s2255: =======no frame\n"); return; - } - dprintk(2, "s2255fill at : Buffer 0x%08lx size= %d\n", + dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n", (unsigned long)vbuf, pos); /* tell v4l buffer was filled */ - - buf->vb.field_count = channel->frame_count * 2; - v4l2_get_timestamp(&buf->vb.ts); - buf->vb.state = VIDEOBUF_DONE; + buf->vb.v4l2_buf.field = vc->field; + buf->vb.v4l2_buf.sequence = vc->frame_count; + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } @@ -689,144 +661,82 @@ static void s2255_fillbuff(struct s2255_channel *channel, Videobuf operations ------------------------------------------------------------------*/ -static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct s2255_fh *fh = vq->priv_data; - struct s2255_channel *channel = fh->channel; - *size = channel->width * channel->height * (channel->fmt->depth >> 3); - - if (0 == *count) - *count = S2255_DEF_BUFS; - - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; - + struct s2255_vc *vc = vb2_get_drv_priv(vq); + if (*nbuffers < S2255_MIN_BUFS) + *nbuffers = S2255_MIN_BUFS; + *nplanes = 1; + sizes[0] = vc->width * vc->height * (vc->fmt->depth >> 3); return 0; } -static void free_buffer(struct videobuf_queue *vq, struct s2255_buffer *buf) -{ - dprintk(4, "%s\n", __func__); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) +static int buffer_prepare(struct vb2_buffer *vb) { - struct s2255_fh *fh = vq->priv_data; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue); struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); - int rc; - int w = channel->width; - int h = channel->height; - dprintk(4, "%s, field=%d\n", __func__, field); - if (channel->fmt == NULL) + int w = vc->width; + int h = vc->height; + unsigned long size; + + dprintk(vc->dev, 4, "%s\n", __func__); + if (vc->fmt == NULL) return -EINVAL; - if ((w < norm_minw(channel)) || - (w > norm_maxw(channel)) || - (h < norm_minh(channel)) || - (h > norm_maxh(channel))) { - dprintk(4, "invalid buffer prepare\n"); + if ((w < norm_minw(vc)) || + (w > norm_maxw(vc)) || + (h < norm_minh(vc)) || + (h > norm_maxh(vc))) { + dprintk(vc->dev, 4, "invalid buffer prepare\n"); return -EINVAL; } - buf->vb.size = w * h * (channel->fmt->depth >> 3); - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) { - dprintk(4, "invalid buffer prepare\n"); + size = w * h * (vc->fmt->depth >> 3); + if (vb2_plane_size(vb, 0) < size) { + dprintk(vc->dev, 4, "invalid buffer prepare\n"); return -EINVAL; } - buf->fmt = channel->fmt; - buf->vb.width = w; - buf->vb.height = h; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; + vb2_set_plane_payload(&buf->vb, 0, size); return 0; -fail: - free_buffer(vq, buf); - return rc; } -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); - struct s2255_fh *fh = vq->priv_data; - struct s2255_channel *channel = fh->channel; - struct s2255_dmaqueue *vidq = &channel->vidq; - dprintk(1, "%s\n", __func__); - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); + struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue); + unsigned long flags = 0; + dprintk(vc->dev, 1, "%s\n", __func__); + spin_lock_irqsave(&vc->qlock, flags); + list_add_tail(&buf->list, &vc->buf_list); + spin_unlock_irqrestore(&vc->qlock, flags); } -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb); - struct s2255_fh *fh = vq->priv_data; - dprintk(4, "%s %d\n", __func__, fh->channel->idx); - free_buffer(vq, buf); -} +static int start_streaming(struct vb2_queue *vq, unsigned int count); +static void stop_streaming(struct vb2_queue *vq); -static struct videobuf_queue_ops s2255_video_qops = { - .buf_setup = buffer_setup, +static struct vb2_ops s2255_video_qops = { + .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .buf_release = buffer_release, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; - -static int res_get(struct s2255_fh *fh) -{ - struct s2255_channel *channel = fh->channel; - /* is it free? */ - if (channel->resources) - return 0; /* no, someone else uses it */ - /* it's free, grab it */ - channel->resources = 1; - fh->resources = 1; - dprintk(1, "s2255: res: get\n"); - return 1; -} - -static int res_locked(struct s2255_fh *fh) -{ - return fh->channel->resources; -} - -static int res_check(struct s2255_fh *fh) -{ - return fh->resources; -} - - -static void res_free(struct s2255_fh *fh) -{ - struct s2255_channel *channel = fh->channel; - channel->resources = 0; - fh->resources = 0; - dprintk(1, "res: put\n"); -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct s2255_fh *fh = file->private_data; - struct s2255_dev *dev = fh->dev; + struct s2255_vc *vc = video_drvdata(file); + struct s2255_dev *dev = vc->dev; strlcpy(cap->driver, "s2255", sizeof(cap->driver)); strlcpy(cap->card, "s2255", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -841,7 +751,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) return -EINVAL; - dprintk(4, "name %s\n", formats[index].name); strlcpy(f->description, formats[index].name, sizeof(f->description)); f->pixelformat = formats[index].fourcc; return 0; @@ -850,19 +759,18 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - int is_ntsc = channel->std & V4L2_STD_525_60; + struct s2255_vc *vc = video_drvdata(file); + int is_ntsc = vc->std & V4L2_STD_525_60; - f->fmt.pix.width = channel->width; - f->fmt.pix.height = channel->height; + f->fmt.pix.width = vc->width; + f->fmt.pix.height = vc->height; if (f->fmt.pix.height >= (is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2) f->fmt.pix.field = V4L2_FIELD_INTERLACED; else f->fmt.pix.field = V4L2_FIELD_TOP; - f->fmt.pix.pixelformat = channel->fmt->fourcc; - f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3); + f->fmt.pix.pixelformat = vc->fmt->fourcc; + f->fmt.pix.bytesperline = f->fmt.pix.width * (vc->fmt->depth >> 3); f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; @@ -874,9 +782,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { const struct s2255_fmt *fmt; enum v4l2_field field; - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - int is_ntsc = channel->std & V4L2_STD_525_60; + struct s2255_vc *vc = video_drvdata(file); + int is_ntsc = vc->std & V4L2_STD_525_60; fmt = format_by_fourcc(f->fmt.pix.pixelformat); @@ -885,7 +792,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, field = f->fmt.pix.field; - dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n", + dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n", __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height); if (is_ntsc) { /* NTSC */ @@ -927,7 +834,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; - dprintk(50, "%s: set width %d height %d field %d\n", __func__, + dprintk(vc->dev, 50, "%s: set width %d height %d field %d\n", __func__, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); return 0; } @@ -935,14 +842,13 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = video_drvdata(file); const struct s2255_fmt *fmt; - struct videobuf_queue *q = &fh->vb_vidq; + struct vb2_queue *q = &vc->vb_vidq; struct s2255_mode mode; int ret; - ret = vidioc_try_fmt_vid_cap(file, fh, f); + ret = vidioc_try_fmt_vid_cap(file, vc, f); if (ret < 0) return ret; @@ -952,28 +858,19 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (fmt == NULL) return -EINVAL; - mutex_lock(&q->vb_lock); - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { - dprintk(1, "queue busy\n"); - ret = -EBUSY; - goto out_s_fmt; + if (vb2_is_busy(q)) { + dprintk(vc->dev, 1, "queue busy\n"); + return -EBUSY; } - if (res_locked(fh)) { - dprintk(1, "%s: channel busy\n", __func__); - ret = -EBUSY; - goto out_s_fmt; - } - mode = channel->mode; - channel->fmt = fmt; - channel->width = f->fmt.pix.width; - channel->height = f->fmt.pix.height; - fh->vb_vidq.field = f->fmt.pix.field; - fh->type = f->type; - if (channel->width > norm_minw(channel)) { - if (channel->height > norm_minh(channel)) { - if (channel->cap_parm.capturemode & + mode = vc->mode; + vc->fmt = fmt; + vc->width = f->fmt.pix.width; + vc->height = f->fmt.pix.height; + vc->field = f->fmt.pix.field; + if (vc->width > norm_minw(vc)) { + if (vc->height > norm_minh(vc)) { + if (vc->cap_parm.capturemode & V4L2_MODE_HIGHQUALITY) mode.scale = SCALE_4CIFSI; else @@ -985,7 +882,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, mode.scale = SCALE_1CIFS; } /* color mode */ - switch (channel->fmt->fourcc) { + switch (vc->fmt->fourcc) { case V4L2_PIX_FMT_GREY: mode.color &= ~MASK_COLOR; mode.color |= COLOR_Y8; @@ -994,7 +891,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, case V4L2_PIX_FMT_MJPEG: mode.color &= ~MASK_COLOR; mode.color |= COLOR_JPG; - mode.color |= (channel->jpegqual << 8); + mode.color |= (vc->jpegqual << 8); break; case V4L2_PIX_FMT_YUV422P: mode.color &= ~MASK_COLOR; @@ -1007,52 +904,17 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, mode.color |= COLOR_YUVPK; break; } - if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR)) + if ((mode.color & MASK_COLOR) != (vc->mode.color & MASK_COLOR)) mode.restart = 1; - else if (mode.scale != channel->mode.scale) + else if (mode.scale != vc->mode.scale) mode.restart = 1; - else if (mode.format != channel->mode.format) + else if (mode.format != vc->mode.format) mode.restart = 1; - channel->mode = mode; - (void) s2255_set_mode(channel, &mode); - ret = 0; -out_s_fmt: - mutex_unlock(&q->vb_lock); - return ret; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - int rc; - struct s2255_fh *fh = priv; - rc = videobuf_reqbufs(&fh->vb_vidq, p); - return rc; -} - -static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int rc; - struct s2255_fh *fh = priv; - rc = videobuf_querybuf(&fh->vb_vidq, p); - return rc; -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int rc; - struct s2255_fh *fh = priv; - rc = videobuf_qbuf(&fh->vb_vidq, p); - return rc; + vc->mode = mode; + (void) s2255_set_mode(vc, &mode); + return 0; } -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - int rc; - struct s2255_fh *fh = priv; - rc = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK); - return rc; -} /* write to the configuration pipe, synchronously */ static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, @@ -1150,201 +1012,165 @@ static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode) * When the restart parameter is set, we sleep for ONE frame to allow the * DSP time to get the new frame */ -static int s2255_set_mode(struct s2255_channel *channel, +static int s2255_set_mode(struct s2255_vc *vc, struct s2255_mode *mode) { int res; - __le32 *buffer; unsigned long chn_rev; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); + struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); int i; + __le32 *buffer = dev->cmdbuf; - chn_rev = G_chnmap[channel->idx]; - dprintk(3, "%s channel: %d\n", __func__, channel->idx); + mutex_lock(&dev->cmdlock); + chn_rev = G_chnmap[vc->idx]; + dprintk(dev, 3, "%s channel: %d\n", __func__, vc->idx); /* if JPEG, set the quality */ if ((mode->color & MASK_COLOR) == COLOR_JPG) { mode->color &= ~MASK_COLOR; mode->color |= COLOR_JPG; mode->color &= ~MASK_JPG_QUALITY; - mode->color |= (channel->jpegqual << 8); + mode->color |= (vc->jpegqual << 8); } /* save the mode */ - channel->mode = *mode; - channel->req_image_size = get_transfer_size(mode); - dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size); - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } + vc->mode = *mode; + vc->req_image_size = get_transfer_size(mode); + dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size); /* set the mode */ buffer[0] = IN_DATA_TOKEN; buffer[1] = (__le32) cpu_to_le32(chn_rev); buffer[2] = CMD_SET_MODE; for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++) - buffer[3 + i] = cpu_to_le32(((u32 *)&channel->mode)[i]); - channel->setmode_ready = 0; + buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]); + vc->setmode_ready = 0; res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); if (debug) s2255_print_cfg(dev, mode); - kfree(buffer); /* wait at least 3 frames before continuing */ if (mode->restart) { - wait_event_timeout(channel->wait_setmode, - (channel->setmode_ready != 0), + wait_event_timeout(vc->wait_setmode, + (vc->setmode_ready != 0), msecs_to_jiffies(S2255_SETMODE_TIMEOUT)); - if (channel->setmode_ready != 1) { - printk(KERN_DEBUG "s2255: no set mode response\n"); + if (vc->setmode_ready != 1) { + dprintk(dev, 0, "s2255: no set mode response\n"); res = -EFAULT; } } /* clear the restart flag */ - channel->mode.restart = 0; - dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res); + vc->mode.restart = 0; + dprintk(dev, 1, "%s chn %d, result: %d\n", __func__, vc->idx, res); + mutex_unlock(&dev->cmdlock); return res; } -static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus) +static int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus) { int res; - __le32 *buffer; u32 chn_rev; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - chn_rev = G_chnmap[channel->idx]; - dprintk(4, "%s chan %d\n", __func__, channel->idx); - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } + struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); + __le32 *buffer = dev->cmdbuf; + + mutex_lock(&dev->cmdlock); + chn_rev = G_chnmap[vc->idx]; + dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx); /* form the get vid status command */ buffer[0] = IN_DATA_TOKEN; buffer[1] = (__le32) cpu_to_le32(chn_rev); buffer[2] = CMD_STATUS; *pstatus = 0; - channel->vidstatus_ready = 0; + vc->vidstatus_ready = 0; res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); - kfree(buffer); - wait_event_timeout(channel->wait_vidstatus, - (channel->vidstatus_ready != 0), + wait_event_timeout(vc->wait_vidstatus, + (vc->vidstatus_ready != 0), msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT)); - if (channel->vidstatus_ready != 1) { - printk(KERN_DEBUG "s2255: no vidstatus response\n"); + if (vc->vidstatus_ready != 1) { + dprintk(dev, 0, "s2255: no vidstatus response\n"); res = -EFAULT; } - *pstatus = channel->vidstatus; - dprintk(4, "%s, vid status %d\n", __func__, *pstatus); + *pstatus = vc->vidstatus; + dprintk(dev, 4, "%s, vid status %d\n", __func__, *pstatus); + mutex_unlock(&dev->cmdlock); return res; } -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +static int start_streaming(struct vb2_queue *vq, unsigned int count) { - int res; - struct s2255_fh *fh = priv; - struct s2255_dev *dev = fh->dev; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = vb2_get_drv_priv(vq); int j; - dprintk(4, "%s\n", __func__); - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&dev->udev->dev, "invalid fh type0\n"); - return -EINVAL; - } - if (i != fh->type) { - dev_err(&dev->udev->dev, "invalid fh type1\n"); - return -EINVAL; - } - if (!res_get(fh)) { - s2255_dev_err(&dev->udev->dev, "stream busy\n"); - return -EBUSY; - } - channel->last_frame = -1; - channel->bad_payload = 0; - channel->cur_frame = 0; - channel->frame_count = 0; + vc->last_frame = -1; + vc->bad_payload = 0; + vc->cur_frame = 0; + vc->frame_count = 0; for (j = 0; j < SYS_FRAMES; j++) { - channel->buffer.frame[j].ulState = S2255_READ_IDLE; - channel->buffer.frame[j].cur_size = 0; + vc->buffer.frame[j].ulState = S2255_READ_IDLE; + vc->buffer.frame[j].cur_size = 0; } - res = videobuf_streamon(&fh->vb_vidq); - if (res == 0) { - s2255_start_acquire(channel); - channel->b_acquire = 1; - } else - res_free(fh); - - return res; + return s2255_start_acquire(vc); } -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +/* abort streaming and wait for last buffer */ +static void stop_streaming(struct vb2_queue *vq) { - struct s2255_fh *fh = priv; - dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx); - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - printk(KERN_ERR "invalid fh type0\n"); - return -EINVAL; + struct s2255_vc *vc = vb2_get_drv_priv(vq); + struct s2255_buffer *buf, *node; + unsigned long flags; + (void) s2255_stop_acquire(vc); + spin_lock_irqsave(&vc->qlock, flags); + list_for_each_entry_safe(buf, node, &vc->buf_list, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + dprintk(vc->dev, 2, "[%p/%d] done\n", + buf, buf->vb.v4l2_buf.index); } - if (i != fh->type) { - printk(KERN_ERR "invalid type i\n"); - return -EINVAL; - } - s2255_stop_acquire(fh->channel); - videobuf_streamoff(&fh->vb_vidq); - res_free(fh); - return 0; + spin_unlock_irqrestore(&vc->qlock, flags); } static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i) { - struct s2255_fh *fh = priv; + struct s2255_vc *vc = video_drvdata(file); struct s2255_mode mode; - struct videobuf_queue *q = &fh->vb_vidq; - struct s2255_channel *channel = fh->channel; - int ret = 0; + struct vb2_queue *q = &vc->vb_vidq; - mutex_lock(&q->vb_lock); - if (res_locked(fh)) { - dprintk(1, "can't change standard after started\n"); - ret = -EBUSY; - goto out_s_std; - } - mode = fh->channel->mode; + /* + * Changing the standard implies a format change, which is not allowed + * while buffers for use with streaming have already been allocated. + */ + if (vb2_is_busy(q)) + return -EBUSY; + + mode = vc->mode; if (i & V4L2_STD_525_60) { - dprintk(4, "%s 60 Hz\n", __func__); + dprintk(vc->dev, 4, "%s 60 Hz\n", __func__); /* if changing format, reset frame decimation/intervals */ if (mode.format != FORMAT_NTSC) { mode.restart = 1; mode.format = FORMAT_NTSC; mode.fdec = FDEC_1; - channel->width = LINE_SZ_4CIFS_NTSC; - channel->height = NUM_LINES_4CIFS_NTSC * 2; + vc->width = LINE_SZ_4CIFS_NTSC; + vc->height = NUM_LINES_4CIFS_NTSC * 2; } } else if (i & V4L2_STD_625_50) { - dprintk(4, "%s 50 Hz\n", __func__); + dprintk(vc->dev, 4, "%s 50 Hz\n", __func__); if (mode.format != FORMAT_PAL) { mode.restart = 1; mode.format = FORMAT_PAL; mode.fdec = FDEC_1; - channel->width = LINE_SZ_4CIFS_PAL; - channel->height = NUM_LINES_4CIFS_PAL * 2; + vc->width = LINE_SZ_4CIFS_PAL; + vc->height = NUM_LINES_4CIFS_PAL * 2; } - } else { - ret = -EINVAL; - goto out_s_std; - } - fh->channel->std = i; + } else + return -EINVAL; + vc->std = i; if (mode.restart) - s2255_set_mode(fh->channel, &mode); -out_s_std: - mutex_unlock(&q->vb_lock); - return ret; + s2255_set_mode(vc, &mode); + return 0; } static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i) { - struct s2255_fh *fh = priv; + struct s2255_vc *vc = video_drvdata(file); - *i = fh->channel->std; + *i = vc->std; return 0; } @@ -1358,10 +1184,10 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { - struct s2255_fh *fh = priv; - struct s2255_dev *dev = fh->dev; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = video_drvdata(file); + struct s2255_dev *dev = vc->dev; u32 status = 0; + if (inp->index != 0) return -EINVAL; inp->type = V4L2_INPUT_TYPE_CAMERA; @@ -1369,8 +1195,9 @@ static int vidioc_enum_input(struct file *file, void *priv, inp->status = 0; if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) { int rc; - rc = s2255_cmd_status(fh->channel, &status); - dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status); + rc = s2255_cmd_status(vc, &status); + dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n", + rc, status); if (rc == 0) inp->status = (status & 0x01) ? 0 : V4L2_IN_ST_NO_SIGNAL; @@ -1381,7 +1208,7 @@ static int vidioc_enum_input(struct file *file, void *priv, strlcpy(inp->name, "Composite", sizeof(inp->name)); break; case 0x2257: - strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video", + strlcpy(inp->name, (vc->idx < 2) ? "Composite" : "S-Video", sizeof(inp->name)); break; } @@ -1402,13 +1229,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) { - struct s2255_channel *channel = - container_of(ctrl->handler, struct s2255_channel, hdl); + struct s2255_vc *vc = + container_of(ctrl->handler, struct s2255_vc, hdl); struct s2255_mode mode; - - mode = channel->mode; - dprintk(4, "%s\n", __func__); - + mode = vc->mode; /* update the mode to the corresponding value */ switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: @@ -1428,7 +1252,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) mode.color |= !ctrl->val << 16; break; case V4L2_CID_JPEG_COMPRESSION_QUALITY: - channel->jpegqual = ctrl->val; + vc->jpegqual = ctrl->val; return 0; default: return -EINVAL; @@ -1438,48 +1262,48 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) some V4L programs restart stream unnecessarily after a s_crtl. */ - s2255_set_mode(channel, &mode); + s2255_set_mode(vc, &mode); return 0; } static int vidioc_g_jpegcomp(struct file *file, void *priv, struct v4l2_jpegcompression *jc) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = video_drvdata(file); memset(jc, 0, sizeof(*jc)); - jc->quality = channel->jpegqual; - dprintk(2, "%s: quality %d\n", __func__, jc->quality); + jc->quality = vc->jpegqual; + dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality); return 0; } static int vidioc_s_jpegcomp(struct file *file, void *priv, const struct v4l2_jpegcompression *jc) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = video_drvdata(file); + if (jc->quality < 0 || jc->quality > 100) return -EINVAL; - v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality); - dprintk(2, "%s: quality %d\n", __func__, jc->quality); + v4l2_ctrl_s_ctrl(vc->jpegqual_ctrl, jc->quality); + dprintk(vc->dev, 2, "%s: quality %d\n", __func__, jc->quality); return 0; } static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *sp) { - struct s2255_fh *fh = priv; __u32 def_num, def_dem; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = video_drvdata(file); + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - sp->parm.capture.capturemode = channel->cap_parm.capturemode; - def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000; - def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000; + sp->parm.capture.capturemode = vc->cap_parm.capturemode; + sp->parm.capture.readbuffers = S2255_MIN_BUFS; + def_num = (vc->mode.format == FORMAT_NTSC) ? 1001 : 1000; + def_dem = (vc->mode.format == FORMAT_NTSC) ? 30000 : 25000; sp->parm.capture.timeperframe.denominator = def_dem; - switch (channel->mode.fdec) { + switch (vc->mode.fdec) { default: case FDEC_1: sp->parm.capture.timeperframe.numerator = def_num; @@ -1494,7 +1318,8 @@ static int vidioc_g_parm(struct file *file, void *priv, sp->parm.capture.timeperframe.numerator = def_num * 5; break; } - dprintk(4, "%s capture mode, %d timeperframe %d/%d\n", __func__, + dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d\n", + __func__, sp->parm.capture.capturemode, sp->parm.capture.timeperframe.numerator, sp->parm.capture.timeperframe.denominator); @@ -1504,17 +1329,16 @@ static int vidioc_g_parm(struct file *file, void *priv, static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *sp) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = video_drvdata(file); struct s2255_mode mode; int fdec = FDEC_1; __u32 def_num, def_dem; if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - mode = channel->mode; + mode = vc->mode; /* high quality capture mode requires a stream restart */ - if (channel->cap_parm.capturemode - != sp->parm.capture.capturemode && res_locked(fh)) + if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode) + && vb2_is_streaming(&vc->vb_vidq)) return -EBUSY; def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000; def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000; @@ -1534,8 +1358,9 @@ static int vidioc_s_parm(struct file *file, void *priv, } mode.fdec = fdec; sp->parm.capture.timeperframe.denominator = def_dem; - s2255_set_mode(channel, &mode); - dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n", + sp->parm.capture.readbuffers = S2255_MIN_BUFS; + s2255_set_mode(vc, &mode); + dprintk(vc->dev, 4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n", __func__, sp->parm.capture.capturemode, sp->parm.capture.timeperframe.numerator, @@ -1558,9 +1383,8 @@ static const struct v4l2_frmsize_discrete pal_sizes[] = { static int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fe) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - int is_ntsc = channel->std & V4L2_STD_525_60; + struct s2255_vc *vc = video_drvdata(file); + int is_ntsc = vc->std & V4L2_STD_525_60; const struct s2255_fmt *fmt; if (fe->index >= NUM_SIZE_ENUMS) @@ -1577,11 +1401,10 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, static int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fe) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; + struct s2255_vc *vc = video_drvdata(file); const struct s2255_fmt *fmt; const struct v4l2_frmsize_discrete *sizes; - int is_ntsc = channel->std & V4L2_STD_525_60; + int is_ntsc = vc->std & V4L2_STD_525_60; #define NUM_FRAME_ENUMS 4 int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5}; int i; @@ -1604,21 +1427,24 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv, fe->type = V4L2_FRMIVAL_TYPE_DISCRETE; fe->discrete.denominator = is_ntsc ? 30000 : 25000; fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index]; - dprintk(4, "%s discrete %d/%d\n", __func__, fe->discrete.numerator, + dprintk(vc->dev, 4, "%s discrete %d/%d\n", __func__, + fe->discrete.numerator, fe->discrete.denominator); return 0; } -static int __s2255_open(struct file *file) +static int s2255_open(struct file *file) { - struct video_device *vdev = video_devdata(file); - struct s2255_channel *channel = video_drvdata(file); - struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); - struct s2255_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + struct s2255_vc *vc = video_drvdata(file); + struct s2255_dev *dev = vc->dev; int state; - dprintk(1, "s2255: open called (dev=%s)\n", - video_device_node_name(vdev)); + int rc = 0; + + rc = v4l2_fh_open(file); + if (rc != 0) + return rc; + + dprintk(dev, 1, "s2255: %s\n", __func__); state = atomic_read(&dev->fw_data->fw_state); switch (state) { case S2255_FW_DISCONNECTING: @@ -1640,7 +1466,7 @@ static int __s2255_open(struct file *file) case S2255_FW_LOADED_DSPWAIT: /* give S2255_LOAD_TIMEOUT time for firmware to load in case driver loaded and then device immediately opened */ - printk(KERN_INFO "%s waiting for firmware load\n", __func__); + pr_info("%s waiting for firmware load\n", __func__); wait_event_timeout(dev->fw_data->wait_fw, ((atomic_read(&dev->fw_data->fw_state) == S2255_FW_SUCCESS) || @@ -1659,16 +1485,15 @@ static int __s2255_open(struct file *file) case S2255_FW_SUCCESS: break; case S2255_FW_FAILED: - printk(KERN_INFO "2255 firmware load failed.\n"); + pr_info("2255 firmware load failed.\n"); return -ENODEV; case S2255_FW_DISCONNECTING: - printk(KERN_INFO "%s: disconnecting\n", __func__); + pr_info("%s: disconnecting\n", __func__); return -ENODEV; case S2255_FW_LOADED_DSPWAIT: case S2255_FW_NOTLOADED: - printk(KERN_INFO "%s: firmware not loaded yet" - "please try again later\n", - __func__); + pr_info("%s: firmware not loaded, please retry\n", + __func__); /* * Timeout on firmware load means device unusable. * Set firmware failure state. @@ -1678,75 +1503,25 @@ static int __s2255_open(struct file *file) S2255_FW_FAILED); return -EAGAIN; default: - printk(KERN_INFO "%s: unknown state\n", __func__); + pr_info("%s: unknown state\n", __func__); return -EFAULT; } - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - v4l2_fh_init(&fh->fh, vdev); - v4l2_fh_add(&fh->fh); - file->private_data = &fh->fh; - fh->dev = dev; - fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fh->channel = channel; - if (!channel->configured) { + if (!vc->configured) { /* configure channel to default state */ - channel->fmt = &formats[0]; - s2255_set_mode(channel, &channel->mode); - channel->configured = 1; - } - dprintk(1, "%s: dev=%s type=%s\n", __func__, - video_device_node_name(vdev), v4l2_type_names[type]); - dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__, - (unsigned long)fh, (unsigned long)dev, - (unsigned long)&channel->vidq); - dprintk(4, "%s: list_empty active=%d\n", __func__, - list_empty(&channel->vidq.active)); - videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops, - NULL, &dev->slock, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct s2255_buffer), - fh, vdev->lock); + vc->fmt = &formats[0]; + s2255_set_mode(vc, &vc->mode); + vc->configured = 1; + } return 0; } -static int s2255_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - int ret; - - if (mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - ret = __s2255_open(file); - mutex_unlock(vdev->lock); - return ret; -} - -static unsigned int s2255_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct s2255_fh *fh = file->private_data; - struct s2255_dev *dev = fh->dev; - int rc = v4l2_ctrl_poll(file, wait); - - dprintk(100, "%s\n", __func__); - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) - return POLLERR; - mutex_lock(&dev->lock); - rc |= videobuf_poll_stream(file, &fh->vb_vidq, wait); - mutex_unlock(&dev->lock); - return rc; -} - static void s2255_destroy(struct s2255_dev *dev) { + dprintk(dev, 1, "%s", __func__); /* board shutdown stops the read pipe if it is running */ s2255_board_shutdown(dev); /* make sure firmware still not trying to load */ - del_timer(&dev->timer); /* only started in .probe and .open */ + del_timer_sync(&dev->timer); /* only started in .probe and .open */ if (dev->fw_data->fw_urb) { usb_kill_urb(dev->fw_data->fw_urb); usb_free_urb(dev->fw_data->fw_urb); @@ -1760,62 +1535,18 @@ static void s2255_destroy(struct s2255_dev *dev) mutex_destroy(&dev->lock); usb_put_dev(dev->udev); v4l2_device_unregister(&dev->v4l2_dev); - dprintk(1, "%s", __func__); + kfree(dev->cmdbuf); kfree(dev); } -static int s2255_release(struct file *file) -{ - struct s2255_fh *fh = file->private_data; - struct s2255_dev *dev = fh->dev; - struct video_device *vdev = video_devdata(file); - struct s2255_channel *channel = fh->channel; - if (!dev) - return -ENODEV; - mutex_lock(&dev->lock); - /* turn off stream */ - if (res_check(fh)) { - if (channel->b_acquire) - s2255_stop_acquire(fh->channel); - videobuf_streamoff(&fh->vb_vidq); - res_free(fh); - } - videobuf_mmap_free(&fh->vb_vidq); - mutex_unlock(&dev->lock); - dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev)); - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - kfree(fh); - return 0; -} - -static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma) -{ - struct s2255_fh *fh = file->private_data; - struct s2255_dev *dev; - int ret; - - if (!fh) - return -ENODEV; - dev = fh->dev; - dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma); - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); - mutex_unlock(&dev->lock); - dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__, - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret); - return ret; -} - static const struct v4l2_file_operations s2255_fops_v4l = { .owner = THIS_MODULE, .open = s2255_open, - .release = s2255_release, - .poll = s2255_poll, + .release = vb2_fop_release, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = s2255_mmap_v4l, + .mmap = vb2_fop_mmap, + .read = vb2_fop_read, }; static const struct v4l2_ioctl_ops s2255_ioctl_ops = { @@ -1824,17 +1555,17 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_s_jpegcomp = vidioc_s_jpegcomp, .vidioc_g_jpegcomp = vidioc_g_jpegcomp, .vidioc_s_parm = vidioc_s_parm, @@ -1849,13 +1580,14 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { static void s2255_video_device_release(struct video_device *vdev) { struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); - struct s2255_channel *channel = - container_of(vdev, struct s2255_channel, vdev); + struct s2255_vc *vc = + container_of(vdev, struct s2255_vc, vdev); - v4l2_ctrl_handler_free(&channel->hdl); - dprintk(4, "%s, chnls: %d\n", __func__, + dprintk(dev, 4, "%s, chnls: %d\n", __func__, atomic_read(&dev->num_channels)); + v4l2_ctrl_handler_free(&vc->hdl); + if (atomic_dec_and_test(&dev->num_channels)) s2255_destroy(dev); return; @@ -1888,52 +1620,70 @@ static int s2255_probe_v4l(struct s2255_dev *dev) int ret; int i; int cur_nr = video_nr; - struct s2255_channel *channel; + struct s2255_vc *vc; + struct vb2_queue *q; + ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev); if (ret) return ret; /* initialize all video 4 linux */ /* register 4 video devices */ for (i = 0; i < MAX_CHANNELS; i++) { - channel = &dev->channel[i]; - INIT_LIST_HEAD(&channel->vidq.active); + vc = &dev->vc[i]; + INIT_LIST_HEAD(&vc->buf_list); - v4l2_ctrl_handler_init(&channel->hdl, 6); - v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + v4l2_ctrl_handler_init(&vc->hdl, 6); + v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); - v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); - v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); - v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, V4L2_CID_HUE, 0, 255, 1, DEF_HUE); - channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl, + vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, V4L2_CID_JPEG_COMPRESSION_QUALITY, 0, 100, 1, S2255_DEF_JPEG_QUAL); if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && - (dev->pid != 0x2257 || channel->idx <= 1)) - v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL); - if (channel->hdl.error) { - ret = channel->hdl.error; - v4l2_ctrl_handler_free(&channel->hdl); + (dev->pid != 0x2257 || vc->idx <= 1)) + v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl, + NULL); + if (vc->hdl.error) { + ret = vc->hdl.error; + v4l2_ctrl_handler_free(&vc->hdl); dev_err(&dev->udev->dev, "couldn't register control\n"); break; } - channel->vidq.dev = dev; - /* register 4 video devices */ - channel->vdev = template; - channel->vdev.ctrl_handler = &channel->hdl; - channel->vdev.lock = &dev->lock; - channel->vdev.v4l2_dev = &dev->v4l2_dev; - set_bit(V4L2_FL_USE_FH_PRIO, &channel->vdev.flags); - video_set_drvdata(&channel->vdev, channel); + q = &vc->vb_vidq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_READ | VB2_USERPTR; + q->drv_priv = vc; + q->lock = &vc->vb_lock; + q->buf_struct_size = sizeof(struct s2255_buffer); + q->mem_ops = &vb2_vmalloc_memops; + q->ops = &s2255_video_qops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(q); + if (ret != 0) { + dev_err(&dev->udev->dev, + "%s vb2_queue_init 0x%x\n", __func__, ret); + break; + } + /* register video devices */ + vc->vdev = template; + vc->vdev.queue = q; + vc->vdev.ctrl_handler = &vc->hdl; + vc->vdev.lock = &dev->lock; + vc->vdev.v4l2_dev = &dev->v4l2_dev; + set_bit(V4L2_FL_USE_FH_PRIO, &vc->vdev.flags); + video_set_drvdata(&vc->vdev, vc); if (video_nr == -1) - ret = video_register_device(&channel->vdev, + ret = video_register_device(&vc->vdev, VFL_TYPE_GRABBER, video_nr); else - ret = video_register_device(&channel->vdev, + ret = video_register_device(&vc->vdev, VFL_TYPE_GRABBER, cur_nr + i); @@ -1944,18 +1694,18 @@ static int s2255_probe_v4l(struct s2255_dev *dev) } atomic_inc(&dev->num_channels); v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", - video_device_node_name(&channel->vdev)); + video_device_node_name(&vc->vdev)); } - printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n", - S2255_VERSION); + pr_info("Sensoray 2255 V4L driver Revision: %s\n", + S2255_VERSION); /* if no channels registered, return error and probe will fail*/ if (atomic_read(&dev->num_channels) == 0) { v4l2_device_unregister(&dev->v4l2_dev); return ret; } if (atomic_read(&dev->num_channels) != MAX_CHANNELS) - printk(KERN_WARNING "s2255: Not all channels available.\n"); + pr_warn("s2255: Not all channels available.\n"); return 0; } @@ -1981,11 +1731,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) s32 idx = -1; struct s2255_framei *frm; unsigned char *pdata; - struct s2255_channel *channel; - dprintk(100, "buffer to user\n"); - channel = &dev->channel[dev->cc]; - idx = channel->cur_frame; - frm = &channel->buffer.frame[idx]; + struct s2255_vc *vc; + dprintk(dev, 100, "buffer to user\n"); + vc = &dev->vc[dev->cc]; + idx = vc->cur_frame; + frm = &vc->buffer.frame[idx]; if (frm->ulState == S2255_READ_IDLE) { int jj; unsigned int cc; @@ -1997,28 +1747,27 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) { switch (*pdword) { case S2255_MARKER_FRAME: - dprintk(4, "found frame marker at offset:" - " %d [%x %x]\n", jj, pdata[0], - pdata[1]); + dprintk(dev, 4, "marker @ offset: %d [%x %x]\n", + jj, pdata[0], pdata[1]); offset = jj + PREFIX_SIZE; bframe = 1; cc = le32_to_cpu(pdword[1]); if (cc >= MAX_CHANNELS) { - printk(KERN_ERR - "bad channel\n"); + dprintk(dev, 0, + "bad channel\n"); return -EINVAL; } /* reverse it */ dev->cc = G_chnmap[cc]; - channel = &dev->channel[dev->cc]; + vc = &dev->vc[dev->cc]; payload = le32_to_cpu(pdword[3]); - if (payload > channel->req_image_size) { - channel->bad_payload++; + if (payload > vc->req_image_size) { + vc->bad_payload++; /* discard the bad frame */ return -EINVAL; } - channel->pkt_size = payload; - channel->jpg_size = le32_to_cpu(pdword[4]); + vc->pkt_size = payload; + vc->jpg_size = le32_to_cpu(pdword[4]); break; case S2255_MARKER_RESPONSE: @@ -2029,34 +1778,34 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) cc = G_chnmap[le32_to_cpu(pdword[1])]; if (cc >= MAX_CHANNELS) break; - channel = &dev->channel[cc]; + vc = &dev->vc[cc]; switch (pdword[2]) { case S2255_RESPONSE_SETMODE: /* check if channel valid */ /* set mode ready */ - channel->setmode_ready = 1; - wake_up(&channel->wait_setmode); - dprintk(5, "setmode ready %d\n", cc); + vc->setmode_ready = 1; + wake_up(&vc->wait_setmode); + dprintk(dev, 5, "setmode rdy %d\n", cc); break; case S2255_RESPONSE_FW: dev->chn_ready |= (1 << cc); if ((dev->chn_ready & 0x0f) != 0x0f) break; /* all channels ready */ - printk(KERN_INFO "s2255: fw loaded\n"); + pr_info("s2255: fw loaded\n"); atomic_set(&dev->fw_data->fw_state, S2255_FW_SUCCESS); wake_up(&dev->fw_data->wait_fw); break; case S2255_RESPONSE_STATUS: - channel->vidstatus = le32_to_cpu(pdword[3]); - channel->vidstatus_ready = 1; - wake_up(&channel->wait_vidstatus); - dprintk(5, "got vidstatus %x chan %d\n", + vc->vidstatus = le32_to_cpu(pdword[3]); + vc->vidstatus_ready = 1; + wake_up(&vc->wait_vidstatus); + dprintk(dev, 5, "vstat %x chan %d\n", le32_to_cpu(pdword[3]), cc); break; default: - printk(KERN_INFO "s2255 unknown resp\n"); + pr_info("s2255 unknown resp\n"); } default: pdata++; @@ -2068,11 +1817,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) if (!bframe) return -EINVAL; } - channel = &dev->channel[dev->cc]; - idx = channel->cur_frame; - frm = &channel->buffer.frame[idx]; + vc = &dev->vc[dev->cc]; + idx = vc->cur_frame; + frm = &vc->buffer.frame[idx]; /* search done. now find out if should be acquiring on this channel */ - if (!channel->b_acquire) { + if (!vb2_is_streaming(&vc->vb_vidq)) { /* we found a frame, but this channel is turned off */ frm->ulState = S2255_READ_IDLE; return -EINVAL; @@ -2088,7 +1837,7 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) if (frm->lpvbits == NULL) { - dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d", + dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d", frm, dev, dev->cc, idx); return -ENOMEM; } @@ -2097,28 +1846,28 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) copy_size = (pipe_info->cur_transfer_size - offset); - size = channel->pkt_size - PREFIX_SIZE; + size = vc->pkt_size - PREFIX_SIZE; /* sanity check on pdest */ - if ((copy_size + frm->cur_size) < channel->req_image_size) + if ((copy_size + frm->cur_size) < vc->req_image_size) memcpy(pdest, psrc, copy_size); frm->cur_size += copy_size; - dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size); + dprintk(dev, 4, "cur_size: %lu, size: %lu\n", frm->cur_size, size); if (frm->cur_size >= size) { - dprintk(2, "****************[%d]Buffer[%d]full*************\n", + dprintk(dev, 2, "******[%d]Buffer[%d]full*******\n", dev->cc, idx); - channel->last_frame = channel->cur_frame; - channel->cur_frame++; + vc->last_frame = vc->cur_frame; + vc->cur_frame++; /* end of system frame ring buffer, start at zero */ - if ((channel->cur_frame == SYS_FRAMES) || - (channel->cur_frame == channel->buffer.dwFrames)) - channel->cur_frame = 0; + if ((vc->cur_frame == SYS_FRAMES) || + (vc->cur_frame == vc->buffer.dwFrames)) + vc->cur_frame = 0; /* frame ready */ - if (channel->b_acquire) - s2255_got_frame(channel, channel->jpg_size); - channel->frame_count++; + if (vb2_is_streaming(&vc->vb_vidq)) + s2255_got_frame(vc, vc->jpg_size); + vc->frame_count++; frm->ulState = S2255_READ_IDLE; frm->cur_size = 0; @@ -2131,7 +1880,7 @@ static void s2255_read_video_callback(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) { int res; - dprintk(50, "callback read video \n"); + dprintk(dev, 50, "callback read video\n"); if (dev->cc >= MAX_CHANNELS) { dev->cc = 0; @@ -2141,9 +1890,9 @@ static void s2255_read_video_callback(struct s2255_dev *dev, /* otherwise copy to the system buffers */ res = save_frame(dev, pipe_info); if (res != 0) - dprintk(4, "s2255: read callback failed\n"); + dprintk(dev, 4, "s2255: read callback failed\n"); - dprintk(50, "callback read video done\n"); + dprintk(dev, 50, "callback read video done\n"); return; } @@ -2181,9 +1930,9 @@ static int s2255_get_fx2fw(struct s2255_dev *dev) ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, 2, S2255_VR_IN); if (ret < 0) - dprintk(2, "get fw error: %x\n", ret); + dprintk(dev, 2, "get fw error: %x\n", ret); fw = transBuffer[0] + (transBuffer[1] << 8); - dprintk(2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); + dprintk(dev, 2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); return fw; } @@ -2191,12 +1940,11 @@ static int s2255_get_fx2fw(struct s2255_dev *dev) * Create the system ring buffer to copy frames into from the * usb read pipe. */ -static int s2255_create_sys_buffers(struct s2255_channel *channel) +static int s2255_create_sys_buffers(struct s2255_vc *vc) { unsigned long i; unsigned long reqsize; - dprintk(1, "create sys buffers\n"); - channel->buffer.dwFrames = SYS_FRAMES; + vc->buffer.dwFrames = SYS_FRAMES; /* always allocate maximum size(PAL) for system buffers */ reqsize = SYS_FRAMES_MAXSIZE; @@ -2205,40 +1953,33 @@ static int s2255_create_sys_buffers(struct s2255_channel *channel) for (i = 0; i < SYS_FRAMES; i++) { /* allocate the frames */ - channel->buffer.frame[i].lpvbits = vmalloc(reqsize); - dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n", - &channel->buffer.frame[i], channel->idx, i, - channel->buffer.frame[i].lpvbits); - channel->buffer.frame[i].size = reqsize; - if (channel->buffer.frame[i].lpvbits == NULL) { - printk(KERN_INFO "out of memory. using less frames\n"); - channel->buffer.dwFrames = i; + vc->buffer.frame[i].lpvbits = vmalloc(reqsize); + vc->buffer.frame[i].size = reqsize; + if (vc->buffer.frame[i].lpvbits == NULL) { + pr_info("out of memory. using less frames\n"); + vc->buffer.dwFrames = i; break; } } /* make sure internal states are set */ for (i = 0; i < SYS_FRAMES; i++) { - channel->buffer.frame[i].ulState = 0; - channel->buffer.frame[i].cur_size = 0; + vc->buffer.frame[i].ulState = 0; + vc->buffer.frame[i].cur_size = 0; } - channel->cur_frame = 0; - channel->last_frame = -1; + vc->cur_frame = 0; + vc->last_frame = -1; return 0; } -static int s2255_release_sys_buffers(struct s2255_channel *channel) +static int s2255_release_sys_buffers(struct s2255_vc *vc) { unsigned long i; - dprintk(1, "release sys buffers\n"); for (i = 0; i < SYS_FRAMES; i++) { - if (channel->buffer.frame[i].lpvbits) { - dprintk(1, "vfree %p\n", - channel->buffer.frame[i].lpvbits); - vfree(channel->buffer.frame[i].lpvbits); - } - channel->buffer.frame[i].lpvbits = NULL; + if (vc->buffer.frame[i].lpvbits) + vfree(vc->buffer.frame[i].lpvbits); + vc->buffer.frame[i].lpvbits = NULL; } return 0; } @@ -2249,7 +1990,7 @@ static int s2255_board_init(struct s2255_dev *dev) int fw_ver; int j; struct s2255_pipeinfo *pipe = &dev->pipe; - dprintk(4, "board init: %p", dev); + dprintk(dev, 4, "board init: %p", dev); memset(pipe, 0, sizeof(*pipe)); pipe->dev = dev; pipe->cur_transfer_size = S2255_USB_XFER_SIZE; @@ -2258,54 +1999,53 @@ static int s2255_board_init(struct s2255_dev *dev) pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, GFP_KERNEL); if (pipe->transfer_buffer == NULL) { - dprintk(1, "out of memory!\n"); + dprintk(dev, 1, "out of memory!\n"); return -ENOMEM; } /* query the firmware */ fw_ver = s2255_get_fx2fw(dev); - printk(KERN_INFO "s2255: usb firmware version %d.%d\n", - (fw_ver >> 8) & 0xff, - fw_ver & 0xff); + pr_info("s2255: usb firmware version %d.%d\n", + (fw_ver >> 8) & 0xff, + fw_ver & 0xff); if (fw_ver < S2255_CUR_USB_FWVER) - printk(KERN_INFO "s2255: newer USB firmware available\n"); + pr_info("s2255: newer USB firmware available\n"); for (j = 0; j < MAX_CHANNELS; j++) { - struct s2255_channel *channel = &dev->channel[j]; - channel->b_acquire = 0; - channel->mode = mode_def; + struct s2255_vc *vc = &dev->vc[j]; + vc->mode = mode_def; if (dev->pid == 0x2257 && j > 1) - channel->mode.color |= (1 << 16); - channel->jpegqual = S2255_DEF_JPEG_QUAL; - channel->width = LINE_SZ_4CIFS_NTSC; - channel->height = NUM_LINES_4CIFS_NTSC * 2; - channel->std = V4L2_STD_NTSC_M; - channel->fmt = &formats[0]; - channel->mode.restart = 1; - channel->req_image_size = get_transfer_size(&mode_def); - channel->frame_count = 0; + vc->mode.color |= (1 << 16); + vc->jpegqual = S2255_DEF_JPEG_QUAL; + vc->width = LINE_SZ_4CIFS_NTSC; + vc->height = NUM_LINES_4CIFS_NTSC * 2; + vc->std = V4L2_STD_NTSC_M; + vc->fmt = &formats[0]; + vc->mode.restart = 1; + vc->req_image_size = get_transfer_size(&mode_def); + vc->frame_count = 0; /* create the system buffers */ - s2255_create_sys_buffers(channel); + s2255_create_sys_buffers(vc); } /* start read pipe */ s2255_start_readpipe(dev); - dprintk(1, "%s: success\n", __func__); + dprintk(dev, 1, "%s: success\n", __func__); return 0; } static int s2255_board_shutdown(struct s2255_dev *dev) { u32 i; - dprintk(1, "%s: dev: %p", __func__, dev); + dprintk(dev, 1, "%s: dev: %p", __func__, dev); for (i = 0; i < MAX_CHANNELS; i++) { - if (dev->channel[i].b_acquire) - s2255_stop_acquire(&dev->channel[i]); + if (vb2_is_streaming(&dev->vc[i].vb_vidq)) + s2255_stop_acquire(&dev->vc[i]); } s2255_stop_readpipe(dev); for (i = 0; i < MAX_CHANNELS; i++) - s2255_release_sys_buffers(&dev->channel[i]); + s2255_release_sys_buffers(&dev->vc[i]); /* release transfer buffer */ kfree(dev->pipe.transfer_buffer); return 0; @@ -2318,13 +2058,10 @@ static void read_pipe_completion(struct urb *purb) int status; int pipe; pipe_info = purb->context; - dprintk(100, "%s: urb:%p, status %d\n", __func__, purb, - purb->status); if (pipe_info == NULL) { dev_err(&purb->dev->dev, "no context!\n"); return; } - dev = pipe_info->dev; if (dev == NULL) { dev_err(&purb->dev->dev, "no context!\n"); @@ -2333,13 +2070,13 @@ static void read_pipe_completion(struct urb *purb) status = purb->status; /* if shutting down, do not resubmit, exit immediately */ if (status == -ESHUTDOWN) { - dprintk(2, "%s: err shutdown\n", __func__); + dprintk(dev, 2, "%s: err shutdown\n", __func__); pipe_info->err_count++; return; } if (pipe_info->state == 0) { - dprintk(2, "%s: exiting USB pipe", __func__); + dprintk(dev, 2, "%s: exiting USB pipe", __func__); return; } @@ -2347,7 +2084,7 @@ static void read_pipe_completion(struct urb *purb) s2255_read_video_callback(dev, pipe_info); else { pipe_info->err_count++; - dprintk(1, "%s: failed URB %d\n", __func__, status); + dprintk(dev, 1, "%s: failed URB %d\n", __func__, status); } pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); @@ -2359,11 +2096,10 @@ static void read_pipe_completion(struct urb *purb) read_pipe_completion, pipe_info); if (pipe_info->state != 0) { - if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) { + if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) dev_err(&dev->udev->dev, "error submitting urb\n"); - } } else { - dprintk(2, "%s :complete state 0\n", __func__); + dprintk(dev, 2, "%s :complete state 0\n", __func__); } return; } @@ -2374,7 +2110,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev) int retval; struct s2255_pipeinfo *pipe_info = &dev->pipe; pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); - dprintk(2, "%s: IN %d\n", __func__, dev->read_endpoint); + dprintk(dev, 2, "%s: IN %d\n", __func__, dev->read_endpoint); pipe_info->state = 1; pipe_info->err_count = 0; pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -2391,70 +2127,64 @@ static int s2255_start_readpipe(struct s2255_dev *dev) read_pipe_completion, pipe_info); retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); if (retval) { - printk(KERN_ERR "s2255: start read pipe failed\n"); + pr_err("s2255: start read pipe failed\n"); return retval; } return 0; } /* starts acquisition process */ -static int s2255_start_acquire(struct s2255_channel *channel) +static int s2255_start_acquire(struct s2255_vc *vc) { - unsigned char *buffer; int res; unsigned long chn_rev; int j; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - chn_rev = G_chnmap[channel->idx]; - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } - - channel->last_frame = -1; - channel->bad_payload = 0; - channel->cur_frame = 0; + struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); + __le32 *buffer = dev->cmdbuf; + + mutex_lock(&dev->cmdlock); + chn_rev = G_chnmap[vc->idx]; + vc->last_frame = -1; + vc->bad_payload = 0; + vc->cur_frame = 0; for (j = 0; j < SYS_FRAMES; j++) { - channel->buffer.frame[j].ulState = 0; - channel->buffer.frame[j].cur_size = 0; + vc->buffer.frame[j].ulState = 0; + vc->buffer.frame[j].cur_size = 0; } /* send the start command */ - *(__le32 *) buffer = IN_DATA_TOKEN; - *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev); - *((__le32 *) buffer + 2) = CMD_START; + buffer[0] = IN_DATA_TOKEN; + buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[2] = CMD_START; res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); if (res != 0) dev_err(&dev->udev->dev, "CMD_START error\n"); - dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res); - kfree(buffer); - return 0; + dprintk(dev, 2, "start acquire exit[%d] %d\n", vc->idx, res); + mutex_unlock(&dev->cmdlock); + return res; } -static int s2255_stop_acquire(struct s2255_channel *channel) +static int s2255_stop_acquire(struct s2255_vc *vc) { - unsigned char *buffer; int res; unsigned long chn_rev; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); - chn_rev = G_chnmap[channel->idx]; - buffer = kzalloc(512, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&dev->udev->dev, "out of mem\n"); - return -ENOMEM; - } + struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev); + __le32 *buffer = dev->cmdbuf; + + mutex_lock(&dev->cmdlock); + chn_rev = G_chnmap[vc->idx]; /* send the stop command */ - *(__le32 *) buffer = IN_DATA_TOKEN; - *((__le32 *) buffer + 1) = (__le32) cpu_to_le32(chn_rev); - *((__le32 *) buffer + 2) = CMD_STOP; + buffer[0] = IN_DATA_TOKEN; + buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[2] = CMD_STOP; + res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); if (res != 0) dev_err(&dev->udev->dev, "CMD_STOP error\n"); - kfree(buffer); - channel->b_acquire = 0; - dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res); + + dprintk(dev, 4, "%s: chn %d, res %d\n", __func__, vc->idx, res); + mutex_unlock(&dev->cmdlock); return res; } @@ -2469,7 +2199,7 @@ static void s2255_stop_readpipe(struct s2255_dev *dev) usb_free_urb(pipe->stream_urb); pipe->stream_urb = NULL; } - dprintk(4, "%s", __func__); + dprintk(dev, 4, "%s", __func__); return; } @@ -2501,19 +2231,27 @@ static int s2255_probe(struct usb_interface *interface, int retval = -ENOMEM; __le32 *pdata; int fw_size; - dprintk(2, "%s\n", __func__); + /* allocate memory for our device state and initialize it to zero */ dev = kzalloc(sizeof(struct s2255_dev), GFP_KERNEL); if (dev == NULL) { s2255_dev_err(&interface->dev, "out of memory\n"); return -ENOMEM; } + + dev->cmdbuf = kzalloc(S2255_CMDBUF_SIZE, GFP_KERNEL); + if (dev->cmdbuf == NULL) { + s2255_dev_err(&interface->dev, "out of memory\n"); + goto errorFWDATA1; + } + atomic_set(&dev->num_channels, 0); dev->pid = le16_to_cpu(id->idProduct); dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); if (!dev->fw_data) goto errorFWDATA1; mutex_init(&dev->lock); + mutex_init(&dev->cmdlock); /* grab usb_device and save it */ dev->udev = usb_get_dev(interface_to_usbdev(interface)); if (dev->udev == NULL) { @@ -2521,12 +2259,13 @@ static int s2255_probe(struct usb_interface *interface, retval = -ENODEV; goto errorUDEV; } - dprintk(1, "dev: %p, udev %p interface %p\n", dev, - dev->udev, interface); + dev_dbg(&interface->dev, "dev: %p, udev %p interface %p\n", + dev, dev->udev, interface); dev->interface = interface; /* set up the endpoint information */ iface_desc = interface->cur_altsetting; - dprintk(1, "num endpoints %d\n", iface_desc->desc.bNumEndpoints); + dev_dbg(&interface->dev, "num EP: %d\n", + iface_desc->desc.bNumEndpoints); for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (!dev->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { @@ -2544,10 +2283,13 @@ static int s2255_probe(struct usb_interface *interface, dev->timer.data = (unsigned long)dev->fw_data; init_waitqueue_head(&dev->fw_data->wait_fw); for (i = 0; i < MAX_CHANNELS; i++) { - struct s2255_channel *channel = &dev->channel[i]; - dev->channel[i].idx = i; - init_waitqueue_head(&channel->wait_setmode); - init_waitqueue_head(&channel->wait_vidstatus); + struct s2255_vc *vc = &dev->vc[i]; + vc->idx = i; + vc->dev = dev; + init_waitqueue_head(&vc->wait_setmode); + init_waitqueue_head(&vc->wait_vidstatus); + spin_lock_init(&vc->qlock); + mutex_init(&vc->vb_lock); } dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -2564,7 +2306,7 @@ static int s2255_probe(struct usb_interface *interface, /* load the first chunk */ if (request_firmware(&dev->fw_data->fw, FIRMWARE_FILE_NAME, &dev->udev->dev)) { - printk(KERN_ERR "sensoray 2255 failed to get firmware\n"); + dev_err(&interface->dev, "sensoray 2255 failed to get firmware\n"); goto errorREQFW; } /* check the firmware is valid */ @@ -2572,28 +2314,27 @@ static int s2255_probe(struct usb_interface *interface, pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8]; if (*pdata != S2255_FW_MARKER) { - printk(KERN_INFO "Firmware invalid.\n"); + dev_err(&interface->dev, "Firmware invalid.\n"); retval = -ENODEV; goto errorFWMARKER; } else { /* make sure firmware is the latest */ __le32 *pRel; pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; - printk(KERN_INFO "s2255 dsp fw version %x\n", le32_to_cpu(*pRel)); + pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*pRel)); dev->dsp_fw_ver = le32_to_cpu(*pRel); if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) - printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); + pr_info("s2255: f2255usb.bin out of date.\n"); if (dev->pid == 0x2257 && dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - printk(KERN_WARNING "s2255: 2257 requires firmware %d" - " or above.\n", S2255_MIN_DSP_COLORFILTER); + pr_warn("2257 needs firmware %d or above.\n", + S2255_MIN_DSP_COLORFILTER); } usb_reset_device(dev->udev); /* load 2255 board specific */ retval = s2255_board_init(dev); if (retval) goto errorBOARDINIT; - spin_lock_init(&dev->slock); s2255_fwload_start(dev, 0); /* loads v4l specific */ retval = s2255_probe_v4l(dev); @@ -2610,15 +2351,16 @@ errorREQFW: errorFWDATA2: usb_free_urb(dev->fw_data->fw_urb); errorFWURB: - del_timer(&dev->timer); + del_timer_sync(&dev->timer); errorEP: usb_put_dev(dev->udev); errorUDEV: kfree(dev->fw_data); mutex_destroy(&dev->lock); errorFWDATA1: + kfree(dev->cmdbuf); kfree(dev); - printk(KERN_WARNING "Sensoray 2255 driver load failed: 0x%x\n", retval); + pr_warn("Sensoray 2255 driver load failed: 0x%x\n", retval); return retval; } @@ -2635,15 +2377,15 @@ static void s2255_disconnect(struct usb_interface *interface) atomic_inc(&dev->num_channels); /* unregister each video device. */ for (i = 0; i < channels; i++) - video_unregister_device(&dev->channel[i].vdev); + video_unregister_device(&dev->vc[i].vdev); /* wake up any of our timers */ atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); wake_up(&dev->fw_data->wait_fw); for (i = 0; i < MAX_CHANNELS; i++) { - dev->channel[i].setmode_ready = 1; - wake_up(&dev->channel[i].wait_setmode); - dev->channel[i].vidstatus_ready = 1; - wake_up(&dev->channel[i].wait_vidstatus); + dev->vc[i].setmode_ready = 1; + wake_up(&dev->vc[i].wait_setmode); + dev->vc[i].vidstatus_ready = 1; + wake_up(&dev->vc[i].wait_vidstatus); } if (atomic_dec_and_test(&dev->num_channels)) s2255_destroy(dev); diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 03761c6f472..1836a416d80 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -209,8 +209,10 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size) struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer; int dummy; - if (dev->state != SMSUSB_ACTIVE) + if (dev->state != SMSUSB_ACTIVE) { + sms_debug("Device not active yet"); return -ENOENT; + } sms_debug("sending %s(%d) size: %d", smscore_translate_msg(phdr->msg_type), phdr->msg_type, @@ -243,6 +245,9 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) int rc, dummy; char *fw_filename; + if (id < 0) + id = sms_get_board(board_id)->default_mode; + if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) { sms_err("invalid firmware id specified %d", id); return -EINVAL; @@ -445,14 +450,15 @@ static int smsusb_probe(struct usb_interface *intf, char devpath[32]; int i, rc; - sms_info("interface number %d", + sms_info("board id=%lu, interface number %d", + id->driver_info, intf->cur_altsetting->desc.bInterfaceNumber); if (sms_get_board(id->driver_info)->intf_num != intf->cur_altsetting->desc.bInterfaceNumber) { - sms_err("interface number is %d expecting %d", - sms_get_board(id->driver_info)->intf_num, - intf->cur_altsetting->desc.bInterfaceNumber); + sms_debug("interface %d won't be used. Expecting interface %d to popup", + intf->cur_altsetting->desc.bInterfaceNumber, + sms_get_board(id->driver_info)->intf_num); return -ENODEV; } @@ -483,22 +489,32 @@ static int smsusb_probe(struct usb_interface *intf, } if ((udev->actconfig->desc.bNumInterfaces == 2) && (intf->cur_altsetting->desc.bInterfaceNumber == 0)) { - sms_err("rom interface 0 is not used"); + sms_debug("rom interface 0 is not used"); return -ENODEV; } if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) { - sms_info("stellar device was found."); + /* Detected a Siano Stellar uninitialized */ + snprintf(devpath, sizeof(devpath), "usb\\%d-%s", udev->bus->busnum, udev->devpath); - sms_info("stellar device was found."); - return smsusb1_load_firmware( + sms_info("stellar device in cold state was found at %s.", devpath); + rc = smsusb1_load_firmware( udev, smscore_registry_getmode(devpath), id->driver_info); + + /* This device will reset and gain another USB ID */ + if (!rc) + sms_info("stellar device now in warm state"); + else + sms_err("Failed to put stellar in warm state. Error: %d", rc); + + return rc; + } else { + rc = smsusb_init_device(intf, id->driver_info); } - rc = smsusb_init_device(intf, id->driver_info); - sms_info("rc %d", rc); + sms_info("Device initialized with return code %d", rc); sms_board_load_modules(id->driver_info); return rc; } @@ -550,10 +566,13 @@ static int smsusb_resume(struct usb_interface *intf) } static const struct usb_device_id smsusb_id_table[] = { + /* This device is only present before firmware load */ { USB_DEVICE(0x187f, 0x0010), - .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + .driver_info = SMS1XXX_BOARD_SIANO_STELLAR_ROM }, + /* This device pops up after firmware load */ { USB_DEVICE(0x187f, 0x0100), .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, + { USB_DEVICE(0x187f, 0x0200), .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A }, { USB_DEVICE(0x187f, 0x0201), @@ -634,6 +653,8 @@ static const struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD }, { USB_DEVICE(0x19D2, 0x0078), .driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD }, + { USB_DEVICE(0x3275, 0x0080), + .driver_info = SMS1XXX_BOARD_SIANO_RIO }, { } /* Terminating entry */ }; diff --git a/drivers/media/usb/sn9c102/Kconfig b/drivers/media/usb/sn9c102/Kconfig deleted file mode 100644 index 6ebaf2940d0..00000000000 --- a/drivers/media/usb/sn9c102/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config USB_SN9C102 - tristate "USB SN9C1xx PC Camera Controller support (DEPRECATED)" - depends on VIDEO_V4L2 - ---help--- - This driver is DEPRECATED please use the gspca sonixb and - sonixj modules instead. - - Say Y here if you want support for cameras based on SONiX SN9C101, - SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. - - See <file:Documentation/video4linux/sn9c102.txt> for more info. - - To compile this driver as a module, choose M here: the - module will be called sn9c102. diff --git a/drivers/media/usb/sn9c102/Makefile b/drivers/media/usb/sn9c102/Makefile deleted file mode 100644 index 7ecd5a90c7c..00000000000 --- a/drivers/media/usb/sn9c102/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -sn9c102-objs := sn9c102_core.o \ - sn9c102_hv7131d.o \ - sn9c102_hv7131r.o \ - sn9c102_mi0343.o \ - sn9c102_mi0360.o \ - sn9c102_mt9v111.o \ - sn9c102_ov7630.o \ - sn9c102_ov7660.o \ - sn9c102_pas106b.o \ - sn9c102_pas202bcb.o \ - sn9c102_tas5110c1b.o \ - sn9c102_tas5110d.o \ - sn9c102_tas5130d1b.o - -obj-$(CONFIG_USB_SN9C102) += sn9c102.o diff --git a/drivers/media/usb/sn9c102/sn9c102.h b/drivers/media/usb/sn9c102/sn9c102.h deleted file mode 100644 index 8a917f06050..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102.h +++ /dev/null @@ -1,214 +0,0 @@ -/*************************************************************************** - * V4L2 driver for SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_H_ -#define _SN9C102_H_ - -#include <linux/usb.h> -#include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-device.h> -#include <linux/device.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/time.h> -#include <linux/wait.h> -#include <linux/types.h> -#include <linux/param.h> -#include <linux/rwsem.h> -#include <linux/mutex.h> -#include <linux/string.h> -#include <linux/stddef.h> -#include <linux/kref.h> - -#include "sn9c102_config.h" -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -enum sn9c102_frame_state { - F_UNUSED, - F_QUEUED, - F_GRABBING, - F_DONE, - F_ERROR, -}; - -struct sn9c102_frame_t { - void* bufmem; - struct v4l2_buffer buf; - enum sn9c102_frame_state state; - struct list_head frame; - unsigned long vma_use_count; -}; - -enum sn9c102_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -enum sn9c102_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum sn9c102_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON, -}; - -typedef char sn9c102_sof_header_t[62]; - -struct sn9c102_sof_t { - sn9c102_sof_header_t header; - u16 bytesread; -}; - -struct sn9c102_sysfs_attr { - u16 reg, i2c_reg; - sn9c102_sof_header_t frame_header; -}; - -struct sn9c102_module_param { - u8 force_munmap; - u16 frame_timeout; -}; - -static DEFINE_MUTEX(sn9c102_sysfs_lock); -static DECLARE_RWSEM(sn9c102_dev_lock); - -struct sn9c102_device { - struct video_device* v4ldev; - - struct v4l2_device v4l2_dev; - - enum sn9c102_bridge bridge; - struct sn9c102_sensor sensor; - - struct usb_device* usbdev; - struct urb* urb[SN9C102_URBS]; - void* transfer_buffer[SN9C102_URBS]; - u8* control_buffer; - - struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; - struct list_head inqueue, outqueue; - u32 frame_count, nbuffers, nreadbuffers; - - enum sn9c102_io_method io; - enum sn9c102_stream_state stream; - - struct v4l2_jpegcompression compression; - - struct sn9c102_sysfs_attr sysfs; - struct sn9c102_sof_t sof; - u16 reg[384]; - - struct sn9c102_module_param module_param; - - struct kref kref; - enum sn9c102_dev_state state; - u8 users; - - struct completion probe; - struct mutex open_mutex, fileop_mutex; - spinlock_t queue_lock; - wait_queue_head_t wait_open, wait_frame, wait_stream; -}; - -/*****************************************************************************/ - -struct sn9c102_device* -sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) -{ - return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; -} - - -void -sn9c102_attach_sensor(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor) -{ - memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); -} - - -enum sn9c102_bridge -sn9c102_get_bridge(struct sn9c102_device* cam) -{ - return cam->bridge; -} - - -struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam) -{ - return &cam->sensor; -} - -/*****************************************************************************/ - -#undef DBG -#undef KDBG -#ifdef SN9C102_DEBUG -# define DBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1) \ - dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) == 2) \ - dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __func__, __LINE__ , ## args); \ - } \ -} while (0) -# define V4LDBG(level, name, cmd) \ -do { \ - if (debug >= (level)) \ - v4l_printk_ioctl(name, cmd); \ -} while (0) -# define KDBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1 || (level) == 2) \ - pr_info("sn9c102: " fmt "\n", ## args); \ - else if ((level) == 3) \ - pr_debug("sn9c102: [%s:%d] " fmt "\n", \ - __func__, __LINE__ , ## args); \ - } \ -} while (0) -#else -# define DBG(level, fmt, args...) do {;} while(0) -# define V4LDBG(level, name, cmd) do {;} while(0) -# define KDBG(level, fmt, args...) do {;} while(0) -#endif - -#undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \ - __LINE__ , ## args) - -#undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ - -#endif /* _SN9C102_H_ */ diff --git a/drivers/media/usb/sn9c102/sn9c102_config.h b/drivers/media/usb/sn9c102/sn9c102_config.h deleted file mode 100644 index 0f4e0378b07..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_config.h +++ /dev/null @@ -1,86 +0,0 @@ -/*************************************************************************** - * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_CONFIG_H_ -#define _SN9C102_CONFIG_H_ - -#include <linux/types.h> -#include <linux/jiffies.h> - -#define SN9C102_DEBUG -#define SN9C102_DEBUG_LEVEL 2 -#define SN9C102_MAX_DEVICES 64 -#define SN9C102_PRESERVE_IMGSCALE 0 -#define SN9C102_FORCE_MUNMAP 0 -#define SN9C102_MAX_FRAMES 32 -#define SN9C102_URBS 2 -#define SN9C102_ISO_PACKETS 7 -#define SN9C102_ALTERNATE_SETTING 8 -#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) -#define SN9C102_CTRL_TIMEOUT 300 -#define SN9C102_FRAME_TIMEOUT 0 - -/*****************************************************************************/ - -static const u8 SN9C102_Y_QTABLE0[64] = { - 8, 5, 5, 8, 12, 20, 25, 30, - 6, 6, 7, 9, 13, 29, 30, 27, - 7, 6, 8, 12, 20, 28, 34, 28, - 7, 8, 11, 14, 25, 43, 40, 31, - 9, 11, 18, 28, 34, 54, 51, 38, - 12, 17, 27, 32, 40, 52, 56, 46, - 24, 32, 39, 43, 51, 60, 60, 50, - 36, 46, 47, 49, 56, 50, 51, 49 -}; - -static const u8 SN9C102_UV_QTABLE0[64] = { - 8, 9, 12, 23, 49, 49, 49, 49, - 9, 10, 13, 33, 49, 49, 49, 49, - 12, 13, 28, 49, 49, 49, 49, 49, - 23, 33, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49 -}; - -static const u8 SN9C102_Y_QTABLE1[64] = { - 16, 11, 10, 16, 24, 40, 51, 61, - 12, 12, 14, 19, 26, 58, 60, 55, - 14, 13, 16, 24, 40, 57, 69, 56, - 14, 17, 22, 29, 51, 87, 80, 62, - 18, 22, 37, 56, 68, 109, 103, 77, - 24, 35, 55, 64, 81, 104, 113, 92, - 49, 64, 78, 87, 103, 121, 120, 101, - 72, 92, 95, 98, 112, 100, 103, 99 -}; - -static const u8 SN9C102_UV_QTABLE1[64] = { - 17, 18, 24, 47, 99, 99, 99, 99, - 18, 21, 26, 66, 99, 99, 99, 99, - 24, 26, 56, 99, 99, 99, 99, 99, - 47, 66, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 -}; - -#endif /* _SN9C102_CONFIG_H_ */ diff --git a/drivers/media/usb/sn9c102/sn9c102_core.c b/drivers/media/usb/sn9c102/sn9c102_core.c deleted file mode 100644 index 2cb44de2b92..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_core.c +++ /dev/null @@ -1,3434 +0,0 @@ -/*************************************************************************** - * V4L2 driver for SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/device.h> -#include <linux/fs.h> -#include <linux/delay.h> -#include <linux/compiler.h> -#include <linux/ioctl.h> -#include <linux/poll.h> -#include <linux/stat.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/version.h> -#include <linux/page-flags.h> -#include <asm/byteorder.h> -#include <asm/page.h> -#include <asm/uaccess.h> - -#include "sn9c102.h" - -/*****************************************************************************/ - -#define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" -#define SN9C102_MODULE_ALIAS "sn9c1xx" -#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" -#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" -#define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.48" - -/*****************************************************************************/ - -MODULE_DEVICE_TABLE(usb, sn9c102_id_table); - -MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); -MODULE_DESCRIPTION(SN9C102_MODULE_NAME); -MODULE_ALIAS(SN9C102_MODULE_ALIAS); -MODULE_VERSION(SN9C102_MODULE_VERSION); -MODULE_LICENSE(SN9C102_MODULE_LICENSE); - -static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; -module_param_array(video_nr, short, NULL, 0444); -MODULE_PARM_DESC(video_nr, - " <-1|n[,...]>" - "\nSpecify V4L2 minor mode number." - "\n-1 = use next available (default)" - "\n n = use minor number n (integer >= 0)" - "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) - " cameras this way." - "\nFor example:" - "\nvideo_nr=-1,2,-1 would assign minor number 2 to" - "\nthe second camera and use auto for the first" - "\none and for every other camera." - "\n"); - -static bool force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = - SN9C102_FORCE_MUNMAP}; -module_param_array(force_munmap, bool, NULL, 0444); -MODULE_PARM_DESC(force_munmap, - " <0|1[,...]>" - "\nForce the application to unmap previously" - "\nmapped buffer memory before calling any VIDIOC_S_CROP or" - "\nVIDIOC_S_FMT ioctl's. Not all the applications support" - "\nthis feature. This parameter is specific for each" - "\ndetected camera." - "\n0 = do not force memory unmapping" - "\n1 = force memory unmapping (save memory)" - "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." - "\n"); - -static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = - SN9C102_FRAME_TIMEOUT}; -module_param_array(frame_timeout, uint, NULL, 0644); -MODULE_PARM_DESC(frame_timeout, - " <0|n[,...]>" - "\nTimeout for a video frame in seconds before" - "\nreturning an I/O error; 0 for infinity." - "\nThis parameter is specific for each detected camera." - "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." - "\n"); - -#ifdef SN9C102_DEBUG -static unsigned short debug = SN9C102_DEBUG_LEVEL; -module_param(debug, ushort, 0644); -MODULE_PARM_DESC(debug, - " <n>" - "\nDebugging information level, from 0 to 3:" - "\n0 = none (use carefully)" - "\n1 = critical errors" - "\n2 = significant informations" - "\n3 = more verbose messages" - "\nLevel 3 is useful for testing only." - "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." - "\n"); -#endif - -/* - Add the probe entries to this table. Be sure to add the entry in the right - place, since, on failure, the next probing routine is called according to - the order of the list below, from top to bottom. -*/ -static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = { - &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ - &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ - &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ - &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ - &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ - &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ - &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ - &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ - &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ -}; - -/*****************************************************************************/ - -static u32 -sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, - enum sn9c102_io_method io) -{ - struct v4l2_pix_format* p = &(cam->sensor.pix_format); - struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); - size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? - (p->width * p->height * p->priv) / 8 : - (r->width * r->height * p->priv) / 8; - void* buff = NULL; - u32 i; - - if (count > SN9C102_MAX_FRAMES) - count = SN9C102_MAX_FRAMES; - - if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120) - imagesize += 589 + 2; /* length of JPEG header + EOI marker */ - - cam->nbuffers = count; - while (cam->nbuffers > 0) { - if ((buff = vmalloc_32_user(cam->nbuffers * - PAGE_ALIGN(imagesize)))) - break; - cam->nbuffers--; - } - - for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.index = i; - cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.length = imagesize; - cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cam->frame[i].buf.sequence = 0; - cam->frame[i].buf.field = V4L2_FIELD_NONE; - cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; - cam->frame[i].buf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - } - - return cam->nbuffers; -} - - -static void sn9c102_release_buffers(struct sn9c102_device* cam) -{ - if (cam->nbuffers) { - vfree(cam->frame[0].bufmem); - cam->nbuffers = 0; - } - cam->frame_current = NULL; -} - - -static void sn9c102_empty_framequeues(struct sn9c102_device* cam) -{ - u32 i; - - INIT_LIST_HEAD(&cam->inqueue); - INIT_LIST_HEAD(&cam->outqueue); - - for (i = 0; i < SN9C102_MAX_FRAMES; i++) { - cam->frame[i].state = F_UNUSED; - cam->frame[i].buf.bytesused = 0; - } -} - - -static void sn9c102_requeue_outqueue(struct sn9c102_device* cam) -{ - struct sn9c102_frame_t *i; - - list_for_each_entry(i, &cam->outqueue, frame) { - i->state = F_QUEUED; - list_add(&i->frame, &cam->inqueue); - } - - INIT_LIST_HEAD(&cam->outqueue); -} - - -static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) -{ - unsigned long lock_flags; - u32 i; - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].state == F_UNUSED) { - cam->frame[i].state = F_QUEUED; - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[i].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - } -} - -/*****************************************************************************/ - -/* - Write a sequence of count value/register pairs. Returns -1 after the first - failed write, or 0 for no errors. -*/ -int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2], - int count) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int i, res; - - for (i = 0; i < count; i++) { - u8 index = valreg[i][1]; - - /* - index is a u8, so it must be <256 and can't be out of range. - If we put in a check anyway, gcc annoys us with a warning - hat our check is useless. People get all uppity when they - see warnings in the kernel compile. - */ - - *buff = valreg[i][0]; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, - 0x41, index, 0, buff, 1, - SN9C102_CTRL_TIMEOUT); - - if (res < 0) { - DBG(3, "Failed to write a register (value 0x%02X, " - "index 0x%02X, error %d)", *buff, index, res); - return -1; - } - - cam->reg[index] = *buff; - } - - return 0; -} - - -int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - if (index >= ARRAY_SIZE(cam->reg)) - return -1; - - *buff = value; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); - if (res < 0) { - DBG(3, "Failed to write a register (value 0x%02X, index " - "0x%02X, error %d)", value, index, res); - return -1; - } - - cam->reg[index] = value; - - return 0; -} - - -/* NOTE: with the SN9C10[123] reading some registers always returns 0 */ -int sn9c102_read_reg(struct sn9c102_device* cam, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); - if (res < 0) - DBG(3, "Failed to read a register (index 0x%02X, error %d)", - index, res); - - return (res >= 0) ? (int)(*buff) : -1; -} - - -int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index) -{ - if (index >= ARRAY_SIZE(cam->reg)) - return -1; - - return cam->reg[index]; -} - - -static int -sn9c102_i2c_wait(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor) -{ - int i, r; - - for (i = 1; i <= 5; i++) { - r = sn9c102_read_reg(cam, 0x08); - if (r < 0) - return -EIO; - if (r & 0x04) - return 0; - if (sensor->frequency & SN9C102_I2C_400KHZ) - udelay(5*16); - else - udelay(16*16); - } - return -EBUSY; -} - - -static int -sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor) -{ - int r , err = 0; - - r = sn9c102_read_reg(cam, 0x08); - if (r < 0) - err += r; - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if (!(r & 0x08)) - err += -1; - } else { - if (r & 0x08) - err += -1; - } - - return err ? -EIO : 0; -} - - -static int -sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor) -{ - int r; - r = sn9c102_read_reg(cam, 0x08); - return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0; -} - - -int -sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, u8 data0, - u8 data1, u8 n, u8 buffer[]) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int i = 0, err = 0, res; - - /* Write cycle */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10; - data[1] = data0; /* I2C slave id */ - data[2] = data1; /* address */ - data[7] = 0x10; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - - /* Read cycle - n bytes */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | - (n << 4) | 0x02; - data[1] = data0; - data[7] = 0x10; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - - /* The first read byte will be placed in data[4] */ - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_detect_read_error(cam, sensor); - - PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1, - data[4]); - - if (err) { - DBG(3, "I2C read failed for %s image sensor", sensor->name); - return -1; - } - - if (buffer) - for (i = 0; i < n && i < 5; i++) - buffer[n-i-1] = data[4-i]; - - return (int)data[4]; -} - - -int -sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, u8 n, u8 data0, - u8 data1, u8 data2, u8 data3, u8 data4, u8 data5) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - /* Write cycle. It usually is address + value */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) - | ((n - 1) << 4); - data[1] = data0; - data[2] = data1; - data[3] = data2; - data[4] = data3; - data[5] = data4; - data[6] = data5; - data[7] = 0x17; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - err += sn9c102_i2c_detect_write_error(cam, sensor); - - if (err) - DBG(3, "I2C write failed for %s image sensor", sensor->name); - - PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " - "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", - n, data0, data1, data2, data3, data4, data5); - - return err ? -1 : 0; -} - - -int -sn9c102_i2c_try_read(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, u8 address) -{ - return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id, - address, 1, NULL); -} - - -static int sn9c102_i2c_try_write(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, - u8 address, u8 value) -{ - return sn9c102_i2c_try_raw_write(cam, sensor, 3, - sensor->i2c_slave_id, address, - value, 0, 0, 0); -} - - -int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) -{ - return sn9c102_i2c_try_read(cam, &cam->sensor, address); -} - - -int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) -{ - return sn9c102_i2c_try_write(cam, &cam->sensor, address, value); -} - -/*****************************************************************************/ - -static size_t sn9c102_sof_length(struct sn9c102_device* cam) -{ - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - return 12; - case BRIDGE_SN9C103: - return 18; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - return 62; - } - - return 0; -} - - -static void* -sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) -{ - static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; - const char *m = mem; - size_t soflen = 0, i, j; - - soflen = sn9c102_sof_length(cam); - - for (i = 0; i < len; i++) { - size_t b; - - /* Read the variable part of the header */ - if (unlikely(cam->sof.bytesread >= sizeof(marker))) { - cam->sof.header[cam->sof.bytesread] = *(m+i); - if (++cam->sof.bytesread == soflen) { - cam->sof.bytesread = 0; - return mem + i; - } - continue; - } - - /* Search for the SOF marker (fixed part) in the header */ - for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) { - if (unlikely(i+j == len)) - return NULL; - if (*(m+i+j) == marker[cam->sof.bytesread]) { - cam->sof.header[cam->sof.bytesread] = *(m+i+j); - if (++cam->sof.bytesread == sizeof(marker)) { - PDBGG("Bytes to analyze: %zd. SOF " - "starts at byte #%zd", len, i); - i += j+1; - break; - } - } else { - cam->sof.bytesread = 0; - break; - } - } - } - - return NULL; -} - - -static void* -sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) -{ - static const u8 eof_header[4][4] = { - {0x00, 0x00, 0x00, 0x00}, - {0x40, 0x00, 0x00, 0x00}, - {0x80, 0x00, 0x00, 0x00}, - {0xc0, 0x00, 0x00, 0x00}, - }; - size_t i, j; - - /* The EOF header does not exist in compressed data */ - if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || - cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - return NULL; - - /* - The EOF header might cross the packet boundary, but this is not a - problem, since the end of a frame is determined by checking its size - in the first place. - */ - for (i = 0; (len >= 4) && (i <= len - 4); i++) - for (j = 0; j < ARRAY_SIZE(eof_header); j++) - if (!memcmp(mem + i, eof_header[j], 4)) - return mem + i; - - return NULL; -} - - -static void -sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) -{ - static const u8 jpeg_header[589] = { - 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, - 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, - 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, - 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16, - 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16, - 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29, - 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29, - 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a, - 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2, - 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, - 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, - 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, - 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, - 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, - 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, - 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, - 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, - 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, - 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, - 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, - 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, - 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, - 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, - 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, - 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, - 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, - 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, - 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, - 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, - 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, - 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, - 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, - 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, - 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, - 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, - 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, - 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11, - 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02, - 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, - 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 - }; - u8 *pos = f->bufmem; - - memcpy(pos, jpeg_header, sizeof(jpeg_header)); - *(pos + 6) = 0x00; - *(pos + 7 + 64) = 0x01; - if (cam->compression.quality == 0) { - memcpy(pos + 7, SN9C102_Y_QTABLE0, 64); - memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64); - } else if (cam->compression.quality == 1) { - memcpy(pos + 7, SN9C102_Y_QTABLE1, 64); - memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64); - } - *(pos + 564) = cam->sensor.pix_format.width & 0xFF; - *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF; - *(pos + 562) = cam->sensor.pix_format.height & 0xFF; - *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF; - *(pos + 567) = 0x21; - - f->buf.bytesused += sizeof(jpeg_header); -} - - -static void sn9c102_urb_complete(struct urb *urb) -{ - struct sn9c102_device* cam = urb->context; - struct sn9c102_frame_t** f; - size_t imagesize, soflen; - u8 i; - int err = 0; - - if (urb->status == -ENOENT) - return; - - f = &cam->frame_current; - - if (cam->stream == STREAM_INTERRUPT) { - cam->stream = STREAM_OFF; - if ((*f)) - (*f)->state = F_QUEUED; - cam->sof.bytesread = 0; - DBG(3, "Stream interrupted by application"); - wake_up(&cam->wait_stream); - } - - if (cam->state & DEV_DISCONNECTED) - return; - - if (cam->state & DEV_MISCONFIGURED) { - wake_up_interruptible(&cam->wait_frame); - return; - } - - if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) - goto resubmit_urb; - - if (!(*f)) - (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, - frame); - - imagesize = (cam->sensor.pix_format.width * - cam->sensor.pix_format.height * - cam->sensor.pix_format.priv) / 8; - if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - imagesize += 589; /* length of jpeg header */ - soflen = sn9c102_sof_length(cam); - - for (i = 0; i < urb->number_of_packets; i++) { - unsigned int img, len, status; - void *pos, *sof, *eof; - - len = urb->iso_frame_desc[i].actual_length; - status = urb->iso_frame_desc[i].status; - pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; - - if (status) { - DBG(3, "Error in isochronous frame"); - (*f)->state = F_ERROR; - cam->sof.bytesread = 0; - continue; - } - - PDBGG("Isochrnous frame: length %u, #%u i", len, i); - -redo: - sof = sn9c102_find_sof_header(cam, pos, len); - if (likely(!sof)) { - eof = sn9c102_find_eof_header(cam, pos, len); - if ((*f)->state == F_GRABBING) { -end_of_frame: - img = len; - - if (eof) - img = (eof > pos) ? eof - pos - 1 : 0; - - if ((*f)->buf.bytesused + img > imagesize) { - u32 b; - b = (*f)->buf.bytesused + img - - imagesize; - img = imagesize - (*f)->buf.bytesused; - PDBGG("Expected EOF not found: video " - "frame cut"); - if (eof) - DBG(3, "Exceeded limit: +%u " - "bytes", (unsigned)(b)); - } - - memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, - img); - - if ((*f)->buf.bytesused == 0) - v4l2_get_timestamp( - &(*f)->buf.timestamp); - - (*f)->buf.bytesused += img; - - if ((*f)->buf.bytesused == imagesize || - ((cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_SN9C10X || - cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_JPEG) && eof)) { - u32 b; - - b = (*f)->buf.bytesused; - (*f)->state = F_DONE; - (*f)->buf.sequence= ++cam->frame_count; - - spin_lock(&cam->queue_lock); - list_move_tail(&(*f)->frame, - &cam->outqueue); - if (!list_empty(&cam->inqueue)) - (*f) = list_entry( - cam->inqueue.next, - struct sn9c102_frame_t, - frame ); - else - (*f) = NULL; - spin_unlock(&cam->queue_lock); - - memcpy(cam->sysfs.frame_header, - cam->sof.header, soflen); - - DBG(3, "Video frame captured: %lu " - "bytes", (unsigned long)(b)); - - if (!(*f)) - goto resubmit_urb; - - } else if (eof) { - (*f)->state = F_ERROR; - DBG(3, "Not expected EOF after %lu " - "bytes of image data", - (unsigned long) - ((*f)->buf.bytesused)); - } - - if (sof) /* (1) */ - goto start_of_frame; - - } else if (eof) { - DBG(3, "EOF without SOF"); - continue; - - } else { - PDBGG("Ignoring pointless isochronous frame"); - continue; - } - - } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) { -start_of_frame: - (*f)->state = F_GRABBING; - (*f)->buf.bytesused = 0; - len -= (sof - pos); - pos = sof; - if (cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_JPEG) - sn9c102_write_jpegheader(cam, (*f)); - DBG(3, "SOF detected: new video frame"); - if (len) - goto redo; - - } else if ((*f)->state == F_GRABBING) { - eof = sn9c102_find_eof_header(cam, pos, len); - if (eof && eof < sof) - goto end_of_frame; /* (1) */ - else { - if (cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_SN9C10X || - cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_JPEG) { - if (sof - pos >= soflen) { - eof = sof - soflen; - } else { /* remove header */ - eof = pos; - (*f)->buf.bytesused -= - (soflen - (sof - pos)); - } - goto end_of_frame; - } else { - DBG(3, "SOF before expected EOF after " - "%lu bytes of image data", - (unsigned long) - ((*f)->buf.bytesused)); - goto start_of_frame; - } - } - } - } - -resubmit_urb: - urb->dev = cam->usbdev; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0 && err != -EPERM) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "usb_submit_urb() failed"); - } - - wake_up_interruptible(&cam->wait_frame); -} - - -static int sn9c102_start_transfer(struct sn9c102_device* cam) -{ - struct usb_device *udev = cam->usbdev; - struct urb* urb; - struct usb_host_interface* altsetting = usb_altnum_to_altsetting( - usb_ifnum_to_if(udev, 0), - SN9C102_ALTERNATE_SETTING); - const unsigned int psz = le16_to_cpu(altsetting-> - endpoint[0].desc.wMaxPacketSize); - s8 i, j; - int err = 0; - - for (i = 0; i < SN9C102_URBS; i++) { - cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz, - GFP_KERNEL); - if (!cam->transfer_buffer[i]) { - err = -ENOMEM; - DBG(1, "Not enough memory"); - goto free_buffers; - } - } - - for (i = 0; i < SN9C102_URBS; i++) { - urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); - cam->urb[i] = urb; - if (!urb) { - err = -ENOMEM; - DBG(1, "usb_alloc_urb() failed"); - goto free_urbs; - } - urb->dev = udev; - urb->context = cam; - urb->pipe = usb_rcvisocpipe(udev, 1); - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = SN9C102_ISO_PACKETS; - urb->complete = sn9c102_urb_complete; - urb->transfer_buffer = cam->transfer_buffer[i]; - urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; - urb->interval = 1; - for (j = 0; j < SN9C102_ISO_PACKETS; j++) { - urb->iso_frame_desc[j].offset = psz * j; - urb->iso_frame_desc[j].length = psz; - } - } - - /* Enable video */ - if (!(cam->reg[0x01] & 0x04)) { - err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); - if (err) { - err = -EIO; - DBG(1, "I/O hardware error"); - goto free_urbs; - } - } - - err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); - if (err) { - DBG(1, "usb_set_interface() failed"); - goto free_urbs; - } - - cam->frame_current = NULL; - cam->sof.bytesread = 0; - - for (i = 0; i < SN9C102_URBS; i++) { - err = usb_submit_urb(cam->urb[i], GFP_KERNEL); - if (err) { - for (j = i-1; j >= 0; j--) - usb_kill_urb(cam->urb[j]); - DBG(1, "usb_submit_urb() failed, error %d", err); - goto free_urbs; - } - } - - return 0; - -free_urbs: - for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) - usb_free_urb(cam->urb[i]); - -free_buffers: - for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) - kfree(cam->transfer_buffer[i]); - - return err; -} - - -static int sn9c102_stop_transfer(struct sn9c102_device* cam) -{ - struct usb_device *udev = cam->usbdev; - s8 i; - int err = 0; - - if (cam->state & DEV_DISCONNECTED) - return 0; - - for (i = SN9C102_URBS-1; i >= 0; i--) { - usb_kill_urb(cam->urb[i]); - usb_free_urb(cam->urb[i]); - kfree(cam->transfer_buffer[i]); - } - - err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ - if (err) - DBG(3, "usb_set_interface() failed"); - - return err; -} - - -static int sn9c102_stream_interrupt(struct sn9c102_device* cam) -{ - cam->stream = STREAM_INTERRUPT; - wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - SN9C102_URB_TIMEOUT); - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - else if (cam->stream != STREAM_OFF) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "URB timeout reached. The camera is misconfigured. " - "To use it, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - return 0; -} - -/*****************************************************************************/ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) -{ - char str[7]; - char* endp; - unsigned long val; - - if (len < 6) { - strncpy(str, buff, len); - str[len] = '\0'; - } else { - strncpy(str, buff, 6); - str[6] = '\0'; - } - - val = simple_strtoul(str, &endp, 0); - - *count = 0; - if (val <= 0xffff) - *count = (ssize_t)(endp - str); - if ((*count) && (len == *count+1) && (buff[*count] == '\n')) - *count += 1; - - return (u16)val; -} - -/* - NOTE 1: being inside one of the following methods implies that the v4l - device exists for sure (see kobjects and reference counters) - NOTE 2: buffers are PAGE_SIZE long -*/ - -static ssize_t sn9c102_show_reg(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.reg); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_reg(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u16 index; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - index = sn9c102_strtou16(buf, len, &count); - if (index >= ARRAY_SIZE(cam->reg) || !count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.reg = index; - - DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_val(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd, value: %d", count, val); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_val(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u16 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - value = sn9c102_strtou16(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - err = sn9c102_write_reg(cam, value, cam->sysfs.reg); - if (err) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X", - cam->sysfs.reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_i2c_reg(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u16 index; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - index = sn9c102_strtou16(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.i2c_reg = index; - - DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_i2c_val(struct device* cd, - struct device_attribute *attr, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENOSYS; - } - - if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd, value: %d", count, val); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u16 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENOSYS; - } - - value = sn9c102_strtou16(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); - if (err) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", - cam->sysfs.i2c_reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_green(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - struct sn9c102_device* cam; - enum sn9c102_bridge bridge; - ssize_t res = 0; - u16 value; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - bridge = cam->bridge; - - mutex_unlock(&sn9c102_sysfs_lock); - - value = sn9c102_strtou16(buf, len, &count); - if (!count) - return -EINVAL; - - switch (bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - if (value > 0x0f) - return -EINVAL; - if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0) - res = sn9c102_store_val(cd, attr, buf, len); - break; - case BRIDGE_SN9C103: - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (value > 0x7f) - return -EINVAL; - if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0) - res = sn9c102_store_val(cd, attr, buf, len); - break; - } - - return res; -} - - -static ssize_t -sn9c102_store_blue(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - ssize_t res = 0; - u16 value; - ssize_t count; - - value = sn9c102_strtou16(buf, len, &count); - if (!count || value > 0x7f) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0) - res = sn9c102_store_val(cd, attr, buf, len); - - return res; -} - - -static ssize_t -sn9c102_store_red(struct device* cd, struct device_attribute *attr, - const char* buf, size_t len) -{ - ssize_t res = 0; - u16 value; - ssize_t count; - - value = sn9c102_strtou16(buf, len, &count); - if (!count || value > 0x7f) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0) - res = sn9c102_store_val(cd, attr, buf, len); - - return res; -} - - -static ssize_t sn9c102_show_frame_header(struct device* cd, - struct device_attribute *attr, - char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - cam = video_get_drvdata(container_of(cd, struct video_device, dev)); - if (!cam) - return -ENODEV; - - count = sizeof(cam->sysfs.frame_header); - memcpy(buf, cam->sysfs.frame_header, count); - - DBG(3, "Frame header, read bytes: %zd", count); - - return count; -} - - -static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg); -static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val); -static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); -static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static DEVICE_ATTR(green, S_IWUSR, NULL, sn9c102_store_green); -static DEVICE_ATTR(blue, S_IWUSR, NULL, sn9c102_store_blue); -static DEVICE_ATTR(red, S_IWUSR, NULL, sn9c102_store_red); -static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); - - -static int sn9c102_create_sysfs(struct sn9c102_device* cam) -{ - struct device *dev = &(cam->v4ldev->dev); - int err = 0; - - if ((err = device_create_file(dev, &dev_attr_reg))) - goto err_out; - if ((err = device_create_file(dev, &dev_attr_val))) - goto err_reg; - if ((err = device_create_file(dev, &dev_attr_frame_header))) - goto err_val; - - if (cam->sensor.sysfs_ops) { - if ((err = device_create_file(dev, &dev_attr_i2c_reg))) - goto err_frame_header; - if ((err = device_create_file(dev, &dev_attr_i2c_val))) - goto err_i2c_reg; - } - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { - if ((err = device_create_file(dev, &dev_attr_green))) - goto err_i2c_val; - } else { - if ((err = device_create_file(dev, &dev_attr_blue))) - goto err_i2c_val; - if ((err = device_create_file(dev, &dev_attr_red))) - goto err_blue; - } - - return 0; - -err_blue: - device_remove_file(dev, &dev_attr_blue); -err_i2c_val: - if (cam->sensor.sysfs_ops) - device_remove_file(dev, &dev_attr_i2c_val); -err_i2c_reg: - if (cam->sensor.sysfs_ops) - device_remove_file(dev, &dev_attr_i2c_reg); -err_frame_header: - device_remove_file(dev, &dev_attr_frame_header); -err_val: - device_remove_file(dev, &dev_attr_val); -err_reg: - device_remove_file(dev, &dev_attr_reg); -err_out: - return err; -} -#endif /* CONFIG_VIDEO_ADV_DEBUG */ - -/*****************************************************************************/ - -static int -sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || - pix->pixelformat == V4L2_PIX_FMT_JPEG) { - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, - 0x18); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, - 0x18); - break; - } - } else { - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, - 0x18); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, - 0x18); - break; - } - } - - return err ? -EIO : 0; -} - - -static int -sn9c102_set_compression(struct sn9c102_device* cam, - struct v4l2_jpegcompression* compression) -{ - int i, err = 0; - - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - if (compression->quality == 0) - err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, - 0x17); - else if (compression->quality == 1) - err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, - 0x17); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (compression->quality == 0) { - for (i = 0; i <= 63; i++) { - err += sn9c102_write_reg(cam, - SN9C102_Y_QTABLE1[i], - 0x100 + i); - err += sn9c102_write_reg(cam, - SN9C102_UV_QTABLE1[i], - 0x140 + i); - } - err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, - 0x18); - } else if (compression->quality == 1) { - for (i = 0; i <= 63; i++) { - err += sn9c102_write_reg(cam, - SN9C102_Y_QTABLE1[i], - 0x100 + i); - err += sn9c102_write_reg(cam, - SN9C102_UV_QTABLE1[i], - 0x140 + i); - } - err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40, - 0x18); - } - break; - } - - return err ? -EIO : 0; -} - - -static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) -{ - u8 r = 0; - int err = 0; - - if (scale == 1) - r = cam->reg[0x18] & 0xcf; - else if (scale == 2) { - r = cam->reg[0x18] & 0xcf; - r |= 0x10; - } else if (scale == 4) - r = cam->reg[0x18] | 0x20; - - err += sn9c102_write_reg(cam, r, 0x18); - if (err) - return -EIO; - - PDBGG("Scaling factor: %u", scale); - - return 0; -} - - -static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &cam->sensor; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), - v_start = (u8)(rect->top - s->cropcap.bounds.top), - h_size = (u8)(rect->width / 16), - v_size = (u8)(rect->height / 16); - int err = 0; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - err += sn9c102_write_reg(cam, h_size, 0x15); - err += sn9c102_write_reg(cam, v_size, 0x16); - if (err) - return -EIO; - - PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " - "%u %u %u %u", h_start, v_start, h_size, v_size); - - return 0; -} - - -static int sn9c102_init(struct sn9c102_device* cam) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - struct v4l2_queryctrl *qctrl; - struct v4l2_rect* rect; - u8 i = 0; - int err = 0; - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->open_mutex); - init_waitqueue_head(&cam->wait_open); - qctrl = s->qctrl; - rect = &(s->cropcap.defrect); - } else { /* use current values */ - qctrl = s->_qctrl; - rect = &(s->_rect); - } - - err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); - err += sn9c102_set_crop(cam, rect); - if (err) - return err; - - if (s->init) { - err = s->init(cam); - if (err) { - DBG(3, "Sensor initialization failed"); - return err; - } - } - - if (!(cam->state & DEV_INITIALIZED)) - if (cam->bridge == BRIDGE_SN9C101 || - cam->bridge == BRIDGE_SN9C102 || - cam->bridge == BRIDGE_SN9C103) { - if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8; - cam->compression.quality = cam->reg[0x17] & 0x01 ? - 0 : 1; - } else { - if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) - s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG; - cam->compression.quality = cam->reg[0x18] & 0x40 ? - 0 : 1; - err += sn9c102_set_compression(cam, &cam->compression); - } - else - err += sn9c102_set_compression(cam, &cam->compression); - err += sn9c102_set_pix_format(cam, &s->pix_format); - if (s->set_pix_format) - err += s->set_pix_format(cam, &s->pix_format); - if (err) - return err; - - if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || - s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) - DBG(3, "Compressed video format is active, quality %d", - cam->compression.quality); - else - DBG(3, "Uncompressed video format is active"); - - if (s->set_crop) - if ((err = s->set_crop(cam, rect))) { - DBG(3, "set_crop() failed"); - return err; - } - - if (s->set_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (s->qctrl[i].id != 0 && - !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl.id = s->qctrl[i].id; - ctrl.value = qctrl[i].default_value; - err = s->set_ctrl(cam, &ctrl); - if (err) { - DBG(3, "Set %s control failed", - s->qctrl[i].name); - return err; - } - DBG(3, "Image sensor supports '%s' control", - s->qctrl[i].name); - } - } - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->fileop_mutex); - spin_lock_init(&cam->queue_lock); - init_waitqueue_head(&cam->wait_frame); - init_waitqueue_head(&cam->wait_stream); - cam->nreadbuffers = 2; - memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); - memcpy(&(s->_rect), &(s->cropcap.defrect), - sizeof(struct v4l2_rect)); - cam->state |= DEV_INITIALIZED; - } - - DBG(2, "Initialization succeeded"); - return 0; -} - -/*****************************************************************************/ - -static void sn9c102_release_resources(struct kref *kref) -{ - struct sn9c102_device *cam; - - mutex_lock(&sn9c102_sysfs_lock); - - cam = container_of(kref, struct sn9c102_device, kref); - - DBG(2, "V4L2 device %s deregistered", - video_device_node_name(cam->v4ldev)); - video_set_drvdata(cam->v4ldev, NULL); - video_unregister_device(cam->v4ldev); - v4l2_device_unregister(&cam->v4l2_dev); - usb_put_dev(cam->usbdev); - kfree(cam->control_buffer); - kfree(cam); - - mutex_unlock(&sn9c102_sysfs_lock); - -} - - -static int sn9c102_open(struct file *filp) -{ - struct sn9c102_device* cam; - int err = 0; - - /* - A read_trylock() in open() is the only safe way to prevent race - conditions with disconnect(), one close() and multiple (not - necessarily simultaneous) attempts to open(). For example, it - prevents from waiting for a second access, while the device - structure is being deallocated, after a possible disconnect() and - during a following close() holding the write lock: given that, after - this deallocation, no access will be possible anymore, using the - non-trylock version would have let open() gain the access to the - device structure improperly. - For this reason the lock must also not be per-device. - */ - if (!down_read_trylock(&sn9c102_dev_lock)) - return -ERESTARTSYS; - - cam = video_drvdata(filp); - - if (wait_for_completion_interruptible(&cam->probe)) { - up_read(&sn9c102_dev_lock); - return -ERESTARTSYS; - } - - kref_get(&cam->kref); - - /* - Make sure to isolate all the simultaneous opens. - */ - if (mutex_lock_interruptible(&cam->open_mutex)) { - kref_put(&cam->kref, sn9c102_release_resources); - up_read(&sn9c102_dev_lock); - return -ERESTARTSYS; - } - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - err = -ENODEV; - goto out; - } - - if (cam->users) { - DBG(2, "Device %s is already in use", - video_device_node_name(cam->v4ldev)); - DBG(3, "Simultaneous opens are not supported"); - /* - open() must follow the open flags and should block - eventually while the device is in use. - */ - if ((filp->f_flags & O_NONBLOCK) || - (filp->f_flags & O_NDELAY)) { - err = -EWOULDBLOCK; - goto out; - } - DBG(2, "A blocking open() has been requested. Wait for the " - "device to be released..."); - up_read(&sn9c102_dev_lock); - /* - We will not release the "open_mutex" lock, so that only one - process can be in the wait queue below. This way the process - will be sleeping while holding the lock, without losing its - priority after any wake_up(). - */ - err = wait_event_interruptible_exclusive(cam->wait_open, - (cam->state & DEV_DISCONNECTED) - || !cam->users); - down_read(&sn9c102_dev_lock); - if (err) - goto out; - if (cam->state & DEV_DISCONNECTED) { - err = -ENODEV; - goto out; - } - } - - if (cam->state & DEV_MISCONFIGURED) { - err = sn9c102_init(cam); - if (err) { - DBG(1, "Initialization failed again. " - "I will retry on next open()."); - goto out; - } - cam->state &= ~DEV_MISCONFIGURED; - } - - if ((err = sn9c102_start_transfer(cam))) - goto out; - - filp->private_data = cam; - cam->users++; - cam->io = IO_NONE; - cam->stream = STREAM_OFF; - cam->nbuffers = 0; - cam->frame_count = 0; - sn9c102_empty_framequeues(cam); - - DBG(3, "Video device %s is open", video_device_node_name(cam->v4ldev)); - -out: - mutex_unlock(&cam->open_mutex); - if (err) - kref_put(&cam->kref, sn9c102_release_resources); - - up_read(&sn9c102_dev_lock); - return err; -} - - -static int sn9c102_release(struct file *filp) -{ - struct sn9c102_device* cam; - - down_write(&sn9c102_dev_lock); - - cam = video_drvdata(filp); - - sn9c102_stop_transfer(cam); - sn9c102_release_buffers(cam); - cam->users--; - wake_up_interruptible_nr(&cam->wait_open, 1); - - DBG(3, "Video device %s closed", video_device_node_name(cam->v4ldev)); - - kref_put(&cam->kref, sn9c102_release_resources); - - up_write(&sn9c102_dev_lock); - - return 0; -} - - -static ssize_t -sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) -{ - struct sn9c102_device *cam = video_drvdata(filp); - struct sn9c102_frame_t* f, * i; - unsigned long lock_flags; - long timeout; - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io == IO_MMAP) { - DBG(3, "Close and open the device again to choose " - "the read method"); - mutex_unlock(&cam->fileop_mutex); - return -EBUSY; - } - - if (cam->io == IO_NONE) { - if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { - DBG(1, "read() failed, not enough memory"); - mutex_unlock(&cam->fileop_mutex); - return -ENOMEM; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (list_empty(&cam->inqueue)) { - if (!list_empty(&cam->outqueue)) - sn9c102_empty_framequeues(cam); - sn9c102_queue_unusedframes(cam); - } - - if (!count) { - mutex_unlock(&cam->fileop_mutex); - return 0; - } - - if (list_empty(&cam->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - if (!cam->module_param.frame_timeout) { - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) { - mutex_unlock(&cam->fileop_mutex); - return err; - } - } else { - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - msecs_to_jiffies( - cam->module_param.frame_timeout * 1000 - ) - ); - if (timeout < 0) { - mutex_unlock(&cam->fileop_mutex); - return timeout; - } else if (timeout == 0 && - !(cam->state & DEV_DISCONNECTED)) { - DBG(1, "Video frame timeout elapsed"); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - } - if (cam->state & DEV_DISCONNECTED) { - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - if (cam->state & DEV_MISCONFIGURED) { - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - } - - f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); - - if (count > f->buf.bytesused) - count = f->buf.bytesused; - - if (copy_to_user(buf, f->bufmem, count)) { - err = -EFAULT; - goto exit; - } - *f_pos += count; - -exit: - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(i, &cam->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - sn9c102_queue_unusedframes(cam); - - PDBGG("Frame #%lu, bytes read: %zu", - (unsigned long)f->buf.index, count); - - mutex_unlock(&cam->fileop_mutex); - - return count; -} - - -static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) -{ - struct sn9c102_device *cam = video_drvdata(filp); - struct sn9c102_frame_t* f; - unsigned long lock_flags; - unsigned int mask = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return POLLERR; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - goto error; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - goto error; - } - - if (cam->io == IO_NONE) { - if (!sn9c102_request_buffers(cam, cam->nreadbuffers, - IO_READ)) { - DBG(1, "poll() failed, not enough memory"); - goto error; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (cam->io == IO_READ) { - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(f, &cam->outqueue, frame) - f->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - sn9c102_queue_unusedframes(cam); - } - - poll_wait(filp, &cam->wait_frame, wait); - - if (!list_empty(&cam->outqueue)) - mask |= POLLIN | POLLRDNORM; - - mutex_unlock(&cam->fileop_mutex); - - return mask; - -error: - mutex_unlock(&cam->fileop_mutex); - return POLLERR; -} - - -static void sn9c102_vm_open(struct vm_area_struct* vma) -{ - struct sn9c102_frame_t* f = vma->vm_private_data; - f->vma_use_count++; -} - - -static void sn9c102_vm_close(struct vm_area_struct* vma) -{ - /* NOTE: buffers are not freed here */ - struct sn9c102_frame_t* f = vma->vm_private_data; - f->vma_use_count--; -} - - -static const struct vm_operations_struct sn9c102_vm_ops = { - .open = sn9c102_vm_open, - .close = sn9c102_vm_close, -}; - - -static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) -{ - struct sn9c102_device *cam = video_drvdata(filp); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { - mutex_unlock(&cam->fileop_mutex); - return -EACCES; - } - - if (cam->io != IO_MMAP || - size != PAGE_ALIGN(cam->frame[0].buf.length)) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) { - if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == cam->nbuffers) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; - - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &sn9c102_vm_ops; - vma->vm_private_data = &cam->frame[i]; - sn9c102_vm_open(vma); - - mutex_unlock(&cam->fileop_mutex); - - return 0; -} - -/*****************************************************************************/ - -static int -sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_capability cap = { - .driver = "sn9c102", - .version = LINUX_VERSION_CODE, - .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING, - }; - - strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); - if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev), - sizeof(cap.bus_info)); - - if (copy_to_user(arg, &cap, sizeof(cap))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_input i; - - if (copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - if (i.index) - return -EINVAL; - - memset(&i, 0, sizeof(i)); - strcpy(i.name, "Camera"); - i.type = V4L2_INPUT_TYPE_CAMERA; - i.capabilities = V4L2_IN_CAP_STD; - - if (copy_to_user(arg, &i, sizeof(i))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg) -{ - int index = 0; - - if (copy_to_user(arg, &index, sizeof(index))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg) -{ - int index; - - if (copy_from_user(&index, arg, sizeof(index))) - return -EFAULT; - - if (index != 0) - return -EINVAL; - - return 0; -} - - -static int -sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_queryctrl qc; - u8 i; - - if (copy_from_user(&qc, arg, sizeof(qc))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (qc.id && qc.id == s->qctrl[i].id) { - memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); - if (copy_to_user(arg, &qc, sizeof(qc))) - return -EFAULT; - return 0; - } - - return -EINVAL; -} - - -static int -sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - int err = 0; - u8 i; - - if (!s->get_ctrl && !s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - if (!s->get_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id && ctrl.id == s->qctrl[i].id) { - ctrl.value = s->_qctrl[i].default_value; - goto exit; - } - return -EINVAL; - } else - err = s->get_ctrl(cam, &ctrl); - -exit: - if (copy_to_user(arg, &ctrl, sizeof(ctrl))) - return -EFAULT; - - PDBGG("VIDIOC_G_CTRL: id %lu, value %lu", - (unsigned long)ctrl.id, (unsigned long)ctrl.value); - - return err; -} - - -static int -sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - u8 i; - int err = 0; - - if (!s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) { - if (ctrl.id == s->qctrl[i].id) { - if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) - return -EINVAL; - if (ctrl.value < s->qctrl[i].minimum || - ctrl.value > s->qctrl[i].maximum) - return -ERANGE; - ctrl.value -= ctrl.value % s->qctrl[i].step; - break; - } - } - if (i == ARRAY_SIZE(s->qctrl)) - return -EINVAL; - if ((err = s->set_ctrl(cam, &ctrl))) - return err; - - s->_qctrl[i].default_value = ctrl.value; - - PDBGG("VIDIOC_S_CTRL: id %lu, value %lu", - (unsigned long)ctrl.id, (unsigned long)ctrl.value); - - return 0; -} - - -static int -sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_cropcap* cc = &(cam->sensor.cropcap); - - cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cc->pixelaspect.numerator = 1; - cc->pixelaspect.denominator = 1; - - if (copy_to_user(arg, cc, sizeof(*cc))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_crop crop = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - }; - - memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); - - if (copy_to_user(arg, &crop, sizeof(crop))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_crop crop; - struct v4l2_rect* rect; - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_pix_format* pix_format = &(s->pix_format); - u8 scale; - const enum sn9c102_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&crop, arg, sizeof(crop))) - return -EFAULT; - - rect = &(crop.c); - - if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_CROP failed. " - "Unmap the buffers first."); - return -EBUSY; - } - - /* Preserve R,G or B origin */ - rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; - rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; - - if (rect->width < 16) - rect->width = 16; - if (rect->height < 16) - rect->height = 16; - if (rect->width > bounds->width) - rect->width = bounds->width; - if (rect->height > bounds->height) - rect->height = bounds->height; - if (rect->left < bounds->left) - rect->left = bounds->left; - if (rect->top < bounds->top) - rect->top = bounds->top; - if (rect->left + rect->width > bounds->left + bounds->width) - rect->left = bounds->left+bounds->width - rect->width; - if (rect->top + rect->height > bounds->top + bounds->height) - rect->top = bounds->top+bounds->height - rect->height; - - rect->width &= ~15L; - rect->height &= ~15L; - - if (SN9C102_PRESERVE_IMGSCALE) { - /* Calculate the actual scaling factor */ - u32 a, b; - a = rect->width * rect->height; - b = pix_format->width * pix_format->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } else - scale = 1; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &crop, sizeof(crop))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - sn9c102_release_buffers(cam); - - err = sn9c102_set_crop(cam, rect); - if (s->set_crop) - err += s->set_crop(cam, rect); - err += sn9c102_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - s->pix_format.width = rect->width/scale; - s->pix_format.height = rect->height/scale; - memcpy(&(s->_rect), rect, sizeof(*rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -ENOMEM; - } - - if (cam->io == IO_READ) - sn9c102_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - sn9c102_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_frmsizeenum frmsize; - - if (copy_from_user(&frmsize, arg, sizeof(frmsize))) - return -EFAULT; - - if (frmsize.index != 0) - return -EINVAL; - - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X && - frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) - return -EINVAL; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG && - frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) - return -EINVAL; - break; - } - - frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE; - frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16; - frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16; - frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width; - frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height; - memset(&frmsize.reserved, 0, sizeof(frmsize.reserved)); - - if (copy_to_user(arg, &frmsize, sizeof(frmsize))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_fmtdesc fmtd; - - if (copy_from_user(&fmtd, arg, sizeof(fmtd))) - return -EFAULT; - - if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (fmtd.index == 0) { - strcpy(fmtd.description, "bayer rgb"); - fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; - } else if (fmtd.index == 1) { - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - strcpy(fmtd.description, "compressed"); - fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - strcpy(fmtd.description, "JPEG"); - fmtd.pixelformat = V4L2_PIX_FMT_JPEG; - break; - } - fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; - } else - return -EINVAL; - - fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); - - if (copy_to_user(arg, &fmtd, sizeof(fmtd))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ? - V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; - pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X || - pfmt->pixelformat == V4L2_PIX_FMT_JPEG) - ? 0 : (pfmt->width * pfmt->priv) / 8; - pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); - pfmt->field = V4L2_FIELD_NONE; - memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); - - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, - void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_format format; - struct v4l2_pix_format* pix; - struct v4l2_pix_format* pfmt = &(s->pix_format); - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_rect rect; - u8 scale; - const enum sn9c102_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - pix = &(format.fmt.pix); - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memcpy(&rect, &(s->_rect), sizeof(rect)); - - { /* calculate the actual scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } - - rect.width = scale * pix->width; - rect.height = scale * pix->height; - - if (rect.width < 16) - rect.width = 16; - if (rect.height < 16) - rect.height = 16; - if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left + bounds->width - rect.left; - if (rect.height > bounds->top + bounds->height - rect.top) - rect.height = bounds->top + bounds->height - rect.top; - - rect.width &= ~15L; - rect.height &= ~15L; - - { /* adjust the scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } - - pix->width = rect.width / scale; - pix->height = rect.height / scale; - - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (pix->pixelformat != V4L2_PIX_FMT_JPEG && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; - break; - } - pix->priv = pfmt->priv; /* bpp */ - pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ? - V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; - pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || - pix->pixelformat == V4L2_PIX_FMT_JPEG) - ? 0 : (pix->width * pix->priv) / 8; - pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); - pix->field = V4L2_FIELD_NONE; - - if (cmd == VIDIOC_TRY_FMT) { - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - return 0; - } - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_FMT failed. Unmap the " - "buffers first."); - return -EBUSY; - } - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &format, sizeof(format))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - sn9c102_release_buffers(cam); - - err += sn9c102_set_pix_format(cam, pix); - err += sn9c102_set_crop(cam, &rect); - if (s->set_pix_format) - err += s->set_pix_format(cam, pix); - if (s->set_crop) - err += s->set_crop(cam, &rect); - err += sn9c102_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - memcpy(pfmt, pix, sizeof(*pix)); - memcpy(&(s->_rect), &rect, sizeof(rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -ENOMEM; - } - - if (cam->io == IO_READ) - sn9c102_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - sn9c102_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg) -{ - if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_jpegcompression jc; - const enum sn9c102_stream_state stream = cam->stream; - int err = 0; - - if (copy_from_user(&jc, arg, sizeof(jc))) - return -EFAULT; - - if (jc.quality != 0 && jc.quality != 1) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - err += sn9c102_set_compression(cam, &jc); - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware problems. " - "To use the camera, close and open %s again.", - video_device_node_name(cam->v4ldev)); - return -EIO; - } - - cam->compression.quality = jc.quality; - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_requestbuffers rb; - u32 i; - int err; - - if (copy_from_user(&rb, arg, sizeof(rb))) - return -EFAULT; - - if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb.memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (cam->io == IO_READ) { - DBG(3, "Close and open the device again to choose the mmap " - "I/O method"); - return -EBUSY; - } - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " - "still mapped."); - return -EBUSY; - } - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - sn9c102_empty_framequeues(cam); - - sn9c102_release_buffers(cam); - if (rb.count) - rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP); - - if (copy_to_user(arg, &rb, sizeof(rb))) { - sn9c102_release_buffers(cam); - cam->io = IO_NONE; - return -EFAULT; - } - - cam->io = rb.count ? IO_MMAP : IO_NONE; - - return 0; -} - - -static int -sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - b = cam->frame[b.index].buf; - - if (cam->frame[b.index].vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (cam->frame[b.index].state == F_DONE) - b.flags |= V4L2_BUF_FLAG_DONE; - else if (cam->frame[b.index].state != F_UNUSED) - b.flags |= V4L2_BUF_FLAG_QUEUED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - unsigned long lock_flags; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->frame[b.index].state != F_UNUSED) - return -EINVAL; - - cam->frame[b.index].state = F_QUEUED; - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - PDBGG("Frame #%lu queued", (unsigned long)b.index); - - return 0; -} - - -static int -sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, - void __user * arg) -{ - struct v4l2_buffer b; - struct sn9c102_frame_t *f; - unsigned long lock_flags; - long timeout; - int err = 0; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->outqueue)) { - if (cam->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - if (!cam->module_param.frame_timeout) { - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) - return err; - } else { - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) - return timeout; - else if (timeout == 0 && - !(cam->state & DEV_DISCONNECTED)) { - DBG(1, "Video frame timeout elapsed"); - return -EIO; - } - } - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - if (cam->state & DEV_MISCONFIGURED) - return -EIO; - } - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); - list_del(cam->outqueue.next); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - f->state = F_UNUSED; - - b = f->buf; - if (f->vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); - - return 0; -} - - -static int -sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) -{ - int type; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - cam->stream = STREAM_ON; - - DBG(3, "Stream on"); - - return 0; -} - - -static int -sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg) -{ - int type, err; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - sn9c102_empty_framequeues(cam); - - DBG(3, "Stream off"); - - return 0; -} - - -static int -sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - - if (sp.parm.capture.readbuffers == 0) - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES) - sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - cam->nreadbuffers = sp.parm.capture.readbuffers; - - return 0; -} - - -static int -sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_audio audio; - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - return -EINVAL; - - if (copy_from_user(&audio, arg, sizeof(audio))) - return -EFAULT; - - if (audio.index != 0) - return -EINVAL; - - strcpy(audio.name, "Microphone"); - audio.capability = 0; - audio.mode = 0; - - if (copy_to_user(arg, &audio, sizeof(audio))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_audio audio; - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - return -EINVAL; - - if (copy_from_user(&audio, arg, sizeof(audio))) - return -EFAULT; - - memset(&audio, 0, sizeof(audio)); - strcpy(audio.name, "Microphone"); - - if (copy_to_user(arg, &audio, sizeof(audio))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_audio audio; - - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - return -EINVAL; - - if (copy_from_user(&audio, arg, sizeof(audio))) - return -EFAULT; - - if (audio.index != 0) - return -EINVAL; - - return 0; -} - - -static long sn9c102_ioctl_v4l2(struct file *filp, - unsigned int cmd, void __user *arg) -{ - struct sn9c102_device *cam = video_drvdata(filp); - - switch (cmd) { - - case VIDIOC_QUERYCAP: - return sn9c102_vidioc_querycap(cam, arg); - - case VIDIOC_ENUMINPUT: - return sn9c102_vidioc_enuminput(cam, arg); - - case VIDIOC_G_INPUT: - return sn9c102_vidioc_g_input(cam, arg); - - case VIDIOC_S_INPUT: - return sn9c102_vidioc_s_input(cam, arg); - - case VIDIOC_QUERYCTRL: - return sn9c102_vidioc_query_ctrl(cam, arg); - - case VIDIOC_G_CTRL: - return sn9c102_vidioc_g_ctrl(cam, arg); - - case VIDIOC_S_CTRL: - return sn9c102_vidioc_s_ctrl(cam, arg); - - case VIDIOC_CROPCAP: - return sn9c102_vidioc_cropcap(cam, arg); - - case VIDIOC_G_CROP: - return sn9c102_vidioc_g_crop(cam, arg); - - case VIDIOC_S_CROP: - return sn9c102_vidioc_s_crop(cam, arg); - - case VIDIOC_ENUM_FRAMESIZES: - return sn9c102_vidioc_enum_framesizes(cam, arg); - - case VIDIOC_ENUM_FMT: - return sn9c102_vidioc_enum_fmt(cam, arg); - - case VIDIOC_G_FMT: - return sn9c102_vidioc_g_fmt(cam, arg); - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - return sn9c102_vidioc_try_s_fmt(cam, cmd, arg); - - case VIDIOC_G_JPEGCOMP: - return sn9c102_vidioc_g_jpegcomp(cam, arg); - - case VIDIOC_S_JPEGCOMP: - return sn9c102_vidioc_s_jpegcomp(cam, arg); - - case VIDIOC_REQBUFS: - return sn9c102_vidioc_reqbufs(cam, arg); - - case VIDIOC_QUERYBUF: - return sn9c102_vidioc_querybuf(cam, arg); - - case VIDIOC_QBUF: - return sn9c102_vidioc_qbuf(cam, arg); - - case VIDIOC_DQBUF: - return sn9c102_vidioc_dqbuf(cam, filp, arg); - - case VIDIOC_STREAMON: - return sn9c102_vidioc_streamon(cam, arg); - - case VIDIOC_STREAMOFF: - return sn9c102_vidioc_streamoff(cam, arg); - - case VIDIOC_G_PARM: - return sn9c102_vidioc_g_parm(cam, arg); - - case VIDIOC_S_PARM: - return sn9c102_vidioc_s_parm(cam, arg); - - case VIDIOC_ENUMAUDIO: - return sn9c102_vidioc_enumaudio(cam, arg); - - case VIDIOC_G_AUDIO: - return sn9c102_vidioc_g_audio(cam, arg); - - case VIDIOC_S_AUDIO: - return sn9c102_vidioc_s_audio(cam, arg); - - default: - return -ENOTTY; - - } -} - - -static long sn9c102_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct sn9c102_device *cam = video_drvdata(filp); - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - V4LDBG(3, "sn9c102", cmd); - - err = sn9c102_ioctl_v4l2(filp, cmd, (void __user *)arg); - - mutex_unlock(&cam->fileop_mutex); - - return err; -} - -/*****************************************************************************/ - -static const struct v4l2_file_operations sn9c102_fops = { - .owner = THIS_MODULE, - .open = sn9c102_open, - .release = sn9c102_release, - .unlocked_ioctl = sn9c102_ioctl, - .read = sn9c102_read, - .poll = sn9c102_poll, - .mmap = sn9c102_mmap, -}; - -/*****************************************************************************/ - -/* It exists a single interface only. We do not need to validate anything. */ -static int -sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct sn9c102_device* cam; - static unsigned int dev_nr; - unsigned int i; - int err = 0, r; - - if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) - return -ENOMEM; - - cam->usbdev = udev; - - /* register v4l2_device early so it can be used for printks */ - if (v4l2_device_register(&intf->dev, &cam->v4l2_dev)) { - dev_err(&intf->dev, "v4l2_device_register failed\n"); - err = -ENOMEM; - goto fail; - } - - if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { - DBG(1, "kzalloc() failed"); - err = -ENOMEM; - goto fail; - } - - if (!(cam->v4ldev = video_device_alloc())) { - DBG(1, "video_device_alloc() failed"); - err = -ENOMEM; - goto fail; - } - - r = sn9c102_read_reg(cam, 0x00); - if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { - DBG(1, "Sorry, this is not a SN9C1xx-based camera " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - err = -ENODEV; - goto fail; - } - - cam->bridge = id->driver_info; - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - DBG(2, "SN9C10[12] PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - break; - case BRIDGE_SN9C103: - DBG(2, "SN9C103 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - break; - case BRIDGE_SN9C105: - DBG(2, "SN9C105 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - break; - case BRIDGE_SN9C120: - DBG(2, "SN9C120 PC Camera Controller detected " - "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); - break; - } - - for (i = 0; i < ARRAY_SIZE(sn9c102_sensor_table); i++) { - err = sn9c102_sensor_table[i](cam); - if (!err) - break; - } - - if (!err) { - DBG(2, "%s image sensor detected", cam->sensor.name); - DBG(3, "Support for %s maintained by %s", - cam->sensor.name, cam->sensor.maintainer); - } else { - DBG(1, "No supported image sensor detected for this bridge"); - err = -ENODEV; - goto fail; - } - - if (!(cam->bridge & cam->sensor.supported_bridge)) { - DBG(1, "Bridge not supported"); - err = -ENODEV; - goto fail; - } - - if (sn9c102_init(cam)) { - DBG(1, "Initialization failed. I will retry on open()."); - cam->state |= DEV_MISCONFIGURED; - } - - strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); - cam->v4ldev->fops = &sn9c102_fops; - cam->v4ldev->release = video_device_release; - cam->v4ldev->v4l2_dev = &cam->v4l2_dev; - - init_completion(&cam->probe); - - err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, - video_nr[dev_nr]); - if (err) { - DBG(1, "V4L2 device registration failed"); - if (err == -ENFILE && video_nr[dev_nr] == -1) - DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - complete_all(&cam->probe); - goto fail; - } - - DBG(2, "V4L2 device registered as %s", - video_device_node_name(cam->v4ldev)); - - video_set_drvdata(cam->v4ldev, cam); - cam->module_param.force_munmap = force_munmap[dev_nr]; - cam->module_param.frame_timeout = frame_timeout[dev_nr]; - - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - -#ifdef CONFIG_VIDEO_ADV_DEBUG - err = sn9c102_create_sysfs(cam); - if (!err) - DBG(2, "Optional device control through 'sysfs' " - "interface ready"); - else - DBG(2, "Failed to create optional 'sysfs' interface for " - "device controlling. Error #%d", err); -#else - DBG(2, "Optional device control through 'sysfs' interface disabled"); - DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " - "configuration option to enable it."); -#endif - - usb_set_intfdata(intf, cam); - kref_init(&cam->kref); - usb_get_dev(cam->usbdev); - - complete_all(&cam->probe); - - return 0; - -fail: - if (cam) { - kfree(cam->control_buffer); - if (cam->v4ldev) - video_device_release(cam->v4ldev); - v4l2_device_unregister(&cam->v4l2_dev); - kfree(cam); - } - return err; -} - - -static void sn9c102_usb_disconnect(struct usb_interface* intf) -{ - struct sn9c102_device* cam; - - down_write(&sn9c102_dev_lock); - - cam = usb_get_intfdata(intf); - - DBG(2, "Disconnecting %s...", cam->v4ldev->name); - - if (cam->users) { - DBG(2, "Device %s is open! Deregistration and memory " - "deallocation are deferred.", - video_device_node_name(cam->v4ldev)); - cam->state |= DEV_MISCONFIGURED; - sn9c102_stop_transfer(cam); - cam->state |= DEV_DISCONNECTED; - wake_up_interruptible(&cam->wait_frame); - wake_up(&cam->wait_stream); - } else - cam->state |= DEV_DISCONNECTED; - - wake_up_interruptible_all(&cam->wait_open); - - v4l2_device_disconnect(&cam->v4l2_dev); - - kref_put(&cam->kref, sn9c102_release_resources); - - up_write(&sn9c102_dev_lock); -} - - -static struct usb_driver sn9c102_usb_driver = { - .name = "sn9c102", - .id_table = sn9c102_id_table, - .probe = sn9c102_usb_probe, - .disconnect = sn9c102_usb_disconnect, -}; - -module_usb_driver(sn9c102_usb_driver); diff --git a/drivers/media/usb/sn9c102/sn9c102_devtable.h b/drivers/media/usb/sn9c102/sn9c102_devtable.h deleted file mode 100644 index b3d2cc72965..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_devtable.h +++ /dev/null @@ -1,147 +0,0 @@ -/*************************************************************************** - * Table of device identifiers of the SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_DEVTABLE_H_ -#define _SN9C102_DEVTABLE_H_ - -#include <linux/usb.h> - -struct sn9c102_device; - -/* - Each SN9C1xx camera has proper PID/VID identifiers. - SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to - handle the video class interface. -*/ -#define SN9C102_USB_DEVICE(vend, prod, bridge) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_INT_CLASS, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bInterfaceClass = 0xff, \ - .driver_info = (bridge) - -static const struct usb_device_id sn9c102_id_table[] = { - /* SN9C101 and SN9C102 */ -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE - { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */ - { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, -#endif - { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), }, -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE - { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, -#endif - { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */ -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE - { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ - { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, -#endif - { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */ - /* SN9C103 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */ - { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */ -#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE -/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */ - { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */ - { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */ - { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */ -#endif - /* SN9C105 */ -#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE - { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */ - { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, - /* SN9C120 */ - { SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */ -/* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */ - { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, -/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ - { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), }, -#endif - { } -}; - -/* - Probing functions: on success, you must attach the sensor to the camera - by calling sn9c102_attach_sensor(). - To enable the I2C communication, you might need to perform a really basic - initialization of the SN9C1XX chip. - Functions must return 0 on success, the appropriate error otherwise. -*/ -extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); -extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); -extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); -extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); -extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam); -extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); -extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); -extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); -extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); - -#endif /* _SN9C102_DEVTABLE_H_ */ diff --git a/drivers/media/usb/sn9c102/sn9c102_hv7131d.c b/drivers/media/usb/sn9c102/sn9c102_hv7131d.c deleted file mode 100644 index 2dce5c908c8..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_hv7131d.c +++ /dev/null @@ -1,264 +0,0 @@ -/*************************************************************************** - * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int hv7131d_init(struct sn9c102_device* cam) -{ - int err; - - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x60, 0x17}, - {0x0e, 0x18}, {0xf2, 0x19}); - - err += sn9c102_i2c_write(cam, 0x01, 0x04); - err += sn9c102_i2c_write(cam, 0x02, 0x00); - err += sn9c102_i2c_write(cam, 0x28, 0x00); - - return err; -} - - -static int hv7131d_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x26), - r2 = sn9c102_i2c_read(cam, 0x27); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 8) | (r2 & 0xff); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case SN9C102_V4L2_CID_RESET_LEVEL: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) - return -EIO; - ctrl->value &= 0x3f; - return 0; - case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0) - return -EIO; - ctrl->value &= 0x07; - return 0; - default: - return -EINVAL; - } -} - - -static int hv7131d_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8); - err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value); - break; - case SN9C102_V4L2_CID_RESET_LEVEL: - err += sn9c102_i2c_write(cam, 0x30, ctrl->value); - break; - case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: - err += sn9c102_i2c_write(cam, 0x34, ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int hv7131d_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int hv7131d_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x42, 0x19); - else - err += sn9c102_write_reg(cam, 0xf2, 0x19); - - return err; -} - - -static const struct sn9c102_sensor hv7131d = { - .name = "HV7131D", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x11, - .init = &hv7131d_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x0250, - .maximum = 0xffff, - .step = 0x0001, - .default_value = 0x0250, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x1e, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_RESET_LEVEL, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "reset level", - .minimum = 0x19, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x30, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "pixel bias voltage", - .minimum = 0x00, - .maximum = 0x07, - .step = 0x01, - .default_value = 0x02, - .flags = 0, - }, - }, - .get_ctrl = &hv7131d_get_ctrl, - .set_ctrl = &hv7131d_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &hv7131d_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &hv7131d_set_pix_format -}; - - -int sn9c102_probe_hv7131d(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0, err; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); - - r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00); - r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01); - if (err || r0 < 0 || r1 < 0) - return -EIO; - - if ((r0 != 0x00 && r0 != 0x01) || r1 != 0x04) - return -ENODEV; - - sn9c102_attach_sensor(cam, &hv7131d); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_hv7131r.c b/drivers/media/usb/sn9c102/sn9c102_hv7131r.c deleted file mode 100644 index 4295887ff60..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_hv7131r.c +++ /dev/null @@ -1,363 +0,0 @@ -/*************************************************************************** - * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int hv7131r_init(struct sn9c102_device* cam) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04}, - {0x20, 0x05}, {0x20, 0x06}, - {0x03, 0x10}, {0x00, 0x14}, - {0x60, 0x17}, {0x0a, 0x18}, - {0xf0, 0x19}, {0x1d, 0x1a}, - {0x10, 0x1b}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x44, 0x05}, {0x3e, 0x06}, - {0x1a, 0x07}, {0x03, 0x10}, - {0x08, 0x14}, {0xa3, 0x17}, - {0x4b, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x29, 0x21}, - {0x40, 0x22}, {0x54, 0x23}, - {0x66, 0x24}, {0x76, 0x25}, - {0x85, 0x26}, {0x94, 0x27}, - {0xa1, 0x28}, {0xae, 0x29}, - {0xbb, 0x2a}, {0xc7, 0x2b}, - {0xd3, 0x2c}, {0xde, 0x2d}, - {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3F}, - {0xC7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xC7, 0x48}, {0x01, 0x49}, - {0xC7, 0x4A}, {0x01, 0x4B}, - {0xC7, 0x4C}, {0x01, 0x4D}, - {0x44, 0x4E}, {0x00, 0x4F}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xC7, 0x54}, {0x01, 0x55}, - {0xC7, 0x56}, {0x01, 0x57}, - {0xC7, 0x58}, {0x01, 0x59}, - {0x44, 0x5A}, {0x00, 0x5B}, - {0x44, 0x5C}, {0x00, 0x5D}, - {0x44, 0x5E}, {0x00, 0x5F}, - {0xC7, 0x60}, {0x01, 0x61}, - {0xC7, 0x62}, {0x01, 0x63}, - {0xC7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6A}, {0x00, 0x6B}, - {0xC7, 0x6C}, {0x01, 0x6D}, - {0xC7, 0x6E}, {0x01, 0x6F}, - {0xC7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xC7, 0x78}, {0x01, 0x79}, - {0xC7, 0x7A}, {0x01, 0x7B}, - {0xC7, 0x7C}, {0x01, 0x7D}, - {0x44, 0x7E}, {0x00, 0x7F}, - {0x14, 0x84}, {0x00, 0x85}, - {0x27, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xEC, 0x8A}, {0x0f, 0x8B}, - {0xD8, 0x8C}, {0x0f, 0x8D}, - {0x3D, 0x8E}, {0x00, 0x8F}, - {0x3D, 0x90}, {0x00, 0x91}, - {0xCD, 0x92}, {0x0f, 0x93}, - {0xf7, 0x94}, {0x0f, 0x95}, - {0x0C, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9A}, {0x00, 0x9B}, - {0x04, 0x9C}, {0x00, 0x9D}, - {0x08, 0x9E}, {0x00, 0x9F}, - {0x2D, 0xC0}, {0x2D, 0xC1}, - {0x3A, 0xC2}, {0x05, 0xC3}, - {0x04, 0xC4}, {0x3F, 0xC5}, - {0x00, 0xC6}, {0x00, 0xC7}, - {0x50, 0xC8}, {0x3C, 0xC9}, - {0x28, 0xCA}, {0xD8, 0xCB}, - {0x14, 0xCC}, {0xEC, 0xCD}, - {0x32, 0xCE}, {0xDD, 0xCF}, - {0x32, 0xD0}, {0xDD, 0xD1}, - {0x6A, 0xD2}, {0x50, 0xD3}, - {0x00, 0xD4}, {0x00, 0xD5}, - {0x00, 0xD6}); - break; - default: - break; - } - - err += sn9c102_i2c_write(cam, 0x20, 0x00); - err += sn9c102_i2c_write(cam, 0x21, 0xd6); - err += sn9c102_i2c_write(cam, 0x25, 0x06); - - return err; -} - - -static int hv7131r_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) - return -EIO; - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) - return -EIO; - ctrl->value = ctrl->value & 0x3f; - return 0; - case V4L2_CID_BLACK_LEVEL: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x08) ? 1 : 0; - return 0; - default: - return -EINVAL; - } -} - - -static int hv7131r_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x30, ctrl->value); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x31, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x33, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x32, ctrl->value); - break; - case V4L2_CID_BLACK_LEVEL: - { - int r = sn9c102_i2c_read(cam, 0x01); - if (r < 0) - return -EIO; - err += sn9c102_i2c_write(cam, 0x01, - (ctrl->value<<3) | (r&0xf7)); - } - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int hv7131r_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int hv7131r_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xa0, 0x19); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } else { - err += sn9c102_write_reg(cam, 0x30, 0x19); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xa5, 0x17); - err += sn9c102_i2c_write(cam, 0x01, 0x24); - } else { - err += sn9c102_write_reg(cam, 0xa3, 0x17); - err += sn9c102_i2c_write(cam, 0x01, 0x04); - } - break; - default: - break; - } - - return err; -} - - -static const struct sn9c102_sensor hv7131r = { - .name = "HV7131R", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x11, - .init = &hv7131r_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x40, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x08, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x1a, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x2f, - .flags = 0, - }, - { - .id = V4L2_CID_BLACK_LEVEL, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto black level compensation", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &hv7131r_get_ctrl, - .set_ctrl = &hv7131r_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &hv7131r_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &hv7131r_set_pix_format -}; - - -int sn9c102_probe_hv7131r(struct sn9c102_device* cam) -{ - int devid, err; - - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02}, - {0x34, 0x01}, {0x20, 0x17}, - {0x34, 0x01}, {0x46, 0x01}); - - devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00); - if (err || devid < 0) - return -EIO; - - if (devid != 0x02) - return -ENODEV; - - sn9c102_attach_sensor(cam, &hv7131r); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_mi0343.c b/drivers/media/usb/sn9c102/sn9c102_mi0343.c deleted file mode 100644 index 1f5b09bec89..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_mi0343.c +++ /dev/null @@ -1,352 +0,0 @@ -/*************************************************************************** - * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int mi0343_init(struct sn9c102_device* cam) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x40, 0x01}, - {0x20, 0x17}, {0x07, 0x18}, - {0xa0, 0x19}); - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe1, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x81, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x17, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x11, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, - 0x04, 0x9a, 0, 0); - - return err; -} - - -static int mi0343_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u8 data[2]; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2, - data) < 0) - return -EIO; - ctrl->value = data[0]; - return 0; - case V4L2_CID_GAIN: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2, - data) < 0) - return -EIO; - break; - case V4L2_CID_HFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x20 ? 1 : 0; - return 0; - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x80 ? 1 : 0; - return 0; - case V4L2_CID_RED_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2, - data) < 0) - return -EIO; - break; - case V4L2_CID_BLUE_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2, - data) < 0) - return -EIO; - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2, - data) < 0) - return -EIO; - break; - default: - return -EINVAL; - } - - switch (ctrl->id) { - case V4L2_CID_GAIN: - case V4L2_CID_RED_BALANCE: - case V4L2_CID_BLUE_BALANCE: - case SN9C102_V4L2_CID_GREEN_BALANCE: - ctrl->value = data[1] | (data[0] << 8); - if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) - ctrl->value -= 0x10; - else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) - ctrl->value -= 0x60; - else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff) - ctrl->value -= 0xe0; - } - - return 0; -} - - -static int mi0343_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u16 reg = 0; - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - case V4L2_CID_RED_BALANCE: - case V4L2_CID_BLUE_BALANCE: - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (ctrl->value <= (0x3f-0x10)) - reg = 0x10 + ctrl->value; - else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60))) - reg = 0x60 + (ctrl->value - (0x3f-0x10)); - else - reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60)); - break; - } - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x09, ctrl->value, 0x00, - 0, 0); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x35, reg >> 8, reg & 0xff, - 0, 0); - break; - case V4L2_CID_HFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x40:0x00, - ctrl->value ? 0x20:0x00, - 0, 0); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x80:0x00, - ctrl->value ? 0x80:0x00, - 0, 0); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2d, reg >> 8, reg & 0xff, - 0, 0); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2c, reg >> 8, reg & 0xff, - 0, 0); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2b, reg >> 8, reg & 0xff, - 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2e, reg >> 8, reg & 0xff, - 0, 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int mi0343_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int mi0343_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x03, 0, 0); - err += sn9c102_write_reg(cam, 0x20, 0x19); - } else { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x05, 0, 0); - err += sn9c102_write_reg(cam, 0xa0, 0x19); - } - - return err; -} - - -static const struct sn9c102_sensor mi0343 = { - .name = "MI-0343", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5d, - .init = &mi0343_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x06, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/ - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &mi0343_get_ctrl, - .set_ctrl = &mi0343_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mi0343_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mi0343_set_pix_format -}; - - -int sn9c102_probe_mi0343(struct sn9c102_device* cam) -{ - u8 data[2]; - - if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17})) - return -EIO; - - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, - 2, data) < 0) - return -EIO; - - if (data[1] != 0x42 || data[0] != 0xe3) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mi0343); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_mi0360.c b/drivers/media/usb/sn9c102/sn9c102_mi0360.c deleted file mode 100644 index d973fc1973d..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_mi0360.c +++ /dev/null @@ -1,453 +0,0 @@ -/*************************************************************************** - * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int mi0360_init(struct sn9c102_device* cam) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x40, 0x01}, - {0x20, 0x17}, {0x07, 0x18}, - {0xa0, 0x19}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x50, 0x05}, {0x20, 0x06}, - {0x10, 0x07}, {0x03, 0x10}, - {0x08, 0x14}, {0xa2, 0x17}, - {0x47, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x29, 0x21}, - {0x40, 0x22}, {0x54, 0x23}, - {0x66, 0x24}, {0x76, 0x25}, - {0x85, 0x26}, {0x94, 0x27}, - {0xa1, 0x28}, {0xae, 0x29}, - {0xbb, 0x2a}, {0xc7, 0x2b}, - {0xd3, 0x2c}, {0xde, 0x2d}, - {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3F}, - {0xC7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xC7, 0x48}, {0x01, 0x49}, - {0xC7, 0x4A}, {0x01, 0x4B}, - {0xC7, 0x4C}, {0x01, 0x4D}, - {0x44, 0x4E}, {0x00, 0x4F}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xC7, 0x54}, {0x01, 0x55}, - {0xC7, 0x56}, {0x01, 0x57}, - {0xC7, 0x58}, {0x01, 0x59}, - {0x44, 0x5A}, {0x00, 0x5B}, - {0x44, 0x5C}, {0x00, 0x5D}, - {0x44, 0x5E}, {0x00, 0x5F}, - {0xC7, 0x60}, {0x01, 0x61}, - {0xC7, 0x62}, {0x01, 0x63}, - {0xC7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6A}, {0x00, 0x6B}, - {0xC7, 0x6C}, {0x01, 0x6D}, - {0xC7, 0x6E}, {0x01, 0x6F}, - {0xC7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xC7, 0x78}, {0x01, 0x79}, - {0xC7, 0x7A}, {0x01, 0x7B}, - {0xC7, 0x7C}, {0x01, 0x7D}, - {0x44, 0x7E}, {0x00, 0x7F}, - {0x14, 0x84}, {0x00, 0x85}, - {0x27, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xEC, 0x8A}, {0x0f, 0x8B}, - {0xD8, 0x8C}, {0x0f, 0x8D}, - {0x3D, 0x8E}, {0x00, 0x8F}, - {0x3D, 0x90}, {0x00, 0x91}, - {0xCD, 0x92}, {0x0f, 0x93}, - {0xf7, 0x94}, {0x0f, 0x95}, - {0x0C, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9A}, {0x00, 0x9B}, - {0x04, 0x9C}, {0x00, 0x9D}, - {0x08, 0x9E}, {0x00, 0x9F}, - {0x2D, 0xC0}, {0x2D, 0xC1}, - {0x3A, 0xC2}, {0x05, 0xC3}, - {0x04, 0xC4}, {0x3F, 0xC5}, - {0x00, 0xC6}, {0x00, 0xC7}, - {0x50, 0xC8}, {0x3C, 0xC9}, - {0x28, 0xCA}, {0xD8, 0xCB}, - {0x14, 0xCC}, {0xEC, 0xCD}, - {0x32, 0xCE}, {0xDD, 0xCF}, - {0x32, 0xD0}, {0xDD, 0xD1}, - {0x6A, 0xD2}, {0x50, 0xD3}, - {0x00, 0xD4}, {0x00, 0xD5}, - {0x00, 0xD6}); - break; - default: - break; - } - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe1, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x81, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x17, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x11, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, - 0x04, 0x9a, 0, 0); - - return err; -} - - -static int mi0360_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u8 data[2]; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2, - data) < 0) - return -EIO; - ctrl->value = data[0]; - return 0; - case V4L2_CID_GAIN: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2, - data) < 0) - return -EIO; - ctrl->value = data[1]; - return 0; - case V4L2_CID_RED_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2, - data) < 0) - return -EIO; - ctrl->value = data[1]; - return 0; - case V4L2_CID_BLUE_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2, - data) < 0) - return -EIO; - ctrl->value = data[1]; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2, - data) < 0) - return -EIO; - ctrl->value = data[1]; - return 0; - case V4L2_CID_HFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x20 ? 1 : 0; - return 0; - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x80 ? 1 : 0; - return 0; - default: - return -EINVAL; - } - - return 0; -} - - -static int mi0360_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x09, ctrl->value, 0x00, - 0, 0); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x35, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2c, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2d, 0x03, ctrl->value, - 0, 0); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2b, 0x03, ctrl->value, - 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x2e, 0x03, ctrl->value, - 0, 0); - break; - case V4L2_CID_HFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x40:0x00, - ctrl->value ? 0x20:0x00, - 0, 0); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, ctrl->value ? 0x80:0x00, - ctrl->value ? 0x80:0x00, - 0, 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int mi0360_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1; - break; - default: - break; - } - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int mi0360_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x05, 0, 0); - err += sn9c102_write_reg(cam, 0x60, 0x19); - if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 || - sn9c102_get_bridge(cam) == BRIDGE_SN9C120) - err += sn9c102_write_reg(cam, 0xa6, 0x17); - } else { - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x0a, 0x00, 0x02, 0, 0); - err += sn9c102_write_reg(cam, 0x20, 0x19); - if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 || - sn9c102_get_bridge(cam) == BRIDGE_SN9C120) - err += sn9c102_write_reg(cam, 0xa2, 0x17); - } - - return err; -} - - -static const struct sn9c102_sensor mi0360 = { - .name = "MI-0360", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5d, - .init = &mi0360_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x05, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x25, - .flags = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x0f, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x32, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x25, - .flags = 0, - }, - }, - .get_ctrl = &mi0360_get_ctrl, - .set_ctrl = &mi0360_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mi0360_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mi0360_set_pix_format -}; - - -int sn9c102_probe_mi0360(struct sn9c102_device* cam) -{ - - u8 data[2]; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C103: - if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17})) - return -EIO; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17})) - return -EIO; - break; - default: - break; - } - - if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00, - 2, data) < 0) - return -EIO; - - if (data[0] != 0x82 || data[1] != 0x43) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mi0360); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_mt9v111.c b/drivers/media/usb/sn9c102/sn9c102_mt9v111.c deleted file mode 100644 index 95986eb492e..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_mt9v111.c +++ /dev/null @@ -1,260 +0,0 @@ -/*************************************************************************** - * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int mt9v111_init(struct sn9c102_device *cam) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x1f, 0x05}, {0x20, 0x06}, - {0x1f, 0x07}, {0x81, 0x08}, - {0x5c, 0x09}, {0x00, 0x0a}, - {0x00, 0x0b}, {0x00, 0x0c}, - {0x00, 0x0d}, {0x00, 0x0e}, - {0x00, 0x0f}, {0x03, 0x10}, - {0x00, 0x11}, {0x00, 0x12}, - {0x02, 0x13}, {0x14, 0x14}, - {0x28, 0x15}, {0x1e, 0x16}, - {0xe2, 0x17}, {0x06, 0x18}, - {0x00, 0x19}, {0x00, 0x1a}, - {0x00, 0x1b}, {0x08, 0x20}, - {0x39, 0x21}, {0x51, 0x22}, - {0x63, 0x23}, {0x73, 0x24}, - {0x82, 0x25}, {0x8f, 0x26}, - {0x9b, 0x27}, {0xa7, 0x28}, - {0xb1, 0x29}, {0xbc, 0x2a}, - {0xc6, 0x2b}, {0xcf, 0x2c}, - {0xd8, 0x2d}, {0xe1, 0x2e}, - {0xea, 0x2f}, {0xf2, 0x30}, - {0x13, 0x84}, {0x00, 0x85}, - {0x25, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xee, 0x8a}, {0x0f, 0x8b}, - {0xe5, 0x8c}, {0x0f, 0x8d}, - {0x2e, 0x8e}, {0x00, 0x8f}, - {0x30, 0x90}, {0x00, 0x91}, - {0xd4, 0x92}, {0x0f, 0x93}, - {0xfc, 0x94}, {0x0f, 0x95}, - {0x14, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x60, 0x99}, - {0x07, 0x9a}, {0x40, 0x9b}, - {0x20, 0x9c}, {0x00, 0x9d}, - {0x00, 0x9e}, {0x00, 0x9f}, - {0x2d, 0xc0}, {0x2d, 0xc1}, - {0x3a, 0xc2}, {0x05, 0xc3}, - {0x04, 0xc4}, {0x3f, 0xc5}, - {0x00, 0xc6}, {0x00, 0xc7}, - {0x50, 0xc8}, {0x3c, 0xc9}, - {0x28, 0xca}, {0xd8, 0xcb}, - {0x14, 0xcc}, {0xec, 0xcd}, - {0x32, 0xce}, {0xdd, 0xcf}, - {0x2d, 0xd0}, {0xdd, 0xd1}, - {0x6a, 0xd2}, {0x50, 0xd3}, - {0x60, 0xd4}, {0x00, 0xd5}, - {0x00, 0xd6}); - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, - 0x04, 0x80, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x04, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, - 0x00, 0x08, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02, - 0x00, 0x16, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe7, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x87, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x40, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x09, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07, - 0x30, 0x02, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12, - 0x00, 0xb0, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13, - 0x00, 0x7c, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x04, 0, 0); - - return err; -} - -static int mt9v111_get_ctrl(struct sn9c102_device *cam, - struct v4l2_control *ctrl) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - u8 data[2]; - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x80 ? 1 : 0; - return 0; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - -static int mt9v111_set_ctrl(struct sn9c102_device *cam, - const struct v4l2_control *ctrl) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, - ctrl->value ? 0x80 : 0x00, - ctrl->value ? 0x80 : 0x00, 0, - 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - -static int mt9v111_set_crop(struct sn9c102_device *cam, - const struct v4l2_rect *rect) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - -static int mt9v111_set_pix_format(struct sn9c102_device *cam, - const struct v4l2_pix_format *pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xb4, 0x17); - } else { - err += sn9c102_write_reg(cam, 0xe2, 0x17); - } - - return err; -} - - -static const struct sn9c102_sensor mt9v111 = { - .name = "MT9V111", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5c, - .init = &mt9v111_init, - .qctrl = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - }, - .get_ctrl = &mt9v111_get_ctrl, - .set_ctrl = &mt9v111_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mt9v111_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mt9v111_set_pix_format -}; - - -int sn9c102_probe_mt9v111(struct sn9c102_device *cam) -{ - u8 data[2]; - int err = 0; - - err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x29, 0x01}, {0x42, 0x17}, - {0x62, 0x17}, {0x08, 0x01}); - err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4, - mt9v111.i2c_slave_id, 0x01, 0x00, - 0x04, 0, 0); - if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111, - mt9v111.i2c_slave_id, 0x36, 2, - data) < 0) - return -EIO; - - if (data[0] != 0x82 || data[1] != 0x3a) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mt9v111); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_ov7630.c b/drivers/media/usb/sn9c102/sn9c102_ov7630.c deleted file mode 100644 index 803712c29f0..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_ov7630.c +++ /dev/null @@ -1,626 +0,0 @@ -/*************************************************************************** - * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int ov7630_init(struct sn9c102_device* cam) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, - {0x0f, 0x18}, {0x50, 0x19}); - - err += sn9c102_i2c_write(cam, 0x12, 0x8d); - err += sn9c102_i2c_write(cam, 0x12, 0x0d); - err += sn9c102_i2c_write(cam, 0x11, 0x00); - err += sn9c102_i2c_write(cam, 0x15, 0x35); - err += sn9c102_i2c_write(cam, 0x16, 0x03); - err += sn9c102_i2c_write(cam, 0x17, 0x1c); - err += sn9c102_i2c_write(cam, 0x18, 0xbd); - err += sn9c102_i2c_write(cam, 0x19, 0x06); - err += sn9c102_i2c_write(cam, 0x1a, 0xf6); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); - err += sn9c102_i2c_write(cam, 0x20, 0x44); - err += sn9c102_i2c_write(cam, 0x23, 0xee); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0x9a); - err += sn9c102_i2c_write(cam, 0x28, 0x20); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2f, 0x3d); - err += sn9c102_i2c_write(cam, 0x30, 0x24); - err += sn9c102_i2c_write(cam, 0x32, 0x86); - err += sn9c102_i2c_write(cam, 0x60, 0xa9); - err += sn9c102_i2c_write(cam, 0x61, 0x42); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x88); - err += sn9c102_i2c_write(cam, 0x70, 0x0b); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x74, 0x21); - err += sn9c102_i2c_write(cam, 0x7d, 0xf7); - break; - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x20, 0x05}, - {0x20, 0x06}, {0x20, 0x07}, - {0x03, 0x10}, {0x0a, 0x14}, - {0x60, 0x17}, {0x0f, 0x18}, - {0x50, 0x19}, {0x1d, 0x1a}, - {0x10, 0x1b}, {0x02, 0x1c}, - {0x03, 0x1d}, {0x0f, 0x1e}, - {0x0c, 0x1f}, {0x00, 0x20}, - {0x10, 0x21}, {0x20, 0x22}, - {0x30, 0x23}, {0x40, 0x24}, - {0x50, 0x25}, {0x60, 0x26}, - {0x70, 0x27}, {0x80, 0x28}, - {0x90, 0x29}, {0xa0, 0x2a}, - {0xb0, 0x2b}, {0xc0, 0x2c}, - {0xd0, 0x2d}, {0xe0, 0x2e}, - {0xf0, 0x2f}, {0xff, 0x30}); - - err += sn9c102_i2c_write(cam, 0x12, 0x8d); - err += sn9c102_i2c_write(cam, 0x12, 0x0d); - err += sn9c102_i2c_write(cam, 0x15, 0x34); - err += sn9c102_i2c_write(cam, 0x11, 0x01); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); - err += sn9c102_i2c_write(cam, 0x20, 0x44); - err += sn9c102_i2c_write(cam, 0x23, 0xee); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0x9a); - err += sn9c102_i2c_write(cam, 0x28, 0x20); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2f, 0x3d); - err += sn9c102_i2c_write(cam, 0x30, 0x24); - err += sn9c102_i2c_write(cam, 0x32, 0x86); - err += sn9c102_i2c_write(cam, 0x60, 0xa9); - err += sn9c102_i2c_write(cam, 0x61, 0x42); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x88); - err += sn9c102_i2c_write(cam, 0x70, 0x0b); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x74, 0x21); - err += sn9c102_i2c_write(cam, 0x7d, 0xf7); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x03, 0x10}, - {0x0a, 0x14}, {0xe2, 0x17}, - {0x0b, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x24, 0x21}, - {0x3b, 0x22}, {0x47, 0x23}, - {0x60, 0x24}, {0x71, 0x25}, - {0x80, 0x26}, {0x8f, 0x27}, - {0x9d, 0x28}, {0xaa, 0x29}, - {0xb8, 0x2a}, {0xc4, 0x2b}, - {0xd1, 0x2c}, {0xdd, 0x2d}, - {0xe8, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3f}, - {0xc7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xc7, 0x48}, {0x01, 0x49}, - {0xc7, 0x4a}, {0x01, 0x4b}, - {0xc7, 0x4c}, {0x01, 0x4d}, - {0x44, 0x4e}, {0x00, 0x4f}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xc7, 0x54}, {0x01, 0x55}, - {0xc7, 0x56}, {0x01, 0x57}, - {0xc7, 0x58}, {0x01, 0x59}, - {0x44, 0x5a}, {0x00, 0x5b}, - {0x44, 0x5c}, {0x00, 0x5d}, - {0x44, 0x5e}, {0x00, 0x5f}, - {0xc7, 0x60}, {0x01, 0x61}, - {0xc7, 0x62}, {0x01, 0x63}, - {0xc7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6a}, {0x00, 0x6b}, - {0xc7, 0x6c}, {0x01, 0x6d}, - {0xc7, 0x6e}, {0x01, 0x6f}, - {0xc7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xc7, 0x78}, {0x01, 0x79}, - {0xc7, 0x7a}, {0x01, 0x7b}, - {0xc7, 0x7c}, {0x01, 0x7d}, - {0x44, 0x7e}, {0x00, 0x7f}, - {0x17, 0x84}, {0x00, 0x85}, - {0x2e, 0x86}, {0x00, 0x87}, - {0x09, 0x88}, {0x00, 0x89}, - {0xe8, 0x8a}, {0x0f, 0x8b}, - {0xda, 0x8c}, {0x0f, 0x8d}, - {0x40, 0x8e}, {0x00, 0x8f}, - {0x37, 0x90}, {0x00, 0x91}, - {0xcf, 0x92}, {0x0f, 0x93}, - {0xfa, 0x94}, {0x0f, 0x95}, - {0x00, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x00, 0x9a}, {0x40, 0x9b}, - {0x20, 0x9c}, {0x00, 0x9d}, - {0x00, 0x9e}, {0x00, 0x9f}, - {0x2d, 0xc0}, {0x2d, 0xc1}, - {0x3a, 0xc2}, {0x00, 0xc3}, - {0x04, 0xc4}, {0x3f, 0xc5}, - {0x00, 0xc6}, {0x00, 0xc7}, - {0x50, 0xc8}, {0x3c, 0xc9}, - {0x28, 0xca}, {0xd8, 0xcb}, - {0x14, 0xcc}, {0xec, 0xcd}, - {0x32, 0xce}, {0xdd, 0xcf}, - {0x32, 0xd0}, {0xdd, 0xd1}, - {0x6a, 0xd2}, {0x50, 0xd3}, - {0x60, 0xd4}, {0x00, 0xd5}, - {0x00, 0xd6}); - - err += sn9c102_i2c_write(cam, 0x12, 0x80); - err += sn9c102_i2c_write(cam, 0x12, 0x48); - err += sn9c102_i2c_write(cam, 0x01, 0x80); - err += sn9c102_i2c_write(cam, 0x02, 0x80); - err += sn9c102_i2c_write(cam, 0x03, 0x80); - err += sn9c102_i2c_write(cam, 0x04, 0x10); - err += sn9c102_i2c_write(cam, 0x05, 0x20); - err += sn9c102_i2c_write(cam, 0x06, 0x80); - err += sn9c102_i2c_write(cam, 0x11, 0x00); - err += sn9c102_i2c_write(cam, 0x0c, 0x20); - err += sn9c102_i2c_write(cam, 0x0d, 0x20); - err += sn9c102_i2c_write(cam, 0x15, 0x80); - err += sn9c102_i2c_write(cam, 0x16, 0x03); - err += sn9c102_i2c_write(cam, 0x17, 0x1b); - err += sn9c102_i2c_write(cam, 0x18, 0xbd); - err += sn9c102_i2c_write(cam, 0x19, 0x05); - err += sn9c102_i2c_write(cam, 0x1a, 0xf6); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); - err += sn9c102_i2c_write(cam, 0x21, 0x1b); - err += sn9c102_i2c_write(cam, 0x22, 0x00); - err += sn9c102_i2c_write(cam, 0x23, 0xde); - err += sn9c102_i2c_write(cam, 0x24, 0x10); - err += sn9c102_i2c_write(cam, 0x25, 0x8a); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0xca); - err += sn9c102_i2c_write(cam, 0x28, 0xa2); - err += sn9c102_i2c_write(cam, 0x29, 0x74); - err += sn9c102_i2c_write(cam, 0x2a, 0x88); - err += sn9c102_i2c_write(cam, 0x2b, 0x34); - err += sn9c102_i2c_write(cam, 0x2c, 0x88); - err += sn9c102_i2c_write(cam, 0x2e, 0x00); - err += sn9c102_i2c_write(cam, 0x2f, 0x00); - err += sn9c102_i2c_write(cam, 0x30, 0x00); - err += sn9c102_i2c_write(cam, 0x32, 0xc2); - err += sn9c102_i2c_write(cam, 0x33, 0x08); - err += sn9c102_i2c_write(cam, 0x4c, 0x40); - err += sn9c102_i2c_write(cam, 0x4d, 0xf3); - err += sn9c102_i2c_write(cam, 0x60, 0x05); - err += sn9c102_i2c_write(cam, 0x61, 0x40); - err += sn9c102_i2c_write(cam, 0x62, 0x12); - err += sn9c102_i2c_write(cam, 0x63, 0x57); - err += sn9c102_i2c_write(cam, 0x64, 0x73); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x66, 0x55); - err += sn9c102_i2c_write(cam, 0x67, 0x01); - err += sn9c102_i2c_write(cam, 0x68, 0xac); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x1f); - err += sn9c102_i2c_write(cam, 0x70, 0x01); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x72, 0x10); - err += sn9c102_i2c_write(cam, 0x73, 0x50); - err += sn9c102_i2c_write(cam, 0x74, 0x20); - err += sn9c102_i2c_write(cam, 0x76, 0x01); - err += sn9c102_i2c_write(cam, 0x77, 0xf3); - err += sn9c102_i2c_write(cam, 0x78, 0x90); - err += sn9c102_i2c_write(cam, 0x79, 0x98); - err += sn9c102_i2c_write(cam, 0x7a, 0x98); - err += sn9c102_i2c_write(cam, 0x7b, 0x00); - err += sn9c102_i2c_write(cam, 0x7c, 0x38); - err += sn9c102_i2c_write(cam, 0x7d, 0xff); - break; - default: - break; - } - - return err; -} - - -static int ov7630_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - enum sn9c102_bridge bridge = sn9c102_get_bridge(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) - return -EIO; - break; - case V4L2_CID_RED_BALANCE: - if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) - ctrl->value = sn9c102_pread_reg(cam, 0x05); - else - ctrl->value = sn9c102_pread_reg(cam, 0x07); - break; - case V4L2_CID_BLUE_BALANCE: - ctrl->value = sn9c102_pread_reg(cam, 0x06); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) - ctrl->value = sn9c102_pread_reg(cam, 0x07); - else - ctrl->value = sn9c102_pread_reg(cam, 0x05); - break; - break; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) - return -EIO; - ctrl->value &= 0x3f; - break; - case V4L2_CID_DO_WHITE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) - return -EIO; - ctrl->value &= 0x3f; - break; - case V4L2_CID_WHITENESS: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0) - return -EIO; - ctrl->value &= 0x3f; - break; - case V4L2_CID_AUTOGAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0) - return -EIO; - ctrl->value &= 0x01; - break; - case V4L2_CID_VFLIP: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x80) ? 1 : 0; - break; - case SN9C102_V4L2_CID_GAMMA: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x02) ? 1 : 0; - break; - case SN9C102_V4L2_CID_BAND_FILTER: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x02) ? 1 : 0; - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7630_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - enum sn9c102_bridge bridge = sn9c102_get_bridge(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value); - break; - case V4L2_CID_RED_BALANCE: - if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) - err += sn9c102_write_reg(cam, ctrl->value, 0x05); - else - err += sn9c102_write_reg(cam, ctrl->value, 0x07); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x06); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120) - err += sn9c102_write_reg(cam, ctrl->value, 0x07); - else - err += sn9c102_write_reg(cam, ctrl->value, 0x05); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x00, ctrl->value); - break; - case V4L2_CID_DO_WHITE_BALANCE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - case V4L2_CID_WHITENESS: - err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); - break; - case V4L2_CID_AUTOGAIN: - err += sn9c102_i2c_write(cam, 0x13, ctrl->value | - (ctrl->value << 1)); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); - break; - case SN9C102_V4L2_CID_GAMMA: - err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2); - break; - case SN9C102_V4L2_CID_BAND_FILTER: - err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7630_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1; - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; - break; - default: - break; - } - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int ov7630_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - case BRIDGE_SN9C103: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) - err += sn9c102_write_reg(cam, 0x50, 0x19); - else - err += sn9c102_write_reg(cam, 0x20, 0x19); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xe5, 0x17); - err += sn9c102_i2c_write(cam, 0x11, 0x04); - } else { - err += sn9c102_write_reg(cam, 0xe2, 0x17); - err += sn9c102_i2c_write(cam, 0x11, 0x02); - } - break; - default: - break; - } - - return err; -} - - -static const struct sn9c102_sensor ov7630 = { - .name = "OV7630", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 | - BRIDGE_SN9C105 | BRIDGE_SN9C120, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x21, - .init = &ov7630_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x60, - .flags = 0, - }, - { - .id = V4L2_CID_WHITENESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "white balance background: red", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_DO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "white balance background: blue", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto adjust", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_BAND_FILTER, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "band filter", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "rgb gamma", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &ov7630_get_ctrl, - .set_ctrl = &ov7630_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &ov7630_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SN9C10X, - .priv = 8, - }, - .set_pix_format = &ov7630_set_pix_format -}; - - -int sn9c102_probe_ov7630(struct sn9c102_device* cam) -{ - int pid, ver, err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); - break; - case BRIDGE_SN9C103: /* do _not_ change anything! */ - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x42, 0x01}, - {0x28, 0x17}, {0x44, 0x02}); - pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); - if (err || pid < 0) /* try a different initialization */ - err += sn9c102_write_const_regs(cam, {0x01, 0x01}, - {0x00, 0x01}); - break; - case BRIDGE_SN9C105: - case BRIDGE_SN9C120: - err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x29, 0x01}, {0x74, 0x02}, - {0x0e, 0x01}, {0x44, 0x01}); - break; - default: - break; - } - - pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); - ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b); - if (err || pid < 0 || ver < 0) - return -EIO; - if (pid != 0x76 || ver != 0x31) - return -ENODEV; - sn9c102_attach_sensor(cam, &ov7630); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_ov7660.c b/drivers/media/usb/sn9c102/sn9c102_ov7660.c deleted file mode 100644 index 7977795d342..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_ov7660.c +++ /dev/null @@ -1,538 +0,0 @@ -/*************************************************************************** - * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int ov7660_init(struct sn9c102_device* cam) -{ - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x03, 0x10}, - {0x08, 0x14}, {0x20, 0x17}, - {0x8b, 0x18}, {0x00, 0x19}, - {0x1d, 0x1a}, {0x10, 0x1b}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x29, 0x21}, - {0x40, 0x22}, {0x54, 0x23}, - {0x66, 0x24}, {0x76, 0x25}, - {0x85, 0x26}, {0x94, 0x27}, - {0xa1, 0x28}, {0xae, 0x29}, - {0xbb, 0x2a}, {0xc7, 0x2b}, - {0xd3, 0x2c}, {0xde, 0x2d}, - {0xea, 0x2e}, {0xf4, 0x2f}, - {0xff, 0x30}, {0x00, 0x3f}, - {0xc7, 0x40}, {0x01, 0x41}, - {0x44, 0x42}, {0x00, 0x43}, - {0x44, 0x44}, {0x00, 0x45}, - {0x44, 0x46}, {0x00, 0x47}, - {0xc7, 0x48}, {0x01, 0x49}, - {0xc7, 0x4a}, {0x01, 0x4b}, - {0xc7, 0x4c}, {0x01, 0x4d}, - {0x44, 0x4e}, {0x00, 0x4f}, - {0x44, 0x50}, {0x00, 0x51}, - {0x44, 0x52}, {0x00, 0x53}, - {0xc7, 0x54}, {0x01, 0x55}, - {0xc7, 0x56}, {0x01, 0x57}, - {0xc7, 0x58}, {0x01, 0x59}, - {0x44, 0x5a}, {0x00, 0x5b}, - {0x44, 0x5c}, {0x00, 0x5d}, - {0x44, 0x5e}, {0x00, 0x5f}, - {0xc7, 0x60}, {0x01, 0x61}, - {0xc7, 0x62}, {0x01, 0x63}, - {0xc7, 0x64}, {0x01, 0x65}, - {0x44, 0x66}, {0x00, 0x67}, - {0x44, 0x68}, {0x00, 0x69}, - {0x44, 0x6a}, {0x00, 0x6b}, - {0xc7, 0x6c}, {0x01, 0x6d}, - {0xc7, 0x6e}, {0x01, 0x6f}, - {0xc7, 0x70}, {0x01, 0x71}, - {0x44, 0x72}, {0x00, 0x73}, - {0x44, 0x74}, {0x00, 0x75}, - {0x44, 0x76}, {0x00, 0x77}, - {0xc7, 0x78}, {0x01, 0x79}, - {0xc7, 0x7a}, {0x01, 0x7b}, - {0xc7, 0x7c}, {0x01, 0x7d}, - {0x44, 0x7e}, {0x00, 0x7f}, - {0x14, 0x84}, {0x00, 0x85}, - {0x27, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xec, 0x8a}, {0x0f, 0x8b}, - {0xd8, 0x8c}, {0x0f, 0x8d}, - {0x3d, 0x8e}, {0x00, 0x8f}, - {0x3d, 0x90}, {0x00, 0x91}, - {0xcd, 0x92}, {0x0f, 0x93}, - {0xf7, 0x94}, {0x0f, 0x95}, - {0x0c, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x66, 0x99}, - {0x05, 0x9a}, {0x00, 0x9b}, - {0x04, 0x9c}, {0x00, 0x9d}, - {0x08, 0x9e}, {0x00, 0x9f}, - {0x2d, 0xc0}, {0x2d, 0xc1}, - {0x3a, 0xc2}, {0x05, 0xc3}, - {0x04, 0xc4}, {0x3f, 0xc5}, - {0x00, 0xc6}, {0x00, 0xc7}, - {0x50, 0xc8}, {0x3C, 0xc9}, - {0x28, 0xca}, {0xd8, 0xcb}, - {0x14, 0xcc}, {0xec, 0xcd}, - {0x32, 0xce}, {0xdd, 0xcf}, - {0x32, 0xd0}, {0xdd, 0xd1}, - {0x6a, 0xd2}, {0x50, 0xd3}, - {0x00, 0xd4}, {0x00, 0xd5}, - {0x00, 0xd6}); - - err += sn9c102_i2c_write(cam, 0x12, 0x80); - err += sn9c102_i2c_write(cam, 0x11, 0x09); - err += sn9c102_i2c_write(cam, 0x00, 0x0A); - err += sn9c102_i2c_write(cam, 0x01, 0x80); - err += sn9c102_i2c_write(cam, 0x02, 0x80); - err += sn9c102_i2c_write(cam, 0x03, 0x00); - err += sn9c102_i2c_write(cam, 0x04, 0x00); - err += sn9c102_i2c_write(cam, 0x05, 0x08); - err += sn9c102_i2c_write(cam, 0x06, 0x0B); - err += sn9c102_i2c_write(cam, 0x07, 0x00); - err += sn9c102_i2c_write(cam, 0x08, 0x1C); - err += sn9c102_i2c_write(cam, 0x09, 0x01); - err += sn9c102_i2c_write(cam, 0x0A, 0x76); - err += sn9c102_i2c_write(cam, 0x0B, 0x60); - err += sn9c102_i2c_write(cam, 0x0C, 0x00); - err += sn9c102_i2c_write(cam, 0x0D, 0x08); - err += sn9c102_i2c_write(cam, 0x0E, 0x04); - err += sn9c102_i2c_write(cam, 0x0F, 0x6F); - err += sn9c102_i2c_write(cam, 0x10, 0x20); - err += sn9c102_i2c_write(cam, 0x11, 0x03); - err += sn9c102_i2c_write(cam, 0x12, 0x05); - err += sn9c102_i2c_write(cam, 0x13, 0xC7); - err += sn9c102_i2c_write(cam, 0x14, 0x2C); - err += sn9c102_i2c_write(cam, 0x15, 0x00); - err += sn9c102_i2c_write(cam, 0x16, 0x02); - err += sn9c102_i2c_write(cam, 0x17, 0x10); - err += sn9c102_i2c_write(cam, 0x18, 0x60); - err += sn9c102_i2c_write(cam, 0x19, 0x02); - err += sn9c102_i2c_write(cam, 0x1A, 0x7B); - err += sn9c102_i2c_write(cam, 0x1B, 0x02); - err += sn9c102_i2c_write(cam, 0x1C, 0x7F); - err += sn9c102_i2c_write(cam, 0x1D, 0xA2); - err += sn9c102_i2c_write(cam, 0x1E, 0x01); - err += sn9c102_i2c_write(cam, 0x1F, 0x0E); - err += sn9c102_i2c_write(cam, 0x20, 0x05); - err += sn9c102_i2c_write(cam, 0x21, 0x05); - err += sn9c102_i2c_write(cam, 0x22, 0x05); - err += sn9c102_i2c_write(cam, 0x23, 0x05); - err += sn9c102_i2c_write(cam, 0x24, 0x68); - err += sn9c102_i2c_write(cam, 0x25, 0x58); - err += sn9c102_i2c_write(cam, 0x26, 0xD4); - err += sn9c102_i2c_write(cam, 0x27, 0x80); - err += sn9c102_i2c_write(cam, 0x28, 0x80); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2A, 0x00); - err += sn9c102_i2c_write(cam, 0x2B, 0x00); - err += sn9c102_i2c_write(cam, 0x2C, 0x80); - err += sn9c102_i2c_write(cam, 0x2D, 0x00); - err += sn9c102_i2c_write(cam, 0x2E, 0x00); - err += sn9c102_i2c_write(cam, 0x2F, 0x0E); - err += sn9c102_i2c_write(cam, 0x30, 0x08); - err += sn9c102_i2c_write(cam, 0x31, 0x30); - err += sn9c102_i2c_write(cam, 0x32, 0xB4); - err += sn9c102_i2c_write(cam, 0x33, 0x00); - err += sn9c102_i2c_write(cam, 0x34, 0x07); - err += sn9c102_i2c_write(cam, 0x35, 0x84); - err += sn9c102_i2c_write(cam, 0x36, 0x00); - err += sn9c102_i2c_write(cam, 0x37, 0x0C); - err += sn9c102_i2c_write(cam, 0x38, 0x02); - err += sn9c102_i2c_write(cam, 0x39, 0x43); - err += sn9c102_i2c_write(cam, 0x3A, 0x00); - err += sn9c102_i2c_write(cam, 0x3B, 0x0A); - err += sn9c102_i2c_write(cam, 0x3C, 0x6C); - err += sn9c102_i2c_write(cam, 0x3D, 0x99); - err += sn9c102_i2c_write(cam, 0x3E, 0x0E); - err += sn9c102_i2c_write(cam, 0x3F, 0x41); - err += sn9c102_i2c_write(cam, 0x40, 0xC1); - err += sn9c102_i2c_write(cam, 0x41, 0x22); - err += sn9c102_i2c_write(cam, 0x42, 0x08); - err += sn9c102_i2c_write(cam, 0x43, 0xF0); - err += sn9c102_i2c_write(cam, 0x44, 0x10); - err += sn9c102_i2c_write(cam, 0x45, 0x78); - err += sn9c102_i2c_write(cam, 0x46, 0xA8); - err += sn9c102_i2c_write(cam, 0x47, 0x60); - err += sn9c102_i2c_write(cam, 0x48, 0x80); - err += sn9c102_i2c_write(cam, 0x49, 0x00); - err += sn9c102_i2c_write(cam, 0x4A, 0x00); - err += sn9c102_i2c_write(cam, 0x4B, 0x00); - err += sn9c102_i2c_write(cam, 0x4C, 0x00); - err += sn9c102_i2c_write(cam, 0x4D, 0x00); - err += sn9c102_i2c_write(cam, 0x4E, 0x00); - err += sn9c102_i2c_write(cam, 0x4F, 0x46); - err += sn9c102_i2c_write(cam, 0x50, 0x36); - err += sn9c102_i2c_write(cam, 0x51, 0x0F); - err += sn9c102_i2c_write(cam, 0x52, 0x17); - err += sn9c102_i2c_write(cam, 0x53, 0x7F); - err += sn9c102_i2c_write(cam, 0x54, 0x96); - err += sn9c102_i2c_write(cam, 0x55, 0x40); - err += sn9c102_i2c_write(cam, 0x56, 0x40); - err += sn9c102_i2c_write(cam, 0x57, 0x40); - err += sn9c102_i2c_write(cam, 0x58, 0x0F); - err += sn9c102_i2c_write(cam, 0x59, 0xBA); - err += sn9c102_i2c_write(cam, 0x5A, 0x9A); - err += sn9c102_i2c_write(cam, 0x5B, 0x22); - err += sn9c102_i2c_write(cam, 0x5C, 0xB9); - err += sn9c102_i2c_write(cam, 0x5D, 0x9B); - err += sn9c102_i2c_write(cam, 0x5E, 0x10); - err += sn9c102_i2c_write(cam, 0x5F, 0xF0); - err += sn9c102_i2c_write(cam, 0x60, 0x05); - err += sn9c102_i2c_write(cam, 0x61, 0x60); - err += sn9c102_i2c_write(cam, 0x62, 0x00); - err += sn9c102_i2c_write(cam, 0x63, 0x00); - err += sn9c102_i2c_write(cam, 0x64, 0x50); - err += sn9c102_i2c_write(cam, 0x65, 0x30); - err += sn9c102_i2c_write(cam, 0x66, 0x00); - err += sn9c102_i2c_write(cam, 0x67, 0x80); - err += sn9c102_i2c_write(cam, 0x68, 0x7A); - err += sn9c102_i2c_write(cam, 0x69, 0x90); - err += sn9c102_i2c_write(cam, 0x6A, 0x80); - err += sn9c102_i2c_write(cam, 0x6B, 0x0A); - err += sn9c102_i2c_write(cam, 0x6C, 0x30); - err += sn9c102_i2c_write(cam, 0x6D, 0x48); - err += sn9c102_i2c_write(cam, 0x6E, 0x80); - err += sn9c102_i2c_write(cam, 0x6F, 0x74); - err += sn9c102_i2c_write(cam, 0x70, 0x64); - err += sn9c102_i2c_write(cam, 0x71, 0x60); - err += sn9c102_i2c_write(cam, 0x72, 0x5C); - err += sn9c102_i2c_write(cam, 0x73, 0x58); - err += sn9c102_i2c_write(cam, 0x74, 0x54); - err += sn9c102_i2c_write(cam, 0x75, 0x4C); - err += sn9c102_i2c_write(cam, 0x76, 0x40); - err += sn9c102_i2c_write(cam, 0x77, 0x38); - err += sn9c102_i2c_write(cam, 0x78, 0x34); - err += sn9c102_i2c_write(cam, 0x79, 0x30); - err += sn9c102_i2c_write(cam, 0x7A, 0x2F); - err += sn9c102_i2c_write(cam, 0x7B, 0x2B); - err += sn9c102_i2c_write(cam, 0x7C, 0x03); - err += sn9c102_i2c_write(cam, 0x7D, 0x07); - err += sn9c102_i2c_write(cam, 0x7E, 0x17); - err += sn9c102_i2c_write(cam, 0x7F, 0x34); - err += sn9c102_i2c_write(cam, 0x80, 0x41); - err += sn9c102_i2c_write(cam, 0x81, 0x4D); - err += sn9c102_i2c_write(cam, 0x82, 0x58); - err += sn9c102_i2c_write(cam, 0x83, 0x63); - err += sn9c102_i2c_write(cam, 0x84, 0x6E); - err += sn9c102_i2c_write(cam, 0x85, 0x77); - err += sn9c102_i2c_write(cam, 0x86, 0x87); - err += sn9c102_i2c_write(cam, 0x87, 0x95); - err += sn9c102_i2c_write(cam, 0x88, 0xAF); - err += sn9c102_i2c_write(cam, 0x89, 0xC7); - err += sn9c102_i2c_write(cam, 0x8A, 0xDF); - err += sn9c102_i2c_write(cam, 0x8B, 0x99); - err += sn9c102_i2c_write(cam, 0x8C, 0x99); - err += sn9c102_i2c_write(cam, 0x8D, 0xCF); - err += sn9c102_i2c_write(cam, 0x8E, 0x20); - err += sn9c102_i2c_write(cam, 0x8F, 0x26); - err += sn9c102_i2c_write(cam, 0x90, 0x10); - err += sn9c102_i2c_write(cam, 0x91, 0x0C); - err += sn9c102_i2c_write(cam, 0x92, 0x25); - err += sn9c102_i2c_write(cam, 0x93, 0x00); - err += sn9c102_i2c_write(cam, 0x94, 0x50); - err += sn9c102_i2c_write(cam, 0x95, 0x50); - err += sn9c102_i2c_write(cam, 0x96, 0x00); - err += sn9c102_i2c_write(cam, 0x97, 0x01); - err += sn9c102_i2c_write(cam, 0x98, 0x10); - err += sn9c102_i2c_write(cam, 0x99, 0x40); - err += sn9c102_i2c_write(cam, 0x9A, 0x40); - err += sn9c102_i2c_write(cam, 0x9B, 0x20); - err += sn9c102_i2c_write(cam, 0x9C, 0x00); - err += sn9c102_i2c_write(cam, 0x9D, 0x99); - err += sn9c102_i2c_write(cam, 0x9E, 0x7F); - err += sn9c102_i2c_write(cam, 0x9F, 0x00); - err += sn9c102_i2c_write(cam, 0xA0, 0x00); - err += sn9c102_i2c_write(cam, 0xA1, 0x00); - - return err; -} - - -static int ov7660_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) - return -EIO; - break; - case V4L2_CID_DO_WHITE_BALANCE: - if ((ctrl->value = sn9c102_read_reg(cam, 0x02)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x04) ? 1 : 0; - break; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_read_reg(cam, 0x05)) < 0) - return -EIO; - ctrl->value &= 0x7f; - break; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_read_reg(cam, 0x06)) < 0) - return -EIO; - ctrl->value &= 0x7f; - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_read_reg(cam, 0x07)) < 0) - return -EIO; - ctrl->value &= 0x7f; - break; - case SN9C102_V4L2_CID_BAND_FILTER: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x3b)) < 0) - return -EIO; - ctrl->value &= 0x08; - break; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0) - return -EIO; - ctrl->value &= 0x1f; - break; - case V4L2_CID_AUTOGAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0) - return -EIO; - ctrl->value &= 0x01; - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7660_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value); - break; - case V4L2_CID_DO_WHITE_BALANCE: - err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x05); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x06); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_write_reg(cam, ctrl->value, 0x07); - break; - case SN9C102_V4L2_CID_BAND_FILTER: - err += sn9c102_i2c_write(cam, ctrl->value << 3, 0x3b); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x00, 0x60 + ctrl->value); - break; - case V4L2_CID_AUTOGAIN: - err += sn9c102_i2c_write(cam, 0x13, 0xc0 | - (ctrl->value * 0x07)); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7660_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int ov7660_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int r0, err = 0; - - r0 = sn9c102_pread_reg(cam, 0x01); - - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { - err += sn9c102_write_reg(cam, r0 | 0x40, 0x01); - err += sn9c102_write_reg(cam, 0xa2, 0x17); - err += sn9c102_i2c_write(cam, 0x11, 0x00); - } else { - err += sn9c102_write_reg(cam, r0 | 0x40, 0x01); - err += sn9c102_write_reg(cam, 0xa2, 0x17); - err += sn9c102_i2c_write(cam, 0x11, 0x0d); - } - - return err; -} - - -static const struct sn9c102_sensor ov7660 = { - .name = "OV7660", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x21, - .init = &ov7660_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x09, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x27, - .flags = 0, - }, - { - .id = V4L2_CID_DO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "night mode", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto adjust", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_BAND_FILTER, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "band filter", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &ov7660_get_ctrl, - .set_ctrl = &ov7660_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &ov7660_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_JPEG, - .priv = 8, - }, - .set_pix_format = &ov7660_set_pix_format -}; - - -int sn9c102_probe_ov7660(struct sn9c102_device* cam) -{ - int pid, ver, err; - - err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x01, 0x01}, {0x00, 0x01}, - {0x28, 0x17}); - - pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); - ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); - if (err || pid < 0 || ver < 0) - return -EIO; - if (pid != 0x76 || ver != 0x60) - return -ENODEV; - - sn9c102_attach_sensor(cam, &ov7660); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_pas106b.c b/drivers/media/usb/sn9c102/sn9c102_pas106b.c deleted file mode 100644 index 81cd969c1b7..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_pas106b.c +++ /dev/null @@ -1,302 +0,0 @@ -/*************************************************************************** - * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include <linux/delay.h> -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int pas106b_init(struct sn9c102_device* cam) -{ - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x20, 0x17}, - {0x20, 0x19}, {0x09, 0x18}); - - err += sn9c102_i2c_write(cam, 0x02, 0x0c); - err += sn9c102_i2c_write(cam, 0x05, 0x5a); - err += sn9c102_i2c_write(cam, 0x06, 0x88); - err += sn9c102_i2c_write(cam, 0x07, 0x80); - err += sn9c102_i2c_write(cam, 0x10, 0x06); - err += sn9c102_i2c_write(cam, 0x11, 0x06); - err += sn9c102_i2c_write(cam, 0x12, 0x00); - err += sn9c102_i2c_write(cam, 0x14, 0x02); - err += sn9c102_i2c_write(cam, 0x13, 0x01); - - msleep(400); - - return err; -} - - -static int pas106b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x03), - r2 = sn9c102_i2c_read(cam, 0x04); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 4) | (r2 & 0x0f); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_CONTRAST: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) - return -EIO; - ctrl->value &= 0x07; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x1f) << 1; - return 0; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) - return -EIO; - ctrl->value &= 0xf8; - return 0; - default: - return -EINVAL; - } -} - - -static int pas106b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4); - err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x0e, ctrl->value); - break; - case V4L2_CID_CONTRAST: - err += sn9c102_i2c_write(cam, 0x0f, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1); - err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1); - break; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3); - break; - default: - return -EINVAL; - } - err += sn9c102_i2c_write(cam, 0x13, 0x01); - - return err ? -EIO : 0; -} - - -static int pas106b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int pas106b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x2c, 0x17); - else - err += sn9c102_write_reg(cam, 0x20, 0x17); - - return err; -} - - -static const struct sn9c102_sensor pas106b = { - .name = "PAS106B", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x40, - .init = &pas106b_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x125, - .maximum = 0xfff, - .step = 0x001, - .default_value = 0x140, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x0d, - .flags = 0, - }, - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "contrast", - .minimum = 0x00, - .maximum = 0x07, - .step = 0x01, - .default_value = 0x00, /* 0x00~0x03 have same effect */ - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x04, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x06, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3e, - .step = 0x02, - .default_value = 0x02, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - }, - .get_ctrl = &pas106b_get_ctrl, - .set_ctrl = &pas106b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &pas106b_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, /* we use this field as 'bits per pixel' */ - }, - .set_pix_format = &pas106b_set_pix_format -}; - - -int sn9c102_probe_pas106b(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0; - unsigned int pid = 0; - - /* - Minimal initialization to enable the I2C communication - NOTE: do NOT change the values! - */ - if (sn9c102_write_const_regs(cam, - {0x01, 0x01}, /* sensor power down */ - {0x00, 0x01}, /* sensor power on */ - {0x28, 0x17})) /* sensor clock at 24 MHz */ - return -EIO; - - r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00); - r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01); - if (r0 < 0 || r1 < 0) - return -EIO; - - pid = (r0 << 11) | ((r1 & 0xf0) >> 4); - if (pid != 0x007) - return -ENODEV; - - sn9c102_attach_sensor(cam, &pas106b); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c b/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c deleted file mode 100644 index 2e86fdc8698..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_pas202bcb.c +++ /dev/null @@ -1,335 +0,0 @@ -/*************************************************************************** - * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * - * <medaglia@undl.org.br> * - * * - * Support for SN9C103, DAC Magnitude, exposure and green gain controls * - * added by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include <linux/delay.h> -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int pas202bcb_init(struct sn9c102_device* cam) -{ - int err = 0; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x20, 0x17}, - {0x30, 0x19}, {0x09, 0x18}); - break; - case BRIDGE_SN9C103: - err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, - {0x1a, 0x04}, {0x20, 0x05}, - {0x20, 0x06}, {0x20, 0x07}, - {0x00, 0x10}, {0x00, 0x11}, - {0x00, 0x14}, {0x20, 0x17}, - {0x30, 0x19}, {0x09, 0x18}, - {0x02, 0x1c}, {0x03, 0x1d}, - {0x0f, 0x1e}, {0x0c, 0x1f}, - {0x00, 0x20}, {0x10, 0x21}, - {0x20, 0x22}, {0x30, 0x23}, - {0x40, 0x24}, {0x50, 0x25}, - {0x60, 0x26}, {0x70, 0x27}, - {0x80, 0x28}, {0x90, 0x29}, - {0xa0, 0x2a}, {0xb0, 0x2b}, - {0xc0, 0x2c}, {0xd0, 0x2d}, - {0xe0, 0x2e}, {0xf0, 0x2f}, - {0xff, 0x30}); - break; - default: - break; - } - - err += sn9c102_i2c_write(cam, 0x02, 0x14); - err += sn9c102_i2c_write(cam, 0x03, 0x40); - err += sn9c102_i2c_write(cam, 0x0d, 0x2c); - err += sn9c102_i2c_write(cam, 0x0e, 0x01); - err += sn9c102_i2c_write(cam, 0x0f, 0xa9); - err += sn9c102_i2c_write(cam, 0x10, 0x08); - err += sn9c102_i2c_write(cam, 0x13, 0x63); - err += sn9c102_i2c_write(cam, 0x15, 0x70); - err += sn9c102_i2c_write(cam, 0x11, 0x01); - - msleep(400); - - return err; -} - - -static int pas202bcb_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x04), - r2 = sn9c102_i2c_read(cam, 0x05); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 6) | (r2 & 0x3f); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) - return -EIO; - return 0; - default: - return -EINVAL; - } -} - - -static int pas202bcb_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x28, 0x17); - else - err += sn9c102_write_reg(cam, 0x20, 0x17); - - return err; -} - - -static int pas202bcb_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); - err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x07, ctrl->value); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x08, ctrl->value); - break; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - default: - return -EINVAL; - } - err += sn9c102_i2c_write(cam, 0x11, 0x01); - - return err ? -EIO : 0; -} - - -static int pas202bcb_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = 0, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; - - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4; - break; - case BRIDGE_SN9C103: - h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3; - break; - default: - break; - } - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static const struct sn9c102_sensor pas202bcb = { - .name = "PAS202BCB", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x40, - .init = &pas202bcb_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x01e5, - .maximum = 0x3fff, - .step = 0x0001, - .default_value = 0x01e5, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x0b, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x05, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x04, - .flags = 0, - }, - }, - .get_ctrl = &pas202bcb_get_ctrl, - .set_ctrl = &pas202bcb_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &pas202bcb_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &pas202bcb_set_pix_format -}; - - -int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0, err = 0; - unsigned int pid = 0; - - /* - * Minimal initialization to enable the I2C communication - * NOTE: do NOT change the values! - */ - switch (sn9c102_get_bridge(cam)) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - err = sn9c102_write_const_regs(cam, - {0x01, 0x01}, /* power down */ - {0x40, 0x01}, /* power on */ - {0x28, 0x17});/* clock 24 MHz */ - break; - case BRIDGE_SN9C103: /* do _not_ change anything! */ - err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x01}, - {0x44, 0x02}, {0x29, 0x17}); - break; - default: - break; - } - - r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); - r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); - - if (err || r0 < 0 || r1 < 0) - return -EIO; - - pid = (r0 << 4) | ((r1 & 0xf0) >> 4); - if (pid != 0x017) - return -ENODEV; - - sn9c102_attach_sensor(cam, &pas202bcb); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_sensor.h b/drivers/media/usb/sn9c102/sn9c102_sensor.h deleted file mode 100644 index 3679970dba2..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_sensor.h +++ /dev/null @@ -1,307 +0,0 @@ -/*************************************************************************** - * API for image sensors connected to the SN9C1xx PC Camera Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_SENSOR_H_ -#define _SN9C102_SENSOR_H_ - -#include <linux/usb.h> -#include <linux/videodev2.h> -#include <linux/device.h> -#include <linux/stddef.h> -#include <linux/errno.h> -#include <asm/types.h> - -struct sn9c102_device; -struct sn9c102_sensor; - -/*****************************************************************************/ - -/* - OVERVIEW. - This is a small interface that allows you to add support for any CCD/CMOS - image sensors connected to the SN9C1XX bridges. The entire API is documented - below. In the most general case, to support a sensor there are three steps - you have to follow: - 1) define the main "sn9c102_sensor" structure by setting the basic fields; - 2) write a probing function to be called by the core module when the USB - camera is recognized, then add both the USB ids and the name of that - function to the two corresponding tables in sn9c102_devtable.h; - 3) implement the methods that you want/need (and fill the rest of the main - structure accordingly). - "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do - NOT need to touch the source code of the core module for the things to work - properly, unless you find bugs or flaws in it. Finally, do not forget to - read the V4L2 API for completeness. -*/ - -/*****************************************************************************/ - -enum sn9c102_bridge { - BRIDGE_SN9C101 = 0x01, - BRIDGE_SN9C102 = 0x02, - BRIDGE_SN9C103 = 0x04, - BRIDGE_SN9C105 = 0x08, - BRIDGE_SN9C120 = 0x10, -}; - -/* Return the bridge name */ -enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam); - -/* Return a pointer the sensor struct attached to the camera */ -struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam); - -/* Identify a device */ -extern struct sn9c102_device* -sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); - -/* Attach a probed sensor to the camera. */ -extern void -sn9c102_attach_sensor(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor); - -/* - Read/write routines: they always return -1 on error, 0 or the read value - otherwise. NOTE that a real read operation is not supported by the SN9C1XX - chip for some of its registers. To work around this problem, a pseudo-read - call is provided instead: it returns the last successfully written value - on the register (0 if it has never been written), the usual -1 on error. -*/ - -/* The "try" I2C I/O versions are used when probing the sensor */ -extern int sn9c102_i2c_try_read(struct sn9c102_device*, - const struct sn9c102_sensor*, u8 address); - -/* - These must be used if and only if the sensor doesn't implement the standard - I2C protocol. There are a number of good reasons why you must use the - single-byte versions of these functions: do not abuse. The first function - writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX - chip. The second one programs the registers 0x09 and 0x10 with data0 and - data1, and places the n bytes read from the sensor register table in the - buffer pointed by 'buffer'. Both the functions return -1 on error; the write - version returns 0 on success, while the read version returns the first read - byte. -*/ -extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, u8 n, - u8 data0, u8 data1, u8 data2, u8 data3, - u8 data4, u8 data5); -extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, - const struct sn9c102_sensor* sensor, - u8 data0, u8 data1, u8 n, u8 buffer[]); - -/* To be used after the sensor struct has been attached to the camera struct */ -extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); -extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); - -/* I/O on registers in the bridge. Could be used by the sensor methods too */ -extern int sn9c102_read_reg(struct sn9c102_device*, u16 index); -extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); -extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); -extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2], - int count); -/* - Write multiple registers with constant values. For example: - sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18}); - Register addresses must be < 256. -*/ -#define sn9c102_write_const_regs(sn9c102_device, data...) \ - ({ static const u8 _valreg[][2] = {data}; \ - sn9c102_write_regs(sn9c102_device, _valreg, ARRAY_SIZE(_valreg)); }) - -/*****************************************************************************/ - -enum sn9c102_i2c_sysfs_ops { - SN9C102_I2C_READ = 0x01, - SN9C102_I2C_WRITE = 0x02, -}; - -enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */ - SN9C102_I2C_100KHZ = 0x01, - SN9C102_I2C_400KHZ = 0x02, -}; - -enum sn9c102_i2c_interface { - SN9C102_I2C_2WIRES, - SN9C102_I2C_3WIRES, -}; - -#define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10) - -struct sn9c102_sensor { - char name[32], /* sensor name */ - maintainer[64]; /* name of the maintainer <email> */ - - enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */ - - /* Supported operations through the 'sysfs' interface */ - enum sn9c102_i2c_sysfs_ops sysfs_ops; - - /* - These sensor capabilities must be provided if the SN9C1XX controller - needs to communicate through the sensor serial interface by using - at least one of the i2c functions available. - */ - enum sn9c102_i2c_frequency frequency; - enum sn9c102_i2c_interface interface; - - /* - This identifier must be provided if the image sensor implements - the standard I2C protocol. - */ - u8 i2c_slave_id; /* reg. 0x09 */ - - /* - NOTE: Where not noted,most of the functions below are not mandatory. - Set to null if you do not implement them. If implemented, - they must return 0 on success, the proper error otherwise. - */ - - int (*init)(struct sn9c102_device* cam); - /* - This function will be called after the sensor has been attached. - It should be used to initialize the sensor only, but may also - configure part of the SN9C1XX chip if necessary. You don't need to - setup picture settings like brightness, contrast, etc.. here, if - the corresponding controls are implemented (see below), since - they are adjusted in the core driver by calling the set_ctrl() - method after init(), where the arguments are the default values - specified in the v4l2_queryctrl list of supported controls; - Same suggestions apply for other settings, _if_ the corresponding - methods are present; if not, the initialization must configure the - sensor according to the default configuration structures below. - */ - - struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; - /* - Optional list of default controls, defined as indicated in the - V4L2 API. Menu type controls are not handled by this interface. - */ - - int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); - int (*set_ctrl)(struct sn9c102_device* cam, - const struct v4l2_control* ctrl); - /* - You must implement at least the set_ctrl method if you have defined - the list above. The returned value must follow the V4L2 - specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER - are not supported by this driver, so do not implement them. Also, - you don't have to check whether the passed values are out of bounds, - given that this is done by the core module. - */ - - struct v4l2_cropcap cropcap; - /* - Think the image sensor as a grid of R,G,B monochromatic pixels - disposed according to a particular Bayer pattern, which describes - the complete array of pixels, from (0,0) to (xmax, ymax). We will - use this coordinate system from now on. It is assumed the sensor - chip can be programmed to capture/transmit a subsection of that - array of pixels: we will call this subsection "active window". - It is not always true that the largest achievable active window can - cover the whole array of pixels. The V4L2 API defines another - area called "source rectangle", which, in turn, is a subrectangle of - the active window. The SN9C1XX chip is always programmed to read the - source rectangle. - The bounds of both the active window and the source rectangle are - specified in the cropcap substructures 'bounds' and 'defrect'. - By default, the source rectangle should cover the largest possible - area. Again, it is not always true that the largest source rectangle - can cover the entire active window, although it is a rare case for - the hardware we have. The bounds of the source rectangle _must_ be - multiple of 16 and must use the same coordinate system as indicated - before; their centers shall align initially. - If necessary, the sensor chip must be initialized during init() to - set the bounds of the active sensor window; however, by default, it - usually covers the largest achievable area (maxwidth x maxheight) - of pixels, so no particular initialization is needed, if you have - defined the correct default bounds in the structures. - See the V4L2 API for further details. - NOTE: once you have defined the bounds of the active window - (struct cropcap.bounds) you must not change them.anymore. - Only 'bounds' and 'defrect' fields are mandatory, other fields - will be ignored. - */ - - int (*set_crop)(struct sn9c102_device* cam, - const struct v4l2_rect* rect); - /* - To be called on VIDIOC_C_SETCROP. The core module always calls a - default routine which configures the appropriate SN9C1XX regs (also - scaling), but you may need to override/adjust specific stuff. - 'rect' contains width and height values that are multiple of 16: in - case you override the default function, you always have to program - the chip to match those values; on error return the corresponding - error code without rolling back. - NOTE: in case, you must program the SN9C1XX chip to get rid of - blank pixels or blank lines at the _start_ of each line or - frame after each HSYNC or VSYNC, so that the image starts with - real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, - V_SIZE you don't have to care about blank pixels or blank - lines at the end of each line or frame). - */ - - struct v4l2_pix_format pix_format; - /* - What you have to define here are: 1) initial 'width' and 'height' of - the target rectangle 2) the initial 'pixelformat', which can be - either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video) - or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate - the number of bits per pixel for uncompressed video, 8 or 9 (despite - the current value of 'pixelformat'). - NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 - of cropcap.defrect.width and cropcap.defrect.height. I - suggest 1/1. - NOTE 2: The initial compression quality is defined by the first bit - of reg 0x17 during the initialization of the image sensor. - NOTE 3: as said above, you have to program the SN9C1XX chip to get - rid of any blank pixels, so that the output of the sensor - matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). - */ - - int (*set_pix_format)(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix); - /* - To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to - SN9C10X pixel format or viceversa. On error return the corresponding - error code without rolling back. - */ - - /* - Do NOT write to the data below, it's READ ONLY. It is used by the - core module to store successfully updated values of the above - settings, for rollbacks..etc..in case of errors during atomic I/O - */ - struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; - struct v4l2_rect _rect; -}; - -/*****************************************************************************/ - -/* Private ioctl's for control settings supported by some image sensors */ -#define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0) -#define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1) -#define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2) -#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3) -#define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4) -#define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5) -#define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6) - -#endif /* _SN9C102_SENSOR_H_ */ diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c deleted file mode 100644 index 04cdfdde856..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c +++ /dev/null @@ -1,154 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int tas5110c1b_init(struct sn9c102_device* cam) -{ - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01}, - {0x00, 0x10}, {0x00, 0x11}, - {0x0a, 0x14}, {0x60, 0x17}, - {0x06, 0x18}, {0xfb, 0x19}); - - err += sn9c102_i2c_write(cam, 0xc0, 0x80); - - return err; -} - - -static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int tas5110c1b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - /* Don't change ! */ - err += sn9c102_write_reg(cam, 0x14, 0x1a); - err += sn9c102_write_reg(cam, 0x0a, 0x1b); - err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); - - return err; -} - - -static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x2b, 0x19); - else - err += sn9c102_write_reg(cam, 0xfb, 0x19); - - return err; -} - - -static const struct sn9c102_sensor tas5110c1b = { - .name = "TAS5110C1B", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_3WIRES, - .init = &tas5110c1b_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xf6, - .step = 0x01, - .default_value = 0x40, - .flags = 0, - }, - }, - .set_ctrl = &tas5110c1b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &tas5110c1b_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5110c1b_set_pix_format -}; - - -int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5110c1b_id_table[] = { - { USB_DEVICE(0x0c45, 0x6001), }, - { USB_DEVICE(0x0c45, 0x6005), }, - { USB_DEVICE(0x0c45, 0x60ab), }, - { } - }; - - /* Sensor detection is based on USB pid/vid */ - if (!sn9c102_match_id(cam, tas5110c1b_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5110c1b); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5110d.c b/drivers/media/usb/sn9c102/sn9c102_tas5110d.c deleted file mode 100644 index 9372e6f9fcf..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_tas5110d.c +++ /dev/null @@ -1,119 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int tas5110d_init(struct sn9c102_device* cam) -{ - int err; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01}, - {0x0a, 0x14}, {0x60, 0x17}, - {0x06, 0x18}, {0xfb, 0x19}); - - err += sn9c102_i2c_write(cam, 0x9a, 0xca); - - return err; -} - - -static int tas5110d_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - err += sn9c102_write_reg(cam, 0x14, 0x1a); - err += sn9c102_write_reg(cam, 0x0a, 0x1b); - - return err; -} - - -static int tas5110d_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x3b, 0x19); - else - err += sn9c102_write_reg(cam, 0xfb, 0x19); - - return err; -} - - -static const struct sn9c102_sensor tas5110d = { - .name = "TAS5110D", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x61, - .init = &tas5110d_init, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &tas5110d_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5110d_set_pix_format -}; - - -int sn9c102_probe_tas5110d(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5110d_id_table[] = { - { USB_DEVICE(0x0c45, 0x6007), }, - { } - }; - - if (!sn9c102_match_id(cam, tas5110d_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5110d); - - return 0; -} diff --git a/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c deleted file mode 100644 index a30bbc4389f..00000000000 --- a/drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c +++ /dev/null @@ -1,165 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" -#include "sn9c102_devtable.h" - - -static int tas5130d1b_init(struct sn9c102_device* cam) -{ - int err; - - err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17}, - {0x04, 0x01}, {0x01, 0x10}, - {0x00, 0x11}, {0x00, 0x14}, - {0x60, 0x17}, {0x07, 0x18}); - - return err; -} - - -static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); - break; - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int tas5130d1b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = sn9c102_get_sensor(cam); - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; - int err = 0; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - /* Do NOT change! */ - err += sn9c102_write_reg(cam, 0x1f, 0x1a); - err += sn9c102_write_reg(cam, 0x1a, 0x1b); - err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); - - return err; -} - - -static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x63, 0x19); - else - err += sn9c102_write_reg(cam, 0xf3, 0x19); - - return err; -} - - -static const struct sn9c102_sensor tas5130d1b = { - .name = "TAS5130D1B", - .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", - .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_3WIRES, - .init = &tas5130d1b_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xf6, - .step = 0x02, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x47, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .set_ctrl = &tas5130d1b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &tas5130d1b_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5130d1b_set_pix_format -}; - - -int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5130d1b_id_table[] = { - { USB_DEVICE(0x0c45, 0x6024), }, - { USB_DEVICE(0x0c45, 0x6025), }, - { USB_DEVICE(0x0c45, 0x60aa), }, - { } - }; - - /* Sensor detection is based on USB pid/vid */ - if (!sn9c102_match_id(cam, tas5130d1b_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5130d1b); - - return 0; -} diff --git a/drivers/media/usb/stk1160/stk1160-ac97.c b/drivers/media/usb/stk1160/stk1160-ac97.c index c8583c262c3..2dd308f9541 100644 --- a/drivers/media/usb/stk1160/stk1160-ac97.c +++ b/drivers/media/usb/stk1160/stk1160-ac97.c @@ -98,19 +98,17 @@ int stk1160_ac97_register(struct stk1160 *dev) * Just want a card to access ac96 controls, * the actual capture interface will be handled by snd-usb-audio */ - rc = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, - THIS_MODULE, 0, &card); + rc = snd_card_new(dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &card); if (rc < 0) return rc; - snd_card_set_dev(card, dev->dev); - /* TODO: I'm not sure where should I get these names :-( */ snprintf(card->shortname, sizeof(card->shortname), "stk1160-mixer"); snprintf(card->longname, sizeof(card->longname), "stk1160 ac97 codec mixer control"); - strncpy(card->driver, dev->dev->driver->name, sizeof(card->driver)); + strlcpy(card->driver, dev->dev->driver->name, sizeof(card->driver)); rc = snd_ac97_bus(card, 0, &stk1160_ac97_ops, NULL, &ac97_bus); if (rc) diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index 34a26e0cfe7..03504dcf3c5 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -67,17 +67,25 @@ int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value) { int ret; int pipe = usb_rcvctrlpipe(dev->udev, 0); + u8 *buf; *value = 0; + + buf = kmalloc(sizeof(u8), GFP_KERNEL); + if (!buf) + return -ENOMEM; ret = usb_control_msg(dev->udev, pipe, 0x00, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, reg, value, sizeof(u8), HZ); + 0x00, reg, buf, sizeof(u8), HZ); if (ret < 0) { stk1160_err("read failed on reg 0x%x (%d)\n", reg, ret); + kfree(buf); return ret; } + *value = *buf; + kfree(buf); return 0; } diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index c45c9881bb5..5461341a31c 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -406,7 +406,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) stk1160_set_std(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); return 0; @@ -583,10 +583,10 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) } /* abort streaming and wait for last buffer */ -static int stop_streaming(struct vb2_queue *vq) +static void stop_streaming(struct vb2_queue *vq) { struct stk1160 *dev = vb2_get_drv_priv(vq); - return stk1160_stop_streaming(dev); + stk1160_stop_streaming(dev); } static struct vb2_ops stk1160_video_qops = { @@ -641,7 +641,7 @@ int stk1160_vb2_setup(struct stk1160 *dev) q->buf_struct_size = sizeof(struct stk1160_buffer); q->ops = &stk1160_video_qops; q->mem_ops = &vb2_vmalloc_memops; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(q); if (rc < 0) @@ -682,7 +682,7 @@ int stk1160_video_register(struct stk1160 *dev) dev->fmt = &format[0]; stk1160_set_std(dev); - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); video_set_drvdata(&dev->vdev, dev); diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 05b05b160e1..abdea484c99 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -143,7 +143,6 @@ struct stk1160 { int num_alt; struct stk1160_isoc_ctl isoc_ctl; - char urb_buf[255]; /* urb control msg buffer */ /* frame properties */ int width; /* current frame width */ diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index c43c8d32be4..be77482c307 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -111,6 +111,13 @@ static const struct dmi_system_id stk_upside_down_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "F3JC") } }, + { + .ident = "T12Rg-H", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HCL Infosystems Limited"), + DMI_MATCH(DMI_PRODUCT_NAME, "T12Rg-H") + } + }, {} }; diff --git a/drivers/media/usb/tlg2300/pd-alsa.c b/drivers/media/usb/tlg2300/pd-alsa.c index 3f3e141f70f..dd8fe100590 100644 --- a/drivers/media/usb/tlg2300/pd-alsa.c +++ b/drivers/media/usb/tlg2300/pd-alsa.c @@ -300,7 +300,8 @@ int poseidon_audio_init(struct poseidon *p) struct snd_pcm *pcm; int ret; - ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card); + ret = snd_card_new(&p->interface->dev, -1, "Telegent", + THIS_MODULE, 0, &card); if (ret != 0) return ret; diff --git a/drivers/media/usb/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c index 95f94e5aa66..3316caa4733 100644 --- a/drivers/media/usb/tlg2300/pd-main.c +++ b/drivers/media/usb/tlg2300/pd-main.c @@ -232,7 +232,7 @@ static int firmware_download(struct usb_device *udev) goto out; } - max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize; + max_packet_size = le16_to_cpu(udev->ep_out[0x1]->desc.wMaxPacketSize); log("\t\t download size : %d", (int)max_packet_size); for (offset = 0; offset < fwlength; offset += max_packet_size) { diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c index 813c1ec5360..74e5697d867 100644 --- a/drivers/media/usb/tm6000/tm6000-alsa.c +++ b/drivers/media/usb/tm6000/tm6000-alsa.c @@ -1,7 +1,7 @@ /* * * Support for audio capture for tm5600/6000/6010 - * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com> + * (c) 2007-2008 Mauro Carvalho Chehab * * Based on cx88-alsa.c * @@ -56,7 +56,7 @@ MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s)."); ****************************************************************************/ MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Trident,tm5600}," "{{Trident,tm6000}," @@ -431,7 +431,8 @@ static int tm6000_audio_init(struct tm6000_core *dev) if (!enable[devnr]) return -ENOENT; - rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card); + rc = snd_card_new(&dev->udev->dev, index[devnr], "tm6000", + THIS_MODULE, 0, &card); if (rc < 0) { snd_printk(KERN_ERR "cannot create card instance %d\n", devnr); return rc; @@ -445,7 +446,6 @@ static int tm6000_audio_init(struct tm6000_core *dev) le16_to_cpu(dev->udev->descriptor.idVendor), le16_to_cpu(dev->udev->descriptor.idProduct)); snd_component_add(card, component); - snd_card_set_dev(card, &dev->udev->dev); chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL); if (!chip) { diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index 1ccaaddaa30..2e8c3afe4ec 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -1120,7 +1120,7 @@ static int tm6000_init_dev(struct tm6000_core *dev) tm6000_config_tuner(dev); /* Set video standard */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); /* Set tuner frequency - also loads firmware on xc2028/xc3028 */ f.tuner = 0; diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 9fc1e940a82..095f5db1a79 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -32,7 +32,7 @@ #include "xc5000.h" MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Trident, tm5600}," diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c index 8a6bbf1d80e..d1af5438c16 100644 --- a/drivers/media/usb/tm6000/tm6000-input.c +++ b/drivers/media/usb/tm6000/tm6000-input.c @@ -422,7 +422,7 @@ int tm6000_ir_init(struct tm6000_core *dev) ir->rc = rc; /* input setup */ - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; + rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC); /* Neded, in order to support NEC remotes with 24 or 32 bits */ rc->scanmask = 0xffff; rc->priv = ir; diff --git a/drivers/media/usb/tm6000/tm6000-stds.c b/drivers/media/usb/tm6000/tm6000-stds.c index 5e28d6a2412..93a4b2434b6 100644 --- a/drivers/media/usb/tm6000/tm6000-stds.c +++ b/drivers/media/usb/tm6000/tm6000-stds.c @@ -1,7 +1,7 @@ /* * tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices * - * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@redhat.com> + * Copyright (C) 2007 Mauro Carvalho Chehab * * 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 diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index cc1aa14996f..e6b3d5d83d4 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1071,7 +1071,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) if (rc < 0) return rc; - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); return 0; } diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index e52c3b97f30..29724af9b9a 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -366,7 +366,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, } return 0; } else { - return -1; + return -ENOENT; } } @@ -1241,6 +1241,8 @@ static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) static int ttusb_dec_init_usb(struct ttusb_dec *dec) { + int result; + dprintk("%s\n", __func__); mutex_init(&dec->usb_mutex); @@ -1258,7 +1260,7 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec) return -ENOMEM; } dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE, - GFP_ATOMIC, &dec->irq_dma_handle); + GFP_KERNEL, &dec->irq_dma_handle); if(!dec->irq_buffer) { usb_free_urb(dec->irq_urb); return -ENOMEM; @@ -1270,7 +1272,13 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec) dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } - return ttusb_dec_alloc_iso_urbs(dec); + result = ttusb_dec_alloc_iso_urbs(dec); + if (result) { + usb_free_urb(dec->irq_urb); + usb_free_coherent(dec->udev, IRQ_PACKET_SIZE, + dec->irq_buffer, dec->irq_dma_handle); + } + return result; } static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) @@ -1293,10 +1301,11 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) dprintk("%s\n", __func__); - if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { + result = request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev); + if (result) { printk(KERN_ERR "%s: Firmware (%s) unavailable.\n", __func__, dec->firmware_name); - return 1; + return result; } firmware = fw_entry->data; @@ -1306,7 +1315,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) printk("%s: firmware size too small for DSP code (%zu < 60).\n", __func__, firmware_size); release_firmware(fw_entry); - return -1; + return -ENOENT; } /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored @@ -1320,7 +1329,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) "0x%08x != 0x%08x in file), file invalid.\n", __func__, crc32_csum, crc32_check); release_firmware(fw_entry); - return -1; + return -ENOENT; } memcpy(idstring, &firmware[36], 20); idstring[20] = '\0'; @@ -1389,55 +1398,48 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) dprintk("%s\n", __func__); result = ttusb_dec_get_stb_state(dec, &mode, &model, &version); + if (result) + return result; - if (!result) { - if (!mode) { - if (version == 0xABCDEFAB) - printk(KERN_INFO "ttusb_dec: no version " - "info in Firmware\n"); - else - printk(KERN_INFO "ttusb_dec: Firmware " - "%x.%02x%c%c\n", - version >> 24, (version >> 16) & 0xff, - (version >> 8) & 0xff, version & 0xff); - - result = ttusb_dec_boot_dsp(dec); - if (result) - return result; - else - return 1; - } else { - /* We can't trust the USB IDs that some firmwares - give the box */ - switch (model) { - case 0x00070001: - case 0x00070008: - case 0x0007000c: - ttusb_dec_set_model(dec, TTUSB_DEC3000S); - break; - case 0x00070009: - case 0x00070013: - ttusb_dec_set_model(dec, TTUSB_DEC2000T); - break; - case 0x00070011: - ttusb_dec_set_model(dec, TTUSB_DEC2540T); - break; - default: - printk(KERN_ERR "%s: unknown model returned " - "by firmware (%08x) - please report\n", - __func__, model); - return -1; - break; - } + if (!mode) { + if (version == 0xABCDEFAB) + printk(KERN_INFO "ttusb_dec: no version " + "info in Firmware\n"); + else + printk(KERN_INFO "ttusb_dec: Firmware " + "%x.%02x%c%c\n", + version >> 24, (version >> 16) & 0xff, + (version >> 8) & 0xff, version & 0xff); + result = ttusb_dec_boot_dsp(dec); + if (result) + return result; + } else { + /* We can't trust the USB IDs that some firmwares + give the box */ + switch (model) { + case 0x00070001: + case 0x00070008: + case 0x0007000c: + ttusb_dec_set_model(dec, TTUSB_DEC3000S); + break; + case 0x00070009: + case 0x00070013: + ttusb_dec_set_model(dec, TTUSB_DEC2000T); + break; + case 0x00070011: + ttusb_dec_set_model(dec, TTUSB_DEC2540T); + break; + default: + printk(KERN_ERR "%s: unknown model returned " + "by firmware (%08x) - please report\n", + __func__, model); + return -ENOENT; + } if (version >= 0x01770000) dec->can_playback = 1; - - return 0; - } } - else - return result; + return 0; } static int ttusb_dec_init_dvb(struct ttusb_dec *dec) @@ -1539,19 +1541,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) static void ttusb_dec_exit_rc(struct ttusb_dec *dec) { - dprintk("%s\n", __func__); - /* we have to check whether the irq URB is already submitted. - * As the irq is submitted after the interface is changed, - * this is the best method i figured out. - * Any others?*/ - if (dec->interface == TTUSB_DEC_INTERFACE_IN) - usb_kill_urb(dec->irq_urb); - - usb_free_urb(dec->irq_urb); - - usb_free_coherent(dec->udev,IRQ_PACKET_SIZE, - dec->irq_buffer, dec->irq_dma_handle); if (dec->rc_input_dev) { input_unregister_device(dec->rc_input_dev); @@ -1566,6 +1556,20 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec) dprintk("%s\n", __func__); + if (enable_rc) { + /* we have to check whether the irq URB is already submitted. + * As the irq is submitted after the interface is changed, + * this is the best method i figured out. + * Any others?*/ + if (dec->interface == TTUSB_DEC_INTERFACE_IN) + usb_kill_urb(dec->irq_urb); + + usb_free_urb(dec->irq_urb); + + usb_free_coherent(dec->udev, IRQ_PACKET_SIZE, + dec->irq_buffer, dec->irq_dma_handle); + } + dec->iso_stream_count = 0; for (i = 0; i < ISO_BUF_COUNT; i++) @@ -1623,6 +1627,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, { struct usb_device *udev; struct ttusb_dec *dec; + int result; dprintk("%s\n", __func__); @@ -1651,13 +1656,15 @@ static int ttusb_dec_probe(struct usb_interface *intf, dec->udev = udev; - if (ttusb_dec_init_usb(dec)) - return 0; - if (ttusb_dec_init_stb(dec)) { - ttusb_dec_exit_usb(dec); - return 0; - } - ttusb_dec_init_dvb(dec); + result = ttusb_dec_init_usb(dec); + if (result) + goto err_usb; + result = ttusb_dec_init_stb(dec); + if (result) + goto err_stb; + result = ttusb_dec_init_dvb(dec); + if (result) + goto err_stb; dec->adapter.priv = dec; switch (id->idProduct) { @@ -1696,6 +1703,11 @@ static int ttusb_dec_probe(struct usb_interface *intf, ttusb_init_rc(dec); return 0; +err_stb: + ttusb_dec_exit_usb(dec); +err_usb: + kfree(dec); + return result; } static void ttusb_dec_disconnect(struct usb_interface *intf) diff --git a/drivers/media/usb/usbtv/Makefile b/drivers/media/usb/usbtv/Makefile index 28b872fa94e..775316a88ea 100644 --- a/drivers/media/usb/usbtv/Makefile +++ b/drivers/media/usb/usbtv/Makefile @@ -1 +1,4 @@ +usbtv-y := usbtv-core.o \ + usbtv-video.o + obj-$(CONFIG_VIDEO_USBTV) += usbtv.o diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c new file mode 100644 index 00000000000..2f87ddfa469 --- /dev/null +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -0,0 +1,134 @@ +/* + * Fushicai USBTV007 Video Grabber Driver + * + * Product web site: + * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html + * + * Following LWN articles were very useful in construction of this driver: + * Video4Linux2 API series: http://lwn.net/Articles/203924/ + * videobuf2 API explanation: http://lwn.net/Articles/447435/ + * Thanks go to Jonathan Corbet for providing this quality documentation. + * He is awesome. + * + * Copyright (c) 2013 Lubomir Rintel + * All rights reserved. + * No physical hardware was harmed running Windows during the + * reverse-engineering activity + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + */ + +#include "usbtv.h" + +int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) +{ + int ret; + int pipe = usb_rcvctrlpipe(usbtv->udev, 0); + int i; + + for (i = 0; i < size; i++) { + u16 index = regs[i][0]; + u16 value = regs[i][1]; + + ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +static int usbtv_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + int size; + struct device *dev = &intf->dev; + struct usbtv *usbtv; + + /* Checks that the device is what we think it is. */ + if (intf->num_altsetting != 2) + return -ENODEV; + if (intf->altsetting[1].desc.bNumEndpoints != 4) + return -ENODEV; + + /* Packet size is split into 11 bits of base size and count of + * extra multiplies of it.*/ + size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc); + size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1); + + /* Device structure */ + usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL); + if (usbtv == NULL) + return -ENOMEM; + usbtv->dev = dev; + usbtv->udev = usb_get_dev(interface_to_usbdev(intf)); + + usbtv->iso_size = size; + + usb_set_intfdata(intf, usbtv); + + ret = usbtv_video_init(usbtv); + if (ret < 0) + goto usbtv_video_fail; + + /* for simplicity we exploit the v4l2_device reference counting */ + v4l2_device_get(&usbtv->v4l2_dev); + + dev_info(dev, "Fushicai USBTV007 Video Grabber\n"); + return 0; + +usbtv_video_fail: + kfree(usbtv); + + return ret; +} + +static void usbtv_disconnect(struct usb_interface *intf) +{ + struct usbtv *usbtv = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + + if (!usbtv) + return; + + usbtv_video_free(usbtv); + + usb_put_dev(usbtv->udev); + usbtv->udev = NULL; + + /* the usbtv structure will be deallocated when v4l2 will be + done using it */ + v4l2_device_put(&usbtv->v4l2_dev); +} + +static struct usb_device_id usbtv_id_table[] = { + { USB_DEVICE(0x1b71, 0x3002) }, + {} +}; +MODULE_DEVICE_TABLE(usb, usbtv_id_table); + +MODULE_AUTHOR("Lubomir Rintel"); +MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +static struct usb_driver usbtv_usb_driver = { + .name = "usbtv", + .id_table = usbtv_id_table, + .probe = usbtv_probe, + .disconnect = usbtv_disconnect, +}; + +module_usb_driver(usbtv_usb_driver); diff --git a/drivers/media/usb/usbtv/usbtv.c b/drivers/media/usb/usbtv/usbtv-video.c index 8a505a90d31..2967e808408 100644 --- a/drivers/media/usb/usbtv/usbtv.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -28,95 +28,46 @@ * GNU General Public License ("GPL"). */ -#include <linux/init.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/videodev2.h> - -#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-core.h> -#include <media/videobuf2-vmalloc.h> - -/* Hardware. */ -#define USBTV_VIDEO_ENDP 0x81 -#define USBTV_BASE 0xc000 -#define USBTV_REQUEST_REG 12 - -/* Number of concurrent isochronous urbs submitted. - * Higher numbers was seen to overly saturate the USB bus. */ -#define USBTV_ISOC_TRANSFERS 16 -#define USBTV_ISOC_PACKETS 8 - -#define USBTV_WIDTH 720 -#define USBTV_HEIGHT 480 - -#define USBTV_CHUNK_SIZE 256 -#define USBTV_CHUNK 240 -#define USBTV_CHUNKS (USBTV_WIDTH * USBTV_HEIGHT \ - / 4 / USBTV_CHUNK) - -/* Chunk header. */ -#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ - == 0x88000000) -#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16) -#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15) -#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff) - -/* A single videobuf2 frame buffer. */ -struct usbtv_buf { - struct vb2_buffer vb; - struct list_head list; -}; -/* Per-device structure. */ -struct usbtv { - struct device *dev; - struct usb_device *udev; - struct v4l2_device v4l2_dev; - struct video_device vdev; - struct vb2_queue vb2q; - struct mutex v4l2_lock; - struct mutex vb2q_lock; - - /* List of videobuf2 buffers protected by a lock. */ - spinlock_t buflock; - struct list_head bufs; - - /* Number of currently processed frame, useful find - * out when a new one begins. */ - u32 frame_id; - int chunks_done; - - enum { - USBTV_COMPOSITE_INPUT, - USBTV_SVIDEO_INPUT, - } input; - int iso_size; - unsigned int sequence; - struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS]; +#include "usbtv.h" + +static struct usbtv_norm_params norm_params[] = { + { + .norm = V4L2_STD_525_60, + .cap_width = 720, + .cap_height = 480, + }, + { + .norm = V4L2_STD_PAL, + .cap_width = 720, + .cap_height = 576, + } }; -static int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) +static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) { - int ret; - int pipe = usb_rcvctrlpipe(usbtv->udev, 0); - int i; - - for (i = 0; i < size; i++) { - u16 index = regs[i][0]; - u16 value = regs[i][1]; + int i, ret = 0; + struct usbtv_norm_params *params = NULL; - ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 0); - if (ret < 0) - return ret; + for (i = 0; i < ARRAY_SIZE(norm_params); i++) { + if (norm_params[i].norm & norm) { + params = &norm_params[i]; + break; + } } - return 0; + if (params) { + usbtv->width = params->cap_width; + usbtv->height = params->cap_height; + usbtv->n_chunks = usbtv->width * usbtv->height + / 4 / USBTV_CHUNK; + usbtv->norm = params->norm; + } else + ret = -EINVAL; + + return ret; } static int usbtv_select_input(struct usbtv *usbtv, int input) @@ -158,6 +109,57 @@ static int usbtv_select_input(struct usbtv *usbtv, int input) return ret; } +static int usbtv_select_norm(struct usbtv *usbtv, v4l2_std_id norm) +{ + int ret; + static const u16 pal[][2] = { + { USBTV_BASE + 0x001a, 0x0068 }, + { USBTV_BASE + 0x010e, 0x0072 }, + { USBTV_BASE + 0x010f, 0x00a2 }, + { USBTV_BASE + 0x0112, 0x00b0 }, + { USBTV_BASE + 0x0117, 0x0001 }, + { USBTV_BASE + 0x0118, 0x002c }, + { USBTV_BASE + 0x012d, 0x0010 }, + { USBTV_BASE + 0x012f, 0x0020 }, + { USBTV_BASE + 0x024f, 0x0002 }, + { USBTV_BASE + 0x0254, 0x0059 }, + { USBTV_BASE + 0x025a, 0x0016 }, + { USBTV_BASE + 0x025b, 0x0035 }, + { USBTV_BASE + 0x0263, 0x0017 }, + { USBTV_BASE + 0x0266, 0x0016 }, + { USBTV_BASE + 0x0267, 0x0036 } + }; + + static const u16 ntsc[][2] = { + { USBTV_BASE + 0x001a, 0x0079 }, + { USBTV_BASE + 0x010e, 0x0068 }, + { USBTV_BASE + 0x010f, 0x009c }, + { USBTV_BASE + 0x0112, 0x00f0 }, + { USBTV_BASE + 0x0117, 0x0000 }, + { USBTV_BASE + 0x0118, 0x00fc }, + { USBTV_BASE + 0x012d, 0x0004 }, + { USBTV_BASE + 0x012f, 0x0008 }, + { USBTV_BASE + 0x024f, 0x0001 }, + { USBTV_BASE + 0x0254, 0x005f }, + { USBTV_BASE + 0x025a, 0x0012 }, + { USBTV_BASE + 0x025b, 0x0001 }, + { USBTV_BASE + 0x0263, 0x001c }, + { USBTV_BASE + 0x0266, 0x0011 }, + { USBTV_BASE + 0x0267, 0x0005 } + }; + + ret = usbtv_configure_for_norm(usbtv, norm); + + if (!ret) { + if (norm & V4L2_STD_525_60) + ret = usbtv_set_regs(usbtv, ntsc, ARRAY_SIZE(ntsc)); + else if (norm & V4L2_STD_PAL) + ret = usbtv_set_regs(usbtv, pal, ARRAY_SIZE(pal)); + } + + return ret; +} + static int usbtv_setup_capture(struct usbtv *usbtv) { int ret; @@ -225,26 +227,11 @@ static int usbtv_setup_capture(struct usbtv *usbtv) { USBTV_BASE + 0x0284, 0x0088 }, { USBTV_BASE + 0x0003, 0x0004 }, - { USBTV_BASE + 0x001a, 0x0079 }, { USBTV_BASE + 0x0100, 0x00d3 }, - { USBTV_BASE + 0x010e, 0x0068 }, - { USBTV_BASE + 0x010f, 0x009c }, - { USBTV_BASE + 0x0112, 0x00f0 }, { USBTV_BASE + 0x0115, 0x0015 }, - { USBTV_BASE + 0x0117, 0x0000 }, - { USBTV_BASE + 0x0118, 0x00fc }, - { USBTV_BASE + 0x012d, 0x0004 }, - { USBTV_BASE + 0x012f, 0x0008 }, { USBTV_BASE + 0x0220, 0x002e }, { USBTV_BASE + 0x0225, 0x0008 }, { USBTV_BASE + 0x024e, 0x0002 }, - { USBTV_BASE + 0x024f, 0x0001 }, - { USBTV_BASE + 0x0254, 0x005f }, - { USBTV_BASE + 0x025a, 0x0012 }, - { USBTV_BASE + 0x025b, 0x0001 }, - { USBTV_BASE + 0x0263, 0x001c }, - { USBTV_BASE + 0x0266, 0x0011 }, - { USBTV_BASE + 0x0267, 0x0005 }, { USBTV_BASE + 0x024e, 0x0002 }, { USBTV_BASE + 0x024f, 0x0002 }, }; @@ -253,6 +240,10 @@ static int usbtv_setup_capture(struct usbtv *usbtv) if (ret) return ret; + ret = usbtv_select_norm(usbtv, usbtv->norm); + if (ret) + return ret; + ret = usbtv_select_input(usbtv, usbtv->input); if (ret) return ret; @@ -296,7 +287,7 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) frame_id = USBTV_FRAME_ID(chunk); odd = USBTV_ODD(chunk); chunk_no = USBTV_CHUNK_NO(chunk); - if (chunk_no >= USBTV_CHUNKS) + if (chunk_no >= usbtv->n_chunks) return; /* Beginning of a frame. */ @@ -324,10 +315,10 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk) usbtv->chunks_done++; /* Last chunk in a frame, signalling an end */ - if (odd && chunk_no == USBTV_CHUNKS-1) { + if (odd && chunk_no == usbtv->n_chunks-1) { int size = vb2_plane_size(&buf->vb, 0); enum vb2_buffer_state state = usbtv->chunks_done == - USBTV_CHUNKS ? + usbtv->n_chunks ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; @@ -477,12 +468,6 @@ start_fail: return ret; } -struct usb_device_id usbtv_id_table[] = { - { USB_DEVICE(0x1b71, 0x3002) }, - {} -}; -MODULE_DEVICE_TABLE(usb, usbtv_id_table); - static int usbtv_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -500,6 +485,8 @@ static int usbtv_querycap(struct file *file, void *priv, static int usbtv_enum_input(struct file *file, void *priv, struct v4l2_input *i) { + struct usbtv *dev = video_drvdata(file); + switch (i->index) { case USBTV_COMPOSITE_INPUT: strlcpy(i->name, "Composite", sizeof(i->name)); @@ -512,7 +499,7 @@ static int usbtv_enum_input(struct file *file, void *priv, } i->type = V4L2_INPUT_TYPE_CAMERA; - i->std = V4L2_STD_525_60; + i->std = dev->vdev.tvnorms; return 0; } @@ -531,23 +518,37 @@ static int usbtv_enum_fmt_vid_cap(struct file *file, void *priv, static int usbtv_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - f->fmt.pix.width = USBTV_WIDTH; - f->fmt.pix.height = USBTV_HEIGHT; + struct usbtv *usbtv = video_drvdata(file); + + f->fmt.pix.width = usbtv->width; + f->fmt.pix.height = usbtv->height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; f->fmt.pix.field = V4L2_FIELD_INTERLACED; - f->fmt.pix.bytesperline = USBTV_WIDTH * 2; + f->fmt.pix.bytesperline = usbtv->width * 2; f->fmt.pix.sizeimage = (f->fmt.pix.bytesperline * f->fmt.pix.height); f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.priv = 0; + return 0; } static int usbtv_g_std(struct file *file, void *priv, v4l2_std_id *norm) { - *norm = V4L2_STD_525_60; + struct usbtv *usbtv = video_drvdata(file); + *norm = usbtv->norm; return 0; } +static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm) +{ + int ret = -EINVAL; + struct usbtv *usbtv = video_drvdata(file); + + if ((norm & V4L2_STD_525_60) || (norm & V4L2_STD_PAL)) + ret = usbtv_select_norm(usbtv, norm); + + return ret; +} + static int usbtv_g_input(struct file *file, void *priv, unsigned int *i) { struct usbtv *usbtv = video_drvdata(file); @@ -561,14 +562,7 @@ static int usbtv_s_input(struct file *file, void *priv, unsigned int i) return usbtv_select_input(usbtv, i); } -static int usbtv_s_std(struct file *file, void *priv, v4l2_std_id norm) -{ - if (norm & V4L2_STD_525_60) - return 0; - return -EINVAL; -} - -struct v4l2_ioctl_ops usbtv_ioctl_ops = { +static struct v4l2_ioctl_ops usbtv_ioctl_ops = { .vidioc_querycap = usbtv_querycap, .vidioc_enum_input = usbtv_enum_input, .vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap, @@ -590,7 +584,7 @@ struct v4l2_ioctl_ops usbtv_ioctl_ops = { .vidioc_streamoff = vb2_ioctl_streamoff, }; -struct v4l2_file_operations usbtv_fops = { +static struct v4l2_file_operations usbtv_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, .mmap = vb2_fop_mmap, @@ -604,10 +598,12 @@ static int usbtv_queue_setup(struct vb2_queue *vq, const struct v4l2_format *v4l_fmt, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { + struct usbtv *usbtv = vb2_get_drv_priv(vq); + if (*nbuffers < 2) *nbuffers = 2; *nplanes = 1; - sizes[0] = USBTV_WIDTH * USBTV_HEIGHT / 2 * sizeof(u32); + sizes[0] = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32); return 0; } @@ -638,18 +634,15 @@ static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count) return usbtv_start(usbtv); } -static int usbtv_stop_streaming(struct vb2_queue *vq) +static void usbtv_stop_streaming(struct vb2_queue *vq) { struct usbtv *usbtv = vb2_get_drv_priv(vq); - if (usbtv->udev == NULL) - return -ENODEV; - - usbtv_stop(usbtv); - return 0; + if (usbtv->udev) + usbtv_stop(usbtv); } -struct vb2_ops usbtv_vb2_ops = { +static struct vb2_ops usbtv_vb2_ops = { .queue_setup = usbtv_queue_setup, .buf_queue = usbtv_buf_queue, .start_streaming = usbtv_start_streaming, @@ -665,32 +658,12 @@ static void usbtv_release(struct v4l2_device *v4l2_dev) kfree(usbtv); } -static int usbtv_probe(struct usb_interface *intf, - const struct usb_device_id *id) +int usbtv_video_init(struct usbtv *usbtv) { int ret; - int size; - struct device *dev = &intf->dev; - struct usbtv *usbtv; - /* Checks that the device is what we think it is. */ - if (intf->num_altsetting != 2) - return -ENODEV; - if (intf->altsetting[1].desc.bNumEndpoints != 4) - return -ENODEV; + (void)usbtv_configure_for_norm(usbtv, V4L2_STD_525_60); - /* Packet size is split into 11 bits of base size and count of - * extra multiplies of it.*/ - size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc); - size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1); - - /* Device structure */ - usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL); - if (usbtv == NULL) - return -ENOMEM; - usbtv->dev = dev; - usbtv->udev = usb_get_dev(interface_to_usbdev(intf)); - usbtv->iso_size = size; spin_lock_init(&usbtv->buflock); mutex_init(&usbtv->v4l2_lock); mutex_init(&usbtv->vb2q_lock); @@ -703,83 +676,60 @@ static int usbtv_probe(struct usb_interface *intf, usbtv->vb2q.buf_struct_size = sizeof(struct usbtv_buf); usbtv->vb2q.ops = &usbtv_vb2_ops; usbtv->vb2q.mem_ops = &vb2_vmalloc_memops; - usbtv->vb2q.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + usbtv->vb2q.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; usbtv->vb2q.lock = &usbtv->vb2q_lock; ret = vb2_queue_init(&usbtv->vb2q); if (ret < 0) { - dev_warn(dev, "Could not initialize videobuf2 queue\n"); - goto usbtv_fail; + dev_warn(usbtv->dev, "Could not initialize videobuf2 queue\n"); + return ret; } /* v4l2 structure */ usbtv->v4l2_dev.release = usbtv_release; - ret = v4l2_device_register(dev, &usbtv->v4l2_dev); + ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev); if (ret < 0) { - dev_warn(dev, "Could not register v4l2 device\n"); + dev_warn(usbtv->dev, "Could not register v4l2 device\n"); goto v4l2_fail; } - usb_set_intfdata(intf, usbtv); - /* Video structure */ strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name)); usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev; usbtv->vdev.release = video_device_release_empty; usbtv->vdev.fops = &usbtv_fops; usbtv->vdev.ioctl_ops = &usbtv_ioctl_ops; - usbtv->vdev.tvnorms = V4L2_STD_525_60; + usbtv->vdev.tvnorms = USBTV_TV_STD; usbtv->vdev.queue = &usbtv->vb2q; usbtv->vdev.lock = &usbtv->v4l2_lock; set_bit(V4L2_FL_USE_FH_PRIO, &usbtv->vdev.flags); video_set_drvdata(&usbtv->vdev, usbtv); ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { - dev_warn(dev, "Could not register video device\n"); + dev_warn(usbtv->dev, "Could not register video device\n"); goto vdev_fail; } - dev_info(dev, "Fushicai USBTV007 Video Grabber\n"); return 0; vdev_fail: v4l2_device_unregister(&usbtv->v4l2_dev); v4l2_fail: vb2_queue_release(&usbtv->vb2q); -usbtv_fail: - kfree(usbtv); return ret; } -static void usbtv_disconnect(struct usb_interface *intf) +void usbtv_video_free(struct usbtv *usbtv) { - struct usbtv *usbtv = usb_get_intfdata(intf); - mutex_lock(&usbtv->vb2q_lock); mutex_lock(&usbtv->v4l2_lock); usbtv_stop(usbtv); - usb_set_intfdata(intf, NULL); video_unregister_device(&usbtv->vdev); v4l2_device_disconnect(&usbtv->v4l2_dev); - usb_put_dev(usbtv->udev); - usbtv->udev = NULL; mutex_unlock(&usbtv->v4l2_lock); mutex_unlock(&usbtv->vb2q_lock); v4l2_device_put(&usbtv->v4l2_dev); } - -MODULE_AUTHOR("Lubomir Rintel"); -MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver"); -MODULE_LICENSE("Dual BSD/GPL"); - -struct usb_driver usbtv_usb_driver = { - .name = "usbtv", - .id_table = usbtv_id_table, - .probe = usbtv_probe, - .disconnect = usbtv_disconnect, -}; - -module_usb_driver(usbtv_usb_driver); diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h new file mode 100644 index 00000000000..cb1d388cc64 --- /dev/null +++ b/drivers/media/usb/usbtv/usbtv.h @@ -0,0 +1,99 @@ +/* + * Fushicai USBTV007 Video Grabber Driver + * + * Copyright (c) 2013 Lubomir Rintel + * All rights reserved. + * No physical hardware was harmed running Windows during the + * reverse-engineering activity + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <media/v4l2-device.h> +#include <media/videobuf2-vmalloc.h> + +/* Hardware. */ +#define USBTV_VIDEO_ENDP 0x81 +#define USBTV_BASE 0xc000 +#define USBTV_REQUEST_REG 12 + +/* Number of concurrent isochronous urbs submitted. + * Higher numbers was seen to overly saturate the USB bus. */ +#define USBTV_ISOC_TRANSFERS 16 +#define USBTV_ISOC_PACKETS 8 + +#define USBTV_CHUNK_SIZE 256 +#define USBTV_CHUNK 240 + +/* Chunk header. */ +#define USBTV_MAGIC_OK(chunk) ((be32_to_cpu(chunk[0]) & 0xff000000) \ + == 0x88000000) +#define USBTV_FRAME_ID(chunk) ((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16) +#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15) +#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff) + +#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL) + +/* parameters for supported TV norms */ +struct usbtv_norm_params { + v4l2_std_id norm; + int cap_width, cap_height; +}; + +/* A single videobuf2 frame buffer. */ +struct usbtv_buf { + struct vb2_buffer vb; + struct list_head list; +}; + +/* Per-device structure. */ +struct usbtv { + struct device *dev; + struct usb_device *udev; + + /* video */ + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct vb2_queue vb2q; + struct mutex v4l2_lock; + struct mutex vb2q_lock; + + /* List of videobuf2 buffers protected by a lock. */ + spinlock_t buflock; + struct list_head bufs; + + /* Number of currently processed frame, useful find + * out when a new one begins. */ + u32 frame_id; + int chunks_done; + + enum { + USBTV_COMPOSITE_INPUT, + USBTV_SVIDEO_INPUT, + } input; + v4l2_std_id norm; + int width, height; + int n_chunks; + int iso_size; + unsigned int sequence; + struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS]; +}; + +int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size); + +int usbtv_video_init(struct usbtv *usbtv); +void usbtv_video_free(struct usbtv *usbtv); diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 5c9e3123ad2..68bc9615660 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -597,7 +597,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) usbvision->tvnorm_id = id; - call_all(usbvision, core, s_std, usbvision->tvnorm_id); + call_all(usbvision, video, s_std, usbvision->tvnorm_id); /* propagate the change to the decoder */ usbvision_muxsel(usbvision, usbvision->ctl_input); diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h index 8a25876d72c..a0c73cf1517 100644 --- a/drivers/media/usb/usbvision/usbvision.h +++ b/drivers/media/usb/usbvision/usbvision.h @@ -203,14 +203,6 @@ enum { mr = LIMIT_RGB(mm_r); \ } -/* Debugging aid */ -#define USBVISION_SAY_AND_WAIT(what) { \ - wait_queue_head_t wq; \ - init_waitqueue_head(&wq); \ - printk(KERN_INFO "Say: %s\n", what); \ - interruptible_sleep_on_timeout(&wq, HZ * 3); \ -} - /* * This macro checks if usbvision is still operational. The 'usbvision' * pointer must be valid, usbvision->dev must be valid, we are not diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index a2f4501c23c..0eb82106d2f 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -664,7 +664,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = { .size = 32, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, + .data_type = UVC_CTRL_DATA_TYPE_SIGNED, }, { .id = V4L2_CID_TILT_ABSOLUTE, @@ -674,7 +674,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = { .size = 32, .offset = 32, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, - .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, + .data_type = UVC_CTRL_DATA_TYPE_SIGNED, }, { .id = V4L2_CID_PRIVACY, diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 81695d48c13..ad47c5cb539 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -108,11 +108,31 @@ static struct uvc_format_desc uvc_fmts[] = { .fcc = V4L2_PIX_FMT_Y16, }, { - .name = "RGB Bayer", + .name = "BGGR Bayer (BY8 )", .guid = UVC_GUID_FORMAT_BY8, .fcc = V4L2_PIX_FMT_SBGGR8, }, { + .name = "BGGR Bayer (BA81)", + .guid = UVC_GUID_FORMAT_BA81, + .fcc = V4L2_PIX_FMT_SBGGR8, + }, + { + .name = "GBRG Bayer (GBRG)", + .guid = UVC_GUID_FORMAT_GBRG, + .fcc = V4L2_PIX_FMT_SGBRG8, + }, + { + .name = "GRBG Bayer (GRBG)", + .guid = UVC_GUID_FORMAT_GRBG, + .fcc = V4L2_PIX_FMT_SGRBG8, + }, + { + .name = "RGGB Bayer (RGGB)", + .guid = UVC_GUID_FORMAT_RGGB, + .fcc = V4L2_PIX_FMT_SRGGB8, + }, + { .name = "RGB565", .guid = UVC_GUID_FORMAT_RGBP, .fcc = V4L2_PIX_FMT_RGB565, @@ -925,7 +945,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, case UVC_VC_HEADER: n = buflen >= 12 ? buffer[11] : 0; - if (buflen < 12 || buflen < 12 + n) { + if (buflen < 12 + n) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d HEADER error\n", udev->devnum, alts->desc.bInterfaceNumber); @@ -2090,6 +2110,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Microsoft Lifecam NX-3000 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x045e, + .idProduct = 0x0721, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_DEF }, /* Microsoft Lifecam VX-7000 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2174,6 +2203,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_DEF }, + /* Dell SP2008WFP Monitor */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x05a9, + .idProduct = 0x2641, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_DEF }, /* Dell Alienware X51 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index cd962be860c..6e92d208025 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -48,12 +48,14 @@ static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, struct uvc_streaming *stream = container_of(queue, struct uvc_streaming, queue); - if (*nbuffers > UVC_MAX_VIDEO_BUFFERS) - *nbuffers = UVC_MAX_VIDEO_BUFFERS; + /* Make sure the image size is large enough. */ + if (fmt && fmt->fmt.pix.sizeimage < stream->ctrl.dwMaxVideoFrameSize) + return -EINVAL; *nplanes = 1; - sizes[0] = stream->ctrl.dwMaxVideoFrameSize; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage + : stream->ctrl.dwMaxVideoFrameSize; return 0; } @@ -104,15 +106,15 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&queue->irqlock, flags); } -static int uvc_buffer_finish(struct vb2_buffer *vb) +static void uvc_buffer_finish(struct vb2_buffer *vb) { struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); struct uvc_streaming *stream = container_of(queue, struct uvc_streaming, queue); struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); - uvc_video_clock_update(stream, &vb->v4l2_buf, buf); - return 0; + if (vb->state == VB2_BUF_STATE_DONE) + uvc_video_clock_update(stream, &vb->v4l2_buf, buf); } static void uvc_wait_prepare(struct vb2_queue *vq) @@ -149,7 +151,8 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; - queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TSTAMP_SRC_SOE; ret = vb2_queue_init(&queue->queue); if (ret) return ret; @@ -196,6 +199,18 @@ int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) return ret; } +int uvc_create_buffers(struct uvc_video_queue *queue, + struct v4l2_create_buffers *cb) +{ + int ret; + + mutex_lock(&queue->mutex); + ret = vb2_create_bufs(&queue->queue, cb); + mutex_unlock(&queue->mutex); + + return ret; +} + int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) { int ret; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 3afff92804d..378ae02e593 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -1000,6 +1000,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) return uvc_query_buffer(&stream->queue, buf); } + case VIDIOC_CREATE_BUFS: + { + struct v4l2_create_buffers *cb = arg; + + ret = uvc_acquire_privileges(handle); + if (ret < 0) + return ret; + + return uvc_create_buffers(&stream->queue, cb); + } + case VIDIOC_QBUF: if (!uvc_has_privileges(handle)) return -EBUSY; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 3394c343201..9144a2f3ed8 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -361,6 +361,14 @@ static int uvc_commit_video(struct uvc_streaming *stream, * Clocks and timestamps */ +static inline void uvc_video_get_ts(struct timespec *ts) +{ + if (uvc_clock_param == CLOCK_MONOTONIC) + ktime_get_ts(ts); + else + ktime_get_real_ts(ts); +} + static void uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, const __u8 *data, int len) @@ -420,7 +428,7 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, stream->clock.last_sof = dev_sof; host_sof = usb_get_current_frame_number(stream->dev->udev); - ktime_get_ts(&ts); + uvc_video_get_ts(&ts); /* The UVC specification allows device implementations that can't obtain * the USB frame number to keep their own frame counters as long as they @@ -556,7 +564,7 @@ static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample) * * SOF = ((SOF2 - SOF1) * PTS + SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1) (1) * - * to avoid loosing precision in the division. Similarly, the host timestamp is + * to avoid losing precision in the division. Similarly, the host timestamp is * computed with * * TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1) (2) @@ -680,7 +688,8 @@ void uvc_video_clock_update(struct uvc_streaming *stream, stream->dev->name, sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536), y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC, - v4l2_buf->timestamp.tv_sec, v4l2_buf->timestamp.tv_usec, + v4l2_buf->timestamp.tv_sec, + (unsigned long)v4l2_buf->timestamp.tv_usec, x1, first->host_sof, first->dev_sof, x2, last->host_sof, last->dev_sof, y1, y2); @@ -1010,10 +1019,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return -ENODATA; } - if (uvc_clock_param == CLOCK_MONOTONIC) - ktime_get_ts(&ts); - else - ktime_get_real_ts(&ts); + uvc_video_get_ts(&ts); buf->buf.v4l2_buf.sequence = stream->sequence; buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec; @@ -1132,6 +1138,17 @@ static int uvc_video_encode_data(struct uvc_streaming *stream, */ /* + * Set error flag for incomplete buffer. + */ +static void uvc_video_validate_buffer(const struct uvc_streaming *stream, + struct uvc_buffer *buf) +{ + if (buf->length != buf->bytesused && + !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)) + buf->error = 1; +} + +/* * Completion handler for video URBs. */ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, @@ -1155,9 +1172,11 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, do { ret = uvc_video_decode_start(stream, buf, mem, urb->iso_frame_desc[i].actual_length); - if (ret == -EAGAIN) + if (ret == -EAGAIN) { + uvc_video_validate_buffer(stream, buf); buf = uvc_queue_next_buffer(&stream->queue, buf); + } } while (ret == -EAGAIN); if (ret < 0) @@ -1172,11 +1191,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, urb->iso_frame_desc[i].actual_length); if (buf->state == UVC_BUF_STATE_READY) { - if (buf->length != buf->bytesused && - !(stream->cur_format->flags & - UVC_FMT_FLAG_COMPRESSED)) - buf->error = 1; - + uvc_video_validate_buffer(stream, buf); buf = uvc_queue_next_buffer(&stream->queue, buf); } } @@ -1452,6 +1467,9 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev, case USB_SPEED_HIGH: psize = usb_endpoint_maxp(&ep->desc); return (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); + case USB_SPEED_WIRELESS: + psize = usb_endpoint_maxp(&ep->desc); + return psize; default: psize = usb_endpoint_maxp(&ep->desc); return psize & 0x07ff; @@ -1846,7 +1864,25 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) if (!enable) { uvc_uninit_video(stream, 1); - usb_set_interface(stream->dev->udev, stream->intfnum, 0); + if (stream->intf->num_altsetting > 1) { + usb_set_interface(stream->dev->udev, + stream->intfnum, 0); + } else { + /* UVC doesn't specify how to inform a bulk-based device + * when the video stream is stopped. Windows sends a + * CLEAR_FEATURE(HALT) request to the video streaming + * bulk endpoint, mimic the same behaviour. + */ + unsigned int epnum = stream->header.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK; + unsigned int dir = stream->header.bEndpointAddress + & USB_ENDPOINT_DIR_MASK; + unsigned int pipe; + + pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir; + usb_clear_halt(stream->dev->udev, pipe); + } + uvc_queue_enable(&stream->queue, 0); uvc_video_clock_cleanup(stream); return 0; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 9e35982d099..b1f69a6d406 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -94,6 +94,18 @@ #define UVC_GUID_FORMAT_BY8 \ { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BA81 \ + { 'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GBRG \ + { 'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GRBG \ + { 'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RGGB \ + { 'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} #define UVC_GUID_FORMAT_RGBP \ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} @@ -115,8 +127,6 @@ #define UVC_URBS 5 /* Maximum number of packets per URB. */ #define UVC_MAX_PACKETS 32 -/* Maximum number of video buffers. */ -#define UVC_MAX_VIDEO_BUFFERS 32 /* Maximum status buffer size in bytes of interrupt URB. */ #define UVC_MAX_STATUS_SIZE 16 @@ -616,6 +626,8 @@ extern int uvc_alloc_buffers(struct uvc_video_queue *queue, extern void uvc_free_buffers(struct uvc_video_queue *queue); extern int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf); +extern int uvc_create_buffers(struct uvc_video_queue *queue, + struct v4l2_create_buffers *v4l2_cb); extern int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf); extern int uvc_dequeue_buffer(struct uvc_video_queue *queue, |
