diff options
Diffstat (limited to 'linux/drivers/media/video/em28xx')
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-audio.c | 95 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-cards.c | 532 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-core.c | 149 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-input.c | 2 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-reg.h | 19 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-video.c | 689 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx.h | 20 |
7 files changed, 767 insertions, 739 deletions
diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c index c62455202..34c494d68 100644 --- a/linux/drivers/media/video/em28xx/em28xx-audio.c +++ b/linux/drivers/media/video/em28xx/em28xx-audio.c @@ -63,9 +63,9 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev) dprintk("Stopping isoc\n"); for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - usb_unlink_urb(dev->adev->urb[i]); - usb_free_urb(dev->adev->urb[i]); - dev->adev->urb[i] = NULL; + usb_unlink_urb(dev->adev.urb[i]); + usb_free_urb(dev->adev.urb[i]); + dev->adev.urb[i] = NULL; } return 0; @@ -94,8 +94,8 @@ static void em28xx_audio_isocirq(struct urb *urb) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; #endif - if (dev->adev->capture_pcm_substream) { - substream = dev->adev->capture_pcm_substream; + if (dev->adev.capture_pcm_substream) { + substream = dev->adev.capture_pcm_substream; runtime = substream->runtime; stride = runtime->frame_bits >> 3; @@ -109,9 +109,9 @@ static void em28xx_audio_isocirq(struct urb *urb) continue; #ifdef NO_PCM_LOCK - spin_lock_irqsave(&dev->adev->slock, flags); + spin_lock_irqsave(&dev->adev.slock, flags); #endif - oldptr = dev->adev->hwptr_done_capture; + oldptr = dev->adev.hwptr_done_capture; if (oldptr + length >= runtime->buffer_size) { unsigned int cnt = runtime->buffer_size - oldptr; @@ -128,22 +128,22 @@ static void em28xx_audio_isocirq(struct urb *urb) snd_pcm_stream_lock(substream); #endif - dev->adev->hwptr_done_capture += length; - if (dev->adev->hwptr_done_capture >= + dev->adev.hwptr_done_capture += length; + if (dev->adev.hwptr_done_capture >= runtime->buffer_size) - dev->adev->hwptr_done_capture -= + dev->adev.hwptr_done_capture -= runtime->buffer_size; - dev->adev->capture_transfer_done += length; - if (dev->adev->capture_transfer_done >= + dev->adev.capture_transfer_done += length; + if (dev->adev.capture_transfer_done >= runtime->period_size) { - dev->adev->capture_transfer_done -= + dev->adev.capture_transfer_done -= runtime->period_size; period_elapsed = 1; } #ifdef NO_PCM_LOCK - spin_unlock_irqrestore(&dev->adev->slock, flags); + spin_unlock_irqrestore(&dev->adev.slock, flags); #else snd_pcm_stream_unlock(substream); #endif @@ -153,7 +153,7 @@ static void em28xx_audio_isocirq(struct urb *urb) } urb->status = 0; - if (dev->adev->shutdown) + if (dev->adev.shutdown) return; status = usb_submit_urb(urb, GFP_ATOMIC); @@ -176,17 +176,17 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) struct urb *urb; int j, k; - dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); - if (!dev->adev->transfer_buffer[i]) + dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); + if (!dev->adev.transfer_buffer[i]) return -ENOMEM; - memset(dev->adev->transfer_buffer[i], 0x80, sb_size); + 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]); + usb_free_urb(dev->adev.urb[j]); + kfree(dev->adev.transfer_buffer[j]); } return -ENOMEM; } @@ -195,7 +195,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) urb->context = dev; urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->adev->transfer_buffer[i]; + urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->interval = 1; urb->complete = em28xx_audio_isocirq; urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; @@ -207,11 +207,11 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) urb->iso_frame_desc[j].length = EM28XX_AUDIO_MAX_PACKET_SIZE; } - dev->adev->urb[i] = urb; + dev->adev.urb[i] = urb; } for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC); + errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); if (errCode) { em28xx_isoc_audio_deinit(dev); @@ -224,16 +224,16 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) static int em28xx_cmd(struct em28xx *dev, int cmd, int arg) { - dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)? + dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ? "stop" : "start"); switch (cmd) { case EM28XX_CAPTURE_STREAM_EN: - if (dev->adev->capture_stream == STREAM_OFF && arg == 1) { - dev->adev->capture_stream = STREAM_ON; + if (dev->adev.capture_stream == STREAM_OFF && arg == 1) { + dev->adev.capture_stream = STREAM_ON; em28xx_init_audio_isoc(dev); - } else if (dev->adev->capture_stream == STREAM_ON && arg == 0) { - dev->adev->capture_stream = STREAM_OFF; + } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) { + dev->adev.capture_stream = STREAM_OFF; em28xx_isoc_audio_deinit(dev); } else { printk(KERN_ERR "An underrun very likely occurred. " @@ -332,17 +332,17 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) goto err; runtime->hw = snd_em28xx_hw_capture; - if (dev->alt == 0 && dev->adev->users == 0) { + if (dev->alt == 0 && dev->adev.users == 0) { int errCode; dev->alt = 7; errCode = usb_set_interface(dev->udev, 0, 7); dprintk("changing alternate number to 7\n"); } - dev->adev->users++; + dev->adev.users++; snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - dev->adev->capture_pcm_substream = substream; + dev->adev.capture_pcm_substream = substream; runtime->private_data = dev; return 0; @@ -358,7 +358,7 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) #endif { struct em28xx *dev = snd_pcm_substream_chip(substream); - dev->adev->users--; + dev->adev.users--; dprintk("closing device\n"); @@ -367,10 +367,10 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) em28xx_audio_analog_set(dev); mutex_unlock(&dev->lock); - if (dev->adev->users == 0 && dev->adev->shutdown == 1) { - dprintk("audio users: %d\n", dev->adev->users); + if (dev->adev.users == 0 && dev->adev.shutdown == 1) { + dprintk("audio users: %d\n", dev->adev.users); dprintk("disabling audio stream!\n"); - dev->adev->shutdown = 0; + dev->adev.shutdown = 0; dprintk("released lock\n"); em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); } @@ -412,7 +412,7 @@ static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) dprintk("Stop capture, if needed\n"); - if (dev->adev->capture_stream == STREAM_ON) + if (dev->adev.capture_stream == STREAM_ON) em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); return 0; @@ -443,7 +443,7 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1); return 0; case SNDRV_PCM_TRIGGER_STOP: - dev->adev->shutdown = 1; + dev->adev.shutdown = 1; return 0; default: return -EINVAL; @@ -462,7 +462,7 @@ 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); - hwptr_done = dev->adev->hwptr_done_capture; + hwptr_done = dev->adev.hwptr_done_capture; return hwptr_done; } @@ -498,7 +498,7 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = { static int em28xx_audio_init(struct em28xx *dev) { - struct em28xx_audio *adev; + struct em28xx_audio *adev = &dev->adev; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16) snd_pcm_t *pcm; snd_card_t *card; @@ -521,16 +521,9 @@ static int em28xx_audio_init(struct em28xx *dev) printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " "Rechberger\n"); - adev = kzalloc(sizeof(*adev), GFP_KERNEL); - if (!adev) { - printk(KERN_ERR "em28xx-audio.c: out of memory\n"); - return -1; - } card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0); - if (card == NULL) { - kfree(adev); + if (card == NULL) return -ENOMEM; - } spin_lock_init(&adev->slock); err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); @@ -554,7 +547,6 @@ static int em28xx_audio_init(struct em28xx *dev) } adev->sndcard = card; adev->udev = dev->udev; - dev->adev = adev; return 0; } @@ -571,10 +563,9 @@ static int em28xx_audio_fini(struct em28xx *dev) return 0; } - if (dev->adev) { - snd_card_free(dev->adev->sndcard); - kfree(dev->adev); - dev->adev = NULL; + if (dev->adev.sndcard) { + snd_card_free(dev->adev.sndcard); + dev->adev.sndcard = NULL; } return 0; diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index c14fca841..73a41bcd5 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -38,6 +38,8 @@ #include "em28xx.h" +#define DRIVER_NAME "em28xx" + static int tuner = -1; module_param(tuner, int, 0444); MODULE_PARM_DESC(tuner, "tuner type"); @@ -46,6 +48,13 @@ static unsigned int disable_ir; module_param(disable_ir, int, 0444); MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); +static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); + +/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ +static unsigned long em28xx_devused; + struct em28xx_hash_table { unsigned long hash; unsigned int model; @@ -114,17 +123,6 @@ static struct em28xx_reg_seq default_tuner_gpio[] = { { -1, -1, -1, -1}, }; -/* Pinnacle 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_pinnacle_80e_digital[] = { - {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ - {EM2874_R80_GPIO, 0x80, 0xff, 100},/*Demod reset*/ - {EM2874_R80_GPIO, 0xc0, 0xff, 10}, - { -1, -1, -1, -1}, -}; - /* * Board definitions */ @@ -343,20 +341,6 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, - [EM2820_BOARD_PINNACLE_DVC_100] = { - .name = "Pinnacle Dazzle DVC 100", - .decoder = EM28XX_SAA711X, - .tuner_type = TUNER_ABSENT, /* Capture only device */ - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { .name = "Videology 20K14XUSB USB2.0", .valid = EM28XX_BOARD_NOT_VALIDATED, @@ -975,8 +959,30 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, + [EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2] = { + .name = "Pixelview PlayTV Box 4 USB 2.0", + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_YMEC_TVF_5533MF, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + .aout = EM28XX_AOUT_MONO | /* I2S */ + EM28XX_AOUT_MASTER, /* Line out pin */ + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { .name = "Pixelview Prolink PlayTV USB 2.0", + .has_snapshot_button = 1, .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_YMEC_TVF_5533MF, .decoder = EM28XX_SAA711X, @@ -1276,27 +1282,6 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, - - /* em2874 tuners are DVB only */ - - [EM2874_BOARD_PINNACLE_PCTV_80E] = { - .name = "Pinnacle PCTV HD Mini", - .tuner_type = TUNER_ABSENT, - .has_dvb = 1, - .dvb_gpio = em2874_pinnacle_80e_digital, - .ir_codes = ir_codes_pinnacle_pctv_hd, - .decoder = EM28XX_NODECODER, - .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | - EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_FREQ_400_KHZ, -#ifdef DJH_DEBUG - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - } }, -#endif - }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1394,8 +1379,6 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO }, { USB_DEVICE(0x2304, 0x0227), .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, - { USB_DEVICE(0x2304, 0x023f), - .driver_info = EM2874_BOARD_PINNACLE_PCTV_80E }, { USB_DEVICE(0x0413, 0x6023), .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, { USB_DEVICE(0x093b, 0xa005), @@ -1410,6 +1393,7 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table); static struct em28xx_hash_table em28xx_eeprom_hash [] = { /* P/N: SA 60002070465 Tuner: TVF7533-MF */ {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, + {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF}, {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028}, }; @@ -1440,6 +1424,17 @@ EXPORT_SYMBOL_GPL(em28xx_tuner_callback); static void inline em28xx_set_model(struct em28xx *dev) { memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board)); + + /* Those are the default values for the majority of boards + Use those values if not specified otherwise at boards entry + */ + if (!dev->board.xclk) + dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE | + EM28XX_XCLK_FREQUENCY_12MHZ; + + if (!dev->board.i2c_speed) + dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_100_KHZ; } /* Since em28xx_pre_card_setup() requires a proper dev->model, @@ -1501,17 +1496,8 @@ void em28xx_pre_card_setup(struct em28xx *dev) if (rc >= 0) dev->reg_gpo = rc; - /* Those are the default values for the majority of boards - Use those values if not specified otherwise at boards entry - */ - if (!dev->board.xclk) - dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE | - EM28XX_XCLK_FREQUENCY_12MHZ; - - if (!dev->board.i2c_speed) - dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | - EM28XX_I2C_FREQ_100_KHZ; - + /* Set the initial XCLK and I2C clock values based on the board + definition */ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); msleep(50); @@ -1870,3 +1856,431 @@ void em28xx_card_setup(struct em28xx *dev) em28xx_ir_init(dev); } + +#if defined(CONFIG_MODULES) && defined(MODULE) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void request_module_async(void *ptr) +{ + struct em28xx *dev = (struct em28xx *)ptr; +#else +static void request_module_async(struct work_struct *work) +{ + struct em28xx *dev = container_of(work, + struct em28xx, request_module_wk); +#endif + + 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"); +} + +static void request_modules(struct em28xx *dev) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + INIT_WORK(&dev->request_module_wk, request_module_async, + (void *)dev); +#else + INIT_WORK(&dev->request_module_wk, request_module_async); +#endif + schedule_work(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#endif /* CONFIG_MODULES */ + +/* + * em28xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +void em28xx_release_resources(struct em28xx *dev) +{ + if (dev->sbutton_input_dev) + em28xx_deregister_snapshot_button(dev); + + if (dev->ir) + em28xx_ir_fini(dev); + + /*FIXME: I2C IR should be disconnected */ + + em28xx_release_analog_resources(dev); + + em28xx_remove_from_devlist(dev); + + em28xx_i2c_unregister(dev); + usb_put_dev(dev->udev); + + /* Mark device as unused */ + em28xx_devused &= ~(1 << dev->devno); +}; + +/* + * em28xx_init_dev() + * allocates and inits the device structs, registers i2c bus and v4l device + */ +static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, + int minor) +{ + struct em28xx *dev = *devhandle; + int retval = -ENOMEM; + int errCode; + + dev->udev = udev; + mutex_init(&dev->ctrl_urb_lock); + spin_lock_init(&dev->slock); + init_waitqueue_head(&dev->open); + init_waitqueue_head(&dev->wait_frame); + init_waitqueue_head(&dev->wait_stream); + + dev->em28xx_write_regs = em28xx_write_regs; + dev->em28xx_read_reg = em28xx_read_reg; + dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; + dev->em28xx_write_regs_req = em28xx_write_regs_req; + dev->em28xx_read_reg_req = em28xx_read_reg_req; + dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800; + + em28xx_pre_card_setup(dev); + + if (!dev->board.is_em2800) { + /* Sets I2C speed to 100 KHz */ + retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); + if (retval < 0) { + em28xx_errdev("%s: em28xx_write_regs_req failed!" + " retval [%d]\n", + __func__, retval); + return retval; + } + } + + /* register i2c bus */ + errCode = em28xx_i2c_register(dev); + if (errCode < 0) { + em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n", + __func__, errCode); + return errCode; + } + + /* Do board specific init and eeprom reading */ + em28xx_card_setup(dev); + + /* Configure audio */ + errCode = em28xx_audio_setup(dev); + if (errCode < 0) { + em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n", + __func__, errCode); + } + + /* wake i2c devices */ + em28xx_wake_i2c(dev); + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + +#if 0 + video_set_drvdata(dev->vbi_dev, dev); +#endif + + if (dev->board.has_msp34xx) { + /* Send a reset to other chips via gpio */ + errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); + if (errCode < 0) { + em28xx_errdev("%s: em28xx_write_regs_req - " + "msp34xx(1) failed! errCode [%d]\n", + __func__, errCode); + return errCode; + } + msleep(3); + + errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); + if (errCode < 0) { + em28xx_errdev("%s: em28xx_write_regs_req - " + "msp34xx(2) failed! errCode [%d]\n", + __func__, errCode); + return errCode; + } + msleep(3); + } + + em28xx_add_into_devlist(dev); + + retval = em28xx_register_analog_devices(dev); + if (retval < 0) { + em28xx_release_resources(dev); + goto fail_reg_devices; + } + + em28xx_init_extension(dev); + + /* Save some power by putting tuner to sleep */ + em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); + + return 0; + +fail_reg_devices: + return retval; +} + +/* + * em28xx_usb_probe() + * checks for supported devices + */ +static int em28xx_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + const struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev; + struct usb_interface *uif; + struct em28xx *dev = NULL; + int retval = -ENODEV; + int i, nr, ifnum, isoc_pipe; + char *speed; + char descr[255] = ""; + + udev = usb_get_dev(interface_to_usbdev(interface)); + ifnum = interface->altsetting[0].desc.bInterfaceNumber; + + /* Check to see next free device and mark as used */ + nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); + em28xx_devused |= 1<<nr; + + /* Don't register audio interfaces */ + if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { + em28xx_err(DRIVER_NAME " audio device (%04x:%04x): " + "interface %i, class %i\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting[0].desc.bInterfaceClass); + + em28xx_devused &= ~(1<<nr); + return -ENODEV; + } + + endpoint = &interface->cur_altsetting->endpoint[0].desc; + + /* check if the device has the iso in endpoint at the correct place */ + if (usb_endpoint_xfer_isoc(endpoint) + && + (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) { + /* It's a newer em2874/em2875 device */ + isoc_pipe = 0; + } else { + int check_interface = 1; + isoc_pipe = 1; + endpoint = &interface->cur_altsetting->endpoint[1].desc; + if (!usb_endpoint_xfer_isoc(endpoint)) + check_interface = 0; + + if (usb_endpoint_dir_out(endpoint)) + check_interface = 0; + + if (!check_interface) { + em28xx_err(DRIVER_NAME " video device (%04x:%04x): " + "interface %i, class %i found.\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting[0].desc.bInterfaceClass); + + em28xx_err(DRIVER_NAME " This is an anciliary " + "interface not used by the driver\n"); + + em28xx_devused &= ~(1<<nr); + return -ENODEV; + } + } + + switch (udev->speed) { + case USB_SPEED_LOW: + speed = "1.5"; + break; + case USB_SPEED_UNKNOWN: + case USB_SPEED_FULL: + speed = "12"; + break; + case USB_SPEED_HIGH: + speed = "480"; + break; + default: + speed = "unknown"; + } + + if (udev->manufacturer) + strlcpy(descr, udev->manufacturer, sizeof(descr)); + + if (udev->product) { + if (*descr) + strlcat(descr, " ", sizeof(descr)); + strlcat(descr, udev->product, sizeof(descr)); + } + if (*descr) + strlcat(descr, " ", sizeof(descr)); + + printk(DRIVER_NAME ": New device %s@ %s Mbps " + "(%04x:%04x, interface %d, class %d)\n", + descr, + speed, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting->desc.bInterfaceNumber); + + if (nr >= EM28XX_MAXBOARDS) { + printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", + EM28XX_MAXBOARDS); + em28xx_devused &= ~(1<<nr); + return -ENOMEM; + } + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + em28xx_err(DRIVER_NAME ": out of memory!\n"); + em28xx_devused &= ~(1<<nr); + return -ENOMEM; + } + + snprintf(dev->name, 29, "em28xx #%d", nr); + dev->devno = nr; + dev->model = id->driver_info; + dev->alt = -1; + + /* Checks if audio is provided by some interface */ + for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { + uif = udev->config->interface[i]; + if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { + dev->has_audio_class = 1; + break; + } + } + + /* compute alternate max packet sizes */ + uif = udev->actconfig->interface[0]; + + dev->num_alt = uif->num_altsetting; + dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); + + if (dev->alt_max_pkt_size == NULL) { + em28xx_errdev("out of memory!\n"); + em28xx_devused &= ~(1<<nr); + kfree(dev); + return -ENOMEM; + } + + for (i = 0; i < dev->num_alt ; i++) { + u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); + dev->alt_max_pkt_size[i] = + (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); + } + + if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) + dev->model = card[nr]; + + /* allocate device struct */ + mutex_init(&dev->lock); + mutex_lock(&dev->lock); + retval = em28xx_init_dev(&dev, udev, nr); + if (retval) { + em28xx_devused &= ~(1<<dev->devno); + kfree(dev); + + return retval; + } + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + 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; +} + +/* + * em28xx_usb_disconnect() + * called when the device gets diconencted + * video device will be unregistered on v4l2_close in case it is still open + */ +static void em28xx_usb_disconnect(struct usb_interface *interface) +{ + struct em28xx *dev; + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + if (!dev) + return; + + em28xx_info("disconnecting %s\n", dev->vdev->name); + + /* wait until all current v4l2 io is finished then deallocate + resources */ + mutex_lock(&dev->lock); + + wake_up_interruptible_all(&dev->open); + + if (dev->users) { + em28xx_warn + ("device /dev/video%d is open! Deregistration and memory " + "deallocation are deferred on close.\n", + dev->vdev->num); + + dev->state |= DEV_MISCONFIGURED; + em28xx_uninit_isoc(dev); + dev->state |= DEV_DISCONNECTED; + wake_up_interruptible(&dev->wait_frame); + wake_up_interruptible(&dev->wait_stream); + } else { + dev->state |= DEV_DISCONNECTED; + em28xx_release_resources(dev); + } + + em28xx_close_extension(dev); + + mutex_unlock(&dev->lock); + + if (!dev->users) { + kfree(dev->alt_max_pkt_size); + kfree(dev); + } +} + +static struct usb_driver em28xx_usb_driver = { + .name = "em28xx", + .probe = em28xx_usb_probe, + .disconnect = em28xx_usb_disconnect, + .id_table = em28xx_id_table, +}; + +static int __init em28xx_module_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&em28xx_usb_driver); + if (result) + em28xx_err(DRIVER_NAME + " usb_register failed. Error number %d.\n", result); + + printk(KERN_INFO DRIVER_NAME " driver loaded\n"); + + return result; +} + +static void __exit em28xx_module_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&em28xx_usb_driver); +} + +module_init(em28xx_module_init); +module_exit(em28xx_module_exit); diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 025a54bb7..5455472b7 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/usb.h> #include <linux/vmalloc.h> +#include <media/v4l2-common.h> #include "em28xx.h" @@ -392,7 +393,7 @@ static int em28xx_set_audio_source(struct em28xx *dev) return ret; } -struct em28xx_vol_table outputs[] = { +static const struct em28xx_vol_table outputs[] = { { EM28XX_AOUT_MASTER, AC97_MASTER_VOL }, { EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL }, { EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL }, @@ -464,7 +465,7 @@ int em28xx_audio_setup(struct em28xx *dev) int vid1, vid2, feat, cfg; u32 vid; - if (dev->chip_id == CHIP_ID_EM2874) { + if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874) { /* Digital only device - don't load any alsa module */ dev->audio_mode.has_audio = 0; dev->has_audio_class = 0; @@ -496,7 +497,8 @@ int em28xx_audio_setup(struct em28xx *dev) dev->audio_mode.i2s_5rates = 1; } - if (!(cfg & EM28XX_CHIPCFG_AC97)) { + if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) { + /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; goto init_audio; } @@ -983,3 +985,144 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, return 0; } EXPORT_SYMBOL_GPL(em28xx_init_isoc); + +/* + * em28xx_wake_i2c() + * configure i2c attached devices + */ +void em28xx_wake_i2c(struct em28xx *dev) +{ + struct v4l2_routing route; + int zero = 0; + + route.input = INPUT(dev->ctl_input)->vmux; + route.output = 0; + em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero); + em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); + em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); +} + +/* + * Device control list + */ + +static LIST_HEAD(em28xx_devlist); +static DEFINE_MUTEX(em28xx_devlist_mutex); + +struct em28xx *em28xx_get_device(int minor, + enum v4l2_buf_type *fh_type, + int *has_radio) +{ + struct em28xx *h, *dev = NULL; + + *fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + *has_radio = 0; + + mutex_lock(&em28xx_devlist_mutex); + list_for_each_entry(h, &em28xx_devlist, devlist) { + if (h->vdev->minor == minor) + dev = h; + if (h->vbi_dev->minor == minor) { + dev = h; + *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; + } + if (h->radio_dev && + h->radio_dev->minor == minor) { + dev = h; + *has_radio = 1; + } + } + mutex_unlock(&em28xx_devlist_mutex); + + return dev; +} + +/* + * em28xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +void em28xx_remove_from_devlist(struct em28xx *dev) +{ + mutex_lock(&em28xx_devlist_mutex); + list_del(&dev->devlist); + mutex_unlock(&em28xx_devlist_mutex); +}; + +void em28xx_add_into_devlist(struct em28xx *dev) +{ + mutex_lock(&em28xx_devlist_mutex); + list_add_tail(&dev->devlist, &em28xx_devlist); + mutex_unlock(&em28xx_devlist_mutex); +}; + +/* + * Extension interface + */ + +static LIST_HEAD(em28xx_extension_devlist); +static DEFINE_MUTEX(em28xx_extension_devlist_lock); + +int em28xx_register_extension(struct em28xx_ops *ops) +{ + struct em28xx *dev = NULL; + + mutex_lock(&em28xx_devlist_mutex); + mutex_lock(&em28xx_extension_devlist_lock); + list_add_tail(&ops->next, &em28xx_extension_devlist); + list_for_each_entry(dev, &em28xx_devlist, devlist) { + if (dev) + ops->init(dev); + } + printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); + mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&em28xx_devlist_mutex); + return 0; +} +EXPORT_SYMBOL(em28xx_register_extension); + +void em28xx_unregister_extension(struct em28xx_ops *ops) +{ + struct em28xx *dev = NULL; + + mutex_lock(&em28xx_devlist_mutex); + list_for_each_entry(dev, &em28xx_devlist, devlist) { + if (dev) + ops->fini(dev); + } + + mutex_lock(&em28xx_extension_devlist_lock); + printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); + list_del(&ops->next); + mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&em28xx_devlist_mutex); +} +EXPORT_SYMBOL(em28xx_unregister_extension); + +void em28xx_init_extension(struct em28xx *dev) +{ + struct em28xx_ops *ops = NULL; + + mutex_lock(&em28xx_extension_devlist_lock); + if (!list_empty(&em28xx_extension_devlist)) { + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->init) + ops->init(dev); + } + } + mutex_unlock(&em28xx_extension_devlist_lock); +} + +void em28xx_close_extension(struct em28xx *dev) +{ + struct em28xx_ops *ops = NULL; + + mutex_lock(&em28xx_extension_devlist_lock); + if (!list_empty(&em28xx_extension_devlist)) { + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->fini) + ops->fini(dev); + } + } + mutex_unlock(&em28xx_extension_devlist_lock); +} diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index d6ef5c461..b97a1bc85 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -321,7 +321,7 @@ static void em28xx_ir_work(struct work_struct *work) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } -void em28xx_ir_start(struct em28xx_IR *ir) +static void em28xx_ir_start(struct em28xx_IR *ir) { setup_timer(&ir->timer, ir_timer, (unsigned long)ir); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index a459b7c6a..24e39c568 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -22,8 +22,8 @@ /* em28xx Chip Configuration 0x00 */ #define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80 #define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40 -#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x30 -#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x20 +#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x30 +#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x20 #define EM28XX_CHIPCFG_AC97 0x10 #define EM28XX_CHIPCFG_AUDIOMASK 0x30 @@ -97,6 +97,19 @@ #define EM28XX_R26_COMPR 0x26 #define EM28XX_R27_OUTFMT 0x27 +/* em28xx Output Format Register (0x27) */ +#define EM28XX_OUTFMT_RGB_8_RGRG 0x00 +#define EM28XX_OUTFMT_RGB_8_GRGR 0x01 +#define EM28XX_OUTFMT_RGB_8_GBGB 0x02 +#define EM28XX_OUTFMT_RGB_8_BGBG 0x03 +#define EM28XX_OUTFMT_RGB_16_656 0x04 +#define EM28XX_OUTFMT_RGB_8_BAYER 0x08 /* Pattern in Reg 0x10[1-0] */ +#define EM28XX_OUTFMT_YUV211 0x10 +#define EM28XX_OUTFMT_YUV422_Y0UY1V 0x14 +#define EM28XX_OUTFMT_YUV422_Y1UY0V 0x15 +#define EM28XX_OUTFMT_YUV411 0x18 + + #define EM28XX_R28_XMIN 0x28 #define EM28XX_R29_XMAX 0x29 #define EM28XX_R2A_YMIN 0x2a @@ -147,7 +160,7 @@ /* FIXME: Need to be populated with the other chip ID's */ enum em28xx_chip_id { - CHIP_ID_EM2820 = 18, + CHIP_ID_EM2820 = 18, /* Also used by em2710 */ CHIP_ID_EM2840 = 20, CHIP_ID_EM2750 = 33, CHIP_ID_EM2860 = 34, diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 9a7f57c8b..a2657fa3d 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -48,9 +48,8 @@ "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ "Sascha Sommer <saschasommer@freenet.de>" -#define DRIVER_NAME "em28xx" #define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 0) +#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 1) #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ @@ -73,19 +72,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -static LIST_HEAD(em28xx_devlist); -static DEFINE_MUTEX(em28xx_devlist_mutex); - -static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -module_param_array(card, int, NULL, 0444); module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); module_param_array(radio_nr, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); MODULE_PARM_DESC(video_nr, "video device numbers"); MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); MODULE_PARM_DESC(radio_nr, "radio device numbers"); @@ -94,16 +87,13 @@ static unsigned int video_debug; module_param(video_debug, int, 0644); MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); -/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ -static unsigned long em28xx_devused; - /* supported video standards */ static struct em28xx_fmt format[] = { { .name = "16bpp YUY2, 4:2:2, packed", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, - .reg = 0x14, + .reg = EM28XX_OUTFMT_YUV422_Y0UY1V, }, }; @@ -131,8 +121,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { } }; -static struct usb_driver em28xx_usb_driver; - /* ------------------------------------------------------------------ DMA and thread functions ------------------------------------------------------------------*/ @@ -523,58 +511,6 @@ static struct videobuf_queue_ops em28xx_video_qops = { /********************* v4l2 interface **************************************/ -/* - * em28xx_config() - * inits registers with sane defaults - */ -static int em28xx_config(struct em28xx *dev) -{ - int retval; - - /* Sets I2C speed to 100 KHz */ - if (!dev->board.is_em2800) { - retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); - if (retval < 0) { - em28xx_errdev("%s: em28xx_write_regs_req failed! retval [%d]\n", - __func__, retval); - return retval; - } - } - -#if 1 - /* enable vbi capturing */ - -/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ -/* em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */ - em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51); -#endif - - dev->mute = 1; /* maybe not the right place... */ - dev->volume = 0x1f; - - em28xx_set_outfmt(dev); - em28xx_colorlevels_set_default(dev); - em28xx_compression_disable(dev); - - return 0; -} - -/* - * em28xx_config_i2c() - * configure i2c attached devices - */ -static void em28xx_config_i2c(struct em28xx *dev) -{ - struct v4l2_routing route; - int zero = 0; - - route.input = INPUT(dev->ctl_input)->vmux; - route.output = 0; - em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero); - em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); - em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); -} - static void video_mux(struct em28xx *dev, int index) { struct v4l2_routing route; @@ -954,10 +890,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) if (0 == INPUT(i)->type) return -EINVAL; - mutex_lock(&dev->lock); - - video_mux(dev, i); + dev->ctl_input = i; + mutex_lock(&dev->lock); + video_mux(dev, dev->ctl_input); mutex_unlock(&dev->lock); return 0; } @@ -1012,6 +948,12 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) if (a->index != dev->ctl_ainput) return -EINVAL; #else + + if (a->index >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(a->index)->type) + return -EINVAL; + mutex_lock(&dev->lock); dev->ctl_ainput = INPUT(a->index)->amux; @@ -1228,7 +1170,7 @@ static int em28xx_reg_len(int reg) } static int vidioc_g_chip_ident(struct file *file, void *priv, - struct v4l2_chip_ident *chip) + struct v4l2_dbg_chip_ident *chip) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; @@ -1236,20 +1178,20 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, chip->ident = V4L2_IDENT_NONE; chip->revision = 0; - em28xx_i2c_call_clients(dev, VIDIOC_G_CHIP_IDENT, chip); + em28xx_i2c_call_clients(dev, VIDIOC_DBG_G_CHIP_IDENT, chip); return 0; } static int vidioc_g_register(struct file *file, void *priv, - struct v4l2_register *reg) + struct v4l2_dbg_register *reg) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int ret; - switch (reg->match_type) { + switch (reg->match.type) { case V4L2_CHIP_MATCH_AC97: mutex_lock(&dev->lock); ret = em28xx_read_ac97(dev, reg->reg); @@ -1258,6 +1200,7 @@ static int vidioc_g_register(struct file *file, void *priv, return ret; reg->val = ret; + reg->size = 1; return 0; case V4L2_CHIP_MATCH_I2C_DRIVER: em28xx_i2c_call_clients(dev, VIDIOC_DBG_G_REGISTER, reg); @@ -1266,12 +1209,13 @@ static int vidioc_g_register(struct file *file, void *priv, /* Not supported yet */ return -EINVAL; default: - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_host(®->match)) return -EINVAL; } /* Match host */ - if (em28xx_reg_len(reg->reg) == 1) { + reg->size = em28xx_reg_len(reg->reg); + if (reg->size == 1) { mutex_lock(&dev->lock); ret = em28xx_read_reg(dev, reg->reg); mutex_unlock(&dev->lock); @@ -1281,7 +1225,7 @@ static int vidioc_g_register(struct file *file, void *priv, reg->val = ret; } else { - __le64 val = 0; + __le16 val = 0; mutex_lock(&dev->lock); ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, reg->reg, (char *)&val, 2); @@ -1289,21 +1233,21 @@ static int vidioc_g_register(struct file *file, void *priv, if (ret < 0) return ret; - reg->val = le64_to_cpu(val); + reg->val = le16_to_cpu(val); } return 0; } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_register *reg) + struct v4l2_dbg_register *reg) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - __le64 buf; + __le16 buf; int rc; - switch (reg->match_type) { + switch (reg->match.type) { case V4L2_CHIP_MATCH_AC97: mutex_lock(&dev->lock); rc = em28xx_write_ac97(dev, reg->reg, reg->val); @@ -1317,12 +1261,12 @@ static int vidioc_s_register(struct file *file, void *priv, /* Not supported yet */ return -EINVAL; default: - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_host(®->match)) return -EINVAL; } /* Match host */ - buf = cpu_to_le64(reg->val); + buf = cpu_to_le16(reg->val); mutex_lock(&dev->lock); rc = em28xx_write_regs(dev, reg->reg, (char *)&buf, @@ -1693,31 +1637,15 @@ static int radio_queryctrl(struct file *file, void *priv, * em28xx_v4l2_open() * inits the device and starts isoc transfer */ -static int em28xx_v4l2_open(struct inode *inode, struct file *filp) +static int em28xx_v4l2_open(struct file *filp) { - int minor = iminor(inode); - int errCode = 0, radio = 0; - struct em28xx *h, *dev = NULL; + int minor = video_devdata(filp)->minor; + int errCode = 0, radio; + struct em28xx *dev; + enum v4l2_buf_type fh_type; struct em28xx_fh *fh; - enum v4l2_buf_type fh_type = 0; - mutex_lock(&em28xx_devlist_mutex); - list_for_each_entry(h, &em28xx_devlist, devlist) { - if (h->vdev->minor == minor) { - dev = h; - fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - if (h->vbi_dev->minor == minor) { - dev = h; - fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - if (h->radio_dev && - h->radio_dev->minor == minor) { - radio = 1; - dev = h; - } - } - mutex_unlock(&em28xx_devlist_mutex); + dev = em28xx_get_device(minor, &fh_type, &radio); if (NULL == dev) return -ENODEV; @@ -1760,11 +1688,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) /* Needed, since GPIO might have disabled power of some i2c device */ - em28xx_config_i2c(dev); + em28xx_wake_i2c(dev); #if 0 /* device needs to be initialized before isoc transfer */ - video_mux(dev, 0); + video_mux(dev, dev->ctl_input); #endif } if (fh->radio) { @@ -1791,18 +1719,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) * unregisters the v4l2,i2c and usb devices * called when the device gets disconected or at module unload */ -static void em28xx_release_resources(struct em28xx *dev) +void em28xx_release_analog_resources(struct em28xx *dev) { /*FIXME: I2C IR should be disconnected */ - list_del(&dev->devlist); - if (dev->sbutton_input_dev) - em28xx_deregister_snapshot_button(dev); - - if (dev->ir) - em28xx_ir_fini(dev); - if (dev->radio_dev) { if (-1 != dev->radio_dev->minor) video_unregister_device(dev->radio_dev); @@ -1828,11 +1749,6 @@ static void em28xx_release_resources(struct em28xx *dev) video_device_release(dev->vdev); dev->vdev = NULL; } - em28xx_i2c_unregister(dev); - usb_put_dev(dev->udev); - - /* Mark device as unused */ - em28xx_devused &= ~(1<<dev->devno); } /* @@ -1840,7 +1756,7 @@ static void em28xx_release_resources(struct em28xx *dev) * stops streaming and deallocates all resources allocated by the v4l2 * calls and ioctls */ -static int em28xx_v4l2_close(struct inode *inode, struct file *filp) +static int em28xx_v4l2_close(struct file *filp) { struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; @@ -1980,7 +1896,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) return rc; } -static const struct file_operations em28xx_v4l_fops = { +static const struct v4l2_file_operations em28xx_v4l_fops = { .owner = THIS_MODULE, .open = em28xx_v4l2_open, .release = em28xx_v4l2_close, @@ -1988,8 +1904,6 @@ static const struct file_operations em28xx_v4l_fops = { .poll = em28xx_v4l2_poll, .mmap = em28xx_v4l2_mmap, .ioctl = video_ioctl2, - .llseek = no_llseek, - .compat_ioctl = v4l_compat_ioctl32, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -2049,13 +1963,11 @@ static const struct video_device em28xx_video_template = { .current_norm = V4L2_STD_PAL, }; -static const struct file_operations radio_fops = { +static const struct v4l2_file_operations radio_fops = { .owner = THIS_MODULE, .open = em28xx_v4l2_open, .release = em28xx_v4l2_close, .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { @@ -2087,44 +1999,6 @@ static struct video_device em28xx_radio_template = { /******************************** usb interface ******************************/ -static LIST_HEAD(em28xx_extension_devlist); -static DEFINE_MUTEX(em28xx_extension_devlist_lock); - -int em28xx_register_extension(struct em28xx_ops *ops) -{ - struct em28xx *dev = NULL; - - mutex_lock(&em28xx_devlist_mutex); - mutex_lock(&em28xx_extension_devlist_lock); - list_add_tail(&ops->next, &em28xx_extension_devlist); - list_for_each_entry(dev, &em28xx_devlist, devlist) { - if (dev) - ops->init(dev); - } - printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); - mutex_unlock(&em28xx_extension_devlist_lock); - mutex_unlock(&em28xx_devlist_mutex); - return 0; -} -EXPORT_SYMBOL(em28xx_register_extension); - -void em28xx_unregister_extension(struct em28xx_ops *ops) -{ - struct em28xx *dev = NULL; - - mutex_lock(&em28xx_devlist_mutex); - list_for_each_entry(dev, &em28xx_devlist, devlist) { - if (dev) - ops->fini(dev); - } - - mutex_lock(&em28xx_extension_devlist_lock); - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); - list_del(&ops->next); - mutex_unlock(&em28xx_extension_devlist_lock); - mutex_unlock(&em28xx_devlist_mutex); -} -EXPORT_SYMBOL(em28xx_unregister_extension); static struct video_device *em28xx_vdev_init(struct em28xx *dev, const struct video_device *template, @@ -2147,10 +2021,44 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return vfd; } -static int register_analog_devices(struct em28xx *dev) +int em28xx_register_analog_devices(struct em28xx *dev) { int ret; + printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n", + dev->name, + (EM28XX_VERSION_CODE >> 16) & 0xff, + (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff); + + /* set default norm */ + dev->norm = em28xx_video_template.current_norm; + dev->width = norm_maxw(dev); + dev->height = norm_maxh(dev); + dev->interlaced = EM28XX_INTERLACED_DEFAULT; + dev->hscale = 0; + dev->vscale = 0; + dev->ctl_input = 0; + + /* Analog specific initialization */ + dev->format = &format[0]; + video_mux(dev, dev->ctl_input); + + /* Audio defaults */ + dev->mute = 1; + dev->volume = 0x1f; + +#if 1 + /* enable vbi capturing */ + +/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ +/* em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */ + em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51); +#endif + + em28xx_set_outfmt(dev); + em28xx_colorlevels_set_default(dev); + em28xx_compression_disable(dev); + /* allocate and fill video video_device struct */ dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); if (!dev->vdev) { @@ -2199,454 +2107,3 @@ static int register_analog_devices(struct em28xx *dev) return 0; } - - -/* - * em28xx_init_dev() - * allocates and inits the device structs, registers i2c bus and v4l device - */ -static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, - int minor) -{ - struct em28xx_ops *ops = NULL; - struct em28xx *dev = *devhandle; - int retval = -ENOMEM; - int errCode; - unsigned int maxh, maxw; - - dev->udev = udev; - mutex_init(&dev->ctrl_urb_lock); - spin_lock_init(&dev->slock); - init_waitqueue_head(&dev->open); - init_waitqueue_head(&dev->wait_frame); - init_waitqueue_head(&dev->wait_stream); - - dev->em28xx_write_regs = em28xx_write_regs; - dev->em28xx_read_reg = em28xx_read_reg; - dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; - dev->em28xx_write_regs_req = em28xx_write_regs_req; - dev->em28xx_read_reg_req = em28xx_read_reg_req; - dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800; - dev->format = &format[0]; - - em28xx_pre_card_setup(dev); - - errCode = em28xx_config(dev); - if (errCode) { - em28xx_errdev("error configuring device\n"); - return -ENOMEM; - } - - /* register i2c bus */ - errCode = em28xx_i2c_register(dev); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* Do board specific init and eeprom reading */ - em28xx_card_setup(dev); - - /* Configure audio */ - errCode = em28xx_audio_setup(dev); - if (errCode < 0) { - em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n", - __func__, errCode); - } - - /* configure the device */ - em28xx_config_i2c(dev); - - /* set default norm */ - dev->norm = em28xx_video_template.current_norm; - - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); - - /* set default image size */ - dev->width = maxw; - dev->height = maxh; - dev->interlaced = EM28XX_INTERLACED_DEFAULT; - dev->hscale = 0; - dev->vscale = 0; - dev->ctl_input = 2; - - errCode = em28xx_config(dev); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_config - errCode [%d]!\n", - __func__, errCode); - return errCode; - } - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - -#if 0 - video_set_drvdata(dev->vbi_dev, dev); -#endif - - if (dev->board.has_msp34xx) { - /* Send a reset to other chips via gpio */ - errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(1) failed! errCode [%d]\n", - __func__, errCode); - return errCode; - } - msleep(3); - - errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); - if (errCode < 0) { - em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(2) failed! errCode [%d]\n", - __func__, errCode); - return errCode; - } - msleep(3); - } - - video_mux(dev, 0); - - mutex_lock(&em28xx_devlist_mutex); - list_add_tail(&dev->devlist, &em28xx_devlist); - retval = register_analog_devices(dev); - if (retval < 0) { - em28xx_release_resources(dev); - mutex_unlock(&em28xx_devlist_mutex); - goto fail_reg_devices; - } - - mutex_lock(&em28xx_extension_devlist_lock); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->id) - ops->init(dev); - } - } - mutex_unlock(&em28xx_extension_devlist_lock); - mutex_unlock(&em28xx_devlist_mutex); - - /* Save some power by putting tuner to sleep */ - em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); - - return 0; - -fail_reg_devices: - return retval; -} - -#if defined(CONFIG_MODULES) && defined(MODULE) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -static void request_module_async(void *ptr) -{ - struct em28xx *dev = (struct em28xx *)ptr; -#else -static void request_module_async(struct work_struct *work) -{ - struct em28xx *dev = container_of(work, - struct em28xx, request_module_wk); -#endif - - 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"); -} - -static void request_modules(struct em28xx *dev) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) - INIT_WORK(&dev->request_module_wk, request_module_async, - (void *)dev); -#else - INIT_WORK(&dev->request_module_wk, request_module_async); -#endif - schedule_work(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#endif /* CONFIG_MODULES */ - -/* - * em28xx_usb_probe() - * checks for supported devices - */ -static int em28xx_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - const struct usb_endpoint_descriptor *endpoint; - struct usb_device *udev; - struct usb_interface *uif; - struct em28xx *dev = NULL; - int retval = -ENODEV; - int i, nr, ifnum, isoc_pipe; - char *speed; - char descr[255] = ""; - - udev = usb_get_dev(interface_to_usbdev(interface)); - ifnum = interface->altsetting[0].desc.bInterfaceNumber; - - /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); - em28xx_devused |= 1<<nr; - - /* Don't register audio interfaces */ - if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - em28xx_err(DRIVER_NAME " audio device (%04x:%04x): " - "interface %i, class %i\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - - em28xx_devused &= ~(1<<nr); - return -ENODEV; - } - - endpoint = &interface->cur_altsetting->endpoint[0].desc; - - /* check if the device has the iso in endpoint at the correct place */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC && - (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) - { - /* It's a newer em2874/em2875 device */ - isoc_pipe = 0; - } else { - int check_interface = 1; - isoc_pipe = 1; - endpoint = &interface->cur_altsetting->endpoint[1].desc; - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_ISOC) - check_interface = 0; - - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) - check_interface = 0; - - if (!check_interface) { - em28xx_err(DRIVER_NAME " video device (%04x:%04x): " - "interface %i, class %i found.\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - - em28xx_err(DRIVER_NAME " This is an anciliary " - "interface not used by the driver\n"); - - em28xx_devused &= ~(1<<nr); - return -ENODEV; - } - } - - switch (udev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - default: - speed = "unknown"; - } - - if (udev->manufacturer) - strlcpy(descr, udev->manufacturer, sizeof(descr)); - - if (udev->product) { - if (*descr) - strlcat(descr, " ", sizeof(descr)); - strlcat(descr, udev->product, sizeof(descr)); - } - if (*descr) - strlcat(descr, " ", sizeof(descr)); - - printk(DRIVER_NAME ": New device %s@ %s Mbps " - "(%04x:%04x, interface %d, class %d)\n", - descr, - speed, - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting->desc.bInterfaceNumber); - - if (nr >= EM28XX_MAXBOARDS) { - printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", - EM28XX_MAXBOARDS); - em28xx_devused &= ~(1<<nr); - return -ENOMEM; - } - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - em28xx_err(DRIVER_NAME ": out of memory!\n"); - em28xx_devused &= ~(1<<nr); - return -ENOMEM; - } - - snprintf(dev->name, 29, "em28xx #%d", nr); - dev->devno = nr; - dev->model = id->driver_info; - dev->alt = -1; - - /* Checks if audio is provided by some interface */ - for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { - uif = udev->config->interface[i]; - if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - dev->has_audio_class = 1; - break; - } - } - - /* compute alternate max packet sizes */ - uif = udev->actconfig->interface[0]; - - dev->num_alt = uif->num_altsetting; - em28xx_videodbg("Alternate settings: %i\n", dev->num_alt); -/* dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */ - dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); - - if (dev->alt_max_pkt_size == NULL) { - em28xx_errdev("out of memory!\n"); - em28xx_devused &= ~(1<<nr); - kfree(dev); - return -ENOMEM; - } - - for (i = 0; i < dev->num_alt ; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc. - wMaxPacketSize); - dev->alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - em28xx_videodbg("Alternate setting %i, max size= %i\n", i, - dev->alt_max_pkt_size[i]); - } - - if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) - dev->model = card[nr]; - - /* allocate device struct */ - mutex_init(&dev->lock); - mutex_lock(&dev->lock); - retval = em28xx_init_dev(&dev, udev, nr); - if (retval) { - em28xx_devused &= ~(1<<dev->devno); - kfree(dev); - - return retval; - } - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - 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; -} - -/* - * em28xx_usb_disconnect() - * called when the device gets diconencted - * video device will be unregistered on v4l2_close in case it is still open - */ -static void em28xx_usb_disconnect(struct usb_interface *interface) -{ - struct em28xx *dev; - struct em28xx_ops *ops = NULL; - - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - if (!dev) - return; - - em28xx_info("disconnecting %s\n", dev->vdev->name); - - /* wait until all current v4l2 io is finished then deallocate - resources */ - mutex_lock(&dev->lock); - - wake_up_interruptible_all(&dev->open); - - if (dev->users) { - em28xx_warn - ("device /dev/video%d is open! Deregistration and memory " - "deallocation are deferred on close.\n", - dev->vdev->num); - - dev->state |= DEV_MISCONFIGURED; - em28xx_uninit_isoc(dev); - dev->state |= DEV_DISCONNECTED; - wake_up_interruptible(&dev->wait_frame); - wake_up_interruptible(&dev->wait_stream); - } else { - dev->state |= DEV_DISCONNECTED; - em28xx_release_resources(dev); - } - mutex_unlock(&dev->lock); - - mutex_lock(&em28xx_extension_devlist_lock); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - ops->fini(dev); - } - } - mutex_unlock(&em28xx_extension_devlist_lock); - - if (!dev->users) { - kfree(dev->alt_max_pkt_size); - kfree(dev); - } -} - -static struct usb_driver em28xx_usb_driver = { - .name = "em28xx", - .probe = em28xx_usb_probe, - .disconnect = em28xx_usb_disconnect, - .id_table = em28xx_id_table, -}; - -static int __init em28xx_module_init(void) -{ - int result; - - printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n", - (EM28XX_VERSION_CODE >> 16) & 0xff, - (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n", - SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100); -#endif - - /* register this driver with the USB subsystem */ - result = usb_register(&em28xx_usb_driver); - if (result) - em28xx_err(DRIVER_NAME - " usb_register failed. Error number %d.\n", result); - - return result; -} - -static void __exit em28xx_module_exit(void) -{ - /* deregister this driver with the USB subsystem */ - usb_deregister(&em28xx_usb_driver); -} - -module_init(em28xx_module_init); -module_exit(em28xx_module_exit); - diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 84f49934a..06fe92efc 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -68,7 +68,6 @@ #define EM2820_BOARD_HERCULES_SMART_TV_USB2 26 #define EM2820_BOARD_PINNACLE_USB_2_FM1216ME 27 #define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28 -#define EM2820_BOARD_PINNACLE_DVC_100 29 #define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30 #define EM2821_BOARD_USBGEAR_VD204 31 #define EM2821_BOARD_SUPERCOMP_USB_2 32 @@ -98,8 +97,8 @@ #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 #define EM2883_BOARD_KWORLD_HYBRID_A316 57 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 -#define EM2874_BOARD_PINNACLE_PCTV_80E 59 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 +#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -483,7 +482,7 @@ struct em28xx { unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ - struct em28xx_audio *adev; + struct em28xx_audio adev; /* states */ enum em28xx_dev_state state; @@ -594,10 +593,20 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, void em28xx_uninit_isoc(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); - -/* Provided by em28xx-video.c */ +void em28xx_wake_i2c(struct em28xx *dev); +void em28xx_remove_from_devlist(struct em28xx *dev); +void em28xx_add_into_devlist(struct em28xx *dev); +struct em28xx *em28xx_get_device(int minor, + enum v4l2_buf_type *fh_type, + int *has_radio); 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_register_analog_devices(struct em28xx *dev); +void em28xx_release_analog_resources(struct em28xx *dev); /* Provided by em28xx-cards.c */ extern int em2800_variant_detect(struct usb_device *udev, int model); @@ -608,6 +617,7 @@ extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); int em28xx_tuner_callback(void *ptr, int component, int command, int arg); +void em28xx_release_resources(struct em28xx *dev); /* Provided by em28xx-input.c */ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); |