This driver adds support for stk1160 usb bridge as used in some video/audio usb capture devices. It is a complete rewrite of staging/media/easycap driver and it's expected as a replacement.
Cc: Mauro Carvalho Chehab mchehab@redhat.com Cc: Takashi Iwai tiwai@suse.de Cc: Hans Verkuil hverkuil@xs4all.nl Cc: Sylwester Nawrocki sylvester.nawrocki@gmail.com Signed-off-by: Ezequiel Garcia elezegarcia@gmail.com --- Here we are once again,
As stk1160 allows communication with an ac97 codec chip, this driver registers a control-only sound card to allow the user to access ac97 controls.
This is achieved through snd_ac97_codec/ac97_bus drivers. Mauro suggested that this ac97 handling should be put inside -alsa tree, but I'm still not sure about it. This approach is working well in practice, but I'm not 100% confident so feedback is welcome (in particular from you alsa guys).
Testing has been performed using both vlc and mplayer on a gentoo machine, including hot unplug and on-the-fly standard change. I also got reports about the driver working fine on ARM platforms.
Two devices have been used for testing: * 1-cvbs video and 1-audio ac97 input, * 4-cvbs inputs Both of these devices reports with the same id [05e1:0408], so the driver tries to support a superset of the capabilities.
By using keep_buffers module parameter it's possible to prevent the driver from releasing urb buffers when streaming is stopped. The usage of this parameter can avoid memory fragmentation that may cause the driver to stop working on low memory systems. A similar mechanism is implemented in em28xx driver (see commit 86d38d).
This v5 patch removes easycap driver, takes advantage of latest videobuf2 improvements and addresses some minor comments from Mauro.
I consider the driver to be pretty usable, but of course: bugs happen. As usual, any comments/reviews of *any* kind will be greatly appreciated.
Ah, last but not least, if you're a user and you're reading this: Don't use this patch! Instead, search for <stk1160-standalone> on github :-)
Thanks to Hans, Sylwester, Mauro and everyone else for their indispensable help.
Changes from v4: * Remove old easycap staging driver * Incorporated review comments by Mauro (Thanks!) * Remove (pedantic) BUG usage * Remove unused frame_* ioctls * Use new vb2 helpers for ioctls and fops * Select saa711x unconditionally in Kconfig * Replace usb high speed requirement with a mere warning
Changes from v3: * Incorporated all review comments by Sylwester (Thanks!) * Added keep_buffers module parameter. This parameter keeps the driver from releasing urb buffers when streaming is stopped.
Changes from v2: * Added support for multiple video input device * Added ac97 initialization * Register an ac97 sound card (mixer control only) to access ac97 registers.
Changes from v1: * Use media control framework * Register video device as the last thing * Use v4l_device release to release all resources * Add explicit locking for file operations * Add vb2 buffer sanity check * Minor style cleanups --- drivers/media/video/Kconfig | 2 + drivers/media/video/Makefile | 1 + drivers/media/video/stk1160/Kconfig | 12 + drivers/media/video/stk1160/Makefile | 6 + drivers/media/video/stk1160/stk1160-ac97.c | 153 + drivers/media/video/stk1160/stk1160-core.c | 431 +++ drivers/media/video/stk1160/stk1160-i2c.c | 294 ++ drivers/media/video/stk1160/stk1160-reg.h | 93 + drivers/media/video/stk1160/stk1160-v4l.c | 727 ++++ drivers/media/video/stk1160/stk1160-video.c | 518 +++ drivers/media/video/stk1160/stk1160.h | 202 + drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/easycap/Kconfig | 30 - drivers/staging/media/easycap/Makefile | 10 - drivers/staging/media/easycap/README | 141 - drivers/staging/media/easycap/easycap.h | 567 --- drivers/staging/media/easycap/easycap_ioctl.c | 2442 ------------- drivers/staging/media/easycap/easycap_low.c | 968 ----- drivers/staging/media/easycap/easycap_main.c | 4235 ---------------------- drivers/staging/media/easycap/easycap_settings.c | 696 ---- drivers/staging/media/easycap/easycap_sound.c | 750 ---- drivers/staging/media/easycap/easycap_testcard.c | 155 - 23 files changed, 2439 insertions(+), 9997 deletions(-) create mode 100644 drivers/media/video/stk1160/Kconfig create mode 100644 drivers/media/video/stk1160/Makefile create mode 100644 drivers/media/video/stk1160/stk1160-ac97.c create mode 100644 drivers/media/video/stk1160/stk1160-core.c create mode 100644 drivers/media/video/stk1160/stk1160-i2c.c create mode 100644 drivers/media/video/stk1160/stk1160-reg.h create mode 100644 drivers/media/video/stk1160/stk1160-v4l.c create mode 100644 drivers/media/video/stk1160/stk1160-video.c create mode 100644 drivers/media/video/stk1160/stk1160.h delete mode 100644 drivers/staging/media/easycap/Kconfig delete mode 100644 drivers/staging/media/easycap/Makefile delete mode 100644 drivers/staging/media/easycap/README delete mode 100644 drivers/staging/media/easycap/easycap.h delete mode 100644 drivers/staging/media/easycap/easycap_ioctl.c delete mode 100644 drivers/staging/media/easycap/easycap_low.c delete mode 100644 drivers/staging/media/easycap/easycap_main.c delete mode 100644 drivers/staging/media/easycap/easycap_settings.c delete mode 100644 drivers/staging/media/easycap/easycap_sound.c delete mode 100644 drivers/staging/media/easycap/easycap_testcard.c
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c128fac..0d2447b 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -748,6 +748,8 @@ source "drivers/media/video/tm6000/Kconfig"
source "drivers/media/video/usbvision/Kconfig"
+source "drivers/media/video/stk1160/Kconfig" + endif # V4L_USB_DRIVERS
# diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index b7da9fa..86ab4b6 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -126,6 +126,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_STA2X11_VIP) += sta2x11_vip.o obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o +obj-$(CONFIG_VIDEO_STK1160) += stk1160/
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o diff --git a/drivers/media/video/stk1160/Kconfig b/drivers/media/video/stk1160/Kconfig new file mode 100644 index 0000000..5b54728 --- /dev/null +++ b/drivers/media/video/stk1160/Kconfig @@ -0,0 +1,12 @@ +config VIDEO_STK1160 + tristate "STK1160 USB video capture support" + depends on VIDEO_DEV && I2C + select VIDEOBUF2_VMALLOC + select VIDEO_SAA711X + select SND_AC97_CODEC + + ---help--- + This is a video4linux driver for STK1160 based video capture devices + + To compile this driver as a module, choose M here: the + module will be called stk1160 diff --git a/drivers/media/video/stk1160/Makefile b/drivers/media/video/stk1160/Makefile new file mode 100644 index 0000000..5d8f1ba --- /dev/null +++ b/drivers/media/video/stk1160/Makefile @@ -0,0 +1,6 @@ +stk1160-y := stk1160-core.o stk1160-v4l.o stk1160-video.o stk1160-i2c.o stk1160-ac97.o + +obj-$(CONFIG_VIDEO_STK1160) += stk1160.o + +ccflags-y += -Wall +ccflags-y += -Idrivers/media/video diff --git a/drivers/media/video/stk1160/stk1160-ac97.c b/drivers/media/video/stk1160/stk1160-ac97.c new file mode 100644 index 0000000..8d325f5 --- /dev/null +++ b/drivers/media/video/stk1160/stk1160-ac97.c @@ -0,0 +1,153 @@ +/* + * STK1160 driver + * + * Copyright (C) 2012 Ezequiel Garcia + * <elezegarcia--a.t--gmail.com> + * + * Based on Easycap driver by R.M. Thomas + * Copyright (C) 2010 R.M. Thomas + * <rmthomas--a.t--sciolus.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 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. + * + */ + +#include <linux/module.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/ac97_codec.h> + +#include "stk1160.h" +#include "stk1160-reg.h" + +static struct snd_ac97 *stk1160_ac97; + +static void stk1160_write_ac97(struct snd_ac97 *ac97, u16 reg, u16 value) +{ + struct stk1160 *dev = ac97->private_data; + + /* Set codec register address */ + stk1160_write_reg(dev, STK1160_AC97_ADDR, reg); + + /* Set codec command */ + stk1160_write_reg(dev, STK1160_AC97_CMD, value & 0xff); + stk1160_write_reg(dev, STK1160_AC97_CMD + 1, (value & 0xff00) >> 8); + + /* + * Set command write bit to initiate write operation. + * The bit will be cleared when transfer is done. + */ + stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c); +} + +static u16 stk1160_read_ac97(struct snd_ac97 *ac97, u16 reg) +{ + struct stk1160 *dev = ac97->private_data; + u8 vall = 0; + u8 valh = 0; + + /* Set codec register address */ + stk1160_write_reg(dev, STK1160_AC97_ADDR, reg); + + /* + * Set command read bit to initiate read operation. + * The bit will be cleared when transfer is done. + */ + stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8b); + + /* Retrieve register value */ + stk1160_read_reg(dev, STK1160_AC97_CMD, &vall); + stk1160_read_reg(dev, STK1160_AC97_CMD + 1, &valh); + + return (valh << 8) | vall; +} + +static void stk1160_reset_ac97(struct snd_ac97 *ac97) +{ + struct stk1160 *dev = ac97->private_data; + /* Two-step reset AC97 interface and hardware codec */ + stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x94); + stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x88); + + /* Set 16-bit audio data and choose L&R channel*/ + stk1160_write_reg(dev, STK1160_AC97CTL_1 + 2, 0x01); +} + +static struct snd_ac97_bus_ops stk1160_ac97_ops = { + .read = stk1160_read_ac97, + .write = stk1160_write_ac97, + .reset = stk1160_reset_ac97, +}; + +int stk1160_ac97_register(struct stk1160 *dev) +{ + struct snd_card *card = NULL; + struct snd_ac97_bus *ac97_bus; + struct snd_ac97_template ac97_template; + int rc; + + /* + * 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); + 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)); + + rc = snd_ac97_bus(card, 0, &stk1160_ac97_ops, NULL, &ac97_bus); + if (rc) + goto err; + + /* We must set private_data before calling snd_ac97_mixer */ + memset(&ac97_template, 0, sizeof(ac97_template)); + ac97_template.private_data = dev; + ac97_template.scaps = AC97_SCAP_SKIP_MODEM; + rc = snd_ac97_mixer(ac97_bus, &ac97_template, &stk1160_ac97); + if (rc) + goto err; + + dev->snd_card = card; + rc = snd_card_register(card); + if (rc) + goto err; + + return 0; + +err: + dev->snd_card = NULL; + if (card) + snd_card_free(card); + return rc; +} + +int stk1160_ac97_unregister(struct stk1160 *dev) +{ + struct snd_card *card = dev->snd_card; + + /* + * We need to check usb_device, + * because ac97 release attempts to communicate with codec + */ + if (card && dev->udev) + snd_card_free(card); + + return 0; +} diff --git a/drivers/media/video/stk1160/stk1160-core.c b/drivers/media/video/stk1160/stk1160-core.c new file mode 100644 index 0000000..e902e25 --- /dev/null +++ b/drivers/media/video/stk1160/stk1160-core.c @@ -0,0 +1,431 @@ +/* + * STK1160 driver + * + * Copyright (C) 2012 Ezequiel Garcia + * <elezegarcia--a.t--gmail.com> + * + * Based on Easycap driver by R.M. Thomas + * Copyright (C) 2010 R.M. Thomas + * <rmthomas--a.t--sciolus.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 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. + * + * TODO: + * + * 1. (Try to) detect if we must register ac97 mixer + * 2. Support stream at lower speed: lower frame rate or lower frame size. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> + +#include <linux/usb.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <media/saa7115.h> + +#include "stk1160.h" +#include "stk1160-reg.h" + +static unsigned int input; +module_param(input, int, 0644); +MODULE_PARM_DESC(input, "Set default input"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ezequiel Garcia"); +MODULE_DESCRIPTION("STK1160 driver"); + +/* Devices supported by this driver */ +static struct usb_device_id stk1160_id_table[] = { + { USB_DEVICE(0x05e1, 0x0408) }, + { } +}; +MODULE_DEVICE_TABLE(usb, stk1160_id_table); + +/* saa7113 I2C address */ +static unsigned short saa7113_addrs[] = { + 0x4a >> 1, + I2C_CLIENT_END +}; + +/* + * Read/Write stk registers + */ +int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value) +{ + int ret; + int pipe = usb_rcvctrlpipe(dev->udev, 0); + + *value = 0; + ret = usb_control_msg(dev->udev, pipe, 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, reg, value, sizeof(u8), HZ); + if (ret < 0) { + stk1160_err("read failed on reg 0x%x (%d)\n", + reg, ret); + return ret; + } + + return 0; +} + +int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value) +{ + int ret; + int pipe = usb_sndctrlpipe(dev->udev, 0); + + ret = usb_control_msg(dev->udev, pipe, 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, reg, NULL, 0, HZ); + if (ret < 0) { + stk1160_err("write failed on reg 0x%x (%d)\n", + reg, ret); + return ret; + } + + return 0; +} + +void stk1160_select_input(struct stk1160 *dev) +{ + static const u8 gctrl[] = { + 0x98, 0x90, 0x88, 0x80 + }; + + if (dev->ctl_input < ARRAY_SIZE(gctrl)) + stk1160_write_reg(dev, STK1160_GCTRL, gctrl[dev->ctl_input]); +} + +/* TODO: We should break this into pieces */ +static void stk1160_reg_reset(struct stk1160 *dev) +{ + int i; + + static const struct regval ctl[] = { + {STK1160_GCTRL+2, 0x0078}, + + {STK1160_RMCTL+1, 0x0000}, + {STK1160_RMCTL+3, 0x0002}, + + {STK1160_PLLSO, 0x0010}, + {STK1160_PLLSO+1, 0x0000}, + {STK1160_PLLSO+2, 0x0014}, + {STK1160_PLLSO+3, 0x000E}, + + {STK1160_PLLFD, 0x0046}, + + /* Timing generator setup */ + {STK1160_TIGEN, 0x0012}, + {STK1160_TICTL, 0x002D}, + {STK1160_TICTL+1, 0x0001}, + {STK1160_TICTL+2, 0x0000}, + {STK1160_TICTL+3, 0x0000}, + {STK1160_TIGEN, 0x0080}, + + {0xffff, 0xffff} + }; + + for (i = 0; ctl[i].reg != 0xffff; i++) + stk1160_write_reg(dev, ctl[i].reg, ctl[i].val); +} + +static void stk1160_release(struct v4l2_device *v4l2_dev) +{ + struct stk1160 *dev = container_of(v4l2_dev, struct stk1160, v4l2_dev); + + stk1160_info("releasing all resources\n"); + + stk1160_i2c_unregister(dev); + + v4l2_ctrl_handler_free(&dev->ctrl_handler); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev->alt_max_pkt_size); + kfree(dev); +} + +/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ +#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) + +/* + * Scan usb interface and populate max_pkt_size array + * with information on each alternate setting. + * The array should be allocated by the caller. + */ +static int stk1160_scan_usb(struct usb_interface *intf, struct usb_device *udev, + unsigned int *max_pkt_size) +{ + int i, e, sizedescr, size, ifnum; + const struct usb_endpoint_descriptor *desc; + + bool has_video = false, has_audio = false; + const char *speed; + + ifnum = intf->altsetting[0].desc.bInterfaceNumber; + + /* Get endpoints */ + for (i = 0; i < intf->num_altsetting; i++) { + + for (e = 0; e < intf->altsetting[i].desc.bNumEndpoints; e++) { + + /* This isn't clear enough, at least to me */ + desc = &intf->altsetting[i].endpoint[e].desc; + sizedescr = le16_to_cpu(desc->wMaxPacketSize); + size = sizedescr & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(sizedescr); + + if (usb_endpoint_xfer_isoc(desc) && + usb_endpoint_dir_in(desc)) { + switch (desc->bEndpointAddress) { + case STK1160_EP_AUDIO: + has_audio = true; + break; + case STK1160_EP_VIDEO: + has_video = true; + max_pkt_size[i] = size; + break; + } + } + } + } + + /* Is this even possible? */ + if (!(has_audio || has_video)) { + dev_err(&udev->dev, "no audio or video endpoints found\n"); + return -ENODEV; + } + + switch (udev->speed) { + case USB_SPEED_LOW: + speed = "1.5"; + break; + case USB_SPEED_FULL: + speed = "12"; + break; + case USB_SPEED_HIGH: + speed = "480"; + break; + default: + speed = "unknown"; + } + + dev_info(&udev->dev, "New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", + udev->manufacturer ? udev->manufacturer : "", + udev->product ? udev->product : "", + speed, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + intf->altsetting->desc.bInterfaceNumber); + + /* This should never happen, since we rejected audio interfaces */ + if (has_audio) + dev_warn(&udev->dev, "audio interface %d found.\n\ + This is not implemented by this driver,\ + you should use snd-usb-audio instead\n", ifnum); + + if (has_video) + dev_info(&udev->dev, "video interface %d found\n", + ifnum); + + /* + * Make sure we have 480 Mbps of bandwidth, otherwise things like + * video stream wouldn't likely work, since 12 Mbps is generally + * not enough even for most streams. + */ + if (udev->speed != USB_SPEED_HIGH) + dev_warn(&udev->dev, "must be connected to a high-speed USB 2.0 port\n\ + You may not be able to stream video smoothly\n"); + + return 0; +} + +static int stk1160_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + int ifnum; + int rc = 0; + + unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ + struct usb_device *udev; + struct stk1160 *dev; + + ifnum = interface->altsetting[0].desc.bInterfaceNumber; + udev = interface_to_usbdev(interface); + + /* + * Since usb audio class is supported by snd-usb-audio, + * we reject audio interface. + */ + if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) + return -ENODEV; + + /* Alloc an array for all possible max_pkt_size */ + alt_max_pkt_size = kmalloc(sizeof(alt_max_pkt_size[0]) * + interface->num_altsetting, GFP_KERNEL); + if (alt_max_pkt_size == NULL) + return -ENOMEM; + + /* + * Scan usb posibilities and populate alt_max_pkt_size array. + * Also, check if device speed is fast enough. + */ + rc = stk1160_scan_usb(interface, udev, alt_max_pkt_size); + if (rc < 0) { + kfree(alt_max_pkt_size); + return rc; + } + + dev = kzalloc(sizeof(struct stk1160), GFP_KERNEL); + if (dev == NULL) { + kfree(alt_max_pkt_size); + return -ENOMEM; + } + + dev->alt_max_pkt_size = alt_max_pkt_size; + dev->udev = udev; + dev->num_alt = interface->num_altsetting; + dev->ctl_input = input; + + /* We save struct device for debug purposes only */ + dev->dev = &interface->dev; + + usb_set_intfdata(interface, dev); + + /* initialize videobuf2 stuff */ + rc = stk1160_vb2_setup(dev); + if (rc < 0) + goto free_err; + + /* + * There is no need to take any locks here in probe + * because we register the device node as the *last* thing. + */ + spin_lock_init(&dev->buf_lock); + mutex_init(&dev->v4l_lock); + + rc = v4l2_ctrl_handler_init(&dev->ctrl_handler, 0); + if (rc) { + stk1160_err("v4l2_ctrl_handler_init failed (%d)\n", rc); + goto free_err; + } + + /* + * We obtain a v4l2_dev but defer + * registration of video device node as the last thing. + * There is no need to set the name if we give a device struct + */ + dev->v4l2_dev.release = stk1160_release; + dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler; + rc = v4l2_device_register(dev->dev, &dev->v4l2_dev); + if (rc) { + stk1160_err("v4l2_device_register failed (%d)\n", rc); + goto free_ctrl; + } + + rc = stk1160_i2c_register(dev); + if (rc < 0) + goto unreg_v4l2; + + /* + * To the best of my knowledge stk1160 boards only have + * saa7113, but it doesn't hurt to support them all. + */ + dev->sd_saa7115 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + "saa7115_auto", 0, saa7113_addrs); + + stk1160_info("driver ver %s successfully loaded\n", + STK1160_VERSION); + + /* i2c reset saa711x */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, + 0, 0, 0); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); + + /* reset stk1160 to default values */ + stk1160_reg_reset(dev); + + /* select default input */ + stk1160_select_input(dev); + + stk1160_ac97_register(dev); + + rc = stk1160_video_register(dev); + if (rc < 0) + goto unreg_i2c; + + return 0; + +unreg_i2c: + stk1160_i2c_unregister(dev); +unreg_v4l2: + v4l2_device_unregister(&dev->v4l2_dev); +free_ctrl: + v4l2_ctrl_handler_free(&dev->ctrl_handler); +free_err: + kfree(alt_max_pkt_size); + kfree(dev); + + return rc; +} + +/* + * TODO: What happens if device gets diconnected while probing? + */ +static void stk1160_disconnect(struct usb_interface *interface) +{ + struct stk1160 *dev; + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + /* + * Wait until all current v4l2 operation are finished + * then deallocate resources + */ + mutex_lock(&dev->v4l_lock); + + /* Here is the only place where isoc get released */ + stk1160_uninit_isoc(dev); + + /* ac97 unregister needs to be done before usb_device is cleared */ + stk1160_ac97_unregister(dev); + + stk1160_stop_streaming(dev, false); + video_unregister_device(&dev->vdev); + v4l2_device_disconnect(&dev->v4l2_dev); + + /* This way current users can detect device is gone */ + dev->udev = NULL; + + mutex_unlock(&dev->v4l_lock); + + /* + * This calls stk1160_release if it's the last reference. + * therwise, release is posponed until there are no users left. + */ + v4l2_device_put(&dev->v4l2_dev); +} + +static struct usb_driver stk1160_usb_driver = { + .name = "stk1160", + .id_table = stk1160_id_table, + .probe = stk1160_probe, + .disconnect = stk1160_disconnect, +}; + +module_usb_driver(stk1160_usb_driver); diff --git a/drivers/media/video/stk1160/stk1160-i2c.c b/drivers/media/video/stk1160/stk1160-i2c.c new file mode 100644 index 0000000..176ac93 --- /dev/null +++ b/drivers/media/video/stk1160/stk1160-i2c.c @@ -0,0 +1,294 @@ +/* + * STK1160 driver + * + * Copyright (C) 2012 Ezequiel Garcia + * <elezegarcia--a.t--gmail.com> + * + * Based on Easycap driver by R.M. Thomas + * Copyright (C) 2010 R.M. Thomas + * <rmthomas--a.t--sciolus.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 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. + * + */ + +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/i2c.h> + +#include "stk1160.h" +#include "stk1160-reg.h" + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +#define dprintk_i2c(fmt, args...) \ +do { \ + if (i2c_debug) \ + printk(KERN_DEBUG fmt, ##args); \ +} while (0) + +static int stk1160_i2c_busy_wait(struct stk1160 *dev, u8 wait_bit_mask) +{ + unsigned long end; + u8 flag; + + /* Wait until read/write finish bit is set */ + end = jiffies + msecs_to_jiffies(STK1160_I2C_TIMEOUT); + while (time_is_after_jiffies(end)) { + + stk1160_read_reg(dev, STK1160_SICTL+1, &flag); + /* read/write done? */ + if (flag & wait_bit_mask) + goto done; + + usleep_range(10 * USEC_PER_MSEC, 20 * USEC_PER_MSEC); + } + + return -ETIMEDOUT; + +done: + return 0; +} + +static int stk1160_i2c_write_reg(struct stk1160 *dev, u8 addr, + u8 reg, u8 value) +{ + int rc; + + /* Set serial device address */ + rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); + if (rc < 0) + return rc; + + /* Set i2c device register sub-address */ + rc = stk1160_write_reg(dev, STK1160_SBUSW_WA, reg); + if (rc < 0) + return rc; + + /* Set i2c device register value */ + rc = stk1160_write_reg(dev, STK1160_SBUSW_WD, value); + if (rc < 0) + return rc; + + /* Start write now */ + rc = stk1160_write_reg(dev, STK1160_SICTL, 0x01); + if (rc < 0) + return rc; + + rc = stk1160_i2c_busy_wait(dev, 0x04); + if (rc < 0) + return rc; + + return 0; +} + +static int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr, + u8 reg, u8 *value) +{ + int rc; + + /* Set serial device address */ + rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); + if (rc < 0) + return rc; + + /* Set i2c device register sub-address */ + rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, reg); + if (rc < 0) + return rc; + + /* Start read now */ + rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20); + if (rc < 0) + return rc; + + rc = stk1160_i2c_busy_wait(dev, 0x01); + if (rc < 0) + return rc; + + stk1160_read_reg(dev, STK1160_SBUSR_RD, value); + if (rc < 0) + return rc; + + return 0; +} + +/* + * stk1160_i2c_check_for_device() + * check if there is a i2c_device at the supplied address + */ +static int stk1160_i2c_check_for_device(struct stk1160 *dev, + unsigned char addr) +{ + int rc; + + /* Set serial device address */ + rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); + if (rc < 0) + return rc; + + /* Set device sub-address, we'll chip version reg */ + rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, 0x00); + if (rc < 0) + return rc; + + /* Start read now */ + rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20); + if (rc < 0) + return rc; + + rc = stk1160_i2c_busy_wait(dev, 0x01); + if (rc < 0) + return -ENODEV; + + return 0; +} + +/* + * stk1160_i2c_xfer() + * the main i2c transfer function + */ +static int stk1160_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct stk1160 *dev = i2c_adap->algo_data; + int addr, rc, i; + + for (i = 0; i < num; i++) { + addr = msgs[i].addr << 1; + dprintk_i2c("%s: addr=%x", __func__, addr); + + if (!msgs[i].len) { + /* no len: check only for device presence */ + rc = stk1160_i2c_check_for_device(dev, addr); + if (rc < 0) { + dprintk_i2c(" no device\n"); + return rc; + } + + } else if (msgs[i].flags & I2C_M_RD) { + /* read request without preceding register selection */ + dprintk_i2c(" subaddr not selected"); + rc = -EOPNOTSUPP; + goto err; + + } else if (i + 1 < num && msgs[i].len <= 2 && + (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr) { + + if (msgs[i].len != 1 || msgs[i + 1].len != 1) { + dprintk_i2c(" len not supported"); + rc = -EOPNOTSUPP; + goto err; + } + + dprintk_i2c(" subaddr=%x", msgs[i].buf[0]); + + rc = stk1160_i2c_read_reg(dev, addr, msgs[i].buf[0], + msgs[i + 1].buf); + + dprintk_i2c(" read=%x", *msgs[i + 1].buf); + + /* consumed two msgs, so we skip one of them */ + i++; + + } else { + if (msgs[i].len != 2) { + dprintk_i2c(" len not supported"); + rc = -EOPNOTSUPP; + goto err; + } + + dprintk_i2c(" subaddr=%x write=%x", + msgs[i].buf[0], msgs[i].buf[1]); + + rc = stk1160_i2c_write_reg(dev, addr, msgs[i].buf[0], + msgs[i].buf[1]); + } + + if (rc < 0) + goto err; + dprintk_i2c(" OK\n"); + } + + return num; +err: + dprintk_i2c(" ERROR: %d\n", rc); + return num; +} + +/* + * functionality(), what da heck is this? + */ +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm algo = { + .master_xfer = stk1160_i2c_xfer, + .functionality = functionality, +}; + +static struct i2c_adapter adap_template = { + .owner = THIS_MODULE, + .name = "stk1160", + .algo = &algo, +}; + +static struct i2c_client client_template = { + .name = "stk1160 internal", +}; + +/* + * stk1160_i2c_register() + * register i2c bus + */ +int stk1160_i2c_register(struct stk1160 *dev) +{ + int rc; + + dev->i2c_adap = adap_template; + dev->i2c_adap.dev.parent = dev->dev; + strcpy(dev->i2c_adap.name, "stk1160"); + dev->i2c_adap.algo_data = dev; + + i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); + + rc = i2c_add_adapter(&dev->i2c_adap); + if (rc < 0) { + stk1160_err("cannot add i2c adapter (%d)\n", rc); + return rc; + } + + dev->i2c_client = client_template; + dev->i2c_client.adapter = &dev->i2c_adap; + + /* Set i2c clock divider device address */ + stk1160_write_reg(dev, STK1160_SICTL_CD, 0x0f); + + /* ??? */ + stk1160_write_reg(dev, STK1160_ASIC + 3, 0x00); + + return 0; +} + +/* + * stk1160_i2c_unregister() + * unregister i2c_bus + */ +int stk1160_i2c_unregister(struct stk1160 *dev) +{ + i2c_del_adapter(&dev->i2c_adap); + return 0; +} diff --git a/drivers/media/video/stk1160/stk1160-reg.h b/drivers/media/video/stk1160/stk1160-reg.h new file mode 100644 index 0000000..3e49da6 --- /dev/null +++ b/drivers/media/video/stk1160/stk1160-reg.h @@ -0,0 +1,93 @@ +/* + * STK1160 driver + * + * Copyright (C) 2012 Ezequiel Garcia + * <elezegarcia--a.t--gmail.com> + * + * Based on Easycap driver by R.M. Thomas + * Copyright (C) 2010 R.M. Thomas + * <rmthomas--a.t--sciolus.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 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. + * + */ + +/* GPIO Control */ +#define STK1160_GCTRL 0x000 + +/* Remote Wakup Control */ +#define STK1160_RMCTL 0x00c + +/* + * Decoder Control Register: + * This byte controls capture start/stop + * with bit #7 (0x?? OR 0x80 to activate). + */ +#define STK1160_DCTRL 0x100 + +/* Capture Frame Start Position */ +#define STK116_CFSPO 0x110 +#define STK116_CFSPO_STX_L 0x110 +#define STK116_CFSPO_STX_H 0x111 +#define STK116_CFSPO_STY_L 0x112 +#define STK116_CFSPO_STY_H 0x113 + +/* Capture Frame End Position */ +#define STK116_CFEPO 0x114 +#define STK116_CFEPO_ENX_L 0x114 +#define STK116_CFEPO_ENX_H 0x115 +#define STK116_CFEPO_ENY_L 0x116 +#define STK116_CFEPO_ENY_H 0x117 + +/* Serial Interface Control */ +#define STK1160_SICTL 0x200 +#define STK1160_SICTL_CD 0x202 +#define STK1160_SICTL_SDA 0x203 + +/* Serial Bus Write */ +#define STK1160_SBUSW 0x204 +#define STK1160_SBUSW_WA 0x204 +#define STK1160_SBUSW_WD 0x205 + +/* Serial Bus Read */ +#define STK1160_SBUSR 0x208 +#define STK1160_SBUSR_RA 0x208 +#define STK1160_SBUSR_RD 0x209 + +/* Alternate Serial Inteface Control */ +#define STK1160_ASIC 0x2fc + +/* PLL Select Options */ +#define STK1160_PLLSO 0x018 + +/* PLL Frequency Divider */ +#define STK1160_PLLFD 0x01c + +/* Timing Generator */ +#define STK1160_TIGEN 0x300 + +/* Timing Control Parameter */ +#define STK1160_TICTL 0x350 + +/* AC97 Audio Control */ +#define STK1160_AC97CTL_0 0x500 +#define STK1160_AC97CTL_1 0x504 + +/* Use [0:6] bits of register 0x504 to set codec command address */ +#define STK1160_AC97_ADDR 0x504 +/* Use [16:31] bits of register 0x500 to set codec command data */ +#define STK1160_AC97_CMD 0x502 + +/* Audio I2S Interface */ +#define STK1160_I2SCTL 0x50c + +/* EEPROM Interface */ +#define STK1160_EEPROM_SZ 0x5f0 diff --git a/drivers/media/video/stk1160/stk1160-v4l.c b/drivers/media/video/stk1160/stk1160-v4l.c new file mode 100644 index 0000000..1c1a541 --- /dev/null +++ b/drivers/media/video/stk1160/stk1160-v4l.c @@ -0,0 +1,727 @@ +/* + * STK1160 driver + * + * Copyright (C) 2012 Ezequiel Garcia + * <elezegarcia--a.t--gmail.com> + * + * Based on Easycap driver by R.M. Thomas + * Copyright (C) 2010 R.M. Thomas + * <rmthomas--a.t--sciolus.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 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. + * + */ + +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/mm.h> +#include <linux/slab.h> + +#include <linux/videodev2.h> +#include <media/v4l2-device.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-event.h> +#include <media/v4l2-chip-ident.h> +#include <media/videobuf2-vmalloc.h> + +#include <media/saa7115.h> + +#include "stk1160.h" +#include "stk1160-reg.h" + +static unsigned int vidioc_debug; +module_param(vidioc_debug, int, 0644); +MODULE_PARM_DESC(vidioc_debug, "enable debug messages [vidioc]"); + +static bool keep_buffers; +module_param(keep_buffers, bool, 0644); +MODULE_PARM_DESC(keep_buffers, "don't release buffers upon stop streaming"); + +/* supported video standards */ +static struct stk1160_fmt format[] = { + { + .name = "16 bpp YUY2, 4:2:2, packed", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + } +}; + +static void stk1160_set_std(struct stk1160 *dev) +{ + int i; + + static struct regval std525[] = { + + /* 720x480 */ + + /* Frame start */ + {STK116_CFSPO_STX_L, 0x0000}, + {STK116_CFSPO_STX_H, 0x0000}, + {STK116_CFSPO_STY_L, 0x0003}, + {STK116_CFSPO_STY_H, 0x0000}, + + /* Frame end */ + {STK116_CFEPO_ENX_L, 0x05a0}, + {STK116_CFEPO_ENX_H, 0x0005}, + {STK116_CFEPO_ENY_L, 0x00f3}, + {STK116_CFEPO_ENY_H, 0x0000}, + + {0xffff, 0xffff} + }; + + static struct regval std625[] = { + + /* 720x576 */ + + /* TODO: Each line of frame has some junk at the end */ + /* Frame start */ + {STK116_CFSPO, 0x0000}, + {STK116_CFSPO+1, 0x0000}, + {STK116_CFSPO+2, 0x0001}, + {STK116_CFSPO+3, 0x0000}, + + /* Frame end */ + {STK116_CFEPO, 0x05a0}, + {STK116_CFEPO+1, 0x0005}, + {STK116_CFEPO+2, 0x0121}, + {STK116_CFEPO+3, 0x0001}, + + {0xffff, 0xffff} + }; + + if (dev->norm & V4L2_STD_525_60) { + stk1160_dbg("registers to NTSC like standard\n"); + for (i = 0; std525[i].reg != 0xffff; i++) + stk1160_write_reg(dev, std525[i].reg, std525[i].val); + } else { + stk1160_dbg("registers to PAL like standard\n"); + for (i = 0; std625[i].reg != 0xffff; i++) + stk1160_write_reg(dev, std625[i].reg, std625[i].val); + } + +} + +/* + * Set a new alternate setting. + * Returns true is dev->max_pkt_size has changed, false otherwise. + */ +static bool stk1160_set_alternate(struct stk1160 *dev) +{ + int i, prev_alt = dev->alt; + unsigned int min_pkt_size; + bool new_pkt_size; + + /* + * If we don't set right alternate, + * then we will get a green screen with junk. + */ + min_pkt_size = STK1160_MIN_PKT_SIZE; + + for (i = 0; i < dev->num_alt; i++) { + /* stop when the selected alt setting offers enough bandwidth */ + if (dev->alt_max_pkt_size[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[i] > + dev->alt_max_pkt_size[dev->alt]) + dev->alt = i; + } + + stk1160_info("setting alternate %d\n", dev->alt); + + if (dev->alt != prev_alt) { + stk1160_dbg("minimum isoc packet size: %u (alt=%d)\n", + min_pkt_size, dev->alt); + stk1160_dbg("setting alt %d with wMaxPacketSize=%u\n", + dev->alt, dev->alt_max_pkt_size[dev->alt]); + usb_set_interface(dev->udev, 0, dev->alt); + } + + new_pkt_size = dev->max_pkt_size != dev->alt_max_pkt_size[dev->alt]; + dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt]; + + return new_pkt_size; +} + +static int stk1160_start_streaming(struct stk1160 *dev) +{ + int i, rc; + bool new_pkt_size; + + /* Check device presence */ + if (!dev->udev) + return -ENODEV; + + /* + * For some reason it is mandatory to set alternate *first* + * and only *then* initialize isoc urbs. + * Someone please explain me why ;) + */ + new_pkt_size = stk1160_set_alternate(dev); + + /* + * We (re)allocate isoc urbs if: + * there is no allocated isoc urbs, OR + * a new dev->max_pkt_size is detected + */ + if (!dev->isoc_ctl.num_bufs || new_pkt_size) { + rc = stk1160_alloc_isoc(dev); + if (rc < 0) + return rc; + } + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_KERNEL); + if (rc) { + stk1160_err("cannot submit urb[%d] (%d)\n", i, rc); + stk1160_uninit_isoc(dev); + return rc; + } + } + + /* Start saa711x */ + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); + + /* Start stk1160 */ + stk1160_write_reg(dev, STK1160_DCTRL, 0xb3); + stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00); + + stk1160_dbg("streaming started\n"); + + return 0; +} + +int stk1160_stop_streaming(struct stk1160 *dev, bool connected) +{ + struct stk1160_buffer *buf; + unsigned long flags = 0; + + stk1160_cancel_isoc(dev); + + /* + * It is possible to keep buffers around using a module parameter. + * This is intended to avoid memory fragmentation. + */ + if (!keep_buffers) + stk1160_free_isoc(dev); + + /* If the device is physically plugged */ + if (connected && dev->udev) { + + /* set alternate 0 */ + dev->alt = 0; + stk1160_info("setting alternate %d\n", dev->alt); + usb_set_interface(dev->udev, 0, 0); + + /* Stop stk1160 */ + stk1160_write_reg(dev, STK1160_DCTRL, 0x00); + stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00); + + /* Stop saa711x */ + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); + } + + /* Release all active buffers */ + spin_lock_irqsave(&dev->buf_lock, flags); + while (!list_empty(&dev->avail_bufs)) { + buf = list_first_entry(&dev->avail_bufs, + struct stk1160_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + stk1160_info("buffer [%p/%d] aborted\n", + buf, buf->vb.v4l2_buf.index); + } + /* It's important to clear current buffer */ + dev->isoc_ctl.buf = NULL; + spin_unlock_irqrestore(&dev->buf_lock, flags); + + stk1160_dbg("streaming stopped\n"); + return 0; +} + +static struct v4l2_file_operations stk1160_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +/* + * vidioc ioctls + */ +static int vidioc_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + struct stk1160 *dev = video_drvdata(file); + + strcpy(cap->driver, "stk1160"); + strcpy(cap->card, "stk1160"); + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + cap->device_caps = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + strlcpy(f->description, format[f->index].name, sizeof(f->description)); + f->pixelformat = format[f->index].fourcc; + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct stk1160 *dev = video_drvdata(file); + + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.pixelformat = dev->fmt->fourcc; + f->fmt.pix.bytesperline = dev->width * 2; + f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct stk1160 *dev = video_drvdata(file); + + if (f->fmt.pix.pixelformat != format[0].fourcc) { + stk1160_err("fourcc format 0x%08x invalid\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + /* + * User can't choose size at his own will, + * so we just return him the current size chosen + * at standard selection. + * TODO: Implement frame scaling? + */ + + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.bytesperline = dev->width * 2; + f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct stk1160 *dev = video_drvdata(file); + struct vb2_queue *q = &dev->vb_vidq; + int rc; + + if (vb2_is_busy(q)) + return -EBUSY; + + rc = vidioc_try_fmt_vid_cap(file, priv, f); + if (rc < 0) + return rc; + + /* We don't support any format changes */ + + return 0; +} + +static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct stk1160 *dev = video_drvdata(file); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm); + return 0; +} + +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct stk1160 *dev = video_drvdata(file); + + *norm = dev->norm; + return 0; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct stk1160 *dev = video_drvdata(file); + struct vb2_queue *q = &dev->vb_vidq; + + if (vb2_is_busy(q)) + return -EBUSY; + + /* Check device presence */ + if (!dev->udev) + return -ENODEV; + + /* We need to set this now, before we call stk1160_set_std */ + dev->norm = *norm; + + /* This is taken from saa7115 video decoder */ + if (dev->norm & V4L2_STD_525_60) { + dev->width = 720; + dev->height = 480; + } else if (dev->norm & V4L2_STD_625_50) { + dev->width = 720; + dev->height = 576; + } else { + stk1160_err("invalid standard\n"); + return -EINVAL; + } + + stk1160_set_std(dev); + + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, + dev->norm); + + return 0; +} + +/* FIXME: Extend support for other inputs */ +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct stk1160 *dev = video_drvdata(file); + + if (i->index > STK1160_MAX_INPUT) + return -EINVAL; + + sprintf(i->name, "Composite%d", i->index); + i->type = V4L2_INPUT_TYPE_CAMERA; + i->std = dev->vdev.tvnorms; + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct stk1160 *dev = video_drvdata(file); + *i = dev->ctl_input; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct stk1160 *dev = video_drvdata(file); + + if (vb2_is_busy(&dev->vb_vidq)) + return -EBUSY; + + if (i > STK1160_MAX_INPUT) + return -EINVAL; + + dev->ctl_input = i; + + stk1160_select_input(dev); + + return 0; +} + +static int vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + switch (chip->match.type) { + case V4L2_CHIP_MATCH_HOST: + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + return 0; + default: + return -EINVAL; + } +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct stk1160 *dev = video_drvdata(file); + int rc; + u8 val; + + switch (reg->match.type) { + case V4L2_CHIP_MATCH_AC97: + /* TODO: Support me please :-( */ + return -EINVAL; + case V4L2_CHIP_MATCH_I2C_DRIVER: + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + /* TODO: is this correct? */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); + return 0; + default: + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + } + + /* Match host */ + rc = stk1160_read_reg(dev, reg->reg, &val); + reg->val = val; + reg->size = 1; + + return rc; +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct stk1160 *dev = video_drvdata(file); + + switch (reg->match.type) { + case V4L2_CHIP_MATCH_AC97: + return -EINVAL; + case V4L2_CHIP_MATCH_I2C_DRIVER: + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); + return 0; + case V4L2_CHIP_MATCH_I2C_ADDR: + /* TODO: is this correct? */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); + return 0; + default: + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + } + + /* Match host */ + return stk1160_write_reg(dev, reg->reg, cpu_to_le16(reg->val)); +} +#endif + +static const struct v4l2_ioctl_ops stk1160_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .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_querystd = vidioc_querystd, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + + /* vb2 takes care of these */ + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_chip_ident = vidioc_g_chip_ident, + +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +/********************************************************************/ + +/* + * Videobuf2 operations + */ +static int 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 stk1160 *dev = vb2_get_drv_priv(vq); + unsigned long size; + + size = dev->width * dev->height * 2; + + /* + * Here we can change the number of buffers being requested. + * So, we set a minimum and a maximum like this: + */ + *nbuffers = clamp_t(unsigned int, *nbuffers, + STK1160_MIN_VIDEO_BUFFERS, STK1160_MAX_VIDEO_BUFFERS); + + /* This means a packed colorformat */ + *nplanes = 1; + + sizes[0] = size; + + stk1160_info("%s: buffer count %d, each %ld bytes\n", + __func__, *nbuffers, size); + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + unsigned long flags; + struct stk1160 *dev = vb2_get_drv_priv(vb->vb2_queue); + struct stk1160_buffer *buf = + container_of(vb, struct stk1160_buffer, vb); + + spin_lock_irqsave(&dev->buf_lock, flags); + if (!dev->udev) { + /* + * If the device is disconnected return the buffer to userspace + * directly. The next QBUF call will fail with -ENODEV. + */ + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } else { + + buf->mem = vb2_plane_vaddr(vb, 0); + buf->length = vb2_plane_size(vb, 0); + buf->bytesused = 0; + buf->pos = 0; + + /* + * If buffer length is less from expected then we return + * the buffer to userspace directly. + */ + if (buf->length < dev->width * dev->height * 2) + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + else + list_add_tail(&buf->list, &dev->avail_bufs); + + } + spin_unlock_irqrestore(&dev->buf_lock, flags); +} + +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct stk1160 *dev = vb2_get_drv_priv(vq); + return stk1160_start_streaming(dev); +} + +/* abort streaming and wait for last buffer */ +static int stop_streaming(struct vb2_queue *vq) +{ + struct stk1160 *dev = vb2_get_drv_priv(vq); + return stk1160_stop_streaming(dev, true); +} + +static void stk1160_lock(struct vb2_queue *vq) +{ + struct stk1160 *dev = vb2_get_drv_priv(vq); + mutex_lock(&dev->v4l_lock); +} + +static void stk1160_unlock(struct vb2_queue *vq) +{ + struct stk1160 *dev = vb2_get_drv_priv(vq); + mutex_unlock(&dev->v4l_lock); +} + +static struct vb2_ops stk1160_video_qops = { + .queue_setup = queue_setup, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = stk1160_unlock, + .wait_finish = stk1160_lock, +}; + +static struct video_device v4l_template = { + .name = "stk1160", + .tvnorms = V4L2_STD_525_60 | V4L2_STD_625_50, + .fops = &stk1160_fops, + .ioctl_ops = &stk1160_ioctl_ops, + .release = video_device_release_empty, +}; + +/********************************************************************/ + +int stk1160_vb2_setup(struct stk1160 *dev) +{ + int rc; + struct vb2_queue *q; + + q = &dev->vb_vidq; + memset(q, 0, sizeof(dev->vb_vidq)); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct stk1160_buffer); + q->ops = &stk1160_video_qops; + q->mem_ops = &vb2_vmalloc_memops; + + rc = vb2_queue_init(q); + if (rc < 0) + return rc; + + /* initialize video dma queue */ + INIT_LIST_HEAD(&dev->avail_bufs); + + return 0; +} + +int stk1160_video_register(struct stk1160 *dev) +{ + int rc; + + /* Initialize video_device with a template structure */ + dev->vdev = v4l_template; + dev->vdev.debug = vidioc_debug; + dev->vdev.queue = &dev->vb_vidq; + + /* + * Provide a mutex to v4l2 core. + * It will be used to protect *only* v4l2 ioctls. + */ + dev->vdev.lock = &dev->v4l_lock; + + /* This will be used to set video_device parent */ + dev->vdev.v4l2_dev = &dev->v4l2_dev; + set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); + + /* NTSC is default */ + dev->norm = V4L2_STD_NTSC_M; + dev->width = 720; + dev->height = 480; + + /* set default format */ + dev->fmt = &format[0]; + stk1160_set_std(dev); + + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, + dev->norm); + + video_set_drvdata(&dev->vdev, dev); + rc = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); + if (rc < 0) { + stk1160_err("video_register_device failed (%d)\n", rc); + return rc; + } + + v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", + video_device_node_name(&dev->vdev)); + + return 0; +} diff --git a/drivers/media/video/stk1160/stk1160-video.c b/drivers/media/video/stk1160/stk1160-video.c new file mode 100644 index 0000000..3785269 --- /dev/null +++ b/drivers/media/video/stk1160/stk1160-video.c @@ -0,0 +1,518 @@ +/* + * STK1160 driver + * + * Copyright (C) 2012 Ezequiel Garcia + * <elezegarcia--a.t--gmail.com> + * + * Based on Easycap driver by R.M. Thomas + * Copyright (C) 2010 R.M. Thomas + * <rmthomas--a.t--sciolus.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 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. + * + */ + +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/slab.h> +#include <linux/ratelimit.h> + +#include "stk1160.h" + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); + +static inline void print_err_status(struct stk1160 *dev, + int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + + if (packet < 0) + printk_ratelimited(KERN_WARNING "URB status %d [%s].\n", + status, errmsg); + else + printk_ratelimited(KERN_INFO "URB packet %d, status %d [%s].\n", + packet, status, errmsg); +} + +static inline +struct stk1160_buffer *stk1160_next_buffer(struct stk1160 *dev) +{ + struct stk1160_buffer *buf = NULL; + unsigned long flags = 0; + + /* Current buffer must be NULL when this functions gets called */ + BUG_ON(dev->isoc_ctl.buf); + + spin_lock_irqsave(&dev->buf_lock, flags); + if (!list_empty(&dev->avail_bufs)) { + buf = list_first_entry(&dev->avail_bufs, + struct stk1160_buffer, list); + list_del(&buf->list); + } + spin_unlock_irqrestore(&dev->buf_lock, flags); + + return buf; +} + +static inline +void stk1160_buffer_done(struct stk1160 *dev) +{ + struct stk1160_buffer *buf = dev->isoc_ctl.buf; + + dev->field_count++; + + buf->vb.v4l2_buf.sequence = dev->field_count >> 1; + buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + buf->vb.v4l2_buf.bytesused = buf->bytesused; + do_gettimeofday(&buf->vb.v4l2_buf.timestamp); + + vb2_set_plane_payload(&buf->vb, 0, buf->bytesused); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); + + dev->isoc_ctl.buf = NULL; +} + +static inline +void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len) +{ + int linesdone, lineoff, lencopy; + int bytesperline = dev->width * 2; + struct stk1160_buffer *buf = dev->isoc_ctl.buf; + u8 *dst = buf->mem; + int remain; + + /* + * TODO: These stk1160_dbg are very spammy! + * We should 1) check why we are getting them + * and 2) add ratelimit. + * + * UPDATE: One of the reasons (the only one?) for getting these + * is incorrect standard (mismatch between expected and configured). + * So perhaps, we could add a counter for errors. When the counter + * reaches some value, we simply stop streaming. + */ + + len -= 4; + src += 4; + + remain = len; + + linesdone = buf->pos / bytesperline; + lineoff = buf->pos % bytesperline; /* offset in current line */ + + if (!buf->odd) + dst += bytesperline; + + /* Multiply linesdone by two, to take account of the other field */ + dst += linesdone * bytesperline * 2 + lineoff; + + /* Copy the remaining of current line */ + if (remain < (bytesperline - lineoff)) + lencopy = remain; + else + lencopy = bytesperline - lineoff; + + /* + * Check if we have enough space left in the buffer. + * In that case, we force loop exit after copy. + */ + if (lencopy > buf->bytesused - buf->length) { + lencopy = buf->bytesused - buf->length; + remain = lencopy; + } + + /* Check if the copy is done */ + if (lencopy == 0 || remain == 0) + return; + + /* Let the bug hunt begin! sanity checks! */ + if (lencopy < 0) { + stk1160_dbg("copy skipped: negative lencopy\n"); + return; + } + + if ((unsigned long)dst + lencopy > + (unsigned long)buf->mem + buf->length) { + printk_ratelimited(KERN_WARNING "stk1160: buffer overflow detected\n"); + return; + } + + memcpy(dst, src, lencopy); + + buf->bytesused += lencopy; + buf->pos += lencopy; + remain -= lencopy; + + /* Copy current field line by line, interlacing with the other field */ + while (remain > 0) { + + dst += lencopy + bytesperline; + src += lencopy; + + /* Copy one line at a time */ + if (remain < bytesperline) + lencopy = remain; + else + lencopy = bytesperline; + + /* + * Check if we have enough space left in the buffer. + * In that case, we force loop exit after copy. + */ + if (lencopy > buf->bytesused - buf->length) { + lencopy = buf->bytesused - buf->length; + remain = lencopy; + } + + /* Check if the copy is done */ + if (lencopy == 0 || remain == 0) + return; + + if (lencopy < 0) { + printk_ratelimited(KERN_WARNING "stk1160: negative lencopy detected\n"); + return; + } + + if ((unsigned long)dst + lencopy > + (unsigned long)buf->mem + buf->length) { + printk_ratelimited(KERN_WARNING "stk1160: buffer overflow detected\n"); + return; + } + + memcpy(dst, src, lencopy); + remain -= lencopy; + + buf->bytesused += lencopy; + buf->pos += lencopy; + } +} + +/* + * Controls the isoc copy of each urb packet + */ +static void stk1160_process_isoc(struct stk1160 *dev, struct urb *urb) +{ + int i, len, status; + u8 *p; + + if (!dev) { + stk1160_warn("%s called with null device\n", __func__); + return; + } + + if (urb->status < 0) { + /* Print status and drop current packet (or field?) */ + print_err_status(dev, -1, urb->status); + return; + } + + for (i = 0; i < urb->number_of_packets; i++) { + status = urb->iso_frame_desc[i].status; + if (status < 0) { + print_err_status(dev, i, status); + continue; + } + + /* Get packet actual length and pointer to data */ + p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + len = urb->iso_frame_desc[i].actual_length; + + /* Empty packet */ + if (len <= 4) + continue; + + /* + * An 8-byte packet sequence means end of field. + * So if we don't have any packet, we start receiving one now + * and if we do have a packet, then we are done with it. + * + * These end of field packets are always 0xc0 or 0x80, + * but not always 8-byte long so we don't check packet length. + */ + if (p[0] == 0xc0) { + + /* + * If first byte is 0xc0 then we received + * second field, and frame has ended. + */ + if (dev->isoc_ctl.buf != NULL) + stk1160_buffer_done(dev); + + dev->isoc_ctl.buf = stk1160_next_buffer(dev); + if (dev->isoc_ctl.buf == NULL) + return; + } + + /* + * If we don't have a buffer here, then it means we + * haven't found the start mark sequence. + */ + if (dev->isoc_ctl.buf == NULL) + continue; + + if (p[0] == 0xc0 || p[0] == 0x80) { + + /* We set next packet parity and + * continue to get next one + */ + dev->isoc_ctl.buf->odd = *p & 0x40; + dev->isoc_ctl.buf->pos = 0; + continue; + } + + stk1160_copy_video(dev, p, len); + } +} + + +/* + * IRQ callback, called by URB callback + */ +static void stk1160_isoc_irq(struct urb *urb) +{ + int i, rc; + struct stk1160 *dev = urb->context; + + switch (urb->status) { + case 0: + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + /* TODO: check uvc driver: he frees the queue here */ + return; + default: + stk1160_err("urb error! status %d\n", urb->status); + return; + } + + stk1160_process_isoc(dev, urb); + + /* Reset urb buffers */ + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc) + stk1160_err("urb re-submit failed (%d)\n", rc); +} + +/* + * Cancel urbs + * This function can't be called in atomic context + */ +void stk1160_cancel_isoc(struct stk1160 *dev) +{ + int i; + + /* + * This check is not necessary, but we add it + * to avoid a spurious debug message + */ + if (!dev->isoc_ctl.num_bufs) + return; + + stk1160_dbg("killing urbs...\n"); + + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + + /* + * To kill urbs we can't be in atomic context. + * We don't care for NULL pointer since + * usb_kill_urb allows it. + */ + usb_kill_urb(dev->isoc_ctl.urb[i]); + } + + stk1160_dbg("all urbs killed\n"); +} + +/* + * Releases urb and transfer buffers + * Obviusly, associated urb must be killed before releasing it. + */ +void stk1160_free_isoc(struct stk1160 *dev) +{ + struct urb *urb; + int i; + + stk1160_dbg("freeing urb buffers...\n"); + + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + + urb = dev->isoc_ctl.urb[i]; + if (urb) { + + if (dev->isoc_ctl.transfer_buffer[i]) { +#ifndef CONFIG_DMA_NONCOHERENT + usb_free_coherent(dev->udev, + urb->transfer_buffer_length, + dev->isoc_ctl.transfer_buffer[i], + urb->transfer_dma); +#else + kfree(dev->isoc_ctl.transfer_buffer[i]); +#endif + } + usb_free_urb(urb); + dev->isoc_ctl.urb[i] = NULL; + } + dev->isoc_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->isoc_ctl.urb); + kfree(dev->isoc_ctl.transfer_buffer); + + dev->isoc_ctl.urb = NULL; + dev->isoc_ctl.transfer_buffer = NULL; + dev->isoc_ctl.num_bufs = 0; + + stk1160_dbg("all urb buffers freed\n"); +} + +/* + * Helper for cancelling and freeing urbs + * This function can't be called in atomic context + */ +void stk1160_uninit_isoc(struct stk1160 *dev) +{ + stk1160_cancel_isoc(dev); + stk1160_free_isoc(dev); +} + +/* + * Allocate URBs + */ +int stk1160_alloc_isoc(struct stk1160 *dev) +{ + struct urb *urb; + int i, j, k, sb_size, max_packets, num_bufs; + + /* + * It may be necessary to release isoc here, + * since isoc are only released on disconnection. + * (see new_pkt_size flag) + */ + if (dev->isoc_ctl.num_bufs) + stk1160_uninit_isoc(dev); + + stk1160_dbg("allocating urbs...\n"); + + num_bufs = STK1160_NUM_BUFS; + max_packets = STK1160_NUM_PACKETS; + sb_size = max_packets * dev->max_pkt_size; + + dev->isoc_ctl.buf = NULL; + dev->isoc_ctl.max_pkt_size = dev->max_pkt_size; + dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + if (!dev->isoc_ctl.urb) { + stk1160_err("out of memory for urb array\n"); + return -ENOMEM; + } + + dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, + GFP_KERNEL); + if (!dev->isoc_ctl.transfer_buffer) { + stk1160_err("out of memory for usb transfers\n"); + kfree(dev->isoc_ctl.urb); + return -ENOMEM; + } + + /* allocate urbs and transfer buffers */ + for (i = 0; i < num_bufs; i++) { + + urb = usb_alloc_urb(max_packets, GFP_KERNEL); + if (!urb) { + stk1160_err("cannot alloc urb[%d]\n", i); + stk1160_uninit_isoc(dev); + return -ENOMEM; + } + dev->isoc_ctl.urb[i] = urb; + +#ifndef CONFIG_DMA_NONCOHERENT + dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, + sb_size, GFP_KERNEL, &urb->transfer_dma); +#else + dev->isoc_ctl.transfer_buffer[i] = kmalloc(sb_size, GFP_KERNEL); +#endif + if (!dev->isoc_ctl.transfer_buffer[i]) { + stk1160_err("cannot alloc %d bytes for tx buffer\n", + sb_size); + stk1160_uninit_isoc(dev); + return -ENOMEM; + } + memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); + + /* + * FIXME: Where can I get the endpoint? + */ + urb->dev = dev->udev; + urb->pipe = usb_rcvisocpipe(dev->udev, STK1160_EP_VIDEO); + urb->transfer_buffer = dev->isoc_ctl.transfer_buffer[i]; + urb->transfer_buffer_length = sb_size; + urb->complete = stk1160_isoc_irq; + urb->context = dev; + urb->interval = 1; + urb->start_frame = 0; + urb->number_of_packets = max_packets; +#ifndef CONFIG_DMA_NONCOHERENT + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; +#else + urb->transfer_flags = URB_ISO_ASAP; +#endif + + k = 0; + for (j = 0; j < max_packets; j++) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + dev->isoc_ctl.max_pkt_size; + k += dev->isoc_ctl.max_pkt_size; + } + } + + stk1160_dbg("urbs allocated\n"); + + /* At last we can say we have some buffers */ + dev->isoc_ctl.num_bufs = num_bufs; + + return 0; +} + diff --git a/drivers/media/video/stk1160/stk1160.h b/drivers/media/video/stk1160/stk1160.h new file mode 100644 index 0000000..7b9ce28 --- /dev/null +++ b/drivers/media/video/stk1160/stk1160.h @@ -0,0 +1,202 @@ +/* + * STK1160 driver + * + * Copyright (C) 2012 Ezequiel Garcia + * <elezegarcia--a.t--gmail.com> + * + * Based on Easycap driver by R.M. Thomas + * Copyright (C) 2010 R.M. Thomas + * <rmthomas--a.t--sciolus.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 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. + * + */ + +#include <linux/i2c.h> +#include <sound/core.h> +#include <sound/ac97_codec.h> +#include <media/videobuf2-core.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> + +#define STK1160_VERSION "0.9.5" +#define STK1160_VERSION_NUM 0x000905 + +/* TODO: Decide on number of packets for each buffer */ +#define STK1160_NUM_PACKETS 64 + +/* Number of buffers for isoc transfers */ +#define STK1160_NUM_BUFS 16 /* TODO */ + +/* TODO: This endpoint address should be retrieved */ +#define STK1160_EP_VIDEO 0x82 +#define STK1160_EP_AUDIO 0x81 + +/* Max and min video buffers */ +#define STK1160_MIN_VIDEO_BUFFERS 8 +#define STK1160_MAX_VIDEO_BUFFERS 32 + +#define STK1160_MIN_PKT_SIZE 3072 + +#define STK1160_MAX_INPUT 3 + +#define STK1160_I2C_TIMEOUT 100 + +/* TODO: Print helpers + * I could use dev_xxx, pr_xxx, v4l2_xxx or printk. + * However, there isn't a solid consensus on which + * new drivers should use. + * + */ +#define DEBUG +#ifdef DEBUG +#define stk1160_dbg(fmt, args...) \ + printk(KERN_DEBUG "stk1160: " fmt, ## args) +#else +#define stk1160_dbg(fmt, args...) +#endif + +#define stk1160_info(fmt, args...) \ + pr_info("stk1160: " fmt, ## args) + +#define stk1160_warn(fmt, args...) \ + pr_warn("stk1160: " fmt, ## args) + +#define stk1160_err(fmt, args...) \ + pr_err("stk1160: " fmt, ## args) + +/* Buffer for one video frame */ +struct stk1160_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_buffer vb; + struct list_head list; + + void *mem; + unsigned int length; /* buffer length */ + unsigned int bytesused; /* bytes written */ + int odd; /* current oddity */ + + /* + * Since we interlace two fields per frame, + * this is different from bytesused. + */ + unsigned int pos; /* current pos inside buffer */ +}; + +struct stk1160_isoc_ctl { + /* max packet size of isoc transaction */ + int max_pkt_size; + + /* number of allocated urbs */ + int num_bufs; + + /* urb for isoc transfers */ + struct urb **urb; + + /* transfer buffers for isoc transfer */ + char **transfer_buffer; + + /* current buffer */ + struct stk1160_buffer *buf; +}; + +struct stk1160_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; +}; + +struct stk1160 { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct v4l2_ctrl_handler ctrl_handler; + + struct device *dev; + struct usb_device *udev; + + /* saa7115 subdev */ + struct v4l2_subdev *sd_saa7115; + + /* isoc control struct */ + struct list_head avail_bufs; + + /* video capture */ + struct vb2_queue vb_vidq; + + /* max packet size of isoc transaction */ + int max_pkt_size; + /* array of wMaxPacketSize */ + unsigned int *alt_max_pkt_size; + /* alternate */ + int alt; + /* Number of alternative settings */ + int num_alt; + + struct stk1160_isoc_ctl isoc_ctl; + char urb_buf[255]; /* urb control msg buffer */ + + /* frame properties */ + int width; /* current frame width */ + int height; /* current frame height */ + unsigned int ctl_input; /* selected input */ + v4l2_std_id norm; /* current norm */ + struct stk1160_fmt *fmt; /* selected format */ + + unsigned int field_count; /* not sure ??? */ + enum v4l2_field field; /* also not sure :/ */ + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_client i2c_client; + + struct mutex v4l_lock; + spinlock_t buf_lock; + + struct file *fh_owner; /* filehandle ownership */ + + /* EXPERIMENTAL */ + struct snd_card *snd_card; +}; + +struct regval { + u16 reg; + u16 val; +}; + +/* Provided by stk1160-v4l.c */ +int stk1160_vb2_setup(struct stk1160 *dev); +int stk1160_video_register(struct stk1160 *dev); +void stk1160_video_unregister(struct stk1160 *dev); +int stk1160_stop_streaming(struct stk1160 *dev, bool connected); + +/* Provided by stk1160-video.c */ +int stk1160_alloc_isoc(struct stk1160 *dev); +void stk1160_free_isoc(struct stk1160 *dev); +void stk1160_cancel_isoc(struct stk1160 *dev); +void stk1160_uninit_isoc(struct stk1160 *dev); + +/* Provided by stk1160-i2c.c */ +int stk1160_i2c_register(struct stk1160 *dev); +int stk1160_i2c_unregister(struct stk1160 *dev); + +/* Provided by stk1160-core.c */ +int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value); +int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value); +int stk1160_write_regs_req(struct stk1160 *dev, u8 req, u16 reg, + char *buf, int len); +int stk1160_read_reg_req_len(struct stk1160 *dev, u8 req, u16 reg, + char *buf, int len); +void stk1160_select_input(struct stk1160 *dev); + +/* Provided by stk1160-ac97.c */ +int stk1160_ac97_register(struct stk1160 *dev); +int stk1160_ac97_unregister(struct stk1160 *dev); + diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 4f4b7d6..427218b 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -25,8 +25,6 @@ source "drivers/staging/media/cxd2099/Kconfig"
source "drivers/staging/media/dt3155v4l/Kconfig"
-source "drivers/staging/media/easycap/Kconfig" - source "drivers/staging/media/go7007/Kconfig"
source "drivers/staging/media/solo6x10/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index c69124c..aec6eb9 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,6 +1,5 @@ obj-$(CONFIG_DVB_AS102) += as102/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ -obj-$(CONFIG_EASYCAP) += easycap/ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_SOLO6X10) += solo6x10/ obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ diff --git a/drivers/staging/media/easycap/Kconfig b/drivers/staging/media/easycap/Kconfig deleted file mode 100644 index a425a6f..0000000 --- a/drivers/staging/media/easycap/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config EASYCAP - tristate "EasyCAP USB ID 05e1:0408 support" - depends on USB && VIDEO_DEV && SND - select SND_PCM - - ---help--- - This is an integrated audio/video driver for EasyCAP cards with - USB ID 05e1:0408. It supports two hardware variants: - - * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60, - having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R) - - * EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled - 1, 2, 3, 4 and an unlabelled input cable for a microphone. - - To compile this driver as a module, choose M here: the - module will be called easycap - -config EASYCAP_DEBUG - bool "Enable EasyCAP driver debugging" - depends on EASYCAP - - ---help--- - This option enables debug printouts - - To enable debug, pass the debug level to the debug module - parameter: - - modprobe easycap debug=[0..9] - diff --git a/drivers/staging/media/easycap/Makefile b/drivers/staging/media/easycap/Makefile deleted file mode 100644 index a34e75f..0000000 --- a/drivers/staging/media/easycap/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -easycap-objs := easycap_main.o -easycap-objs += easycap_low.o -easycap-objs += easycap_ioctl.o -easycap-objs += easycap_settings.o -easycap-objs += easycap_testcard.o -easycap-objs += easycap_sound.o -obj-$(CONFIG_EASYCAP) += easycap.o - -ccflags-y := -Wall - diff --git a/drivers/staging/media/easycap/README b/drivers/staging/media/easycap/README deleted file mode 100644 index 796b032..0000000 --- a/drivers/staging/media/easycap/README +++ /dev/null @@ -1,141 +0,0 @@ - - *********************************************************** - * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60 * - * and * - * EasyCAP002 4-Channel USB 2.0 DVR * - *********************************************************** - Mike Thomas rmthomas@sciolus.org - - - -SUPPORTED HARDWARE ------------------- - -This driver is intended for use with hardware having USB ID 05e1:0408. -Two kinds of EasyCAP have this USB ID, namely: - - * EasyCAP USB 2.0 Video Adapter with Audio, Model DC60, - having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R) - - * EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled - 1, 2, 3, 4 and an unlabelled input cable for a microphone. - - -BUILD OPTIONS AND DEPENDENCIES ------------------------------- - -Unless EASYCAP_DEBUG is defined during compilation it will not be possible -to select a debug level at the time of module installation. - - -KNOWN RUNTIME ISSUES --------------------- - -(1) Intentionally, this driver will not stream material which is unambiguously -identified by the hardware as copy-protected. Normal video output will be -present for about a minute but will then freeze when this situation arises. - -(2) The controls for luminance, contrast, saturation, hue and volume may not -always work properly. - -(3) Reduced-resolution S-Video seems to suffer from moire artefacts. - - -INPUT NUMBERING ---------------- - -For the EasyCAP with S-VIDEO input cable the driver regards a request for -inputs numbered 0 or 1 as referring to CVBS and a request for input -numbered 5 as referring to S-VIDEO. - -For the EasyCAP with four CVBS inputs the driver expects to be asked for -any one of inputs numbered 1,2,3,4. If input 0 is asked for, it is -interpreted as input 1. - - -MODULE PARAMETERS ------------------ - -Three module parameters are defined: - -debug the easycap module is configured at diagnostic level n (0 to 9) -gain audio gain level n (0 to 31, default is 16) -bars whether to display testcard bars when incoming video signal is lost - 0 => no, 1 => yes (default) - - -SUPPORTED TV STANDARDS AND RESOLUTIONS --------------------------------------- - -The following TV standards are natively supported by the hardware and are -usable as (for example) the "norm=" parameter in the mplayer command: - - PAL_BGHIN, NTSC_N_443, - PAL_Nc, NTSC_N, - SECAM, NTSC_M, NTSC_M_JP, - PAL_60, NTSC_443, - PAL_M. - -In addition, the driver offers "custom" pseudo-standards with a framerate -which is 20% of the usual framerate. These pseudo-standards are named: - - PAL_BGHIN_SLOW, NTSC_N_443_SLOW, - PAL_Nc_SLOW, NTSC_N_SLOW, - SECAM_SLOW, NTSC_M_SLOW, NTSC_M_JP_SLOW, - PAL_60_SLOW, NTSC_443_SLOW, - PAL_M_SLOW. - - -The available picture sizes are: - - at 25 frames per second: 720x576, 704x576, 640x480, 360x288, 320x240; - at 30 frames per second: 720x480, 640x480, 360x240, 320x240. - - -WHAT'S TESTED AND WHAT'S NOT ----------------------------- - -This driver is known to work with mplayer, mencoder, tvtime, zoneminder, -xawtv, gstreamer and sufficiently recent versions of vlc. An interface -to ffmpeg is implemented, but serious audio-video synchronization problems -remain. - -The driver is designed to support all the TV standards accepted by the -hardware, but as yet it has actually been tested on only a few of these. - -I have been unable to test and calibrate the S-video input myself because I -do not possess any equipment with S-video output. - - -UDEV RULES ----------- - -In order that the special files /dev/easycap0 and /dev/easysnd1 are created -with conveniently relaxed permissions when the EasyCAP is plugged in, a file -is preferably to be provided in directory /etc/udev/rules.d with content: - -ACTION!="add|change", GOTO="easycap_rules_end" -ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \ - MODE="0666", OWNER="root", GROUP="root" -LABEL="easycap_rules_end" - - -MODPROBE CONFIGURATION ----------------------- - -The easycap module is in competition with the module snd-usb-audio for the -EasyCAP's audio channel, and its installation can be aided by providing a -file in directory /etc/modprobe.d with content: - -options easycap gain=16 bars=1 -install easycap /sbin/rmmod snd-usb-audio; /sbin/modprobe --ignore-install easycap - - -ACKNOWLEGEMENTS AND REFERENCES ------------------------------- -This driver makes use of information contained in the Syntek Semicon DC-1125 -Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/ -by Nicolas Vivien. Particularly useful has been a patch to the latter driver -provided by Ivor Hewitt in January 2009. The NTSC implementation is taken -from the work of Ben Trask. - diff --git a/drivers/staging/media/easycap/easycap.h b/drivers/staging/media/easycap/easycap.h deleted file mode 100644 index a007e74..0000000 --- a/drivers/staging/media/easycap/easycap.h +++ /dev/null @@ -1,567 +0,0 @@ -/***************************************************************************** -* * -* easycap.h * -* * -*****************************************************************************/ -/* - * - * Copyright (C) 2010 R.M. Thomas rmthomas@sciolus.org - * - * - * This 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. - * - * The software 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 software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * THE FOLLOWING PARAMETERS ARE UNDEFINED: - * - * EASYCAP_DEBUG - * - * IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER - * OPTIONS. - */ -/*---------------------------------------------------------------------------*/ - -#ifndef __EASYCAP_H__ -#define __EASYCAP_H__ - -/*---------------------------------------------------------------------------*/ -/* - * THESE ARE NORMALLY DEFINED - */ -/*---------------------------------------------------------------------------*/ -#define PATIENCE 500 -#define PERSEVERE -/*---------------------------------------------------------------------------*/ -/* - * THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED: - */ -/*---------------------------------------------------------------------------*/ -#undef EASYCAP_TESTCARD -/*---------------------------------------------------------------------------*/ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/kref.h> -#include <linux/usb.h> -#include <linux/uaccess.h> - -#include <linux/i2c.h> -#include <linux/workqueue.h> -#include <linux/poll.h> -#include <linux/mm.h> -#include <linux/fs.h> -#include <linux/delay.h> -#include <linux/types.h> - -#include <linux/vmalloc.h> -#include <linux/sound.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/info.h> -#include <sound/initval.h> -#include <sound/control.h> -#include <media/v4l2-dev.h> -#include <media/v4l2-device.h> -#include <linux/videodev2.h> -#include <linux/soundcard.h> - -/*---------------------------------------------------------------------------*/ -/* VENDOR, PRODUCT: Syntek Semiconductor Co., Ltd - * - * EITHER EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60 - * with input cabling: AUDIO(L), AUDIO(R), CVBS, S-VIDEO. - * - * OR EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002 - * with input cabling: MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4. - */ -/*---------------------------------------------------------------------------*/ -#define USB_EASYCAP_VENDOR_ID 0x05e1 -#define USB_EASYCAP_PRODUCT_ID 0x0408 - -#define EASYCAP_DRIVER_VERSION "0.9.01" -#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60" - -#define DONGLE_MANY 8 -#define INPUT_MANY 6 -/*---------------------------------------------------------------------------*/ -/* - * DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE - */ -/*---------------------------------------------------------------------------*/ -#define SAA_0A_DEFAULT 0x7F -#define SAA_0B_DEFAULT 0x3F -#define SAA_0C_DEFAULT 0x2F -#define SAA_0D_DEFAULT 0x00 -/*---------------------------------------------------------------------------*/ -/* - * VIDEO STREAMING PARAMETERS: - * USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT - * OF 3072 BYTES PER MICROFRAME for wMaxPacketSize. - */ -/*---------------------------------------------------------------------------*/ -#define VIDEO_ISOC_BUFFER_MANY 16 -#define VIDEO_ISOC_ORDER 3 -#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER) -#define USB_2_0_MAXPACKETSIZE 3072 -#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE) -#error video_isoc_buffer[.] will not be big enough -#endif -#define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY -#define VIDEO_LOST_TOLERATE 50 -/*---------------------------------------------------------------------------*/ -/* - * VIDEO BUFFERS - */ -/*---------------------------------------------------------------------------*/ -#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE) -#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE) -#define FIELD_BUFFER_MANY 4 -#define FRAME_BUFFER_MANY 6 -/*---------------------------------------------------------------------------*/ -/* - * AUDIO STREAMING PARAMETERS - */ -/*---------------------------------------------------------------------------*/ -#define AUDIO_ISOC_BUFFER_MANY 16 -#define AUDIO_ISOC_ORDER 1 -#define AUDIO_ISOC_FRAMESPERDESC 32 -#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER) -/*---------------------------------------------------------------------------*/ -/* - * AUDIO BUFFERS - */ -/*---------------------------------------------------------------------------*/ -#define AUDIO_FRAGMENT_MANY 32 -#define PAGES_PER_AUDIO_FRAGMENT 4 -/*---------------------------------------------------------------------------*/ -/* - * IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND, - * ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND. - * THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE. NOT - * ONLY MUST THE PARAMETER - * STANDARD_MANY - * BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE - * NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE: DUMMY STANDARDS - * MAY NEED TO BE ADDED. APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN - * ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE. BEWARE. - */ -/*---------------------------------------------------------------------------*/ -#define PAL_BGHIN 0 -#define PAL_Nc 2 -#define SECAM 4 -#define NTSC_N 6 -#define NTSC_N_443 8 -#define NTSC_M 1 -#define NTSC_443 3 -#define NTSC_M_JP 5 -#define PAL_60 7 -#define PAL_M 9 -#define PAL_BGHIN_SLOW 10 -#define PAL_Nc_SLOW 12 -#define SECAM_SLOW 14 -#define NTSC_N_SLOW 16 -#define NTSC_N_443_SLOW 18 -#define NTSC_M_SLOW 11 -#define NTSC_443_SLOW 13 -#define NTSC_M_JP_SLOW 15 -#define PAL_60_SLOW 17 -#define PAL_M_SLOW 19 -#define STANDARD_MANY 20 -/*---------------------------------------------------------------------------*/ -/* - * ENUMS - */ -/*---------------------------------------------------------------------------*/ -enum { - AT_720x576, - AT_704x576, - AT_640x480, - AT_720x480, - AT_360x288, - AT_320x240, - AT_360x240, - RESOLUTION_MANY -}; -enum { - FMT_UYVY, - FMT_YUY2, - FMT_RGB24, - FMT_RGB32, - FMT_BGR24, - FMT_BGR32, - PIXELFORMAT_MANY -}; -enum { - FIELD_NONE, - FIELD_INTERLACED, - INTERLACE_MANY -}; -#define SETTINGS_MANY (STANDARD_MANY * \ - RESOLUTION_MANY * \ - 2 * \ - PIXELFORMAT_MANY * \ - INTERLACE_MANY) -/*---------------------------------------------------------------------------*/ -/* - * STRUCTURE DEFINITIONS - */ -/*---------------------------------------------------------------------------*/ -struct easycap_dongle { - struct easycap *peasycap; - struct mutex mutex_video; - struct mutex mutex_audio; -}; -/*---------------------------------------------------------------------------*/ -struct data_buffer { - struct list_head list_head; - void *pgo; - void *pto; - u16 kount; - u16 input; -}; -/*---------------------------------------------------------------------------*/ -struct data_urb { - struct list_head list_head; - struct urb *purb; - int isbuf; - int length; -}; -/*---------------------------------------------------------------------------*/ -struct easycap_standard { - u16 mask; -struct v4l2_standard v4l2_standard; -}; -struct easycap_format { - u16 mask; - char name[128]; -struct v4l2_format v4l2_format; -}; -struct inputset { - int input; - int input_ok; - int standard_offset; - int standard_offset_ok; - int format_offset; - int format_offset_ok; - int brightness; - int brightness_ok; - int contrast; - int contrast_ok; - int saturation; - int saturation_ok; - int hue; - int hue_ok; -}; -/*---------------------------------------------------------------------------*/ -/* - * easycap.ilk == 0 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256 - * easycap.ilk == 2 => CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9 - * easycap.ilk == 3 => FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9 - */ -/*---------------------------------------------------------------------------*/ -struct easycap { - int isdongle; - int minor; - - struct video_device video_device; - struct v4l2_device v4l2_device; - - int status; - unsigned int audio_pages_per_fragment; - unsigned int audio_bytes_per_fragment; - unsigned int audio_buffer_page_many; - -#define UPSAMPLE -#ifdef UPSAMPLE - s16 oldaudio; -#endif /*UPSAMPLE*/ - - int ilk; - bool microphone; - - struct usb_device *pusb_device; - struct usb_interface *pusb_interface; - - struct kref kref; - - int queued[FRAME_BUFFER_MANY]; - int done[FRAME_BUFFER_MANY]; - - wait_queue_head_t wq_video; - wait_queue_head_t wq_audio; - wait_queue_head_t wq_trigger; - - int input; - int polled; - int standard_offset; - int format_offset; - struct inputset inputset[INPUT_MANY]; - - bool ntsc; - int fps; - int usec; - int tolerate; - int skip; - int skipped; - int lost[INPUT_MANY]; - int merit[180]; - - int video_interface; - int video_altsetting_on; - int video_altsetting_off; - int video_endpointnumber; - int video_isoc_maxframesize; - int video_isoc_buffer_size; - int video_isoc_framesperdesc; - - int video_isoc_streaming; - int video_isoc_sequence; - int video_idle; - int video_eof; - int video_junk; - - struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY]; - struct data_buffer field_buffer[FIELD_BUFFER_MANY] - [(FIELD_BUFFER_SIZE/PAGE_SIZE)]; - struct data_buffer frame_buffer[FRAME_BUFFER_MANY] - [(FRAME_BUFFER_SIZE/PAGE_SIZE)]; - - struct list_head urb_video_head; - struct list_head *purb_video_head; - - u8 cache[8]; - u8 *pcache; - int video_mt; - int audio_mt; - u32 isequence; - - int vma_many; -/*---------------------------------------------------------------------------*/ -/* - * BUFFER INDICATORS - */ -/*---------------------------------------------------------------------------*/ - int field_fill; /* Field buffer being filled by easycap_complete(). */ - /* Bumped only by easycap_complete(). */ - int field_page; /* Page of field buffer page being filled by */ - /* easycap_complete(). */ - int field_read; /* Field buffer to be read by field2frame(). */ - /* Bumped only by easycap_complete(). */ - int frame_fill; /* Frame buffer being filled by field2frame(). */ - /* Bumped only by easycap_dqbuf() when */ - /* field2frame() has created a complete frame. */ - int frame_read; /* Frame buffer offered to user by DQBUF. */ - /* Set only by easycap_dqbuf() to trail frame_fill.*/ - int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF */ -/*---------------------------------------------------------------------------*/ -/* - * IMAGE PROPERTIES - */ -/*---------------------------------------------------------------------------*/ - u32 pixelformat; - int width; - int height; - int bytesperpixel; - bool byteswaporder; - bool decimatepixel; - bool offerfields; - int frame_buffer_used; - int frame_buffer_many; - int videofieldamount; - - int brightness; - int contrast; - int saturation; - int hue; - - int allocation_video_urb; - int allocation_video_page; - int allocation_video_struct; - int registered_video; -/*---------------------------------------------------------------------------*/ -/* - * ALSA - */ -/*---------------------------------------------------------------------------*/ - struct snd_pcm_hardware alsa_hardware; - struct snd_card *psnd_card; - struct snd_pcm *psnd_pcm; - struct snd_pcm_substream *psubstream; - int dma_fill; - int dma_next; - int dma_read; -/*---------------------------------------------------------------------------*/ -/* - * SOUND PROPERTIES - */ -/*---------------------------------------------------------------------------*/ - int audio_interface; - int audio_altsetting_on; - int audio_altsetting_off; - int audio_endpointnumber; - int audio_isoc_maxframesize; - int audio_isoc_buffer_size; - int audio_isoc_framesperdesc; - - int audio_isoc_streaming; - int audio_idle; - int audio_eof; - int volume; - int mute; - s8 gain; - - struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY]; - - struct list_head urb_audio_head; - struct list_head *purb_audio_head; -/*---------------------------------------------------------------------------*/ -/* - * BUFFER INDICATORS - */ -/*---------------------------------------------------------------------------*/ - int audio_fill; /* Audio buffer being filled by easycap_complete(). */ - /* Bumped only by easycap_complete(). */ - int audio_read; /* Audio buffer page being read by easycap_read(). */ - /* Set by easycap_read() to trail audio_fill by */ - /* one fragment. */ -/*---------------------------------------------------------------------------*/ -/* - * SOUND PROPERTIES - */ -/*---------------------------------------------------------------------------*/ - int allocation_audio_urb; - int allocation_audio_page; - int allocation_audio_struct; - int registered_audio; - - long long int audio_sample; - long long int audio_niveau; - long long int audio_square; - - struct data_buffer audio_buffer[]; -}; -/*---------------------------------------------------------------------------*/ -/* - * VIDEO FUNCTION PROTOTYPES - */ -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ -int easycap_newinput(struct easycap *, int); -void easycap_testcard(struct easycap *, int); -int easycap_isdongle(struct easycap *); - -long easycap_unlocked_ioctl(struct file *, unsigned int, unsigned long); - -int easycap_video_dqbuf(struct easycap *, int); -int easycap_video_submit_urbs(struct easycap *); -int easycap_video_kill_urbs(struct easycap *); -int easycap_video_fillin_formats(void); - -int adjust_standard(struct easycap *, v4l2_std_id); -int adjust_format(struct easycap *, u32, u32, u32, int, bool); -int adjust_brightness(struct easycap *, int); -int adjust_contrast(struct easycap *, int); -int adjust_saturation(struct easycap *, int); -int adjust_hue(struct easycap *, int); -/*---------------------------------------------------------------------------*/ -/* - * AUDIO FUNCTION PROTOTYPES - */ -/*---------------------------------------------------------------------------*/ -int easycap_alsa_probe(struct easycap *); -int easycap_audio_kill_urbs(struct easycap *); -void easycap_alsa_complete(struct urb *); -/*---------------------------------------------------------------------------*/ -/* - * LOW-LEVEL FUNCTION PROTOTYPES - */ -/*---------------------------------------------------------------------------*/ -int easycap_audio_gainset(struct usb_device *, s8); -int easycap_audio_setup(struct easycap *); - -int easycap_wakeup_device(struct usb_device *); - -int setup_stk(struct usb_device *, bool); -int setup_saa(struct usb_device *, bool); -int ready_saa(struct usb_device *); -int merit_saa(struct usb_device *); -int check_vt(struct usb_device *); -int select_input(struct usb_device *, int, int); -int set_resolution(struct usb_device *, u16, u16, u16, u16); - -int read_saa(struct usb_device *, u16); -int write_saa(struct usb_device *, u16, u16); -int start_100(struct usb_device *); -int stop_100(struct usb_device *); -/*---------------------------------------------------------------------------*/ - - -/*---------------------------------------------------------------------------*/ -/* - * MACROS SAM(...) AND JOM(...) ALLOW DIAGNOSTIC OUTPUT TO BE TAGGED WITH - * THE IDENTITY OF THE DONGLE TO WHICH IT APPLIES, BUT IF INVOKED WHEN THE - * POINTER peasycap IS INVALID AN Oops IS LIKELY, AND ITS CAUSE MAY NOT BE - * IMMEDIATELY OBVIOUS FROM A CASUAL READING OF THE SOURCE CODE. BEWARE. -*/ -/*---------------------------------------------------------------------------*/ -const char *strerror(int err); - -#define SAY(format, args...) do { \ - printk(KERN_DEBUG "easycap:: %s: " \ - format, __func__, ##args); \ -} while (0) -#define SAM(format, args...) do { \ - printk(KERN_DEBUG "easycap::%i%s: " \ - format, peasycap->isdongle, __func__, ##args);\ -} while (0) - -#ifdef CONFIG_EASYCAP_DEBUG -extern int easycap_debug; -#define JOT(n, format, args...) do { \ - if (n <= easycap_debug) { \ - printk(KERN_DEBUG "easycap:: %s: " \ - format, __func__, ##args);\ - } \ -} while (0) -#define JOM(n, format, args...) do { \ - if (n <= easycap_debug) { \ - printk(KERN_DEBUG "easycap::%i%s: " \ - format, peasycap->isdongle, __func__, ##args);\ - } \ -} while (0) - -#else -#define JOT(n, format, args...) do {} while (0) -#define JOM(n, format, args...) do {} while (0) -#endif /* CONFIG_EASYCAP_DEBUG */ - -/*---------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------*/ -/* globals - */ -/*---------------------------------------------------------------------------*/ - -extern bool easycap_readback; -extern const struct easycap_standard easycap_standard[]; -extern struct easycap_format easycap_format[]; -extern struct v4l2_queryctrl easycap_control[]; -extern struct easycap_dongle easycapdc60_dongle[]; - -#endif /* !__EASYCAP_H__ */ diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c deleted file mode 100644 index 9413b37..0000000 --- a/drivers/staging/media/easycap/easycap_ioctl.c +++ /dev/null @@ -1,2442 +0,0 @@ -/****************************************************************************** -* * -* easycap_ioctl.c * -* * -******************************************************************************/ -/* - * - * Copyright (C) 2010 R.M. Thomas rmthomas@sciolus.org - * - * - * This 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. - * - * The software 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 software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ -/*****************************************************************************/ - -#include "easycap.h" - -/*--------------------------------------------------------------------------*/ -/* - * UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE - * FOLLOWING: - * peasycap->standard_offset - * peasycap->inputset[peasycap->input].standard_offset - * peasycap->fps - * peasycap->usec - * peasycap->tolerate - * peasycap->skip - */ -/*---------------------------------------------------------------------------*/ -int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) -{ - struct easycap_standard const *peasycap_standard; - u16 reg, set; - int ir, rc, need, k; - unsigned int itwas, isnow; - bool resubmit; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - peasycap_standard = &easycap_standard[0]; - while (0xFFFF != peasycap_standard->mask) { - if (std_id == peasycap_standard->v4l2_standard.id) - break; - peasycap_standard++; - } - if (0xFFFF == peasycap_standard->mask) { - peasycap_standard = &easycap_standard[0]; - while (0xFFFF != peasycap_standard->mask) { - if (std_id & peasycap_standard->v4l2_standard.id) - break; - peasycap_standard++; - } - } - if (0xFFFF == peasycap_standard->mask) { - SAM("ERROR: 0x%08X=std_id: standard not found\n", - (unsigned int)std_id); - return -EINVAL; - } - SAM("selected standard: %s\n", - &(peasycap_standard->v4l2_standard.name[0])); - if (peasycap->standard_offset == peasycap_standard - easycap_standard) { - SAM("requested standard already in effect\n"); - return 0; - } - peasycap->standard_offset = peasycap_standard - easycap_standard; - for (k = 0; k < INPUT_MANY; k++) { - if (!peasycap->inputset[k].standard_offset_ok) { - peasycap->inputset[k].standard_offset = - peasycap->standard_offset; - } - } - if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { - peasycap->inputset[peasycap->input].standard_offset = - peasycap->standard_offset; - peasycap->inputset[peasycap->input].standard_offset_ok = 1; - } else - JOM(8, "%i=peasycap->input\n", peasycap->input); - - peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / - peasycap_standard->v4l2_standard.frameperiod.numerator; - switch (peasycap->fps) { - case 6: - case 30: { - peasycap->ntsc = true; - break; - } - case 5: - case 25: { - peasycap->ntsc = false; - break; - } - default: { - SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps); - return -ENOENT; - } - } - JOM(8, "%i frames-per-second\n", peasycap->fps); - if (0x8000 & peasycap_standard->mask) { - peasycap->skip = 5; - peasycap->usec = 1000000 / (2 * (5 * peasycap->fps)); - peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps)); - } else { - peasycap->skip = 0; - peasycap->usec = 1000000 / (2 * peasycap->fps); - peasycap->tolerate = 1000 * (25 / peasycap->fps); - } - if (peasycap->video_isoc_streaming) { - resubmit = true; - easycap_video_kill_urbs(peasycap); - } else - resubmit = false; -/*--------------------------------------------------------------------------*/ -/* - * SAA7113H DATASHEET PAGE 44, TABLE 42 - */ -/*--------------------------------------------------------------------------*/ - need = 0; - itwas = 0; - reg = 0x00; - set = 0x00; - switch (peasycap_standard->mask & 0x000F) { - case NTSC_M_JP: { - reg = 0x0A; - set = 0x95; - ir = read_saa(peasycap->pusb_device, reg); - if (0 > ir) - SAM("ERROR: cannot read SAA register 0x%02X\n", reg); - else - itwas = (unsigned int)ir; - rc = write_saa(peasycap->pusb_device, reg, set); - if (rc) - SAM("ERROR: failed to set SAA register " - "0x%02X to 0x%02X for JP standard\n", reg, set); - else { - isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); - if (0 > ir) - JOM(8, "SAA register 0x%02X changed " - "to 0x%02X\n", reg, isnow); - else - JOM(8, "SAA register 0x%02X changed " - "from 0x%02X to 0x%02X\n", reg, itwas, isnow); - } - - reg = 0x0B; - set = 0x48; - ir = read_saa(peasycap->pusb_device, reg); - if (0 > ir) - SAM("ERROR: cannot read SAA register 0x%02X\n", reg); - else - itwas = (unsigned int)ir; - rc = write_saa(peasycap->pusb_device, reg, set); - if (rc) - SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X " - "for JP standard\n", reg, set); - else { - isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); - if (0 > ir) - JOM(8, "SAA register 0x%02X changed " - "to 0x%02X\n", reg, isnow); - else - JOM(8, "SAA register 0x%02X changed " - "from 0x%02X to 0x%02X\n", reg, itwas, isnow); - } -/*--------------------------------------------------------------------------*/ -/* - * NOTE: NO break HERE: RUN ON TO NEXT CASE - */ -/*--------------------------------------------------------------------------*/ - } - case NTSC_M: - case PAL_BGHIN: { - reg = 0x0E; - set = 0x01; - need = 1; - break; - } - case NTSC_N_443: - case PAL_60: { - reg = 0x0E; - set = 0x11; - need = 1; - break; - } - case NTSC_443: - case PAL_Nc: { - reg = 0x0E; - set = 0x21; - need = 1; - break; - } - case NTSC_N: - case PAL_M: { - reg = 0x0E; - set = 0x31; - need = 1; - break; - } - case SECAM: { - reg = 0x0E; - set = 0x51; - need = 1; - break; - } - default: - break; - } -/*--------------------------------------------------------------------------*/ - if (need) { - ir = read_saa(peasycap->pusb_device, reg); - if (0 > ir) - SAM("ERROR: failed to read SAA register 0x%02X\n", reg); - else - itwas = (unsigned int)ir; - rc = write_saa(peasycap->pusb_device, reg, set); - if (0 != write_saa(peasycap->pusb_device, reg, set)) { - SAM("ERROR: failed to set SAA register " - "0x%02X to 0x%02X for table 42\n", reg, set); - } else { - isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); - if (0 > ir) - JOM(8, "SAA register 0x%02X changed " - "to 0x%02X\n", reg, isnow); - else - JOM(8, "SAA register 0x%02X changed " - "from 0x%02X to 0x%02X\n", reg, itwas, isnow); - } - } -/*--------------------------------------------------------------------------*/ -/* - * SAA7113H DATASHEET PAGE 41 - */ -/*--------------------------------------------------------------------------*/ - reg = 0x08; - ir = read_saa(peasycap->pusb_device, reg); - if (0 > ir) - SAM("ERROR: failed to read SAA register 0x%02X " - "so cannot reset\n", reg); - else { - itwas = (unsigned int)ir; - if (peasycap_standard->mask & 0x0001) - set = itwas | 0x40 ; - else - set = itwas & ~0x40 ; - rc = write_saa(peasycap->pusb_device, reg, set); - if (rc) - SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", - reg, set); - else { - isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); - if (0 > ir) - JOM(8, "SAA register 0x%02X changed to 0x%02X\n", - reg, isnow); - else - JOM(8, "SAA register 0x%02X changed " - "from 0x%02X to 0x%02X\n", reg, itwas, isnow); - } - } -/*--------------------------------------------------------------------------*/ -/* - * SAA7113H DATASHEET PAGE 51, TABLE 57 - */ -/*---------------------------------------------------------------------------*/ - reg = 0x40; - ir = read_saa(peasycap->pusb_device, reg); - if (0 > ir) - SAM("ERROR: failed to read SAA register 0x%02X " - "so cannot reset\n", reg); - else { - itwas = (unsigned int)ir; - if (peasycap_standard->mask & 0x0001) - set = itwas | 0x80 ; - else - set = itwas & ~0x80 ; - rc = write_saa(peasycap->pusb_device, reg, set); - if (rc) - SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", - reg, set); - else { - isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); - if (0 > ir) - JOM(8, "SAA register 0x%02X changed to 0x%02X\n", - reg, isnow); - else - JOM(8, "SAA register 0x%02X changed " - "from 0x%02X to 0x%02X\n", reg, itwas, isnow); - } - } -/*--------------------------------------------------------------------------*/ -/* - * SAA7113H DATASHEET PAGE 53, TABLE 66 - */ -/*--------------------------------------------------------------------------*/ - reg = 0x5A; - ir = read_saa(peasycap->pusb_device, reg); - if (0 > ir) - SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg); - itwas = (unsigned int)ir; - if (peasycap_standard->mask & 0x0001) - set = 0x0A ; - else - set = 0x07 ; - if (0 != write_saa(peasycap->pusb_device, reg, set)) - SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", - reg, set); - else { - isnow = (unsigned int)read_saa(peasycap->pusb_device, reg); - if (0 > ir) - JOM(8, "SAA register 0x%02X changed " - "to 0x%02X\n", reg, isnow); - else - JOM(8, "SAA register 0x%02X changed " - "from 0x%02X to 0x%02X\n", reg, itwas, isnow); - } - if (resubmit) - easycap_video_submit_urbs(peasycap); - return 0; -} -/*****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES - * A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED. - * - * PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN - * THIS ROUTINE UPDATES THE FOLLOWING: - * peasycap->format_offset - * peasycap->inputset[peasycap->input].format_offset - * peasycap->pixelformat - * peasycap->height - * peasycap->width - * peasycap->bytesperpixel - * peasycap->byteswaporder - * peasycap->decimatepixel - * peasycap->frame_buffer_used - * peasycap->videofieldamount - * peasycap->offerfields - * - * IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[] - * IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER. - * ERRORS RETURN A NEGATIVE NUMBER. - */ -/*--------------------------------------------------------------------------*/ -int adjust_format(struct easycap *peasycap, - u32 width, u32 height, u32 pixelformat, int field, bool try) -{ - struct easycap_format *peasycap_format, *peasycap_best_format; - u16 mask; - struct usb_device *p; - int miss, multiplier, best, k; - char bf[5], fo[32], *pc; - u32 uc; - bool resubmit; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (0 > peasycap->standard_offset) { - JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset); - return -EBUSY; - } - p = peasycap->pusb_device; - if (!p) { - SAM("ERROR: peaycap->pusb_device is NULL\n"); - return -EFAULT; - } - pc = &bf[0]; - uc = pixelformat; - memcpy((void *)pc, (void *)(&uc), 4); - bf[4] = 0; - mask = 0xFF & easycap_standard[peasycap->standard_offset].mask; - SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", - width, height, pc, pixelformat, field, mask); - switch (field) { - case V4L2_FIELD_ANY: { - strcpy(&fo[0], "V4L2_FIELD_ANY "); - break; - } - case V4L2_FIELD_NONE: { - strcpy(&fo[0], "V4L2_FIELD_NONE"); - break; - } - case V4L2_FIELD_TOP: { - strcpy(&fo[0], "V4L2_FIELD_TOP"); - break; - } - case V4L2_FIELD_BOTTOM: { - strcpy(&fo[0], "V4L2_FIELD_BOTTOM"); - break; - } - case V4L2_FIELD_INTERLACED: { - strcpy(&fo[0], "V4L2_FIELD_INTERLACED"); - break; - } - case V4L2_FIELD_SEQ_TB: { - strcpy(&fo[0], "V4L2_FIELD_SEQ_TB"); - break; - } - case V4L2_FIELD_SEQ_BT: { - strcpy(&fo[0], "V4L2_FIELD_SEQ_BT"); - break; - } - case V4L2_FIELD_ALTERNATE: { - strcpy(&fo[0], "V4L2_FIELD_ALTERNATE"); - break; - } - case V4L2_FIELD_INTERLACED_TB: { - strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB"); - break; - } - case V4L2_FIELD_INTERLACED_BT: { - strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT"); - break; - } - default: { - strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN "); - break; - } - } - SAM("sought: %s\n", &fo[0]); - if (V4L2_FIELD_ANY == field) { - field = V4L2_FIELD_NONE; - SAM("prefer: V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n"); - } - peasycap_best_format = NULL; - peasycap_format = &easycap_format[0]; - while (0 != peasycap_format->v4l2_format.fmt.pix.width) { - JOM(16, ".> %i %i 0x%08X %ix%i\n", - peasycap_format->mask & 0x01, - peasycap_format->v4l2_format.fmt.pix.field, - peasycap_format->v4l2_format.fmt.pix.pixelformat, - peasycap_format->v4l2_format.fmt.pix.width, - peasycap_format->v4l2_format.fmt.pix.height); - - if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && - (peasycap_format->v4l2_format.fmt.pix.field == field) && - (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat) && - (peasycap_format->v4l2_format.fmt.pix.width == width) && - (peasycap_format->v4l2_format.fmt.pix.height == height)) { - - peasycap_best_format = peasycap_format; - break; - } - peasycap_format++; - } - if (0 == peasycap_format->v4l2_format.fmt.pix.width) { - SAM("cannot do: %ix%i with standard mask 0x%02X\n", - width, height, mask); - peasycap_format = &easycap_format[0]; - best = -1; - while (0 != peasycap_format->v4l2_format.fmt.pix.width) { - if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && - (peasycap_format->v4l2_format.fmt.pix.field == field) && - (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat)) { - - miss = abs(peasycap_format->v4l2_format.fmt.pix.width - width); - if ((best > miss) || (best < 0)) { - best = miss; - peasycap_best_format = peasycap_format; - if (!miss) - break; - } - } - peasycap_format++; - } - if (-1 == best) { - SAM("cannot do %ix... with standard mask 0x%02X\n", - width, mask); - SAM("cannot do ...x%i with standard mask 0x%02X\n", - height, mask); - SAM(" %ix%i unmatched\n", width, height); - return peasycap->format_offset; - } - } - if (!peasycap_best_format) { - SAM("MISTAKE: peasycap_best_format is NULL"); - return -EINVAL; - } - peasycap_format = peasycap_best_format; - -/*...........................................................................*/ - if (try) - return peasycap_best_format - easycap_format; -/*...........................................................................*/ - - if (false != try) { - SAM("MISTAKE: true==try where is should be false\n"); - return -EINVAL; - } - SAM("actioning: %ix%i %s\n", - peasycap_format->v4l2_format.fmt.pix.width, - peasycap_format->v4l2_format.fmt.pix.height, - &peasycap_format->name[0]); - peasycap->height = peasycap_format->v4l2_format.fmt.pix.height; - peasycap->width = peasycap_format->v4l2_format.fmt.pix.width; - peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat; - peasycap->format_offset = peasycap_format - easycap_format; - - - for (k = 0; k < INPUT_MANY; k++) { - if (!peasycap->inputset[k].format_offset_ok) { - peasycap->inputset[k].format_offset = - peasycap->format_offset; - } - } - if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { - peasycap->inputset[peasycap->input].format_offset = - peasycap->format_offset; - peasycap->inputset[peasycap->input].format_offset_ok = 1; - } else - JOM(8, "%i=peasycap->input\n", peasycap->input); - - - - peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ; - if (0x0100 & peasycap_format->mask) - peasycap->byteswaporder = true; - else - peasycap->byteswaporder = false; - if (0x0200 & peasycap_format->mask) - peasycap->skip = 5; - else - peasycap->skip = 0; - if (0x0800 & peasycap_format->mask) - peasycap->decimatepixel = true; - else - peasycap->decimatepixel = false; - if (0x1000 & peasycap_format->mask) - peasycap->offerfields = true; - else - peasycap->offerfields = false; - if (peasycap->decimatepixel) - multiplier = 2; - else - multiplier = 1; - peasycap->videofieldamount = - multiplier * peasycap->width * multiplier * peasycap->height; - peasycap->frame_buffer_used = - peasycap->bytesperpixel * peasycap->width * peasycap->height; - if (peasycap->video_isoc_streaming) { - resubmit = true; - easycap_video_kill_urbs(peasycap); - } else - resubmit = false; -/*---------------------------------------------------------------------------*/ -/* - * PAL - */ -/*---------------------------------------------------------------------------*/ - if (0 == (0x01 & peasycap_format->mask)) { - if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && - (576 == peasycap_format->v4l2_format.fmt.pix.height)) || - ((360 == peasycap_format->v4l2_format.fmt.pix.width) && - (288 == peasycap_format->v4l2_format.fmt.pix.height))) { - if (set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) { - SAM("ERROR: set_resolution() failed\n"); - return -EINVAL; - } - } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) && - (576 == peasycap_format->v4l2_format.fmt.pix.height)) { - if (set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) { - SAM("ERROR: set_resolution() failed\n"); - return -EINVAL; - } - } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && - (480 == peasycap_format->v4l2_format.fmt.pix.height)) || - ((320 == peasycap_format->v4l2_format.fmt.pix.width) && - (240 == peasycap_format->v4l2_format.fmt.pix.height))) { - if (set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) { - SAM("ERROR: set_resolution() failed\n"); - return -EINVAL; - } - } else { - SAM("MISTAKE: bad format, cannot set resolution\n"); - return -EINVAL; - } -/*---------------------------------------------------------------------------*/ -/* - * NTSC - */ -/*---------------------------------------------------------------------------*/ - } else { - if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && - (480 == peasycap_format->v4l2_format.fmt.pix.height)) || - ((360 == peasycap_format->v4l2_format.fmt.pix.width) && - (240 == peasycap_format->v4l2_format.fmt.pix.height))) { - if (set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) { - SAM("ERROR: set_resolution() failed\n"); - return -EINVAL; - } - } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && - (480 == peasycap_format->v4l2_format.fmt.pix.height)) || - ((320 == peasycap_format->v4l2_format.fmt.pix.width) && - (240 == peasycap_format->v4l2_format.fmt.pix.height))) { - if (set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) { - SAM("ERROR: set_resolution() failed\n"); - return -EINVAL; - } - } else { - SAM("MISTAKE: bad format, cannot set resolution\n"); - return -EINVAL; - } - } -/*---------------------------------------------------------------------------*/ - if (resubmit) - easycap_video_submit_urbs(peasycap); - - return peasycap_best_format - easycap_format; -} -/*****************************************************************************/ -int adjust_brightness(struct easycap *peasycap, int value) -{ - unsigned int mood; - int i1, k; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - i1 = 0; - while (0xFFFFFFFF != easycap_control[i1].id) { - if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) { - if ((easycap_control[i1].minimum > value) || - (easycap_control[i1].maximum < value)) - value = easycap_control[i1].default_value; - - if ((easycap_control[i1].minimum <= peasycap->brightness) && - (easycap_control[i1].maximum >= peasycap->brightness)) { - if (peasycap->brightness == value) { - SAM("unchanged brightness at 0x%02X\n", - value); - return 0; - } - } - peasycap->brightness = value; - for (k = 0; k < INPUT_MANY; k++) { - if (!peasycap->inputset[k].brightness_ok) - peasycap->inputset[k].brightness = - peasycap->brightness; - } - if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { - peasycap->inputset[peasycap->input].brightness = - peasycap->brightness; - peasycap->inputset[peasycap->input].brightness_ok = 1; - } else - JOM(8, "%i=peasycap->input\n", peasycap->input); - - mood = 0x00FF & (unsigned int)peasycap->brightness; - if (write_saa(peasycap->pusb_device, 0x0A, mood)) { - SAM("WARNING: failed to adjust brightness " - "to 0x%02X\n", mood); - return -ENOENT; - } - SAM("adjusting brightness to 0x%02X\n", mood); - return 0; - } - i1++; - } - SAM("WARNING: failed to adjust brightness: control not found\n"); - return -ENOENT; -} -/*****************************************************************************/ -int adjust_contrast(struct easycap *peasycap, int value) -{ - unsigned int mood; - int i1, k; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - i1 = 0; - while (0xFFFFFFFF != easycap_control[i1].id) { - if (V4L2_CID_CONTRAST == easycap_control[i1].id) { - if ((easycap_control[i1].minimum > value) || - (easycap_control[i1].maximum < value)) - value = easycap_control[i1].default_value; - - - if ((easycap_control[i1].minimum <= peasycap->contrast) && - (easycap_control[i1].maximum >= peasycap->contrast)) { - if (peasycap->contrast == value) { - SAM("unchanged contrast at 0x%02X\n", value); - return 0; - } - } - peasycap->contrast = value; - for (k = 0; k < INPUT_MANY; k++) { - if (!peasycap->inputset[k].contrast_ok) - peasycap->inputset[k].contrast = peasycap->contrast; - } - - if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { - peasycap->inputset[peasycap->input].contrast = - peasycap->contrast; - peasycap->inputset[peasycap->input].contrast_ok = 1; - } else - JOM(8, "%i=peasycap->input\n", peasycap->input); - - mood = 0x00FF & (unsigned int) (peasycap->contrast - 128); - if (write_saa(peasycap->pusb_device, 0x0B, mood)) { - SAM("WARNING: failed to adjust contrast to " - "0x%02X\n", mood); - return -ENOENT; - } - SAM("adjusting contrast to 0x%02X\n", mood); - return 0; - } - i1++; - } - SAM("WARNING: failed to adjust contrast: control not found\n"); - return -ENOENT; -} -/*****************************************************************************/ -int adjust_saturation(struct easycap *peasycap, int value) -{ - unsigned int mood; - int i1, k; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - i1 = 0; - while (0xFFFFFFFF != easycap_control[i1].id) { - if (V4L2_CID_SATURATION == easycap_control[i1].id) { - if ((easycap_control[i1].minimum > value) || - (easycap_control[i1].maximum < value)) - value = easycap_control[i1].default_value; - - - if ((easycap_control[i1].minimum <= peasycap->saturation) && - (easycap_control[i1].maximum >= peasycap->saturation)) { - if (peasycap->saturation == value) { - SAM("unchanged saturation at 0x%02X\n", - value); - return 0; - } - } - peasycap->saturation = value; - for (k = 0; k < INPUT_MANY; k++) { - if (!peasycap->inputset[k].saturation_ok) - peasycap->inputset[k].saturation = - peasycap->saturation; - } - if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { - peasycap->inputset[peasycap->input].saturation = - peasycap->saturation; - peasycap->inputset[peasycap->input].saturation_ok = 1; - } else - JOM(8, "%i=peasycap->input\n", peasycap->input); - mood = 0x00FF & (unsigned int) (peasycap->saturation - 128); - if (write_saa(peasycap->pusb_device, 0x0C, mood)) { - SAM("WARNING: failed to adjust saturation to " - "0x%02X\n", mood); - return -ENOENT; - } - SAM("adjusting saturation to 0x%02X\n", mood); - return 0; - break; - } - i1++; - } - SAM("WARNING: failed to adjust saturation: control not found\n"); - return -ENOENT; -} -/*****************************************************************************/ -int adjust_hue(struct easycap *peasycap, int value) -{ - unsigned int mood; - int i1, i2, k; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - i1 = 0; - while (0xFFFFFFFF != easycap_control[i1].id) { - if (V4L2_CID_HUE == easycap_control[i1].id) { - if ((easycap_control[i1].minimum > value) || - (easycap_control[i1].maximum < value)) - value = easycap_control[i1].default_value; - - if ((easycap_control[i1].minimum <= peasycap->hue) && - (easycap_control[i1].maximum >= peasycap->hue)) { - if (peasycap->hue == value) { - SAM("unchanged hue at 0x%02X\n", value); - return 0; - } - } - peasycap->hue = value; - for (k = 0; k < INPUT_MANY; k++) { - if (!peasycap->inputset[k].hue_ok) - peasycap->inputset[k].hue = peasycap->hue; - } - if (0 <= peasycap->input && INPUT_MANY > peasycap->input) { - peasycap->inputset[peasycap->input].hue = peasycap->hue; - peasycap->inputset[peasycap->input].hue_ok = 1; - } else - JOM(8, "%i=peasycap->input\n", peasycap->input); - i2 = peasycap->hue - 128; - mood = 0x00FF & ((int) i2); - if (write_saa(peasycap->pusb_device, 0x0D, mood)) { - SAM("WARNING: failed to adjust hue to 0x%02X\n", mood); - return -ENOENT; - } - SAM("adjusting hue to 0x%02X\n", mood); - return 0; - break; - } - i1++; - } - SAM("WARNING: failed to adjust hue: control not found\n"); - return -ENOENT; -} -/*****************************************************************************/ -static int adjust_volume(struct easycap *peasycap, int value) -{ - s8 mood; - int i1; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - i1 = 0; - while (0xFFFFFFFF != easycap_control[i1].id) { - if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) { - if ((easycap_control[i1].minimum > value) || - (easycap_control[i1].maximum < value)) - value = easycap_control[i1].default_value; - - if ((easycap_control[i1].minimum <= peasycap->volume) && - (easycap_control[i1].maximum >= peasycap->volume)) { - if (peasycap->volume == value) { - SAM("unchanged volume at 0x%02X\n", value); - return 0; - } - } - peasycap->volume = value; - mood = (16 > peasycap->volume) ? 16 : - ((31 < peasycap->volume) ? 31 : - (s8) peasycap->volume); - if (!easycap_audio_gainset(peasycap->pusb_device, mood)) { - SAM("WARNING: failed to adjust volume to " - "0x%2X\n", mood); - return -ENOENT; - } - SAM("adjusting volume to 0x%02X\n", mood); - return 0; - } - i1++; - } - SAM("WARNING: failed to adjust volume: control not found\n"); - return -ENOENT; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE: - * usb_set_interface(peasycap->pusb_device, - * peasycap->audio_interface, - * peasycap->audio_altsetting_off); - * HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS - * -ESHUTDOWN. THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT - * THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY. BEWARE. - */ -/*---------------------------------------------------------------------------*/ -static int adjust_mute(struct easycap *peasycap, int value) -{ - int i1; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - i1 = 0; - while (0xFFFFFFFF != easycap_control[i1].id) { - if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) { - peasycap->mute = value; - switch (peasycap->mute) { - case 1: { - peasycap->audio_idle = 1; - SAM("adjusting mute: %i=peasycap->audio_idle\n", - peasycap->audio_idle); - return 0; - } - default: { - peasycap->audio_idle = 0; - SAM("adjusting mute: %i=peasycap->audio_idle\n", - peasycap->audio_idle); - return 0; - } - } - break; - } - i1++; - } - SAM("WARNING: failed to adjust mute: control not found\n"); - return -ENOENT; -} -/*---------------------------------------------------------------------------*/ -long easycap_unlocked_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct easycap *peasycap; - struct usb_device *p; - int kd; - - if (!file) { - SAY("ERROR: file is NULL\n"); - return -ERESTARTSYS; - } - peasycap = file->private_data; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -1; - } - p = peasycap->pusb_device; - if (!p) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - kd = easycap_isdongle(peasycap); - if (0 <= kd && DONGLE_MANY > kd) { - if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) { - SAY("ERROR: cannot lock " - "easycapdc60_dongle[%i].mutex_video\n", kd); - return -ERESTARTSYS; - } - JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd); -/*---------------------------------------------------------------------------*/ -/* - * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap, - * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. - * IF NECESSARY, BAIL OUT. - */ -/*---------------------------------------------------------------------------*/ - if (kd != easycap_isdongle(peasycap)) - return -ERESTARTSYS; - if (!file) { - SAY("ERROR: file is NULL\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ERESTARTSYS; - } - peasycap = file->private_data; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ERESTARTSYS; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ERESTARTSYS; - } - } else { -/*---------------------------------------------------------------------------*/ -/* - * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE - * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT. - */ -/*---------------------------------------------------------------------------*/ - return -ERESTARTSYS; - } -/*---------------------------------------------------------------------------*/ - switch (cmd) { - case VIDIOC_QUERYCAP: { - struct v4l2_capability v4l2_capability; - char version[16], *p1, *p2; - int i, rc, k[3]; - long lng; - - JOM(8, "VIDIOC_QUERYCAP\n"); - - if (16 <= strlen(EASYCAP_DRIVER_VERSION)) { - SAM("ERROR: bad driver version string\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - strcpy(&version[0], EASYCAP_DRIVER_VERSION); - for (i = 0; i < 3; i++) - k[i] = 0; - p2 = &version[0]; - i = 0; - while (*p2) { - p1 = p2; - while (*p2 && ('.' != *p2)) - p2++; - if (*p2) - *p2++ = 0; - if (3 > i) { - rc = (int) strict_strtol(p1, 10, &lng); - if (rc) { - SAM("ERROR: %i=strict_strtol(%s,.,,)\n", - rc, p1); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - k[i] = (int)lng; - } - i++; - } - - memset(&v4l2_capability, 0, sizeof(struct v4l2_capability)); - strlcpy(&v4l2_capability.driver[0], - "easycap", sizeof(v4l2_capability.driver)); - - v4l2_capability.capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE; - - v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]); - JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]); - - strlcpy(&v4l2_capability.card[0], - "EasyCAP DC60", sizeof(v4l2_capability.card)); - - if (usb_make_path(peasycap->pusb_device, - &v4l2_capability.bus_info[0], - sizeof(v4l2_capability.bus_info)) < 0) { - - strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", - sizeof(v4l2_capability.bus_info)); - JOM(8, "%s=v4l2_capability.bus_info\n", - &v4l2_capability.bus_info[0]); - } - if (copy_to_user((void __user *)arg, &v4l2_capability, - sizeof(struct v4l2_capability))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_ENUMINPUT: { - struct v4l2_input v4l2_input; - u32 index; - - JOM(8, "VIDIOC_ENUMINPUT\n"); - - if (copy_from_user(&v4l2_input, (void __user *)arg, - sizeof(struct v4l2_input))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - index = v4l2_input.index; - memset(&v4l2_input, 0, sizeof(struct v4l2_input)); - - switch (index) { - case 0: { - v4l2_input.index = index; - strcpy(&v4l2_input.name[0], "CVBS0"); - v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; - v4l2_input.audioset = 0x01; - v4l2_input.tuner = 0; - v4l2_input.std = V4L2_STD_PAL | - V4L2_STD_SECAM | - V4L2_STD_NTSC ; - v4l2_input.status = 0; - JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); - break; - } - case 1: { - v4l2_input.index = index; - strcpy(&v4l2_input.name[0], "CVBS1"); - v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; - v4l2_input.audioset = 0x01; - v4l2_input.tuner = 0; - v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | - V4L2_STD_NTSC; - v4l2_input.status = 0; - JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); - break; - } - case 2: { - v4l2_input.index = index; - strcpy(&v4l2_input.name[0], "CVBS2"); - v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; - v4l2_input.audioset = 0x01; - v4l2_input.tuner = 0; - v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | - V4L2_STD_NTSC ; - v4l2_input.status = 0; - JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); - break; - } - case 3: { - v4l2_input.index = index; - strcpy(&v4l2_input.name[0], "CVBS3"); - v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; - v4l2_input.audioset = 0x01; - v4l2_input.tuner = 0; - v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | - V4L2_STD_NTSC ; - v4l2_input.status = 0; - JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); - break; - } - case 4: { - v4l2_input.index = index; - strcpy(&v4l2_input.name[0], "CVBS4"); - v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; - v4l2_input.audioset = 0x01; - v4l2_input.tuner = 0; - v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | - V4L2_STD_NTSC ; - v4l2_input.status = 0; - JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); - break; - } - case 5: { - v4l2_input.index = index; - strcpy(&v4l2_input.name[0], "S-VIDEO"); - v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; - v4l2_input.audioset = 0x01; - v4l2_input.tuner = 0; - v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | - V4L2_STD_NTSC ; - v4l2_input.status = 0; - JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); - break; - } - default: { - JOM(8, "%i=index: exhausts inputs\n", index); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - } - - if (copy_to_user((void __user *)arg, &v4l2_input, - sizeof(struct v4l2_input))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_INPUT: { - u32 index; - - JOM(8, "VIDIOC_G_INPUT\n"); - index = (u32)peasycap->input; - JOM(8, "user is told: %i\n", index); - if (copy_to_user((void __user *)arg, &index, sizeof(u32))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_S_INPUT: - { - u32 index; - int rc; - - JOM(8, "VIDIOC_S_INPUT\n"); - - if (0 != copy_from_user(&index, (void __user *)arg, sizeof(u32))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - JOM(8, "user requests input %i\n", index); - - if ((int)index == peasycap->input) { - SAM("requested input already in effect\n"); - break; - } - - if ((0 > index) || (INPUT_MANY <= index)) { - JOM(8, "ERROR: bad requested input: %i\n", index); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - - rc = easycap_newinput(peasycap, (int)index); - if (0 == rc) { - JOM(8, "newinput(.,%i) OK\n", (int)index); - } else { - SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_ENUMAUDIO: { - JOM(8, "VIDIOC_ENUMAUDIO\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_ENUMAUDOUT: { - struct v4l2_audioout v4l2_audioout; - - JOM(8, "VIDIOC_ENUMAUDOUT\n"); - - if (copy_from_user(&v4l2_audioout, (void __user *)arg, - sizeof(struct v4l2_audioout))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - if (0 != v4l2_audioout.index) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout)); - v4l2_audioout.index = 0; - strcpy(&v4l2_audioout.name[0], "Soundtrack"); - - if (copy_to_user((void __user *)arg, &v4l2_audioout, - sizeof(struct v4l2_audioout))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_QUERYCTRL: { - int i1; - struct v4l2_queryctrl v4l2_queryctrl; - - JOM(8, "VIDIOC_QUERYCTRL\n"); - - if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, - sizeof(struct v4l2_queryctrl))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - i1 = 0; - while (0xFFFFFFFF != easycap_control[i1].id) { - if (easycap_control[i1].id == v4l2_queryctrl.id) { - JOM(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" - ".name\n", &easycap_control[i1].name[0], i1); - memcpy(&v4l2_queryctrl, &easycap_control[i1], - sizeof(struct v4l2_queryctrl)); - break; - } - i1++; - } - if (0xFFFFFFFF == easycap_control[i1].id) { - JOM(8, "%i=index: exhausts controls\n", i1); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - if (copy_to_user((void __user *)arg, &v4l2_queryctrl, - sizeof(struct v4l2_queryctrl))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_QUERYMENU: { - JOM(8, "VIDIOC_QUERYMENU unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_CTRL: { - struct v4l2_control *pv4l2_control; - - JOM(8, "VIDIOC_G_CTRL\n"); - pv4l2_control = memdup_user((void __user *)arg, - sizeof(struct v4l2_control)); - if (IS_ERR(pv4l2_control)) { - SAM("ERROR: copy from user failed\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return PTR_ERR(pv4l2_control); - } - - switch (pv4l2_control->id) { - case V4L2_CID_BRIGHTNESS: { - pv4l2_control->value = peasycap->brightness; - JOM(8, "user enquires brightness: %i\n", pv4l2_control->value); - break; - } - case V4L2_CID_CONTRAST: { - pv4l2_control->value = peasycap->contrast; - JOM(8, "user enquires contrast: %i\n", pv4l2_control->value); - break; - } - case V4L2_CID_SATURATION: { - pv4l2_control->value = peasycap->saturation; - JOM(8, "user enquires saturation: %i\n", pv4l2_control->value); - break; - } - case V4L2_CID_HUE: { - pv4l2_control->value = peasycap->hue; - JOM(8, "user enquires hue: %i\n", pv4l2_control->value); - break; - } - case V4L2_CID_AUDIO_VOLUME: { - pv4l2_control->value = peasycap->volume; - JOM(8, "user enquires volume: %i\n", pv4l2_control->value); - break; - } - case V4L2_CID_AUDIO_MUTE: { - if (1 == peasycap->mute) - pv4l2_control->value = true; - else - pv4l2_control->value = false; - JOM(8, "user enquires mute: %i\n", pv4l2_control->value); - break; - } - default: { - SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", - pv4l2_control->id); - kfree(pv4l2_control); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - } - if (copy_to_user((void __user *)arg, pv4l2_control, - sizeof(struct v4l2_control))) { - kfree(pv4l2_control); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - kfree(pv4l2_control); - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_S_CTRL: { - struct v4l2_control v4l2_control; - - JOM(8, "VIDIOC_S_CTRL\n"); - - if (0 != copy_from_user(&v4l2_control, (void __user *)arg, - sizeof(struct v4l2_control))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - switch (v4l2_control.id) { - case V4L2_CID_BRIGHTNESS: { - JOM(8, "user requests brightness %i\n", v4l2_control.value); - if (0 != adjust_brightness(peasycap, v4l2_control.value)) - ; - break; - } - case V4L2_CID_CONTRAST: { - JOM(8, "user requests contrast %i\n", v4l2_control.value); - if (0 != adjust_contrast(peasycap, v4l2_control.value)) - ; - break; - } - case V4L2_CID_SATURATION: { - JOM(8, "user requests saturation %i\n", v4l2_control.value); - if (0 != adjust_saturation(peasycap, v4l2_control.value)) - ; - break; - } - case V4L2_CID_HUE: { - JOM(8, "user requests hue %i\n", v4l2_control.value); - if (0 != adjust_hue(peasycap, v4l2_control.value)) - ; - break; - } - case V4L2_CID_AUDIO_VOLUME: { - JOM(8, "user requests volume %i\n", v4l2_control.value); - if (0 != adjust_volume(peasycap, v4l2_control.value)) - ; - break; - } - case V4L2_CID_AUDIO_MUTE: { - int mute; - - JOM(8, "user requests mute %i\n", v4l2_control.value); - if (v4l2_control.value) - mute = 1; - else - mute = 0; - - if (0 != adjust_mute(peasycap, mute)) - SAM("WARNING: failed to adjust mute to %i\n", mute); - break; - } - default: { - SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", - v4l2_control.id); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_S_EXT_CTRLS: { - JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_ENUM_FMT: { - u32 index; - struct v4l2_fmtdesc v4l2_fmtdesc; - - JOM(8, "VIDIOC_ENUM_FMT\n"); - - if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, - sizeof(struct v4l2_fmtdesc))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - index = v4l2_fmtdesc.index; - memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc)); - - v4l2_fmtdesc.index = index; - v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - switch (index) { - case 0: { - v4l2_fmtdesc.flags = 0; - strcpy(&v4l2_fmtdesc.description[0], "uyvy"); - v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY; - JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); - break; - } - case 1: { - v4l2_fmtdesc.flags = 0; - strcpy(&v4l2_fmtdesc.description[0], "yuy2"); - v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV; - JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); - break; - } - case 2: { - v4l2_fmtdesc.flags = 0; - strcpy(&v4l2_fmtdesc.description[0], "rgb24"); - v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24; - JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); - break; - } - case 3: { - v4l2_fmtdesc.flags = 0; - strcpy(&v4l2_fmtdesc.description[0], "rgb32"); - v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32; - JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); - break; - } - case 4: { - v4l2_fmtdesc.flags = 0; - strcpy(&v4l2_fmtdesc.description[0], "bgr24"); - v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24; - JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); - break; - } - case 5: { - v4l2_fmtdesc.flags = 0; - strcpy(&v4l2_fmtdesc.description[0], "bgr32"); - v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32; - JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); - break; - } - default: { - JOM(8, "%i=index: exhausts formats\n", index); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - } - if (copy_to_user((void __user *)arg, &v4l2_fmtdesc, - sizeof(struct v4l2_fmtdesc))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -/* - * THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE - * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE. - */ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_ENUM_FRAMESIZES: { - u32 index; - struct v4l2_frmsizeenum v4l2_frmsizeenum; - - JOM(8, "VIDIOC_ENUM_FRAMESIZES\n"); - - if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, - sizeof(struct v4l2_frmsizeenum))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - index = v4l2_frmsizeenum.index; - - v4l2_frmsizeenum.type = (u32) V4L2_FRMSIZE_TYPE_DISCRETE; - - if (peasycap->ntsc) { - switch (index) { - case 0: { - v4l2_frmsizeenum.discrete.width = 640; - v4l2_frmsizeenum.discrete.height = 480; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - case 1: { - v4l2_frmsizeenum.discrete.width = 320; - v4l2_frmsizeenum.discrete.height = 240; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - case 2: { - v4l2_frmsizeenum.discrete.width = 720; - v4l2_frmsizeenum.discrete.height = 480; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - case 3: { - v4l2_frmsizeenum.discrete.width = 360; - v4l2_frmsizeenum.discrete.height = 240; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - default: { - JOM(8, "%i=index: exhausts framesizes\n", index); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - } - } else { - switch (index) { - case 0: { - v4l2_frmsizeenum.discrete.width = 640; - v4l2_frmsizeenum.discrete.height = 480; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - case 1: { - v4l2_frmsizeenum.discrete.width = 320; - v4l2_frmsizeenum.discrete.height = 240; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - case 2: { - v4l2_frmsizeenum.discrete.width = 704; - v4l2_frmsizeenum.discrete.height = 576; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - case 3: { - v4l2_frmsizeenum.discrete.width = 720; - v4l2_frmsizeenum.discrete.height = 576; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - case 4: { - v4l2_frmsizeenum.discrete.width = 360; - v4l2_frmsizeenum.discrete.height = 288; - JOM(8, "%i=index: %ix%i\n", index, - (int)(v4l2_frmsizeenum. - discrete.width), - (int)(v4l2_frmsizeenum. - discrete.height)); - break; - } - default: { - JOM(8, "%i=index: exhausts framesizes\n", index); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - } - } - if (copy_to_user((void __user *)arg, &v4l2_frmsizeenum, - sizeof(struct v4l2_frmsizeenum))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -/* - * THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE - * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE. - */ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_ENUM_FRAMEINTERVALS: { - u32 index; - int denominator; - struct v4l2_frmivalenum v4l2_frmivalenum; - - JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n"); - - if (peasycap->fps) - denominator = peasycap->fps; - else { - if (peasycap->ntsc) - denominator = 30; - else - denominator = 25; - } - - if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, - sizeof(struct v4l2_frmivalenum))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - index = v4l2_frmivalenum.index; - - v4l2_frmivalenum.type = (u32) V4L2_FRMIVAL_TYPE_DISCRETE; - - switch (index) { - case 0: { - v4l2_frmivalenum.discrete.numerator = 1; - v4l2_frmivalenum.discrete.denominator = denominator; - JOM(8, "%i=index: %i/%i\n", index, - (int)(v4l2_frmivalenum.discrete.numerator), - (int)(v4l2_frmivalenum.discrete.denominator)); - break; - } - case 1: { - v4l2_frmivalenum.discrete.numerator = 1; - v4l2_frmivalenum.discrete.denominator = denominator/5; - JOM(8, "%i=index: %i/%i\n", index, - (int)(v4l2_frmivalenum.discrete.numerator), - (int)(v4l2_frmivalenum.discrete.denominator)); - break; - } - default: { - JOM(8, "%i=index: exhausts frameintervals\n", index); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - } - if (copy_to_user((void __user *)arg, &v4l2_frmivalenum, - sizeof(struct v4l2_frmivalenum))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_FMT: { - struct v4l2_format *pv4l2_format; - struct v4l2_pix_format *pv4l2_pix_format; - - JOM(8, "VIDIOC_G_FMT\n"); - pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL); - if (!pv4l2_format) { - SAM("ERROR: out of memory\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ENOMEM; - } - pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL); - if (!pv4l2_pix_format) { - SAM("ERROR: out of memory\n"); - kfree(pv4l2_format); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ENOMEM; - } - if (0 != copy_from_user(pv4l2_format, (void __user *)arg, - sizeof(struct v4l2_format))) { - kfree(pv4l2_format); - kfree(pv4l2_pix_format); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - kfree(pv4l2_format); - kfree(pv4l2_pix_format); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - - memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); - pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memcpy(&pv4l2_format->fmt.pix, - &easycap_format[peasycap->format_offset] - .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format)); - JOM(8, "user is told: %s\n", - &easycap_format[peasycap->format_offset].name[0]); - - if (copy_to_user((void __user *)arg, pv4l2_format, - sizeof(struct v4l2_format))) { - kfree(pv4l2_format); - kfree(pv4l2_pix_format); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - kfree(pv4l2_format); - kfree(pv4l2_pix_format); - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: { - struct v4l2_format v4l2_format; - struct v4l2_pix_format v4l2_pix_format; - bool try; - int best_format; - - if (VIDIOC_TRY_FMT == cmd) { - JOM(8, "VIDIOC_TRY_FMT\n"); - try = true; - } else { - JOM(8, "VIDIOC_S_FMT\n"); - try = false; - } - - if (0 != copy_from_user(&v4l2_format, (void __user *)arg, - sizeof(struct v4l2_format))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - best_format = adjust_format(peasycap, - v4l2_format.fmt.pix.width, - v4l2_format.fmt.pix.height, - v4l2_format.fmt.pix.pixelformat, - v4l2_format.fmt.pix.field, - try); - if (0 > best_format) { - if (-EBUSY == best_format) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EBUSY; - } - JOM(8, "WARNING: adjust_format() returned %i\n", best_format); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ENOENT; - } -/*...........................................................................*/ - memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); - v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - memcpy(&(v4l2_format.fmt.pix), - &(easycap_format[best_format].v4l2_format.fmt.pix), - sizeof(v4l2_pix_format)); - JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]); - - if (copy_to_user((void __user *)arg, &v4l2_format, - sizeof(struct v4l2_format))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_CROPCAP: { - struct v4l2_cropcap v4l2_cropcap; - - JOM(8, "VIDIOC_CROPCAP\n"); - - if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, - sizeof(struct v4l2_cropcap))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); - - memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap)); - v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - v4l2_cropcap.bounds.left = 0; - v4l2_cropcap.bounds.top = 0; - v4l2_cropcap.bounds.width = peasycap->width; - v4l2_cropcap.bounds.height = peasycap->height; - v4l2_cropcap.defrect.left = 0; - v4l2_cropcap.defrect.top = 0; - v4l2_cropcap.defrect.width = peasycap->width; - v4l2_cropcap.defrect.height = peasycap->height; - v4l2_cropcap.pixelaspect.numerator = 1; - v4l2_cropcap.pixelaspect.denominator = 1; - - JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height); - - if (copy_to_user((void __user *)arg, &v4l2_cropcap, - sizeof(struct v4l2_cropcap))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_CROP: - case VIDIOC_S_CROP: { - JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_QUERYSTD: { - JOM(8, "VIDIOC_QUERYSTD: " - "EasyCAP is incapable of detecting standard\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - break; - } - /*-------------------------------------------------------------------*/ - /* - * THE MANIPULATIONS INVOLVING last0,last1,last2,last3 - * CONSTITUTE A WORKAROUND * FOR WHAT APPEARS TO BE - * A BUG IN 64-BIT mplayer. - * NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer. - */ - /*------------------------------------------------------------------*/ - case VIDIOC_ENUMSTD: { - int last0 = -1, last1 = -1, last2 = -1, last3 = -1; - struct v4l2_standard v4l2_standard; - u32 index; - struct easycap_standard const *peasycap_standard; - - JOM(8, "VIDIOC_ENUMSTD\n"); - - if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, - sizeof(struct v4l2_standard))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - index = v4l2_standard.index; - - last3 = last2; - last2 = last1; - last1 = last0; - last0 = index; - if ((index == last3) && (index == last2) && - (index == last1) && (index == last0)) { - index++; - last3 = last2; - last2 = last1; - last1 = last0; - last0 = index; - } - - memset(&v4l2_standard, 0, sizeof(struct v4l2_standard)); - - peasycap_standard = &easycap_standard[0]; - while (0xFFFF != peasycap_standard->mask) { - if ((int)(peasycap_standard - &easycap_standard[0]) == index) - break; - peasycap_standard++; - } - if (0xFFFF == peasycap_standard->mask) { - JOM(8, "%i=index: exhausts standards\n", index); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - JOM(8, "%i=index: %s\n", index, - &(peasycap_standard->v4l2_standard.name[0])); - memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard), - sizeof(struct v4l2_standard)); - - v4l2_standard.index = index; - - if (copy_to_user((void __user *)arg, &v4l2_standard, - sizeof(struct v4l2_standard))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_STD: { - v4l2_std_id std_id; - struct easycap_standard const *peasycap_standard; - - JOM(8, "VIDIOC_G_STD\n"); - - if (0 > peasycap->standard_offset) { - JOM(8, "%i=peasycap->standard_offset\n", - peasycap->standard_offset); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EBUSY; - } - - if (0 != copy_from_user(&std_id, (void __user *)arg, - sizeof(v4l2_std_id))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - peasycap_standard = &easycap_standard[peasycap->standard_offset]; - std_id = peasycap_standard->v4l2_standard.id; - - JOM(8, "user is told: %s\n", - &peasycap_standard->v4l2_standard.name[0]); - - if (copy_to_user((void __user *)arg, &std_id, - sizeof(v4l2_std_id))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_S_STD: { - v4l2_std_id std_id; - int rc; - - JOM(8, "VIDIOC_S_STD\n"); - - if (0 != copy_from_user(&std_id, (void __user *)arg, - sizeof(v4l2_std_id))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - JOM(8, "User requests standard: 0x%08X%08X\n", - (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), - (int)(std_id & ((v4l2_std_id)0xFFFFFFFF))); - - rc = adjust_standard(peasycap, std_id); - if (0 > rc) { - JOM(8, "WARNING: adjust_standard() returned %i\n", rc); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ENOENT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_REQBUFS: { - int nbuffers; - struct v4l2_requestbuffers v4l2_requestbuffers; - - JOM(8, "VIDIOC_REQBUFS\n"); - - if (0 != copy_from_user(&v4l2_requestbuffers, - (void __user *)arg, - sizeof(struct v4l2_requestbuffers))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - nbuffers = v4l2_requestbuffers.count; - JOM(8, " User requests %i buffers ...\n", nbuffers); - if (nbuffers < 2) - nbuffers = 2; - if (nbuffers > FRAME_BUFFER_MANY) - nbuffers = FRAME_BUFFER_MANY; - if (v4l2_requestbuffers.count == nbuffers) { - JOM(8, " ... agree to %i buffers\n", - nbuffers); - } else { - JOM(8, " ... insist on %i buffers\n", - nbuffers); - v4l2_requestbuffers.count = nbuffers; - } - peasycap->frame_buffer_many = nbuffers; - - if (copy_to_user((void __user *)arg, &v4l2_requestbuffers, - sizeof(struct v4l2_requestbuffers))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_QUERYBUF: { - u32 index; - struct v4l2_buffer v4l2_buffer; - - JOM(8, "VIDIOC_QUERYBUF\n"); - - if (peasycap->video_eof) { - JOM(8, "returning -EIO because %i=video_eof\n", - peasycap->video_eof); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EIO; - } - - if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, - sizeof(struct v4l2_buffer))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - index = v4l2_buffer.index; - if (index < 0 || index >= peasycap->frame_buffer_many) - return -EINVAL; - memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer)); - v4l2_buffer.index = index; - v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - v4l2_buffer.bytesused = peasycap->frame_buffer_used; - v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | - peasycap->done[index] | - peasycap->queued[index]; - v4l2_buffer.field = V4L2_FIELD_NONE; - v4l2_buffer.memory = V4L2_MEMORY_MMAP; - v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE; - v4l2_buffer.length = FRAME_BUFFER_SIZE; - - JOM(16, " %10i=index\n", v4l2_buffer.index); - JOM(16, " 0x%08X=type\n", v4l2_buffer.type); - JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused); - JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags); - JOM(16, " %10i=field\n", v4l2_buffer.field); - JOM(16, " %10li=timestamp.tv_usec\n", - (long)v4l2_buffer.timestamp.tv_usec); - JOM(16, " %10i=sequence\n", v4l2_buffer.sequence); - JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory); - JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset); - JOM(16, " %10i=length\n", v4l2_buffer.length); - - if (copy_to_user((void __user *)arg, &v4l2_buffer, - sizeof(struct v4l2_buffer))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_QBUF: { - struct v4l2_buffer v4l2_buffer; - - JOM(8, "VIDIOC_QBUF\n"); - - if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, - sizeof(struct v4l2_buffer))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - if (v4l2_buffer.index < 0 || - v4l2_buffer.index >= peasycap->frame_buffer_many) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED; - - peasycap->done[v4l2_buffer.index] = 0; - peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED; - - if (copy_to_user((void __user *)arg, &v4l2_buffer, - sizeof(struct v4l2_buffer))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - JOM(8, "..... user queueing frame buffer %i\n", - (int)v4l2_buffer.index); - - peasycap->frame_lock = 0; - - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_DQBUF: - { - struct timeval timeval, timeval2; - int i, j; - struct v4l2_buffer v4l2_buffer; - int rcdq; - u16 input; - - JOM(8, "VIDIOC_DQBUF\n"); - - if ((peasycap->video_idle) || (peasycap->video_eof)) { - JOM(8, "returning -EIO because " - "%i=video_idle %i=video_eof\n", - peasycap->video_idle, peasycap->video_eof); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EIO; - } - - if (copy_from_user(&v4l2_buffer, (void __user *)arg, - sizeof(struct v4l2_buffer))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - - if (peasycap->offerfields) { - /*---------------------------------------------------*/ - /* - * IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST - * V4L2_FIELD_BOTTOM - */ - /*---------------------------------------------------*/ - if (V4L2_FIELD_TOP == v4l2_buffer.field) - JOM(8, "user wants V4L2_FIELD_TOP\n"); - else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field) - JOM(8, "user wants V4L2_FIELD_BOTTOM\n"); - else if (V4L2_FIELD_ANY == v4l2_buffer.field) - JOM(8, "user wants V4L2_FIELD_ANY\n"); - else - JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n", - v4l2_buffer.field); - } - - if (!peasycap->video_isoc_streaming) { - JOM(16, "returning -EIO because video urbs not streaming\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EIO; - } - /*-------------------------------------------------------------------*/ - /* - * IF THE USER HAS PREVIOUSLY CALLED easycap_poll(), - * AS DETERMINED BY FINDING - * THE FLAG peasycap->polled SET, THERE MUST BE - * NO FURTHER WAIT HERE. IN THIS - * CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read - */ - /*-------------------------------------------------------------------*/ - - if (!peasycap->polled) { - do { - rcdq = easycap_video_dqbuf(peasycap, 0); - if (-EIO == rcdq) { - JOM(8, "returning -EIO because " - "dqbuf() returned -EIO\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EIO; - } - } while (0 != rcdq); - } else { - if (peasycap->video_eof) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EIO; - } - } - if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) { - JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n", - peasycap->done[peasycap->frame_read]); - } - peasycap->polled = 0; - - if (!(peasycap->isequence % 10)) { - for (i = 0; i < 179; i++) - peasycap->merit[i] = peasycap->merit[i+1]; - peasycap->merit[179] = merit_saa(peasycap->pusb_device); - j = 0; - for (i = 0; i < 180; i++) - j += peasycap->merit[i]; - if (90 < j) { - SAM("easycap driver shutting down " - "on condition blue\n"); - peasycap->video_eof = 1; - peasycap->audio_eof = 1; - } - } - - v4l2_buffer.index = peasycap->frame_read; - v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - v4l2_buffer.bytesused = peasycap->frame_buffer_used; - v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; - if (peasycap->offerfields) - v4l2_buffer.field = V4L2_FIELD_BOTTOM; - else - v4l2_buffer.field = V4L2_FIELD_NONE; - do_gettimeofday(&timeval); - timeval2 = timeval; - - v4l2_buffer.timestamp = timeval2; - v4l2_buffer.sequence = peasycap->isequence++; - v4l2_buffer.memory = V4L2_MEMORY_MMAP; - v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE; - v4l2_buffer.length = FRAME_BUFFER_SIZE; - - JOM(16, " %10i=index\n", v4l2_buffer.index); - JOM(16, " 0x%08X=type\n", v4l2_buffer.type); - JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused); - JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags); - JOM(16, " %10i=field\n", v4l2_buffer.field); - JOM(16, " %10li=timestamp.tv_sec\n", - (long)v4l2_buffer.timestamp.tv_sec); - JOM(16, " %10li=timestamp.tv_usec\n", - (long)v4l2_buffer.timestamp.tv_usec); - JOM(16, " %10i=sequence\n", v4l2_buffer.sequence); - JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory); - JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset); - JOM(16, " %10i=length\n", v4l2_buffer.length); - - if (copy_to_user((void __user *)arg, &v4l2_buffer, - sizeof(struct v4l2_buffer))) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - input = peasycap->frame_buffer[peasycap->frame_read][0].input; - if (0x08 & input) { - JOM(8, "user is offered frame buffer %i, input %i\n", - peasycap->frame_read, (0x07 & input)); - } else { - JOM(8, "user is offered frame buffer %i\n", - peasycap->frame_read); - } - peasycap->frame_lock = 1; - JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill); - if (peasycap->frame_read == peasycap->frame_fill) { - if (peasycap->frame_lock) { - JOM(8, "WORRY: filling frame buffer " - "while offered to user\n"); - } - } - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_STREAMON: { - int i; - - JOM(8, "VIDIOC_STREAMON\n"); - - peasycap->isequence = 0; - for (i = 0; i < 180; i++) - peasycap->merit[i] = 0; - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - easycap_video_submit_urbs(peasycap); - peasycap->video_idle = 0; - peasycap->audio_idle = 0; - peasycap->video_eof = 0; - peasycap->audio_eof = 0; - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_STREAMOFF: { - JOM(8, "VIDIOC_STREAMOFF\n"); - - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - - peasycap->video_idle = 1; - peasycap->audio_idle = 1; -/*---------------------------------------------------------------------------*/ -/* - * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND - * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE. - */ -/*---------------------------------------------------------------------------*/ - JOM(8, "calling wake_up on wq_video and wq_audio\n"); - wake_up_interruptible(&(peasycap->wq_video)); - if (peasycap->psubstream) - snd_pcm_period_elapsed(peasycap->psubstream); - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_PARM: { - struct v4l2_streamparm *pv4l2_streamparm; - - JOM(8, "VIDIOC_G_PARM\n"); - pv4l2_streamparm = memdup_user((void __user *)arg, - sizeof(struct v4l2_streamparm)); - if (IS_ERR(pv4l2_streamparm)) { - SAM("ERROR: copy from user failed\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return PTR_ERR(pv4l2_streamparm); - } - - if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - kfree(pv4l2_streamparm); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - pv4l2_streamparm->parm.capture.capability = 0; - pv4l2_streamparm->parm.capture.capturemode = 0; - pv4l2_streamparm->parm.capture.timeperframe.numerator = 1; - - if (peasycap->fps) { - pv4l2_streamparm->parm.capture.timeperframe. - denominator = peasycap->fps; - } else { - if (peasycap->ntsc) { - pv4l2_streamparm->parm.capture.timeperframe. - denominator = 30; - } else { - pv4l2_streamparm->parm.capture.timeperframe. - denominator = 25; - } - } - - pv4l2_streamparm->parm.capture.readbuffers = - peasycap->frame_buffer_many; - pv4l2_streamparm->parm.capture.extendedmode = 0; - if (copy_to_user((void __user *)arg, - pv4l2_streamparm, - sizeof(struct v4l2_streamparm))) { - kfree(pv4l2_streamparm); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EFAULT; - } - kfree(pv4l2_streamparm); - break; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_S_PARM: { - JOM(8, "VIDIOC_S_PARM unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_AUDIO: { - JOM(8, "VIDIOC_G_AUDIO unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_S_AUDIO: { - JOM(8, "VIDIOC_S_AUDIO unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_S_TUNER: { - JOM(8, "VIDIOC_S_TUNER unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_FBUF: - case VIDIOC_S_FBUF: - case VIDIOC_OVERLAY: { - JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - case VIDIOC_G_TUNER: { - JOM(8, "VIDIOC_G_TUNER unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: { - JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -EINVAL; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - default: { - JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ENOIOCTLCMD; - } - } - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd); - return 0; -} -/*****************************************************************************/ diff --git a/drivers/staging/media/easycap/easycap_low.c b/drivers/staging/media/easycap/easycap_low.c deleted file mode 100644 index 0380bab..0000000 --- a/drivers/staging/media/easycap/easycap_low.c +++ /dev/null @@ -1,968 +0,0 @@ -/***************************************************************************** -* * -* * -* easycap_low.c * -* * -* * -*****************************************************************************/ -/* - * - * Copyright (C) 2010 R.M. Thomas rmthomas@sciolus.org - * - * - * This 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. - * - * The software 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 software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ -/*****************************************************************************/ -/* - * ACKNOWLEGEMENTS AND REFERENCES - * ------------------------------ - * This driver makes use of register information contained in the Syntek - * Semicon DC-1125 driver hosted at - * http://sourceforge.net/projects/syntekdriver/. - * Particularly useful has been a patch to the latter driver provided by - * Ivor Hewitt in January 2009. The NTSC implementation is taken from the - * work of Ben Trask. -*/ -/****************************************************************************/ - -#include "easycap.h" - - -#define GET(X, Y, Z) do { \ - int __rc; \ - *(Z) = (u16)0; \ - __rc = regget(X, Y, Z, sizeof(u8)); \ - if (0 > __rc) { \ - JOT(8, ":-(%i\n", __LINE__); return __rc; \ - } \ -} while (0) - -#define SET(X, Y, Z) do { \ - int __rc; \ - __rc = regset(X, Y, Z); \ - if (0 > __rc) { \ - JOT(8, ":-(%i\n", __LINE__); return __rc; \ - } \ -} while (0) - -/*--------------------------------------------------------------------------*/ -static const struct stk1160config { - u16 reg; - u16 set; -} stk1160configPAL[] = { - {0x000, 0x0098}, - {0x002, 0x0093}, - - {0x001, 0x0003}, - {0x003, 0x0080}, - {0x00D, 0x0000}, - {0x00F, 0x0002}, - {0x018, 0x0010}, - {0x019, 0x0000}, - {0x01A, 0x0014}, - {0x01B, 0x000E}, - {0x01C, 0x0046}, - - {0x100, 0x0033}, - {0x103, 0x0000}, - {0x104, 0x0000}, - {0x105, 0x0000}, - {0x106, 0x0000}, - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -/* - * RESOLUTION 640x480 -*/ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - {0x110, 0x0008}, - {0x111, 0x0000}, - {0x112, 0x0020}, - {0x113, 0x0000}, - {0x114, 0x0508}, - {0x115, 0x0005}, - {0x116, 0x0110}, - {0x117, 0x0001}, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - {0x202, 0x000F}, - {0x203, 0x004A}, - {0x2FF, 0x0000}, - - {0xFFF, 0xFFFF} -}; -/*--------------------------------------------------------------------------*/ -static const struct stk1160config stk1160configNTSC[] = { - {0x000, 0x0098}, - {0x002, 0x0093}, - - {0x001, 0x0003}, - {0x003, 0x0080}, - {0x00D, 0x0000}, - {0x00F, 0x0002}, - {0x018, 0x0010}, - {0x019, 0x0000}, - {0x01A, 0x0014}, - {0x01B, 0x000E}, - {0x01C, 0x0046}, - - {0x100, 0x0033}, - {0x103, 0x0000}, - {0x104, 0x0000}, - {0x105, 0x0000}, - {0x106, 0x0000}, - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -/* - * RESOLUTION 640x480 -*/ -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - {0x110, 0x0008}, - {0x111, 0x0000}, - {0x112, 0x0003}, - {0x113, 0x0000}, - {0x114, 0x0508}, - {0x115, 0x0005}, - {0x116, 0x00F3}, - {0x117, 0x0000}, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - {0x202, 0x000F}, - {0x203, 0x004A}, - {0x2FF, 0x0000}, - - {0xFFF, 0xFFFF} -}; -/*--------------------------------------------------------------------------*/ -static const struct saa7113config { - u8 reg; - u8 set; -} saa7113configPAL[] = { - {0x01, 0x08}, - {0x02, 0x80}, - {0x03, 0x33}, - {0x04, 0x00}, - {0x05, 0x00}, - {0x06, 0xE9}, - {0x07, 0x0D}, - {0x08, 0x38}, - {0x09, 0x00}, - {0x0A, SAA_0A_DEFAULT}, - {0x0B, SAA_0B_DEFAULT}, - {0x0C, SAA_0C_DEFAULT}, - {0x0D, SAA_0D_DEFAULT}, - {0x0E, 0x01}, - {0x0F, 0x36}, - {0x10, 0x00}, - {0x11, 0x0C}, - {0x12, 0xE7}, - {0x13, 0x00}, - {0x15, 0x00}, - {0x16, 0x00}, - {0x40, 0x02}, - {0x41, 0xFF}, - {0x42, 0xFF}, - {0x43, 0xFF}, - {0x44, 0xFF}, - {0x45, 0xFF}, - {0x46, 0xFF}, - {0x47, 0xFF}, - {0x48, 0xFF}, - {0x49, 0xFF}, - {0x4A, 0xFF}, - {0x4B, 0xFF}, - {0x4C, 0xFF}, - {0x4D, 0xFF}, - {0x4E, 0xFF}, - {0x4F, 0xFF}, - {0x50, 0xFF}, - {0x51, 0xFF}, - {0x52, 0xFF}, - {0x53, 0xFF}, - {0x54, 0xFF}, - {0x55, 0xFF}, - {0x56, 0xFF}, - {0x57, 0xFF}, - {0x58, 0x40}, - {0x59, 0x54}, - {0x5A, 0x07}, - {0x5B, 0x83}, - - {0xFF, 0xFF} -}; -/*--------------------------------------------------------------------------*/ -static const struct saa7113config saa7113configNTSC[] = { - {0x01, 0x08}, - {0x02, 0x80}, - {0x03, 0x33}, - {0x04, 0x00}, - {0x05, 0x00}, - {0x06, 0xE9}, - {0x07, 0x0D}, - {0x08, 0x78}, - {0x09, 0x00}, - {0x0A, SAA_0A_DEFAULT}, - {0x0B, SAA_0B_DEFAULT}, - {0x0C, SAA_0C_DEFAULT}, - {0x0D, SAA_0D_DEFAULT}, - {0x0E, 0x01}, - {0x0F, 0x36}, - {0x10, 0x00}, - {0x11, 0x0C}, - {0x12, 0xE7}, - {0x13, 0x00}, - {0x15, 0x00}, - {0x16, 0x00}, - {0x40, 0x82}, - {0x41, 0xFF}, - {0x42, 0xFF}, - {0x43, 0xFF}, - {0x44, 0xFF}, - {0x45, 0xFF}, - {0x46, 0xFF}, - {0x47, 0xFF}, - {0x48, 0xFF}, - {0x49, 0xFF}, - {0x4A, 0xFF}, - {0x4B, 0xFF}, - {0x4C, 0xFF}, - {0x4D, 0xFF}, - {0x4E, 0xFF}, - {0x4F, 0xFF}, - {0x50, 0xFF}, - {0x51, 0xFF}, - {0x52, 0xFF}, - {0x53, 0xFF}, - {0x54, 0xFF}, - {0x55, 0xFF}, - {0x56, 0xFF}, - {0x57, 0xFF}, - {0x58, 0x40}, - {0x59, 0x54}, - {0x5A, 0x0A}, - {0x5B, 0x83}, - - {0xFF, 0xFF} -}; - -static int regget(struct usb_device *pusb_device, - u16 index, void *reg, int reg_size) -{ - int rc; - - if (!pusb_device) - return -ENODEV; - - rc = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), - 0x00, - (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), - 0x00, - index, reg, reg_size, 50000); - - return rc; -} - -static int regset(struct usb_device *pusb_device, u16 index, u16 value) -{ - int rc; - - if (!pusb_device) - return -ENODEV; - - rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), - 0x01, - (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), - value, index, NULL, 0, 500); - - if (rc < 0) - return rc; - - if (easycap_readback) { - u16 igot = 0; - rc = regget(pusb_device, index, &igot, sizeof(igot)); - igot = 0xFF & igot; - switch (index) { - case 0x000: - case 0x500: - case 0x502: - case 0x503: - case 0x504: - case 0x506: - case 0x507: - break; - - case 0x204: - case 0x205: - case 0x350: - case 0x351: - if (igot) - JOT(8, "unexpected 0x%02X " - "for STK register 0x%03X\n", - igot, index); - break; - - default: - if ((0xFF & value) != igot) - JOT(8, "unexpected 0x%02X != 0x%02X " - "for STK register 0x%03X\n", - igot, value, index); - break; - } - } - - return rc; -} -/*--------------------------------------------------------------------------*/ -/* - * FUNCTION wait_i2c() RETURNS 0 ON SUCCESS -*/ -/*--------------------------------------------------------------------------*/ -static int wait_i2c(struct usb_device *p) -{ - u16 get0; - u8 igot; - const int max = 2; - int k; - - if (!p) - return -ENODEV; - - for (k = 0; k < max; k++) { - GET(p, 0x0201, &igot); get0 = igot; - switch (get0) { - case 0x04: - case 0x01: - return 0; - case 0x00: - msleep(20); - continue; - default: - return get0 - 1; - } - } - return -1; -} - -/****************************************************************************/ -int write_saa(struct usb_device *p, u16 reg0, u16 set0) -{ - if (!p) - return -ENODEV; - SET(p, 0x200, 0x00); - SET(p, 0x204, reg0); - SET(p, 0x205, set0); - SET(p, 0x200, 0x01); - return wait_i2c(p); -} -/****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?) - * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A - * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO SET - * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO SET - * REGISTER 504: TARGET ADDRESS ON VT1612A - */ -/*--------------------------------------------------------------------------*/ -static int write_vt(struct usb_device *p, u16 reg0, u16 set0) -{ - u8 igot; - u16 got502, got503; - u16 set502, set503; - - if (!p) - return -ENODEV; - SET(p, 0x0504, reg0); - SET(p, 0x0500, 0x008B); - - GET(p, 0x0502, &igot); got502 = (0xFF & igot); - GET(p, 0x0503, &igot); got503 = (0xFF & igot); - - JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n", - reg0, set0, ((got503 << 8) | got502)); - - set502 = (0x00FF & set0); - set503 = ((0xFF00 & set0) >> 8); - - SET(p, 0x0504, reg0); - SET(p, 0x0502, set502); - SET(p, 0x0503, set503); - SET(p, 0x0500, 0x008C); - - return 0; -} -/****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?) - * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A - * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO GET - * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO GET - * REGISTER 504: TARGET ADDRESS ON VT1612A - */ -/*--------------------------------------------------------------------------*/ -static int read_vt(struct usb_device *p, u16 reg0) -{ - u8 igot; - u16 got502, got503; - - if (!p) - return -ENODEV; - SET(p, 0x0504, reg0); - SET(p, 0x0500, 0x008B); - - GET(p, 0x0502, &igot); got502 = (0xFF & igot); - GET(p, 0x0503, &igot); got503 = (0xFF & igot); - - JOT(16, "read_vt(., 0x%04X): has 0x%04X\n", - reg0, ((got503 << 8) | got502)); - - return (got503 << 8) | got502; -} -/****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO. - */ -/*--------------------------------------------------------------------------*/ -static int write_300(struct usb_device *p) -{ - if (!p) - return -ENODEV; - SET(p, 0x300, 0x0012); - SET(p, 0x350, 0x002D); - SET(p, 0x351, 0x0001); - SET(p, 0x352, 0x0000); - SET(p, 0x353, 0x0000); - SET(p, 0x300, 0x0080); - return 0; -} -/****************************************************************************/ -/****************************************************************************/ -int setup_stk(struct usb_device *p, bool ntsc) -{ - int i; - const struct stk1160config *cfg; - if (!p) - return -ENODEV; - cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL; - for (i = 0; cfg[i].reg != 0xFFF; i++) - SET(p, cfg[i].reg, cfg[i].set); - - write_300(p); - - return 0; -} -/****************************************************************************/ -int setup_saa(struct usb_device *p, bool ntsc) -{ - int i, rc; - const struct saa7113config *cfg; - if (!p) - return -ENODEV; - cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL; - for (i = 0; cfg[i].reg != 0xFF; i++) { - rc = write_saa(p, cfg[i].reg, cfg[i].set); - if (rc) - dev_err(&p->dev, - "Failed to set SAA register %d", cfg[i].reg); - } - return 0; -} -/****************************************************************************/ -int merit_saa(struct usb_device *p) -{ - int rc; - - if (!p) - return -ENODEV; - rc = read_saa(p, 0x1F); - return ((0 > rc) || (0x02 & rc)) ? 1 : 0; -} -/****************************************************************************/ -int ready_saa(struct usb_device *p) -{ - int j, rc, rate; - const int max = 5, marktime = PATIENCE/5; -/*--------------------------------------------------------------------------*/ -/* - * RETURNS 0 FOR INTERLACED 50 Hz - * 1 FOR NON-INTERLACED 50 Hz - * 2 FOR INTERLACED 60 Hz - * 3 FOR NON-INTERLACED 60 Hz -*/ -/*--------------------------------------------------------------------------*/ - if (!p) - return -ENODEV; - j = 0; - while (max > j) { - rc = read_saa(p, 0x1F); - if (0 <= rc) { - if (0 == (0x40 & rc)) - break; - if (1 == (0x01 & rc)) - break; - } - msleep(marktime); - j++; - } - - if (max == j) - return -1; - - if (0x20 & rc) { - rate = 2; - JOT(8, "hardware detects 60 Hz\n"); - } else { - rate = 0; - JOT(8, "hardware detects 50 Hz\n"); - } - if (0x80 & rc) - JOT(8, "hardware detects interlacing\n"); - else { - rate++; - JOT(8, "hardware detects no interlacing\n"); - } - return 0; -} -/****************************************************************************/ -int read_saa(struct usb_device *p, u16 reg0) -{ - u8 igot; - - if (!p) - return -ENODEV; - SET(p, 0x208, reg0); - SET(p, 0x200, 0x20); - if (0 != wait_i2c(p)) - return -1; - igot = 0; - GET(p, 0x0209, &igot); - return igot; -} -/****************************************************************************/ -static int read_stk(struct usb_device *p, u32 reg0) -{ - u8 igot; - - if (!p) - return -ENODEV; - igot = 0; - GET(p, reg0, &igot); - return igot; -} -int select_input(struct usb_device *p, int input, int mode) -{ - int ir; - - if (!p) - return -ENODEV; - stop_100(p); - switch (input) { - case 0: - case 1: { - if (0 != write_saa(p, 0x02, 0x80)) - SAY("ERROR: failed to set SAA register 0x02 " - "for input %i\n", input); - - SET(p, 0x0000, 0x0098); - SET(p, 0x0002, 0x0078); - break; - } - case 2: { - if (0 != write_saa(p, 0x02, 0x80)) - SAY("ERROR: failed to set SAA register 0x02 " - "for input %i\n", input); - - SET(p, 0x0000, 0x0090); - SET(p, 0x0002, 0x0078); - break; - } - case 3: { - if (0 != write_saa(p, 0x02, 0x80)) - SAY("ERROR: failed to set SAA register 0x02 " - " for input %i\n", input); - - SET(p, 0x0000, 0x0088); - SET(p, 0x0002, 0x0078); - break; - } - case 4: { - if (0 != write_saa(p, 0x02, 0x80)) { - SAY("ERROR: failed to set SAA register 0x02 " - "for input %i\n", input); - } - SET(p, 0x0000, 0x0080); - SET(p, 0x0002, 0x0078); - break; - } - case 5: { - if (9 != mode) - mode = 7; - switch (mode) { - case 7: { - if (0 != write_saa(p, 0x02, 0x87)) - SAY("ERROR: failed to set SAA register 0x02 " - "for input %i\n", input); - - if (0 != write_saa(p, 0x05, 0xFF)) - SAY("ERROR: failed to set SAA register 0x05 " - "for input %i\n", input); - - break; - } - case 9: { - if (0 != write_saa(p, 0x02, 0x89)) - SAY("ERROR: failed to set SAA register 0x02 " - "for input %i\n", input); - - if (0 != write_saa(p, 0x05, 0x00)) - SAY("ERROR: failed to set SAA register 0x05 " - "for input %i\n", input); - - break; - } - default: - SAY("MISTAKE: bad mode: %i\n", mode); - return -1; - } - - if (0 != write_saa(p, 0x04, 0x00)) - SAY("ERROR: failed to set SAA register 0x04 " - "for input %i\n", input); - - if (0 != write_saa(p, 0x09, 0x80)) - SAY("ERROR: failed to set SAA register 0x09 " - "for input %i\n", input); - - SET(p, 0x0002, 0x0093); - break; - } - default: - SAY("ERROR: bad input: %i\n", input); - return -1; - } - - ir = read_stk(p, 0x00); - JOT(8, "STK register 0x00 has 0x%02X\n", ir); - ir = read_saa(p, 0x02); - JOT(8, "SAA register 0x02 has 0x%02X\n", ir); - - start_100(p); - - return 0; -} -/****************************************************************************/ -int set_resolution(struct usb_device *p, - u16 set0, u16 set1, u16 set2, u16 set3) -{ - u16 u0x0111, u0x0113, u0x0115, u0x0117; - - if (!p) - return -ENODEV; - u0x0111 = ((0xFF00 & set0) >> 8); - u0x0113 = ((0xFF00 & set1) >> 8); - u0x0115 = ((0xFF00 & set2) >> 8); - u0x0117 = ((0xFF00 & set3) >> 8); - - SET(p, 0x0110, (0x00FF & set0)); - SET(p, 0x0111, u0x0111); - SET(p, 0x0112, (0x00FF & set1)); - SET(p, 0x0113, u0x0113); - SET(p, 0x0114, (0x00FF & set2)); - SET(p, 0x0115, u0x0115); - SET(p, 0x0116, (0x00FF & set3)); - SET(p, 0x0117, u0x0117); - - return 0; -} -/****************************************************************************/ -int start_100(struct usb_device *p) -{ - u16 get116, get117, get0; - u8 igot116, igot117, igot; - - if (!p) - return -ENODEV; - GET(p, 0x0116, &igot116); - get116 = igot116; - GET(p, 0x0117, &igot117); - get117 = igot117; - SET(p, 0x0116, 0x0000); - SET(p, 0x0117, 0x0000); - - GET(p, 0x0100, &igot); - get0 = igot; - SET(p, 0x0100, (0x80 | get0)); - - SET(p, 0x0116, get116); - SET(p, 0x0117, get117); - - return 0; -} -/****************************************************************************/ -int stop_100(struct usb_device *p) -{ - u16 get0; - u8 igot; - - if (!p) - return -ENODEV; - GET(p, 0x0100, &igot); - get0 = igot; - SET(p, 0x0100, (0x7F & get0)); - return 0; -} -/****************************************************************************/ -/****************************************************************************/ -/*****************************************************************************/ -int easycap_wakeup_device(struct usb_device *pusb_device) -{ - if (!pusb_device) - return -ENODEV; - - return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), - USB_REQ_SET_FEATURE, - USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, - 0, NULL, 0, 50000); -} -/*****************************************************************************/ -int easycap_audio_setup(struct easycap *peasycap) -{ - struct usb_device *pusb_device; - u8 buffer[1]; - int rc, id1, id2; -/*---------------------------------------------------------------------------*/ -/* - * IMPORTANT: - * THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) - * CAUSES MUTING IF THE VALUE 0x0100 IS SENT. - * TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT. - */ -/*---------------------------------------------------------------------------*/ - const u8 request = 0x01; - const u8 requesttype = USB_DIR_OUT | - USB_TYPE_CLASS | - USB_RECIP_INTERFACE; - const u16 value_unmute = 0x0200; - const u16 index = 0x0301; - const u16 length = 1; - - if (!peasycap) - return -EFAULT; - - pusb_device = peasycap->pusb_device; - if (!pusb_device) - return -ENODEV; - - JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n", - requesttype, request, - (0x00FF & value_unmute), - (0xFF00 & value_unmute) >> 8, - (0x00FF & index), - (0xFF00 & index) >> 8, - (0x00FF & length), - (0xFF00 & length) >> 8); - - buffer[0] = 0x01; - - rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), - request, requesttype, value_unmute, - index, &buffer[0], length, 50000); - - JOT(8, "0x%02X=buffer\n", buffer[0]); - if (rc != (int)length) { - switch (rc) { - case -EPIPE: - SAY("usb_control_msg returned -EPIPE\n"); - break; - default: - SAY("ERROR: usb_control_msg returned %i\n", rc); - break; - } - } -/*--------------------------------------------------------------------------*/ -/* - * REGISTER 500: SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ??? - * REGISTER 506: ANALOGUE AUDIO ATTENTUATOR ??? - * FOR THE CVBS+S-VIDEO HARDWARE: - * SETTING VALUE TO 0x0000 GIVES QUIET SOUND. - * THE UPPER BYTE SEEMS TO HAVE NO EFFECT. - * FOR THE FOUR-CVBS HARDWARE: - * SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT. - * REGISTER 507: ANALOGUE AUDIO PREAMPLIFIER ON/OFF ??? - * FOR THE CVBS-S-VIDEO HARDWARE: - * SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND. - * THE UPPER BYTE SEEMS TO HAVE NO EFFECT. - */ -/*--------------------------------------------------------------------------*/ - SET(pusb_device, 0x0500, 0x0094); - SET(pusb_device, 0x0500, 0x008C); - SET(pusb_device, 0x0506, 0x0001); - SET(pusb_device, 0x0507, 0x0000); - id1 = read_vt(pusb_device, 0x007C); - id2 = read_vt(pusb_device, 0x007E); - SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2); -/*---------------------------------------------------------------------------*/ -/* - * SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN. -*/ -/*---------------------------------------------------------------------------*/ - if (easycap_audio_gainset(pusb_device, peasycap->gain)) - SAY("ERROR: audio_gainset() failed\n"); - check_vt(pusb_device); - return 0; -} -/*****************************************************************************/ -int check_vt(struct usb_device *pusb_device) -{ - int igot; - - if (!pusb_device) - return -ENODEV; - igot = read_vt(pusb_device, 0x0002); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x02\n"); - if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x02); - - igot = read_vt(pusb_device, 0x000E); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x0E\n"); - if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x0E); - - igot = read_vt(pusb_device, 0x0010); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x10\n"); - if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x10); - - igot = read_vt(pusb_device, 0x0012); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x12\n"); - if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x12); - - igot = read_vt(pusb_device, 0x0014); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x14\n"); - if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x14); - - igot = read_vt(pusb_device, 0x0016); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x16\n"); - if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x16); - - igot = read_vt(pusb_device, 0x0018); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x18\n"); - if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x18); - - igot = read_vt(pusb_device, 0x001C); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x1C\n"); - if (0x8000 & igot) - SAY("register 0x%02X muted\n", 0x1C); - - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY: - * audio_gainset(pusb_device, 0x000F); - * - * loud dB register 0x10 dB register 0x1C dB total - * 0 -34.5 0 -34.5 - * .. .... . .... - * 15 10.5 0 10.5 - * 16 12.0 0 12.0 - * 17 12.0 1.5 13.5 - * .. .... .... .... - * 31 12.0 22.5 34.5 -*/ -/*---------------------------------------------------------------------------*/ -int easycap_audio_gainset(struct usb_device *pusb_device, s8 loud) -{ - int igot; - u8 tmp; - u16 mute; - - if (!pusb_device) - return -ENODEV; - if (0 > loud) - loud = 0; - if (31 < loud) - loud = 31; - - write_vt(pusb_device, 0x0002, 0x8000); -/*---------------------------------------------------------------------------*/ - igot = read_vt(pusb_device, 0x000E); - if (0 > igot) { - SAY("ERROR: failed to read VT1612A register 0x0E\n"); - mute = 0x0000; - } else - mute = 0x8000 & ((unsigned int)igot); - mute = 0; - - if (16 > loud) - tmp = 0x01 | (0x001F & (((u8)(15 - loud)) << 1)); - else - tmp = 0; - - JOT(8, "0x%04X=(mute|tmp) for VT1612A register 0x0E\n", mute | tmp); - write_vt(pusb_device, 0x000E, (mute | tmp)); -/*---------------------------------------------------------------------------*/ - igot = read_vt(pusb_device, 0x0010); - if (0 > igot) { - SAY("ERROR: failed to read VT1612A register 0x10\n"); - mute = 0x0000; - } else - mute = 0x8000 & ((unsigned int)igot); - mute = 0; - - JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x10,...0x18\n", - mute | tmp | (tmp << 8)); - write_vt(pusb_device, 0x0010, (mute | tmp | (tmp << 8))); - write_vt(pusb_device, 0x0012, (mute | tmp | (tmp << 8))); - write_vt(pusb_device, 0x0014, (mute | tmp | (tmp << 8))); - write_vt(pusb_device, 0x0016, (mute | tmp | (tmp << 8))); - write_vt(pusb_device, 0x0018, (mute | tmp | (tmp << 8))); -/*---------------------------------------------------------------------------*/ - igot = read_vt(pusb_device, 0x001C); - if (0 > igot) { - SAY("ERROR: failed to read VT1612A register 0x1C\n"); - mute = 0x0000; - } else - mute = 0x8000 & ((unsigned int)igot); - mute = 0; - - if (16 <= loud) - tmp = 0x000F & (u8)(loud - 16); - else - tmp = 0; - - JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x1C\n", - mute | tmp | (tmp << 8)); - write_vt(pusb_device, 0x001C, (mute | tmp | (tmp << 8))); - write_vt(pusb_device, 0x001A, 0x0404); - write_vt(pusb_device, 0x0002, 0x0000); - return 0; -} -/*****************************************************************************/ diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c deleted file mode 100644 index aed9537..0000000 --- a/drivers/staging/media/easycap/easycap_main.c +++ /dev/null @@ -1,4235 +0,0 @@ -/****************************************************************************** -* * -* easycap_main.c * -* * -* Video driver for EasyCAP USB2.0 Video Capture Device DC60 * -* * -* * -******************************************************************************/ -/* - * - * Copyright (C) 2010 R.M. Thomas rmthomas@sciolus.org - * - * - * This 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. - * - * The software 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 software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ -/*****************************************************************************/ - -#include "easycap.h" -#include <linux/usb/audio.h> - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("R.M. Thomas rmthomas@sciolus.org"); -MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION); -MODULE_VERSION(EASYCAP_DRIVER_VERSION); - -#ifdef CONFIG_EASYCAP_DEBUG -int easycap_debug; -module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug level: 0(default),1,2,...,9"); -#endif /* CONFIG_EASYCAP_DEBUG */ - -bool easycap_readback; -module_param_named(readback, easycap_readback, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(readback, "read back written registers: (default false)"); - -static int easycap_bars = 1; -module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(bars, - "Testcard bars on input signal failure: 0=>no, 1=>yes(default)"); - -static int easycap_gain = 16; -module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(gain, "Audio gain: 0,...,16(default),...31"); - -static bool easycap_ntsc; -module_param_named(ntsc, easycap_ntsc, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ntsc, "NTSC default encoding (default PAL)"); - - - -struct easycap_dongle easycapdc60_dongle[DONGLE_MANY]; -static struct mutex mutex_dongle; -static void easycap_complete(struct urb *purb); -static int reset(struct easycap *peasycap); -static int field2frame(struct easycap *peasycap); -static int redaub(struct easycap *peasycap, - void *pad, void *pex, int much, int more, - u8 mask, u8 margin, bool isuy); - -const char *strerror(int err) -{ -#define ERRNOSTR(_e) case _e: return # _e - switch (err) { - case 0: return "OK"; - ERRNOSTR(ENOMEM); - ERRNOSTR(ENODEV); - ERRNOSTR(ENXIO); - ERRNOSTR(EINVAL); - ERRNOSTR(EAGAIN); - ERRNOSTR(EFBIG); - ERRNOSTR(EPIPE); - ERRNOSTR(EMSGSIZE); - ERRNOSTR(ENOSPC); - ERRNOSTR(EINPROGRESS); - ERRNOSTR(ENOSR); - ERRNOSTR(EOVERFLOW); - ERRNOSTR(EPROTO); - ERRNOSTR(EILSEQ); - ERRNOSTR(ETIMEDOUT); - ERRNOSTR(EOPNOTSUPP); - ERRNOSTR(EPFNOSUPPORT); - ERRNOSTR(EAFNOSUPPORT); - ERRNOSTR(EADDRINUSE); - ERRNOSTR(EADDRNOTAVAIL); - ERRNOSTR(ENOBUFS); - ERRNOSTR(EISCONN); - ERRNOSTR(ENOTCONN); - ERRNOSTR(ESHUTDOWN); - ERRNOSTR(ENOENT); - ERRNOSTR(ECONNRESET); - ERRNOSTR(ETIME); - ERRNOSTR(ECOMM); - ERRNOSTR(EREMOTEIO); - ERRNOSTR(EXDEV); - ERRNOSTR(EPERM); - default: return "unknown"; - } - -#undef ERRNOSTR -} - -/****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap -*/ -/*---------------------------------------------------------------------------*/ -int easycap_isdongle(struct easycap *peasycap) -{ - int k; - if (!peasycap) - return -2; - for (k = 0; k < DONGLE_MANY; k++) { - if (easycapdc60_dongle[k].peasycap == peasycap) { - peasycap->isdongle = k; - return k; - } - } - return -1; -} -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ -static int easycap_open(struct inode *inode, struct file *file) -{ - struct video_device *pvideo_device; - struct easycap *peasycap; - int rc; - - JOT(4, "\n"); - SAY("==========OPEN=========\n"); - - pvideo_device = video_devdata(file); - if (!pvideo_device) { - SAY("ERROR: pvideo_device is NULL.\n"); - return -EFAULT; - } - peasycap = (struct easycap *)video_get_drvdata(pvideo_device); - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - - JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device); - - file->private_data = peasycap; - rc = easycap_wakeup_device(peasycap->pusb_device); - if (rc) { - SAM("ERROR: wakeup_device() rc = %i\n", rc); - if (-ENODEV == rc) - SAM("ERROR: wakeup_device() returned -ENODEV\n"); - else - SAM("ERROR: wakeup_device() rc = %i\n", rc); - return rc; - } - JOM(8, "wakeup_device() OK\n"); - peasycap->input = 0; - rc = reset(peasycap); - if (rc) { - SAM("ERROR: reset() rc = %i\n", rc); - return -EFAULT; - } - return 0; -} - -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * RESET THE HARDWARE TO ITS REFERENCE STATE. - * - * THIS ROUTINE MAY BE CALLED REPEATEDLY IF easycap_complete() DETECTS - * A BAD VIDEO FRAME SIZE. -*/ -/*---------------------------------------------------------------------------*/ -static int reset(struct easycap *peasycap) -{ - struct easycap_standard const *peasycap_standard; - int fmtidx, input, rate; - bool ntsc, other; - int rc; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - input = peasycap->input; - -/*---------------------------------------------------------------------------*/ -/* - * IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED - * FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR - * gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE - * A SWITCH BETWEEN PAL AND NTSC. - * - * FUNCTION ready_saa() MAY REQUIRE A SUBSTANTIAL FRACTION OF A SECOND TO - * COMPLETE, SO SHOULD NOT BE INVOKED WITHOUT GOOD REASON. -*/ -/*---------------------------------------------------------------------------*/ - other = false; - JOM(8, "peasycap->ntsc=%d\n", peasycap->ntsc); - - rate = ready_saa(peasycap->pusb_device); - if (rate < 0) { - JOM(8, "not ready to capture after %i ms ...\n", PATIENCE); - ntsc = !peasycap->ntsc; - JOM(8, "... trying %s ..\n", ntsc ? "NTSC" : "PAL"); - rc = setup_stk(peasycap->pusb_device, ntsc); - if (rc) { - SAM("ERROR: setup_stk() rc = %i\n", rc); - return -EFAULT; - } - rc = setup_saa(peasycap->pusb_device, ntsc); - if (rc) { - SAM("ERROR: setup_saa() rc = %i\n", rc); - return -EFAULT; - } - - rate = ready_saa(peasycap->pusb_device); - if (rate < 0) { - JOM(8, "not ready to capture after %i ms\n", PATIENCE); - JOM(8, "... saa register 0x1F has 0x%02X\n", - read_saa(peasycap->pusb_device, 0x1F)); - ntsc = peasycap->ntsc; - } else { - JOM(8, "... success at second try: %i=rate\n", rate); - ntsc = (0 < (rate/2)) ? true : false ; - other = true; - } - } else { - JOM(8, "... success at first try: %i=rate\n", rate); - ntsc = (0 < rate/2) ? true : false ; - } - JOM(8, "ntsc=%d\n", ntsc); -/*---------------------------------------------------------------------------*/ - - rc = setup_stk(peasycap->pusb_device, ntsc); - if (rc) { - SAM("ERROR: setup_stk() rc = %i\n", rc); - return -EFAULT; - } - rc = setup_saa(peasycap->pusb_device, ntsc); - if (rc) { - SAM("ERROR: setup_saa() rc = %i\n", rc); - return -EFAULT; - } - - memset(peasycap->merit, 0, sizeof(peasycap->merit)); - - peasycap->video_eof = 0; - peasycap->audio_eof = 0; -/*---------------------------------------------------------------------------*/ -/* - * RESTORE INPUT AND FORCE REFRESH OF STANDARD, FORMAT, ETC. - * - * WHILE THIS PROCEDURE IS IN PROGRESS, SOME IOCTL COMMANDS WILL RETURN -EBUSY. -*/ -/*---------------------------------------------------------------------------*/ - peasycap->input = -8192; - peasycap->standard_offset = -8192; - fmtidx = ntsc ? NTSC_M : PAL_BGHIN; - if (other) { - peasycap_standard = &easycap_standard[0]; - while (0xFFFF != peasycap_standard->mask) { - if (fmtidx == peasycap_standard->v4l2_standard.index) { - peasycap->inputset[input].standard_offset = - peasycap_standard - easycap_standard; - break; - } - peasycap_standard++; - } - if (0xFFFF == peasycap_standard->mask) { - SAM("ERROR: standard not found\n"); - return -EINVAL; - } - JOM(8, "%i=peasycap->inputset[%i].standard_offset\n", - peasycap->inputset[input].standard_offset, input); - } - peasycap->format_offset = -8192; - peasycap->brightness = -8192; - peasycap->contrast = -8192; - peasycap->saturation = -8192; - peasycap->hue = -8192; - - rc = easycap_newinput(peasycap, input); - - if (rc) { - SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input); - return -EFAULT; - } - JOM(4, "restored input, standard and format\n"); - - JOM(8, "true=peasycap->ntsc %d\n", peasycap->ntsc); - - if (0 > peasycap->input) { - SAM("MISTAKE: %i=peasycap->input\n", peasycap->input); - return -ENOENT; - } - if (0 > peasycap->standard_offset) { - SAM("MISTAKE: %i=peasycap->standard_offset\n", - peasycap->standard_offset); - return -ENOENT; - } - if (0 > peasycap->format_offset) { - SAM("MISTAKE: %i=peasycap->format_offset\n", - peasycap->format_offset); - return -ENOENT; - } - if (0 > peasycap->brightness) { - SAM("MISTAKE: %i=peasycap->brightness\n", - peasycap->brightness); - return -ENOENT; - } - if (0 > peasycap->contrast) { - SAM("MISTAKE: %i=peasycap->contrast\n", peasycap->contrast); - return -ENOENT; - } - if (0 > peasycap->saturation) { - SAM("MISTAKE: %i=peasycap->saturation\n", - peasycap->saturation); - return -ENOENT; - } - if (0 > peasycap->hue) { - SAM("MISTAKE: %i=peasycap->hue\n", peasycap->hue); - return -ENOENT; - } - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * IF THE REQUESTED INPUT IS THE SAME AS THE EXISTING INPUT, DO NOTHING. - * OTHERWISE: - * KILL URBS, CLEAR FIELD AND FRAME BUFFERS AND RESET THEIR - * _read AND _fill POINTERS. - * SELECT THE NEW INPUT. - * ADJUST THE STANDARD, FORMAT, BRIGHTNESS, CONTRAST, SATURATION AND HUE - * ON THE BASIS OF INFORMATION IN STRUCTURE easycap.inputset[input]. - * RESUBMIT THE URBS IF STREAMING WAS ALREADY IN PROGRESS. - * - * NOTE: - * THIS ROUTINE MAY BE CALLED FREQUENTLY BY ZONEMINDER VIA IOCTL, - * SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE. -*/ -/*---------------------------------------------------------------------------*/ -int easycap_newinput(struct easycap *peasycap, int input) -{ - int rc, k, m, mood, off; - int inputnow, video_idlenow, audio_idlenow; - bool resubmit; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - JOM(8, "%i=input sought\n", input); - - if (0 > input && INPUT_MANY <= input) - return -ENOENT; - inputnow = peasycap->input; - if (input == inputnow) - return 0; -/*---------------------------------------------------------------------------*/ -/* - * IF STREAMING IS IN PROGRESS THE URBS ARE KILLED AT THIS - * STAGE AND WILL BE RESUBMITTED PRIOR TO EXIT FROM THE ROUTINE. - * IF NO STREAMING IS IN PROGRESS NO URBS WILL BE SUBMITTED BY THE - * ROUTINE. -*/ -/*---------------------------------------------------------------------------*/ - video_idlenow = peasycap->video_idle; - audio_idlenow = peasycap->audio_idle; - - peasycap->video_idle = 1; - peasycap->audio_idle = 1; - if (peasycap->video_isoc_streaming) { - resubmit = true; - easycap_video_kill_urbs(peasycap); - } else { - resubmit = false; - } -/*---------------------------------------------------------------------------*/ - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -ENODEV; - } - rc = usb_set_interface(peasycap->pusb_device, - peasycap->video_interface, - peasycap->video_altsetting_off); - if (rc) { - SAM("ERROR: usb_set_interface() rc = %i\n", rc); - return -EFAULT; - } - rc = stop_100(peasycap->pusb_device); - if (rc) { - SAM("ERROR: stop_100() rc = %i\n", rc); - return -EFAULT; - } - for (k = 0; k < FIELD_BUFFER_MANY; k++) { - for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) - memset(peasycap->field_buffer[k][m].pgo, 0, PAGE_SIZE); - } - for (k = 0; k < FRAME_BUFFER_MANY; k++) { - for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) - memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE); - } - peasycap->field_page = 0; - peasycap->field_read = 0; - peasycap->field_fill = 0; - - peasycap->frame_read = 0; - peasycap->frame_fill = 0; - for (k = 0; k < peasycap->input; k++) { - (peasycap->frame_fill)++; - if (peasycap->frame_buffer_many <= peasycap->frame_fill) - peasycap->frame_fill = 0; - } - peasycap->input = input; - select_input(peasycap->pusb_device, peasycap->input, 9); -/*---------------------------------------------------------------------------*/ - if (input == peasycap->inputset[input].input) { - off = peasycap->inputset[input].standard_offset; - if (off != peasycap->standard_offset) { - rc = adjust_standard(peasycap, - easycap_standard[off].v4l2_standard.id); - if (rc) { - SAM("ERROR: adjust_standard() rc = %i\n", rc); - return -EFAULT; - } - JOM(8, "%i=peasycap->standard_offset\n", - peasycap->standard_offset); - } else { - JOM(8, "%i=peasycap->standard_offset unchanged\n", - peasycap->standard_offset); - } - off = peasycap->inputset[input].format_offset; - if (off != peasycap->format_offset) { - struct v4l2_pix_format *pix = - &easycap_format[off].v4l2_format.fmt.pix; - rc = adjust_format(peasycap, - pix->width, pix->height, - pix->pixelformat, pix->field, false); - if (0 > rc) { - SAM("ERROR: adjust_format() rc = %i\n", rc); - return -EFAULT; - } - JOM(8, "%i=peasycap->format_offset\n", - peasycap->format_offset); - } else { - JOM(8, "%i=peasycap->format_offset unchanged\n", - peasycap->format_offset); - } - mood = peasycap->inputset[input].brightness; - if (mood != peasycap->brightness) { - rc = adjust_brightness(peasycap, mood); - if (rc) { - SAM("ERROR: adjust_brightness rc = %i\n", rc); - return -EFAULT; - } - JOM(8, "%i=peasycap->brightness\n", - peasycap->brightness); - } - mood = peasycap->inputset[input].contrast; - if (mood != peasycap->contrast) { - rc = adjust_contrast(peasycap, mood); - if (rc) { - SAM("ERROR: adjust_contrast rc = %i\n", rc); - return -EFAULT; - } - JOM(8, "%i=peasycap->contrast\n", peasycap->contrast); - } - mood = peasycap->inputset[input].saturation; - if (mood != peasycap->saturation) { - rc = adjust_saturation(peasycap, mood); - if (rc) { - SAM("ERROR: adjust_saturation rc = %i\n", rc); - return -EFAULT; - } - JOM(8, "%i=peasycap->saturation\n", - peasycap->saturation); - } - mood = peasycap->inputset[input].hue; - if (mood != peasycap->hue) { - rc = adjust_hue(peasycap, mood); - if (rc) { - SAM("ERROR: adjust_hue rc = %i\n", rc); - return -EFAULT; - } - JOM(8, "%i=peasycap->hue\n", peasycap->hue); - } - } else { - SAM("MISTAKE: easycap.inputset[%i] unpopulated\n", input); - return -ENOENT; - } -/*---------------------------------------------------------------------------*/ - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -ENODEV; - } - rc = usb_set_interface(peasycap->pusb_device, - peasycap->video_interface, - peasycap->video_altsetting_on); - if (rc) { - SAM("ERROR: usb_set_interface() rc = %i\n", rc); - return -EFAULT; - } - rc = start_100(peasycap->pusb_device); - if (rc) { - SAM("ERROR: start_100() rc = %i\n", rc); - return -EFAULT; - } - if (resubmit) - easycap_video_submit_urbs(peasycap); - - peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1; - peasycap->video_idle = video_idlenow; - peasycap->audio_idle = audio_idlenow; - peasycap->video_junk = 0; - - return 0; -} -/*****************************************************************************/ -int easycap_video_submit_urbs(struct easycap *peasycap) -{ - struct data_urb *pdata_urb; - struct urb *purb; - struct list_head *plist_head; - int j, isbad, nospc, m, rc; - int isbuf; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - - if (!peasycap->purb_video_head) { - SAY("ERROR: peasycap->urb_video_head uninitialized\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); - return -ENODEV; - } - if (!peasycap->video_isoc_streaming) { - JOM(4, "submission of all video urbs\n"); - isbad = 0; nospc = 0; m = 0; - list_for_each(plist_head, (peasycap->purb_video_head)) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - purb = pdata_urb->purb; - isbuf = pdata_urb->isbuf; - purb->interval = 1; - purb->dev = peasycap->pusb_device; - purb->pipe = - usb_rcvisocpipe(peasycap->pusb_device, - peasycap->video_endpointnumber); - purb->transfer_flags = URB_ISO_ASAP; - purb->transfer_buffer = - peasycap->video_isoc_buffer[isbuf].pgo; - purb->transfer_buffer_length = - peasycap->video_isoc_buffer_size; - purb->complete = easycap_complete; - purb->context = peasycap; - purb->start_frame = 0; - purb->number_of_packets = - peasycap->video_isoc_framesperdesc; - - for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) { - purb->iso_frame_desc[j]. offset = - j * peasycap->video_isoc_maxframesize; - purb->iso_frame_desc[j]. length = - peasycap->video_isoc_maxframesize; - } - - rc = usb_submit_urb(purb, GFP_KERNEL); - if (rc) { - isbad++; - SAM("ERROR: usb_submit_urb() failed " - "for urb with rc:-%s\n", - strerror(rc)); - if (rc == -ENOSPC) - nospc++; - } else { - m++; - } - } else { - isbad++; - } - } - if (nospc) { - SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc); - SAM("..... possibly inadequate USB bandwidth\n"); - peasycap->video_eof = 1; - } - - if (isbad) - easycap_video_kill_urbs(peasycap); - else - peasycap->video_isoc_streaming = 1; - } else { - JOM(4, "already streaming video urbs\n"); - } - return 0; -} -/*****************************************************************************/ -int easycap_audio_kill_urbs(struct easycap *peasycap) -{ - int m; - struct list_head *plist_head; - struct data_urb *pdata_urb; - - if (!peasycap->audio_isoc_streaming) - return 0; - - if (!peasycap->purb_audio_head) { - SAM("ERROR: peasycap->purb_audio_head is NULL\n"); - return -EFAULT; - } - - peasycap->audio_isoc_streaming = 0; - m = 0; - list_for_each(plist_head, peasycap->purb_audio_head) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } - } - - JOM(4, "%i audio urbs killed\n", m); - - return 0; -} -int easycap_video_kill_urbs(struct easycap *peasycap) -{ - int m; - struct list_head *plist_head; - struct data_urb *pdata_urb; - - if (!peasycap->video_isoc_streaming) - return 0; - - if (!peasycap->purb_video_head) { - SAM("ERROR: peasycap->purb_video_head is NULL\n"); - return -EFAULT; - } - - peasycap->video_isoc_streaming = 0; - JOM(4, "killing video urbs\n"); - m = 0; - list_for_each(plist_head, (peasycap->purb_video_head)) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } - } - JOM(4, "%i video urbs killed\n", m); - - return 0; -} -/****************************************************************************/ -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ -/*--------------------------------------------------------------------------*/ -static int easycap_open_noinode(struct file *file) -{ - return easycap_open(NULL, file); -} - -static int videodev_release(struct video_device *pvideo_device) -{ - struct easycap *peasycap; - - peasycap = video_get_drvdata(pvideo_device); - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - SAY("ending unsuccessfully\n"); - return -EFAULT; - } - if (easycap_video_kill_urbs(peasycap)) { - SAM("ERROR: easycap_video_kill_urbs() failed\n"); - return -EFAULT; - } - JOM(4, "ending successfully\n"); - return 0; -} - -/*****************************************************************************/ -static unsigned int easycap_poll(struct file *file, poll_table *wait) -{ - struct easycap *peasycap; - int rc, kd; - - JOT(8, "\n"); - - if (NULL == ((poll_table *)wait)) - JOT(8, "WARNING: poll table pointer is NULL ... continuing\n"); - if (!file) { - SAY("ERROR: file pointer is NULL\n"); - return -ERESTARTSYS; - } - peasycap = file->private_data; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } -/*---------------------------------------------------------------------------*/ - kd = easycap_isdongle(peasycap); - if (0 <= kd && DONGLE_MANY > kd) { - if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) { - SAY("ERROR: cannot down dongle[%i].mutex_video\n", kd); - return -ERESTARTSYS; - } - JOM(4, "locked dongle[%i].mutex_video\n", kd); - /* - * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER - * peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. - * IF NECESSARY, BAIL OUT. - */ - if (kd != easycap_isdongle(peasycap)) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ERESTARTSYS; - } - if (!file) { - SAY("ERROR: file is NULL\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ERESTARTSYS; - } - peasycap = file->private_data; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ERESTARTSYS; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return -ERESTARTSYS; - } - } else - /* - * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap - * BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL - * HAVE FAILED. BAIL OUT. - */ - return -ERESTARTSYS; -/*---------------------------------------------------------------------------*/ - rc = easycap_video_dqbuf(peasycap, 0); - peasycap->polled = 1; - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - if (rc) - return POLLERR; - - return POLLIN | POLLRDNORM; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING. - */ -/*---------------------------------------------------------------------------*/ -int easycap_video_dqbuf(struct easycap *peasycap, int mode) -{ - int input, ifield, miss, rc; - - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAY("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - ifield = 0; - JOM(8, "%i=ifield\n", ifield); -/*---------------------------------------------------------------------------*/ -/* - * CHECK FOR LOST INPUT SIGNAL. - * - * FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED. - * IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT - * RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE - * IS FLYWHEELING ON INPUT 0. THE UPSHOT IS: - * - * INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK - * INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK - * INPUT 0 UNPLUGGED, INPUT 4 PLUGGED => SCREEN 0 BARS, SCREEN 4 OK - * INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS -*/ -/*---------------------------------------------------------------------------*/ - input = peasycap->input; - if (0 <= input && INPUT_MANY > input) { - rc = read_saa(peasycap->pusb_device, 0x1F); - if (0 <= rc) { - if (rc & 0x40) - peasycap->lost[input] += 1; - else - peasycap->lost[input] -= 2; - - if (0 > peasycap->lost[input]) - peasycap->lost[input] = 0; - else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input]) - peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE); - } - } -/*---------------------------------------------------------------------------*/ -/* - * WAIT FOR FIELD ifield (0 => TOP, 1 => BOTTOM) - */ -/*---------------------------------------------------------------------------*/ - miss = 0; - while ((peasycap->field_read == peasycap->field_fill) || - (0 != (0xFF00 & peasycap->field_buffer - [peasycap->field_read][0].kount)) || - (ifield != (0x00FF & peasycap->field_buffer - [peasycap->field_read][0].kount))) { - if (mode) - return -EAGAIN; - - JOM(8, "first wait on wq_video, %i=field_read %i=field_fill\n", - peasycap->field_read, peasycap->field_fill); - - if (0 != (wait_event_interruptible(peasycap->wq_video, - (peasycap->video_idle || peasycap->video_eof || - ((peasycap->field_read != peasycap->field_fill) && - (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) && - (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) { - SAM("aborted by signal\n"); - return -EIO; - } - if (peasycap->video_idle) { - JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n", - peasycap->video_idle); - return -EAGAIN; - } - if (peasycap->video_eof) { - JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof); - #if defined(PERSEVERE) - if (1 == peasycap->status) { - JOM(8, "persevering ...\n"); - peasycap->video_eof = 0; - peasycap->audio_eof = 0; - if (0 != reset(peasycap)) { - JOM(8, " ... failed returning -EIO\n"); - peasycap->video_eof = 1; - peasycap->audio_eof = 1; - easycap_video_kill_urbs(peasycap); - return -EIO; - } - peasycap->status = 0; - JOM(8, " ... OK returning -EAGAIN\n"); - return -EAGAIN; - } - #endif /*PERSEVERE*/ - peasycap->video_eof = 1; - peasycap->audio_eof = 1; - easycap_video_kill_urbs(peasycap); - JOM(8, "returning -EIO\n"); - return -EIO; - } - miss++; - } - JOM(8, "first awakening on wq_video after %i waits\n", miss); - - rc = field2frame(peasycap); - if (rc) - SAM("ERROR: field2frame() rc = %i\n", rc); -/*---------------------------------------------------------------------------*/ -/* - * WAIT FOR THE OTHER FIELD - */ -/*---------------------------------------------------------------------------*/ - if (ifield) - ifield = 0; - else - ifield = 1; - miss = 0; - while ((peasycap->field_read == peasycap->field_fill) || - (0 != (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) || - (ifield != (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))) { - if (mode) - return -EAGAIN; - - JOM(8, "second wait on wq_video %i=field_read %i=field_fill\n", - peasycap->field_read, peasycap->field_fill); - if (0 != (wait_event_interruptible(peasycap->wq_video, - (peasycap->video_idle || peasycap->video_eof || - ((peasycap->field_read != peasycap->field_fill) && - (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) && - (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) { - SAM("aborted by signal\n"); - return -EIO; - } - if (peasycap->video_idle) { - JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n", - peasycap->video_idle); - return -EAGAIN; - } - if (peasycap->video_eof) { - JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof); -#if defined(PERSEVERE) - if (1 == peasycap->status) { - JOM(8, "persevering ...\n"); - peasycap->video_eof = 0; - peasycap->audio_eof = 0; - if (0 != reset(peasycap)) { - JOM(8, " ... failed returning -EIO\n"); - peasycap->video_eof = 1; - peasycap->audio_eof = 1; - easycap_video_kill_urbs(peasycap); - return -EIO; - } - peasycap->status = 0; - JOM(8, " ... OK ... returning -EAGAIN\n"); - return -EAGAIN; - } -#endif /*PERSEVERE*/ - peasycap->video_eof = 1; - peasycap->audio_eof = 1; - easycap_video_kill_urbs(peasycap); - JOM(8, "returning -EIO\n"); - return -EIO; - } - miss++; - } - JOM(8, "second awakening on wq_video after %i waits\n", miss); - - rc = field2frame(peasycap); - if (rc) - SAM("ERROR: field2frame() rc = %i\n", rc); -/*---------------------------------------------------------------------------*/ -/* - * WASTE THIS FRAME -*/ -/*---------------------------------------------------------------------------*/ - if (peasycap->skip) { - peasycap->skipped++; - if (peasycap->skip != peasycap->skipped) - return peasycap->skip - peasycap->skipped; - else - peasycap->skipped = 0; - } -/*---------------------------------------------------------------------------*/ - peasycap->frame_read = peasycap->frame_fill; - peasycap->queued[peasycap->frame_read] = 0; - peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE; - - peasycap->frame_fill++; - if (peasycap->frame_buffer_many <= peasycap->frame_fill) - peasycap->frame_fill = 0; - - if (0x01 & easycap_standard[peasycap->standard_offset].mask) - peasycap->frame_buffer[peasycap->frame_read][0].kount = - V4L2_FIELD_TOP; - else - peasycap->frame_buffer[peasycap->frame_read][0].kount = - V4L2_FIELD_BOTTOM; - - - JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read); - JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill); - - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * BY DEFINITION, odd IS true FOR THE FIELD OCCUPYING LINES 1,3,5,...,479 - * odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,478 - * - * WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH - * odd==false IS TRANSFERRED TO THE FRAME BUFFER. - * - */ -/*---------------------------------------------------------------------------*/ -static int field2frame(struct easycap *peasycap) -{ - - void *pex, *pad; - int kex, kad, mex, mad, rex, rad, rad2; - int c2, c3, w2, w3, cz, wz; - int rc, bytesperpixel, multiplier; - int much, more, over, rump, caches, input; - u8 mask, margin; - bool odd, isuy, decimatepixel, badinput; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - - badinput = false; - input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input; - - JOM(8, "===== parity %i, input 0x%02X, field buffer %i --> " - "frame buffer %i\n", - peasycap->field_buffer[peasycap->field_read][0].kount, - peasycap->field_buffer[peasycap->field_read][0].input, - peasycap->field_read, peasycap->frame_fill); - JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel); - -/*---------------------------------------------------------------------------*/ -/* - * REJECT OR CLEAN BAD FIELDS - */ -/*---------------------------------------------------------------------------*/ - if (peasycap->field_read == peasycap->field_fill) { - SAM("ERROR: on entry, still filling field buffer %i\n", - peasycap->field_read); - return 0; - } -#ifdef EASYCAP_TESTCARD - easycap_testcard(peasycap, peasycap->field_read); -#else - if (0 <= input && INPUT_MANY > input) { - if (easycap_bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input]) - easycap_testcard(peasycap, peasycap->field_read); - } -#endif /*EASYCAP_TESTCARD*/ -/*---------------------------------------------------------------------------*/ - - bytesperpixel = peasycap->bytesperpixel; - decimatepixel = peasycap->decimatepixel; - - if ((2 != bytesperpixel) && - (3 != bytesperpixel) && - (4 != bytesperpixel)) { - SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel); - return -EFAULT; - } - if (decimatepixel) - multiplier = 2; - else - multiplier = 1; - - w2 = 2 * multiplier * (peasycap->width); - w3 = bytesperpixel * multiplier * (peasycap->width); - wz = multiplier * (peasycap->height) * - multiplier * (peasycap->width); - - kex = peasycap->field_read; mex = 0; - kad = peasycap->frame_fill; mad = 0; - - pex = peasycap->field_buffer[kex][0].pgo; rex = PAGE_SIZE; - pad = peasycap->frame_buffer[kad][0].pgo; rad = PAGE_SIZE; - odd = !!(peasycap->field_buffer[kex][0].kount); - - if (odd && (!decimatepixel)) { - JOM(8, "initial skipping %4i bytes p.%4i\n", - w3/multiplier, mad); - pad += (w3 / multiplier); rad -= (w3 / multiplier); - } - isuy = true; - mask = 0; rump = 0; caches = 0; - - cz = 0; - while (cz < wz) { - /* - * PROCESS ONE LINE OF FRAME AT FULL RESOLUTION: - * READ w2 BYTES FROM FIELD BUFFER, - * WRITE w3 BYTES TO FRAME BUFFER - */ - if (!decimatepixel) { - over = w2; - do { - much = over; more = 0; - margin = 0; mask = 0x00; - if (rex < much) - much = rex; - rump = 0; - - if (much % 2) { - SAM("MISTAKE: much is odd\n"); - return -EFAULT; - } - - more = (bytesperpixel * - much) / 2; -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - if (1 < bytesperpixel) { - if (rad * 2 < much * bytesperpixel) { - /* - * INJUDICIOUS ALTERATION OF - * THIS STATEMENT BLOCK WILL - * CAUSE BREAKAGE. BEWARE. - */ - rad2 = rad + bytesperpixel - 1; - much = ((((2 * rad2)/bytesperpixel)/2) * 2); - rump = ((bytesperpixel * much) / 2) - rad; - more = rad; - } - mask = (u8)rump; - margin = 0; - if (much == rex) { - mask |= 0x04; - if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE) - margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo)); - else - mask |= 0x08; - } - } else { - SAM("MISTAKE: %i=bytesperpixel\n", - bytesperpixel); - return -EFAULT; - } - if (rump) - caches++; - if (badinput) { - JOM(8, "ERROR: 0x%02X=->field_buffer" - "[%i][%i].input, " - "0x%02X=(0x08|->input)\n", - peasycap->field_buffer - [kex][mex].input, kex, mex, - (0x08|peasycap->input)); - } - rc = redaub(peasycap, pad, pex, much, more, - mask, margin, isuy); - if (0 > rc) { - SAM("ERROR: redaub() failed\n"); - return -EFAULT; - } - if (much % 4) - isuy = !isuy; - - over -= much; cz += much; - pex += much; rex -= much; - if (!rex) { - mex++; - pex = peasycap->field_buffer[kex][mex].pgo; - rex = PAGE_SIZE; - if (peasycap->field_buffer[kex][mex].input != (0x08|peasycap->input)) - badinput = true; - } - pad += more; - rad -= more; - if (!rad) { - mad++; - pad = peasycap->frame_buffer[kad][mad].pgo; - rad = PAGE_SIZE; - if (rump) { - pad += rump; - rad -= rump; - } - } - } while (over); -/*---------------------------------------------------------------------------*/ -/* - * SKIP w3 BYTES IN TARGET FRAME BUFFER, - * UNLESS IT IS THE LAST LINE OF AN ODD FRAME - */ -/*---------------------------------------------------------------------------*/ - if (!odd || (cz != wz)) { - over = w3; - do { - if (!rad) { - mad++; - pad = peasycap->frame_buffer - [kad][mad].pgo; - rad = PAGE_SIZE; - } - more = over; - if (rad < more) - more = rad; - over -= more; - pad += more; - rad -= more; - } while (over); - } -/*---------------------------------------------------------------------------*/ -/* - * PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION: - * ONLY IF false==odd, - * READ w2 BYTES FROM FIELD BUFFER, - * WRITE w3 / 2 BYTES TO FRAME BUFFER - */ -/*---------------------------------------------------------------------------*/ - } else if (!odd) { - over = w2; - do { - much = over; more = 0; margin = 0; mask = 0x00; - if (rex < much) - much = rex; - rump = 0; - - if (much % 2) { - SAM("MISTAKE: much is odd\n"); - return -EFAULT; - } - - more = (bytesperpixel * much) / 4; -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - if (1 < bytesperpixel) { - if (rad * 4 < much * bytesperpixel) { - /* - * INJUDICIOUS ALTERATION OF - * THIS STATEMENT BLOCK - * WILL CAUSE BREAKAGE. - * BEWARE. - */ - rad2 = rad + bytesperpixel - 1; - much = ((((2 * rad2) / bytesperpixel) / 2) * 4); - rump = ((bytesperpixel * much) / 4) - rad; - more = rad; - } - mask = (u8)rump; - margin = 0; - if (much == rex) { - mask |= 0x04; - if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE) - margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo)); - else - mask |= 0x08; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - } else { - SAM("MISTAKE: %i=bytesperpixel\n", - bytesperpixel); - return -EFAULT; - } -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - if (rump) - caches++; - - if (badinput) { - JOM(8, "ERROR: 0x%02X=->field_buffer" - "[%i][%i].input, " - "0x%02X=(0x08|->input)\n", - peasycap->field_buffer - [kex][mex].input, kex, mex, - (0x08|peasycap->input)); - } - rc = redaub(peasycap, pad, pex, much, more, - mask, margin, isuy); - if (0 > rc) { - SAM("ERROR: redaub() failed\n"); - return -EFAULT; - } - over -= much; cz += much; - pex += much; rex -= much; - if (!rex) { - mex++; - pex = peasycap->field_buffer[kex][mex].pgo; - rex = PAGE_SIZE; - if (peasycap->field_buffer[kex][mex].input != - (0x08|peasycap->input)) - badinput = true; - } - pad += more; - rad -= more; - if (!rad) { - mad++; - pad = peasycap->frame_buffer[kad][mad].pgo; - rad = PAGE_SIZE; - if (rump) { - pad += rump; - rad -= rump; - } - } - } while (over); -/*---------------------------------------------------------------------------*/ -/* - * OTHERWISE JUST - * READ w2 BYTES FROM FIELD BUFFER AND DISCARD THEM - */ -/*---------------------------------------------------------------------------*/ - } else { - over = w2; - do { - if (!rex) { - mex++; - pex = peasycap->field_buffer[kex][mex].pgo; - rex = PAGE_SIZE; - if (peasycap->field_buffer[kex][mex].input != - (0x08|peasycap->input)) { - JOM(8, "ERROR: 0x%02X=->field_buffer" - "[%i][%i].input, " - "0x%02X=(0x08|->input)\n", - peasycap->field_buffer - [kex][mex].input, kex, mex, - (0x08|peasycap->input)); - badinput = true; - } - } - much = over; - if (rex < much) - much = rex; - over -= much; - cz += much; - pex += much; - rex -= much; - } while (over); - } - } -/*---------------------------------------------------------------------------*/ -/* - * SANITY CHECKS - */ -/*---------------------------------------------------------------------------*/ - c2 = (mex + 1)*PAGE_SIZE - rex; - if (cz != c2) - SAM("ERROR: discrepancy %i in bytes read\n", c2 - cz); - c3 = (mad + 1)*PAGE_SIZE - rad; - - if (!decimatepixel) { - if (bytesperpixel * cz != c3) - SAM("ERROR: discrepancy %i in bytes written\n", - c3 - (bytesperpixel * cz)); - } else { - if (!odd) { - if (bytesperpixel * - cz != (4 * c3)) - SAM("ERROR: discrepancy %i in bytes written\n", - (2*c3)-(bytesperpixel * cz)); - } else { - if (0 != c3) - SAM("ERROR: discrepancy %i " - "in bytes written\n", c3); - } - } - if (rump) - SAM("WORRY: undischarged cache at end of line in frame buffer\n"); - - JOM(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3); - JOM(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad); - - if (odd) - JOM(8, "+++++ field2frame(): frame buffer %i is full\n", kad); - - if (peasycap->field_read == peasycap->field_fill) - SAM("WARNING: on exit, filling field buffer %i\n", - peasycap->field_read); - - if (caches) - JOM(8, "%i=caches\n", caches); - return 0; -} -/*---------------------------------------------------------------------------*/ -/* - * DECIMATION AND COLOURSPACE CONVERSION. - * - * THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE - * AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE. - * THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST - * ALSO ENSURE THAT much IS EVEN. - * - * much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN - * IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION. - * - * mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS: - * 0x03 & mask = number of bytes to be written to cache instead of to - * frame buffer - * 0x04 & mask => use argument margin to set the chrominance for last pixel - * 0x08 & mask => do not set the chrominance for last pixel - * - * YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601. - * - * THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID - * INEFFICIENT SWITCHING INSIDE INNER LOOPS. REARRANGING THE LOGIC TO - * REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE. BEWARE. - */ -/*---------------------------------------------------------------------------*/ -static int redaub(struct easycap *peasycap, - void *pad, void *pex, int much, int more, - u8 mask, u8 margin, bool isuy) -{ - static s32 ay[256], bu[256], rv[256], gu[256], gv[256]; - u8 *pcache; - u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr; - int bytesperpixel; - bool byteswaporder, decimatepixel, last; - int j, rump; - s32 tmp; - - if (much % 2) { - SAM("MISTAKE: much is odd\n"); - return -EFAULT; - } - bytesperpixel = peasycap->bytesperpixel; - byteswaporder = peasycap->byteswaporder; - decimatepixel = peasycap->decimatepixel; - -/*---------------------------------------------------------------------------*/ - if (!bu[255]) { - for (j = 0; j < 112; j++) { - tmp = (0xFF00 & (453 * j)) >> 8; - bu[j + 128] = tmp; bu[127 - j] = -tmp; - tmp = (0xFF00 & (359 * j)) >> 8; - rv[j + 128] = tmp; rv[127 - j] = -tmp; - tmp = (0xFF00 & (88 * j)) >> 8; - gu[j + 128] = tmp; gu[127 - j] = -tmp; - tmp = (0xFF00 & (183 * j)) >> 8; - gv[j + 128] = tmp; gv[127 - j] = -tmp; - } - for (j = 0; j < 16; j++) { - bu[j] = bu[16]; rv[j] = rv[16]; - gu[j] = gu[16]; gv[j] = gv[16]; - } - for (j = 240; j < 256; j++) { - bu[j] = bu[239]; rv[j] = rv[239]; - gu[j] = gu[239]; gv[j] = gv[239]; - } - for (j = 16; j < 236; j++) - ay[j] = j; - for (j = 0; j < 16; j++) - ay[j] = ay[16]; - for (j = 236; j < 256; j++) - ay[j] = ay[235]; - JOM(8, "lookup tables are prepared\n"); - } - pcache = peasycap->pcache; - if (!pcache) - pcache = &peasycap->cache[0]; -/*---------------------------------------------------------------------------*/ -/* - * TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER - */ -/*---------------------------------------------------------------------------*/ - if (!pcache) { - SAM("MISTAKE: pcache is NULL\n"); - return -EFAULT; - } - - if (pcache != &peasycap->cache[0]) - JOM(16, "cache has %i bytes\n", (int)(pcache - &peasycap->cache[0])); - p2 = &peasycap->cache[0]; - p3 = (u8 *)pad - (int)(pcache - &peasycap->cache[0]); - while (p2 < pcache) { - *p3++ = *p2; p2++; - } - pcache = &peasycap->cache[0]; - if (p3 != pad) { - SAM("MISTAKE: pointer misalignment\n"); - return -EFAULT; - } -/*---------------------------------------------------------------------------*/ - rump = (int)(0x03 & mask); - u = 0; v = 0; - p2 = (u8 *)pex; pz = p2 + much; pr = p3 + more; last = false; - p2++; - - if (isuy) - u = *(p2 - 1); - else - v = *(p2 - 1); - - if (rump) - JOM(16, "%4i=much %4i=more %i=rump\n", much, more, rump); - -/*---------------------------------------------------------------------------*/ - switch (bytesperpixel) { - case 2: { - if (!decimatepixel) { - memcpy(pad, pex, (size_t)much); - if (!byteswaporder) { - /* UYVY */ - return 0; - } else { - /* YUYV */ - p3 = (u8 *)pad; pz = p3 + much; - while (pz > p3) { - c = *p3; - *p3 = *(p3 + 1); - *(p3 + 1) = c; - p3 += 2; - } - return 0; - } - } else { - if (!byteswaporder) { - /* UYVY DECIMATED */ - p2 = (u8 *)pex; p3 = (u8 *)pad; pz = p2 + much; - while (pz > p2) { - *p3 = *p2; - *(p3 + 1) = *(p2 + 1); - *(p3 + 2) = *(p2 + 2); - *(p3 + 3) = *(p2 + 3); - p3 += 4; p2 += 8; - } - return 0; - } else { - /* YUYV DECIMATED */ - p2 = (u8 *)pex; p3 = (u8 *)pad; pz = p2 + much; - while (pz > p2) { - *p3 = *(p2 + 1); - *(p3 + 1) = *p2; - *(p3 + 2) = *(p2 + 3); - *(p3 + 3) = *(p2 + 2); - p3 += 4; p2 += 8; - } - return 0; - } - } - break; - } - case 3: - { - if (!decimatepixel) { - if (!byteswaporder) { - /* RGB */ - while (pz > p2) { - if (pr <= (p3 + bytesperpixel)) - last = true; - else - last = false; - y = *p2; - if (last && (0x0C & mask)) { - if (0x04 & mask) { - if (isuy) - v = margin; - else - u = margin; - } else - if (0x08 & mask) - ; - } else { - if (isuy) - v = *(p2 + 1); - else - u = *(p2 + 1); - } - - tmp = ay[(int)y] + rv[(int)v]; - r = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] - gu[(int)u] - gv[(int)v]; - g = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] + bu[(int)u]; - b = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - - if (last && rump) { - pcache = &peasycap->cache[0]; - switch (bytesperpixel - rump) { - case 1: { - *p3 = r; - *pcache++ = g; - *pcache++ = b; - break; - } - case 2: { - *p3 = r; - *(p3 + 1) = g; - *pcache++ = b; - break; - } - default: { - SAM("MISTAKE: %i=rump\n", - bytesperpixel - rump); - return -EFAULT; - } - } - } else { - *p3 = r; - *(p3 + 1) = g; - *(p3 + 2) = b; - } - p2 += 2; - if (isuy) - isuy = false; - else - isuy = true; - p3 += bytesperpixel; - } - return 0; - } else { - /* BGR */ - while (pz > p2) { - if (pr <= (p3 + bytesperpixel)) - last = true; - else - last = false; - y = *p2; - if (last && (0x0C & mask)) { - if (0x04 & mask) { - if (isuy) - v = margin; - else - u = margin; - } - else - if (0x08 & mask) - ; - } else { - if (isuy) - v = *(p2 + 1); - else - u = *(p2 + 1); - } - - tmp = ay[(int)y] + rv[(int)v]; - r = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] - gu[(int)u] - gv[(int)v]; - g = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] + bu[(int)u]; - b = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - - if (last && rump) { - pcache = &peasycap->cache[0]; - switch (bytesperpixel - rump) { - case 1: { - *p3 = b; - *pcache++ = g; - *pcache++ = r; - break; - } - case 2: { - *p3 = b; - *(p3 + 1) = g; - *pcache++ = r; - break; - } - default: { - SAM("MISTAKE: %i=rump\n", - bytesperpixel - rump); - return -EFAULT; - } - } - } else { - *p3 = b; - *(p3 + 1) = g; - *(p3 + 2) = r; - } - p2 += 2; - if (isuy) - isuy = false; - else - isuy = true; - p3 += bytesperpixel; - } - } - return 0; - } else { - if (!byteswaporder) { - /* RGB DECIMATED */ - while (pz > p2) { - if (pr <= (p3 + bytesperpixel)) - last = true; - else - last = false; - y = *p2; - if (last && (0x0C & mask)) { - if (0x04 & mask) { - if (isuy) - v = margin; - else - u = margin; - } else - if (0x08 & mask) - ; - } else { - if (isuy) - v = *(p2 + 1); - else - u = *(p2 + 1); - } - - if (isuy) { - tmp = ay[(int)y] + rv[(int)v]; - r = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] - gu[(int)u] - - gv[(int)v]; - g = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] + bu[(int)u]; - b = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - - if (last && rump) { - pcache = &peasycap->cache[0]; - switch (bytesperpixel - rump) { - case 1: { - *p3 = r; - *pcache++ = g; - *pcache++ = b; - break; - } - case 2: { - *p3 = r; - *(p3 + 1) = g; - *pcache++ = b; - break; - } - default: { - SAM("MISTAKE: " - "%i=rump\n", - bytesperpixel - rump); - return -EFAULT; - } - } - } else { - *p3 = r; - *(p3 + 1) = g; - *(p3 + 2) = b; - } - isuy = false; - p3 += bytesperpixel; - } else { - isuy = true; - } - p2 += 2; - } - return 0; - } else { - /* BGR DECIMATED */ - while (pz > p2) { - if (pr <= (p3 + bytesperpixel)) - last = true; - else - last = false; - y = *p2; - if (last && (0x0C & mask)) { - if (0x04 & mask) { - if (isuy) - v = margin; - else - u = margin; - } else - if (0x08 & mask) - ; - } else { - if (isuy) - v = *(p2 + 1); - else - u = *(p2 + 1); - } - - if (isuy) { - - tmp = ay[(int)y] + rv[(int)v]; - r = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] - gu[(int)u] - - gv[(int)v]; - g = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] + bu[(int)u]; - b = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - - if (last && rump) { - pcache = &peasycap->cache[0]; - switch (bytesperpixel - rump) { - case 1: { - *p3 = b; - *pcache++ = g; - *pcache++ = r; - break; - } - case 2: { - *p3 = b; - *(p3 + 1) = g; - *pcache++ = r; - break; - } - default: { - SAM("MISTAKE: " - "%i=rump\n", - bytesperpixel - rump); - return -EFAULT; - } - } - } else { - *p3 = b; - *(p3 + 1) = g; - *(p3 + 2) = r; - } - isuy = false; - p3 += bytesperpixel; - } - else - isuy = true; - p2 += 2; - } - return 0; - } - } - break; - } - case 4: - { - if (!decimatepixel) { - if (!byteswaporder) { - /* RGBA */ - while (pz > p2) { - if (pr <= (p3 + bytesperpixel)) - last = true; - else - last = false; - y = *p2; - if (last && (0x0C & mask)) { - if (0x04 & mask) { - if (isuy) - v = margin; - else - u = margin; - } else - if (0x08 & mask) - ; - } else { - if (isuy) - v = *(p2 + 1); - else - u = *(p2 + 1); - } - - tmp = ay[(int)y] + rv[(int)v]; - r = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] - gu[(int)u] - gv[(int)v]; - g = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] + bu[(int)u]; - b = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - - if (last && rump) { - pcache = &peasycap->cache[0]; - switch (bytesperpixel - rump) { - case 1: { - *p3 = r; - *pcache++ = g; - *pcache++ = b; - *pcache++ = 0; - break; - } - case 2: { - *p3 = r; - *(p3 + 1) = g; - *pcache++ = b; - *pcache++ = 0; - break; - } - case 3: { - *p3 = r; - *(p3 + 1) = g; - *(p3 + 2) = b; - *pcache++ = 0; - break; - } - default: { - SAM("MISTAKE: %i=rump\n", - bytesperpixel - rump); - return -EFAULT; - } - } - } else { - *p3 = r; - *(p3 + 1) = g; - *(p3 + 2) = b; - *(p3 + 3) = 0; - } - p2 += 2; - if (isuy) - isuy = false; - else - isuy = true; - p3 += bytesperpixel; - } - return 0; - } else { - /* - * BGRA - */ - while (pz > p2) { - if (pr <= (p3 + bytesperpixel)) - last = true; - else - last = false; - y = *p2; - if (last && (0x0C & mask)) { - if (0x04 & mask) { - if (isuy) - v = margin; - else - u = margin; - } else - if (0x08 & mask) - ; - } else { - if (isuy) - v = *(p2 + 1); - else - u = *(p2 + 1); - } - - tmp = ay[(int)y] + rv[(int)v]; - r = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] - gu[(int)u] - gv[(int)v]; - g = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] + bu[(int)u]; - b = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - - if (last && rump) { - pcache = &peasycap->cache[0]; - switch (bytesperpixel - rump) { - case 1: { - *p3 = b; - *pcache++ = g; - *pcache++ = r; - *pcache++ = 0; - break; - } - case 2: { - *p3 = b; - *(p3 + 1) = g; - *pcache++ = r; - *pcache++ = 0; - break; - } - case 3: { - *p3 = b; - *(p3 + 1) = g; - *(p3 + 2) = r; - *pcache++ = 0; - break; - } - default: - SAM("MISTAKE: %i=rump\n", - bytesperpixel - rump); - return -EFAULT; - } - } else { - *p3 = b; - *(p3 + 1) = g; - *(p3 + 2) = r; - *(p3 + 3) = 0; - } - p2 += 2; - if (isuy) - isuy = false; - else - isuy = true; - p3 += bytesperpixel; - } - } - return 0; - } else { - if (!byteswaporder) { - /* - * RGBA DECIMATED - */ - while (pz > p2) { - if (pr <= (p3 + bytesperpixel)) - last = true; - else - last = false; - y = *p2; - if (last && (0x0C & mask)) { - if (0x04 & mask) { - if (isuy) - v = margin; - else - u = margin; - } else - if (0x08 & mask) - ; - } else { - if (isuy) - v = *(p2 + 1); - else - u = *(p2 + 1); - } - - if (isuy) { - - tmp = ay[(int)y] + rv[(int)v]; - r = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] - gu[(int)u] - - gv[(int)v]; - g = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] + bu[(int)u]; - b = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - - if (last && rump) { - pcache = &peasycap->cache[0]; - switch (bytesperpixel - rump) { - case 1: { - *p3 = r; - *pcache++ = g; - *pcache++ = b; - *pcache++ = 0; - break; - } - case 2: { - *p3 = r; - *(p3 + 1) = g; - *pcache++ = b; - *pcache++ = 0; - break; - } - case 3: { - *p3 = r; - *(p3 + 1) = g; - *(p3 + 2) = b; - *pcache++ = 0; - break; - } - default: { - SAM("MISTAKE: " - "%i=rump\n", - bytesperpixel - - rump); - return -EFAULT; - } - } - } else { - *p3 = r; - *(p3 + 1) = g; - *(p3 + 2) = b; - *(p3 + 3) = 0; - } - isuy = false; - p3 += bytesperpixel; - } else - isuy = true; - p2 += 2; - } - return 0; - } else { - /* - * BGRA DECIMATED - */ - while (pz > p2) { - if (pr <= (p3 + bytesperpixel)) - last = true; - else - last = false; - y = *p2; - if (last && (0x0C & mask)) { - if (0x04 & mask) { - if (isuy) - v = margin; - else - u = margin; - } else - if (0x08 & mask) - ; - } else { - if (isuy) - v = *(p2 + 1); - else - u = *(p2 + 1); - } - - if (isuy) { - tmp = ay[(int)y] + rv[(int)v]; - r = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] - gu[(int)u] - - gv[(int)v]; - g = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - tmp = ay[(int)y] + bu[(int)u]; - b = (255 < tmp) ? 255 : ((0 > tmp) ? - 0 : (u8)tmp); - - if (last && rump) { - pcache = &peasycap->cache[0]; - switch (bytesperpixel - rump) { - case 1: { - *p3 = b; - *pcache++ = g; - *pcache++ = r; - *pcache++ = 0; - break; - } - case 2: { - *p3 = b; - *(p3 + 1) = g; - *pcache++ = r; - *pcache++ = 0; - break; - } - case 3: { - *p3 = b; - *(p3 + 1) = g; - *(p3 + 2) = r; - *pcache++ = 0; - break; - } - default: { - SAM("MISTAKE: " - "%i=rump\n", - bytesperpixel - rump); - return -EFAULT; - } - } - } else { - *p3 = b; - *(p3 + 1) = g; - *(p3 + 2) = r; - *(p3 + 3) = 0; - } - isuy = false; - p3 += bytesperpixel; - } else - isuy = true; - p2 += 2; - } - return 0; - } - } - break; - } - default: { - SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel); - return -EFAULT; - } - } - return 0; -} -/*****************************************************************************/ -/* - * SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434 - */ -/*****************************************************************************/ -static void easycap_vma_open(struct vm_area_struct *pvma) -{ - struct easycap *peasycap; - - peasycap = pvma->vm_private_data; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return; - } - peasycap->vma_many++; - JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many); - return; -} -/*****************************************************************************/ -static void easycap_vma_close(struct vm_area_struct *pvma) -{ - struct easycap *peasycap; - - peasycap = pvma->vm_private_data; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return; - } - peasycap->vma_many--; - JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many); - return; -} -/*****************************************************************************/ -static int easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf) -{ - int k, m, retcode; - void *pbuf; - struct page *page; - struct easycap *peasycap; - - retcode = VM_FAULT_NOPAGE; - - if (!pvma) { - SAY("pvma is NULL\n"); - return retcode; - } - if (!pvmf) { - SAY("pvmf is NULL\n"); - return retcode; - } - - k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE); - m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE); - - if (!m) - JOT(4, "%4i=k, %4i=m\n", k, m); - else - JOT(16, "%4i=k, %4i=m\n", k, m); - - if ((0 > k) || (FRAME_BUFFER_MANY <= k)) { - SAY("ERROR: buffer index %i out of range\n", k); - return retcode; - } - if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) { - SAY("ERROR: page number %i out of range\n", m); - return retcode; - } - peasycap = pvma->vm_private_data; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return retcode; - } -/*---------------------------------------------------------------------------*/ - pbuf = peasycap->frame_buffer[k][m].pgo; - if (!pbuf) { - SAM("ERROR: pbuf is NULL\n"); - return retcode; - } - page = virt_to_page(pbuf); - if (!page) { - SAM("ERROR: page is NULL\n"); - return retcode; - } - get_page(page); -/*---------------------------------------------------------------------------*/ - if (!page) { - SAM("ERROR: page is NULL after get_page(page)\n"); - } else { - pvmf->page = page; - retcode = VM_FAULT_MINOR; - } - return retcode; -} - -static const struct vm_operations_struct easycap_vm_ops = { - .open = easycap_vma_open, - .close = easycap_vma_close, - .fault = easycap_vma_fault, -}; - -static int easycap_mmap(struct file *file, struct vm_area_struct *pvma) -{ - JOT(8, "\n"); - - pvma->vm_ops = &easycap_vm_ops; - pvma->vm_flags |= VM_RESERVED; - if (file) - pvma->vm_private_data = file->private_data; - easycap_vma_open(pvma); - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS - * PROVIDED peasycap->video_idle IS ZERO. REGARDLESS OF THIS BEING TRUE, - * IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO. - * - * THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP. - * - * INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE - * STORED IN THE TWO-BYTE STATUS PARAMETER - * peasycap->field_buffer[peasycap->field_fill][0].kount - * NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER. - * - * THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H - * CHIP. - * - * THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE: - * 0 != (kount & 0x8000) => AT LEAST ONE URB COMPLETED WITH ERRORS - * 0 != (kount & 0x4000) => BUFFER HAS TOO MUCH DATA - * 0 != (kount & 0x2000) => BUFFER HAS NOT ENOUGH DATA - * 0 != (kount & 0x1000) => BUFFER HAS DATA FROM DISPARATE INPUTS - * 0 != (kount & 0x0400) => RESERVED - * 0 != (kount & 0x0200) => FIELD BUFFER NOT YET CHECKED - * 0 != (kount & 0x0100) => BUFFER HAS TWO EXTRA BYTES - WHY? - */ -/*---------------------------------------------------------------------------*/ -static void easycap_complete(struct urb *purb) -{ - struct easycap *peasycap; - struct data_buffer *pfield_buffer; - char errbuf[16]; - int i, more, much, leap, rc, last; - int videofieldamount; - unsigned int override, bad; - int framestatus, framelength, frameactual, frameoffset; - u8 *pu; - - if (!purb) { - SAY("ERROR: easycap_complete(): purb is NULL\n"); - return; - } - peasycap = purb->context; - if (!peasycap) { - SAY("ERROR: easycap_complete(): peasycap is NULL\n"); - return; - } - if (peasycap->video_eof) - return; - for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) - if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo) - break; - JOM(16, "%2i=urb\n", i); - last = peasycap->video_isoc_sequence; - if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && (0 != i)) || - (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && ((last + 1) != i))) { - JOM(16, "ERROR: out-of-order urbs %i,%i ... continuing\n", - last, i); - } - peasycap->video_isoc_sequence = i; - - if (peasycap->video_idle) { - JOM(16, "%i=video_idle %i=video_isoc_streaming\n", - peasycap->video_idle, peasycap->video_isoc_streaming); - if (peasycap->video_isoc_streaming) { - rc = usb_submit_urb(purb, GFP_ATOMIC); - if (rc) { - SAM("%s:%d ENOMEM\n", strerror(rc), rc); - if (-ENODEV != rc) - SAM("ERROR: while %i=video_idle, " - "usb_submit_urb() " - "failed with rc:\n", - peasycap->video_idle); - } - } - return; - } - override = 0; -/*---------------------------------------------------------------------------*/ - if (FIELD_BUFFER_MANY <= peasycap->field_fill) { - SAM("ERROR: bad peasycap->field_fill\n"); - return; - } - if (purb->status) { - if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) { - JOM(8, "urb status -ESHUTDOWN or -ENOENT\n"); - return; - } - - (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ; - SAM("ERROR: bad urb status -%s: %d\n", - strerror(purb->status), purb->status); -/*---------------------------------------------------------------------------*/ - } else { - for (i = 0; i < purb->number_of_packets; i++) { - if (0 != purb->iso_frame_desc[i].status) { - (peasycap->field_buffer - [peasycap->field_fill][0].kount) |= 0x8000 ; - /* FIXME: 1. missing '-' check boundaries */ - strcpy(&errbuf[0], - strerror(purb->iso_frame_desc[i].status)); - } - framestatus = purb->iso_frame_desc[i].status; - framelength = purb->iso_frame_desc[i].length; - frameactual = purb->iso_frame_desc[i].actual_length; - frameoffset = purb->iso_frame_desc[i].offset; - - JOM(16, "frame[%2i]:" - "%4i=status " - "%4i=actual " - "%4i=length " - "%5i=offset\n", - i, framestatus, frameactual, framelength, frameoffset); - if (!purb->iso_frame_desc[i].status) { - more = purb->iso_frame_desc[i].actual_length; - pfield_buffer = &peasycap->field_buffer - [peasycap->field_fill][peasycap->field_page]; - videofieldamount = (peasycap->field_page * - PAGE_SIZE) + - (int)(pfield_buffer->pto - pfield_buffer->pgo); - if (4 == more) - peasycap->video_mt++; - if (4 < more) { - if (peasycap->video_mt) { - JOM(8, "%4i empty video urb frames\n", - peasycap->video_mt); - peasycap->video_mt = 0; - } - if (FIELD_BUFFER_MANY <= peasycap->field_fill) { - SAM("ERROR: bad peasycap->field_fill\n"); - return; - } - if (FIELD_BUFFER_SIZE/PAGE_SIZE <= - peasycap->field_page) { - SAM("ERROR: bad peasycap->field_page\n"); - return; - } - pfield_buffer = &peasycap->field_buffer - [peasycap->field_fill][peasycap->field_page]; - pu = (u8 *)(purb->transfer_buffer + - purb->iso_frame_desc[i].offset); - if (0x80 & *pu) - leap = 8; - else - leap = 4; -/*--------------------------------------------------------------------------*/ -/* - * EIGHT-BYTE END-OF-VIDEOFIELD MARKER. - * NOTE: A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY, - * CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD. - * - * PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER - * BYTE OF - * peasycap->field_buffer[peasycap->field_fill][0].kount - * THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS - * UPDATED AND field_fill IS BUMPED. IF THE FIELD BUFFER CONTAINS BAD DATA - * NOTHING IS OFFERED TO dqbuf(). - * - * THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT - * RESTS WITH dqbuf(). - */ -/*---------------------------------------------------------------------------*/ - if ((8 == more) || override) { - if (videofieldamount > - peasycap->videofieldamount) { - if (2 == videofieldamount - - peasycap-> - videofieldamount) { - (peasycap->field_buffer - [peasycap->field_fill] - [0].kount) |= 0x0100; - peasycap->video_junk += (1 + - VIDEO_JUNK_TOLERATE); - } else - (peasycap->field_buffer - [peasycap->field_fill] - [0].kount) |= 0x4000; - } else if (videofieldamount < - peasycap-> - videofieldamount) { - (peasycap->field_buffer - [peasycap->field_fill] - [0].kount) |= 0x2000; - } - bad = 0xFF00 & peasycap->field_buffer - [peasycap->field_fill] - [0].kount; - if (!bad) { - (peasycap->video_junk)--; - if (-VIDEO_JUNK_TOLERATE > - peasycap->video_junk) - peasycap->video_junk = - -VIDEO_JUNK_TOLERATE; - peasycap->field_read = - (peasycap-> - field_fill)++; - if (FIELD_BUFFER_MANY <= - peasycap-> - field_fill) - peasycap-> - field_fill = 0; - peasycap->field_page = 0; - pfield_buffer = &peasycap-> - field_buffer - [peasycap-> - field_fill] - [peasycap-> - field_page]; - pfield_buffer->pto = - pfield_buffer->pgo; - JOM(8, "bumped to: %i=" - "peasycap->" - "field_fill %i=" - "parity\n", - peasycap->field_fill, - 0x00FF & - pfield_buffer->kount); - JOM(8, "field buffer %i has " - "%i bytes fit to be " - "read\n", - peasycap->field_read, - videofieldamount); - JOM(8, "wakeup call to " - "wq_video, " - "%i=field_read " - "%i=field_fill " - "%i=parity\n", - peasycap->field_read, - peasycap->field_fill, - 0x00FF & peasycap-> - field_buffer - [peasycap-> - field_read][0].kount); - wake_up_interruptible - (&(peasycap-> - wq_video)); - } else { - peasycap->video_junk++; - if (bad & 0x0010) - peasycap->video_junk += - (1 + VIDEO_JUNK_TOLERATE/2); - JOM(8, "field buffer %i had %i " - "bytes, now discarded: " - "0x%04X\n", - peasycap->field_fill, - videofieldamount, - (0xFF00 & - peasycap->field_buffer - [peasycap->field_fill][0]. - kount)); - (peasycap->field_fill)++; - - if (FIELD_BUFFER_MANY <= - peasycap->field_fill) - peasycap->field_fill = 0; - peasycap->field_page = 0; - pfield_buffer = - &peasycap->field_buffer - [peasycap->field_fill] - [peasycap->field_page]; - pfield_buffer->pto = - pfield_buffer->pgo; - - JOM(8, "bumped to: %i=peasycap->" - "field_fill %i=parity\n", - peasycap->field_fill, - 0x00FF & pfield_buffer->kount); - } - if (8 == more) { - JOM(8, "end-of-field: received " - "parity byte 0x%02X\n", - (0xFF & *pu)); - if (0x40 & *pu) - pfield_buffer->kount = 0x0000; - else - pfield_buffer->kount = 0x0001; - pfield_buffer->input = 0x08 | - (0x07 & peasycap->input); - JOM(8, "end-of-field: 0x%02X=kount\n", - 0xFF & pfield_buffer->kount); - } - } -/*---------------------------------------------------------------------------*/ -/* - * COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER - */ -/*---------------------------------------------------------------------------*/ - pu += leap; - more -= leap; - - if (FIELD_BUFFER_MANY <= peasycap->field_fill) { - SAM("ERROR: bad peasycap->field_fill\n"); - return; - } - if (FIELD_BUFFER_SIZE/PAGE_SIZE <= peasycap->field_page) { - SAM("ERROR: bad peasycap->field_page\n"); - return; - } - pfield_buffer = &peasycap->field_buffer - [peasycap->field_fill][peasycap->field_page]; - while (more) { - pfield_buffer = &peasycap->field_buffer - [peasycap->field_fill] - [peasycap->field_page]; - if (PAGE_SIZE < (pfield_buffer->pto - - pfield_buffer->pgo)) { - SAM("ERROR: bad pfield_buffer->pto\n"); - return; - } - if (PAGE_SIZE == (pfield_buffer->pto - - pfield_buffer->pgo)) { - (peasycap->field_page)++; - if (FIELD_BUFFER_SIZE/PAGE_SIZE <= - peasycap->field_page) { - JOM(16, "wrapping peasycap->" - "field_page\n"); - peasycap->field_page = 0; - } - pfield_buffer = &peasycap-> - field_buffer - [peasycap->field_fill] - [peasycap->field_page]; - pfield_buffer->pto = pfield_buffer->pgo; - pfield_buffer->input = 0x08 | - (0x07 & peasycap->input); - if ((peasycap->field_buffer[peasycap-> - field_fill][0]). - input != - pfield_buffer->input) - (peasycap->field_buffer - [peasycap->field_fill] - [0]).kount |= 0x1000; - } - - much = PAGE_SIZE - - (int)(pfield_buffer->pto - - pfield_buffer->pgo); - - if (much > more) - much = more; - memcpy(pfield_buffer->pto, pu, much); - pu += much; - (pfield_buffer->pto) += much; - more -= much; - } - } - } - } - } -/*---------------------------------------------------------------------------*/ -/* - * RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS. - * - * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION - * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE. - */ -/*---------------------------------------------------------------------------*/ - if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) { - SAM("easycap driver shutting down on condition green\n"); - peasycap->status = 1; - peasycap->video_eof = 1; - peasycap->video_junk = 0; - wake_up_interruptible(&peasycap->wq_video); -#if !defined(PERSEVERE) - peasycap->audio_eof = 1; - wake_up_interruptible(&peasycap->wq_audio); -#endif /*PERSEVERE*/ - return; - } - if (peasycap->video_isoc_streaming) { - rc = usb_submit_urb(purb, GFP_ATOMIC); - if (rc) { - SAM("%s: %d\n", strerror(rc), rc); - if (-ENODEV != rc) - SAM("ERROR: while %i=video_idle, " - "usb_submit_urb() " - "failed with rc:\n", - peasycap->video_idle); - } - } - return; -} - -static struct easycap *alloc_easycap(u8 bInterfaceNumber) -{ - struct easycap *peasycap; - int i; - - peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL); - if (!peasycap) { - SAY("ERROR: Could not allocate peasycap\n"); - return NULL; - } - - if (mutex_lock_interruptible(&mutex_dongle)) { - SAY("ERROR: cannot lock mutex_dongle\n"); - kfree(peasycap); - return NULL; - } - - /* Find a free dongle in easycapdc60_dongle array */ - for (i = 0; i < DONGLE_MANY; i++) { - - if ((!easycapdc60_dongle[i].peasycap) && - (!mutex_is_locked(&easycapdc60_dongle[i].mutex_video)) && - (!mutex_is_locked(&easycapdc60_dongle[i].mutex_audio))) { - - easycapdc60_dongle[i].peasycap = peasycap; - peasycap->isdongle = i; - JOM(8, "intf[%i]: peasycap-->easycap" - "_dongle[%i].peasycap\n", - bInterfaceNumber, i); - break; - } - } - - mutex_unlock(&mutex_dongle); - - if (i >= DONGLE_MANY) { - SAM("ERROR: too many dongles\n"); - kfree(peasycap); - return NULL; - } - - return peasycap; -} - -static void free_easycap(struct easycap *peasycap) -{ - int allocation_video_urb; - int allocation_video_page; - int allocation_video_struct; - int allocation_audio_urb; - int allocation_audio_page; - int allocation_audio_struct; - int registered_video, registered_audio; - int kd; - - JOM(4, "freeing easycap structure.\n"); - allocation_video_urb = peasycap->allocation_video_urb; - allocation_video_page = peasycap->allocation_video_page; - allocation_video_struct = peasycap->allocation_video_struct; - registered_video = peasycap->registered_video; - allocation_audio_urb = peasycap->allocation_audio_urb; - allocation_audio_page = peasycap->allocation_audio_page; - allocation_audio_struct = peasycap->allocation_audio_struct; - registered_audio = peasycap->registered_audio; - - kd = easycap_isdongle(peasycap); - if (0 <= kd && DONGLE_MANY > kd) { - if (mutex_lock_interruptible(&mutex_dongle)) { - SAY("ERROR: cannot down mutex_dongle\n"); - } else { - JOM(4, "locked mutex_dongle\n"); - easycapdc60_dongle[kd].peasycap = NULL; - mutex_unlock(&mutex_dongle); - JOM(4, "unlocked mutex_dongle\n"); - JOT(4, " null-->dongle[%i].peasycap\n", kd); - allocation_video_struct -= sizeof(struct easycap); - } - } else { - SAY("ERROR: cannot purge dongle[].peasycap"); - } - - /* Free device structure */ - kfree(peasycap); - - SAY("%8i=video urbs after all deletions\n", allocation_video_urb); - SAY("%8i=video pages after all deletions\n", allocation_video_page); - SAY("%8i=video structs after all deletions\n", allocation_video_struct); - SAY("%8i=video devices after all deletions\n", registered_video); - SAY("%8i=audio urbs after all deletions\n", allocation_audio_urb); - SAY("%8i=audio pages after all deletions\n", allocation_audio_page); - SAY("%8i=audio structs after all deletions\n", allocation_audio_struct); - SAY("%8i=audio devices after all deletions\n", registered_audio); -} - -/* - * FIXME: Identify the appropriate pointer peasycap for interfaces - * 1 and 2. The address of peasycap->pusb_device is reluctantly used - * for this purpose. - */ -static struct easycap *get_easycap(struct usb_device *usbdev, - u8 bInterfaceNumber) -{ - int i; - struct easycap *peasycap; - - for (i = 0; i < DONGLE_MANY; i++) { - if (easycapdc60_dongle[i].peasycap->pusb_device == usbdev) { - peasycap = easycapdc60_dongle[i].peasycap; - JOT(8, "intf[%i]: dongle[%i].peasycap\n", - bInterfaceNumber, i); - break; - } - } - if (i >= DONGLE_MANY) { - SAY("ERROR: peasycap is unknown when probing interface %i\n", - bInterfaceNumber); - return NULL; - } - if (!peasycap) { - SAY("ERROR: peasycap is NULL when probing interface %i\n", - bInterfaceNumber); - return NULL; - } - - return peasycap; -} - -static void init_easycap(struct easycap *peasycap, - struct usb_device *usbdev, - struct usb_interface *intf, - u8 bInterfaceNumber) -{ - /* Save usb_device and usb_interface */ - peasycap->pusb_device = usbdev; - peasycap->pusb_interface = intf; - - peasycap->minor = -1; - kref_init(&peasycap->kref); - JOM(8, "intf[%i]: after kref_init(..._video) " - "%i=peasycap->kref.refcount.counter\n", - bInterfaceNumber, peasycap->kref.refcount.counter); - - /* module params */ - peasycap->gain = (s8)clamp(easycap_gain, 0, 31); - - init_waitqueue_head(&peasycap->wq_video); - init_waitqueue_head(&peasycap->wq_audio); - init_waitqueue_head(&peasycap->wq_trigger); - - peasycap->allocation_video_struct = sizeof(struct easycap); - - peasycap->microphone = false; - - peasycap->video_interface = -1; - peasycap->video_altsetting_on = -1; - peasycap->video_altsetting_off = -1; - peasycap->video_endpointnumber = -1; - peasycap->video_isoc_maxframesize = -1; - peasycap->video_isoc_buffer_size = -1; - - peasycap->audio_interface = -1; - peasycap->audio_altsetting_on = -1; - peasycap->audio_altsetting_off = -1; - peasycap->audio_endpointnumber = -1; - peasycap->audio_isoc_maxframesize = -1; - peasycap->audio_isoc_buffer_size = -1; - - peasycap->frame_buffer_many = FRAME_BUFFER_MANY; - - peasycap->ntsc = easycap_ntsc; - JOM(8, "defaulting initially to %s\n", - easycap_ntsc ? "NTSC" : "PAL"); -} - -static int populate_inputset(struct easycap *peasycap) -{ - struct inputset *inputset; - struct easycap_format *peasycap_format; - struct v4l2_pix_format *pix; - int m, i, k, mask, fmtidx; - s32 value; - - inputset = peasycap->inputset; - - fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN; - - m = 0; - mask = 0; - for (i = 0; easycap_standard[i].mask != 0xffff; i++) { - if (fmtidx == easycap_standard[i].v4l2_standard.index) { - m++; - for (k = 0; k < INPUT_MANY; k++) - inputset[k].standard_offset = i; - mask = easycap_standard[i].mask; - } - } - - if (m != 1) { - SAM("ERROR: inputset->standard_offset unpopulated, %i=m\n", m); - return -ENOENT; - } - - peasycap_format = &easycap_format[0]; - m = 0; - for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) { - pix = &peasycap_format->v4l2_format.fmt.pix; - if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) - && pix->field == V4L2_FIELD_NONE - && pix->pixelformat == V4L2_PIX_FMT_UYVY - && pix->width == 640 && pix->height == 480) { - m++; - for (k = 0; k < INPUT_MANY; k++) - inputset[k].format_offset = i; - break; - } - peasycap_format++; - } - if (m != 1) { - SAM("ERROR: inputset[]->format_offset unpopulated\n"); - return -ENOENT; - } - - m = 0; - for (i = 0; easycap_control[i].id != 0xffffffff; i++) { - value = easycap_control[i].default_value; - if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) { - m++; - for (k = 0; k < INPUT_MANY; k++) - inputset[k].brightness = value; - } else if (V4L2_CID_CONTRAST == easycap_control[i].id) { - m++; - for (k = 0; k < INPUT_MANY; k++) - inputset[k].contrast = value; - } else if (V4L2_CID_SATURATION == easycap_control[i].id) { - m++; - for (k = 0; k < INPUT_MANY; k++) - inputset[k].saturation = value; - } else if (V4L2_CID_HUE == easycap_control[i].id) { - m++; - for (k = 0; k < INPUT_MANY; k++) - inputset[k].hue = value; - } - } - - if (m != 4) { - SAM("ERROR: inputset[]->brightness underpopulated\n"); - return -ENOENT; - } - - for (k = 0; k < INPUT_MANY; k++) - inputset[k].input = k; - JOM(4, "populated inputset[]\n"); - - return 0; -} - -static int alloc_framebuffers(struct easycap *peasycap) -{ - int i, j; - void *pbuf; - - JOM(4, "allocating %i frame buffers of size %li\n", - FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE); - JOM(4, ".... each scattered over %li pages\n", - FRAME_BUFFER_SIZE/PAGE_SIZE); - - for (i = 0; i < FRAME_BUFFER_MANY; i++) { - for (j = 0; j < FRAME_BUFFER_SIZE/PAGE_SIZE; j++) { - if (peasycap->frame_buffer[i][j].pgo) - SAM("attempting to reallocate framebuffers\n"); - else { - pbuf = (void *)__get_free_page(GFP_KERNEL); - if (!pbuf) { - SAM("ERROR: Could not allocate " - "framebuffer %i page %i\n", i, j); - return -ENOMEM; - } - peasycap->allocation_video_page += 1; - peasycap->frame_buffer[i][j].pgo = pbuf; - } - peasycap->frame_buffer[i][j].pto = - peasycap->frame_buffer[i][j].pgo; - } - } - - peasycap->frame_fill = 0; - peasycap->frame_read = 0; - JOM(4, "allocation of frame buffers done: %i pages\n", i*j); - - return 0; -} - -static void free_framebuffers(struct easycap *peasycap) -{ - int k, m, gone; - - JOM(4, "freeing video frame buffers.\n"); - gone = 0; - for (k = 0; k < FRAME_BUFFER_MANY; k++) { - for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) { - if (peasycap->frame_buffer[k][m].pgo) { - free_page((unsigned long) - peasycap->frame_buffer[k][m].pgo); - peasycap->frame_buffer[k][m].pgo = NULL; - peasycap->allocation_video_page -= 1; - gone++; - } - } - } - JOM(4, "video frame buffers freed: %i pages\n", gone); -} - -static int alloc_fieldbuffers(struct easycap *peasycap) -{ - int i, j; - void *pbuf; - - JOM(4, "allocating %i field buffers of size %li\n", - FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE); - JOM(4, ".... each scattered over %li pages\n", - FIELD_BUFFER_SIZE/PAGE_SIZE); - - for (i = 0; i < FIELD_BUFFER_MANY; i++) { - for (j = 0; j < FIELD_BUFFER_SIZE/PAGE_SIZE; j++) { - if (peasycap->field_buffer[i][j].pgo) { - SAM("ERROR: attempting to reallocate " - "fieldbuffers\n"); - } else { - pbuf = (void *) __get_free_page(GFP_KERNEL); - if (!pbuf) { - SAM("ERROR: Could not allocate " - "fieldbuffer %i page %i\n", i, j); - return -ENOMEM; - } - peasycap->allocation_video_page += 1; - peasycap->field_buffer[i][j].pgo = pbuf; - } - peasycap->field_buffer[i][j].pto = - peasycap->field_buffer[i][j].pgo; - } - /* TODO: Hardcoded 0x0200 meaning? */ - peasycap->field_buffer[i][0].kount = 0x0200; - } - peasycap->field_fill = 0; - peasycap->field_page = 0; - peasycap->field_read = 0; - JOM(4, "allocation of field buffers done: %i pages\n", i*j); - - return 0; -} - -static void free_fieldbuffers(struct easycap *peasycap) -{ - int k, m, gone; - - JOM(4, "freeing video field buffers.\n"); - gone = 0; - for (k = 0; k < FIELD_BUFFER_MANY; k++) { - for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) { - if (peasycap->field_buffer[k][m].pgo) { - free_page((unsigned long) - peasycap->field_buffer[k][m].pgo); - peasycap->field_buffer[k][m].pgo = NULL; - peasycap->allocation_video_page -= 1; - gone++; - } - } - } - JOM(4, "video field buffers freed: %i pages\n", gone); -} - -static int alloc_isocbuffers(struct easycap *peasycap) -{ - int i; - void *pbuf; - - JOM(4, "allocating %i isoc video buffers of size %i\n", - VIDEO_ISOC_BUFFER_MANY, - peasycap->video_isoc_buffer_size); - JOM(4, ".... each occupying contiguous memory pages\n"); - - for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) { - pbuf = (void *)__get_free_pages(GFP_KERNEL, - VIDEO_ISOC_ORDER); - if (!pbuf) { - SAM("ERROR: Could not allocate isoc " - "video buffer %i\n", i); - return -ENOMEM; - } - peasycap->allocation_video_page += BIT(VIDEO_ISOC_ORDER); - - peasycap->video_isoc_buffer[i].pgo = pbuf; - peasycap->video_isoc_buffer[i].pto = - pbuf + peasycap->video_isoc_buffer_size; - peasycap->video_isoc_buffer[i].kount = i; - } - JOM(4, "allocation of isoc video buffers done: %i pages\n", - i * (0x01 << VIDEO_ISOC_ORDER)); - return 0; -} - -static void free_isocbuffers(struct easycap *peasycap) -{ - int k, m; - - JOM(4, "freeing video isoc buffers.\n"); - m = 0; - for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) { - if (peasycap->video_isoc_buffer[k].pgo) { - free_pages((unsigned long) - peasycap->video_isoc_buffer[k].pgo, - VIDEO_ISOC_ORDER); - peasycap->video_isoc_buffer[k].pgo = NULL; - peasycap->allocation_video_page -= - BIT(VIDEO_ISOC_ORDER); - m++; - } - } - JOM(4, "isoc video buffers freed: %i pages\n", - m * (0x01 << VIDEO_ISOC_ORDER)); -} - -static int create_video_urbs(struct easycap *peasycap) -{ - struct urb *purb; - struct data_urb *pdata_urb; - int i, j; - - JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY); - JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n", - peasycap->video_isoc_framesperdesc); - JOM(4, "using %i=peasycap->video_isoc_maxframesize\n", - peasycap->video_isoc_maxframesize); - JOM(4, "using %i=peasycap->video_isoc_buffer_sizen", - peasycap->video_isoc_buffer_size); - - for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) { - purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc, - GFP_KERNEL); - if (!purb) { - SAM("ERROR: usb_alloc_urb returned NULL for buffer " - "%i\n", i); - return -ENOMEM; - } - - peasycap->allocation_video_urb += 1; - pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL); - if (!pdata_urb) { - SAM("ERROR: Could not allocate struct data_urb.\n"); - return -ENOMEM; - } - - peasycap->allocation_video_struct += - sizeof(struct data_urb); - - pdata_urb->purb = purb; - pdata_urb->isbuf = i; - pdata_urb->length = 0; - list_add_tail(&(pdata_urb->list_head), - peasycap->purb_video_head); - - if (!i) { - JOM(4, "initializing video urbs thus:\n"); - JOM(4, " purb->interval = 1;\n"); - JOM(4, " purb->dev = peasycap->pusb_device;\n"); - JOM(4, " purb->pipe = usb_rcvisocpipe" - "(peasycap->pusb_device,%i);\n", - peasycap->video_endpointnumber); - JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n"); - JOM(4, " purb->transfer_buffer = peasycap->" - "video_isoc_buffer[.].pgo;\n"); - JOM(4, " purb->transfer_buffer_length = %i;\n", - peasycap->video_isoc_buffer_size); - JOM(4, " purb->complete = easycap_complete;\n"); - JOM(4, " purb->context = peasycap;\n"); - JOM(4, " purb->start_frame = 0;\n"); - JOM(4, " purb->number_of_packets = %i;\n", - peasycap->video_isoc_framesperdesc); - JOM(4, " for (j = 0; j < %i; j++)\n", - peasycap->video_isoc_framesperdesc); - JOM(4, " {\n"); - JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n", - peasycap->video_isoc_maxframesize); - JOM(4, " purb->iso_frame_desc[j].length = %i;\n", - peasycap->video_isoc_maxframesize); - JOM(4, " }\n"); - } - - purb->interval = 1; - purb->dev = peasycap->pusb_device; - purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, - peasycap->video_endpointnumber); - - purb->transfer_flags = URB_ISO_ASAP; - purb->transfer_buffer = peasycap->video_isoc_buffer[i].pgo; - purb->transfer_buffer_length = - peasycap->video_isoc_buffer_size; - - purb->complete = easycap_complete; - purb->context = peasycap; - purb->start_frame = 0; - purb->number_of_packets = peasycap->video_isoc_framesperdesc; - - for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) { - purb->iso_frame_desc[j].offset = - j * peasycap->video_isoc_maxframesize; - purb->iso_frame_desc[j].length = - peasycap->video_isoc_maxframesize; - } - } - JOM(4, "allocation of %i struct urb done.\n", i); - return 0; -} - -static void free_video_urbs(struct easycap *peasycap) -{ - struct list_head *plist_head, *plist_next; - struct data_urb *pdata_urb; - int m; - - if (peasycap->purb_video_head) { - m = 0; - list_for_each(plist_head, peasycap->purb_video_head) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - usb_free_urb(pdata_urb->purb); - pdata_urb->purb = NULL; - peasycap->allocation_video_urb--; - m++; - } - } - - JOM(4, "%i video urbs freed\n", m); - JOM(4, "freeing video data_urb structures.\n"); - m = 0; - list_for_each_safe(plist_head, plist_next, - peasycap->purb_video_head) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb) { - peasycap->allocation_video_struct -= - sizeof(struct data_urb); - kfree(pdata_urb); - m++; - } - } - JOM(4, "%i video data_urb structures freed\n", m); - JOM(4, "setting peasycap->purb_video_head=NULL\n"); - peasycap->purb_video_head = NULL; - } -} - -static int alloc_audio_buffers(struct easycap *peasycap) -{ - void *pbuf; - int k; - - JOM(4, "allocating %i isoc audio buffers of size %i\n", - AUDIO_ISOC_BUFFER_MANY, - peasycap->audio_isoc_buffer_size); - JOM(4, ".... each occupying contiguous memory pages\n"); - - for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) { - pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER); - if (!pbuf) { - SAM("ERROR: Could not allocate isoc audio buffer %i\n", - k); - return -ENOMEM; - } - peasycap->allocation_audio_page += BIT(AUDIO_ISOC_ORDER); - - peasycap->audio_isoc_buffer[k].pgo = pbuf; - peasycap->audio_isoc_buffer[k].pto = - pbuf + peasycap->audio_isoc_buffer_size; - peasycap->audio_isoc_buffer[k].kount = k; - } - - JOM(4, "allocation of isoc audio buffers done.\n"); - return 0; -} - -static void free_audio_buffers(struct easycap *peasycap) -{ - int k, m; - - JOM(4, "freeing audio isoc buffers.\n"); - m = 0; - for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) { - if (peasycap->audio_isoc_buffer[k].pgo) { - free_pages((unsigned long) - (peasycap->audio_isoc_buffer[k].pgo), - AUDIO_ISOC_ORDER); - peasycap->audio_isoc_buffer[k].pgo = NULL; - peasycap->allocation_audio_page -= - BIT(AUDIO_ISOC_ORDER); - m++; - } - } - JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n", - m * (0x01 << AUDIO_ISOC_ORDER)); -} - -static int create_audio_urbs(struct easycap *peasycap) -{ - struct urb *purb; - struct data_urb *pdata_urb; - int k, j; - - JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY); - JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n", - peasycap->audio_isoc_framesperdesc); - JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n", - peasycap->audio_isoc_maxframesize); - JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n", - peasycap->audio_isoc_buffer_size); - - for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) { - purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc, - GFP_KERNEL); - if (!purb) { - SAM("ERROR: usb_alloc_urb returned NULL for buffer " - "%i\n", k); - return -ENOMEM; - } - peasycap->allocation_audio_urb += 1 ; - pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL); - if (!pdata_urb) { - usb_free_urb(purb); - SAM("ERROR: Could not allocate struct data_urb.\n"); - return -ENOMEM; - } - peasycap->allocation_audio_struct += - sizeof(struct data_urb); - - pdata_urb->purb = purb; - pdata_urb->isbuf = k; - pdata_urb->length = 0; - list_add_tail(&(pdata_urb->list_head), - peasycap->purb_audio_head); - - if (!k) { - JOM(4, "initializing audio urbs thus:\n"); - JOM(4, " purb->interval = 1;\n"); - JOM(4, " purb->dev = peasycap->pusb_device;\n"); - JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->" - "pusb_device,%i);\n", - peasycap->audio_endpointnumber); - JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n"); - JOM(4, " purb->transfer_buffer = " - "peasycap->audio_isoc_buffer[.].pgo;\n"); - JOM(4, " purb->transfer_buffer_length = %i;\n", - peasycap->audio_isoc_buffer_size); - JOM(4, " purb->complete = easycap_alsa_complete;\n"); - JOM(4, " purb->context = peasycap;\n"); - JOM(4, " purb->start_frame = 0;\n"); - JOM(4, " purb->number_of_packets = %i;\n", - peasycap->audio_isoc_framesperdesc); - JOM(4, " for (j = 0; j < %i; j++)\n", - peasycap->audio_isoc_framesperdesc); - JOM(4, " {\n"); - JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n", - peasycap->audio_isoc_maxframesize); - JOM(4, " purb->iso_frame_desc[j].length = %i;\n", - peasycap->audio_isoc_maxframesize); - JOM(4, " }\n"); - } - - purb->interval = 1; - purb->dev = peasycap->pusb_device; - purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, - peasycap->audio_endpointnumber); - purb->transfer_flags = URB_ISO_ASAP; - purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo; - purb->transfer_buffer_length = - peasycap->audio_isoc_buffer_size; - purb->complete = easycap_alsa_complete; - purb->context = peasycap; - purb->start_frame = 0; - purb->number_of_packets = peasycap->audio_isoc_framesperdesc; - for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) { - purb->iso_frame_desc[j].offset = - j * peasycap->audio_isoc_maxframesize; - purb->iso_frame_desc[j].length = - peasycap->audio_isoc_maxframesize; - } - } - JOM(4, "allocation of %i struct urb done.\n", k); - return 0; -} - -static void free_audio_urbs(struct easycap *peasycap) -{ - struct list_head *plist_head, *plist_next; - struct data_urb *pdata_urb; - int m; - - if (peasycap->purb_audio_head) { - JOM(4, "freeing audio urbs\n"); - m = 0; - list_for_each(plist_head, (peasycap->purb_audio_head)) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - usb_free_urb(pdata_urb->purb); - pdata_urb->purb = NULL; - peasycap->allocation_audio_urb--; - m++; - } - } - JOM(4, "%i audio urbs freed\n", m); - JOM(4, "freeing audio data_urb structures.\n"); - m = 0; - list_for_each_safe(plist_head, plist_next, - peasycap->purb_audio_head) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb) { - peasycap->allocation_audio_struct -= - sizeof(struct data_urb); - kfree(pdata_urb); - m++; - } - } - JOM(4, "%i audio data_urb structures freed\n", m); - JOM(4, "setting peasycap->purb_audio_head=NULL\n"); - peasycap->purb_audio_head = NULL; - } -} - -static void config_easycap(struct easycap *peasycap, - u8 bInterfaceNumber, - u8 bInterfaceClass, - u8 bInterfaceSubClass) -{ - if ((USB_CLASS_VIDEO == bInterfaceClass) || - (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) { - if (-1 == peasycap->video_interface) { - peasycap->video_interface = bInterfaceNumber; - JOM(4, "setting peasycap->video_interface=%i\n", - peasycap->video_interface); - } else { - if (peasycap->video_interface != bInterfaceNumber) { - SAM("ERROR: attempting to reset " - "peasycap->video_interface\n"); - SAM("...... continuing with " - "%i=peasycap->video_interface\n", - peasycap->video_interface); - } - } - } else if ((USB_CLASS_AUDIO == bInterfaceClass) && - (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) { - if (-1 == peasycap->audio_interface) { - peasycap->audio_interface = bInterfaceNumber; - JOM(4, "setting peasycap->audio_interface=%i\n", - peasycap->audio_interface); - } else { - if (peasycap->audio_interface != bInterfaceNumber) { - SAM("ERROR: attempting to reset " - "peasycap->audio_interface\n"); - SAM("...... continuing with " - "%i=peasycap->audio_interface\n", - peasycap->audio_interface); - } - } - } -} - -/* - * This function is called from within easycap_usb_disconnect() and is - * protected by semaphores set and cleared by easycap_usb_disconnect(). - * By this stage the device has already been physically unplugged, - * so peasycap->pusb_device is no longer valid. - */ -static void easycap_delete(struct kref *pkref) -{ - struct easycap *peasycap; - - peasycap = container_of(pkref, struct easycap, kref); - if (!peasycap) { - SAM("ERROR: peasycap is NULL: cannot perform deletions\n"); - return; - } - - /* Free video urbs */ - free_video_urbs(peasycap); - - /* Free video isoc buffers */ - free_isocbuffers(peasycap); - - /* Free video field buffers */ - free_fieldbuffers(peasycap); - - /* Free video frame buffers */ - free_framebuffers(peasycap); - - /* Free audio urbs */ - free_audio_urbs(peasycap); - - /* Free audio isoc buffers */ - free_audio_buffers(peasycap); - - free_easycap(peasycap); - - JOT(4, "ending.\n"); -} - -static const struct v4l2_file_operations v4l2_fops = { - .owner = THIS_MODULE, - .open = easycap_open_noinode, - .unlocked_ioctl = easycap_unlocked_ioctl, - .poll = easycap_poll, - .mmap = easycap_mmap, -}; - -static int easycap_register_video(struct easycap *peasycap) -{ - /* - * FIXME: This is believed to be harmless, - * but may well be unnecessary or wrong. - */ - peasycap->video_device.v4l2_dev = NULL; - - strcpy(&peasycap->video_device.name[0], "easycapdc60"); - peasycap->video_device.fops = &v4l2_fops; - peasycap->video_device.minor = -1; - peasycap->video_device.release = (void *)(&videodev_release); - - video_set_drvdata(&(peasycap->video_device), (void *)peasycap); - - if (0 != (video_register_device(&(peasycap->video_device), - VFL_TYPE_GRABBER, -1))) { - err("Not able to register with videodev"); - videodev_release(&(peasycap->video_device)); - return -ENODEV; - } - - peasycap->registered_video++; - - SAM("registered with videodev: %i=minor\n", - peasycap->video_device.minor); - peasycap->minor = peasycap->video_device.minor; - - return 0; -} - -/* - * When the device is plugged, this function is called three times, - * one for each interface. - */ -static int easycap_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usbdev; - struct usb_host_interface *alt; - struct usb_endpoint_descriptor *ep; - struct usb_interface_descriptor *interface; - struct easycap *peasycap; - int i, j, rc; - u8 bInterfaceNumber; - u8 bInterfaceClass; - u8 bInterfaceSubClass; - int okalt[8], isokalt; - int okepn[8]; - int okmps[8]; - int maxpacketsize; - - usbdev = interface_to_usbdev(intf); - - alt = usb_altnum_to_altsetting(intf, 0); - if (!alt) { - SAY("ERROR: usb_host_interface not found\n"); - return -EFAULT; - } - - interface = &alt->desc; - if (!interface) { - SAY("ERROR: intf_descriptor is NULL\n"); - return -EFAULT; - } - - /* Get properties of probed interface */ - bInterfaceNumber = interface->bInterfaceNumber; - bInterfaceClass = interface->bInterfaceClass; - bInterfaceSubClass = interface->bInterfaceSubClass; - - JOT(4, "intf[%i]: num_altsetting=%i\n", - bInterfaceNumber, intf->num_altsetting); - JOT(4, "intf[%i]: cur_altsetting - altsetting=%li\n", - bInterfaceNumber, - (long int)(intf->cur_altsetting - intf->altsetting)); - JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n", - bInterfaceNumber, bInterfaceClass, bInterfaceSubClass); - - /* - * A new struct easycap is always allocated when interface 0 is probed. - * It is not possible here to free any existing struct easycap. - * This should have been done by easycap_delete() when the device was - * physically unplugged. - * The allocated struct easycap is saved for later usage when - * interfaces 1 and 2 are probed. - */ - if (0 == bInterfaceNumber) { - /* - * Alloc structure and save it in a free slot in - * easycapdc60_dongle array - */ - peasycap = alloc_easycap(bInterfaceNumber); - if (!peasycap) - return -ENOMEM; - - /* Perform basic struct initialization */ - init_easycap(peasycap, usbdev, intf, bInterfaceNumber); - - /* Dynamically fill in the available formats */ - rc = easycap_video_fillin_formats(); - if (0 > rc) { - SAM("ERROR: fillin_formats() rc = %i\n", rc); - return -EFAULT; - } - JOM(4, "%i formats available\n", rc); - - /* Populate easycap.inputset[] */ - rc = populate_inputset(peasycap); - if (rc < 0) - return rc; - JOM(4, "finished initialization\n"); - } else { - peasycap = get_easycap(usbdev, bInterfaceNumber); - if (!peasycap) - return -ENODEV; - } - - config_easycap(peasycap, bInterfaceNumber, - bInterfaceClass, - bInterfaceSubClass); - - /* - * Investigate all altsettings. This is done in detail - * because USB device 05e1:0408 has disparate incarnations. - */ - isokalt = 0; - for (i = 0; i < intf->num_altsetting; i++) { - alt = usb_altnum_to_altsetting(intf, i); - if (!alt) { - SAM("ERROR: alt is NULL\n"); - return -EFAULT; - } - interface = &alt->desc; - if (!interface) { - SAM("ERROR: intf_descriptor is NULL\n"); - return -EFAULT; - } - - if (0 == interface->bNumEndpoints) - JOM(4, "intf[%i]alt[%i] has no endpoints\n", - bInterfaceNumber, i); - for (j = 0; j < interface->bNumEndpoints; j++) { - ep = &alt->endpoint[j].desc; - if (!ep) { - SAM("ERROR: ep is NULL.\n"); - SAM("...... skipping\n"); - continue; - } - - if (!usb_endpoint_is_isoc_in(ep)) { - JOM(4, "intf[%i]alt[%i]end[%i] is a %d endpoint\n", - bInterfaceNumber, - i, j, ep->bmAttributes); - if (usb_endpoint_dir_out(ep)) { - SAM("ERROR: OUT endpoint unexpected\n"); - SAM("...... continuing\n"); - } - continue; - } - switch (bInterfaceClass) { - case USB_CLASS_VIDEO: - case USB_CLASS_VENDOR_SPEC: { - if (ep->wMaxPacketSize) { - if (8 > isokalt) { - okalt[isokalt] = i; - JOM(4, - "%i=okalt[%i]\n", - okalt[isokalt], - isokalt); - okepn[isokalt] = - ep-> - bEndpointAddress & - 0x0F; - JOM(4, - "%i=okepn[%i]\n", - okepn[isokalt], - isokalt); - okmps[isokalt] = - le16_to_cpu(ep-> - wMaxPacketSize); - JOM(4, - "%i=okmps[%i]\n", - okmps[isokalt], - isokalt); - isokalt++; - } - } else { - if (-1 == peasycap-> - video_altsetting_off) { - peasycap-> - video_altsetting_off = - i; - JOM(4, "%i=video_" - "altsetting_off " - "<====\n", - peasycap-> - video_altsetting_off); - } else { - SAM("ERROR: peasycap" - "->video_altsetting_" - "off already set\n"); - SAM("...... " - "continuing with " - "%i=peasycap->video_" - "altsetting_off\n", - peasycap-> - video_altsetting_off); - } - } - break; - } - case USB_CLASS_AUDIO: { - if (bInterfaceSubClass != - USB_SUBCLASS_AUDIOSTREAMING) - break; - if (!peasycap) { - SAM("MISTAKE: " - "peasycap is NULL\n"); - return -EFAULT; - } - if (ep->wMaxPacketSize) { - if (8 > isokalt) { - okalt[isokalt] = i ; - JOM(4, - "%i=okalt[%i]\n", - okalt[isokalt], - isokalt); - okepn[isokalt] = - ep-> - bEndpointAddress & - 0x0F; - JOM(4, - "%i=okepn[%i]\n", - okepn[isokalt], - isokalt); - okmps[isokalt] = - le16_to_cpu(ep-> - wMaxPacketSize); - JOM(4, - "%i=okmps[%i]\n", - okmps[isokalt], - isokalt); - isokalt++; - } - } else { - if (-1 == peasycap-> - audio_altsetting_off) { - peasycap-> - audio_altsetting_off = - i; - JOM(4, "%i=audio_" - "altsetting_off " - "<====\n", - peasycap-> - audio_altsetting_off); - } else { - SAM("ERROR: peasycap" - "->audio_altsetting_" - "off already set\n"); - SAM("...... " - "continuing with " - "%i=peasycap->" - "audio_altsetting_" - "off\n", - peasycap-> - audio_altsetting_off); - } - } - break; - } - default: - break; - } - if (0 == ep->wMaxPacketSize) { - JOM(4, "intf[%i]alt[%i]end[%i] " - "has zero packet size\n", - bInterfaceNumber, i, j); - } - } - } - - /* Perform initialization of the probed interface */ - JOM(4, "initialization begins for interface %i\n", - interface->bInterfaceNumber); - switch (bInterfaceNumber) { - /* 0: Video interface */ - case 0: { - if (!peasycap) { - SAM("MISTAKE: peasycap is NULL\n"); - return -EFAULT; - } - if (!isokalt) { - SAM("ERROR: no viable video_altsetting_on\n"); - return -ENOENT; - } - peasycap->video_altsetting_on = okalt[isokalt - 1]; - JOM(4, "%i=video_altsetting_on <====\n", - peasycap->video_altsetting_on); - - /* Decide video streaming parameters */ - peasycap->video_endpointnumber = okepn[isokalt - 1]; - JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber); - maxpacketsize = okmps[isokalt - 1]; - - peasycap->video_isoc_maxframesize = - min(maxpacketsize, USB_2_0_MAXPACKETSIZE); - if (0 >= peasycap->video_isoc_maxframesize) { - SAM("ERROR: bad video_isoc_maxframesize\n"); - SAM(" possibly because port is USB 1.1\n"); - return -ENOENT; - } - JOM(4, "%i=video_isoc_maxframesize\n", - peasycap->video_isoc_maxframesize); - - peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC; - JOM(4, "%i=video_isoc_framesperdesc\n", - peasycap->video_isoc_framesperdesc); - if (0 >= peasycap->video_isoc_framesperdesc) { - SAM("ERROR: bad video_isoc_framesperdesc\n"); - return -ENOENT; - } - peasycap->video_isoc_buffer_size = - peasycap->video_isoc_maxframesize * - peasycap->video_isoc_framesperdesc; - JOM(4, "%i=video_isoc_buffer_size\n", - peasycap->video_isoc_buffer_size); - if ((PAGE_SIZE << VIDEO_ISOC_ORDER) < - peasycap->video_isoc_buffer_size) { - SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n"); - return -EFAULT; - } - if (-1 == peasycap->video_interface) { - SAM("MISTAKE: video_interface is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->video_altsetting_on) { - SAM("MISTAKE: video_altsetting_on is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->video_altsetting_off) { - SAM("MISTAKE: video_interface_off is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->video_endpointnumber) { - SAM("MISTAKE: video_endpointnumber is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->video_isoc_maxframesize) { - SAM("MISTAKE: video_isoc_maxframesize is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->video_isoc_buffer_size) { - SAM("MISTAKE: video_isoc_buffer_size is unset\n"); - return -EFAULT; - } - - /* - * Allocate memory for video buffers. - * Lists must be initialized first. - */ - INIT_LIST_HEAD(&(peasycap->urb_video_head)); - peasycap->purb_video_head = &(peasycap->urb_video_head); - - rc = alloc_framebuffers(peasycap); - if (rc < 0) - return rc; - - rc = alloc_fieldbuffers(peasycap); - if (rc < 0) - return rc; - - rc = alloc_isocbuffers(peasycap); - if (rc < 0) - return rc; - - /* Allocate and initialize video urbs */ - rc = create_video_urbs(peasycap); - if (rc < 0) - return rc; - - /* Save pointer peasycap in this interface */ - usb_set_intfdata(intf, peasycap); - - /* - * It is essential to initialize the hardware before, - * rather than after, the device is registered, - * because some udev rules triggers easycap_open() - * immediately after registration, causing a clash. - */ - rc = reset(peasycap); - if (rc) { - SAM("ERROR: reset() rc = %i\n", rc); - return -EFAULT; - } - - /* The video device can now be registered */ - if (v4l2_device_register(&intf->dev, &peasycap->v4l2_device)) { - SAM("v4l2_device_register() failed\n"); - return -ENODEV; - } - JOM(4, "registered device instance: %s\n", - peasycap->v4l2_device.name); - - rc = easycap_register_video(peasycap); - if (rc < 0) - return -ENODEV; - break; - } - /* 1: Audio control */ - case 1: { - if (!peasycap) { - SAM("MISTAKE: peasycap is NULL\n"); - return -EFAULT; - } - /* Save pointer peasycap in this interface */ - usb_set_intfdata(intf, peasycap); - JOM(4, "no initialization required for interface %i\n", - interface->bInterfaceNumber); - break; - } - /* 2: Audio streaming */ - case 2: { - if (!peasycap) { - SAM("MISTAKE: peasycap is NULL\n"); - return -EFAULT; - } - if (!isokalt) { - SAM("ERROR: no viable audio_altsetting_on\n"); - return -ENOENT; - } - peasycap->audio_altsetting_on = okalt[isokalt - 1]; - JOM(4, "%i=audio_altsetting_on <====\n", - peasycap->audio_altsetting_on); - - peasycap->audio_endpointnumber = okepn[isokalt - 1]; - JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber); - - peasycap->audio_isoc_maxframesize = okmps[isokalt - 1]; - JOM(4, "%i=audio_isoc_maxframesize\n", - peasycap->audio_isoc_maxframesize); - if (0 >= peasycap->audio_isoc_maxframesize) { - SAM("ERROR: bad audio_isoc_maxframesize\n"); - return -ENOENT; - } - if (9 == peasycap->audio_isoc_maxframesize) { - peasycap->ilk |= 0x02; - SAM("audio hardware is microphone\n"); - peasycap->microphone = true; - peasycap->audio_pages_per_fragment = - PAGES_PER_AUDIO_FRAGMENT; - } else if (256 == peasycap->audio_isoc_maxframesize) { - peasycap->ilk &= ~0x02; - SAM("audio hardware is AC'97\n"); - peasycap->microphone = false; - peasycap->audio_pages_per_fragment = - PAGES_PER_AUDIO_FRAGMENT; - } else { - SAM("hardware is unidentified:\n"); - SAM("%i=audio_isoc_maxframesize\n", - peasycap->audio_isoc_maxframesize); - return -ENOENT; - } - - peasycap->audio_bytes_per_fragment = - peasycap->audio_pages_per_fragment * PAGE_SIZE; - peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY * - peasycap->audio_pages_per_fragment); - - JOM(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY); - JOM(4, "%6i=audio_pages_per_fragment\n", - peasycap->audio_pages_per_fragment); - JOM(4, "%6i=audio_bytes_per_fragment\n", - peasycap->audio_bytes_per_fragment); - JOM(4, "%6i=audio_buffer_page_many\n", - peasycap->audio_buffer_page_many); - - peasycap->audio_isoc_framesperdesc = AUDIO_ISOC_FRAMESPERDESC; - - JOM(4, "%i=audio_isoc_framesperdesc\n", - peasycap->audio_isoc_framesperdesc); - if (0 >= peasycap->audio_isoc_framesperdesc) { - SAM("ERROR: bad audio_isoc_framesperdesc\n"); - return -ENOENT; - } - - peasycap->audio_isoc_buffer_size = - peasycap->audio_isoc_maxframesize * - peasycap->audio_isoc_framesperdesc; - JOM(4, "%i=audio_isoc_buffer_size\n", - peasycap->audio_isoc_buffer_size); - if (AUDIO_ISOC_BUFFER_SIZE < peasycap->audio_isoc_buffer_size) { - SAM("MISTAKE: audio_isoc_buffer_size bigger " - "than %li=AUDIO_ISOC_BUFFER_SIZE\n", - AUDIO_ISOC_BUFFER_SIZE); - return -EFAULT; - } - if (-1 == peasycap->audio_interface) { - SAM("MISTAKE: audio_interface is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->audio_altsetting_on) { - SAM("MISTAKE: audio_altsetting_on is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->audio_altsetting_off) { - SAM("MISTAKE: audio_interface_off is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->audio_endpointnumber) { - SAM("MISTAKE: audio_endpointnumber is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->audio_isoc_maxframesize) { - SAM("MISTAKE: audio_isoc_maxframesize is unset\n"); - return -EFAULT; - } - if (-1 == peasycap->audio_isoc_buffer_size) { - SAM("MISTAKE: audio_isoc_buffer_size is unset\n"); - return -EFAULT; - } - - /* - * Allocate memory for audio buffers. - * Lists must be initialized first. - */ - INIT_LIST_HEAD(&(peasycap->urb_audio_head)); - peasycap->purb_audio_head = &(peasycap->urb_audio_head); - - alloc_audio_buffers(peasycap); - if (rc < 0) - return rc; - - /* Allocate and initialize urbs */ - rc = create_audio_urbs(peasycap); - if (rc < 0) - return rc; - - /* Save pointer peasycap in this interface */ - usb_set_intfdata(intf, peasycap); - - /* The audio device can now be registered */ - JOM(4, "initializing ALSA card\n"); - - rc = easycap_alsa_probe(peasycap); - if (rc) { - err("easycap_alsa_probe() rc = %i\n", rc); - return -ENODEV; - } - - - JOM(8, "kref_get() with %i=kref.refcount.counter\n", - peasycap->kref.refcount.counter); - kref_get(&peasycap->kref); - peasycap->registered_audio++; - break; - } - /* Interfaces other than 0,1,2 are unexpected */ - default: - JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber); - return -EINVAL; - } - SAM("ends successfully for interface %i\n", bInterfaceNumber); - return 0; -} - -/* - * When this function is called the device has already been - * physically unplugged. - * Hence, peasycap->pusb_device is no longer valid. - * This function affects alsa. - */ -static void easycap_usb_disconnect(struct usb_interface *pusb_interface) -{ - struct usb_host_interface *pusb_host_interface; - struct usb_interface_descriptor *pusb_interface_descriptor; - struct easycap *peasycap; - int minor, kd; - u8 bInterfaceNumber; - - JOT(4, "\n"); - - pusb_host_interface = pusb_interface->cur_altsetting; - if (!pusb_host_interface) { - JOT(4, "ERROR: pusb_host_interface is NULL\n"); - return; - } - pusb_interface_descriptor = &(pusb_host_interface->desc); - if (!pusb_interface_descriptor) { - JOT(4, "ERROR: pusb_interface_descriptor is NULL\n"); - return; - } - bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber; - minor = pusb_interface->minor; - JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor); - - /* There is nothing to do for Interface Number 1 */ - if (1 == bInterfaceNumber) - return; - - peasycap = usb_get_intfdata(pusb_interface); - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return; - } - - /* If the waitqueues are not cleared a deadlock is possible */ - peasycap->video_eof = 1; - peasycap->audio_eof = 1; - wake_up_interruptible(&(peasycap->wq_video)); - wake_up_interruptible(&(peasycap->wq_audio)); - - switch (bInterfaceNumber) { - case 0: - easycap_video_kill_urbs(peasycap); - break; - case 2: - easycap_audio_kill_urbs(peasycap); - break; - default: - break; - } - - /* - * Deregister - * This procedure will block until easycap_poll(), - * video and audio ioctl are all unlocked. - * If this is not done an oops can occur when an easycap - * is unplugged while the urbs are running. - */ - kd = easycap_isdongle(peasycap); - switch (bInterfaceNumber) { - case 0: { - if (0 <= kd && DONGLE_MANY > kd) { - wake_up_interruptible(&peasycap->wq_video); - JOM(4, "about to lock dongle[%i].mutex_video\n", kd); - if (mutex_lock_interruptible(&easycapdc60_dongle[kd]. - mutex_video)) { - SAY("ERROR: " - "cannot lock dongle[%i].mutex_video\n", kd); - return; - } - JOM(4, "locked dongle[%i].mutex_video\n", kd); - } else { - SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd); - } - if (!peasycap->v4l2_device.name[0]) { - SAM("ERROR: peasycap->v4l2_device.name is empty\n"); - if (0 <= kd && DONGLE_MANY > kd) - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - return; - } - v4l2_device_disconnect(&peasycap->v4l2_device); - JOM(4, "v4l2_device_disconnect() OK\n"); - v4l2_device_unregister(&peasycap->v4l2_device); - JOM(4, "v4l2_device_unregister() OK\n"); - - video_unregister_device(&peasycap->video_device); - JOM(4, "intf[%i]: video_unregister_device() minor=%i\n", - bInterfaceNumber, minor); - peasycap->registered_video--; - - if (0 <= kd && DONGLE_MANY > kd) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - JOM(4, "unlocked dongle[%i].mutex_video\n", kd); - } - break; - } - case 2: { - if (0 <= kd && DONGLE_MANY > kd) { - wake_up_interruptible(&peasycap->wq_audio); - JOM(4, "about to lock dongle[%i].mutex_audio\n", kd); - if (mutex_lock_interruptible(&easycapdc60_dongle[kd]. - mutex_audio)) { - SAY("ERROR: " - "cannot lock dongle[%i].mutex_audio\n", kd); - return; - } - JOM(4, "locked dongle[%i].mutex_audio\n", kd); - } else - SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd); - if (0 != snd_card_free(peasycap->psnd_card)) { - SAY("ERROR: snd_card_free() failed\n"); - } else { - peasycap->psnd_card = NULL; - (peasycap->registered_audio)--; - } - if (0 <= kd && DONGLE_MANY > kd) { - mutex_unlock(&easycapdc60_dongle[kd].mutex_audio); - JOM(4, "unlocked dongle[%i].mutex_audio\n", kd); - } - break; - } - default: - break; - } - - /* - * If no remaining references to peasycap, - * call easycap_delete. - * (Also when alsa has been in use) - */ - if (!peasycap->kref.refcount.counter) { - SAM("ERROR: peasycap->kref.refcount.counter is zero " - "so cannot call kref_put()\n"); - SAM("ending unsuccessfully: may cause memory leak\n"); - return; - } - if (0 <= kd && DONGLE_MANY > kd) { - JOM(4, "about to lock dongle[%i].mutex_video\n", kd); - if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) { - SAY("ERROR: cannot lock dongle[%i].mutex_video\n", kd); - SAM("ending unsuccessfully: may cause memory leak\n"); - return; - } - JOM(4, "locked dongle[%i].mutex_video\n", kd); - JOM(4, "about to lock dongle[%i].mutex_audio\n", kd); - if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) { - SAY("ERROR: cannot lock dongle[%i].mutex_audio\n", kd); - mutex_unlock(&(easycapdc60_dongle[kd].mutex_video)); - JOM(4, "unlocked dongle[%i].mutex_video\n", kd); - SAM("ending unsuccessfully: may cause memory leak\n"); - return; - } - JOM(4, "locked dongle[%i].mutex_audio\n", kd); - } - JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n", - bInterfaceNumber, (int)peasycap->kref.refcount.counter); - kref_put(&peasycap->kref, easycap_delete); - JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber); - if (0 <= kd && DONGLE_MANY > kd) { - mutex_unlock(&(easycapdc60_dongle[kd].mutex_audio)); - JOT(4, "unlocked dongle[%i].mutex_audio\n", kd); - mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - JOT(4, "unlocked dongle[%i].mutex_video\n", kd); - } - JOM(4, "ends\n"); - return; -} - -/* Devices supported by this driver */ -static struct usb_device_id easycap_usb_device_id_table[] = { - {USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)}, - { } -}; - -MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table); -static struct usb_driver easycap_usb_driver = { - .name = "easycap", - .id_table = easycap_usb_device_id_table, - .probe = easycap_usb_probe, - .disconnect = easycap_usb_disconnect, -}; - -static int __init easycap_module_init(void) -{ - int k, rc; - - printk(KERN_INFO "Easycap version: "EASYCAP_DRIVER_VERSION "\n"); - - JOT(4, "begins. %i=debug %i=bars %i=gain\n", - easycap_debug, easycap_bars, easycap_gain); - - mutex_init(&mutex_dongle); - for (k = 0; k < DONGLE_MANY; k++) { - easycapdc60_dongle[k].peasycap = NULL; - mutex_init(&easycapdc60_dongle[k].mutex_video); - mutex_init(&easycapdc60_dongle[k].mutex_audio); - } - rc = usb_register(&easycap_usb_driver); - if (rc) - printk(KERN_ERR "Easycap: usb_register failed rc=%d\n", rc); - - return rc; -} - -static void __exit easycap_module_exit(void) -{ - usb_deregister(&easycap_usb_driver); -} - -module_init(easycap_module_init); -module_exit(easycap_module_exit); diff --git a/drivers/staging/media/easycap/easycap_settings.c b/drivers/staging/media/easycap/easycap_settings.c deleted file mode 100644 index 3f5f5b3..0000000 --- a/drivers/staging/media/easycap/easycap_settings.c +++ /dev/null @@ -1,696 +0,0 @@ -/****************************************************************************** -* * -* easycap_settings.c * -* * -******************************************************************************/ -/* - * - * Copyright (C) 2010 R.M. Thomas rmthomas@sciolus.org - * - * - * This 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. - * - * The software 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 software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ -/*****************************************************************************/ - -#include "easycap.h" - -/*---------------------------------------------------------------------------*/ -/* - * THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING: - * 0 => 25 fps - * 1 => 30 fps - * - * THE MOST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING: - * 0 => full framerate - * 1 => 20% framerate - */ -/*---------------------------------------------------------------------------*/ -const struct easycap_standard easycap_standard[] = { - { - .mask = 0x00FF & PAL_BGHIN , - .v4l2_standard = { - .index = PAL_BGHIN, - .id = (V4L2_STD_PAL_B | - V4L2_STD_PAL_G | V4L2_STD_PAL_H | - V4L2_STD_PAL_I | V4L2_STD_PAL_N), - .name = "PAL_BGHIN", - .frameperiod = {1, 25}, - .framelines = 625, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & NTSC_N_443 , - .v4l2_standard = { - .index = NTSC_N_443, - .id = V4L2_STD_UNKNOWN, - .name = "NTSC_N_443", - .frameperiod = {1, 25}, - .framelines = 480, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & PAL_Nc , - .v4l2_standard = { - .index = PAL_Nc, - .id = V4L2_STD_PAL_Nc, - .name = "PAL_Nc", - .frameperiod = {1, 25}, - .framelines = 625, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & NTSC_N , - .v4l2_standard = { - .index = NTSC_N, - .id = V4L2_STD_UNKNOWN, - .name = "NTSC_N", - .frameperiod = {1, 25}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & SECAM , - .v4l2_standard = { - .index = SECAM, - .id = V4L2_STD_SECAM, - .name = "SECAM", - .frameperiod = {1, 25}, - .framelines = 625, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & NTSC_M , - .v4l2_standard = { - .index = NTSC_M, - .id = V4L2_STD_NTSC_M, - .name = "NTSC_M", - .frameperiod = {1, 30}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & NTSC_M_JP , - .v4l2_standard = { - .index = NTSC_M_JP, - .id = V4L2_STD_NTSC_M_JP, - .name = "NTSC_M_JP", - .frameperiod = {1, 30}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & PAL_60 , - .v4l2_standard = { - .index = PAL_60, - .id = V4L2_STD_PAL_60, - .name = "PAL_60", - .frameperiod = {1, 30}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & NTSC_443 , - .v4l2_standard = { - .index = NTSC_443, - .id = V4L2_STD_NTSC_443, - .name = "NTSC_443", - .frameperiod = {1, 30}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x00FF & PAL_M , - .v4l2_standard = { - .index = PAL_M, - .id = V4L2_STD_PAL_M, - .name = "PAL_M", - .frameperiod = {1, 30}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW), - .v4l2_standard = { - .index = PAL_BGHIN_SLOW, - .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | - V4L2_STD_PAL_H | - V4L2_STD_PAL_I | V4L2_STD_PAL_N | - (((v4l2_std_id)0x01) << 32)), - .name = "PAL_BGHIN_SLOW", - .frameperiod = {1, 5}, - .framelines = 625, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW), - .v4l2_standard = { - .index = NTSC_N_443_SLOW, - .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)), - .name = "NTSC_N_443_SLOW", - .frameperiod = {1, 5}, - .framelines = 480, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & PAL_Nc_SLOW), - .v4l2_standard = { - .index = PAL_Nc_SLOW, - .id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)), - .name = "PAL_Nc_SLOW", - .frameperiod = {1, 5}, - .framelines = 625, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & NTSC_N_SLOW), - .v4l2_standard = { - .index = NTSC_N_SLOW, - .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)), - .name = "NTSC_N_SLOW", - .frameperiod = {1, 5}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & SECAM_SLOW), - .v4l2_standard = { - .index = SECAM_SLOW, - .id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)), - .name = "SECAM_SLOW", - .frameperiod = {1, 5}, - .framelines = 625, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & NTSC_M_SLOW), - .v4l2_standard = { - .index = NTSC_M_SLOW, - .id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)), - .name = "NTSC_M_SLOW", - .frameperiod = {1, 6}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW), - .v4l2_standard = { - .index = NTSC_M_JP_SLOW, - .id = (V4L2_STD_NTSC_M_JP | - (((v4l2_std_id)0x01) << 32)), - .name = "NTSC_M_JP_SLOW", - .frameperiod = {1, 6}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & PAL_60_SLOW), - .v4l2_standard = { - .index = PAL_60_SLOW, - .id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)), - .name = "PAL_60_SLOW", - .frameperiod = {1, 6}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & NTSC_443_SLOW), - .v4l2_standard = { - .index = NTSC_443_SLOW, - .id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)), - .name = "NTSC_443_SLOW", - .frameperiod = {1, 6}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0x8000 | (0x00FF & PAL_M_SLOW), - .v4l2_standard = { - .index = PAL_M_SLOW, - .id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)), - .name = "PAL_M_SLOW", - .frameperiod = {1, 6}, - .framelines = 525, - .reserved = {0, 0, 0, 0} - } - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .mask = 0xFFFF - } -}; -/*---------------------------------------------------------------------------*/ -/* - * THE 16-BIT easycap_format.mask HAS MEANING: - * (least significant) BIT 0: 0 => PAL, 25 FPS; 1 => NTSC, 30 FPS - * BITS 2-4: RESERVED FOR DIFFERENTIATING STANDARDS - * BITS 5-7: NUMBER OF BYTES PER PIXEL - * BIT 8: 0 => NATIVE BYTE ORDER; 1 => SWAPPED - * BITS 9-10: RESERVED FOR OTHER BYTE PERMUTATIONS - * BIT 11: 0 => UNDECIMATED; 1 => DECIMATED - * BIT 12: 0 => OFFER FRAMES; 1 => OFFER FIELDS - * BIT 13: 0 => FULL FRAMERATE; 1 => REDUCED - * (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS - * IT FOLLOWS THAT: - * bytesperpixel IS ((0x00E0 & easycap_format.mask) >> 5) - * byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask)) - * - * decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask)) - * - * offerfields IS true IF (0 != (0x1000 & easycap_format.mask)) - */ -/*---------------------------------------------------------------------------*/ - -struct easycap_format easycap_format[1 + SETTINGS_MANY]; - -int easycap_video_fillin_formats(void) -{ - const char *name1, *name2, *name3, *name4; - struct v4l2_format *fmt; - int i, j, k, m, n; - u32 width, height, pixelformat, bytesperline, sizeimage; - u16 mask1, mask2, mask3, mask4; - enum v4l2_field field; - enum v4l2_colorspace colorspace; - - for (i = 0, n = 0; i < STANDARD_MANY; i++) { - mask1 = 0x0000; - switch (i) { - case PAL_BGHIN: { - mask1 = 0x1F & PAL_BGHIN; - name1 = "PAL_BGHIN"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case SECAM: { - mask1 = 0x1F & SECAM; - name1 = "SECAM"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case PAL_Nc: { - mask1 = 0x1F & PAL_Nc; - name1 = "PAL_Nc"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case PAL_60: { - mask1 = 0x1F & PAL_60; - name1 = "PAL_60"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case PAL_M: { - mask1 = 0x1F & PAL_M; - name1 = "PAL_M"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case NTSC_M: { - mask1 = 0x1F & NTSC_M; - name1 = "NTSC_M"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case NTSC_443: { - mask1 = 0x1F & NTSC_443; - name1 = "NTSC_443"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case NTSC_M_JP: { - mask1 = 0x1F & NTSC_M_JP; - name1 = "NTSC_M_JP"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case NTSC_N: { - mask1 = 0x1F & NTSC_M; - name1 = "NTSC_N"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case NTSC_N_443: { - mask1 = 0x1F & NTSC_N_443; - name1 = "NTSC_N_443"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case PAL_BGHIN_SLOW: { - mask1 = 0x001F & PAL_BGHIN_SLOW; - mask1 |= 0x0200; - name1 = "PAL_BGHIN_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case SECAM_SLOW: { - mask1 = 0x001F & SECAM_SLOW; - mask1 |= 0x0200; - name1 = "SECAM_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case PAL_Nc_SLOW: { - mask1 = 0x001F & PAL_Nc_SLOW; - mask1 |= 0x0200; - name1 = "PAL_Nc_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case PAL_60_SLOW: { - mask1 = 0x001F & PAL_60_SLOW; - mask1 |= 0x0200; - name1 = "PAL_60_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case PAL_M_SLOW: { - mask1 = 0x001F & PAL_M_SLOW; - mask1 |= 0x0200; - name1 = "PAL_M_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_BG; - break; - } - case NTSC_M_SLOW: { - mask1 = 0x001F & NTSC_M_SLOW; - mask1 |= 0x0200; - name1 = "NTSC_M_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case NTSC_443_SLOW: { - mask1 = 0x001F & NTSC_443_SLOW; - mask1 |= 0x0200; - name1 = "NTSC_443_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case NTSC_M_JP_SLOW: { - mask1 = 0x001F & NTSC_M_JP_SLOW; - mask1 |= 0x0200; - name1 = "NTSC_M_JP_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case NTSC_N_SLOW: { - mask1 = 0x001F & NTSC_N_SLOW; - mask1 |= 0x0200; - name1 = "NTSC_N_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - case NTSC_N_443_SLOW: { - mask1 = 0x001F & NTSC_N_443_SLOW; - mask1 |= 0x0200; - name1 = "NTSC_N_443_SLOW"; - colorspace = V4L2_COLORSPACE_470_SYSTEM_M; - break; - } - default: - return -1; - } - - for (j = 0; j < RESOLUTION_MANY; j++) { - mask2 = 0x0000; - switch (j) { - case AT_720x576: { - if (0x1 & mask1) - continue; - name2 = "_AT_720x576"; - width = 720; - height = 576; - break; - } - case AT_704x576: { - if (0x1 & mask1) - continue; - name2 = "_AT_704x576"; - width = 704; - height = 576; - break; - } - case AT_640x480: { - name2 = "_AT_640x480"; - width = 640; - height = 480; - break; - } - case AT_720x480: { - if (!(0x1 & mask1)) - continue; - name2 = "_AT_720x480"; - width = 720; - height = 480; - break; - } - case AT_360x288: { - if (0x1 & mask1) - continue; - name2 = "_AT_360x288"; - width = 360; - height = 288; - mask2 = 0x0800; - break; - } - case AT_320x240: { - name2 = "_AT_320x240"; - width = 320; - height = 240; - mask2 = 0x0800; - break; - } - case AT_360x240: { - if (!(0x1 & mask1)) - continue; - name2 = "_AT_360x240"; - width = 360; - height = 240; - mask2 = 0x0800; - break; - } - default: - return -2; - } - - for (k = 0; k < PIXELFORMAT_MANY; k++) { - mask3 = 0x0000; - switch (k) { - case FMT_UYVY: { - name3 = __stringify(FMT_UYVY); - pixelformat = V4L2_PIX_FMT_UYVY; - mask3 |= (0x02 << 5); - break; - } - case FMT_YUY2: { - name3 = __stringify(FMT_YUY2); - pixelformat = V4L2_PIX_FMT_YUYV; - mask3 |= (0x02 << 5); - mask3 |= 0x0100; - break; - } - case FMT_RGB24: { - name3 = __stringify(FMT_RGB24); - pixelformat = V4L2_PIX_FMT_RGB24; - mask3 |= (0x03 << 5); - break; - } - case FMT_RGB32: { - name3 = __stringify(FMT_RGB32); - pixelformat = V4L2_PIX_FMT_RGB32; - mask3 |= (0x04 << 5); - break; - } - case FMT_BGR24: { - name3 = __stringify(FMT_BGR24); - pixelformat = V4L2_PIX_FMT_BGR24; - mask3 |= (0x03 << 5); - mask3 |= 0x0100; - break; - } - case FMT_BGR32: { - name3 = __stringify(FMT_BGR32); - pixelformat = V4L2_PIX_FMT_BGR32; - mask3 |= (0x04 << 5); - mask3 |= 0x0100; - break; - } - default: - return -3; - } - bytesperline = width * ((mask3 & 0x00E0) >> 5); - sizeimage = bytesperline * height; - - for (m = 0; m < INTERLACE_MANY; m++) { - mask4 = 0x0000; - switch (m) { - case FIELD_NONE: { - name4 = "-n"; - field = V4L2_FIELD_NONE; - break; - } - case FIELD_INTERLACED: { - name4 = "-i"; - mask4 |= 0x1000; - field = V4L2_FIELD_INTERLACED; - break; - } - default: - return -4; - } - if (SETTINGS_MANY <= n) - return -5; - - strcpy(easycap_format[n].name, name1); - strcat(easycap_format[n].name, name2); - strcat(easycap_format[n].name, "_"); - strcat(easycap_format[n].name, name3); - strcat(easycap_format[n].name, name4); - easycap_format[n].mask = - mask1 | mask2 | mask3 | mask4; - fmt = &easycap_format[n].v4l2_format; - - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt->fmt.pix.width = width; - fmt->fmt.pix.height = height; - fmt->fmt.pix.pixelformat = pixelformat; - fmt->fmt.pix.field = field; - fmt->fmt.pix.bytesperline = bytesperline; - fmt->fmt.pix.sizeimage = sizeimage; - fmt->fmt.pix.colorspace = colorspace; - fmt->fmt.pix.priv = 0; - n++; - } - } - } - } - if ((1 + SETTINGS_MANY) <= n) - return -6; - easycap_format[n].mask = 0xFFFF; - return n; -} -/*---------------------------------------------------------------------------*/ -struct v4l2_queryctrl easycap_control[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = SAA_0A_DEFAULT, - .flags = 0, - .reserved = {0, 0} - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = SAA_0B_DEFAULT + 128, - .flags = 0, - .reserved = {0, 0} - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = SAA_0C_DEFAULT + 128, - .flags = 0, - .reserved = {0, 0} - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = SAA_0D_DEFAULT + 128, - .flags = 0, - .reserved = {0, 0} - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .id = V4L2_CID_AUDIO_VOLUME, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Volume", - .minimum = 0, - .maximum = 31, - .step = 1, - .default_value = 16, - .flags = 0, - .reserved = {0, 0} - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .default_value = true, - .flags = 0, - .reserved = {0, 0} - }, -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - { - .id = 0xFFFFFFFF - } -}; -/*****************************************************************************/ diff --git a/drivers/staging/media/easycap/easycap_sound.c b/drivers/staging/media/easycap/easycap_sound.c deleted file mode 100644 index 8c8bcae..0000000 --- a/drivers/staging/media/easycap/easycap_sound.c +++ /dev/null @@ -1,750 +0,0 @@ -/****************************************************************************** -* * -* easycap_sound.c * -* * -* Audio driver for EasyCAP USB2.0 Video Capture Device DC60 * -* * -* * -******************************************************************************/ -/* - * - * Copyright (C) 2010 R.M. Thomas rmthomas@sciolus.org - * - * - * This 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. - * - * The software 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 software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ -/*****************************************************************************/ - -#include "easycap.h" - -/*--------------------------------------------------------------------------*/ -/* - * PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE - */ -/*--------------------------------------------------------------------------*/ -static const struct snd_pcm_hardware alsa_hardware = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000, - .rate_min = 32000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = PAGE_SIZE * - PAGES_PER_AUDIO_FRAGMENT * - AUDIO_FRAGMENT_MANY, - .period_bytes_min = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT, - .period_bytes_max = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT * 2, - .periods_min = AUDIO_FRAGMENT_MANY, - .periods_max = AUDIO_FRAGMENT_MANY * 2, -}; - - -/*---------------------------------------------------------------------------*/ -/* - * SUBMIT ALL AUDIO URBS. - */ -/*---------------------------------------------------------------------------*/ -static int easycap_audio_submit_urbs(struct easycap *peasycap) -{ - struct data_urb *pdata_urb; - struct urb *purb; - struct list_head *plist_head; - int j, isbad, nospc, m, rc; - int isbuf; - - if (!peasycap->purb_audio_head) { - SAM("ERROR: peasycap->urb_audio_head uninitialized\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - - if (peasycap->audio_isoc_streaming) { - JOM(4, "already streaming audio urbs\n"); - return 0; - } - - JOM(4, "initial submission of all audio urbs\n"); - rc = usb_set_interface(peasycap->pusb_device, - peasycap->audio_interface, - peasycap->audio_altsetting_on); - JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", - peasycap->audio_interface, - peasycap->audio_altsetting_on, rc); - - isbad = 0; - nospc = 0; - m = 0; - list_for_each(plist_head, peasycap->purb_audio_head) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - purb = pdata_urb->purb; - isbuf = pdata_urb->isbuf; - - purb->interval = 1; - purb->dev = peasycap->pusb_device; - purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, - peasycap->audio_endpointnumber); - purb->transfer_flags = URB_ISO_ASAP; - purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo; - purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size; - purb->complete = easycap_alsa_complete; - purb->context = peasycap; - purb->start_frame = 0; - purb->number_of_packets = peasycap->audio_isoc_framesperdesc; - for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) { - purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize; - purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize; - } - - rc = usb_submit_urb(purb, GFP_KERNEL); - if (rc) { - isbad++; - SAM("ERROR: usb_submit_urb() failed" - " for urb with rc: -%s: %d\n", - strerror(rc), rc); - } else { - m++; - } - } else { - isbad++; - } - } - if (nospc) { - SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc); - SAM("..... possibly inadequate USB bandwidth\n"); - peasycap->audio_eof = 1; - } - - if (isbad) - easycap_audio_kill_urbs(peasycap); - else - peasycap->audio_isoc_streaming = m; - - return 0; -} -/*---------------------------------------------------------------------------*/ -/* - * COMMON AUDIO INITIALIZATION - */ -/*---------------------------------------------------------------------------*/ -static int easycap_sound_setup(struct easycap *peasycap) -{ - int rc; - - JOM(4, "starting initialization\n"); - - if (!peasycap) { - SAY("ERROR: peasycap is NULL.\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -ENODEV; - } - JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device); - - rc = easycap_audio_setup(peasycap); - JOM(8, "audio_setup() returned %i\n", rc); - - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -ENODEV; - } -/*---------------------------------------------------------------------------*/ - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -ENODEV; - } - rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, - peasycap->audio_altsetting_on); - JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, - peasycap->audio_altsetting_on, rc); - - rc = easycap_wakeup_device(peasycap->pusb_device); - JOM(8, "wakeup_device() returned %i\n", rc); - - peasycap->audio_eof = 0; - peasycap->audio_idle = 0; - - easycap_audio_submit_urbs(peasycap); - - JOM(4, "finished initialization\n"); - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE DAM BUFFER - * PROVIDED peasycap->audio_idle IS ZERO. REGARDLESS OF THIS BEING TRUE, - * IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO. - */ -/*---------------------------------------------------------------------------*/ -void easycap_alsa_complete(struct urb *purb) -{ - struct easycap *peasycap; - struct snd_pcm_substream *pss; - struct snd_pcm_runtime *prt; - int dma_bytes, fragment_bytes; - int isfragment; - u8 *p1, *p2; - s16 tmp; - int i, j, more, much, rc; -#ifdef UPSAMPLE - int k; - s16 oldaudio, newaudio, delta; -#endif /*UPSAMPLE*/ - - JOT(16, "\n"); - - if (!purb) { - SAY("ERROR: purb is NULL\n"); - return; - } - peasycap = purb->context; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return; - } - much = 0; - if (peasycap->audio_idle) { - JOM(16, "%i=audio_idle %i=audio_isoc_streaming\n", - peasycap->audio_idle, peasycap->audio_isoc_streaming); - if (peasycap->audio_isoc_streaming) - goto resubmit; - } -/*---------------------------------------------------------------------------*/ - pss = peasycap->psubstream; - if (!pss) - goto resubmit; - prt = pss->runtime; - if (!prt) - goto resubmit; - dma_bytes = (int)prt->dma_bytes; - if (0 == dma_bytes) - goto resubmit; - fragment_bytes = 4 * ((int)prt->period_size); - if (0 == fragment_bytes) - goto resubmit; -/* -------------------------------------------------------------------------*/ - if (purb->status) { - if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) { - JOM(16, "urb status -ESHUTDOWN or -ENOENT\n"); - return; - } - SAM("ERROR: non-zero urb status: -%s: %d\n", - strerror(purb->status), purb->status); - goto resubmit; - } -/*---------------------------------------------------------------------------*/ -/* - * PROCEED HERE WHEN NO ERROR - */ -/*---------------------------------------------------------------------------*/ - -#ifdef UPSAMPLE - oldaudio = peasycap->oldaudio; -#endif /*UPSAMPLE*/ - - for (i = 0; i < purb->number_of_packets; i++) { - if (purb->iso_frame_desc[i].status < 0) { - SAM("-%s: %d\n", - strerror(purb->iso_frame_desc[i].status), - purb->iso_frame_desc[i].status); - } - if (purb->iso_frame_desc[i].status) { - JOM(12, "discarding audio samples because " - "%i=purb->iso_frame_desc[i].status\n", - purb->iso_frame_desc[i].status); - continue; - } - more = purb->iso_frame_desc[i].actual_length; - if (more == 0) { - peasycap->audio_mt++; - continue; - } - if (0 > more) { - SAM("MISTAKE: more is negative\n"); - return; - } - - if (peasycap->audio_mt) { - JOM(12, "%4i empty audio urb frames\n", - peasycap->audio_mt); - peasycap->audio_mt = 0; - } - - p1 = (u8 *)(purb->transfer_buffer + - purb->iso_frame_desc[i].offset); - - /* - * COPY more BYTES FROM ISOC BUFFER - * TO THE DMA BUFFER, CONVERTING - * 8-BIT MONO TO 16-BIT SIGNED - * LITTLE-ENDIAN SAMPLES IF NECESSARY - */ - while (more) { - much = dma_bytes - peasycap->dma_fill; - if (0 > much) { - SAM("MISTAKE: much is negative\n"); - return; - } - if (0 == much) { - peasycap->dma_fill = 0; - peasycap->dma_next = fragment_bytes; - JOM(8, "wrapped dma buffer\n"); - } - if (!peasycap->microphone) { - if (much > more) - much = more; - memcpy(prt->dma_area + peasycap->dma_fill, - p1, much); - p1 += much; - more -= much; - } else { -#ifdef UPSAMPLE - if (much % 16) - JOM(8, "MISTAKE? much" - " is not divisible by 16\n"); - if (much > (16 * more)) - much = 16 * more; - p2 = (u8 *)(prt->dma_area + peasycap->dma_fill); - - for (j = 0; j < (much / 16); j++) { - newaudio = ((int) *p1) - 128; - newaudio = 128 * newaudio; - - delta = (newaudio - oldaudio) / 4; - tmp = oldaudio + delta; - - for (k = 0; k < 4; k++) { - *p2 = (0x00FF & tmp); - *(p2 + 1) = (0xFF00 & tmp) >> 8; - p2 += 2; - *p2 = (0x00FF & tmp); - *(p2 + 1) = (0xFF00 & tmp) >> 8; - p2 += 2; - tmp += delta; - } - p1++; - more--; - oldaudio = tmp; - } -#else /*!UPSAMPLE*/ - if (much > (2 * more)) - much = 2 * more; - p2 = (u8 *)(prt->dma_area + peasycap->dma_fill); - - for (j = 0; j < (much / 2); j++) { - tmp = ((int) *p1) - 128; - tmp = 128 * tmp; - *p2 = (0x00FF & tmp); - *(p2 + 1) = (0xFF00 & tmp) >> 8; - p1++; - p2 += 2; - more--; - } -#endif /*UPSAMPLE*/ - } - peasycap->dma_fill += much; - if (peasycap->dma_fill >= peasycap->dma_next) { - isfragment = peasycap->dma_fill / fragment_bytes; - if (0 > isfragment) { - SAM("MISTAKE: isfragment is negative\n"); - return; - } - peasycap->dma_read = (isfragment - 1) * fragment_bytes; - peasycap->dma_next = (isfragment + 1) * fragment_bytes; - if (dma_bytes < peasycap->dma_next) - peasycap->dma_next = fragment_bytes; - - if (0 <= peasycap->dma_read) { - JOM(8, "snd_pcm_period_elapsed(), %i=" - "isfragment\n", isfragment); - snd_pcm_period_elapsed(pss); - } - } - } - -#ifdef UPSAMPLE - peasycap->oldaudio = oldaudio; -#endif /*UPSAMPLE*/ - - } -/*---------------------------------------------------------------------------*/ -/* - * RESUBMIT THIS URB - */ -/*---------------------------------------------------------------------------*/ -resubmit: - if (peasycap->audio_isoc_streaming == 0) - return; - - rc = usb_submit_urb(purb, GFP_ATOMIC); - if (rc) { - if ((-ENODEV != rc) && (-ENOENT != rc)) { - SAM("ERROR: while %i=audio_idle, usb_submit_urb failed " - "with rc: -%s :%d\n", - peasycap->audio_idle, strerror(rc), rc); - } - if (0 < peasycap->audio_isoc_streaming) - peasycap->audio_isoc_streaming--; - } - return; -} -/*****************************************************************************/ -static int easycap_alsa_open(struct snd_pcm_substream *pss) -{ - struct snd_pcm *psnd_pcm; - struct snd_card *psnd_card; - struct easycap *peasycap; - - JOT(4, "\n"); - if (!pss) { - SAY("ERROR: pss is NULL\n"); - return -EFAULT; - } - psnd_pcm = pss->pcm; - if (!psnd_pcm) { - SAY("ERROR: psnd_pcm is NULL\n"); - return -EFAULT; - } - psnd_card = psnd_pcm->card; - if (!psnd_card) { - SAY("ERROR: psnd_card is NULL\n"); - return -EFAULT; - } - - peasycap = psnd_card->private_data; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (peasycap->psnd_card != psnd_card) { - SAM("ERROR: bad peasycap->psnd_card\n"); - return -EFAULT; - } - if (peasycap->psubstream) { - SAM("ERROR: bad peasycap->psubstream\n"); - return -EFAULT; - } - pss->private_data = peasycap; - peasycap->psubstream = pss; - pss->runtime->hw = peasycap->alsa_hardware; - pss->runtime->private_data = peasycap; - pss->private_data = peasycap; - - if (0 != easycap_sound_setup(peasycap)) { - JOM(4, "ending unsuccessfully\n"); - return -EFAULT; - } - JOM(4, "ending successfully\n"); - return 0; -} -/*****************************************************************************/ -static int easycap_alsa_close(struct snd_pcm_substream *pss) -{ - struct easycap *peasycap; - - JOT(4, "\n"); - if (!pss) { - SAY("ERROR: pss is NULL\n"); - return -EFAULT; - } - peasycap = snd_pcm_substream_chip(pss); - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - pss->private_data = NULL; - peasycap->psubstream = NULL; - JOT(4, "ending successfully\n"); - return 0; -} -/*****************************************************************************/ -static int easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz) -{ - struct snd_pcm_runtime *prt; - JOT(4, "\n"); - - if (!pss) { - SAY("ERROR: pss is NULL\n"); - return -EFAULT; - } - prt = pss->runtime; - if (!prt) { - SAY("ERROR: substream.runtime is NULL\n"); - return -EFAULT; - } - if (prt->dma_area) { - if (prt->dma_bytes > sz) - return 0; - vfree(prt->dma_area); - } - prt->dma_area = vmalloc(sz); - if (!prt->dma_area) - return -ENOMEM; - prt->dma_bytes = sz; - return 0; -} -/*****************************************************************************/ -static int easycap_alsa_hw_params(struct snd_pcm_substream *pss, - struct snd_pcm_hw_params *phw) -{ - int rc; - - JOT(4, "%i\n", (params_buffer_bytes(phw))); - if (!pss) { - SAY("ERROR: pss is NULL\n"); - return -EFAULT; - } - rc = easycap_alsa_vmalloc(pss, params_buffer_bytes(phw)); - if (rc) - return rc; - return 0; -} -/*****************************************************************************/ -static int easycap_alsa_hw_free(struct snd_pcm_substream *pss) -{ - struct snd_pcm_runtime *prt; - JOT(4, "\n"); - - if (!pss) { - SAY("ERROR: pss is NULL\n"); - return -EFAULT; - } - prt = pss->runtime; - if (!prt) { - SAY("ERROR: substream.runtime is NULL\n"); - return -EFAULT; - } - if (prt->dma_area) { - JOT(8, "prt->dma_area = %p\n", prt->dma_area); - vfree(prt->dma_area); - prt->dma_area = NULL; - } else - JOT(8, "dma_area already freed\n"); - return 0; -} -/*****************************************************************************/ -static int easycap_alsa_prepare(struct snd_pcm_substream *pss) -{ - struct easycap *peasycap; - struct snd_pcm_runtime *prt; - - JOT(4, "\n"); - if (!pss) { - SAY("ERROR: pss is NULL\n"); - return -EFAULT; - } - prt = pss->runtime; - peasycap = snd_pcm_substream_chip(pss); - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - - JOM(16, "ALSA decides %8i Hz=rate\n", pss->runtime->rate); - JOM(16, "ALSA decides %8ld =period_size\n", pss->runtime->period_size); - JOM(16, "ALSA decides %8i =periods\n", pss->runtime->periods); - JOM(16, "ALSA decides %8ld =buffer_size\n", pss->runtime->buffer_size); - JOM(16, "ALSA decides %8zd =dma_bytes\n", pss->runtime->dma_bytes); - JOM(16, "ALSA decides %8ld =boundary\n", pss->runtime->boundary); - JOM(16, "ALSA decides %8i =period_step\n", pss->runtime->period_step); - JOM(16, "ALSA decides %8i =sample_bits\n", pss->runtime->sample_bits); - JOM(16, "ALSA decides %8i =frame_bits\n", pss->runtime->frame_bits); - JOM(16, "ALSA decides %8ld =min_align\n", pss->runtime->min_align); - JOM(12, "ALSA decides %8ld =hw_ptr_base\n", pss->runtime->hw_ptr_base); - JOM(12, "ALSA decides %8ld =hw_ptr_interrupt\n", - pss->runtime->hw_ptr_interrupt); - - if (prt->dma_bytes != 4 * ((int)prt->period_size) * ((int)prt->periods)) { - SAY("MISTAKE: unexpected ALSA parameters\n"); - return -ENOENT; - } - return 0; -} -/*****************************************************************************/ -static int easycap_alsa_ack(struct snd_pcm_substream *pss) -{ - return 0; -} -/*****************************************************************************/ -static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd) -{ - struct easycap *peasycap; - - JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START, - SNDRV_PCM_TRIGGER_STOP); - if (!pss) { - SAY("ERROR: pss is NULL\n"); - return -EFAULT; - } - peasycap = snd_pcm_substream_chip(pss); - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: { - peasycap->audio_idle = 0; - break; - } - case SNDRV_PCM_TRIGGER_STOP: { - peasycap->audio_idle = 1; - break; - } - default: - return -EINVAL; - } - return 0; -} -/*****************************************************************************/ -static snd_pcm_uframes_t easycap_alsa_pointer(struct snd_pcm_substream *pss) -{ - struct easycap *peasycap; - snd_pcm_uframes_t offset; - - JOT(16, "\n"); - if (!pss) { - SAY("ERROR: pss is NULL\n"); - return -EFAULT; - } - peasycap = snd_pcm_substream_chip(pss); - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if ((0 != peasycap->audio_eof) || (0 != peasycap->audio_idle)) { - JOM(8, "returning -EIO because " - "%i=audio_idle %i=audio_eof\n", - peasycap->audio_idle, peasycap->audio_eof); - return -EIO; - } -/*---------------------------------------------------------------------------*/ - if (0 > peasycap->dma_read) { - JOM(8, "returning -EBUSY\n"); - return -EBUSY; - } - offset = ((snd_pcm_uframes_t)peasycap->dma_read)/4; - JOM(8, "ALSA decides %8i =hw_ptr_base\n", (int)pss->runtime->hw_ptr_base); - JOM(8, "ALSA decides %8i =hw_ptr_interrupt\n", - (int)pss->runtime->hw_ptr_interrupt); - JOM(8, "%7i=offset %7i=dma_read %7i=dma_next\n", - (int)offset, peasycap->dma_read, peasycap->dma_next); - return offset; -} -/*****************************************************************************/ -static struct page * -easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset) -{ - return vmalloc_to_page(pss->runtime->dma_area + offset); -} -/*****************************************************************************/ - -static struct snd_pcm_ops easycap_alsa_pcm_ops = { - .open = easycap_alsa_open, - .close = easycap_alsa_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = easycap_alsa_hw_params, - .hw_free = easycap_alsa_hw_free, - .prepare = easycap_alsa_prepare, - .ack = easycap_alsa_ack, - .trigger = easycap_alsa_trigger, - .pointer = easycap_alsa_pointer, - .page = easycap_alsa_page, -}; - -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * THE FUNCTION snd_card_create() HAS THIS_MODULE AS AN ARGUMENT. THIS - * MEANS MODULE easycap. BEWARE. -*/ -/*---------------------------------------------------------------------------*/ -int easycap_alsa_probe(struct easycap *peasycap) -{ - int rc; - struct snd_card *psnd_card; - struct snd_pcm *psnd_pcm; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -ENODEV; - } - if (0 > peasycap->minor) { - SAY("ERROR: no minor\n"); - return -ENODEV; - } - - peasycap->alsa_hardware = alsa_hardware; - if (peasycap->microphone) { - peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_32000; - peasycap->alsa_hardware.rate_min = 32000; - peasycap->alsa_hardware.rate_max = 32000; - } else { - peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_48000; - peasycap->alsa_hardware.rate_min = 48000; - peasycap->alsa_hardware.rate_max = 48000; - } - - if (0 != snd_card_create(SNDRV_DEFAULT_IDX1, "easycap_alsa", - THIS_MODULE, 0, &psnd_card)) { - SAY("ERROR: Cannot do ALSA snd_card_create()\n"); - return -EFAULT; - } - - sprintf(&psnd_card->id[0], "EasyALSA%i", peasycap->minor); - strcpy(&psnd_card->driver[0], EASYCAP_DRIVER_DESCRIPTION); - strcpy(&psnd_card->shortname[0], "easycap_alsa"); - sprintf(&psnd_card->longname[0], "%s", &psnd_card->shortname[0]); - - psnd_card->dev = &peasycap->pusb_device->dev; - psnd_card->private_data = peasycap; - peasycap->psnd_card = psnd_card; - - rc = snd_pcm_new(psnd_card, "easycap_pcm", 0, 0, 1, &psnd_pcm); - if (rc) { - SAM("ERROR: Cannot do ALSA snd_pcm_new()\n"); - snd_card_free(psnd_card); - return -EFAULT; - } - - snd_pcm_set_ops(psnd_pcm, SNDRV_PCM_STREAM_CAPTURE, - &easycap_alsa_pcm_ops); - psnd_pcm->info_flags = 0; - strcpy(&psnd_pcm->name[0], &psnd_card->id[0]); - psnd_pcm->private_data = peasycap; - peasycap->psnd_pcm = psnd_pcm; - peasycap->psubstream = NULL; - - rc = snd_card_register(psnd_card); - if (rc) { - SAM("ERROR: Cannot do ALSA snd_card_register()\n"); - snd_card_free(psnd_card); - return -EFAULT; - } - - SAM("registered %s\n", &psnd_card->id[0]); - return 0; -} - diff --git a/drivers/staging/media/easycap/easycap_testcard.c b/drivers/staging/media/easycap/easycap_testcard.c deleted file mode 100644 index 0f71470..0000000 --- a/drivers/staging/media/easycap/easycap_testcard.c +++ /dev/null @@ -1,155 +0,0 @@ -/****************************************************************************** -* * -* easycap_testcard.c * -* * -******************************************************************************/ -/* - * - * Copyright (C) 2010 R.M. Thomas rmthomas@sciolus.org - * - * - * This 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. - * - * The software 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 software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * -*/ -/*****************************************************************************/ - -#include "easycap.h" - -/*****************************************************************************/ -#define TESTCARD_BYTESPERLINE (2 * 720) -void -easycap_testcard(struct easycap *peasycap, int field) -{ - int total; - int y, u, v, r, g, b; - unsigned char uyvy[4]; - int i1, line, k, m, n, more, much, barwidth, barheight; - unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2; - struct data_buffer *pfield_buffer; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return; - } - JOM(8, "%i=field\n", field); - switch (peasycap->width) { - case 720: - case 360: { - barwidth = (2 * 720) / 8; - break; - } - case 704: - case 352: { - barwidth = (2 * 704) / 8; - break; - } - case 640: - case 320: { - barwidth = (2 * 640) / 8; - break; - } - default: { - SAM("ERROR: cannot set barwidth\n"); - return; - } - } - if (TESTCARD_BYTESPERLINE < barwidth) { - SAM("ERROR: barwidth is too large\n"); - return; - } - switch (peasycap->height) { - case 576: - case 288: { - barheight = 576; - break; - } - case 480: - case 240: { - barheight = 480; - break; - } - default: { - SAM("ERROR: cannot set barheight\n"); - return; - } - } - total = 0; - k = field; - m = 0; - n = 0; - - for (line = 0; line < (barheight / 2); line++) { - for (i1 = 0; i1 < 8; i1++) { - r = (i1 * 256)/8; - g = (i1 * 256)/8; - b = (i1 * 256)/8; - - y = 299*r/1000 + 587*g/1000 + 114*b/1000 ; - u = -147*r/1000 - 289*g/1000 + 436*b/1000 ; - u = u + 128; - v = 615*r/1000 - 515*g/1000 - 100*b/1000 ; - v = v + 128; - - uyvy[0] = 0xFF & u ; - uyvy[1] = 0xFF & y ; - uyvy[2] = 0xFF & v ; - uyvy[3] = 0xFF & y ; - - p1 = &bfbar[0]; - while (p1 < &bfbar[barwidth]) { - *p1++ = uyvy[0] ; - *p1++ = uyvy[1] ; - *p1++ = uyvy[2] ; - *p1++ = uyvy[3] ; - total += 4; - } - - p1 = &bfbar[0]; - more = barwidth; - - while (more) { - if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) { - SAM("ERROR: bad m reached\n"); - return; - } - if (PAGE_SIZE < n) { - SAM("ERROR: bad n reached\n"); - return; - } - - if (0 > more) { - SAM("ERROR: internal fault\n"); - return; - } - - much = PAGE_SIZE - n; - if (much > more) - much = more; - pfield_buffer = &peasycap->field_buffer[k][m]; - p2 = pfield_buffer->pgo + n; - memcpy(p2, p1, much); - - p1 += much; - n += much; - more -= much; - if (PAGE_SIZE == n) { - m++; - n = 0; - } - } - } - } - return; -}