From 489447380a2921ec0e9154f773c44ab3167ede4b Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 19 Jan 2006 17:56:29 +0000 Subject: [PATCH] handle errors returned by platform_get_irq*() platform_get_irq*() now returns on -ENXIO when the resource cannot be found. Ensure all users of platform_get_irq*() handle this error appropriately. Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-omap.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 3785b3f7df1b..ca19abe01c53 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -286,7 +286,7 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *); int usb_hcd_omap_probe (const struct hc_driver *driver, struct platform_device *pdev) { - int retval; + int retval, irq; struct usb_hcd *hcd = 0; struct ohci_hcd *ohci; @@ -329,7 +329,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver, if (retval < 0) goto err2; - retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), SA_INTERRUPT); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + retval = -ENXIO; + goto err2; + } + retval = usb_add_hcd(hcd, irq, SA_INTERRUPT); if (retval == 0) return retval; -- cgit v1.2.2 From b87ba0a33a634c9a8e3609702122a04034a0688d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Mar 2006 13:17:13 -0800 Subject: [PATCH] add EXPORT_SYMBOL_GPL_FUTURE() to USB subsystem The USB core symbols will be converted to GPL-only in a few years. Mark this as such and update the documentation explaining why, and provide a pointer for developers to receive help if they need it. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index dce9d987f0fc..c196f3845305 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -378,7 +378,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, return NULL; } -EXPORT_SYMBOL(usb_match_id); +EXPORT_SYMBOL_GPL_FUTURE(usb_match_id); int usb_device_match(struct device *dev, struct device_driver *drv) { @@ -446,7 +446,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner) return retval; } -EXPORT_SYMBOL(usb_register_driver); +EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver); /** * usb_deregister - unregister a USB driver @@ -469,4 +469,4 @@ void usb_deregister(struct usb_driver *driver) usbfs_update_special(); } -EXPORT_SYMBOL(usb_deregister); +EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); -- cgit v1.2.2 From 60f780528f3ae603eb169a221628b93b6c6929f9 Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Mon, 6 Feb 2006 16:29:35 +0000 Subject: [PATCH] USB: Add ZC0301 Video4Linux2 driver This patch adds a Video4Linux2 driver for ZC0301 Image Processor and Control Chip. Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + drivers/usb/media/Kconfig | 15 + drivers/usb/media/Makefile | 2 + drivers/usb/media/zc0301.h | 185 ++++ drivers/usb/media/zc0301_core.c | 2028 ++++++++++++++++++++++++++++++++++ drivers/usb/media/zc0301_pas202bcb.c | 353 ++++++ drivers/usb/media/zc0301_sensor.h | 98 ++ 7 files changed, 2682 insertions(+) create mode 100644 drivers/usb/media/zc0301.h create mode 100644 drivers/usb/media/zc0301_core.c create mode 100644 drivers/usb/media/zc0301_pas202bcb.c create mode 100644 drivers/usb/media/zc0301_sensor.h (limited to 'drivers/usb') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 36e476dd9123..bade87b62cf9 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_USB_SN9C102) += media/ obj-$(CONFIG_USB_STV680) += media/ obj-$(CONFIG_USB_VICAM) += media/ obj-$(CONFIG_USB_W9968CF) += media/ +obj-$(CONFIG_USB_ZC0301) += media/ obj-$(CONFIG_USB_CATC) += net/ obj-$(CONFIG_USB_KAWETH) += net/ diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig index 0d3d2cc5d7be..189d40f96be5 100644 --- a/drivers/usb/media/Kconfig +++ b/drivers/usb/media/Kconfig @@ -191,6 +191,21 @@ config USB_W9968CF To compile this driver as a module, choose M here: the module will be called w9968cf. +config USB_ZC0301 + tristate "USB ZC0301 Image Processor and Control Chip support" + depends on USB && VIDEO_DEV + ---help--- + Say Y here if you want support for cameras based on the ZC0301 + Image Processor and Control Chip. + + See for more informations. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" to use this driver. + + To compile this driver as a module, choose M here: the + module will be called zc0301. + config USB_PWC tristate "USB Philips Cameras" depends on USB && VIDEO_DEV diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile index 3957aa1be0f2..333bf09ca2d6 100644 --- a/drivers/usb/media/Makefile +++ b/drivers/usb/media/Makefile @@ -4,6 +4,7 @@ sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o +zc0301-objs := zc0301_core.o zc0301_pas202bcb.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o @@ -16,4 +17,5 @@ obj-$(CONFIG_USB_SN9C102) += sn9c102.o obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o +obj-$(CONFIG_USB_ZC0301) += zc0301.o obj-$(CONFIG_USB_PWC) += pwc/ diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h new file mode 100644 index 000000000000..6fa5075f1e3d --- /dev/null +++ b/drivers/usb/media/zc0301.h @@ -0,0 +1,185 @@ +/*************************************************************************** + * V4L2 driver for ZC0301 Image Processor and Control Chip * + * * + * Copyright (C) 2006 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#ifndef _ZC0301_H_ +#define _ZC0301_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zc0301_sensor.h" + +/*****************************************************************************/ + +#define ZC0301_DEBUG +#define ZC0301_DEBUG_LEVEL 2 +#define ZC0301_MAX_DEVICES 64 +#define ZC0301_FORCE_MUNMAP 0 +#define ZC0301_MAX_FRAMES 32 +#define ZC0301_COMPRESSION_QUALITY 2 +#define ZC0301_URBS 2 +#define ZC0301_ISO_PACKETS 7 +#define ZC0301_ALTERNATE_SETTING 7 +#define ZC0301_URB_TIMEOUT msecs_to_jiffies(2 * ZC0301_ISO_PACKETS) +#define ZC0301_CTRL_TIMEOUT 100 +#define ZC0301_FRAME_TIMEOUT 2 * 1000 * msecs_to_jiffies(1) + +/*****************************************************************************/ + +ZC0301_ID_TABLE +ZC0301_SENSOR_TABLE + +enum zc0301_frame_state { + F_UNUSED, + F_QUEUED, + F_GRABBING, + F_DONE, + F_ERROR, +}; + +struct zc0301_frame_t { + void* bufmem; + struct v4l2_buffer buf; + enum zc0301_frame_state state; + struct list_head frame; + unsigned long vma_use_count; +}; + +enum zc0301_dev_state { + DEV_INITIALIZED = 0x01, + DEV_DISCONNECTED = 0x02, + DEV_MISCONFIGURED = 0x04, +}; + +enum zc0301_io_method { + IO_NONE, + IO_READ, + IO_MMAP, +}; + +enum zc0301_stream_state { + STREAM_OFF, + STREAM_INTERRUPT, + STREAM_ON, +}; + +struct zc0301_module_param { + u8 force_munmap; +}; + +static DECLARE_RWSEM(zc0301_disconnect); + +struct zc0301_device { + struct video_device* v4ldev; + + struct zc0301_sensor* sensor; + + struct usb_device* usbdev; + struct urb* urb[ZC0301_URBS]; + void* transfer_buffer[ZC0301_URBS]; + u8* control_buffer; + + struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES]; + struct list_head inqueue, outqueue; + u32 frame_count, nbuffers, nreadbuffers; + + enum zc0301_io_method io; + enum zc0301_stream_state stream; + + struct v4l2_jpegcompression compression; + + struct zc0301_module_param module_param; + + enum zc0301_dev_state state; + u8 users; + + struct mutex dev_mutex, fileop_mutex; + spinlock_t queue_lock; + wait_queue_head_t open, wait_frame, wait_stream; +}; + +/*****************************************************************************/ + +void +zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor) +{ + cam->sensor = sensor; + cam->sensor->usbdev = cam->usbdev; +} + +/*****************************************************************************/ + +#undef DBG +#undef KDBG +#ifdef ZC0301_DEBUG +# define DBG(level, fmt, args...) \ +do { \ + if (debug >= (level)) { \ + if ((level) == 1) \ + dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ + else if ((level) == 2) \ + dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ + else if ((level) >= 3) \ + dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args); \ + } \ +} while (0) +# define KDBG(level, fmt, args...) \ +do { \ + if (debug >= (level)) { \ + if ((level) == 1 || (level) == 2) \ + pr_info("zc0301: " fmt "\n", ## args); \ + else if ((level) == 3) \ + pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__, \ + __LINE__ , ## args); \ + } \ +} while (0) +# define V4LDBG(level, name, cmd) \ +do { \ + if (debug >= (level)) \ + v4l_print_ioctl(name, cmd); \ +} while (0) +#else +# define DBG(level, fmt, args...) do {;} while(0) +# define KDBG(level, fmt, args...) do {;} while(0) +# define V4LDBG(level, name, cmd) do {;} while(0) +#endif + +#undef PDBG +#define PDBG(fmt, args...) \ +dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args) + +#undef PDBGG +#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ + +#endif /* _ZC0301_H_ */ diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c new file mode 100644 index 000000000000..238f60f7f472 --- /dev/null +++ b/drivers/usb/media/zc0301_core.c @@ -0,0 +1,2028 @@ +/*************************************************************************** + * Video4Linux2 driver for ZC0301 Image Processor and Control Chip * + * * + * Copyright (C) 2006 by Luca Risolia * + * * + * Informations about the chip internals to enable the I2C protocol have * + * been taken from the documentation of the ZC030x Video4Linux1 driver * + * written by Andrew Birkett * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zc0301.h" + +/*****************************************************************************/ + +#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301 " \ + "Image Processor and Control Chip" +#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia" +#define ZC0301_AUTHOR_EMAIL "" +#define ZC0301_MODULE_LICENSE "GPL" +#define ZC0301_MODULE_VERSION "1:1.00" +#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 0) + +/*****************************************************************************/ + +MODULE_DEVICE_TABLE(usb, zc0301_id_table); + +MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL); +MODULE_DESCRIPTION(ZC0301_MODULE_NAME); +MODULE_VERSION(ZC0301_MODULE_VERSION); +MODULE_LICENSE(ZC0301_MODULE_LICENSE); + +static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1}; +module_param_array(video_nr, short, NULL, 0444); +MODULE_PARM_DESC(video_nr, + "\n<-1|n[,...]> Specify V4L2 minor mode number." + "\n -1 = use next available (default)" + "\n n = use minor number n (integer >= 0)" + "\nYou can specify up to " + __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way." + "\nFor example:" + "\nvideo_nr=-1,2,-1 would assign minor number 2 to" + "\nthe second registered camera and use auto for the first" + "\none and for every other camera." + "\n"); + +static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] = + ZC0301_FORCE_MUNMAP}; +module_param_array(force_munmap, bool, NULL, 0444); +MODULE_PARM_DESC(force_munmap, + "\n<0|1[,...]> Force the application to unmap previously" + "\nmapped buffer memory before calling any VIDIOC_S_CROP or" + "\nVIDIOC_S_FMT ioctl's. Not all the applications support" + "\nthis feature. This parameter is specific for each" + "\ndetected camera." + "\n 0 = do not force memory unmapping" + "\n 1 = force memory unmapping (save memory)" + "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." + "\n"); + +#ifdef ZC0301_DEBUG +static unsigned short debug = ZC0301_DEBUG_LEVEL; +module_param(debug, ushort, 0644); +MODULE_PARM_DESC(debug, + "\n Debugging information level, from 0 to 3:" + "\n0 = none (use carefully)" + "\n1 = critical errors" + "\n2 = significant informations" + "\n3 = more verbose messages" + "\nLevel 3 is useful for testing only, when only " + "one device is used." + "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"." + "\n"); +#endif + +/*****************************************************************************/ + +static u32 +zc0301_request_buffers(struct zc0301_device* cam, u32 count, + enum zc0301_io_method io) +{ + struct v4l2_pix_format* p = &(cam->sensor->pix_format); + struct v4l2_rect* r = &(cam->sensor->cropcap.bounds); + const size_t imagesize = cam->module_param.force_munmap || + io == IO_READ ? + (p->width * p->height * p->priv) / 8 : + (r->width * r->height * p->priv) / 8; + void* buff = NULL; + u32 i; + + if (count > ZC0301_MAX_FRAMES) + count = ZC0301_MAX_FRAMES; + + cam->nbuffers = count; + while (cam->nbuffers > 0) { + if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) + break; + cam->nbuffers--; + } + + for (i = 0; i < cam->nbuffers; i++) { + cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); + cam->frame[i].buf.index = i; + cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); + cam->frame[i].buf.length = imagesize; + cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cam->frame[i].buf.sequence = 0; + cam->frame[i].buf.field = V4L2_FIELD_NONE; + cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; + cam->frame[i].buf.flags = 0; + } + + return cam->nbuffers; +} + + +static void zc0301_release_buffers(struct zc0301_device* cam) +{ + if (cam->nbuffers) { + vfree(cam->frame[0].bufmem); + cam->nbuffers = 0; + } + cam->frame_current = NULL; +} + + +static void zc0301_empty_framequeues(struct zc0301_device* cam) +{ + u32 i; + + INIT_LIST_HEAD(&cam->inqueue); + INIT_LIST_HEAD(&cam->outqueue); + + for (i = 0; i < ZC0301_MAX_FRAMES; i++) { + cam->frame[i].state = F_UNUSED; + cam->frame[i].buf.bytesused = 0; + } +} + + +static void zc0301_requeue_outqueue(struct zc0301_device* cam) +{ + struct zc0301_frame_t *i; + + list_for_each_entry(i, &cam->outqueue, frame) { + i->state = F_QUEUED; + list_add(&i->frame, &cam->inqueue); + } + + INIT_LIST_HEAD(&cam->outqueue); +} + + +static void zc0301_queue_unusedframes(struct zc0301_device* cam) +{ + unsigned long lock_flags; + u32 i; + + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].state == F_UNUSED) { + cam->frame[i].state = F_QUEUED; + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_add_tail(&cam->frame[i].frame, &cam->inqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + } +} + +/*****************************************************************************/ + +int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value) +{ + struct usb_device* udev = cam->usbdev; + int res; + + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40, + value, index, NULL, 0, ZC0301_CTRL_TIMEOUT); + if (res < 0) { + DBG(3, "Failed to write a register (index 0x%04X, " + "value 0x%02X, error %d)",index, value, res); + return -1; + } + + return 0; +} + + +int zc0301_read_reg(struct zc0301_device* cam, u16 index) +{ + struct usb_device* udev = cam->usbdev; + u8* buff = cam->control_buffer; + int res; + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0, + 0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT); + if (res < 0) + DBG(3, "Failed to read a register (index 0x%04X, error %d)", + index, res); + + PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff)); + + return (res >= 0) ? (int)(*buff) : -1; +} + + +int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length) +{ + int err = 0, res, r0, r1; + + err += zc0301_write_reg(cam, 0x0092, address); + err += zc0301_write_reg(cam, 0x0090, 0x02); + + msleep(1); + + res = zc0301_read_reg(cam, 0x0091); + if (res < 0) + err += res; + r0 = zc0301_read_reg(cam, 0x0095); + if (r0 < 0) + err += r0; + r1 = zc0301_read_reg(cam, 0x0096); + if (r1 < 0) + err += r1; + + res = (length <= 1) ? r0 : r0 | (r1 << 8); + + if (err) + DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X", + address, res); + + + PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res); + + return err ? -1 : res; +} + + +int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value) +{ + int err = 0, res; + + err += zc0301_write_reg(cam, 0x0092, address); + err += zc0301_write_reg(cam, 0x0093, value & 0xff); + err += zc0301_write_reg(cam, 0x0094, value >> 8); + err += zc0301_write_reg(cam, 0x0090, 0x01); + + msleep(1); + + res = zc0301_read_reg(cam, 0x0091); + if (res < 0) + err += res; + + if (err) + DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X", + address, value); + + PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value); + + return err ? -1 : 0; +} + +/*****************************************************************************/ + +static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs) +{ + struct zc0301_device* cam = urb->context; + struct zc0301_frame_t** f; + size_t imagesize; + u8 i; + int err = 0; + + if (urb->status == -ENOENT) + return; + + f = &cam->frame_current; + + if (cam->stream == STREAM_INTERRUPT) { + cam->stream = STREAM_OFF; + if ((*f)) + (*f)->state = F_QUEUED; + DBG(3, "Stream interrupted"); + wake_up_interruptible(&cam->wait_stream); + } + + if (cam->state & DEV_DISCONNECTED) + return; + + if (cam->state & DEV_MISCONFIGURED) { + wake_up_interruptible(&cam->wait_frame); + return; + } + + if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) + goto resubmit_urb; + + if (!(*f)) + (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t, + frame); + + imagesize = (cam->sensor->pix_format.width * + cam->sensor->pix_format.height * + cam->sensor->pix_format.priv) / 8; + + for (i = 0; i < urb->number_of_packets; i++) { + unsigned int len, status; + void *pos; + u16* soi; + u8 sof; + + len = urb->iso_frame_desc[i].actual_length; + status = urb->iso_frame_desc[i].status; + pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; + + if (status) { + DBG(3, "Error in isochronous frame"); + (*f)->state = F_ERROR; + continue; + } + + sof = (*(soi = pos) == 0xd8ff); + + PDBGG("Isochrnous frame: length %u, #%u i,", len, i); + + if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) +start_of_frame: + if (sof) { + (*f)->state = F_GRABBING; + (*f)->buf.bytesused = 0; + do_gettimeofday(&(*f)->buf.timestamp); + DBG(3, "SOF detected: new video frame"); + } + + if ((*f)->state == F_GRABBING) { + if (sof && (*f)->buf.bytesused) + goto end_of_frame; + + if ((*f)->buf.bytesused + len > imagesize) { + DBG(3, "Video frame size exceeded"); + (*f)->state = F_ERROR; + continue; + } + + memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len); + (*f)->buf.bytesused += len; + + if ((*f)->buf.bytesused == imagesize) { + u32 b; +end_of_frame: + b = (*f)->buf.bytesused; + (*f)->state = F_DONE; + (*f)->buf.sequence= ++cam->frame_count; + spin_lock(&cam->queue_lock); + list_move_tail(&(*f)->frame, &cam->outqueue); + if (!list_empty(&cam->inqueue)) + (*f) = list_entry(cam->inqueue.next, + struct zc0301_frame_t, + frame); + else + (*f) = NULL; + spin_unlock(&cam->queue_lock); + DBG(3, "Video frame captured: : %lu bytes", + (unsigned long)(b)); + + if (!(*f)) + goto resubmit_urb; + + if (sof) + goto start_of_frame; + } + } + } + +resubmit_urb: + urb->dev = cam->usbdev; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0 && err != -EPERM) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "usb_submit_urb() failed"); + } + + wake_up_interruptible(&cam->wait_frame); +} + + +static int zc0301_start_transfer(struct zc0301_device* cam) +{ + struct usb_device *udev = cam->usbdev; + struct urb* urb; + const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384, + 512, 768, 1023}; + const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING]; + s8 i, j; + int err = 0; + + for (i = 0; i < ZC0301_URBS; i++) { + cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz, + GFP_KERNEL); + if (!cam->transfer_buffer[i]) { + err = -ENOMEM; + DBG(1, "Not enough memory"); + goto free_buffers; + } + } + + for (i = 0; i < ZC0301_URBS; i++) { + urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL); + cam->urb[i] = urb; + if (!urb) { + err = -ENOMEM; + DBG(1, "usb_alloc_urb() failed"); + goto free_urbs; + } + urb->dev = udev; + urb->context = cam; + urb->pipe = usb_rcvisocpipe(udev, 1); + urb->transfer_flags = URB_ISO_ASAP; + urb->number_of_packets = ZC0301_ISO_PACKETS; + urb->complete = zc0301_urb_complete; + urb->transfer_buffer = cam->transfer_buffer[i]; + urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS; + urb->interval = 1; + for (j = 0; j < ZC0301_ISO_PACKETS; j++) { + urb->iso_frame_desc[j].offset = psz * j; + urb->iso_frame_desc[j].length = psz; + } + } + + err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING); + if (err) { + DBG(1, "usb_set_interface() failed"); + goto free_urbs; + } + + cam->frame_current = NULL; + + for (i = 0; i < ZC0301_URBS; i++) { + err = usb_submit_urb(cam->urb[i], GFP_KERNEL); + if (err) { + for (j = i-1; j >= 0; j--) + usb_kill_urb(cam->urb[j]); + DBG(1, "usb_submit_urb() failed, error %d", err); + goto free_urbs; + } + } + + return 0; + +free_urbs: + for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++) + usb_free_urb(cam->urb[i]); + +free_buffers: + for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++) + kfree(cam->transfer_buffer[i]); + + return err; +} + + +static int zc0301_stop_transfer(struct zc0301_device* cam) +{ + struct usb_device *udev = cam->usbdev; + s8 i; + int err = 0; + + if (cam->state & DEV_DISCONNECTED) + return 0; + + for (i = ZC0301_URBS-1; i >= 0; i--) { + usb_kill_urb(cam->urb[i]); + usb_free_urb(cam->urb[i]); + kfree(cam->transfer_buffer[i]); + } + + err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ + if (err) + DBG(3, "usb_set_interface() failed"); + + return err; +} + + +static int zc0301_stream_interrupt(struct zc0301_device* cam) +{ + long timeout; + + cam->stream = STREAM_INTERRUPT; + timeout = wait_event_timeout(cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED), + ZC0301_URB_TIMEOUT); + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + else if (!timeout) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "URB timeout reached. The camera is misconfigured. To " + "use it, close and open /dev/video%d again.", + cam->v4ldev->minor); + return -EIO; + } + + return 0; +} + +/*****************************************************************************/ + +static int +zc0301_set_compression(struct zc0301_device* cam, + struct v4l2_jpegcompression* compression) +{ + int r, err = 0; + + if ((r = zc0301_read_reg(cam, 0x0008)) < 0) + err += r; + err += zc0301_write_reg(cam, 0x0008, + r | 0x11 | (compression->quality >> 1)); + + return err ? -EIO : 0; +} + + +static int zc0301_init(struct zc0301_device* cam) +{ + struct zc0301_sensor* s = cam->sensor; + struct v4l2_control ctrl; + struct v4l2_queryctrl *qctrl; + struct v4l2_rect* rect; + u8 i = 0; + int err = 0; + + if (!(cam->state & DEV_INITIALIZED)) { + init_waitqueue_head(&cam->open); + qctrl = s->qctrl; + rect = &(s->cropcap.defrect); + cam->compression.quality = ZC0301_COMPRESSION_QUALITY; + } else { /* use current values */ + qctrl = s->_qctrl; + rect = &(s->_rect); + } + + if (s->init) { + err = s->init(cam); + if (err) { + DBG(3, "Sensor initialization failed"); + return err; + } + } + + if ((err = zc0301_set_compression(cam, &cam->compression))) { + DBG(3, "set_compression() failed"); + return err; + } + + if (s->set_crop) + if ((err = s->set_crop(cam, rect))) { + DBG(3, "set_crop() failed"); + return err; + } + + if (s->set_ctrl) { + for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) + if (s->qctrl[i].id != 0 && + !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { + ctrl.id = s->qctrl[i].id; + ctrl.value = qctrl[i].default_value; + err = s->set_ctrl(cam, &ctrl); + if (err) { + DBG(3, "Set %s control failed", + s->qctrl[i].name); + return err; + } + DBG(3, "Image sensor supports '%s' control", + s->qctrl[i].name); + } + } + + if (!(cam->state & DEV_INITIALIZED)) { + mutex_init(&cam->fileop_mutex); + spin_lock_init(&cam->queue_lock); + init_waitqueue_head(&cam->wait_frame); + init_waitqueue_head(&cam->wait_stream); + cam->nreadbuffers = 2; + memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); + memcpy(&(s->_rect), &(s->cropcap.defrect), + sizeof(struct v4l2_rect)); + cam->state |= DEV_INITIALIZED; + } + + DBG(2, "Initialization succeeded"); + return 0; +} + + +static void zc0301_release_resources(struct zc0301_device* cam) +{ + DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); + video_set_drvdata(cam->v4ldev, NULL); + video_unregister_device(cam->v4ldev); + kfree(cam->control_buffer); +} + +/*****************************************************************************/ + +static int zc0301_open(struct inode* inode, struct file* filp) +{ + struct zc0301_device* cam; + int err = 0; + + /* + This is the only safe way to prevent race conditions with + disconnect + */ + if (!down_read_trylock(&zc0301_disconnect)) + return -ERESTARTSYS; + + cam = video_get_drvdata(video_devdata(filp)); + + if (mutex_lock_interruptible(&cam->dev_mutex)) { + up_read(&zc0301_disconnect); + return -ERESTARTSYS; + } + + if (cam->users) { + DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); + if ((filp->f_flags & O_NONBLOCK) || + (filp->f_flags & O_NDELAY)) { + err = -EWOULDBLOCK; + goto out; + } + mutex_unlock(&cam->dev_mutex); + err = wait_event_interruptible_exclusive(cam->open, + cam->state & DEV_DISCONNECTED + || !cam->users); + if (err) { + up_read(&zc0301_disconnect); + return err; + } + if (cam->state & DEV_DISCONNECTED) { + up_read(&zc0301_disconnect); + return -ENODEV; + } + mutex_lock(&cam->dev_mutex); + } + + + if (cam->state & DEV_MISCONFIGURED) { + err = zc0301_init(cam); + if (err) { + DBG(1, "Initialization failed again. " + "I will retry on next open()."); + goto out; + } + cam->state &= ~DEV_MISCONFIGURED; + } + + if ((err = zc0301_start_transfer(cam))) + goto out; + + filp->private_data = cam; + cam->users++; + cam->io = IO_NONE; + cam->stream = STREAM_OFF; + cam->nbuffers = 0; + cam->frame_count = 0; + zc0301_empty_framequeues(cam); + + DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); + +out: + mutex_unlock(&cam->dev_mutex); + up_read(&zc0301_disconnect); + return err; +} + + +static int zc0301_release(struct inode* inode, struct file* filp) +{ + struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + + mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ + + zc0301_stop_transfer(cam); + + zc0301_release_buffers(cam); + + if (cam->state & DEV_DISCONNECTED) { + zc0301_release_resources(cam); + mutex_unlock(&cam->dev_mutex); + kfree(cam); + return 0; + } + + cam->users--; + wake_up_interruptible_nr(&cam->open, 1); + + DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); + + mutex_unlock(&cam->dev_mutex); + + return 0; +} + + +static ssize_t +zc0301_read(struct file* filp, char __user * buf, + size_t count, loff_t* f_pos) +{ + struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + struct zc0301_frame_t* f, * i; + unsigned long lock_flags; + long timeout; + int err = 0; + + if (mutex_lock_interruptible(&cam->fileop_mutex)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + mutex_unlock(&cam->fileop_mutex); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it " + "again."); + mutex_unlock(&cam->fileop_mutex); + return -EIO; + } + + if (cam->io == IO_MMAP) { + DBG(3, "Close and open the device again to choose the read " + "method"); + mutex_unlock(&cam->fileop_mutex); + return -EINVAL; + } + + if (cam->io == IO_NONE) { + if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) { + DBG(1, "read() failed, not enough memory"); + mutex_unlock(&cam->fileop_mutex); + return -ENOMEM; + } + cam->io = IO_READ; + cam->stream = STREAM_ON; + } + + if (list_empty(&cam->inqueue)) { + if (!list_empty(&cam->outqueue)) + zc0301_empty_framequeues(cam); + zc0301_queue_unusedframes(cam); + } + + if (!count) { + mutex_unlock(&cam->fileop_mutex); + return 0; + } + + if (list_empty(&cam->outqueue)) { + if (filp->f_flags & O_NONBLOCK) { + mutex_unlock(&cam->fileop_mutex); + return -EAGAIN; + } + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + ZC0301_FRAME_TIMEOUT ); + if (timeout < 0) { + mutex_unlock(&cam->fileop_mutex); + return timeout; + } + if (cam->state & DEV_DISCONNECTED) { + mutex_unlock(&cam->fileop_mutex); + return -ENODEV; + } + if (!timeout || (cam->state & DEV_MISCONFIGURED)) { + mutex_unlock(&cam->fileop_mutex); + return -EIO; + } + } + + f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame); + + if (count > f->buf.bytesused) + count = f->buf.bytesused; + + if (copy_to_user(buf, f->bufmem, count)) { + err = -EFAULT; + goto exit; + } + *f_pos += count; + +exit: + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_for_each_entry(i, &cam->outqueue, frame) + i->state = F_UNUSED; + INIT_LIST_HEAD(&cam->outqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + zc0301_queue_unusedframes(cam); + + PDBGG("Frame #%lu, bytes read: %zu", + (unsigned long)f->buf.index, count); + + mutex_unlock(&cam->fileop_mutex); + + return err ? err : count; +} + + +static unsigned int zc0301_poll(struct file *filp, poll_table *wait) +{ + struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + struct zc0301_frame_t* f; + unsigned long lock_flags; + unsigned int mask = 0; + + if (mutex_lock_interruptible(&cam->fileop_mutex)) + return POLLERR; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + goto error; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it " + "again."); + goto error; + } + + if (cam->io == IO_NONE) { + if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) { + DBG(1, "poll() failed, not enough memory"); + goto error; + } + cam->io = IO_READ; + cam->stream = STREAM_ON; + } + + if (cam->io == IO_READ) { + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_for_each_entry(f, &cam->outqueue, frame) + f->state = F_UNUSED; + INIT_LIST_HEAD(&cam->outqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + zc0301_queue_unusedframes(cam); + } + + poll_wait(filp, &cam->wait_frame, wait); + + if (!list_empty(&cam->outqueue)) + mask |= POLLIN | POLLRDNORM; + + mutex_unlock(&cam->fileop_mutex); + + return mask; + +error: + mutex_unlock(&cam->fileop_mutex); + return POLLERR; +} + + +static void zc0301_vm_open(struct vm_area_struct* vma) +{ + struct zc0301_frame_t* f = vma->vm_private_data; + f->vma_use_count++; +} + + +static void zc0301_vm_close(struct vm_area_struct* vma) +{ + /* NOTE: buffers are not freed here */ + struct zc0301_frame_t* f = vma->vm_private_data; + f->vma_use_count--; +} + + +static struct vm_operations_struct zc0301_vm_ops = { + .open = zc0301_vm_open, + .close = zc0301_vm_close, +}; + + +static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma) +{ + struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + unsigned long size = vma->vm_end - vma->vm_start, + start = vma->vm_start; + void *pos; + u32 i; + + if (mutex_lock_interruptible(&cam->fileop_mutex)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + mutex_unlock(&cam->fileop_mutex); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it " + "again."); + mutex_unlock(&cam->fileop_mutex); + return -EIO; + } + + if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || + size != PAGE_ALIGN(cam->frame[0].buf.length)) { + mutex_unlock(&cam->fileop_mutex); + return -EINVAL; + } + + for (i = 0; i < cam->nbuffers; i++) { + if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) + break; + } + if (i == cam->nbuffers) { + mutex_unlock(&cam->fileop_mutex); + return -EINVAL; + } + + vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED; + + pos = cam->frame[i].bufmem; + while (size > 0) { /* size is page-aligned */ + if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { + mutex_unlock(&cam->fileop_mutex); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + + vma->vm_ops = &zc0301_vm_ops; + vma->vm_private_data = &cam->frame[i]; + + zc0301_vm_open(vma); + + mutex_unlock(&cam->fileop_mutex); + + return 0; +} + +/*****************************************************************************/ + +static int +zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_capability cap = { + .driver = "zc0301", + .version = ZC0301_MODULE_VERSION_CODE, + .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, + }; + + strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); + if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) + strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, + sizeof(cap.bus_info)); + + if (copy_to_user(arg, &cap, sizeof(cap))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_input i; + + if (copy_from_user(&i, arg, sizeof(i))) + return -EFAULT; + + if (i.index) + return -EINVAL; + + memset(&i, 0, sizeof(i)); + strcpy(i.name, "Camera"); + + if (copy_to_user(arg, &i, sizeof(i))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_gs_input(struct zc0301_device* cam, void __user * arg) +{ + int index; + + if (copy_from_user(&index, arg, sizeof(index))) + return -EFAULT; + + if (index != 0) + return -EINVAL; + + return 0; +} + + +static int +zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg) +{ + struct zc0301_sensor* s = cam->sensor; + struct v4l2_queryctrl qc; + u8 i; + + if (copy_from_user(&qc, arg, sizeof(qc))) + return -EFAULT; + + for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) + if (qc.id && qc.id == s->qctrl[i].id) { + memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); + if (copy_to_user(arg, &qc, sizeof(qc))) + return -EFAULT; + return 0; + } + + return -EINVAL; +} + + +static int +zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg) +{ + struct zc0301_sensor* s = cam->sensor; + struct v4l2_control ctrl; + int err = 0; + u8 i; + + if (!s->get_ctrl && !s->set_ctrl) + return -EINVAL; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) + return -EFAULT; + + if (!s->get_ctrl) { + for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) + if (ctrl.id == s->qctrl[i].id) { + ctrl.value = s->_qctrl[i].default_value; + goto exit; + } + return -EINVAL; + } else + err = s->get_ctrl(cam, &ctrl); + +exit: + if (copy_to_user(arg, &ctrl, sizeof(ctrl))) + return -EFAULT; + + return err; +} + + +static int +zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg) +{ + struct zc0301_sensor* s = cam->sensor; + struct v4l2_control ctrl; + u8 i; + int err = 0; + + if (!s->set_ctrl) + return -EINVAL; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) + return -EFAULT; + + for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) + if (ctrl.id == s->qctrl[i].id) { + if (ctrl.value < s->qctrl[i].minimum || + ctrl.value > s->qctrl[i].maximum) + return -ERANGE; + ctrl.value -= ctrl.value % s->qctrl[i].step; + break; + } + + if ((err = s->set_ctrl(cam, &ctrl))) + return err; + + s->_qctrl[i].default_value = ctrl.value; + + return 0; +} + + +static int +zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_cropcap* cc = &(cam->sensor->cropcap); + + cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cc->pixelaspect.numerator = 1; + cc->pixelaspect.denominator = 1; + + if (copy_to_user(arg, cc, sizeof(*cc))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg) +{ + struct zc0301_sensor* s = cam->sensor; + struct v4l2_crop crop = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + }; + + memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); + + if (copy_to_user(arg, &crop, sizeof(crop))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) +{ + struct zc0301_sensor* s = cam->sensor; + struct v4l2_crop crop; + struct v4l2_rect* rect; + struct v4l2_rect* bounds = &(s->cropcap.bounds); + const enum zc0301_stream_state stream = cam->stream; + const u32 nbuffers = cam->nbuffers; + u32 i; + int err = 0; + + if (copy_from_user(&crop, arg, sizeof(crop))) + return -EFAULT; + + rect = &(crop.c); + + if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (cam->module_param.force_munmap) + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_S_CROP failed. " + "Unmap the buffers first."); + return -EINVAL; + } + + if (!s->set_crop) { + memcpy(rect, &(s->_rect), sizeof(*rect)); + if (copy_to_user(arg, &crop, sizeof(crop))) + return -EFAULT; + return 0; + } + + rect->left &= ~7L; + rect->top &= ~7L; + if (rect->width < 8) + rect->width = 8; + if (rect->height < 8) + rect->height = 8; + if (rect->width > bounds->width) + rect->width = bounds->width; + if (rect->height > bounds->height) + rect->height = bounds->height; + if (rect->left < bounds->left) + rect->left = bounds->left; + if (rect->top < bounds->top) + rect->top = bounds->top; + if (rect->left + rect->width > bounds->left + bounds->width) + rect->left = bounds->left+bounds->width - rect->width; + if (rect->top + rect->height > bounds->top + bounds->height) + rect->top = bounds->top+bounds->height - rect->height; + rect->width &= ~7L; + rect->height &= ~7L; + + if (cam->stream == STREAM_ON) + if ((err = zc0301_stream_interrupt(cam))) + return err; + + if (copy_to_user(arg, &crop, sizeof(crop))) { + cam->stream = stream; + return -EFAULT; + } + + if (cam->module_param.force_munmap || cam->io == IO_READ) + zc0301_release_buffers(cam); + + if (s->set_crop) + err += s->set_crop(cam, rect); + + if (err) { /* atomic, no rollback in ioctl() */ + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " + "use the camera, close and open /dev/video%d again.", + cam->v4ldev->minor); + return -EIO; + } + + s->pix_format.width = rect->width; + s->pix_format.height = rect->height; + memcpy(&(s->_rect), rect, sizeof(*rect)); + + if ((cam->module_param.force_munmap || cam->io == IO_READ) && + nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " + "use the camera, close and open /dev/video%d again.", + cam->v4ldev->minor); + return -ENOMEM; + } + + if (cam->io == IO_READ) + zc0301_empty_framequeues(cam); + else if (cam->module_param.force_munmap) + zc0301_requeue_outqueue(cam); + + cam->stream = stream; + + return 0; +} + + +static int +zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_fmtdesc fmtd; + + if (copy_from_user(&fmtd, arg, sizeof(fmtd))) + return -EFAULT; + + if (fmtd.index == 0) { + strcpy(fmtd.description, "JPEG"); + fmtd.pixelformat = V4L2_PIX_FMT_JPEG; + fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; + } else + return -EINVAL; + + fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); + + if (copy_to_user(arg, &fmtd, sizeof(fmtd))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_format format; + struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format); + + if (copy_from_user(&format, arg, sizeof(format))) + return -EFAULT; + + if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + pfmt->bytesperline = 0; + pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); + pfmt->field = V4L2_FIELD_NONE; + memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); + + if (copy_to_user(arg, &format, sizeof(format))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, + void __user * arg) +{ + struct zc0301_sensor* s = cam->sensor; + struct v4l2_format format; + struct v4l2_pix_format* pix; + struct v4l2_pix_format* pfmt = &(s->pix_format); + struct v4l2_rect* bounds = &(s->cropcap.bounds); + struct v4l2_rect rect; + const enum zc0301_stream_state stream = cam->stream; + const u32 nbuffers = cam->nbuffers; + u32 i; + int err = 0; + + if (copy_from_user(&format, arg, sizeof(format))) + return -EFAULT; + + pix = &(format.fmt.pix); + + if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memcpy(&rect, &(s->_rect), sizeof(rect)); + + if (!s->set_crop) { + pix->width = rect.width; + pix->height = rect.height; + } else { + rect.width = pix->width; + rect.height = pix->height; + } + + if (rect.width < 8) + rect.width = 8; + if (rect.height < 8) + rect.height = 8; + if (rect.width > bounds->left + bounds->width - rect.left) + rect.width = bounds->left + bounds->width - rect.left; + if (rect.height > bounds->top + bounds->height - rect.top) + rect.height = bounds->top + bounds->height - rect.top; + rect.width &= ~7L; + rect.height &= ~7L; + + pix->width = rect.width; + pix->height = rect.height; + pix->pixelformat = pfmt->pixelformat; + pix->priv = pfmt->priv; + pix->colorspace = pfmt->colorspace; + pix->bytesperline = 0; + pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); + pix->field = V4L2_FIELD_NONE; + + if (cmd == VIDIOC_TRY_FMT) { + if (copy_to_user(arg, &format, sizeof(format))) + return -EFAULT; + return 0; + } + + if (cam->module_param.force_munmap) + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_S_FMT failed. " + "Unmap the buffers first."); + return -EINVAL; + } + + if (cam->stream == STREAM_ON) + if ((err = zc0301_stream_interrupt(cam))) + return err; + + if (copy_to_user(arg, &format, sizeof(format))) { + cam->stream = stream; + return -EFAULT; + } + + if (cam->module_param.force_munmap || cam->io == IO_READ) + zc0301_release_buffers(cam); + + if (s->set_crop) + err += s->set_crop(cam, &rect); + + if (err) { /* atomic, no rollback in ioctl() */ + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " + "use the camera, close and open /dev/video%d again.", + cam->v4ldev->minor); + return -EIO; + } + + memcpy(pfmt, pix, sizeof(*pix)); + memcpy(&(s->_rect), &rect, sizeof(rect)); + + if ((cam->module_param.force_munmap || cam->io == IO_READ) && + nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " + "use the camera, close and open /dev/video%d again.", + cam->v4ldev->minor); + return -ENOMEM; + } + + if (cam->io == IO_READ) + zc0301_empty_framequeues(cam); + else if (cam->module_param.force_munmap) + zc0301_requeue_outqueue(cam); + + cam->stream = stream; + + return 0; +} + + +static int +zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg) +{ + if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_jpegcompression jc; + const enum zc0301_stream_state stream = cam->stream; + int err = 0; + + if (copy_from_user(&jc, arg, sizeof(jc))) + return -EFAULT; + + if (jc.quality < 0 || jc.quality > 3) + return -EINVAL; + + if (cam->stream == STREAM_ON) + if ((err = zc0301_stream_interrupt(cam))) + return err; + + err += zc0301_set_compression(cam, &jc); + if (err) { /* atomic, no rollback in ioctl() */ + cam->state |= DEV_MISCONFIGURED; + DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " + "problems. To use the camera, close and open " + "/dev/video%d again.", cam->v4ldev->minor); + return -EIO; + } + + cam->compression.quality = jc.quality; + + cam->stream = stream; + + return 0; +} + + +static int +zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_requestbuffers rb; + u32 i; + int err; + + if (copy_from_user(&rb, arg, sizeof(rb))) + return -EFAULT; + + if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + rb.memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (cam->io == IO_READ) { + DBG(3, "Close and open the device again to choose the mmap " + "I/O method"); + return -EINVAL; + } + + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_REQBUFS failed. " + "Previous buffers are still mapped."); + return -EINVAL; + } + + if (cam->stream == STREAM_ON) + if ((err = zc0301_stream_interrupt(cam))) + return err; + + zc0301_empty_framequeues(cam); + + zc0301_release_buffers(cam); + if (rb.count) + rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP); + + if (copy_to_user(arg, &rb, sizeof(rb))) { + zc0301_release_buffers(cam); + cam->io = IO_NONE; + return -EFAULT; + } + + cam->io = rb.count ? IO_MMAP : IO_NONE; + + return 0; +} + + +static int +zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_buffer b; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b.index >= cam->nbuffers || cam->io != IO_MMAP) + return -EINVAL; + + memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); + + if (cam->frame[b.index].vma_use_count) + b.flags |= V4L2_BUF_FLAG_MAPPED; + + if (cam->frame[b.index].state == F_DONE) + b.flags |= V4L2_BUF_FLAG_DONE; + else if (cam->frame[b.index].state != F_UNUSED) + b.flags |= V4L2_BUF_FLAG_QUEUED; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_buffer b; + unsigned long lock_flags; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b.index >= cam->nbuffers || cam->io != IO_MMAP) + return -EINVAL; + + if (cam->frame[b.index].state != F_UNUSED) + return -EINVAL; + + cam->frame[b.index].state = F_QUEUED; + + spin_lock_irqsave(&cam->queue_lock, lock_flags); + list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + PDBGG("Frame #%lu queued", (unsigned long)b.index); + + return 0; +} + + +static int +zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp, + void __user * arg) +{ + struct v4l2_buffer b; + struct zc0301_frame_t *f; + unsigned long lock_flags; + long timeout; + + if (copy_from_user(&b, arg, sizeof(b))) + return -EFAULT; + + if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) + return -EINVAL; + + if (list_empty(&cam->outqueue)) { + if (cam->stream == STREAM_OFF) + return -EINVAL; + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + ZC0301_FRAME_TIMEOUT ); + if (timeout < 0) + return timeout; + if (cam->state & DEV_DISCONNECTED) + return -ENODEV; + if (!timeout || (cam->state & DEV_MISCONFIGURED)) + return -EIO; + } + + spin_lock_irqsave(&cam->queue_lock, lock_flags); + f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame); + list_del(cam->outqueue.next); + spin_unlock_irqrestore(&cam->queue_lock, lock_flags); + + f->state = F_UNUSED; + + memcpy(&b, &f->buf, sizeof(b)); + if (f->vma_use_count) + b.flags |= V4L2_BUF_FLAG_MAPPED; + + if (copy_to_user(arg, &b, sizeof(b))) + return -EFAULT; + + PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); + + return 0; +} + + +static int +zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg) +{ + int type; + + if (copy_from_user(&type, arg, sizeof(type))) + return -EFAULT; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) + return -EINVAL; + + if (list_empty(&cam->inqueue)) + return -EINVAL; + + cam->stream = STREAM_ON; + + DBG(3, "Stream on"); + + return 0; +} + + +static int +zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg) +{ + int type, err; + + if (copy_from_user(&type, arg, sizeof(type))) + return -EFAULT; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) + return -EINVAL; + + if (cam->stream == STREAM_ON) + if ((err = zc0301_stream_interrupt(cam))) + return err; + + zc0301_empty_framequeues(cam); + + DBG(3, "Stream off"); + + return 0; +} + + +static int +zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_streamparm sp; + + if (copy_from_user(&sp, arg, sizeof(sp))) + return -EFAULT; + + if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + sp.parm.capture.extendedmode = 0; + sp.parm.capture.readbuffers = cam->nreadbuffers; + + if (copy_to_user(arg, &sp, sizeof(sp))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg) +{ + struct v4l2_streamparm sp; + + if (copy_from_user(&sp, arg, sizeof(sp))) + return -EFAULT; + + if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + sp.parm.capture.extendedmode = 0; + + if (sp.parm.capture.readbuffers == 0) + sp.parm.capture.readbuffers = cam->nreadbuffers; + + if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES) + sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES; + + if (copy_to_user(arg, &sp, sizeof(sp))) + return -EFAULT; + + cam->nreadbuffers = sp.parm.capture.readbuffers; + + return 0; +} + + +static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp, + unsigned int cmd, void __user * arg) +{ + struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + + switch (cmd) { + + case VIDIOC_QUERYCAP: + return zc0301_vidioc_querycap(cam, arg); + + case VIDIOC_ENUMINPUT: + return zc0301_vidioc_enuminput(cam, arg); + + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + return zc0301_vidioc_gs_input(cam, arg); + + case VIDIOC_QUERYCTRL: + return zc0301_vidioc_query_ctrl(cam, arg); + + case VIDIOC_G_CTRL: + return zc0301_vidioc_g_ctrl(cam, arg); + + case VIDIOC_S_CTRL_OLD: + case VIDIOC_S_CTRL: + return zc0301_vidioc_s_ctrl(cam, arg); + + case VIDIOC_CROPCAP_OLD: + case VIDIOC_CROPCAP: + return zc0301_vidioc_cropcap(cam, arg); + + case VIDIOC_G_CROP: + return zc0301_vidioc_g_crop(cam, arg); + + case VIDIOC_S_CROP: + return zc0301_vidioc_s_crop(cam, arg); + + case VIDIOC_ENUM_FMT: + return zc0301_vidioc_enum_fmt(cam, arg); + + case VIDIOC_G_FMT: + return zc0301_vidioc_g_fmt(cam, arg); + + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: + return zc0301_vidioc_try_s_fmt(cam, cmd, arg); + + case VIDIOC_G_JPEGCOMP: + return zc0301_vidioc_g_jpegcomp(cam, arg); + + case VIDIOC_S_JPEGCOMP: + return zc0301_vidioc_s_jpegcomp(cam, arg); + + case VIDIOC_REQBUFS: + return zc0301_vidioc_reqbufs(cam, arg); + + case VIDIOC_QUERYBUF: + return zc0301_vidioc_querybuf(cam, arg); + + case VIDIOC_QBUF: + return zc0301_vidioc_qbuf(cam, arg); + + case VIDIOC_DQBUF: + return zc0301_vidioc_dqbuf(cam, filp, arg); + + case VIDIOC_STREAMON: + return zc0301_vidioc_streamon(cam, arg); + + case VIDIOC_STREAMOFF: + return zc0301_vidioc_streamoff(cam, arg); + + case VIDIOC_G_PARM: + return zc0301_vidioc_g_parm(cam, arg); + + case VIDIOC_S_PARM_OLD: + case VIDIOC_S_PARM: + return zc0301_vidioc_s_parm(cam, arg); + + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_QUERYSTD: + case VIDIOC_ENUMSTD: + case VIDIOC_QUERYMENU: + return -EINVAL; + + default: + return -EINVAL; + + } +} + + +static int zc0301_ioctl(struct inode* inode, struct file* filp, + unsigned int cmd, unsigned long arg) +{ + struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + int err = 0; + + if (mutex_lock_interruptible(&cam->fileop_mutex)) + return -ERESTARTSYS; + + if (cam->state & DEV_DISCONNECTED) { + DBG(1, "Device not present"); + mutex_unlock(&cam->fileop_mutex); + return -ENODEV; + } + + if (cam->state & DEV_MISCONFIGURED) { + DBG(1, "The camera is misconfigured. Close and open it " + "again."); + mutex_unlock(&cam->fileop_mutex); + return -EIO; + } + + V4LDBG(3, "zc0301", cmd); + + err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); + + mutex_unlock(&cam->fileop_mutex); + + return err; +} + + +static struct file_operations zc0301_fops = { + .owner = THIS_MODULE, + .open = zc0301_open, + .release = zc0301_release, + .ioctl = zc0301_ioctl, + .read = zc0301_read, + .poll = zc0301_poll, + .mmap = zc0301_mmap, + .llseek = no_llseek, +}; + +/*****************************************************************************/ + +static int +zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct zc0301_device* cam; + static unsigned int dev_nr = 0; + unsigned int i; + int err = 0; + + if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL))) + return -ENOMEM; + + cam->usbdev = udev; + + if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) { + DBG(1, "kmalloc() failed"); + err = -ENOMEM; + goto fail; + } + + if (!(cam->v4ldev = video_device_alloc())) { + DBG(1, "video_device_alloc() failed"); + err = -ENOMEM; + goto fail; + } + + mutex_init(&cam->dev_mutex); + + DBG(2, "ZC0301 Image Processor and Control Chip detected " + "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); + + for (i = 0; zc0301_sensor_table[i]; i++) { + err = zc0301_sensor_table[i](cam); + if (!err) + break; + } + + if (!err && cam->sensor) + DBG(2, "%s image sensor detected", cam->sensor->name); + else { + DBG(1, "No supported image sensor detected"); + err = -ENODEV; + goto fail; + } + + if (zc0301_init(cam)) { + DBG(1, "Initialization failed. I will retry on open()."); + cam->state |= DEV_MISCONFIGURED; + } + + strcpy(cam->v4ldev->name, "ZC0301 PC Camera"); + cam->v4ldev->owner = THIS_MODULE; + cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; + cam->v4ldev->hardware = 0; + cam->v4ldev->fops = &zc0301_fops; + cam->v4ldev->minor = video_nr[dev_nr]; + cam->v4ldev->release = video_device_release; + video_set_drvdata(cam->v4ldev, cam); + + mutex_lock(&cam->dev_mutex); + + err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, + video_nr[dev_nr]); + if (err) { + DBG(1, "V4L2 device registration failed"); + if (err == -ENFILE && video_nr[dev_nr] == -1) + DBG(1, "Free /dev/videoX node not found"); + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; + mutex_unlock(&cam->dev_mutex); + goto fail; + } + + DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); + + cam->module_param.force_munmap = force_munmap[dev_nr]; + + dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; + + usb_set_intfdata(intf, cam); + + mutex_unlock(&cam->dev_mutex); + + return 0; + +fail: + if (cam) { + kfree(cam->control_buffer); + if (cam->v4ldev) + video_device_release(cam->v4ldev); + kfree(cam); + } + return err; +} + + +static void zc0301_usb_disconnect(struct usb_interface* intf) +{ + struct zc0301_device* cam = usb_get_intfdata(intf); + + if (!cam) + return; + + down_write(&zc0301_disconnect); + + mutex_lock(&cam->dev_mutex); + + DBG(2, "Disconnecting %s...", cam->v4ldev->name); + + wake_up_interruptible_all(&cam->open); + + if (cam->users) { + DBG(2, "Device /dev/video%d is open! Deregistration and " + "memory deallocation are deferred on close.", + cam->v4ldev->minor); + cam->state |= DEV_MISCONFIGURED; + zc0301_stop_transfer(cam); + cam->state |= DEV_DISCONNECTED; + wake_up_interruptible(&cam->wait_frame); + wake_up_interruptible(&cam->wait_stream); + } else { + cam->state |= DEV_DISCONNECTED; + zc0301_release_resources(cam); + } + + mutex_unlock(&cam->dev_mutex); + + if (!cam->users) + kfree(cam); + + up_write(&zc0301_disconnect); +} + + +static struct usb_driver zc0301_usb_driver = { + .name = "zc0301", + .id_table = zc0301_id_table, + .probe = zc0301_usb_probe, + .disconnect = zc0301_usb_disconnect, +}; + +/*****************************************************************************/ + +static int __init zc0301_module_init(void) +{ + int err = 0; + + KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION); + KDBG(3, ZC0301_MODULE_AUTHOR); + + if ((err = usb_register(&zc0301_usb_driver))) + KDBG(1, "usb_register() failed"); + + return err; +} + + +static void __exit zc0301_module_exit(void) +{ + usb_deregister(&zc0301_usb_driver); +} + + +module_init(zc0301_module_init); +module_exit(zc0301_module_exit); diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c new file mode 100644 index 000000000000..83b45f1c0f4e --- /dev/null +++ b/drivers/usb/media/zc0301_pas202bcb.c @@ -0,0 +1,353 @@ +/*************************************************************************** + * Plug-in for PAS202BCB image sensor connected to the ZC030! Image * + * Processor and Control Chip * + * * + * Copyright (C) 2006 by Luca Risolia * + * * + * Initialization values of the ZC0301 have been taken from the SPCA5XX * + * driver maintained by Michel Xhaard * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include "zc0301_sensor.h" + + +static struct zc0301_sensor pas202bcb; + + +static int pas202bcb_init(struct zc0301_device* cam) +{ + int err = 0; + + err += zc0301_write_reg(cam, 0x0002, 0x00); + err += zc0301_write_reg(cam, 0x0003, 0x02); + err += zc0301_write_reg(cam, 0x0004, 0x80); + err += zc0301_write_reg(cam, 0x0005, 0x01); + err += zc0301_write_reg(cam, 0x0006, 0xE0); + err += zc0301_write_reg(cam, 0x0098, 0x00); + err += zc0301_write_reg(cam, 0x009A, 0x03); + err += zc0301_write_reg(cam, 0x011A, 0x00); + err += zc0301_write_reg(cam, 0x011C, 0x03); + err += zc0301_write_reg(cam, 0x009B, 0x01); + err += zc0301_write_reg(cam, 0x009C, 0xE6); + err += zc0301_write_reg(cam, 0x009D, 0x02); + err += zc0301_write_reg(cam, 0x009E, 0x86); + + err += zc0301_i2c_write(cam, 0x02, 0x02); + err += zc0301_i2c_write(cam, 0x0A, 0x01); + err += zc0301_i2c_write(cam, 0x0B, 0x01); + err += zc0301_i2c_write(cam, 0x0D, 0x00); + err += zc0301_i2c_write(cam, 0x12, 0x05); + err += zc0301_i2c_write(cam, 0x13, 0x63); + err += zc0301_i2c_write(cam, 0x15, 0x70); + + err += zc0301_write_reg(cam, 0x0101, 0xB7); + err += zc0301_write_reg(cam, 0x0100, 0x0D); + err += zc0301_write_reg(cam, 0x0189, 0x06); + err += zc0301_write_reg(cam, 0x01AD, 0x00); + err += zc0301_write_reg(cam, 0x01C5, 0x03); + err += zc0301_write_reg(cam, 0x01CB, 0x13); + err += zc0301_write_reg(cam, 0x0250, 0x08); + err += zc0301_write_reg(cam, 0x0301, 0x08); + err += zc0301_write_reg(cam, 0x018D, 0x70); + err += zc0301_write_reg(cam, 0x0008, 0x03); + err += zc0301_write_reg(cam, 0x01C6, 0x04); + err += zc0301_write_reg(cam, 0x01CB, 0x07); + err += zc0301_write_reg(cam, 0x0120, 0x11); + err += zc0301_write_reg(cam, 0x0121, 0x37); + err += zc0301_write_reg(cam, 0x0122, 0x58); + err += zc0301_write_reg(cam, 0x0123, 0x79); + err += zc0301_write_reg(cam, 0x0124, 0x91); + err += zc0301_write_reg(cam, 0x0125, 0xA6); + err += zc0301_write_reg(cam, 0x0126, 0xB8); + err += zc0301_write_reg(cam, 0x0127, 0xC7); + err += zc0301_write_reg(cam, 0x0128, 0xD3); + err += zc0301_write_reg(cam, 0x0129, 0xDE); + err += zc0301_write_reg(cam, 0x012A, 0xE6); + err += zc0301_write_reg(cam, 0x012B, 0xED); + err += zc0301_write_reg(cam, 0x012C, 0xF3); + err += zc0301_write_reg(cam, 0x012D, 0xF8); + err += zc0301_write_reg(cam, 0x012E, 0xFB); + err += zc0301_write_reg(cam, 0x012F, 0xFF); + err += zc0301_write_reg(cam, 0x0130, 0x26); + err += zc0301_write_reg(cam, 0x0131, 0x23); + err += zc0301_write_reg(cam, 0x0132, 0x20); + err += zc0301_write_reg(cam, 0x0133, 0x1C); + err += zc0301_write_reg(cam, 0x0134, 0x16); + err += zc0301_write_reg(cam, 0x0135, 0x13); + err += zc0301_write_reg(cam, 0x0136, 0x10); + err += zc0301_write_reg(cam, 0x0137, 0x0D); + err += zc0301_write_reg(cam, 0x0138, 0x0B); + err += zc0301_write_reg(cam, 0x0139, 0x09); + err += zc0301_write_reg(cam, 0x013A, 0x07); + err += zc0301_write_reg(cam, 0x013B, 0x06); + err += zc0301_write_reg(cam, 0x013C, 0x05); + err += zc0301_write_reg(cam, 0x013D, 0x04); + err += zc0301_write_reg(cam, 0x013E, 0x03); + err += zc0301_write_reg(cam, 0x013F, 0x02); + err += zc0301_write_reg(cam, 0x010A, 0x4C); + err += zc0301_write_reg(cam, 0x010B, 0xF5); + err += zc0301_write_reg(cam, 0x010C, 0xFF); + err += zc0301_write_reg(cam, 0x010D, 0xF9); + err += zc0301_write_reg(cam, 0x010E, 0x51); + err += zc0301_write_reg(cam, 0x010F, 0xF5); + err += zc0301_write_reg(cam, 0x0110, 0xFB); + err += zc0301_write_reg(cam, 0x0111, 0xED); + err += zc0301_write_reg(cam, 0x0112, 0x5F); + err += zc0301_write_reg(cam, 0x0180, 0x00); + err += zc0301_write_reg(cam, 0x0019, 0x00); + err += zc0301_write_reg(cam, 0x0087, 0x20); + err += zc0301_write_reg(cam, 0x0088, 0x21); + + err += zc0301_i2c_write(cam, 0x20, 0x02); + err += zc0301_i2c_write(cam, 0x21, 0x1B); + err += zc0301_i2c_write(cam, 0x03, 0x44); + err += zc0301_i2c_write(cam, 0x0E, 0x01); + err += zc0301_i2c_write(cam, 0x0F, 0x00); + + err += zc0301_write_reg(cam, 0x01A9, 0x14); + err += zc0301_write_reg(cam, 0x01AA, 0x24); + err += zc0301_write_reg(cam, 0x0190, 0x00); + err += zc0301_write_reg(cam, 0x0191, 0x02); + err += zc0301_write_reg(cam, 0x0192, 0x1B); + err += zc0301_write_reg(cam, 0x0195, 0x00); + err += zc0301_write_reg(cam, 0x0196, 0x00); + err += zc0301_write_reg(cam, 0x0197, 0x4D); + err += zc0301_write_reg(cam, 0x018C, 0x10); + err += zc0301_write_reg(cam, 0x018F, 0x20); + err += zc0301_write_reg(cam, 0x001D, 0x44); + err += zc0301_write_reg(cam, 0x001E, 0x6F); + err += zc0301_write_reg(cam, 0x001F, 0xAD); + err += zc0301_write_reg(cam, 0x0020, 0xEB); + err += zc0301_write_reg(cam, 0x0087, 0x0F); + err += zc0301_write_reg(cam, 0x0088, 0x0E); + err += zc0301_write_reg(cam, 0x0180, 0x40); + err += zc0301_write_reg(cam, 0x0192, 0x1B); + err += zc0301_write_reg(cam, 0x0191, 0x02); + err += zc0301_write_reg(cam, 0x0190, 0x00); + err += zc0301_write_reg(cam, 0x0116, 0x1D); + err += zc0301_write_reg(cam, 0x0117, 0x40); + err += zc0301_write_reg(cam, 0x0118, 0x99); + err += zc0301_write_reg(cam, 0x0180, 0x42); + err += zc0301_write_reg(cam, 0x0116, 0x1D); + err += zc0301_write_reg(cam, 0x0117, 0x40); + err += zc0301_write_reg(cam, 0x0118, 0x99); + err += zc0301_write_reg(cam, 0x0007, 0x00); + + err += zc0301_i2c_write(cam, 0x11, 0x01); + + msleep(100); + + return err; +} + + +static int pas202bcb_get_ctrl(struct zc0301_device* cam, + struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + { + int r1 = zc0301_i2c_read(cam, 0x04, 1), + r2 = zc0301_i2c_read(cam, 0x05, 1); + if (r1 < 0 || r2 < 0) + return -EIO; + ctrl->value = (r1 << 6) | (r2 & 0x3f); + } + return 0; + case V4L2_CID_RED_BALANCE: + if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case V4L2_CID_BLUE_BALANCE: + if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case V4L2_CID_GAIN: + if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case ZC0301_V4L2_CID_GREEN_BALANCE: + if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case ZC0301_V4L2_CID_DAC_MAGNITUDE: + if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0) + return -EIO; + return 0; + default: + return -EINVAL; + } +} + + +static int pas202bcb_set_ctrl(struct zc0301_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6); + err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f); + break; + case V4L2_CID_RED_BALANCE: + err += zc0301_i2c_write(cam, 0x09, ctrl->value); + break; + case V4L2_CID_BLUE_BALANCE: + err += zc0301_i2c_write(cam, 0x07, ctrl->value); + break; + case V4L2_CID_GAIN: + err += zc0301_i2c_write(cam, 0x10, ctrl->value); + break; + case ZC0301_V4L2_CID_GREEN_BALANCE: + err += zc0301_i2c_write(cam, 0x08, ctrl->value); + break; + case ZC0301_V4L2_CID_DAC_MAGNITUDE: + err += zc0301_i2c_write(cam, 0x0c, ctrl->value); + break; + default: + return -EINVAL; + } + err += zc0301_i2c_write(cam, 0x11, 0x01); + + return err ? -EIO : 0; +} + + +static struct zc0301_sensor pas202bcb = { + .name = "PAS202BCB", + .init = &pas202bcb_init, + .qctrl = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x01e5, + .maximum = 0x3fff, + .step = 0x0001, + .default_value = 0x01e5, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x0c, + .flags = 0, + }, + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x05, + .flags = 0, + }, + { + .id = ZC0301_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = ZC0301_V4L2_CID_DAC_MAGNITUDE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DAC magnitude", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x04, + .flags = 0, + }, + }, + .get_ctrl = &pas202bcb_get_ctrl, + .set_ctrl = &pas202bcb_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_JPEG, + .priv = 16, + }, +}; + + +int zc0301_probe_pas202bcb(struct zc0301_device* cam) +{ + int r0 = 0, r1 = 0, err = 0; + unsigned int pid = 0; + + err += zc0301_write_reg(cam, 0x0000, 0x01); + err += zc0301_write_reg(cam, 0x0010, 0x0e); + err += zc0301_write_reg(cam, 0x0001, 0x01); + err += zc0301_write_reg(cam, 0x0012, 0x03); + err += zc0301_write_reg(cam, 0x0012, 0x01); + err += zc0301_write_reg(cam, 0x008d, 0x08); + + msleep(10); + + r0 = zc0301_i2c_read(cam, 0x00, 1); + r1 = zc0301_i2c_read(cam, 0x01, 1); + + if (r0 < 0 || r1 < 0 || err) + return -EIO; + + pid = (r0 << 4) | ((r1 & 0xf0) >> 4); + if (pid != 0x017) + return -ENODEV; + + zc0301_attach_sensor(cam, &pas202bcb); + + return 0; +} diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h new file mode 100644 index 000000000000..8890e32405d4 --- /dev/null +++ b/drivers/usb/media/zc0301_sensor.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * API for image sensors connected to the ZC030! Image Processor and * + * Control Chip * + * * + * Copyright (C) 2006 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#ifndef _ZC0301_SENSOR_H_ +#define _ZC0301_SENSOR_H_ + +#include +#include +#include +#include +#include +#include + +struct zc0301_device; +struct zc0301_sensor; + +/*****************************************************************************/ + +extern int zc0301_probe_pas202bcb(struct zc0301_device* cam); + +#define ZC0301_SENSOR_TABLE \ +/* Weak detections must go at the end of the list */ \ +static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \ + &zc0301_probe_pas202bcb, \ + NULL, \ +}; + +extern void +zc0301_attach_sensor(struct zc0301_device* cam, + struct zc0301_sensor* sensor); + +#define ZC0301_USB_DEVICE(vend, prod, intclass) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_CLASS, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .bInterfaceClass = (intclass) + +#define ZC0301_ID_TABLE \ +static const struct usb_device_id zc0301_id_table[] = { \ + { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \ + { } \ +}; + +/*****************************************************************************/ + +extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value); +extern int zc0301_read_reg(struct zc0301_device*, u16 index); +extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value); +extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length); + +/*****************************************************************************/ + +#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 +#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE +#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 + +struct zc0301_sensor { + char name[32]; + + struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS]; + struct v4l2_cropcap cropcap; + struct v4l2_pix_format pix_format; + + int (*init)(struct zc0301_device* cam); + int (*get_ctrl)(struct zc0301_device* cam, + struct v4l2_control* ctrl); + int (*set_ctrl)(struct zc0301_device* cam, + const struct v4l2_control* ctrl); + int (*set_crop)(struct zc0301_device* cam, + const struct v4l2_rect* rect); + + const struct usb_device* usbdev; + + /* Private */ + struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS]; + struct v4l2_rect _rect; +}; + +#endif /* _ZC0301_SENSOR_H_ */ -- cgit v1.2.2 From 8781ba0aa9d9dd2870b75dba8d9a47e0f5a3f96a Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 21:24:25 +0100 Subject: [PATCH] USB: optimise devio.c::usbdev_read this is a small optimisation. It is ridiculous to do a kmalloc for 18 bytes. This puts it onto the stack. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 2b68998fe4b3..d01bd77e7b14 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -134,26 +134,21 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l } if (pos < sizeof(struct usb_device_descriptor)) { - struct usb_device_descriptor *desc = kmalloc(sizeof(*desc), GFP_KERNEL); - if (!desc) { - ret = -ENOMEM; - goto err; - } - memcpy(desc, &dev->descriptor, sizeof(dev->descriptor)); - le16_to_cpus(&desc->bcdUSB); - le16_to_cpus(&desc->idVendor); - le16_to_cpus(&desc->idProduct); - le16_to_cpus(&desc->bcdDevice); + struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */ + + memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor)); + le16_to_cpus(&temp_desc->bcdUSB); + le16_to_cpus(&temp_desc->idVendor); + le16_to_cpus(&temp_desc->idProduct); + le16_to_cpus(&temp_desc->bcdDevice); len = sizeof(struct usb_device_descriptor) - pos; if (len > nbytes) len = nbytes; - if (copy_to_user(buf, ((char *)desc) + pos, len)) { - kfree(desc); + if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) { ret = -EFAULT; goto err; } - kfree(desc); *ppos += len; buf += len; -- cgit v1.2.2 From 9fcd5c322ca2ee636e06e0c099cf8f1a692f832e Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 18 Jan 2006 23:55:07 -0800 Subject: [PATCH] USB: optimise devio.c usbdev_read fix drivers/usb/core/devio.c: In function `usbdev_read': drivers/usb/core/devio.c:140: error: invalid type argument of `->' drivers/usb/core/devio.c:141: error: invalid type argument of `->' drivers/usb/core/devio.c:142: error: invalid type argument of `->' drivers/usb/core/devio.c:143: error: invalid type argument of `->' Cc: Oliver Neukum Cc: Pete Zaitcev Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index d01bd77e7b14..de6a7c07cf97 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -137,10 +137,10 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */ memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor)); - le16_to_cpus(&temp_desc->bcdUSB); - le16_to_cpus(&temp_desc->idVendor); - le16_to_cpus(&temp_desc->idProduct); - le16_to_cpus(&temp_desc->bcdDevice); + le16_to_cpus(&temp_desc.bcdUSB); + le16_to_cpus(&temp_desc.idVendor); + le16_to_cpus(&temp_desc.idProduct); + le16_to_cpus(&temp_desc.bcdDevice); len = sizeof(struct usb_device_descriptor) - pos; if (len > nbytes) -- cgit v1.2.2 From 9ff87d7326d9e4666721070040474f60a68ab467 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 20:45:11 +0100 Subject: [PATCH] USB: mdc800.c to kzalloc one more conversion to kzalloc. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/image/mdc800.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 049871145d63..4e3e4d048c14 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -978,13 +978,11 @@ static int __init usb_mdc800_init (void) { int retval = -ENODEV; /* Allocate Memory */ - mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL); + mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL); if (!mdc800) goto cleanup_on_fail; - memset(mdc800, 0, sizeof(struct mdc800_data)); mdc800->dev = NULL; - mdc800->open=0; mdc800->state=NOT_CONNECTED; init_MUTEX (&mdc800->io_lock); -- cgit v1.2.2 From 887c2560b6ceb5fe7ac24704e85af507c6d960e5 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Sun, 8 Jan 2006 12:33:45 +0100 Subject: [PATCH] USB: kzalloc for storage another one for kzalloc. This covers the storage subdirectory. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/datafab.c | 3 +-- drivers/usb/storage/isd200.c | 8 +++----- drivers/usb/storage/jumpshot.c | 3 +-- drivers/usb/storage/sddr55.c | 3 +-- drivers/usb/storage/shuttle_usbat.c | 3 +-- 5 files changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 54e3e6c7ecd8..01d8971ad7db 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -512,13 +512,12 @@ int datafab_transport(struct scsi_cmnd * srb, struct us_data *us) }; if (!us->extra) { - us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO); + us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO); if (!us->extra) { US_DEBUGP("datafab_transport: Gah! " "Can't allocate storage for Datafab info struct!\n"); return USB_STOR_TRANSPORT_ERROR; } - memset(us->extra, 0, sizeof(struct datafab_info)); us->extra_destructor = datafab_info_destructor; ((struct datafab_info *)us->extra)->lun = -1; } diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index ecb328aa9ea1..7308e8cbe8f9 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1361,21 +1361,19 @@ static int isd200_init_info(struct us_data *us) struct isd200_info *info; info = (struct isd200_info *) - kmalloc(sizeof(struct isd200_info), GFP_KERNEL); + kzalloc(sizeof(struct isd200_info), GFP_KERNEL); if (!info) retStatus = ISD200_ERROR; else { - memset(info, 0, sizeof(struct isd200_info)); info->id = (struct hd_driveid *) - kmalloc(sizeof(struct hd_driveid), GFP_KERNEL); + kzalloc(sizeof(struct hd_driveid), GFP_KERNEL); info->RegsBuf = (unsigned char *) kmalloc(sizeof(info->ATARegs), GFP_KERNEL); if (!info->id || !info->RegsBuf) { isd200_free_info_ptrs(info); kfree(info); retStatus = ISD200_ERROR; - } else - memset(info->id, 0, sizeof(struct hd_driveid)); + } } if (retStatus == ISD200_GOOD) { diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index aff9d51c327c..5031aa98f6a9 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -441,12 +441,11 @@ int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us) }; if (!us->extra) { - us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO); + us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO); if (!us->extra) { US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n"); return USB_STOR_TRANSPORT_ERROR; } - memset(us->extra, 0, sizeof(struct jumpshot_info)); us->extra_destructor = jumpshot_info_destructor; } diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index 8451779f4269..0b1b5b59ca7b 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -751,11 +751,10 @@ int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) struct sddr55_card_info *info; if (!us->extra) { - us->extra = kmalloc( + us->extra = kzalloc( sizeof(struct sddr55_card_info), GFP_NOIO); if (!us->extra) return USB_STOR_TRANSPORT_ERROR; - memset(us->extra, 0, sizeof(struct sddr55_card_info)); us->extra_destructor = sddr55_card_info_destructor; } diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index fea176d7e79a..f2bc5c9e23d5 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -1318,12 +1318,11 @@ int init_usbat(struct us_data *us) unsigned char subcountL = USBAT_ATA_LBA_ME; unsigned char *status = us->iobuf; - us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO); + us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO); if (!us->extra) { US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n"); return 1; } - memset(us->extra, 0, sizeof(struct usbat_info)); info = (struct usbat_info *) (us->extra); /* Enable peripheral control signals */ -- cgit v1.2.2 From bbdb7dafb5b5a3c0197cbabd5055d8e9c093e3ea Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 20:54:29 +0100 Subject: [PATCH] USB: kzalloc for hid this uses kzalloc in hid. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 18 +++++------------- drivers/usb/input/hid-lgff.c | 6 ++---- drivers/usb/input/hid-tmff.c | 3 +-- drivers/usb/input/hiddev.c | 6 ++---- 4 files changed, 10 insertions(+), 23 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 07a012f88772..f187a719f17e 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -66,9 +66,8 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne if (report_enum->report_id_hash[id]) return report_enum->report_id_hash[id]; - if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL))) + if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL))) return NULL; - memset(report, 0, sizeof(struct hid_report)); if (id != 0) report_enum->numbered = 1; @@ -97,12 +96,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned return NULL; } - if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + values * sizeof(unsigned), GFP_KERNEL))) return NULL; - memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage) - + values * sizeof(unsigned)); - field->index = report->maxfield++; report->field[field->index] = field; field->usage = (struct hid_usage *)(field + 1); @@ -651,17 +647,14 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) hid_parser_reserved }; - if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL))) + if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL))) return NULL; - memset(device, 0, sizeof(struct hid_device)); - if (!(device->collection = kmalloc(sizeof(struct hid_collection) * + if (!(device->collection = kzalloc(sizeof(struct hid_collection) * HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { kfree(device); return NULL; } - memset(device->collection, 0, sizeof(struct hid_collection) * - HID_DEFAULT_NUM_COLLECTIONS); device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; for (i = 0; i < HID_REPORT_TYPES; i++) @@ -675,13 +668,12 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) memcpy(device->rdesc, start, size); device->rsize = size; - if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) { + if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) { kfree(device->rdesc); kfree(device->collection); kfree(device); return NULL; } - memset(parser, 0, sizeof(struct hid_parser)); parser->device = device; end = start + size; diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index f82c9c9e5d51..f07d44357ff1 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -154,10 +154,9 @@ int hid_lgff_init(struct hid_device* hid) return -1; } - private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL); + private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL); if (!private) return -1; - memset(private, 0, sizeof(struct lgff_device)); hid->ff_private = private; /* Input init */ @@ -228,13 +227,12 @@ static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report) } *ret->field[0] = *report->field[0]; - ret->field[0]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL); + ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL); if (!ret->field[0]->value) { kfree(ret->field[0]); kfree(ret); return NULL; } - memset(ret->field[0]->value, 0, sizeof(s32[8])); return ret; } diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 023fd5ac31c8..534425c69c0a 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -113,11 +113,10 @@ int hid_tmff_init(struct hid_device *hid) struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; - private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL); + private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!private) return -ENOMEM; - memset(private, 0, sizeof(struct tmff_device)); hid->ff_private = private; /* Find the report to use */ diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 925f5aba06f5..6dd666696178 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -257,9 +257,8 @@ static int hiddev_open(struct inode * inode, struct file * file) { if (i >= HIDDEV_MINORS || !hiddev_table[i]) return -ENODEV; - if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL))) + if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) return -ENOMEM; - memset(list, 0, sizeof(struct hiddev_list)); list->hiddev = hiddev_table[i]; list->next = hiddev_table[i]->list; @@ -754,9 +753,8 @@ int hiddev_connect(struct hid_device *hid) if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0) return -1; - if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) + if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL))) return -1; - memset(hiddev, 0, sizeof(struct hiddev)); retval = usb_register_dev(hid->intf, &hiddev_class); if (retval) { -- cgit v1.2.2 From d8e298dc9feed17f397be4bb2cd8c1dd47248c74 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 21:01:47 +0100 Subject: [PATCH] USB: kzalloc in dabusb kzalloc in dabusb. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/dabusb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c index 18d8eaf408d5..6f560fe9a519 100644 --- a/drivers/usb/media/dabusb.c +++ b/drivers/usb/media/dabusb.c @@ -217,12 +217,11 @@ static int dabusb_alloc_buffers (pdabusb_t s) pipesize, packets, transfer_buffer_length); while (buffers < (s->total_buffer_size << 10)) { - b = (pbuff_t) kmalloc (sizeof (buff_t), GFP_KERNEL); + b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL); if (!b) { - err("kmalloc(sizeof(buff_t))==NULL"); + err("kzalloc(sizeof(buff_t))==NULL"); goto err; } - memset (b, 0, sizeof (buff_t)); b->s = s; b->purb = usb_alloc_urb(packets, GFP_KERNEL); if (!b->purb) { -- cgit v1.2.2 From b10b4177881c50f22a79832558054f2e42be5cfa Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 21:28:40 +0100 Subject: [PATCH] USB: kzalloc in w9968cf another one for kzalloc. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/w9968cf.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c index 9937fc64c8bf..78cd1a577d26 100644 --- a/drivers/usb/media/w9968cf.c +++ b/drivers/usb/media/w9968cf.c @@ -695,13 +695,12 @@ static int w9968cf_allocate_memory(struct w9968cf_device* cam) /* Allocate memory for the isochronous transfer buffers */ for (i = 0; i < W9968CF_URBS; i++) { if (!(cam->transfer_buffer[i] = - kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { + kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { DBG(1, "Couldn't allocate memory for the isochronous " "transfer buffers (%u bytes)", p_size * W9968CF_ISO_PACKETS) return -ENOMEM; } - memset(cam->transfer_buffer[i], 0, W9968CF_ISO_PACKETS*p_size); } /* Allocate memory for the temporary frame buffer */ @@ -3499,12 +3498,10 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) return -ENODEV; cam = (struct w9968cf_device*) - kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL); + kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL); if (!cam) return -ENOMEM; - memset(cam, 0, sizeof(*cam)); - init_MUTEX(&cam->dev_sem); down(&cam->dev_sem); @@ -3532,21 +3529,19 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) /* Allocate 2 bytes of memory for camera control USB transfers */ - if (!(cam->control_buffer = kmalloc(2, GFP_KERNEL))) { + if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) { DBG(1,"Couldn't allocate memory for camera control transfers") err = -ENOMEM; goto fail; } - memset(cam->control_buffer, 0, 2); /* Allocate 8 bytes of memory for USB data transfers to the FSB */ - if (!(cam->data_buffer = kmalloc(8, GFP_KERNEL))) { + if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) { DBG(1, "Couldn't allocate memory for data " "transfers to the FSB") err = -ENOMEM; goto fail; } - memset(cam->data_buffer, 0, 8); /* Register the V4L device */ cam->v4ldev = video_device_alloc(); -- cgit v1.2.2 From 51b208ddf6e492c58609e07fa50bce98bb02cb27 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 21:35:08 +0100 Subject: [PATCH] USB: kzalloc in usbvideo another for kzalloc. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/usbvideo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c index 63a72e550a1b..63d279ec722b 100644 --- a/drivers/usb/media/usbvideo.c +++ b/drivers/usb/media/usbvideo.c @@ -690,14 +690,13 @@ int usbvideo_register( } base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo); - cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL); + cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL); if (cams == NULL) { err("Failed to allocate %d. bytes for usbvideo struct", base_size); return -ENOMEM; } dbg("%s: Allocated $%p (%d. bytes) for %d. cameras", __FUNCTION__, cams, base_size, num_cams); - memset(cams, 0, base_size); /* Copy callbacks, apply defaults for those that are not set */ memmove(&cams->cb, cbTbl, sizeof(cams->cb)); -- cgit v1.2.2 From 5f7481337cc803926b5c43aac44441f683ff91ed Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 22:24:56 +0100 Subject: [PATCH] USB: kzalloc in cytherm another one for kzalloc. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/cytherm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c index 6671317b495f..a04204292aa3 100644 --- a/drivers/usb/misc/cytherm.c +++ b/drivers/usb/misc/cytherm.c @@ -351,12 +351,11 @@ static int cytherm_probe(struct usb_interface *interface, struct usb_cytherm *dev = NULL; int retval = -ENOMEM; - dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL); + dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL); if (dev == NULL) { dev_err (&interface->dev, "Out of memory\n"); goto error; } - memset (dev, 0x00, sizeof (*dev)); dev->udev = usb_get_dev(udev); -- cgit v1.2.2 From 092e462a537ba60e5f78ff208c8a95e6fd071fa5 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 22:36:27 +0100 Subject: [PATCH] USB: kzalloc in idmouse another for kzalloc. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/idmouse.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index d8cde1017985..b3aca5124339 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -340,10 +340,9 @@ static int idmouse_probe(struct usb_interface *interface, return -ENODEV; /* allocate memory for our device state and initialize it */ - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; - memset(dev, 0x00, sizeof(*dev)); init_MUTEX(&dev->sem); dev->udev = udev; -- cgit v1.2.2 From 1144cf7af2ff8e6816e360d03f867439f7efde40 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 22:40:02 +0100 Subject: [PATCH] USB: kzalloc in ldusb another one for kzalloc Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ldusb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index e2d1198623eb..f6bdaf08a80f 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -626,12 +626,11 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * /* allocate memory for our device state and intialize it */ - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { dev_err(&intf->dev, "Out of memory\n"); goto exit; } - memset(dev, 0x00, sizeof(*dev)); init_MUTEX(&dev->sem); dev->intf = intf; init_waitqueue_head(&dev->read_wait); -- cgit v1.2.2 From 17590840dc3c14cb059817466884ac9bd97c4a35 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 22:41:51 +0100 Subject: [PATCH] USB: kzalloc in PhidgetInterfaceKit another for kzalloc. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/phidgetkit.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index 605a3c87e05c..997db5d8e35b 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -88,7 +88,7 @@ static int change_outputs(struct phidget_interfacekit *kit, int output_num, int int retval; int n; - buffer = kmalloc(4, GFP_KERNEL); + buffer = kzalloc(4, GFP_KERNEL); if (!buffer) { dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__); @@ -96,7 +96,6 @@ static int change_outputs(struct phidget_interfacekit *kit, int output_num, int } kit->outputs[output_num] = enable; - memset(buffer, 0, 4); for (n=0; n<8; n++) { if (kit->outputs[n]) { buffer[0] |= 1 << n; @@ -192,7 +191,7 @@ static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, unsigned char *buffer; int retval = -ENOMEM; - buffer = kmalloc(8, GFP_KERNEL); + buffer = kzalloc(8, GFP_KERNEL); if (!buffer) { dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__); goto exit; @@ -202,7 +201,6 @@ static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, retval = -EINVAL; goto exit; } - memset(buffer, 0x00, 8); if (enabled) buffer[0] = 0x01; buffer[7] = 0x11; @@ -406,12 +404,11 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - kit = kmalloc(sizeof(*kit), GFP_KERNEL); + kit = kzalloc(sizeof(*kit), GFP_KERNEL); if (kit == NULL) { dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } - memset(kit, 0, sizeof(*kit)); kit->ifkit = ifkit; kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma); -- cgit v1.2.2 From d874a2bade6eec21abb30d4822d7b3e43cfbae95 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 22:43:32 +0100 Subject: [PATCH] USB: kzalloc in PhidgetServo another for kzalloc. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/phidgetservo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c index b3418d2bcc69..5a040c205eed 100644 --- a/drivers/usb/misc/phidgetservo.c +++ b/drivers/usb/misc/phidgetservo.c @@ -252,12 +252,11 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id) struct usb_device *udev = interface_to_usbdev(interface); struct phidget_servo *dev; - dev = kmalloc(sizeof (struct phidget_servo), GFP_KERNEL); + dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL); if (dev == NULL) { dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } - memset(dev, 0x00, sizeof (*dev)); dev->udev = usb_get_dev(udev); dev->type = id->driver_info; -- cgit v1.2.2 From 06d694748b5173d972d7e4169173adad62ee67c0 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 22:44:52 +0100 Subject: [PATCH] USB: kzalloc in usbled another one for kzalloc. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbled.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c index 877b081a3a6e..f441964132c0 100644 --- a/drivers/usb/misc/usbled.c +++ b/drivers/usb/misc/usbled.c @@ -106,12 +106,11 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id struct usb_led *dev = NULL; int retval = -ENOMEM; - dev = kmalloc(sizeof(struct usb_led), GFP_KERNEL); + dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL); if (dev == NULL) { dev_err(&interface->dev, "Out of memory\n"); goto error; } - memset (dev, 0x00, sizeof (*dev)); dev->udev = usb_get_dev(udev); -- cgit v1.2.2 From 9ee884cc89dc339276c719ab4ff53913ac03d083 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 6 Jan 2006 23:27:17 +0100 Subject: [PATCH] USB: kzalloc in sisusbvga this does two things: - use kzalloc where appropriate - correct error return codes in ioctl Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 3260d595441f..196c8794a73c 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3188,7 +3188,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, break; default: - retval = -EINVAL; + retval = -ENOTTY; break; } @@ -3251,12 +3251,11 @@ static int sisusb_probe(struct usb_interface *intf, dev->devnum); /* Allocate memory for our private */ - if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) { + if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { printk(KERN_ERR "sisusb: Failed to allocate memory for private data\n"); return -ENOMEM; } - memset(sisusb, 0, sizeof(*sisusb)); kref_init(&sisusb->kref); init_MUTEX(&(sisusb->lock)); -- cgit v1.2.2 From 9628416a542488230b53df48d90d4a967dea41c8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 5 Feb 2006 00:03:28 +0100 Subject: [PATCH] USB: remove OBSOLETE_OSS_USB_DRIVER drivers This patch removes the obsolete USB_MIDI and USB_AUDIO drivers. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 2 - drivers/usb/class/Kconfig | 47 - drivers/usb/class/Makefile | 2 - drivers/usb/class/audio.c | 3869 ------------------------------------------ drivers/usb/class/audio.h | 110 -- drivers/usb/class/usb-midi.c | 2153 ----------------------- drivers/usb/class/usb-midi.h | 164 -- 7 files changed, 6347 deletions(-) delete mode 100644 drivers/usb/class/audio.c delete mode 100644 drivers/usb/class/audio.h delete mode 100644 drivers/usb/class/usb-midi.c delete mode 100644 drivers/usb/class/usb-midi.h (limited to 'drivers/usb') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index bade87b62cf9..7796ecfc0765 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -17,8 +17,6 @@ obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_ETRAX_USB_HOST) += host/ obj-$(CONFIG_USB_ACM) += class/ -obj-$(CONFIG_USB_AUDIO) += class/ -obj-$(CONFIG_USB_MIDI) += class/ obj-$(CONFIG_USB_PRINTER) += class/ obj-$(CONFIG_USB_STORAGE) += storage/ diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index ef105a92a7bd..3a9102d2591b 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig @@ -4,53 +4,6 @@ comment "USB Device Class drivers" depends on USB -config OBSOLETE_OSS_USB_DRIVER - bool "Obsolete OSS USB drivers" - depends on USB && SOUND - help - This option enables support for the obsolete USB Audio and Midi - drivers that are scheduled for removal in the near future since - there are ALSA drivers for the same hardware. - - Please contact Adrian Bunk if you had to - say Y here because of missing support in the ALSA drivers. - - If unsure, say N. - -config USB_AUDIO - tristate "USB Audio support" - depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER - help - Say Y here if you want to connect USB audio equipment such as - speakers to your computer's USB port. You only need this if you use - the OSS sound driver; ALSA has its own option for usb audio support. - - To compile this driver as a module, choose M here: the - module will be called audio. - -config USB_MIDI - tristate "USB MIDI support" - depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER - ---help--- - Say Y here if you want to connect a USB MIDI device to your - computer's USB port. You only need this if you use the OSS - sound system; USB MIDI devices are supported by ALSA's USB - audio driver. This driver is for devices that comply with - 'Universal Serial Bus Device Class Definition for MIDI Device'. - - The following devices are known to work: - * Steinberg USB2MIDI - * Roland MPU64 - * Roland PC-300 - * Roland SC8850 - * Roland UM-1 - * Roland UM-2 - * Roland UA-100 - * Yamaha MU1000 - - To compile this driver as a module, choose M here: the - module will be called usb-midi. - config USB_ACM tristate "USB Modem (CDC ACM) support" depends on USB diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile index 229471247751..cc391e6c2af8 100644 --- a/drivers/usb/class/Makefile +++ b/drivers/usb/class/Makefile @@ -4,6 +4,4 @@ # obj-$(CONFIG_USB_ACM) += cdc-acm.o -obj-$(CONFIG_USB_AUDIO) += audio.o -obj-$(CONFIG_USB_MIDI) += usb-midi.o obj-$(CONFIG_USB_PRINTER) += usblp.o diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c deleted file mode 100644 index 3ad9ee8b84a9..000000000000 --- a/drivers/usb/class/audio.c +++ /dev/null @@ -1,3869 +0,0 @@ -/*****************************************************************************/ - -/* - * audio.c -- USB Audio Class driver - * - * Copyright (C) 1999, 2000, 2001, 2003, 2004 - * Alan Cox (alan@lxorguk.ukuu.org.uk) - * Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * 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. - * - * Debugging: - * Use the 'lsusb' utility to dump the descriptors. - * - * 1999-09-07: Alan Cox - * Parsing Audio descriptor patch - * 1999-09-08: Thomas Sailer - * Added OSS compatible data io functions; both parts of the - * driver remain to be glued together - * 1999-09-10: Thomas Sailer - * Beautified the driver. Added sample format conversions. - * Still not properly glued with the parsing code. - * The parsing code seems to have its problems btw, - * Since it parses all available configs but doesn't - * store which iface/altsetting belongs to which config. - * 1999-09-20: Thomas Sailer - * Threw out Alan's parsing code and implemented my own one. - * You cannot reasonnably linearly parse audio descriptors, - * especially the AudioClass descriptors have to be considered - * pointer lists. Mixer parsing untested, due to lack of device. - * First stab at synch pipe implementation, the Dallas USB DAC - * wants to use an Asynch out pipe. usb_audio_state now basically - * only contains lists of mixer and wave devices. We can therefore - * now have multiple mixer/wave devices per USB device. - * 1999-10-28: Thomas Sailer - * Converted to URB API. Fixed a taskstate/wakeup semantics mistake - * that made the driver consume all available CPU cycles. - * Now runs stable on UHCI-Acher/Fliegl/Sailer. - * 1999-10-31: Thomas Sailer - * Audio can now be unloaded if it is not in use by any mixer - * or dsp client (formerly you had to disconnect the audio devices - * from the USB port) - * Finally, about three months after ordering, my "Maxxtro SPK222" - * speakers arrived, isn't disdata a great mail order company 8-) - * Parse class specific endpoint descriptor of the audiostreaming - * interfaces and take the endpoint attributes from there. - * Unbelievably, the Philips USB DAC has a sampling rate range - * of over a decade, yet does not support the sampling rate control! - * No wonder it sounds so bad, has very audible sampling rate - * conversion distortion. Don't try to listen to it using - * decent headphones! - * "Let's make things better" -> but please Philips start with your - * own stuff!!!! - * 1999-11-02: Thomas Sailer - * It takes the Philips boxes several seconds to acquire synchronisation - * that means they won't play short sounds. Should probably maintain - * the ISO datastream even if there's nothing to play. - * Fix counting the total_bytes counter, RealPlayer G2 depends on it. - * 1999-12-20: Thomas Sailer - * Fix bad bug in conversion to per interface probing. - * disconnect was called multiple times for the audio device, - * leading to a premature freeing of the audio structures - * 2000-05-13: Thomas Sailer - * I don't remember who changed the find_format routine, - * but the change was completely broken for the Dallas - * chip. Anyway taking sampling rate into account in find_format - * is bad and should not be done unless there are devices with - * completely broken audio descriptors. Unless someone shows - * me such a descriptor, I will not allow find_format to - * take the sampling rate into account. - * Also, the former find_format made: - * - mpg123 play mono instead of stereo - * - sox completely fail for wav's with sample rates < 44.1kHz - * for the Dallas chip. - * Also fix a rather long standing problem with applications that - * use "small" writes producing no sound at all. - * 2000-05-15: Thomas Sailer - * My fears came true, the Philips camera indeed has pretty stupid - * audio descriptors. - * 2000-05-17: Thomas Sailer - * Nemsoft spotted my stupid last minute change, thanks - * 2000-05-19: Thomas Sailer - * Fixed FEATURE_UNIT thinkos found thanks to the KC Technology - * Xtend device. Basically the driver treated FEATURE_UNIT's sourced - * by mono terminals as stereo. - * 2000-05-20: Thomas Sailer - * SELECTOR support (and thus selecting record channels from the mixer). - * Somewhat peculiar due to OSS interface limitations. Only works - * for channels where a "slider" is already in front of it (i.e. - * a MIXER unit or a FEATURE unit with volume capability). - * 2000-11-26: Thomas Sailer - * Workaround for Dallas DS4201. The DS4201 uses PCM8 as format tag for - * its 8 bit modes, but expects signed data (and should therefore have used PCM). - * 2001-03-10: Thomas Sailer - * provide abs function, prevent picking up a bogus kernel macro - * for abs. Bug report by Andrew Morton - * 2001-06-16: Bryce Nesbitt - * Fix SNDCTL_DSP_STEREO API violation - * 2003-04-08: Oliver Neukum (oliver@neukum.name): - * Setting a configuration is done by usbcore and must not be overridden - * 2004-02-27: Workaround for broken synch descriptors - * 2004-03-07: Alan Stern - * Add usb_ifnum_to_if() and usb_altnum_to_altsetting() support. - * Use the in-memory descriptors instead of reading them from the device. - * - */ - -/* - * Strategy: - * - * Alan Cox and Thomas Sailer are starting to dig at opposite ends and - * are hoping to meet in the middle, just like tunnel diggers :) - * Alan tackles the descriptor parsing, Thomas the actual data IO and the - * OSS compatible interface. - * - * Data IO implementation issues - * - * A mmap'able ring buffer per direction is implemented, because - * almost every OSS app expects it. It is however impractical to - * transmit/receive USB data directly into and out of the ring buffer, - * due to alignment and synchronisation issues. Instead, the ring buffer - * feeds a constant time delay line that handles the USB issues. - * - * Now we first try to find an alternate setting that exactly matches - * the sample format requested by the user. If we find one, we do not - * need to perform any sample rate conversions. If there is no matching - * altsetting, we choose the closest one and perform sample format - * conversions. We never do sample rate conversion; these are too - * expensive to be performed in the kernel. - * - * Current status: no known HCD-specific issues. - * - * Generally: Due to the brokenness of the Audio Class spec - * it seems generally impossible to write a generic Audio Class driver, - * so a reasonable driver should implement the features that are actually - * used. - * - * Parsing implementation issues - * - * One cannot reasonably parse the AudioClass descriptors linearly. - * Therefore the current implementation features routines to look - * for a specific descriptor in the descriptor list. - * - * How does the parsing work? First, all interfaces are searched - * for an AudioControl class interface. If found, the config descriptor - * that belongs to the current configuration is searched and - * the HEADER descriptor is found. It contains a list of - * all AudioStreaming and MIDIStreaming devices. This list is then walked, - * and all AudioStreaming interfaces are classified into input and output - * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming - * is currently not supported). The input & output list is then used - * to group inputs and outputs together and issued pairwise to the - * AudioStreaming class parser. Finally, all OUTPUT_TERMINAL descriptors - * are walked and issued to the mixer construction routine. - * - * The AudioStreaming parser simply enumerates all altsettings belonging - * to the specified interface. It looks for AS_GENERAL and FORMAT_TYPE - * class specific descriptors to extract the sample format/sample rate - * data. Only sample format types PCM and PCM8 are supported right now, and - * only FORMAT_TYPE_I is handled. The isochronous data endpoint needs to - * be the first endpoint of the interface, and the optional synchronisation - * isochronous endpoint the second one. - * - * Mixer construction works as follows: The various TERMINAL and UNIT - * descriptors span a tree from the root (OUTPUT_TERMINAL) through the - * intermediate nodes (UNITs) to the leaves (INPUT_TERMINAL). We walk - * that tree in a depth first manner. FEATURE_UNITs may contribute volume, - * bass and treble sliders to the mixer, MIXER_UNITs volume sliders. - * The terminal type encoded in the INPUT_TERMINALs feeds a heuristic - * to determine "meaningful" OSS slider numbers, however we will see - * how well this works in practice. Other features are not used at the - * moment, they seem less often used. Also, it seems difficult at least - * to construct recording source switches from SELECTOR_UNITs, but - * since there are not many USB ADC's available, we leave that for later. - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "audio.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.0.0" -#define DRIVER_AUTHOR "Alan Cox , Thomas Sailer (sailer@ife.ee.ethz.ch)" -#define DRIVER_DESC "USB Audio Class driver" - -#define AUDIO_DEBUG 1 - -#define SND_DEV_DSP16 5 - -#define dprintk(x) - -/* --------------------------------------------------------------------- */ - -/* - * Linked list of all audio devices... - */ -static struct list_head audiodevs = LIST_HEAD_INIT(audiodevs); -static DECLARE_MUTEX(open_sem); - -/* - * wait queue for processes wanting to open an USB audio device - */ -static DECLARE_WAIT_QUEUE_HEAD(open_wait); - - -#define MAXFORMATS MAX_ALT -#define DMABUFSHIFT 17 /* 128k worth of DMA buffer */ -#define NRSGBUF (1U<<(DMABUFSHIFT-PAGE_SHIFT)) - -/* - * This influences: - * - Latency - * - Interrupt rate - * - Synchronisation behaviour - * Don't touch this if you don't understand all of the above. - */ -#define DESCFRAMES 5 -#define SYNCFRAMES DESCFRAMES - -#define MIXFLG_STEREOIN 1 -#define MIXFLG_STEREOOUT 2 - -struct mixerchannel { - __u16 value; - __u16 osschannel; /* number of the OSS channel */ - __s16 minval, maxval; - __u16 slctunitid; - __u8 unitid; - __u8 selector; - __u8 chnum; - __u8 flags; -}; - -struct audioformat { - unsigned int format; - unsigned int sratelo; - unsigned int sratehi; - unsigned char altsetting; - unsigned char attributes; -}; - -struct dmabuf { - /* buffer data format */ - unsigned int format; - unsigned int srate; - /* physical buffer */ - unsigned char *sgbuf[NRSGBUF]; - unsigned bufsize; - unsigned numfrag; - unsigned fragshift; - unsigned wrptr, rdptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; -}; - -struct usb_audio_state; - -#define FLG_URB0RUNNING 1 -#define FLG_URB1RUNNING 2 -#define FLG_SYNC0RUNNING 4 -#define FLG_SYNC1RUNNING 8 -#define FLG_RUNNING 16 -#define FLG_CONNECTED 32 - -struct my_data_urb { - struct urb *urb; -}; - -struct my_sync_urb { - struct urb *urb; -}; - - -struct usb_audiodev { - struct list_head list; - struct usb_audio_state *state; - - /* soundcore stuff */ - int dev_audio; - - /* wave stuff */ - mode_t open_mode; - spinlock_t lock; /* DMA buffer access spinlock */ - - struct usbin { - int interface; /* Interface number, -1 means not used */ - unsigned int format; /* USB data format */ - unsigned int datapipe; /* the data input pipe */ - unsigned int syncpipe; /* the synchronisation pipe - 0 for anything but adaptive IN mode */ - unsigned int syncinterval; /* P for adaptive IN mode, 0 otherwise */ - unsigned int freqn; /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */ - unsigned int freqmax; /* maximum sampling rate, used for buffer management */ - unsigned int phase; /* phase accumulator */ - unsigned int flags; /* see FLG_ defines */ - - struct my_data_urb durb[2]; /* ISO descriptors for the data endpoint */ - struct my_sync_urb surb[2]; /* ISO sync pipe descriptor if needed */ - - struct dmabuf dma; - } usbin; - - struct usbout { - int interface; /* Interface number, -1 means not used */ - unsigned int format; /* USB data format */ - unsigned int datapipe; /* the data input pipe */ - unsigned int syncpipe; /* the synchronisation pipe - 0 for anything but asynchronous OUT mode */ - unsigned int syncinterval; /* P for asynchronous OUT mode, 0 otherwise */ - unsigned int freqn; /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */ - unsigned int freqm; /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */ - unsigned int freqmax; /* maximum sampling rate, used for buffer management */ - unsigned int phase; /* phase accumulator */ - unsigned int flags; /* see FLG_ defines */ - - struct my_data_urb durb[2]; /* ISO descriptors for the data endpoint */ - struct my_sync_urb surb[2]; /* ISO sync pipe descriptor if needed */ - - struct dmabuf dma; - } usbout; - - - unsigned int numfmtin, numfmtout; - struct audioformat fmtin[MAXFORMATS]; - struct audioformat fmtout[MAXFORMATS]; -}; - -struct usb_mixerdev { - struct list_head list; - struct usb_audio_state *state; - - /* soundcore stuff */ - int dev_mixer; - - unsigned char iface; /* interface number of the AudioControl interface */ - - /* USB format descriptions */ - unsigned int numch, modcnt; - - /* mixch is last and gets allocated dynamically */ - struct mixerchannel ch[0]; -}; - -struct usb_audio_state { - struct list_head audiodev; - - /* USB device */ - struct usb_device *usbdev; - - struct list_head audiolist; - struct list_head mixerlist; - - unsigned count; /* usage counter; NOTE: the usb stack is also considered a user */ -}; - -/* private audio format extensions */ -#define AFMT_STEREO 0x80000000 -#define AFMT_ISSTEREO(x) ((x) & AFMT_STEREO) -#define AFMT_IS16BIT(x) ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE)) -#define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE)) -#define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0)) -#define AFMT_BYTES(x) (1<= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* --------------------------------------------------------------------- */ - -/* - * OSS compatible ring buffer management. The ring buffer may be mmap'ed into - * an application address space. - * - * I first used the rvmalloc stuff copied from bttv. Alan Cox did not like it, so - * we now use an array of pointers to a single page each. This saves us the - * kernel page table manipulations, but we have to do a page table alike mechanism - * (though only one indirection) in software. - */ - -static void dmabuf_release(struct dmabuf *db) -{ - unsigned int nr; - void *p; - - for(nr = 0; nr < NRSGBUF; nr++) { - if (!(p = db->sgbuf[nr])) - continue; - ClearPageReserved(virt_to_page(p)); - free_page((unsigned long)p); - db->sgbuf[nr] = NULL; - } - db->mapped = db->ready = 0; -} - -static int dmabuf_init(struct dmabuf *db) -{ - unsigned int nr, bytepersec, bufs; - void *p; - - /* initialize some fields */ - db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0; - /* calculate required buffer size */ - bytepersec = db->srate << AFMT_BYTESSHIFT(db->format); - bufs = 1U << DMABUFSHIFT; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->dmasize = db->numfrag << db->fragshift; - for(nr = 0; nr < NRSGBUF; nr++) { - if (!db->sgbuf[nr]) { - p = (void *)get_zeroed_page(GFP_KERNEL); - if (!p) - return -ENOMEM; - db->sgbuf[nr] = p; - SetPageReserved(virt_to_page(p)); - } - memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE); - if ((nr << PAGE_SHIFT) >= db->dmasize) - break; - } - db->bufsize = nr << PAGE_SHIFT; - db->ready = 1; - dprintk((KERN_DEBUG "usbaudio: dmabuf_init bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d " - "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x srate %d\n", - bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize, - db->numfrag, db->dmasize, db->bufsize, db->format, db->srate)); - return 0; -} - -static int dmabuf_mmap(struct vm_area_struct *vma, struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot) -{ - unsigned int nr; - - if (!db->ready || db->mapped || (start | size) & (PAGE_SIZE-1) || size > db->bufsize) - return -EINVAL; - size >>= PAGE_SHIFT; - for(nr = 0; nr < size; nr++) - if (!db->sgbuf[nr]) - return -EINVAL; - db->mapped = 1; - for(nr = 0; nr < size; nr++) { - unsigned long pfn; - - pfn = virt_to_phys(db->sgbuf[nr]) >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, prot)) - return -EAGAIN; - start += PAGE_SIZE; - } - return 0; -} - -static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size) -{ - unsigned int pgrem, rem; - - db->total_bytes += size; - for (;;) { - if (size <= 0) - return; - pgrem = ((~db->wrptr) & (PAGE_SIZE-1)) + 1; - if (pgrem > size) - pgrem = size; - rem = db->dmasize - db->wrptr; - if (pgrem > rem) - pgrem = rem; - memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem); - size -= pgrem; - buffer += pgrem; - db->wrptr += pgrem; - if (db->wrptr >= db->dmasize) - db->wrptr = 0; - } -} - -static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size) -{ - unsigned int pgrem, rem; - - db->total_bytes += size; - for (;;) { - if (size <= 0) - return; - pgrem = ((~db->rdptr) & (PAGE_SIZE-1)) + 1; - if (pgrem > size) - pgrem = size; - rem = db->dmasize - db->rdptr; - if (pgrem > rem) - pgrem = rem; - memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem); - size -= pgrem; - buffer += pgrem; - db->rdptr += pgrem; - if (db->rdptr >= db->dmasize) - db->rdptr = 0; - } -} - -static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void __user *buffer, unsigned int size) -{ - unsigned int pgrem, rem; - - if (!db->ready || db->mapped) - return -EINVAL; - for (;;) { - if (size <= 0) - return 0; - pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1; - if (pgrem > size) - pgrem = size; - rem = db->dmasize - ptr; - if (pgrem > rem) - pgrem = rem; - if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem)) - return -EFAULT; - size -= pgrem; - buffer += pgrem; - ptr += pgrem; - if (ptr >= db->dmasize) - ptr = 0; - } -} - -static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void __user *buffer, unsigned int size) -{ - unsigned int pgrem, rem; - - if (!db->ready || db->mapped) - return -EINVAL; - for (;;) { - if (size <= 0) - return 0; - pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1; - if (pgrem > size) - pgrem = size; - rem = db->dmasize - ptr; - if (pgrem > rem) - pgrem = rem; - if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem)) - return -EFAULT; - size -= pgrem; - buffer += pgrem; - ptr += pgrem; - if (ptr >= db->dmasize) - ptr = 0; - } -} - -/* --------------------------------------------------------------------- */ -/* - * USB I/O code. We do sample format conversion if necessary - */ - -static void usbin_stop(struct usb_audiodev *as) -{ - struct usbin *u = &as->usbin; - unsigned long flags; - unsigned int i, notkilled = 1; - - spin_lock_irqsave(&as->lock, flags); - u->flags &= ~FLG_RUNNING; - i = u->flags; - spin_unlock_irqrestore(&as->lock, flags); - while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { - if (notkilled) - schedule_timeout_interruptible(1); - else - schedule_timeout_uninterruptible(1); - spin_lock_irqsave(&as->lock, flags); - i = u->flags; - spin_unlock_irqrestore(&as->lock, flags); - if (notkilled && signal_pending(current)) { - if (i & FLG_URB0RUNNING) - usb_kill_urb(u->durb[0].urb); - if (i & FLG_URB1RUNNING) - usb_kill_urb(u->durb[1].urb); - if (i & FLG_SYNC0RUNNING) - usb_kill_urb(u->surb[0].urb); - if (i & FLG_SYNC1RUNNING) - usb_kill_urb(u->surb[1].urb); - notkilled = 0; - } - } - set_current_state(TASK_RUNNING); - kfree(u->durb[0].urb->transfer_buffer); - kfree(u->durb[1].urb->transfer_buffer); - kfree(u->surb[0].urb->transfer_buffer); - kfree(u->surb[1].urb->transfer_buffer); - u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = - u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL; -} - -static inline void usbin_release(struct usb_audiodev *as) -{ - usbin_stop(as); -} - -static void usbin_disc(struct usb_audiodev *as) -{ - struct usbin *u = &as->usbin; - - unsigned long flags; - - spin_lock_irqsave(&as->lock, flags); - u->flags &= ~(FLG_RUNNING | FLG_CONNECTED); - spin_unlock_irqrestore(&as->lock, flags); - usbin_stop(as); -} - -static void conversion(const void *ibuf, unsigned int ifmt, void *obuf, unsigned int ofmt, void *tmp, unsigned int scnt) -{ - unsigned int cnt, i; - __s16 *sp, *sp2, s; - unsigned char *bp; - - cnt = scnt; - if (AFMT_ISSTEREO(ifmt)) - cnt <<= 1; - sp = ((__s16 *)tmp) + cnt; - switch (ifmt & ~AFMT_STEREO) { - case AFMT_U8: - for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) { - bp--; - sp--; - *sp = (*bp ^ 0x80) << 8; - } - break; - - case AFMT_S8: - for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) { - bp--; - sp--; - *sp = *bp << 8; - } - break; - - case AFMT_U16_LE: - for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) { - bp -= 2; - sp--; - *sp = (bp[0] | (bp[1] << 8)) ^ 0x8000; - } - break; - - case AFMT_U16_BE: - for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) { - bp -= 2; - sp--; - *sp = (bp[1] | (bp[0] << 8)) ^ 0x8000; - } - break; - - case AFMT_S16_LE: - for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) { - bp -= 2; - sp--; - *sp = bp[0] | (bp[1] << 8); - } - break; - - case AFMT_S16_BE: - for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) { - bp -= 2; - sp--; - *sp = bp[1] | (bp[0] << 8); - } - break; - } - if (!AFMT_ISSTEREO(ifmt) && AFMT_ISSTEREO(ofmt)) { - /* expand from mono to stereo */ - for (sp = ((__s16 *)tmp)+scnt, sp2 = ((__s16 *)tmp)+2*scnt, i = 0; i < scnt; i++) { - sp--; - sp2 -= 2; - sp2[0] = sp2[1] = sp[0]; - } - } - if (AFMT_ISSTEREO(ifmt) && !AFMT_ISSTEREO(ofmt)) { - /* contract from stereo to mono */ - for (sp = sp2 = ((__s16 *)tmp), i = 0; i < scnt; i++, sp++, sp2 += 2) - sp[0] = (sp2[0] + sp2[1]) >> 1; - } - cnt = scnt; - if (AFMT_ISSTEREO(ofmt)) - cnt <<= 1; - sp = ((__s16 *)tmp); - bp = ((unsigned char *)obuf); - switch (ofmt & ~AFMT_STEREO) { - case AFMT_U8: - for (i = 0; i < cnt; i++, sp++, bp++) - *bp = (*sp >> 8) ^ 0x80; - break; - - case AFMT_S8: - for (i = 0; i < cnt; i++, sp++, bp++) - *bp = *sp >> 8; - break; - - case AFMT_U16_LE: - for (i = 0; i < cnt; i++, sp++, bp += 2) { - s = *sp; - bp[0] = s; - bp[1] = (s >> 8) ^ 0x80; - } - break; - - case AFMT_U16_BE: - for (i = 0; i < cnt; i++, sp++, bp += 2) { - s = *sp; - bp[1] = s; - bp[0] = (s >> 8) ^ 0x80; - } - break; - - case AFMT_S16_LE: - for (i = 0; i < cnt; i++, sp++, bp += 2) { - s = *sp; - bp[0] = s; - bp[1] = s >> 8; - } - break; - - case AFMT_S16_BE: - for (i = 0; i < cnt; i++, sp++, bp += 2) { - s = *sp; - bp[1] = s; - bp[0] = s >> 8; - } - break; - } - -} - -static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples) -{ - union { - __s16 s[64]; - unsigned char b[0]; - } tmp; - unsigned int scnt, maxs, ufmtsh, dfmtsh; - - ufmtsh = AFMT_BYTESSHIFT(u->format); - dfmtsh = AFMT_BYTESSHIFT(u->dma.format); - maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64; - while (samples > 0) { - scnt = samples; - if (scnt > maxs) - scnt = maxs; - conversion(buffer, u->format, tmp.b, u->dma.format, tmp.b, scnt); - dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh); - buffer += scnt << ufmtsh; - samples -= scnt; - } -} - -static int usbin_prepare_desc(struct usbin *u, struct urb *urb) -{ - unsigned int i, maxsize, offs; - - maxsize = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format)); - //printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format); - for (i = offs = 0; i < DESCFRAMES; i++, offs += maxsize) { - urb->iso_frame_desc[i].length = maxsize; - urb->iso_frame_desc[i].offset = offs; - } - urb->interval = 1; - return 0; -} - -/* - * return value: 0 if descriptor should be restarted, -1 otherwise - * convert sample format on the fly if necessary - */ -static int usbin_retire_desc(struct usbin *u, struct urb *urb) -{ - unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree; - unsigned char *cp; - - ufmtsh = AFMT_BYTESSHIFT(u->format); - dfmtsh = AFMT_BYTESSHIFT(u->dma.format); - for (i = 0; i < DESCFRAMES; i++) { - cp = ((unsigned char *)urb->transfer_buffer) + urb->iso_frame_desc[i].offset; - if (urb->iso_frame_desc[i].status) { - dprintk((KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status)); - continue; - } - scnt = urb->iso_frame_desc[i].actual_length >> ufmtsh; - if (!scnt) - continue; - cnt = scnt << dfmtsh; - if (!u->dma.mapped) { - dmafree = u->dma.dmasize - u->dma.count; - if (cnt > dmafree) { - scnt = dmafree >> dfmtsh; - cnt = scnt << dfmtsh; - err++; - } - } - u->dma.count += cnt; - if (u->format == u->dma.format) { - /* we do not need format conversion */ - dprintk((KERN_DEBUG "usbaudio: no sample format conversion\n")); - dmabuf_copyin(&u->dma, cp, cnt); - } else { - /* we need sampling format conversion */ - dprintk((KERN_DEBUG "usbaudio: sample format conversion %x != %x\n", u->format, u->dma.format)); - usbin_convert(u, cp, scnt); - } - } - if (err) - u->dma.error++; - if (u->dma.count >= (signed)u->dma.fragsize) - wake_up(&u->dma.wait); - return err ? -1 : 0; -} - -static void usbin_completed(struct urb *urb, struct pt_regs *regs) -{ - struct usb_audiodev *as = (struct usb_audiodev *)urb->context; - struct usbin *u = &as->usbin; - unsigned long flags; - unsigned int mask; - int suret = 0; - -#if 0 - printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags); -#endif - if (urb == u->durb[0].urb) - mask = FLG_URB0RUNNING; - else if (urb == u->durb[1].urb) - mask = FLG_URB1RUNNING; - else { - mask = 0; - printk(KERN_ERR "usbin_completed: panic: unknown URB\n"); - } - urb->dev = as->state->usbdev; - spin_lock_irqsave(&as->lock, flags); - if (!usbin_retire_desc(u, urb) && - u->flags & FLG_RUNNING && - !usbin_prepare_desc(u, urb) && - (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) { - u->flags |= mask; - } else { - u->flags &= ~(mask | FLG_RUNNING); - wake_up(&u->dma.wait); - printk(KERN_DEBUG "usbin_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret); - } - spin_unlock_irqrestore(&as->lock, flags); -} - -/* - * we output sync data - */ -static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb) -{ - unsigned char *cp = urb->transfer_buffer; - unsigned int i, offs; - - for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3, cp += 3) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - cp[0] = u->freqn; - cp[1] = u->freqn >> 8; - cp[2] = u->freqn >> 16; - } - urb->interval = 1; - return 0; -} - -/* - * return value: 0 if descriptor should be restarted, -1 otherwise - */ -static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb) -{ - unsigned int i; - - for (i = 0; i < SYNCFRAMES; i++) - if (urb->iso_frame_desc[0].status) - dprintk((KERN_DEBUG "usbin_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status)); - return 0; -} - -static void usbin_sync_completed(struct urb *urb, struct pt_regs *regs) -{ - struct usb_audiodev *as = (struct usb_audiodev *)urb->context; - struct usbin *u = &as->usbin; - unsigned long flags; - unsigned int mask; - int suret = 0; - -#if 0 - printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags); -#endif - if (urb == u->surb[0].urb) - mask = FLG_SYNC0RUNNING; - else if (urb == u->surb[1].urb) - mask = FLG_SYNC1RUNNING; - else { - mask = 0; - printk(KERN_ERR "usbin_sync_completed: panic: unknown URB\n"); - } - urb->dev = as->state->usbdev; - spin_lock_irqsave(&as->lock, flags); - if (!usbin_sync_retire_desc(u, urb) && - u->flags & FLG_RUNNING && - !usbin_sync_prepare_desc(u, urb) && - (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) { - u->flags |= mask; - } else { - u->flags &= ~(mask | FLG_RUNNING); - wake_up(&u->dma.wait); - dprintk((KERN_DEBUG "usbin_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret)); - } - spin_unlock_irqrestore(&as->lock, flags); -} - -static int usbin_start(struct usb_audiodev *as) -{ - struct usb_device *dev = as->state->usbdev; - struct usbin *u = &as->usbin; - struct urb *urb; - unsigned long flags; - unsigned int maxsze, bufsz; - -#if 0 - printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n", - dev->devnum, u->format, u->dma.format, u->dma.srate); -#endif - /* allocate USB storage if not already done */ - spin_lock_irqsave(&as->lock, flags); - if (!(u->flags & FLG_CONNECTED)) { - spin_unlock_irqrestore(&as->lock, flags); - return -EIO; - } - if (!(u->flags & FLG_RUNNING)) { - spin_unlock_irqrestore(&as->lock, flags); - u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */ - u->freqmax = u->freqn + (u->freqn >> 2); - u->phase = 0; - maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format)); - bufsz = DESCFRAMES * maxsze; - kfree(u->durb[0].urb->transfer_buffer); - u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL); - u->durb[0].urb->transfer_buffer_length = bufsz; - kfree(u->durb[1].urb->transfer_buffer); - u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL); - u->durb[1].urb->transfer_buffer_length = bufsz; - if (u->syncpipe) { - kfree(u->surb[0].urb->transfer_buffer); - u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL); - u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES; - kfree(u->surb[1].urb->transfer_buffer); - u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL); - u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES; - } - if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || - (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) { - printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum); - return 0; - } - spin_lock_irqsave(&as->lock, flags); - } - if (u->dma.count >= u->dma.dmasize && !u->dma.mapped) { - spin_unlock_irqrestore(&as->lock, flags); - return 0; - } - u->flags |= FLG_RUNNING; - if (!(u->flags & FLG_URB0RUNNING)) { - urb = u->durb[0].urb; - urb->dev = dev; - urb->pipe = u->datapipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = DESCFRAMES; - urb->context = as; - urb->complete = usbin_completed; - if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL)) - u->flags |= FLG_URB0RUNNING; - else - u->flags &= ~FLG_RUNNING; - } - if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) { - urb = u->durb[1].urb; - urb->dev = dev; - urb->pipe = u->datapipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = DESCFRAMES; - urb->context = as; - urb->complete = usbin_completed; - if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL)) - u->flags |= FLG_URB1RUNNING; - else - u->flags &= ~FLG_RUNNING; - } - if (u->syncpipe) { - if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) { - urb = u->surb[0].urb; - urb->dev = dev; - urb->pipe = u->syncpipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = SYNCFRAMES; - urb->context = as; - urb->complete = usbin_sync_completed; - /* stride: u->syncinterval */ - if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL)) - u->flags |= FLG_SYNC0RUNNING; - else - u->flags &= ~FLG_RUNNING; - } - if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) { - urb = u->surb[1].urb; - urb->dev = dev; - urb->pipe = u->syncpipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = SYNCFRAMES; - urb->context = as; - urb->complete = usbin_sync_completed; - /* stride: u->syncinterval */ - if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL)) - u->flags |= FLG_SYNC1RUNNING; - else - u->flags &= ~FLG_RUNNING; - } - } - spin_unlock_irqrestore(&as->lock, flags); - return 0; -} - -static void usbout_stop(struct usb_audiodev *as) -{ - struct usbout *u = &as->usbout; - unsigned long flags; - unsigned int i, notkilled = 1; - - spin_lock_irqsave(&as->lock, flags); - u->flags &= ~FLG_RUNNING; - i = u->flags; - spin_unlock_irqrestore(&as->lock, flags); - while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { - if (notkilled) - schedule_timeout_interruptible(1); - else - schedule_timeout_uninterruptible(1); - spin_lock_irqsave(&as->lock, flags); - i = u->flags; - spin_unlock_irqrestore(&as->lock, flags); - if (notkilled && signal_pending(current)) { - if (i & FLG_URB0RUNNING) - usb_kill_urb(u->durb[0].urb); - if (i & FLG_URB1RUNNING) - usb_kill_urb(u->durb[1].urb); - if (i & FLG_SYNC0RUNNING) - usb_kill_urb(u->surb[0].urb); - if (i & FLG_SYNC1RUNNING) - usb_kill_urb(u->surb[1].urb); - notkilled = 0; - } - } - set_current_state(TASK_RUNNING); - kfree(u->durb[0].urb->transfer_buffer); - kfree(u->durb[1].urb->transfer_buffer); - kfree(u->surb[0].urb->transfer_buffer); - kfree(u->surb[1].urb->transfer_buffer); - u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = - u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL; -} - -static inline void usbout_release(struct usb_audiodev *as) -{ - usbout_stop(as); -} - -static void usbout_disc(struct usb_audiodev *as) -{ - struct usbout *u = &as->usbout; - unsigned long flags; - - spin_lock_irqsave(&as->lock, flags); - u->flags &= ~(FLG_RUNNING | FLG_CONNECTED); - spin_unlock_irqrestore(&as->lock, flags); - usbout_stop(as); -} - -static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples) -{ - union { - __s16 s[64]; - unsigned char b[0]; - } tmp; - unsigned int scnt, maxs, ufmtsh, dfmtsh; - - ufmtsh = AFMT_BYTESSHIFT(u->format); - dfmtsh = AFMT_BYTESSHIFT(u->dma.format); - maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64; - while (samples > 0) { - scnt = samples; - if (scnt > maxs) - scnt = maxs; - dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh); - conversion(tmp.b, u->dma.format, buffer, u->format, tmp.b, scnt); - buffer += scnt << ufmtsh; - samples -= scnt; - } -} - -static int usbout_prepare_desc(struct usbout *u, struct urb *urb) -{ - unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs; - unsigned char *cp = urb->transfer_buffer; - - ufmtsh = AFMT_BYTESSHIFT(u->format); - dfmtsh = AFMT_BYTESSHIFT(u->dma.format); - for (i = offs = 0; i < DESCFRAMES; i++) { - urb->iso_frame_desc[i].offset = offs; - u->phase = (u->phase & 0x3fff) + u->freqm; - scnt = u->phase >> 14; - if (!scnt) { - urb->iso_frame_desc[i].length = 0; - continue; - } - cnt = scnt << dfmtsh; - if (!u->dma.mapped) { - if (cnt > u->dma.count) { - scnt = u->dma.count >> dfmtsh; - cnt = scnt << dfmtsh; - err++; - } - u->dma.count -= cnt; - } else - u->dma.count += cnt; - if (u->format == u->dma.format) { - /* we do not need format conversion */ - dmabuf_copyout(&u->dma, cp, cnt); - } else { - /* we need sampling format conversion */ - usbout_convert(u, cp, scnt); - } - cnt = scnt << ufmtsh; - urb->iso_frame_desc[i].length = cnt; - offs += cnt; - cp += cnt; - } - urb->interval = 1; - if (err) - u->dma.error++; - if (u->dma.mapped) { - if (u->dma.count >= (signed)u->dma.fragsize) - wake_up(&u->dma.wait); - } else { - if ((signed)u->dma.dmasize >= u->dma.count + (signed)u->dma.fragsize) - wake_up(&u->dma.wait); - } - return err ? -1 : 0; -} - -/* - * return value: 0 if descriptor should be restarted, -1 otherwise - */ -static int usbout_retire_desc(struct usbout *u, struct urb *urb) -{ - unsigned int i; - - for (i = 0; i < DESCFRAMES; i++) { - if (urb->iso_frame_desc[i].status) { - dprintk((KERN_DEBUG "usbout_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status)); - continue; - } - } - return 0; -} - -static void usbout_completed(struct urb *urb, struct pt_regs *regs) -{ - struct usb_audiodev *as = (struct usb_audiodev *)urb->context; - struct usbout *u = &as->usbout; - unsigned long flags; - unsigned int mask; - int suret = 0; - -#if 0 - printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags); -#endif - if (urb == u->durb[0].urb) - mask = FLG_URB0RUNNING; - else if (urb == u->durb[1].urb) - mask = FLG_URB1RUNNING; - else { - mask = 0; - printk(KERN_ERR "usbout_completed: panic: unknown URB\n"); - } - urb->dev = as->state->usbdev; - spin_lock_irqsave(&as->lock, flags); - if (!usbout_retire_desc(u, urb) && - u->flags & FLG_RUNNING && - !usbout_prepare_desc(u, urb) && - (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) { - u->flags |= mask; - } else { - u->flags &= ~(mask | FLG_RUNNING); - wake_up(&u->dma.wait); - dprintk((KERN_DEBUG "usbout_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret)); - } - spin_unlock_irqrestore(&as->lock, flags); -} - -static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb) -{ - unsigned int i, offs; - - for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - } - urb->interval = 1; - return 0; -} - -/* - * return value: 0 if descriptor should be restarted, -1 otherwise - */ -static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb) -{ - unsigned char *cp = urb->transfer_buffer; - unsigned int f, i; - - for (i = 0; i < SYNCFRAMES; i++, cp += 3) { - if (urb->iso_frame_desc[i].status) { - dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status)); - continue; - } - if (urb->iso_frame_desc[i].actual_length < 3) { - dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u length %d\n", i, urb->iso_frame_desc[i].actual_length)); - continue; - } - f = cp[0] | (cp[1] << 8) | (cp[2] << 16); - if (abs(f - u->freqn) > (u->freqn >> 3) || f > u->freqmax) { - printk(KERN_WARNING "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n", f, u->freqn); - continue; - } - u->freqm = f; - } - return 0; -} - -static void usbout_sync_completed(struct urb *urb, struct pt_regs *regs) -{ - struct usb_audiodev *as = (struct usb_audiodev *)urb->context; - struct usbout *u = &as->usbout; - unsigned long flags; - unsigned int mask; - int suret = 0; - -#if 0 - printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags); -#endif - if (urb == u->surb[0].urb) - mask = FLG_SYNC0RUNNING; - else if (urb == u->surb[1].urb) - mask = FLG_SYNC1RUNNING; - else { - mask = 0; - printk(KERN_ERR "usbout_sync_completed: panic: unknown URB\n"); - } - urb->dev = as->state->usbdev; - spin_lock_irqsave(&as->lock, flags); - if (!usbout_sync_retire_desc(u, urb) && - u->flags & FLG_RUNNING && - !usbout_sync_prepare_desc(u, urb) && - (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) { - u->flags |= mask; - } else { - u->flags &= ~(mask | FLG_RUNNING); - wake_up(&u->dma.wait); - dprintk((KERN_DEBUG "usbout_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret)); - } - spin_unlock_irqrestore(&as->lock, flags); -} - -static int usbout_start(struct usb_audiodev *as) -{ - struct usb_device *dev = as->state->usbdev; - struct usbout *u = &as->usbout; - struct urb *urb; - unsigned long flags; - unsigned int maxsze, bufsz; - -#if 0 - printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n", - dev->devnum, u->format, u->dma.format, u->dma.srate); -#endif - /* allocate USB storage if not already done */ - spin_lock_irqsave(&as->lock, flags); - if (!(u->flags & FLG_CONNECTED)) { - spin_unlock_irqrestore(&as->lock, flags); - return -EIO; - } - if (!(u->flags & FLG_RUNNING)) { - spin_unlock_irqrestore(&as->lock, flags); - u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */ - u->freqmax = u->freqn + (u->freqn >> 2); - u->phase = 0; - maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format)); - bufsz = DESCFRAMES * maxsze; - kfree(u->durb[0].urb->transfer_buffer); - u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL); - u->durb[0].urb->transfer_buffer_length = bufsz; - kfree(u->durb[1].urb->transfer_buffer); - u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL); - u->durb[1].urb->transfer_buffer_length = bufsz; - if (u->syncpipe) { - kfree(u->surb[0].urb->transfer_buffer); - u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL); - u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES; - kfree(u->surb[1].urb->transfer_buffer); - u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL); - u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES; - } - if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || - (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) { - printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum); - return 0; - } - spin_lock_irqsave(&as->lock, flags); - } - if (u->dma.count <= 0 && !u->dma.mapped) { - spin_unlock_irqrestore(&as->lock, flags); - return 0; - } - u->flags |= FLG_RUNNING; - if (!(u->flags & FLG_URB0RUNNING)) { - urb = u->durb[0].urb; - urb->dev = dev; - urb->pipe = u->datapipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = DESCFRAMES; - urb->context = as; - urb->complete = usbout_completed; - if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC)) - u->flags |= FLG_URB0RUNNING; - else - u->flags &= ~FLG_RUNNING; - } - if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) { - urb = u->durb[1].urb; - urb->dev = dev; - urb->pipe = u->datapipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = DESCFRAMES; - urb->context = as; - urb->complete = usbout_completed; - if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC)) - u->flags |= FLG_URB1RUNNING; - else - u->flags &= ~FLG_RUNNING; - } - if (u->syncpipe) { - if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) { - urb = u->surb[0].urb; - urb->dev = dev; - urb->pipe = u->syncpipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = SYNCFRAMES; - urb->context = as; - urb->complete = usbout_sync_completed; - /* stride: u->syncinterval */ - if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC)) - u->flags |= FLG_SYNC0RUNNING; - else - u->flags &= ~FLG_RUNNING; - } - if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) { - urb = u->surb[1].urb; - urb->dev = dev; - urb->pipe = u->syncpipe; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = SYNCFRAMES; - urb->context = as; - urb->complete = usbout_sync_completed; - /* stride: u->syncinterval */ - if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC)) - u->flags |= FLG_SYNC1RUNNING; - else - u->flags &= ~FLG_RUNNING; - } - } - spin_unlock_irqrestore(&as->lock, flags); - return 0; -} - -/* --------------------------------------------------------------------- */ - -static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate) -{ - unsigned int g = 0; - - if (srate < afp->sratelo) - g += afp->sratelo - srate; - if (srate > afp->sratehi) - g += srate - afp->sratehi; - if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt)) - g += 0x100000; - if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt)) - g += 0x400000; - if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt)) - g += 0x100000; - if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt)) - g += 0x400000; - return g; -} - -static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate) -{ - unsigned int i, g, gb = ~0; - int j = -1; /* default to failure */ - - /* find "best" format (according to format_goodness) */ - for (i = 0; i < nr; i++) { - g = format_goodness(&afp[i], fmt, srate); - if (g >= gb) - continue; - j = i; - gb = g; - } - return j; -} - -static int set_format_in(struct usb_audiodev *as) -{ - struct usb_device *dev = as->state->usbdev; - struct usb_host_interface *alts; - struct usb_interface *iface; - struct usbin *u = &as->usbin; - struct dmabuf *d = &u->dma; - struct audioformat *fmt; - unsigned int ep; - unsigned char data[3]; - int fmtnr, ret; - - iface = usb_ifnum_to_if(dev, u->interface); - if (!iface) - return 0; - - fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate); - if (fmtnr < 0) { - printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n"); - return -1; - } - - fmt = as->fmtin + fmtnr; - alts = usb_altnum_to_altsetting(iface, fmt->altsetting); - u->format = fmt->format; - u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf); - u->syncpipe = u->syncinterval = 0; - if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x08) { - if (alts->desc.bNumEndpoints < 2 || - alts->endpoint[1].desc.bmAttributes != 0x01 || - alts->endpoint[1].desc.bSynchAddress != 0 || - alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) { - printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in " - "but has invalid synch pipe; treating as asynchronous in\n", - dev->devnum, u->interface, fmt->altsetting); - } else { - u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); - u->syncinterval = alts->endpoint[1].desc.bRefresh; - } - } - if (d->srate < fmt->sratelo) - d->srate = fmt->sratelo; - if (d->srate > fmt->sratehi) - d->srate = fmt->sratehi; - dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n", - u->interface, fmt->altsetting)); - if (usb_set_interface(dev, alts->desc.bInterfaceNumber, fmt->altsetting) < 0) { - printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", - dev->devnum, u->interface, fmt->altsetting); - return -1; - } - if (fmt->sratelo == fmt->sratehi) - return 0; - ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN); - /* if endpoint has pitch control, enable it */ - if (fmt->attributes & 0x02) { - data[0] = 1; - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) { - printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n", - ret, dev->devnum, u->interface, ep, d->srate); - return -1; - } - } - /* if endpoint has sampling rate control, set it */ - if (fmt->attributes & 0x01) { - data[0] = d->srate; - data[1] = d->srate >> 8; - data[2] = d->srate >> 16; - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) { - printk(KERN_ERR "usbaudio: failure (error %d) to set input sampling frequency device %d interface %u endpoint 0x%x to %u\n", - ret, dev->devnum, u->interface, ep, d->srate); - return -1; - } - if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, - SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) { - printk(KERN_ERR "usbaudio: failure (error %d) to get input sampling frequency device %d interface %u endpoint 0x%x\n", - ret, dev->devnum, u->interface, ep); - return -1; - } - dprintk((KERN_DEBUG "usbaudio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n", - dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16))); - d->srate = data[0] | (data[1] << 8) | (data[2] << 16); - } - dprintk((KERN_DEBUG "usbaudio: set_format_in: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate)); - return 0; -} - -static int set_format_out(struct usb_audiodev *as) -{ - struct usb_device *dev = as->state->usbdev; - struct usb_host_interface *alts; - struct usb_interface *iface; - struct usbout *u = &as->usbout; - struct dmabuf *d = &u->dma; - struct audioformat *fmt; - unsigned int ep; - unsigned char data[3]; - int fmtnr, ret; - - iface = usb_ifnum_to_if(dev, u->interface); - if (!iface) - return 0; - - fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate); - if (fmtnr < 0) { - printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n"); - return -1; - } - - fmt = as->fmtout + fmtnr; - u->format = fmt->format; - alts = usb_altnum_to_altsetting(iface, fmt->altsetting); - u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf); - u->syncpipe = u->syncinterval = 0; - if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x04) { -#if 0 - printk(KERN_DEBUG "bNumEndpoints 0x%02x endpoint[1].bmAttributes 0x%02x\n" - KERN_DEBUG "endpoint[1].bSynchAddress 0x%02x endpoint[1].bEndpointAddress 0x%02x\n" - KERN_DEBUG "endpoint[0].bSynchAddress 0x%02x\n", alts->bNumEndpoints, - alts->endpoint[1].bmAttributes, alts->endpoint[1].bSynchAddress, - alts->endpoint[1].bEndpointAddress, alts->endpoint[0].bSynchAddress); -#endif - if (alts->desc.bNumEndpoints < 2 || - alts->endpoint[1].desc.bmAttributes != 0x01 || - alts->endpoint[1].desc.bSynchAddress != 0 || - alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress | 0x80)) { - printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out " - "but has invalid synch pipe; treating as adaptive out\n", - dev->devnum, u->interface, fmt->altsetting); - } else { - u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf); - u->syncinterval = alts->endpoint[1].desc.bRefresh; - } - } - if (d->srate < fmt->sratelo) - d->srate = fmt->sratelo; - if (d->srate > fmt->sratehi) - d->srate = fmt->sratehi; - dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n", - u->interface, fmt->altsetting)); - if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) { - printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", - dev->devnum, u->interface, fmt->altsetting); - return -1; - } - if (fmt->sratelo == fmt->sratehi) - return 0; - ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN); - /* if endpoint has pitch control, enable it */ - if (fmt->attributes & 0x02) { - data[0] = 1; - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) { - printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n", - ret, dev->devnum, u->interface, ep, d->srate); - return -1; - } - } - /* if endpoint has sampling rate control, set it */ - if (fmt->attributes & 0x01) { - data[0] = d->srate; - data[1] = d->srate >> 8; - data[2] = d->srate >> 16; - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) { - printk(KERN_ERR "usbaudio: failure (error %d) to set output sampling frequency device %d interface %u endpoint 0x%x to %u\n", - ret, dev->devnum, u->interface, ep, d->srate); - return -1; - } - if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, - SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) { - printk(KERN_ERR "usbaudio: failure (error %d) to get output sampling frequency device %d interface %u endpoint 0x%x\n", - ret, dev->devnum, u->interface, ep); - return -1; - } - dprintk((KERN_DEBUG "usbaudio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n", - dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16))); - d->srate = data[0] | (data[1] << 8) | (data[2] << 16); - } - dprintk((KERN_DEBUG "usbaudio: set_format_out: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate)); - return 0; -} - -static int set_format(struct usb_audiodev *s, unsigned int fmode, unsigned int fmt, unsigned int srate) -{ - int ret1 = 0, ret2 = 0; - - if (!(fmode & (FMODE_READ|FMODE_WRITE))) - return -EINVAL; - if (fmode & FMODE_READ) { - usbin_stop(s); - s->usbin.dma.ready = 0; - if (fmt == AFMT_QUERY) - fmt = s->usbin.dma.format; - else - s->usbin.dma.format = fmt; - if (!srate) - srate = s->usbin.dma.srate; - else - s->usbin.dma.srate = srate; - } - if (fmode & FMODE_WRITE) { - usbout_stop(s); - s->usbout.dma.ready = 0; - if (fmt == AFMT_QUERY) - fmt = s->usbout.dma.format; - else - s->usbout.dma.format = fmt; - if (!srate) - srate = s->usbout.dma.srate; - else - s->usbout.dma.srate = srate; - } - if (fmode & FMODE_READ) - ret1 = set_format_in(s); - if (fmode & FMODE_WRITE) - ret2 = set_format_out(s); - return ret1 ? ret1 : ret2; -} - -/* --------------------------------------------------------------------- */ - -static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value) -{ - struct usb_device *dev = ms->state->usbdev; - unsigned char data[2]; - struct mixerchannel *ch; - int v1, v2, v3; - - if (mixch >= ms->numch) - return -1; - ch = &ms->ch[mixch]; - v3 = ch->maxval - ch->minval; - v1 = value & 0xff; - v2 = (value >> 8) & 0xff; - if (v1 > 100) - v1 = 100; - if (v2 > 100) - v2 = 100; - if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) - v2 = v1; - ch->value = v1 | (v2 << 8); - v1 = (v1 * v3) / 100 + ch->minval; - v2 = (v2 * v3) / 100 + ch->minval; - switch (ch->selector) { - case 0: /* mixer unit request */ - data[0] = v1; - data[1] = v1 >> 8; - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0) - goto err; - if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) - return 0; - data[0] = v2; - data[1] = v2 >> 8; - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)), - ms->iface | (ch->unitid << 8), data, 2, 1000) < 0) - goto err; - return 0; - - /* various feature unit controls */ - case VOLUME_CONTROL: - data[0] = v1; - data[1] = v1 >> 8; - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0) - goto err; - if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) - return 0; - data[0] = v2; - data[1] = v2 >> 8; - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, 1000) < 0) - goto err; - return 0; - - case BASS_CONTROL: - case MID_CONTROL: - case TREBLE_CONTROL: - data[0] = v1 >> 8; - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, 1000) < 0) - goto err; - if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) - return 0; - data[0] = v2 >> 8; - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, 1000) < 0) - goto err; - return 0; - - default: - return -1; - } - return 0; - - err: - printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", - dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector); - return -1; -} - -static int get_rec_src(struct usb_mixerdev *ms) -{ - struct usb_device *dev = ms->state->usbdev; - unsigned int mask = 0, retmask = 0; - unsigned int i, j; - unsigned char buf; - int err = 0; - - for (i = 0; i < ms->numch; i++) { - if (!ms->ch[i].slctunitid || (mask & (1 << i))) - continue; - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) { - err = -EIO; - printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", - dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff); - continue; - } - for (j = i; j < ms->numch; j++) { - if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) - continue; - mask |= 1 << j; - if (buf == (ms->ch[j].slctunitid >> 8)) - retmask |= 1 << ms->ch[j].osschannel; - } - } - if (err) - return -EIO; - return retmask; -} - -static int set_rec_src(struct usb_mixerdev *ms, int srcmask) -{ - struct usb_device *dev = ms->state->usbdev; - unsigned int mask = 0, smask, bmask; - unsigned int i, j; - unsigned char buf; - int err = 0; - - for (i = 0; i < ms->numch; i++) { - if (!ms->ch[i].slctunitid || (mask & (1 << i))) - continue; - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) { - err = -EIO; - printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", - dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff); - continue; - } - /* first generate smask */ - smask = bmask = 0; - for (j = i; j < ms->numch; j++) { - if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) - continue; - smask |= 1 << ms->ch[j].osschannel; - if (buf == (ms->ch[j].slctunitid >> 8)) - bmask |= 1 << ms->ch[j].osschannel; - mask |= 1 << j; - } - /* check for multiple set sources */ - j = hweight32(srcmask & smask); - if (j == 0) - continue; - if (j > 1) - srcmask &= ~bmask; - for (j = i; j < ms->numch; j++) { - if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff) - continue; - if (!(srcmask & (1 << ms->ch[j].osschannel))) - continue; - buf = ms->ch[j].slctunitid >> 8; - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - 0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, 1000) < 0) { - err = -EIO; - printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n", - dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff); - continue; - } - } - } - return err ? -EIO : 0; -} - -/* --------------------------------------------------------------------- */ - -/* - * should be called with open_sem hold, so that no new processes - * look at the audio device to be destroyed - */ - -static void release(struct usb_audio_state *s) -{ - struct usb_audiodev *as; - struct usb_mixerdev *ms; - - s->count--; - if (s->count) { - up(&open_sem); - return; - } - up(&open_sem); - wake_up(&open_wait); - while (!list_empty(&s->audiolist)) { - as = list_entry(s->audiolist.next, struct usb_audiodev, list); - list_del(&as->list); - usbin_release(as); - usbout_release(as); - dmabuf_release(&as->usbin.dma); - dmabuf_release(&as->usbout.dma); - usb_free_urb(as->usbin.durb[0].urb); - usb_free_urb(as->usbin.durb[1].urb); - usb_free_urb(as->usbin.surb[0].urb); - usb_free_urb(as->usbin.surb[1].urb); - usb_free_urb(as->usbout.durb[0].urb); - usb_free_urb(as->usbout.durb[1].urb); - usb_free_urb(as->usbout.surb[0].urb); - usb_free_urb(as->usbout.surb[1].urb); - kfree(as); - } - while (!list_empty(&s->mixerlist)) { - ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list); - list_del(&ms->list); - kfree(ms); - } - kfree(s); -} - -static inline int prog_dmabuf_in(struct usb_audiodev *as) -{ - usbin_stop(as); - return dmabuf_init(&as->usbin.dma); -} - -static inline int prog_dmabuf_out(struct usb_audiodev *as) -{ - usbout_stop(as); - return dmabuf_init(&as->usbout.dma); -} - -/* --------------------------------------------------------------------- */ - -static int usb_audio_open_mixdev(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - struct usb_mixerdev *ms; - struct usb_audio_state *s; - - down(&open_sem); - list_for_each_entry(s, &audiodevs, audiodev) { - list_for_each_entry(ms, &s->mixerlist, list) { - if (ms->dev_mixer == minor) - goto mixer_found; - } - } - up(&open_sem); - return -ENODEV; - - mixer_found: - if (!s->usbdev) { - up(&open_sem); - return -EIO; - } - file->private_data = ms; - s->count++; - - up(&open_sem); - return nonseekable_open(inode, file); -} - -static int usb_audio_release_mixdev(struct inode *inode, struct file *file) -{ - struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data; - struct usb_audio_state *s; - - lock_kernel(); - s = ms->state; - down(&open_sem); - release(s); - unlock_kernel(); - return 0; -} - -static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data; - int i, j, val; - int __user *user_arg = (int __user *)arg; - - if (!ms->state->usbdev) - return -ENODEV; - - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - - memset(&info, 0, sizeof(info)); - strncpy(info.id, "USB_AUDIO", sizeof(info.id)); - strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); - info.modify_counter = ms->modcnt; - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - - memset(&info, 0, sizeof(info)); - strncpy(info.id, "USB_AUDIO", sizeof(info.id)); - strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, user_arg); - if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - if (_IOC_DIR(cmd) == _IOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - val = get_rec_src(ms); - if (val < 0) - return val; - return put_user(val, user_arg); - - case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - for (val = i = 0; i < ms->numch; i++) - val |= 1 << ms->ch[i].osschannel; - return put_user(val, user_arg); - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - for (val = i = 0; i < ms->numch; i++) - if (ms->ch[i].slctunitid) - val |= 1 << ms->ch[i].osschannel; - return put_user(val, user_arg); - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - for (val = i = 0; i < ms->numch; i++) - if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) - val |= 1 << ms->ch[i].osschannel; - return put_user(val, user_arg); - - case SOUND_MIXER_CAPS: - return put_user(SOUND_CAP_EXCL_INPUT, user_arg); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES) - return -EINVAL; - for (j = 0; j < ms->numch; j++) { - if (ms->ch[j].osschannel == i) { - return put_user(ms->ch[j].value, user_arg); - } - } - return -EINVAL; - } - } - if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) - return -EINVAL; - ms->modcnt++; - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - if (get_user(val, user_arg)) - return -EFAULT; - return set_rec_src(ms, val); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES) - return -EINVAL; - for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++); - if (j >= ms->numch) - return -EINVAL; - if (get_user(val, user_arg)) - return -EFAULT; - if (wrmixer(ms, j, val)) - return -EIO; - return put_user(ms->ch[j].value, user_arg); - } -} - -static /*const*/ struct file_operations usb_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = usb_audio_ioctl_mixdev, - .open = usb_audio_open_mixdev, - .release = usb_audio_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_out(struct usb_audiodev *as, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (as->usbout.dma.mapped || !as->usbout.dma.ready) - return 0; - usbout_start(as); - add_wait_queue(&as->usbout.dma.wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&as->lock, flags); - count = as->usbout.dma.count; - spin_unlock_irqrestore(&as->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&as->usbout.dma.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * count / as->usbout.dma.srate; - tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format); - if (!schedule_timeout(tmo + 1)) { - printk(KERN_DEBUG "usbaudio: dma timed out??\n"); - break; - } - } - remove_wait_queue(&as->usbout.dma.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static ssize_t usb_audio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned int ptr; - int cnt, err; - - if (as->usbin.dma.mapped) - return -ENXIO; - if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - add_wait_queue(&as->usbin.dma.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&as->lock, flags); - ptr = as->usbin.dma.rdptr; - cnt = as->usbin.dma.count; - /* set task state early to avoid wakeup races */ - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&as->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (usbin_start(as)) { - if (!ret) - ret = -ENODEV; - break; - } - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if ((err = dmabuf_copyout_user(&as->usbin.dma, ptr, buffer, cnt))) { - if (!ret) - ret = err; - break; - } - ptr += cnt; - if (ptr >= as->usbin.dma.dmasize) - ptr -= as->usbin.dma.dmasize; - spin_lock_irqsave(&as->lock, flags); - as->usbin.dma.rdptr = ptr; - as->usbin.dma.count -= cnt; - spin_unlock_irqrestore(&as->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&as->usbin.dma.wait, &wait); - return ret; -} - -static ssize_t usb_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned int ptr; - unsigned int start_thr; - int cnt, err; - - if (as->usbout.dma.mapped) - return -ENXIO; - if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES)); - add_wait_queue(&as->usbout.dma.wait, &wait); - while (count > 0) { -#if 0 - printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%lx\n", - count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize, - as->usbout.flags, current->state); -#endif - spin_lock_irqsave(&as->lock, flags); - if (as->usbout.dma.count < 0) { - as->usbout.dma.count = 0; - as->usbout.dma.rdptr = as->usbout.dma.wrptr; - } - ptr = as->usbout.dma.wrptr; - cnt = as->usbout.dma.dmasize - as->usbout.dma.count; - /* set task state early to avoid wakeup races */ - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&as->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (usbout_start(as)) { - if (!ret) - ret = -ENODEV; - break; - } - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if ((err = dmabuf_copyin_user(&as->usbout.dma, ptr, buffer, cnt))) { - if (!ret) - ret = err; - break; - } - ptr += cnt; - if (ptr >= as->usbout.dma.dmasize) - ptr -= as->usbout.dma.dmasize; - spin_lock_irqsave(&as->lock, flags); - as->usbout.dma.wrptr = ptr; - as->usbout.dma.count += cnt; - spin_unlock_irqrestore(&as->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (as->usbout.dma.count >= start_thr && usbout_start(as)) { - if (!ret) - ret = -ENODEV; - break; - } - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&as->usbout.dma.wait, &wait); - return ret; -} - -/* Called without the kernel lock - fine */ -static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait) -{ - struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - if (file->f_mode & FMODE_WRITE) { - if (!as->usbout.dma.ready) - prog_dmabuf_out(as); - poll_wait(file, &as->usbout.dma.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!as->usbin.dma.ready) - prog_dmabuf_in(as); - poll_wait(file, &as->usbin.dma.wait, wait); - } - spin_lock_irqsave(&as->lock, flags); - if (file->f_mode & FMODE_READ) { - if (as->usbin.dma.count >= (signed)as->usbin.dma.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (as->usbout.dma.mapped) { - if (as->usbout.dma.count >= (signed)as->usbout.dma.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)as->usbout.dma.dmasize >= as->usbout.dma.count + (signed)as->usbout.dma.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&as->lock, flags); - return mask; -} - -static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; - struct dmabuf *db; - int ret = -EINVAL; - - lock_kernel(); - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf_out(as)) != 0) - goto out; - db = &as->usbout.dma; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf_in(as)) != 0) - goto out; - db = &as->usbin.dma; - } else - goto out; - - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - - ret = dmabuf_mmap(vma, db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); -out: - unlock_kernel(); - return ret; -} - -static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; - struct usb_audio_state *s = as->state; - int __user *user_arg = (int __user *)arg; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int val = 0; - int val2, mapped, ret; - - if (!s->usbdev) - return -EIO; - mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) || - ((file->f_mode & FMODE_READ) && as->usbin.dma.mapped); -#if 0 - if (arg) - get_user(val, (int *)arg); - printk(KERN_DEBUG "usbaudio: usb_audio_ioctl cmd=%x arg=%lx *arg=%d\n", cmd, arg, val) -#endif - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, user_arg); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_out(as, 0/*file->f_flags & O_NONBLOCK*/); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | - DSP_CAP_MMAP | DSP_CAP_BATCH, user_arg); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - usbout_stop(as); - as->usbout.dma.rdptr = as->usbout.dma.wrptr = as->usbout.dma.count = as->usbout.dma.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - usbin_stop(as); - as->usbin.dma.rdptr = as->usbin.dma.wrptr = as->usbin.dma.count = as->usbin.dma.total_bytes = 0; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, user_arg)) - return -EFAULT; - if (val >= 0) { - if (val < 4000) - val = 4000; - if (val > 100000) - val = 100000; - if (set_format(as, file->f_mode, AFMT_QUERY, val)) - return -EIO; - } - return put_user((file->f_mode & FMODE_READ) ? - as->usbin.dma.srate : as->usbout.dma.srate, - user_arg); - - case SNDCTL_DSP_STEREO: - if (get_user(val, user_arg)) - return -EFAULT; - val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; - if (val) - val2 |= AFMT_STEREO; - else - val2 &= ~AFMT_STEREO; - if (set_format(as, file->f_mode, val2, 0)) - return -EIO; - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, user_arg)) - return -EFAULT; - if (val != 0) { - val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; - if (val == 1) - val2 &= ~AFMT_STEREO; - else - val2 |= AFMT_STEREO; - if (set_format(as, file->f_mode, val2, 0)) - return -EIO; - } - val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; - return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE | - AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, user_arg); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, user_arg)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (hweight32(val) != 1) - return -EINVAL; - if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE | - AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE))) - return -EINVAL; - val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; - val |= val2 & AFMT_STEREO; - if (set_format(as, file->f_mode, val, 0)) - return -EIO; - } - val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; - return put_user(val2 & ~AFMT_STEREO, user_arg); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & FMODE_READ && as->usbin.flags & FLG_RUNNING) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && as->usbout.flags & FLG_RUNNING) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, user_arg); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, user_arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as))) - return ret; - if (usbin_start(as)) - return -ENODEV; - } else - usbin_stop(as); - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as))) - return ret; - if (usbout_start(as)) - return -ENODEV; - } else - usbout_stop(as); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0) - return val; - spin_lock_irqsave(&as->lock, flags); - abinfo.fragsize = as->usbout.dma.fragsize; - abinfo.bytes = as->usbout.dma.dmasize - as->usbout.dma.count; - abinfo.fragstotal = as->usbout.dma.numfrag; - abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift; - spin_unlock_irqrestore(&as->lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0) - return val; - spin_lock_irqsave(&as->lock, flags); - abinfo.fragsize = as->usbin.dma.fragsize; - abinfo.bytes = as->usbin.dma.count; - abinfo.fragstotal = as->usbin.dma.numfrag; - abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift; - spin_unlock_irqrestore(&as->lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&as->lock, flags); - val = as->usbout.dma.count; - spin_unlock_irqrestore(&as->lock, flags); - return put_user(val, user_arg); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - spin_lock_irqsave(&as->lock, flags); - cinfo.bytes = as->usbin.dma.total_bytes; - cinfo.blocks = as->usbin.dma.count >> as->usbin.dma.fragshift; - cinfo.ptr = as->usbin.dma.wrptr; - if (as->usbin.dma.mapped) - as->usbin.dma.count &= as->usbin.dma.fragsize-1; - spin_unlock_irqrestore(&as->lock, flags); - if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&as->lock, flags); - cinfo.bytes = as->usbout.dma.total_bytes; - cinfo.blocks = as->usbout.dma.count >> as->usbout.dma.fragshift; - cinfo.ptr = as->usbout.dma.rdptr; - if (as->usbout.dma.mapped) - as->usbout.dma.count &= as->usbout.dma.fragsize-1; - spin_unlock_irqrestore(&as->lock, flags); - if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf_out(as))) - return val; - return put_user(as->usbout.dma.fragsize, user_arg); - } - if ((val = prog_dmabuf_in(as))) - return val; - return put_user(as->usbin.dma.fragsize, user_arg); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, user_arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - as->usbin.dma.ossfragshift = val & 0xffff; - as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff; - if (as->usbin.dma.ossfragshift < 4) - as->usbin.dma.ossfragshift = 4; - if (as->usbin.dma.ossfragshift > 15) - as->usbin.dma.ossfragshift = 15; - if (as->usbin.dma.ossmaxfrags < 4) - as->usbin.dma.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - as->usbout.dma.ossfragshift = val & 0xffff; - as->usbout.dma.ossmaxfrags = (val >> 16) & 0xffff; - if (as->usbout.dma.ossfragshift < 4) - as->usbout.dma.ossfragshift = 4; - if (as->usbout.dma.ossfragshift > 15) - as->usbout.dma.ossfragshift = 15; - if (as->usbout.dma.ossmaxfrags < 4) - as->usbout.dma.ossmaxfrags = 4; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) || - (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision)) - return -EINVAL; - if (get_user(val, user_arg)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - as->usbin.dma.subdivision = val; - if (file->f_mode & FMODE_WRITE) - as->usbout.dma.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? - as->usbin.dma.srate : as->usbout.dma.srate, - user_arg); - - case SOUND_PCM_READ_CHANNELS: - val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; - return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg); - - case SOUND_PCM_READ_BITS: - val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format; - return put_user(AFMT_IS16BIT(val2) ? 16 : 8, user_arg); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - } - dprintk((KERN_DEBUG "usbaudio: usb_audio_ioctl - no command found\n")); - return -ENOIOCTLCMD; -} - -static int usb_audio_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - struct usb_audiodev *as; - struct usb_audio_state *s; - - for (;;) { - down(&open_sem); - list_for_each_entry(s, &audiodevs, audiodev) { - list_for_each_entry(as, &s->audiolist, list) { - if (!((as->dev_audio ^ minor) & ~0xf)) - goto device_found; - } - } - up(&open_sem); - return -ENODEV; - - device_found: - if (!s->usbdev) { - up(&open_sem); - return -EIO; - } - /* wait for device to become free */ - if (!(as->open_mode & file->f_mode)) - break; - if (file->f_flags & O_NONBLOCK) { - up(&open_sem); - return -EBUSY; - } - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&open_wait, &wait); - up(&open_sem); - schedule(); - __set_current_state(TASK_RUNNING); - remove_wait_queue(&open_wait, &wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - if (file->f_mode & FMODE_READ) - as->usbin.dma.ossfragshift = as->usbin.dma.ossmaxfrags = as->usbin.dma.subdivision = 0; - if (file->f_mode & FMODE_WRITE) - as->usbout.dma.ossfragshift = as->usbout.dma.ossmaxfrags = as->usbout.dma.subdivision = 0; - if (set_format(as, file->f_mode, ((minor & 0xf) == SND_DEV_DSP16) ? AFMT_S16_LE : AFMT_U8 /* AFMT_ULAW */, 8000)) { - up(&open_sem); - return -EIO; - } - file->private_data = as; - as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - s->count++; - up(&open_sem); - return nonseekable_open(inode, file); -} - -static int usb_audio_release(struct inode *inode, struct file *file) -{ - struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; - struct usb_audio_state *s; - struct usb_device *dev; - - lock_kernel(); - s = as->state; - dev = s->usbdev; - if (file->f_mode & FMODE_WRITE) - drain_out(as, file->f_flags & O_NONBLOCK); - down(&open_sem); - if (file->f_mode & FMODE_WRITE) { - usbout_stop(as); - if (dev && as->usbout.interface >= 0) - usb_set_interface(dev, as->usbout.interface, 0); - dmabuf_release(&as->usbout.dma); - usbout_release(as); - } - if (file->f_mode & FMODE_READ) { - usbin_stop(as); - if (dev && as->usbin.interface >= 0) - usb_set_interface(dev, as->usbin.interface, 0); - dmabuf_release(&as->usbin.dma); - usbin_release(as); - } - as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - release(s); - wake_up(&open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations usb_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = usb_audio_read, - .write = usb_audio_write, - .poll = usb_audio_poll, - .ioctl = usb_audio_ioctl, - .mmap = usb_audio_mmap, - .open = usb_audio_open, - .release = usb_audio_release, -}; - -/* --------------------------------------------------------------------- */ - -static int usb_audio_probe(struct usb_interface *iface, - const struct usb_device_id *id); -static void usb_audio_disconnect(struct usb_interface *iface); - -static struct usb_device_id usb_audio_ids [] = { - { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), - .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = 1}, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_audio_ids); - -static struct usb_driver usb_audio_driver = { - .name = "audio", - .probe = usb_audio_probe, - .disconnect = usb_audio_disconnect, - .id_table = usb_audio_ids, -}; - -static void *find_descriptor(void *descstart, unsigned int desclen, void *after, - u8 dtype, int iface, int altsetting) -{ - u8 *p, *end, *next; - int ifc = -1, as = -1; - - p = descstart; - end = p + desclen; - for (; p < end;) { - if (p[0] < 2) - return NULL; - next = p + p[0]; - if (next > end) - return NULL; - if (p[1] == USB_DT_INTERFACE) { - /* minimum length of interface descriptor */ - if (p[0] < 9) - return NULL; - ifc = p[2]; - as = p[3]; - } - if (p[1] == dtype && (!after || (void *)p > after) && - (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) { - return p; - } - p = next; - } - return NULL; -} - -static void *find_csinterface_descriptor(void *descstart, unsigned int desclen, void *after, u8 dsubtype, int iface, int altsetting) -{ - unsigned char *p; - - p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, altsetting); - while (p) { - if (p[0] >= 3 && p[2] == dsubtype) - return p; - p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, altsetting); - } - return NULL; -} - -static void *find_audiocontrol_unit(void *descstart, unsigned int desclen, void *after, u8 unit, int iface) -{ - unsigned char *p; - - p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, -1); - while (p) { - if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit) - return p; - p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, -1); - } - return NULL; -} - -static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, int asifin, int asifout) -{ - struct usb_device *dev = s->usbdev; - struct usb_audiodev *as; - struct usb_host_interface *alts; - struct usb_interface *iface; - struct audioformat *fp; - unsigned char *fmt, *csep; - unsigned int i, j, k, format, idx; - - if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL))) - return; - memset(as, 0, sizeof(struct usb_audiodev)); - init_waitqueue_head(&as->usbin.dma.wait); - init_waitqueue_head(&as->usbout.dma.wait); - spin_lock_init(&as->lock); - as->usbin.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL); - as->usbin.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL); - as->usbin.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL); - as->usbin.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL); - as->usbout.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL); - as->usbout.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL); - as->usbout.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL); - as->usbout.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL); - if ((!as->usbin.durb[0].urb) || - (!as->usbin.durb[1].urb) || - (!as->usbin.surb[0].urb) || - (!as->usbin.surb[1].urb) || - (!as->usbout.durb[0].urb) || - (!as->usbout.durb[1].urb) || - (!as->usbout.surb[0].urb) || - (!as->usbout.surb[1].urb)) { - usb_free_urb(as->usbin.durb[0].urb); - usb_free_urb(as->usbin.durb[1].urb); - usb_free_urb(as->usbin.surb[0].urb); - usb_free_urb(as->usbin.surb[1].urb); - usb_free_urb(as->usbout.durb[0].urb); - usb_free_urb(as->usbout.durb[1].urb); - usb_free_urb(as->usbout.surb[0].urb); - usb_free_urb(as->usbout.surb[1].urb); - kfree(as); - return; - } - as->state = s; - as->usbin.interface = asifin; - as->usbout.interface = asifout; - /* search for input formats */ - if (asifin >= 0) { - as->usbin.flags = FLG_CONNECTED; - iface = usb_ifnum_to_if(dev, asifin); - for (idx = 0; idx < iface->num_altsetting; idx++) { - alts = &iface->altsetting[idx]; - i = alts->desc.bAlternateSetting; - if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2) - continue; - if (alts->desc.bNumEndpoints < 1) { - if (i != 0) { /* altsetting 0 has no endpoints (Section B.3.4.1) */ - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", - dev->devnum, asifin, i); - } - continue; - } - if ((alts->endpoint[0].desc.bmAttributes & 0x03) != 0x01 || - !(alts->endpoint[0].desc.bEndpointAddress & 0x80)) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous in\n", - dev->devnum, asifin, i); - continue; - } - fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifin, i); - if (!fmt) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", - dev->devnum, asifin, i); - continue; - } - if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", - dev->devnum, asifin, i); - continue; - } - format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8); - fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i); - if (!fmt) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", - dev->devnum, asifin, i); - continue; - } - if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", - dev->devnum, asifin, i); - continue; - } - if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", - dev->devnum, asifin, i, fmt[4], fmt[5]); - continue; - } - csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifin, i); - if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", - dev->devnum, asifin, i); - continue; - } - if (as->numfmtin >= MAXFORMATS) - continue; - fp = &as->fmtin[as->numfmtin++]; - if (fmt[5] == 2) - format &= (AFMT_U16_LE | AFMT_S16_LE); - else - format &= (AFMT_U8 | AFMT_S8); - if (fmt[4] == 2) - format |= AFMT_STEREO; - fp->format = format; - fp->altsetting = i; - fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16); - printk(KERN_INFO "usbaudio: valid input sample rate %u\n", fp->sratelo); - for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) { - k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16); - printk(KERN_INFO "usbaudio: valid input sample rate %u\n", k); - if (k > fp->sratehi) - fp->sratehi = k; - if (k < fp->sratelo) - fp->sratelo = k; - } - fp->attributes = csep[3]; - printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", - dev->devnum, asifin, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes); - } - } - /* search for output formats */ - if (asifout >= 0) { - as->usbout.flags = FLG_CONNECTED; - iface = usb_ifnum_to_if(dev, asifout); - for (idx = 0; idx < iface->num_altsetting; idx++) { - alts = &iface->altsetting[idx]; - i = alts->desc.bAlternateSetting; - if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2) - continue; - if (alts->desc.bNumEndpoints < 1) { - /* altsetting 0 should never have iso EPs */ - if (i != 0) - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", - dev->devnum, asifout, i); - continue; - } - if ((alts->endpoint[0].desc.bmAttributes & 0x03) != 0x01 || - (alts->endpoint[0].desc.bEndpointAddress & 0x80)) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous out\n", - dev->devnum, asifout, i); - continue; - } - /* See USB audio formats manual, section 2 */ - fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifout, i); - if (!fmt) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", - dev->devnum, asifout, i); - continue; - } - if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", - dev->devnum, asifout, i); - continue; - } - format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8); - /* Dallas DS4201 workaround */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && - le16_to_cpu(dev->descriptor.idProduct) == 0x4201) - format = (AFMT_S16_LE | AFMT_S8); - fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifout, i); - if (!fmt) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", - dev->devnum, asifout, i); - continue; - } - if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", - dev->devnum, asifout, i); - continue; - } - if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", - dev->devnum, asifout, i, fmt[4], fmt[5]); - continue; - } - csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifout, i); - if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) { - printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", - dev->devnum, asifout, i); - continue; - } - if (as->numfmtout >= MAXFORMATS) - continue; - fp = &as->fmtout[as->numfmtout++]; - if (fmt[5] == 2) - format &= (AFMT_U16_LE | AFMT_S16_LE); - else - format &= (AFMT_U8 | AFMT_S8); - if (fmt[4] == 2) - format |= AFMT_STEREO; - fp->format = format; - fp->altsetting = i; - fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16); - printk(KERN_INFO "usbaudio: valid output sample rate %u\n", fp->sratelo); - for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) { - k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16); - printk(KERN_INFO "usbaudio: valid output sample rate %u\n", k); - if (k > fp->sratehi) - fp->sratehi = k; - if (k < fp->sratelo) - fp->sratelo = k; - } - fp->attributes = csep[3]; - printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", - dev->devnum, asifout, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes); - } - } - if (as->numfmtin == 0 && as->numfmtout == 0) { - usb_free_urb(as->usbin.durb[0].urb); - usb_free_urb(as->usbin.durb[1].urb); - usb_free_urb(as->usbin.surb[0].urb); - usb_free_urb(as->usbin.surb[1].urb); - usb_free_urb(as->usbout.durb[0].urb); - usb_free_urb(as->usbout.durb[1].urb); - usb_free_urb(as->usbout.surb[0].urb); - usb_free_urb(as->usbout.surb[1].urb); - kfree(as); - return; - } - if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) { - printk(KERN_ERR "usbaudio: cannot register dsp\n"); - usb_free_urb(as->usbin.durb[0].urb); - usb_free_urb(as->usbin.durb[1].urb); - usb_free_urb(as->usbin.surb[0].urb); - usb_free_urb(as->usbin.surb[1].urb); - usb_free_urb(as->usbout.durb[0].urb); - usb_free_urb(as->usbout.durb[1].urb); - usb_free_urb(as->usbout.surb[0].urb); - usb_free_urb(as->usbout.surb[1].urb); - kfree(as); - return; - } - printk(KERN_INFO "usbaudio: registered dsp 14,%d\n", as->dev_audio); - /* everything successful */ - list_add_tail(&as->list, &s->audiolist); -} - -struct consmixstate { - struct usb_audio_state *s; - unsigned char *buffer; - unsigned int buflen; - unsigned int ctrlif; - struct mixerchannel mixch[SOUND_MIXER_NRDEVICES]; - unsigned int nrmixch; - unsigned int mixchmask; - unsigned long unitbitmap[32/sizeof(unsigned long)]; - /* return values */ - unsigned int nrchannels; - unsigned int termtype; - unsigned int chconfig; -}; - -static struct mixerchannel *getmixchannel(struct consmixstate *state, unsigned int nr) -{ - struct mixerchannel *c; - - if (nr >= SOUND_MIXER_NRDEVICES) { - printk(KERN_ERR "usbaudio: invalid OSS mixer channel %u\n", nr); - return NULL; - } - if (!(state->mixchmask & (1 << nr))) { - printk(KERN_WARNING "usbaudio: OSS mixer channel %u already in use\n", nr); - return NULL; - } - c = &state->mixch[state->nrmixch++]; - c->osschannel = nr; - state->mixchmask &= ~(1 << nr); - return c; -} - -static unsigned int getvolchannel(struct consmixstate *state) -{ - unsigned int u; - - if ((state->termtype & 0xff00) == 0x0000 && (state->mixchmask & SOUND_MASK_VOLUME)) - return SOUND_MIXER_VOLUME; - if ((state->termtype & 0xff00) == 0x0100) { - if (state->mixchmask & SOUND_MASK_PCM) - return SOUND_MIXER_PCM; - if (state->mixchmask & SOUND_MASK_ALTPCM) - return SOUND_MIXER_ALTPCM; - } - if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC)) - return SOUND_MIXER_MIC; - if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER)) - return SOUND_MIXER_SPEAKER; - if ((state->termtype & 0xff00) == 0x0500) { - if (state->mixchmask & SOUND_MASK_PHONEIN) - return SOUND_MIXER_PHONEIN; - if (state->mixchmask & SOUND_MASK_PHONEOUT) - return SOUND_MIXER_PHONEOUT; - } - if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO)) - return SOUND_MIXER_RADIO; - if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO)) - return SOUND_MIXER_VIDEO; - u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 | - SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3)); - return u-1; -} - -static void prepmixch(struct consmixstate *state) -{ - struct usb_device *dev = state->s->usbdev; - struct mixerchannel *ch; - unsigned char *buf; - __s16 v1; - unsigned int v2, v3; - - if (!state->nrmixch || state->nrmixch > SOUND_MIXER_NRDEVICES) - return; - buf = kmalloc(sizeof(*buf) * 2, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "prepmixch: out of memory\n") ; - return; - } - - ch = &state->mixch[state->nrmixch-1]; - switch (ch->selector) { - case 0: /* mixer unit request */ - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0) - goto err; - ch->minval = buf[0] | (buf[1] << 8); - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0) - goto err; - ch->maxval = buf[0] | (buf[1] << 8); - v2 = ch->maxval - ch->minval; - if (!v2) - v2 = 1; - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0) - goto err; - v1 = buf[0] | (buf[1] << 8); - v3 = v1 - ch->minval; - v3 = 100 * v3 / v2; - if (v3 > 100) - v3 = 100; - ch->value = v3; - if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) { - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)), - state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0) - goto err; - v1 = buf[0] | (buf[1] << 8); - v3 = v1 - ch->minval; - v3 = 100 * v3 / v2; - if (v3 > 100) - v3 = 100; - } - ch->value |= v3 << 8; - break; - - /* various feature unit controls */ - case VOLUME_CONTROL: - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0) - goto err; - ch->minval = buf[0] | (buf[1] << 8); - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0) - goto err; - ch->maxval = buf[0] | (buf[1] << 8); - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0) - goto err; - v1 = buf[0] | (buf[1] << 8); - v2 = ch->maxval - ch->minval; - v3 = v1 - ch->minval; - if (!v2) - v2 = 1; - v3 = 100 * v3 / v2; - if (v3 > 100) - v3 = 100; - ch->value = v3; - if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) { - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0) - goto err; - v1 = buf[0] | (buf[1] << 8); - v3 = v1 - ch->minval; - v3 = 100 * v3 / v2; - if (v3 > 100) - v3 = 100; - } - ch->value |= v3 << 8; - break; - - case BASS_CONTROL: - case MID_CONTROL: - case TREBLE_CONTROL: - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0) - goto err; - ch->minval = buf[0] << 8; - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0) - goto err; - ch->maxval = buf[0] << 8; - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0) - goto err; - v1 = buf[0] << 8; - v2 = ch->maxval - ch->minval; - v3 = v1 - ch->minval; - if (!v2) - v2 = 1; - v3 = 100 * v3 / v2; - if (v3 > 100) - v3 = 100; - ch->value = v3; - if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) { - if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0) - goto err; - v1 = buf[0] << 8; - v3 = v1 - ch->minval; - v3 = 100 * v3 / v2; - if (v3 > 100) - v3 = 100; - } - ch->value |= v3 << 8; - break; - - default: - goto err; - } - - freebuf: - kfree(buf); - return; - err: - printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", - dev->devnum, state->ctrlif, ch->unitid, ch->chnum, ch->selector); - if (state->nrmixch) - state->nrmixch--; - goto freebuf; -} - - -static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid); - -static inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch) -{ - unsigned int idx; - - idx = inidx*numoch; - if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7)))) - return 0; - if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))) - return 1; - idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT); - if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7)))) - return 0; - return 1; -} - -static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer) -{ - unsigned int nroutch = mixer[5+mixer[4]]; - unsigned int chidx[SOUND_MIXER_NRDEVICES+1]; - unsigned int termt[SOUND_MIXER_NRDEVICES]; - unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0; - unsigned char *bmap = &mixer[9+mixer[4]]; - unsigned int bmapsize; - struct mixerchannel *ch; - unsigned int i; - - if (!mixer[4]) { - printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor\n", mixer[3]); - return; - } - if (mixer[4] > SOUND_MIXER_NRDEVICES) { - printk(KERN_ERR "usbaudio: mixer unit %u: too many input pins\n", mixer[3]); - return; - } - chidx[0] = 0; - for (i = 0; i < mixer[4]; i++) { - usb_audio_recurseunit(state, mixer[5+i]); - chidx[i+1] = chidx[i] + state->nrchannels; - termt[i] = state->termtype; - } - state->termtype = 0; - state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8); - bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3; - bmap += bmapsize - 1; - if (mixer[0] < 10+mixer[4]+bmapsize) { - printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]); - return; - } - for (i = 0; i < mixer[4]; i++) { - state->termtype = termt[i]; - if (chidx[i+1]-chidx[i] >= 2) { - flg |= MIXFLG_STEREOIN; - if (checkmixbmap(bmap, flg, chidx[i], nroutch)) { - ch = getmixchannel(state, getvolchannel(state)); - if (ch) { - ch->unitid = mixer[3]; - ch->selector = 0; - ch->chnum = chidx[i]+1; - ch->flags = flg; - prepmixch(state); - } - continue; - } - } - flg &= ~MIXFLG_STEREOIN; - if (checkmixbmap(bmap, flg, chidx[i], nroutch)) { - ch = getmixchannel(state, getvolchannel(state)); - if (ch) { - ch->unitid = mixer[3]; - ch->selector = 0; - ch->chnum = chidx[i]+1; - ch->flags = flg; - prepmixch(state); - } - } - } - state->termtype = 0; -} - -static struct mixerchannel *slctsrc_findunit(struct consmixstate *state, __u8 unitid) -{ - unsigned int i; - - for (i = 0; i < state->nrmixch; i++) - if (state->mixch[i].unitid == unitid) - return &state->mixch[i]; - return NULL; -} - -static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector) -{ - unsigned int chnum, i, mixch; - struct mixerchannel *mch; - - if (!selector[4]) { - printk(KERN_ERR "usbaudio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]); - return; - } - mixch = state->nrmixch; - usb_audio_recurseunit(state, selector[5]); - if (state->nrmixch != mixch) { - mch = &state->mixch[state->nrmixch-1]; - mch->slctunitid = selector[3] | (1 << 8); - } else if ((mch = slctsrc_findunit(state, selector[5]))) { - mch->slctunitid = selector[3] | (1 << 8); - } else { - printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]); - } - chnum = state->nrchannels; - for (i = 1; i < selector[4]; i++) { - mixch = state->nrmixch; - usb_audio_recurseunit(state, selector[5+i]); - if (chnum != state->nrchannels) { - printk(KERN_ERR "usbaudio: selector unit %u: input pins with varying channel numbers\n", selector[3]); - state->termtype = 0; - state->chconfig = 0; - state->nrchannels = 0; - return; - } - if (state->nrmixch != mixch) { - mch = &state->mixch[state->nrmixch-1]; - mch->slctunitid = selector[3] | ((i + 1) << 8); - } else if ((mch = slctsrc_findunit(state, selector[5+i]))) { - mch->slctunitid = selector[3] | ((i + 1) << 8); - } else { - printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1); - } - } - state->termtype = 0; - state->chconfig = 0; -} - -/* in the future we might try to handle 3D etc. effect units */ - -static void usb_audio_processingunit(struct consmixstate *state, unsigned char *proc) -{ - unsigned int i; - - for (i = 0; i < proc[6]; i++) - usb_audio_recurseunit(state, proc[7+i]); - state->nrchannels = proc[7+proc[6]]; - state->termtype = 0; - state->chconfig = proc[8+proc[6]] | (proc[9+proc[6]] << 8); -} - - -/* See Audio Class Spec, section 4.3.2.5 */ -static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr) -{ - struct mixerchannel *ch; - unsigned short chftr, mchftr; -#if 0 - struct usb_device *dev = state->s->usbdev; - unsigned char data[1]; -#endif - unsigned char nr_logical_channels, i; - - usb_audio_recurseunit(state, ftr[4]); - - if (ftr[5] == 0 ) { - printk(KERN_ERR "usbaudio: wrong controls size in feature unit %u\n",ftr[3]); - return; - } - - if (state->nrchannels == 0) { - printk(KERN_ERR "usbaudio: feature unit %u source has no channels\n", ftr[3]); - return; - } - if (state->nrchannels > 2) - printk(KERN_WARNING "usbaudio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]); - - nr_logical_channels=(ftr[0]-7)/ftr[5]-1; - - if (nr_logical_channels != state->nrchannels) { - printk(KERN_WARNING "usbaudio: warning: found %d of %d logical channels.\n", state->nrchannels,nr_logical_channels); - - if (state->nrchannels == 1 && nr_logical_channels==0) { - printk(KERN_INFO "usbaudio: assuming the channel found is the master channel (got a Philips camera?). Should be fine.\n"); - } else if (state->nrchannels == 1 && nr_logical_channels==2) { - printk(KERN_INFO "usbaudio: assuming that a stereo channel connected directly to a mixer is missing in search (got Labtec headset?). Should be fine.\n"); - state->nrchannels=nr_logical_channels; - } else { - printk(KERN_WARNING "usbaudio: no idea what's going on..., contact linux-usb-devel@lists.sourceforge.net\n"); - } - } - - /* There is always a master channel */ - mchftr = ftr[6]; - /* Binary AND over logical channels if they exist */ - if (nr_logical_channels) { - chftr = ftr[6+ftr[5]]; - for (i = 2; i <= nr_logical_channels; i++) - chftr &= ftr[6+i*ftr[5]]; - } else { - chftr = 0; - } - - /* volume control */ - if (chftr & 2) { - ch = getmixchannel(state, getvolchannel(state)); - if (ch) { - ch->unitid = ftr[3]; - ch->selector = VOLUME_CONTROL; - ch->chnum = 1; - ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0; - prepmixch(state); - } - } else if (mchftr & 2) { - ch = getmixchannel(state, getvolchannel(state)); - if (ch) { - ch->unitid = ftr[3]; - ch->selector = VOLUME_CONTROL; - ch->chnum = 0; - ch->flags = 0; - prepmixch(state); - } - } - /* bass control */ - if (chftr & 4) { - ch = getmixchannel(state, SOUND_MIXER_BASS); - if (ch) { - ch->unitid = ftr[3]; - ch->selector = BASS_CONTROL; - ch->chnum = 1; - ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0; - prepmixch(state); - } - } else if (mchftr & 4) { - ch = getmixchannel(state, SOUND_MIXER_BASS); - if (ch) { - ch->unitid = ftr[3]; - ch->selector = BASS_CONTROL; - ch->chnum = 0; - ch->flags = 0; - prepmixch(state); - } - } - /* treble control */ - if (chftr & 16) { - ch = getmixchannel(state, SOUND_MIXER_TREBLE); - if (ch) { - ch->unitid = ftr[3]; - ch->selector = TREBLE_CONTROL; - ch->chnum = 1; - ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0; - prepmixch(state); - } - } else if (mchftr & 16) { - ch = getmixchannel(state, SOUND_MIXER_TREBLE); - if (ch) { - ch->unitid = ftr[3]; - ch->selector = TREBLE_CONTROL; - ch->chnum = 0; - ch->flags = 0; - prepmixch(state); - } - } -#if 0 - /* if there are mute controls, unmute them */ - /* does not seem to be necessary, and the Dallas chip does not seem to support the "all" channel (255) */ - if ((chftr & 1) || (mchftr & 1)) { - printk(KERN_DEBUG "usbaudio: unmuting feature unit %u interface %u\n", ftr[3], state->ctrlif); - data[0] = 0; - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, 1000) < 0) - printk(KERN_WARNING "usbaudio: failure to unmute feature unit %u interface %u\n", ftr[3], state->ctrlif); - } -#endif -} - -static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid) -{ - unsigned char *p1; - unsigned int i, j; - - if (test_and_set_bit(unitid, state->unitbitmap)) { - printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid); - return; - } - p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif); - if (!p1) { - printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid); - return; - } - state->nrchannels = 0; - state->termtype = 0; - state->chconfig = 0; - switch (p1[2]) { - case INPUT_TERMINAL: - if (p1[0] < 12) { - printk(KERN_ERR "usbaudio: unit %u: invalid INPUT_TERMINAL descriptor\n", unitid); - return; - } - state->nrchannels = p1[7]; - state->termtype = p1[4] | (p1[5] << 8); - state->chconfig = p1[8] | (p1[9] << 8); - return; - - case MIXER_UNIT: - if (p1[0] < 10 || p1[0] < 10+p1[4]) { - printk(KERN_ERR "usbaudio: unit %u: invalid MIXER_UNIT descriptor\n", unitid); - return; - } - usb_audio_mixerunit(state, p1); - return; - - case SELECTOR_UNIT: - if (p1[0] < 6 || p1[0] < 6+p1[4]) { - printk(KERN_ERR "usbaudio: unit %u: invalid SELECTOR_UNIT descriptor\n", unitid); - return; - } - usb_audio_selectorunit(state, p1); - return; - - case FEATURE_UNIT: /* See USB Audio Class Spec 4.3.2.5 */ - if (p1[0] < 7 || p1[0] < 7+p1[5]) { - printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid); - return; - } - usb_audio_featureunit(state, p1); - return; - - case PROCESSING_UNIT: - if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) { - printk(KERN_ERR "usbaudio: unit %u: invalid PROCESSING_UNIT descriptor\n", unitid); - return; - } - usb_audio_processingunit(state, p1); - return; - - case EXTENSION_UNIT: - if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) { - printk(KERN_ERR "usbaudio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid); - return; - } - for (j = i = 0; i < p1[6]; i++) { - usb_audio_recurseunit(state, p1[7+i]); - if (!i) - j = state->termtype; - else if (j != state->termtype) - j = 0; - } - state->nrchannels = p1[7+p1[6]]; - state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8); - state->termtype = j; - return; - - default: - printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return; - } -} - -static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif, unsigned char *oterm) -{ - struct usb_mixerdev *ms; - struct consmixstate state; - - memset(&state, 0, sizeof(state)); - state.s = s; - state.nrmixch = 0; - state.mixchmask = ~0; - state.buffer = buffer; - state.buflen = buflen; - state.ctrlif = ctrlif; - set_bit(oterm[3], state.unitbitmap); /* mark terminal ID as visited */ - printk(KERN_DEBUG "usbaudio: constructing mixer for Terminal %u type 0x%04x\n", - oterm[3], oterm[4] | (oterm[5] << 8)); - usb_audio_recurseunit(&state, oterm[7]); - if (!state.nrmixch) { - printk(KERN_INFO "usbaudio: no mixer controls found for Terminal %u\n", oterm[3]); - return; - } - if (!(ms = kmalloc(sizeof(struct usb_mixerdev)+state.nrmixch*sizeof(struct mixerchannel), GFP_KERNEL))) - return; - memset(ms, 0, sizeof(struct usb_mixerdev)); - memcpy(&ms->ch, &state.mixch, state.nrmixch*sizeof(struct mixerchannel)); - ms->state = s; - ms->iface = ctrlif; - ms->numch = state.nrmixch; - if ((ms->dev_mixer = register_sound_mixer(&usb_mixer_fops, -1)) < 0) { - printk(KERN_ERR "usbaudio: cannot register mixer\n"); - kfree(ms); - return; - } - printk(KERN_INFO "usbaudio: registered mixer 14,%d\n", ms->dev_mixer); - list_add_tail(&ms->list, &s->mixerlist); -} - -/* arbitrary limit, we won't check more interfaces than this */ -#define USB_MAXINTERFACES 32 - -static struct usb_audio_state *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif) -{ - struct usb_audio_state *s; - struct usb_interface *iface; - struct usb_host_interface *alt; - unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES]; - unsigned char *p1; - unsigned int i, j, k, numifin = 0, numifout = 0; - - if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL))) - return NULL; - memset(s, 0, sizeof(struct usb_audio_state)); - INIT_LIST_HEAD(&s->audiolist); - INIT_LIST_HEAD(&s->mixerlist); - s->usbdev = dev; - s->count = 1; - - /* find audiocontrol interface */ - if (!(p1 = find_csinterface_descriptor(buffer, buflen, NULL, HEADER, ctrlif, -1))) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u no HEADER found\n", - dev->devnum, ctrlif); - goto ret; - } - if (p1[0] < 8 + p1[7]) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u HEADER error\n", - dev->devnum, ctrlif); - goto ret; - } - if (!p1[7]) - printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has no AudioStreaming and MidiStreaming interfaces\n", - dev->devnum, ctrlif); - for (i = 0; i < p1[7]; i++) { - j = p1[8+i]; - iface = usb_ifnum_to_if(dev, j); - if (!iface) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u does not exist\n", - dev->devnum, ctrlif, j); - continue; - } - if (iface->num_altsetting == 1) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif); - continue; - } - alt = usb_altnum_to_altsetting(iface, 0); - if (!alt) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 0\n", - dev->devnum, ctrlif, j); - continue; - } - if (alt->desc.bInterfaceClass != USB_CLASS_AUDIO) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n", - dev->devnum, ctrlif, j); - continue; - } - if (alt->desc.bInterfaceSubClass == 3) { - printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n", - dev->devnum, ctrlif, j); - continue; - } - if (alt->desc.bInterfaceSubClass != 2) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n", - dev->devnum, ctrlif, j); - continue; - } - if (alt->desc.bNumEndpoints > 0) { - /* Check all endpoints; should they all have a bandwidth of 0 ? */ - for (k = 0; k < alt->desc.bNumEndpoints; k++) { - if (le16_to_cpu(alt->endpoint[k].desc.wMaxPacketSize) > 0) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k); - break; - } - } - if (k < alt->desc.bNumEndpoints) - continue; - } - - alt = usb_altnum_to_altsetting(iface, 1); - if (!alt) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 1\n", - dev->devnum, ctrlif, j); - continue; - } - if (alt->desc.bNumEndpoints < 1) { - printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n", - dev->devnum, ctrlif, j); - continue; - } - /* note: this requires the data endpoint to be ep0 and the optional sync - ep to be ep1, which seems to be the case */ - if (alt->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) { - if (numifin < USB_MAXINTERFACES) { - ifin[numifin++] = j; - usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1); - } - } else { - if (numifout < USB_MAXINTERFACES) { - ifout[numifout++] = j; - usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1); - } - } - } - printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n", - dev->devnum, ctrlif, numifin, numifout); - for (i = 0; i < numifin && i < numifout; i++) - usb_audio_parsestreaming(s, buffer, buflen, ifin[i], ifout[i]); - for (j = i; j < numifin; j++) - usb_audio_parsestreaming(s, buffer, buflen, ifin[i], -1); - for (j = i; j < numifout; j++) - usb_audio_parsestreaming(s, buffer, buflen, -1, ifout[i]); - /* now walk through all OUTPUT_TERMINAL descriptors to search for mixers */ - p1 = find_csinterface_descriptor(buffer, buflen, NULL, OUTPUT_TERMINAL, ctrlif, -1); - while (p1) { - if (p1[0] >= 9) - usb_audio_constructmixer(s, buffer, buflen, ctrlif, p1); - p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1); - } - -ret: - if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) { - kfree(s); - return NULL; - } - /* everything successful */ - down(&open_sem); - list_add_tail(&s->audiodev, &audiodevs); - up(&open_sem); - printk(KERN_DEBUG "usb_audio_parsecontrol: usb_audio_state at %p\n", s); - return s; -} - -/* we only care for the currently active configuration */ - -static int usb_audio_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev (intf); - struct usb_audio_state *s; - unsigned char *buffer; - unsigned int buflen; - -#if 0 - printk(KERN_DEBUG "usbaudio: Probing if %i: IC %x, ISC %x\n", ifnum, - config->interface[ifnum].altsetting[0].desc.bInterfaceClass, - config->interface[ifnum].altsetting[0].desc.bInterfaceSubClass); -#endif - - /* - * audiocontrol interface found - * find which configuration number is active - */ - buffer = dev->rawdescriptors[dev->actconfig - dev->config]; - buflen = le16_to_cpu(dev->actconfig->desc.wTotalLength); - s = usb_audio_parsecontrol(dev, buffer, buflen, intf->altsetting->desc.bInterfaceNumber); - if (s) { - usb_set_intfdata (intf, s); - return 0; - } - return -ENODEV; -} - - -/* a revoke facility would make things simpler */ - -static void usb_audio_disconnect(struct usb_interface *intf) -{ - struct usb_audio_state *s = usb_get_intfdata (intf); - struct usb_audiodev *as; - struct usb_mixerdev *ms; - - if (!s) - return; - - /* we get called with -1 for every audiostreaming interface registered */ - if (s == (struct usb_audio_state *)-1) { - dprintk((KERN_DEBUG "usbaudio: note, usb_audio_disconnect called with -1\n")); - return; - } - if (!s->usbdev) { - dprintk((KERN_DEBUG "usbaudio: error, usb_audio_disconnect already called for %p!\n", s)); - return; - } - down(&open_sem); - list_del_init(&s->audiodev); - s->usbdev = NULL; - usb_set_intfdata (intf, NULL); - - /* deregister all audio and mixer devices, so no new processes can open this device */ - list_for_each_entry(as, &s->audiolist, list) { - usbin_disc(as); - usbout_disc(as); - wake_up(&as->usbin.dma.wait); - wake_up(&as->usbout.dma.wait); - if (as->dev_audio >= 0) { - unregister_sound_dsp(as->dev_audio); - printk(KERN_INFO "usbaudio: unregister dsp 14,%d\n", as->dev_audio); - } - as->dev_audio = -1; - } - list_for_each_entry(ms, &s->mixerlist, list) { - if (ms->dev_mixer >= 0) { - unregister_sound_mixer(ms->dev_mixer); - printk(KERN_INFO "usbaudio: unregister mixer 14,%d\n", ms->dev_mixer); - } - ms->dev_mixer = -1; - } - release(s); - wake_up(&open_wait); -} - -static int __init usb_audio_init(void) -{ - int result = usb_register(&usb_audio_driver); - if (result == 0) - info(DRIVER_VERSION ":" DRIVER_DESC); - return result; -} - - -static void __exit usb_audio_cleanup(void) -{ - usb_deregister(&usb_audio_driver); -} - -module_init(usb_audio_init); -module_exit(usb_audio_cleanup); - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/class/audio.h b/drivers/usb/class/audio.h deleted file mode 100644 index 45916eb12103..000000000000 --- a/drivers/usb/class/audio.h +++ /dev/null @@ -1,110 +0,0 @@ -#define CS_AUDIO_UNDEFINED 0x20 -#define CS_AUDIO_DEVICE 0x21 -#define CS_AUDIO_CONFIGURATION 0x22 -#define CS_AUDIO_STRING 0x23 -#define CS_AUDIO_INTERFACE 0x24 -#define CS_AUDIO_ENDPOINT 0x25 - -#define HEADER 0x01 -#define INPUT_TERMINAL 0x02 -#define OUTPUT_TERMINAL 0x03 -#define MIXER_UNIT 0x04 -#define SELECTOR_UNIT 0x05 -#define FEATURE_UNIT 0x06 -#define PROCESSING_UNIT 0x07 -#define EXTENSION_UNIT 0x08 - -#define AS_GENERAL 0x01 -#define FORMAT_TYPE 0x02 -#define FORMAT_SPECIFIC 0x03 - -#define EP_GENERAL 0x01 - -#define MAX_CHAN 9 -#define MAX_FREQ 16 -#define MAX_IFACE 8 -#define MAX_FORMAT 8 -#define MAX_ALT 32 /* Sorry, we need quite a few for the Philips webcams */ - -struct usb_audio_terminal -{ - u8 flags; - u8 assoc; - u16 type; /* Mic etc */ - u8 channels; - u8 source; - u16 chancfg; -}; - -struct usb_audio_format -{ - u8 type; - u8 channels; - u8 num_freq; - u8 sfz; - u8 bits; - u16 freq[MAX_FREQ]; -}; - -struct usb_audio_interface -{ - u8 terminal; - u8 delay; - u16 num_formats; - u16 format_type; - u8 flags; - u8 idleconf; /* Idle config */ -#define AU_IFACE_FOUND 1 - struct usb_audio_format format[MAX_FORMAT]; -}; - -struct usb_audio_device -{ - struct list_head list; - u8 mixer; - u8 selector; - void *irq_handle; - u8 num_channels; - u8 num_dsp_iface; - u8 channel_map[MAX_CHAN]; - struct usb_audio_terminal terminal[MAX_CHAN]; - struct usb_audio_interface interface[MAX_IFACE][MAX_ALT]; -}; - - - -/* Audio Class specific Request Codes */ - -#define SET_CUR 0x01 -#define GET_CUR 0x81 -#define SET_MIN 0x02 -#define GET_MIN 0x82 -#define SET_MAX 0x03 -#define GET_MAX 0x83 -#define SET_RES 0x04 -#define GET_RES 0x84 -#define SET_MEM 0x05 -#define GET_MEM 0x85 -#define GET_STAT 0xff - -/* Terminal Control Selectors */ - -#define COPY_PROTECT_CONTROL 0x01 - -/* Feature Unit Control Selectors */ - -#define MUTE_CONTROL 0x01 -#define VOLUME_CONTROL 0x02 -#define BASS_CONTROL 0x03 -#define MID_CONTROL 0x04 -#define TREBLE_CONTROL 0x05 -#define GRAPHIC_EQUALIZER_CONTROL 0x06 -#define AUTOMATIC_GAIN_CONTROL 0x07 -#define DELAY_CONTROL 0x08 -#define BASS_BOOST_CONTROL 0x09 -#define LOUDNESS_CONTROL 0x0a - -/* Endpoint Control Selectors */ - -#define SAMPLING_FREQ_CONTROL 0x01 -#define PITCH_CONTROL 0x02 diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c deleted file mode 100644 index f13f004d311f..000000000000 --- a/drivers/usb/class/usb-midi.c +++ /dev/null @@ -1,2153 +0,0 @@ -/* - usb-midi.c -- USB-MIDI driver - - Copyright (C) 2001 - NAGANO Daisuke - - 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, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - This driver is based on: - - 'Universal Serial Bus Device Class Definition for MIDI Device' - - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c - - alsa/lowlevel/pci/cs64xx.c - - umidi.c for NetBSD - */ - -/* ------------------------------------------------------------------------- */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usb-midi.h" - -/* ------------------------------------------------------------------------- */ - -/* More verbose on syslog */ -#undef MIDI_DEBUG - -#define MIDI_IN_BUFSIZ 1024 - -#define HAVE_SUPPORT_USB_MIDI_CLASS - -#undef HAVE_SUPPORT_ALSA - -/* ------------------------------------------------------------------------- */ - -static int singlebyte = 0; -module_param(singlebyte, int, 0); -MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet"); - -static int maxdevices = 4; -module_param(maxdevices, int, 0); -MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device"); - -static int uvendor = -1; -module_param(uvendor, int, 0); -MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface"); - -static int uproduct = -1; -module_param(uproduct, int, 0); -MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface"); - -static int uinterface = -1; -module_param(uinterface, int, 0); -MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface"); - -static int ualt = -1; -module_param(ualt, int, 0); -MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface"); - -static int umin = -1; -module_param(umin, int, 0); -MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface"); - -static int umout = -1; -module_param(umout, int, 0); -MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface"); - -static int ucable = -1; -module_param(ucable, int, 0); -MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface"); - -/** Note -- the usb_string() returns only Latin-1 characters. - * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or - * unicode16LE-to-JIS routine is needed to wrap around usb_get_string(). - **/ -static unsigned short ulangid = 0x0409; /** 0x0411 for Japanese **/ -module_param(ulangid, ushort, 0); -MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices"); - -MODULE_AUTHOR("NAGANO Daisuke "); -MODULE_DESCRIPTION("USB-MIDI driver"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------------- */ - -/** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/ - -#define MS_DESCRIPTOR_UNDEFINED 0 -#define MS_HEADER 1 -#define MIDI_IN_JACK 2 -#define MIDI_OUT_JACK 3 -/* Spec reads: ELEMENT */ -#define ELEMENT_DESCRIPTOR 4 - -#define MS_HEADER_LENGTH 7 - -/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/ - -#define DESCRIPTOR_UNDEFINED 0 -/* Spec reads: MS_GENERAL */ -#define MS_GENERAL_ENDPOINT 1 - -/** MIDIStreaming MIDI IN and OUT Jack Types **/ - -#define JACK_TYPE_UNDEFINED 0 -/* Spec reads: EMBEDDED */ -#define EMBEDDED_JACK 1 -/* Spec reads: EXTERNAL */ -#define EXTERNAL_JACK 2 - - -/* structure summary - - usb_midi_state usb_device - | | - *| *| per ep - in_ep out_ep - | | - *| *| per cable - min mout - | | (cable to device pairing magic) - | | - usb_midi_dev dev_id (major,minor) == file->private_data - -*/ - -/* usb_midi_state: corresponds to a USB-MIDI module */ -struct usb_midi_state { - struct list_head mididev; - - struct usb_device *usbdev; - - struct list_head midiDevList; - struct list_head inEndpointList; - struct list_head outEndpointList; - - spinlock_t lock; - - unsigned int count; /* usage counter */ -}; - -/* midi_out_endpoint: corresponds to an output endpoint */ -struct midi_out_endpoint { - struct list_head list; - - struct usb_device *usbdev; - int endpoint; - spinlock_t lock; - wait_queue_head_t wait; - - unsigned char *buf; - int bufWrPtr; - int bufSize; - - struct urb *urb; -}; - -/* midi_in_endpoint: corresponds to an input endpoint */ -struct midi_in_endpoint { - struct list_head list; - - struct usb_device *usbdev; - int endpoint; - spinlock_t lock; - wait_queue_head_t wait; - - struct usb_mididev *cables[16]; // cables open for read - int readers; // number of cables open for read - - struct urb *urb; - unsigned char *recvBuf; - int recvBufSize; - int urbSubmitted; //FIXME: == readers > 0 -}; - -/* usb_mididev: corresponds to a logical device */ -struct usb_mididev { - struct list_head list; - - struct usb_midi_state *midi; - int dev_midi; - mode_t open_mode; - - struct { - struct midi_in_endpoint *ep; - int cableId; - -// as we are pushing data from usb_bulk_read to usb_midi_read, -// we need a larger, cyclic buffer here. - unsigned char buf[MIDI_IN_BUFSIZ]; - int bufRdPtr; - int bufWrPtr; - int bufRemains; - } min; - - struct { - struct midi_out_endpoint *ep; - int cableId; - - unsigned char buf[3]; - int bufPtr; - int bufRemains; - - int isInExclusive; - unsigned char lastEvent; - } mout; - - int singlebyte; -}; - -/** Map the high nybble of MIDI voice messages to number of Message bytes. - * High nyble ranges from 0x8 to 0xe - */ - -static int remains_80e0[] = { - 3, /** 0x8X Note Off **/ - 3, /** 0x9X Note On **/ - 3, /** 0xAX Poly-key pressure **/ - 3, /** 0xBX Control Change **/ - 2, /** 0xCX Program Change **/ - 2, /** 0xDX Channel pressure **/ - 3 /** 0xEX PitchBend Change **/ -}; - -/** Map the messages to a number of Message bytes. - * - **/ -static int remains_f0f6[] = { - 0, /** 0xF0 **/ - 2, /** 0XF1 **/ - 3, /** 0XF2 **/ - 2, /** 0XF3 **/ - 2, /** 0XF4 (Undefined by MIDI Spec, and subject to change) **/ - 2, /** 0XF5 (Undefined by MIDI Spec, and subject to change) **/ - 1 /** 0XF6 **/ -}; - -/** Map the messages to a CIN (Code Index Number). - * - **/ -static int cin_f0ff[] = { - 4, /** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */ - 2, /** 0xF1 **/ - 3, /** 0xF2 **/ - 2, /** 0xF3 **/ - 2, /** 0xF4 **/ - 2, /** 0xF5 **/ - 5, /** 0xF6 **/ - 5, /** 0xF7 End of System Exclusive Message (May be 6 or 7) **/ - 5, /** 0xF8 **/ - 5, /** 0xF9 **/ - 5, /** 0xFA **/ - 5, /** 0xFB **/ - 5, /** 0xFC **/ - 5, /** 0xFD **/ - 5, /** 0xFE **/ - 5 /** 0xFF **/ -}; - -/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0) - * to the number of bytes of valid MIDI data. - * - * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0. - * - **/ -static int cin_to_len[] = { - 0, 0, 2, 3, - 3, 1, 2, 3, - 3, 3, 3, 3, - 2, 2, 3, 1 -}; - - -/* ------------------------------------------------------------------------- */ - -static struct list_head mididevs = LIST_HEAD_INIT(mididevs); - -static DECLARE_MUTEX(open_sem); -static DECLARE_WAIT_QUEUE_HEAD(open_wait); - - -/* ------------------------------------------------------------------------- */ - -static void usb_write_callback(struct urb *urb, struct pt_regs *regs) -{ - struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context; - - if ( waitqueue_active( &ep->wait ) ) - wake_up_interruptible( &ep->wait ); -} - - -static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len ) -{ - struct usb_device *d; - int pipe; - int ret = 0; - int status; - int maxretry = 50; - - DECLARE_WAITQUEUE(wait,current); - init_waitqueue_head(&ep->wait); - - d = ep->usbdev; - pipe = usb_sndbulkpipe(d, ep->endpoint); - usb_fill_bulk_urb( ep->urb, d, pipe, (unsigned char*)buf, len, - usb_write_callback, ep ); - - status = usb_submit_urb(ep->urb, GFP_KERNEL); - - if (status) { - printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status); - ret = -EIO; - goto error; - } - - add_wait_queue( &ep->wait, &wait ); - set_current_state( TASK_INTERRUPTIBLE ); - - while( ep->urb->status == -EINPROGRESS ) { - if ( maxretry-- < 0 ) { - printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n"); - ret = -ETIME; - break; - } - interruptible_sleep_on_timeout( &ep->wait, 10 ); - } - set_current_state( TASK_RUNNING ); - remove_wait_queue( &ep->wait, &wait ); - -error: - return ret; -} - - -/** Copy data from URB to In endpoint buf. - * Discard if CIN == 0 or CIN = 1. - * - * - **/ - -static void usb_bulk_read(struct urb *urb, struct pt_regs *regs) -{ - struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context); - unsigned char *data = urb->transfer_buffer; - int i, j, wake; - - if ( !ep->urbSubmitted ) { - return; - } - - if ( (urb->status == 0) && (urb->actual_length > 0) ) { - wake = 0; - spin_lock( &ep->lock ); - - for(j = 0; j < urb->actual_length; j += 4) { - int cin = (data[j]>>0)&0xf; - int cab = (data[j]>>4)&0xf; - struct usb_mididev *cable = ep->cables[cab]; - if ( cable ) { - int len = cin_to_len[cin]; /** length of MIDI data **/ - for (i = 0; i < len; i++) { - cable->min.buf[cable->min.bufWrPtr] = data[1+i+j]; - cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ; - if (cable->min.bufRemains < MIDI_IN_BUFSIZ) - cable->min.bufRemains += 1; - else /** need to drop data **/ - cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ; - wake = 1; - } - } - } - - spin_unlock ( &ep->lock ); - if ( wake ) { - wake_up( &ep->wait ); - } - } - - /* urb->dev must be reinitialized on 2.4.x kernels */ - urb->dev = ep->usbdev; - - urb->actual_length = 0; - usb_submit_urb(urb, GFP_ATOMIC); -} - - - -/* ------------------------------------------------------------------------- */ - -/* This routine must be called with spin_lock */ - -/** Wrapper around usb_write(). - * This routine must be called with spin_lock held on ep. - * Called by midiWrite(), putOneMidiEvent(), and usb_midi_write(); - **/ -static int flush_midi_buffer( struct midi_out_endpoint *ep ) -{ - int ret=0; - - if ( ep->bufWrPtr > 0 ) { - ret = usb_write( ep, ep->buf, ep->bufWrPtr ); - ep->bufWrPtr = 0; - } - - return ret; -} - - -/* ------------------------------------------------------------------------- */ - - -/** Given a MIDI Event, determine size of data to be attached to - * USB-MIDI packet. - * Returns 1, 2 or 3. - * Called by midiWrite(); - * Uses remains_80e0 and remains_f0f6; - **/ -static int get_remains(int event) -{ - int ret; - - if ( event < 0x80 ) { - ret = 1; - } else if ( event < 0xf0 ) { - ret = remains_80e0[((event-0x80)>>4)&0x0f]; - } else if ( event < 0xf7 ) { - ret = remains_f0f6[event-0xf0]; - } else { - ret = 1; - } - - return ret; -} - -/** Given the output MIDI data in the output buffer, computes a reasonable - * CIN. - * Called by putOneMidiEvent(). - **/ -static int get_CIN( struct usb_mididev *m ) -{ - int cin; - - if ( m->mout.buf[0] == 0xf7 ) { - cin = 5; - } - else if ( m->mout.buf[1] == 0xf7 ) { - cin = 6; - } - else if ( m->mout.buf[2] == 0xf7 ) { - cin = 7; - } - else { - if ( m->mout.isInExclusive == 1 ) { - cin = 4; - } else if ( m->mout.buf[0] < 0x80 ) { - /** One byte that we know nothing about. **/ - cin = 0xF; - } else if ( m->mout.buf[0] < 0xf0 ) { - /** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/ - cin = (m->mout.buf[0]>>4)&0x0f; - } - else { - /** Special lookup table exists for real-time events. **/ - cin = cin_f0ff[m->mout.buf[0]-0xf0]; - } - } - - return cin; -} - - -/* ------------------------------------------------------------------------- */ - - - -/** Move data to USB endpoint buffer. - * - **/ -static int put_one_midi_event(struct usb_mididev *m) -{ - int cin; - unsigned long flags; - struct midi_out_endpoint *ep = m->mout.ep; - int ret=0; - - cin = get_CIN( m ); - if ( cin > 0x0f || cin < 0 ) { - return -EINVAL; - } - - spin_lock_irqsave( &ep->lock, flags ); - ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin; - ep->buf[ep->bufWrPtr++] = m->mout.buf[0]; - ep->buf[ep->bufWrPtr++] = m->mout.buf[1]; - ep->buf[ep->bufWrPtr++] = m->mout.buf[2]; - if ( ep->bufWrPtr >= ep->bufSize ) { - ret = flush_midi_buffer( ep ); - } - spin_unlock_irqrestore( &ep->lock, flags); - - m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0; - m->mout.bufPtr = 0; - - return ret; -} - -/** Write the MIDI message v on the midi device. - * Called by usb_midi_write(); - * Responsible for packaging a MIDI data stream into USB-MIDI packets. - **/ - -static int midi_write( struct usb_mididev *m, int v ) -{ - unsigned long flags; - struct midi_out_endpoint *ep = m->mout.ep; - int ret=0; - unsigned char c = (unsigned char)v; - unsigned char sysrt_buf[4]; - - if ( m->singlebyte != 0 ) { - /** Simple code to handle the single-byte USB-MIDI protocol. */ - spin_lock_irqsave( &ep->lock, flags ); - if ( ep->bufWrPtr+4 > ep->bufSize ) { - ret = flush_midi_buffer( ep ); - if ( !ret ) { - spin_unlock_irqrestore( &ep->lock, flags ); - return ret; - } - } - ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | 0x0f; /* single byte */ - ep->buf[ep->bufWrPtr++] = c; - ep->buf[ep->bufWrPtr++] = 0; - ep->buf[ep->bufWrPtr++] = 0; - if ( ep->bufWrPtr >= ep->bufSize ) { - ret = flush_midi_buffer( ep ); - } - spin_unlock_irqrestore( &ep->lock, flags ); - - return ret; - } - /** Normal USB-MIDI protocol begins here. */ - - if ( c > 0xf7 ) { /* system: Realtime messages */ - /** Realtime messages are written IMMEDIATELY. */ - sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f; - sysrt_buf[1] = c; - sysrt_buf[2] = 0; - sysrt_buf[3] = 0; - spin_lock_irqsave( &ep->lock, flags ); - ret = usb_write( ep, sysrt_buf, 4 ); - spin_unlock_irqrestore( &ep->lock, flags ); - /* m->mout.lastEvent = 0; */ - - return ret; - } - - if ( c >= 0x80 ) { - if ( c < 0xf0 ) { - m->mout.lastEvent = c; - m->mout.isInExclusive = 0; - m->mout.bufRemains = get_remains(c); - } else if ( c == 0xf0 ) { - /* m->mout.lastEvent = 0; */ - m->mout.isInExclusive = 1; - m->mout.bufRemains = get_remains(c); - } else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) { - /* m->mout.lastEvent = 0; */ - m->mout.isInExclusive = 0; - m->mout.bufRemains = 1; - } else if ( c > 0xf0 ) { - /* m->mout.lastEvent = 0; */ - m->mout.isInExclusive = 0; - m->mout.bufRemains = get_remains(c); - } - - } else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) { - if ( m->mout.lastEvent == 0 ) { - return 0; /* discard, waiting for the first event */ - } - /** track status **/ - m->mout.buf[0] = m->mout.lastEvent; - m->mout.bufPtr = 1; - m->mout.bufRemains = get_remains(m->mout.lastEvent)-1; - } - - m->mout.buf[m->mout.bufPtr++] = c; - m->mout.bufRemains--; - if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) { - ret = put_one_midi_event(m); - } - - return ret; -} - - -/* ------------------------------------------------------------------------- */ - -/** Basic operation on /dev/midiXX as registered through struct file_operations. - * - * Basic contract: Used to change the current read/write position in a file. - * On success, the non-negative position is reported. - * On failure, the negative of an error code is reported. - * - * Because a MIDIStream is not a file, all seek operations are doomed to fail. - * - **/ -static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin) -{ - /** Tell user you cannot seek on a PIPE-like device. **/ - return -ESPIPE; -} - - -/** Basic operation on /dev/midiXX as registered through struct file_operations. - * - * Basic contract: Block until count bytes have been read or an error occurs. - * - **/ - -static ssize_t usb_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct usb_mididev *m = (struct usb_mididev *)file->private_data; - struct midi_in_endpoint *ep = m->min.ep; - ssize_t ret; - DECLARE_WAITQUEUE(wait, current); - - if ( !access_ok(VERIFY_READ, buffer, count) ) { - return -EFAULT; - } - if ( count == 0 ) { - return 0; - } - - add_wait_queue( &ep->wait, &wait ); - ret = 0; - while( count > 0 ) { - int cnt; - int d = (int)count; - - cnt = m->min.bufRemains; - if ( cnt > d ) { - cnt = d; - } - - if ( cnt <= 0 ) { - if ( file->f_flags & O_NONBLOCK ) { - if (!ret) - ret = -EAGAIN; - break; - } - __set_current_state(TASK_INTERRUPTIBLE); - schedule(); - if (signal_pending(current)) { - if(!ret) - ret=-ERESTARTSYS; - break; - } - continue; - } - - { - int i; - unsigned long flags; /* used to synchronize access to the endpoint */ - spin_lock_irqsave( &ep->lock, flags ); - for (i = 0; i < cnt; i++) { - if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) { - if ( !ret ) - ret = -EFAULT; - break; - } - m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ; - m->min.bufRemains -= 1; - } - spin_unlock_irqrestore( &ep->lock, flags ); - } - - count-=cnt; - buffer+=cnt; - ret+=cnt; - - break; - } - - remove_wait_queue( &ep->wait, &wait ); - set_current_state(TASK_RUNNING); - - return ret; -} - - -/** Basic operation on /dev/midiXX as registered through struct file_operations. - * - * Basic Contract: Take MIDI data byte-by-byte and pass it to - * writeMidi() which packages MIDI data into USB-MIDI stream. - * Then flushMidiData() is called to ensure all bytes have been written - * in a timely fashion. - * - **/ - -static ssize_t usb_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct usb_mididev *m = (struct usb_mididev *)file->private_data; - ssize_t ret; - unsigned long int flags; - - if ( !access_ok(VERIFY_READ, buffer, count) ) { - return -EFAULT; - } - if ( count == 0 ) { - return 0; - } - - ret = 0; - while( count > 0 ) { - unsigned char c; - - if (copy_from_user((unsigned char *)&c, buffer, 1)) { - if ( ret == 0 ) - ret = -EFAULT; - break; - } - if( midi_write(m, (int)c) ) { - if ( ret == 0 ) - ret = -EFAULT; - break; - } - count--; - buffer++; - ret++; - } - - spin_lock_irqsave( &m->mout.ep->lock, flags ); - if ( flush_midi_buffer(m->mout.ep) < 0 ) { - ret = -EFAULT; - } - spin_unlock_irqrestore( &m->mout.ep->lock, flags ); - - return ret; -} - -/** Basic operation on /dev/midiXX as registered through struct file_operations. - * - * Basic contract: Wait (spin) until ready to read or write on the file. - * - **/ -static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait) -{ - struct usb_mididev *m = (struct usb_mididev *)file->private_data; - struct midi_in_endpoint *iep = m->min.ep; - struct midi_out_endpoint *oep = m->mout.ep; - unsigned long flags; - unsigned int mask = 0; - - if ( file->f_mode & FMODE_READ ) { - poll_wait( file, &iep->wait, wait ); - spin_lock_irqsave( &iep->lock, flags ); - if ( m->min.bufRemains > 0 ) - mask |= POLLIN | POLLRDNORM; - spin_unlock_irqrestore( &iep->lock, flags ); - } - - if ( file->f_mode & FMODE_WRITE ) { - poll_wait( file, &oep->wait, wait ); - spin_lock_irqsave( &oep->lock, flags ); - if ( oep->bufWrPtr < oep->bufSize ) - mask |= POLLOUT | POLLWRNORM; - spin_unlock_irqrestore( &oep->lock, flags ); - } - - return mask; -} - - -/** Basic operation on /dev/midiXX as registered through struct file_operations. - * - * Basic contract: This is always the first operation performed on the - * device node. If no method is defined, the open succeeds without any - * notification given to the module. - * - **/ - -static int usb_midi_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - struct usb_midi_state *s; - struct usb_mididev *m; - unsigned long flags; - int succeed = 0; - -#if 0 - printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor); -#endif - - for(;;) { - down(&open_sem); - list_for_each_entry(s, &mididevs, mididev) { - list_for_each_entry(m, &s->midiDevList, list) { - if ( !((m->dev_midi ^ minor) & ~0xf) ) - goto device_found; - } - } - up(&open_sem); - return -ENODEV; - - device_found: - if ( !s->usbdev ) { - up(&open_sem); - return -EIO; - } - if ( !(m->open_mode & file->f_mode) ) { - break; - } - if ( file->f_flags & O_NONBLOCK ) { - up(&open_sem); - return -EBUSY; - } - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue( &open_wait, &wait ); - up(&open_sem); - schedule(); - remove_wait_queue( &open_wait, &wait ); - if ( signal_pending(current) ) { - return -ERESTARTSYS; - } - } - - file->private_data = m; - spin_lock_irqsave( &s->lock, flags ); - - if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) { - //FIXME: intented semantics unclear here - m->min.bufRdPtr = 0; - m->min.bufWrPtr = 0; - m->min.bufRemains = 0; - spin_lock_init(&m->min.ep->lock); - - m->mout.bufPtr = 0; - m->mout.bufRemains = 0; - m->mout.isInExclusive = 0; - m->mout.lastEvent = 0; - spin_lock_init(&m->mout.ep->lock); - } - - if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) { - unsigned long int flagsep; - spin_lock_irqsave( &m->min.ep->lock, flagsep ); - m->min.ep->cables[m->min.cableId] = m; - m->min.ep->readers += 1; - m->min.bufRdPtr = 0; - m->min.bufWrPtr = 0; - m->min.bufRemains = 0; - spin_unlock_irqrestore( &m->min.ep->lock, flagsep ); - - if ( !(m->min.ep->urbSubmitted)) { - - /* urb->dev must be reinitialized on 2.4.x kernels */ - m->min.ep->urb->dev = m->min.ep->usbdev; - - if ( usb_submit_urb(m->min.ep->urb, GFP_ATOMIC) ) { - printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n"); - } - m->min.ep->urbSubmitted = 1; - } - m->open_mode |= FMODE_READ; - succeed = 1; - } - - if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) { - m->mout.bufPtr = 0; - m->mout.bufRemains = 0; - m->mout.isInExclusive = 0; - m->mout.lastEvent = 0; - m->open_mode |= FMODE_WRITE; - succeed = 1; - } - - spin_unlock_irqrestore( &s->lock, flags ); - - s->count++; - up(&open_sem); - - /** Changed to prevent extra increments to USE_COUNT. **/ - if (!succeed) { - return -EBUSY; - } - -#if 0 - printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor); -#endif - - return nonseekable_open(inode, file); /** Success. **/ -} - - -/** Basic operation on /dev/midiXX as registered through struct file_operations. - * - * Basic contract: Close an opened file and deallocate anything we allocated. - * Like open(), this can be missing. If open set file->private_data, - * release() must clear it. - * - **/ - -static int usb_midi_release(struct inode *inode, struct file *file) -{ - struct usb_mididev *m = (struct usb_mididev *)file->private_data; - struct usb_midi_state *s = (struct usb_midi_state *)m->midi; - -#if 0 - printk(KERN_INFO "usb-midi: Close.\n"); -#endif - - down(&open_sem); - - if ( m->open_mode & FMODE_WRITE ) { - m->open_mode &= ~FMODE_WRITE; - usb_kill_urb( m->mout.ep->urb ); - } - - if ( m->open_mode & FMODE_READ ) { - unsigned long int flagsep; - spin_lock_irqsave( &m->min.ep->lock, flagsep ); - m->min.ep->cables[m->min.cableId] = NULL; // discard cable - m->min.ep->readers -= 1; - m->open_mode &= ~FMODE_READ; - if ( m->min.ep->readers == 0 && - m->min.ep->urbSubmitted ) { - m->min.ep->urbSubmitted = 0; - usb_kill_urb(m->min.ep->urb); - } - spin_unlock_irqrestore( &m->min.ep->lock, flagsep ); - } - - s->count--; - - up(&open_sem); - wake_up(&open_wait); - - file->private_data = NULL; - return 0; -} - -static struct file_operations usb_midi_fops = { - .owner = THIS_MODULE, - .llseek = usb_midi_llseek, - .read = usb_midi_read, - .write = usb_midi_write, - .poll = usb_midi_poll, - .open = usb_midi_open, - .release = usb_midi_release, -}; - -/* ------------------------------------------------------------------------- */ - -/** Returns filled midi_in_endpoint structure or null on failure. - * - * Parameters: - * d - a usb_device - * endPoint - An usb endpoint in the range 0 to 15. - * Called by allocUsbMidiDev(); - * - **/ - -static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint ) -{ - struct midi_in_endpoint *ep; - int bufSize; - int pipe; - - endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */ - - pipe = usb_rcvbulkpipe( d, endPoint ); - bufSize = usb_maxpacket( d, pipe, 0 ); - /* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */ - - ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL); - if ( !ep ) { - printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n"); - return NULL; - } - memset( ep, 0, sizeof(struct midi_in_endpoint) ); -// this sets cables[] and readers to 0, too. -// for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable -// ep->readers = 0; - - ep->endpoint = endPoint; - - ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL); - if ( !ep->recvBuf ) { - printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n"); - kfree(ep); - return NULL; - } - - ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */ - if ( !ep->urb ) { - printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n"); - kfree(ep->recvBuf); - kfree(ep); - return NULL; - } - usb_fill_bulk_urb( ep->urb, d, - usb_rcvbulkpipe(d, endPoint), - (unsigned char *)ep->recvBuf, bufSize, - usb_bulk_read, ep ); - - /* ep->bufRdPtr = 0; */ - /* ep->bufWrPtr = 0; */ - /* ep->bufRemains = 0; */ - /* ep->urbSubmitted = 0; */ - ep->recvBufSize = bufSize; - - init_waitqueue_head(&ep->wait); - - return ep; -} - -static int remove_midi_in_endpoint( struct midi_in_endpoint *min ) -{ - usb_kill_urb( min->urb ); - usb_free_urb( min->urb ); - kfree( min->recvBuf ); - kfree( min ); - - return 0; -} - -/** Returns filled midi_out_endpoint structure or null on failure. - * - * Parameters: - * d - a usb_device - * endPoint - An usb endpoint in the range 0 to 15. - * Called by allocUsbMidiDev(); - * - **/ -static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint ) -{ - struct midi_out_endpoint *ep = NULL; - int pipe; - int bufSize; - - endPoint &= 0x0f; - pipe = usb_sndbulkpipe( d, endPoint ); - bufSize = usb_maxpacket( d, pipe, 1 ); - - ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL); - if ( !ep ) { - printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n"); - return NULL; - } - memset( ep, 0, sizeof(struct midi_out_endpoint) ); - - ep->endpoint = endPoint; - ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL); - if ( !ep->buf ) { - printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n"); - kfree(ep); - return NULL; - } - - ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */ - if ( !ep->urb ) { - printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n"); - kfree(ep->buf); - kfree(ep); - return NULL; - } - - ep->bufSize = bufSize; - /* ep->bufWrPtr = 0; */ - - init_waitqueue_head(&ep->wait); - - return ep; -} - - -static int remove_midi_out_endpoint( struct midi_out_endpoint *mout ) -{ - usb_kill_urb( mout->urb ); - usb_free_urb( mout->urb ); - kfree( mout->buf ); - kfree( mout ); - - return 0; -} - - -/** Returns a filled usb_mididev structure, registered as a Linux MIDI device. - * - * Returns null if memory is not available or the device cannot be registered. - * Called by allocUsbMidiDev(); - * - **/ -static struct usb_mididev *allocMidiDev( - struct usb_midi_state *s, - struct midi_in_endpoint *min, - struct midi_out_endpoint *mout, - int inCableId, - int outCableId ) -{ - struct usb_mididev *m; - - m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL); - if (!m) { - printk(KERN_ERR "usbmidi: no memory for midi device\n"); - return NULL; - } - - memset(m, 0, sizeof(struct usb_mididev)); - - if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) { - printk(KERN_ERR "usbmidi: cannot register midi device\n"); - kfree(m); - return NULL; - } - - m->midi = s; - /* m->open_mode = 0; */ - - if ( min ) { - m->min.ep = min; - m->min.ep->usbdev = s->usbdev; - m->min.cableId = inCableId; - } - /* m->min.bufPtr = 0; */ - /* m->min.bufRemains = 0; */ - - if ( mout ) { - m->mout.ep = mout; - m->mout.ep->usbdev = s->usbdev; - m->mout.cableId = outCableId; - } - /* m->mout.bufPtr = 0; */ - /* m->mout.bufRemains = 0; */ - /* m->mout.isInExclusive = 0; */ - /* m->mout.lastEvent = 0; */ - - m->singlebyte = singlebyte; - - return m; -} - - -static void release_midi_device( struct usb_midi_state *s ) -{ - struct usb_mididev *m; - struct midi_in_endpoint *min; - struct midi_out_endpoint *mout; - - if ( s->count > 0 ) { - up(&open_sem); - return; - } - up( &open_sem ); - wake_up( &open_wait ); - - while(!list_empty(&s->inEndpointList)) { - min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list); - list_del(&min->list); - remove_midi_in_endpoint(min); - } - - while(!list_empty(&s->outEndpointList)) { - mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list); - list_del(&mout->list); - remove_midi_out_endpoint(mout); - } - - while(!list_empty(&s->midiDevList)) { - m = list_entry(s->midiDevList.next, struct usb_mididev, list); - list_del(&m->list); - kfree(m); - } - - kfree(s); - - return; -} - - -/* ------------------------------------------------------------------------- */ - -/** Utility routine to find a descriptor in a dump of many descriptors. - * Returns start of descriptor or NULL if not found. - * descStart pointer to list of interfaces. - * descLength length (in bytes) of dump - * after (ignored if NULL) this routine returns only descriptors after "after" - * dtype (mandatory) The descriptor type. - * iface (ignored if -1) returns descriptor at/following given interface - * altSetting (ignored if -1) returns descriptor at/following given altSetting - * - * - * Called by parseDescriptor(), find_csinterface_descriptor(); - * - */ -static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting ) -{ - unsigned char *p, *end, *next; - int interfaceNumber = -1, altSet = -1; - - p = descStart; - end = p + descLength; - for( ; p < end; ) { - if ( p[0] < 2 ) - return NULL; - next = p + p[0]; - if ( next > end ) - return NULL; - if ( p[1] == USB_DT_INTERFACE ) { - if ( p[0] < USB_DT_INTERFACE_SIZE ) - return NULL; - interfaceNumber = p[2]; - altSet = p[3]; - } - if ( p[1] == dtype && - ( !after || ( p > (unsigned char *)after) ) && - ( ( iface == -1) || (iface == interfaceNumber) ) && - ( (altSetting == -1) || (altSetting == altSet) )) { - return p; - } - p = next; - } - return NULL; -} - -/** Utility to find a class-specific interface descriptor. - * dsubtype is a descriptor subtype - * Called by parseDescriptor(); - **/ -static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting) -{ - unsigned char *p; - - p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting ); - while ( p ) { - if ( p[0] >= 3 && p[2] == dsubtype ) - return p; - p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, - iface, altSetting ); - } - return NULL; -} - - -/** The magic of making a new usb_midi_device from config happens here. - * - * The caller is responsible for free-ing this return value (if not NULL). - * - **/ -static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks) -{ - struct usb_midi_device *u; - unsigned char *p1; - unsigned char *p2; - unsigned char *next; - int iep, oep; - int length; - unsigned long longBits; - int pins, nbytes, offset, shift, jack; -#ifdef HAVE_JACK_STRINGS - /** Jacks can have associated names. **/ - unsigned char jack2string[256]; -#endif - - u = NULL; - /* find audiocontrol interface */ - p1 = find_csinterface_descriptor( buffer, bufSize, NULL, - MS_HEADER, ifnum, altSetting); - - if ( !p1 ) { - goto error_end; - } - - if ( p1[0] < MS_HEADER_LENGTH ) { - goto error_end; - } - - /* Assume success. Since the device corresponds to USB-MIDI spec, we assume - that the rest of the USB 2.0 spec is obeyed. */ - - u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL ); - if ( !u ) { - return NULL; - } - u->deviceName = NULL; - u->idVendor = le16_to_cpu(d->descriptor.idVendor); - u->idProduct = le16_to_cpu(d->descriptor.idProduct); - u->interface = ifnum; - u->altSetting = altSetting; - u->in[0].endpoint = -1; - u->in[0].cableId = -1; - u->out[0].endpoint = -1; - u->out[0].cableId = -1; - - - printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n", - (p1[4] >> 4) * 10 + (p1[4] & 0x0f ), - (p1[3] >> 4) * 10 + (p1[3] & 0x0f ) - ); - - length = p1[5] | (p1[6] << 8); - -#ifdef HAVE_JACK_STRINGS - memset(jack2string, 0, sizeof(unsigned char) * 256); -#endif - - length -= p1[0]; - for (p2 = p1 + p1[0]; length > 0; p2 = next) { - next = p2 + p2[0]; - length -= p2[0]; - - if (p2[0] < 2 ) - break; - if (p2[1] != USB_DT_CS_INTERFACE) - break; - if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) { - jack = p2[4]; -#ifdef HAVE_JACK_STRINGS - jack2string[jack] = p2[5]; -#endif - printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n", - jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" ); - } else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) { - pins = p2[5]; - if ( p2[0] < (6 + 2 * pins) ) - continue; - jack = p2[4]; -#ifdef HAVE_JACK_STRINGS - jack2string[jack] = p2[5 + 2 * pins]; -#endif - printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n", - jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins ); - } else if ( p2[2] == ELEMENT_DESCRIPTOR && p2[0] >= 10) { - pins = p2[4]; - if ( p2[0] < (9 + 2 * pins ) ) - continue; - nbytes = p2[8 + 2 * pins ]; - if ( p2[0] < (10 + 2 * pins + nbytes) ) - continue; - longBits = 0L; - for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) { - longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift; - } - jack = p2[3]; -#ifdef HAVE_JACK_STRINGS - jack2string[jack] = p2[9 + 2 * pins + nbytes]; -#endif - printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n", - jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits ); - } else { - } - } - - iep=0; - oep=0; - - if (quirks==0) { - /* MIDISTREAM */ - p2 = NULL; - for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT, - ifnum, altSetting ); p1; p1 = next ) { - next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT, - ifnum, altSetting ); - p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT, - ifnum, altSetting ); - - if ( p2 && next && ( p2 > next ) ) - p2 = NULL; - - if ( p1[0] < 9 || !p2 || p2[0] < 4 ) - continue; - - if ( (p1[2] & 0x80) == 0x80 ) { - if ( iep < 15 ) { - pins = p2[3]; /* not pins -- actually "cables" */ - if ( pins > 16 ) - pins = 16; - u->in[iep].endpoint = p1[2]; - u->in[iep].cableId = ( 1 << pins ) - 1; - if ( u->in[iep].cableId ) - iep ++; - if ( iep < 15 ) { - u->in[iep].endpoint = -1; - u->in[iep].cableId = -1; - } - } - } else { - if ( oep < 15 ) { - pins = p2[3]; /* not pins -- actually "cables" */ - if ( pins > 16 ) - pins = 16; - u->out[oep].endpoint = p1[2]; - u->out[oep].cableId = ( 1 << pins ) - 1; - if ( u->out[oep].cableId ) - oep ++; - if ( oep < 15 ) { - u->out[oep].endpoint = -1; - u->out[oep].cableId = -1; - } - } - } - - } - } else if (quirks==1) { - /* YAMAHA quirks */ - for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT, - ifnum, altSetting ); p1; p1 = next ) { - next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT, - ifnum, altSetting ); - - if ( p1[0] < 7 ) - continue; - - if ( (p1[2] & 0x80) == 0x80 ) { - if ( iep < 15 ) { - pins = iep+1; - if ( pins > 16 ) - pins = 16; - u->in[iep].endpoint = p1[2]; - u->in[iep].cableId = ( 1 << pins ) - 1; - if ( u->in[iep].cableId ) - iep ++; - if ( iep < 15 ) { - u->in[iep].endpoint = -1; - u->in[iep].cableId = -1; - } - } - } else { - if ( oep < 15 ) { - pins = oep+1; - u->out[oep].endpoint = p1[2]; - u->out[oep].cableId = ( 1 << pins ) - 1; - if ( u->out[oep].cableId ) - oep ++; - if ( oep < 15 ) { - u->out[oep].endpoint = -1; - u->out[oep].cableId = -1; - } - } - } - - } - } - - if ( !iep && ! oep ) { - goto error_end; - } - - return u; - -error_end: - kfree(u); - return NULL; -} - -/* ------------------------------------------------------------------------- */ - -/** Returns number between 0 and 16. - * - **/ -static int on_bits( unsigned short v ) -{ - int i; - int ret=0; - - for ( i=0 ; i<16 ; i++ ) { - if ( v & (1<num_altsetting; - - for ( alt=0 ; altaltsetting[alt]; - epin = -1; - epout = -1; - - for ( i=0 ; idesc.bNumEndpoints ; i++ ) { - ep = &interface->endpoint[i].desc; - if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) { - continue; - } - if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) { - epin = i; - } else if ( epout < 0 ) { - epout = i; - } - if ( epin >= 0 && epout >= 0 ) { - return interface->desc.bAlternateSetting; - } - } - } - - return -ENODEV; -} - - -/* ------------------------------------------------------------------------- */ - - -/** Returns 0 if successful in allocating and registering internal structures. - * Returns negative on failure. - * Calls allocMidiDev which additionally registers /dev/midiXX devices. - * Writes messages on success to indicate which /dev/midiXX is which physical - * endpoint. - * - **/ -static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u ) -{ - struct usb_mididev **mdevs=NULL; - struct midi_in_endpoint *mins[15], *min; - struct midi_out_endpoint *mouts[15], *mout; - int inDevs=0, outDevs=0; - int inEndpoints=0, outEndpoints=0; - int inEndpoint, outEndpoint; - int inCableId, outCableId; - int i; - int devices = 0; - int alt = 0; - - /* Obtain altSetting or die.. */ - alt = u->altSetting; - if ( alt < 0 ) { - alt = get_alt_setting( d, u->interface ); - } - if ( alt < 0 ) - return -ENXIO; - - /* Configure interface */ - if ( usb_set_interface( d, u->interface, alt ) < 0 ) { - return -ENXIO; - } - - for ( i = 0 ; i < 15 ; i++ ) { - mins[i] = NULL; - mouts[i] = NULL; - } - - /* Begin Allocation */ - while( inEndpoints < 15 - && inDevs < maxdevices - && u->in[inEndpoints].cableId >= 0 ) { - inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId); - mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint ); - if ( mins[inEndpoints] == NULL ) - goto error_end; - inEndpoints++; - } - - while( outEndpoints < 15 - && outDevs < maxdevices - && u->out[outEndpoints].cableId >= 0 ) { - outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId); - mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint ); - if ( mouts[outEndpoints] == NULL ) - goto error_end; - outEndpoints++; - } - - devices = inDevs > outDevs ? inDevs : outDevs; - devices = maxdevices > devices ? devices : maxdevices; - - /* obtain space for device name (iProduct) if not known. */ - if ( ! u->deviceName ) { - mdevs = (struct usb_mididev **) - kmalloc(sizeof(struct usb_mididevs *)*devices - + sizeof(char) * 256, GFP_KERNEL); - } else { - mdevs = (struct usb_mididev **) - kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL); - } - - if ( !mdevs ) { - /* devices = 0; */ - /* mdevs = NULL; */ - goto error_end; - } - for ( i=0 ; ideviceName ) { - u->deviceName = (char *) (mdevs + devices); - if ( ! d->have_langid && d->descriptor.iProduct) { - alt = usb_get_string(d, 0, 0, u->deviceName, 250); - if (alt < 0) { - printk(KERN_INFO "error getting string descriptor 0 (error=%d)\n", alt); - } else if (u->deviceName[0] < 4) { - printk(KERN_INFO "string descriptor 0 too short (length = %d)\n", alt); - } else { - printk(KERN_INFO "string descriptor 0 found (length = %d)\n", alt); - for(; alt >= 4; alt -= 2) { - i = u->deviceName[alt-2] | (u->deviceName[alt-1]<< 8); - printk(KERN_INFO "usb-midi: langid(%d) 0x%04x\n", - (alt-4) >> 1, i); - if ( ( ( i ^ ulangid ) & 0xff ) == 0 ) { - d->have_langid = 1; - d->string_langid = i; - printk(KERN_INFO "usb-midi: langid(match) 0x%04x\n", i); - if ( i == ulangid ) - break; - } - } - } - } - u->deviceName[0] = (char) 0; - if (d->descriptor.iProduct) { - printk(KERN_INFO "usb-midi: fetchString(%d)\n", d->descriptor.iProduct); - alt = usb_string(d, d->descriptor.iProduct, u->deviceName, 255); - if( alt < 0 ) { - u->deviceName[0] = (char) 0; - } - printk(KERN_INFO "usb-midi: fetchString = %d\n", alt); - } - /* Failsafe */ - if ( !u->deviceName[0] ) { - if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_ROLAND ) { - strcpy(u->deviceName, "Unknown Roland"); - } else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_STEINBERG ) { - strcpy(u->deviceName, "Unknown Steinberg"); - } else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_YAMAHA ) { - strcpy(u->deviceName, "Unknown Yamaha"); - } else { - strcpy(u->deviceName, "Unknown"); - } - } - } - - inEndpoint = 0; inCableId = -1; - outEndpoint = 0; outCableId = -1; - - for ( i=0 ; iin[inEndpoint].cableId & (1<= 16 ) { - inEndpoint ++; - inCableId = 0; - } - } - min = mins[inEndpoint]; - for ( outCableId ++ ; - outEndpoint <15 - && mouts[outEndpoint] - && !(u->out[outEndpoint].cableId & (1<= 16 ) { - outEndpoint ++; - outCableId = 0; - } - } - mout = mouts[outEndpoint]; - - mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId ); - if ( mdevs[i] == NULL ) - goto error_end; - - } - - /* Success! */ - for ( i=0 ; ilist, &s->midiDevList ); - } - for ( i=0 ; ilist, &s->inEndpointList ); - } - for ( i=0 ; ilist, &s->outEndpointList ); - } - - printk(KERN_INFO "usbmidi: found [ %s ] (0x%04x:0x%04x), attached:\n", u->deviceName, u->idVendor, u->idProduct ); - for ( i=0 ; idev_midi-2)>>4; - if ( mdevs[i]->mout.ep != NULL && mdevs[i]->min.ep != NULL ) { - printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%2d) out (ep:%02x cid:%2d bufsiz:%2d)\n", - dm, - mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize, - mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize); - } else if ( mdevs[i]->min.ep != NULL ) { - printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%02d)\n", - dm, - mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize); - } else if ( mdevs[i]->mout.ep != NULL ) { - printk(KERN_INFO "usbmidi: /dev/midi%02d: out (ep:%02x cid:%2d bufsiz:%02d)\n", - dm, - mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize); - } - } - - kfree(mdevs); - return 0; - - error_end: - if ( mdevs != NULL ) { - for ( i=0 ; idev_midi ); - kfree(mdevs[i]); - } - } - kfree(mdevs); - } - - for ( i=0 ; i<15 ; i++ ) { - if ( mins[i] != NULL ) { - remove_midi_in_endpoint( mins[i] ); - } - if ( mouts[i] != NULL ) { - remove_midi_out_endpoint( mouts[i] ); - } - } - - return -ENOMEM; -} - -/* ------------------------------------------------------------------------- */ - -/** Attempt to scan YAMAHA's device descriptor and detect correct values of - * them. - * Return 0 on succes, negative on failure. - * Called by usb_midi_probe(); - **/ - -static int detect_yamaha_device( struct usb_device *d, - struct usb_interface *iface, unsigned int ifnum, - struct usb_midi_state *s) -{ - struct usb_host_interface *interface; - struct usb_midi_device *u; - unsigned char *buffer; - int bufSize; - int i; - int alts=-1; - int ret; - - if (le16_to_cpu(d->descriptor.idVendor) != USB_VENDOR_ID_YAMAHA) { - return -EINVAL; - } - - for ( i=0 ; i < iface->num_altsetting; i++ ) { - interface = iface->altsetting + i; - - if ( interface->desc.bInterfaceClass != 255 || - interface->desc.bInterfaceSubClass != 0 ) - continue; - alts = interface->desc.bAlternateSetting; - } - if ( alts == -1 ) { - return -EINVAL; - } - - printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n", - le16_to_cpu(d->descriptor.idVendor), - le16_to_cpu(d->descriptor.idProduct), ifnum); - - i = d->actconfig - d->config; - buffer = d->rawdescriptors[i]; - bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength); - - u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1); - if ( u == NULL ) { - return -EINVAL; - } - - ret = alloc_usb_midi_device( d, s, u ); - - kfree(u); - - return ret; -} - - -/** Scan table of known devices which are only partially compliant with - * the MIDIStreaming specification. - * Called by usb_midi_probe(); - * - **/ - -static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s ) -{ - struct usb_midi_device *u; - int i; - int ret = -ENXIO; - - for ( i=0; idescriptor.idVendor) != u->idVendor || - le16_to_cpu(d->descriptor.idProduct) != u->idProduct || - ifnum != u->interface ) - continue; - - ret = alloc_usb_midi_device( d, s, u ); - break; - } - - return ret; -} - - -/** Attempt to match any config of an interface to a MIDISTREAMING interface. - * Returns 0 on success, negative on failure. - * Called by usb_midi_probe(); - **/ -static int detect_midi_subclass(struct usb_device *d, - struct usb_interface *iface, unsigned int ifnum, - struct usb_midi_state *s) -{ - struct usb_host_interface *interface; - struct usb_midi_device *u; - unsigned char *buffer; - int bufSize; - int i; - int alts=-1; - int ret; - - for ( i=0 ; i < iface->num_altsetting; i++ ) { - interface = iface->altsetting + i; - - if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO || - interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING ) - continue; - alts = interface->desc.bAlternateSetting; - } - if ( alts == -1 ) { - return -EINVAL; - } - - printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n", - le16_to_cpu(d->descriptor.idVendor), - le16_to_cpu(d->descriptor.idProduct), ifnum); - - - /* From USB Spec v2.0, Section 9.5. - If the class or vendor specific descriptors use the same format - as standard descriptors (e.g., start with a length byte and - followed by a type byte), they must be returned interleaved with - standard descriptors in the configuration information returned by - a GetDescriptor(Configuration) request. In this case, the class - or vendor-specific descriptors must follow a related standard - descriptor they modify or extend. - */ - - i = d->actconfig - d->config; - buffer = d->rawdescriptors[i]; - bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength); - - u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0); - if ( u == NULL ) { - return -EINVAL; - } - - ret = alloc_usb_midi_device( d, s, u ); - - kfree(u); - - return ret; -} - - -/** When user has requested a specific device, match it exactly. - * - * Uses uvendor, uproduct, uinterface, ualt, umin, umout and ucable. - * Called by usb_midi_probe(); - * - **/ -static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s) -{ - struct usb_midi_device u; - - if ( le16_to_cpu(d->descriptor.idVendor) != uvendor || - le16_to_cpu(d->descriptor.idProduct) != uproduct || - ifnum != uinterface ) { - return -EINVAL; - } - - if ( ualt < 0 ) - ualt = -1; - - if ( umin < 0 || umin > 15 ) - umin = 0x01 | USB_DIR_IN; - if ( umout < 0 || umout > 15 ) - umout = 0x01; - if ( ucable < 0 || ucable > 15 ) - ucable = 0; - - u.deviceName = NULL; /* A flag for alloc_usb_midi_device to get device - name from device. */ - u.idVendor = uvendor; - u.idProduct = uproduct; - u.interface = uinterface; - u.altSetting = ualt; - - u.in[0].endpoint = umin; - u.in[0].cableId = (1<cur_altsetting->desc.bInterfaceNumber; - - s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL); - if ( !s ) - return -ENOMEM; - - memset( s, 0, sizeof(struct usb_midi_state) ); - INIT_LIST_HEAD(&s->midiDevList); - INIT_LIST_HEAD(&s->inEndpointList); - INIT_LIST_HEAD(&s->outEndpointList); - s->usbdev = dev; - s->count = 0; - spin_lock_init(&s->lock); - - if ( - detect_by_hand( dev, ifnum, s ) && - detect_midi_subclass( dev, intf, ifnum, s ) && - detect_vendor_specific_device( dev, ifnum, s ) && - detect_yamaha_device( dev, intf, ifnum, s) ) { - kfree(s); - return -EIO; - } - - down(&open_sem); - list_add_tail(&s->mididev, &mididevs); - up(&open_sem); - - usb_set_intfdata (intf, s); - return 0; -} - - -static void usb_midi_disconnect(struct usb_interface *intf) -{ - struct usb_midi_state *s = usb_get_intfdata (intf); - struct usb_mididev *m; - - if ( !s ) - return; - - if ( s == (struct usb_midi_state *)-1 ) { - return; - } - if ( !s->usbdev ) { - return; - } - down(&open_sem); - list_del(&s->mididev); - INIT_LIST_HEAD(&s->mididev); - s->usbdev = NULL; - usb_set_intfdata (intf, NULL); - - list_for_each_entry(m, &s->midiDevList, list) { - wake_up(&(m->min.ep->wait)); - wake_up(&(m->mout.ep->wait)); - if ( m->dev_midi >= 0 ) { - unregister_sound_midi(m->dev_midi); - } - m->dev_midi = -1; - } - release_midi_device(s); - wake_up(&open_wait); -} - -/* we want to look at all devices by hand */ -static struct usb_device_id id_table[] = { - {.driver_info = 42}, - {} -}; - -static struct usb_driver usb_midi_driver = { - .name = "midi", - .probe = usb_midi_probe, - .disconnect = usb_midi_disconnect, - .id_table = id_table, -}; - -/* ------------------------------------------------------------------------- */ - -static int __init usb_midi_init(void) -{ - return usb_register(&usb_midi_driver); -} - -static void __exit usb_midi_exit(void) -{ - usb_deregister(&usb_midi_driver); -} - -module_init(usb_midi_init) ; -module_exit(usb_midi_exit) ; - -#ifdef HAVE_ALSA_SUPPORT -#define SNDRV_MAIN_OBJECT_FILE -#include "../../include/driver.h" -#include "../../include/control.h" -#include "../../include/info.h" -#include "../../include/cs46xx.h" - -/* ------------------------------------------------------------------------- */ - -static int snd_usbmidi_input_close(snd_rawmidi_substream_t * substream) -{ - return 0; -} - -static int snd_usbmidi_input_open(snd_rawmidi_substream_t * substream ) -{ - return 0; -} - -static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t * substream, int up) -{ - return 0; -} - - -/* ------------------------------------------------------------------------- */ - -static int snd_usbmidi_output_close(snd_rawmidi_substream_t * substream) -{ - return 0; -} - -static int snd_usbmidi_output_open(snd_rawmidi_substream_t * substream) -{ - return 0; -} - -static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream, - int up) -{ - return 0; -} - -/* ------------------------------------------------------------------------- */ - -static snd_rawmidi_ops_t snd_usbmidi_output = -{ - .open = snd_usbmidi_output_open, - .close = snd_usbmidi_output_close, - .trigger = snd_usbmidi_output_trigger, -}; -static snd_rawmidi_ops_t snd_usbmidi_input = -{ - .open = snd_usbmidi_input_open, - .close = snd_usbmidi_input_close, - .trigger = snd_usbmidi_input_trigger, -}; - -int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi) -{ - snd_rawmidi_t *rmidi; - int err; - - if (rrawmidi) - *rrawmidi = NULL; - if ((err = snd_rawmidi_new(chip->card, "USB-MIDI", device, 1, 1, &rmidi)) < 0) - return err; - strcpy(rmidi->name, "USB-MIDI"); - - snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output ); - snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input ); - - rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; - - rmidi->private_data = chip; - chip->rmidi = rmidi; - if (rrawmidi) - *rrawmidi = NULL; - - return 0; -} - -int snd_usbmidi_create( snd_card_t * card, - struct pci_dev * pci, - usbmidi_t ** rchip ) -{ - usbmidi_t *chip; - int err, idx; - snd_region_t *region; - static snd_device_opt_t ops = { - .dev_free = snd_usbmidi_dev_free, - }; - - *rchip = NULL; - chip = snd_magic_kcalloc( usbmidi_t, 0, GFP_KERNEL ); - if ( chip == NULL ) - return -ENOMEM; -} - -EXPORT_SYMBOL(snd_usbmidi_create); -EXPORT_SYMBOL(snd_usbmidi_midi); -#endif /* HAVE_ALSA_SUPPORT */ - diff --git a/drivers/usb/class/usb-midi.h b/drivers/usb/class/usb-midi.h deleted file mode 100644 index 358cdef8492e..000000000000 --- a/drivers/usb/class/usb-midi.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - usb-midi.h -- USB-MIDI driver - - Copyright (C) 2001 - NAGANO Daisuke - - 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, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* ------------------------------------------------------------------------- */ - -#ifndef _USB_MIDI_H_ -#define _USB_MIDI_H_ - -#ifndef USB_SUBCLASS_MIDISTREAMING -#define USB_SUBCLASS_MIDISTREAMING 3 -#endif - -/* ------------------------------------------------------------------------- */ -/* Roland MIDI Devices */ - -#define USB_VENDOR_ID_ROLAND 0x0582 -#define USBMIDI_ROLAND_UA100G 0x0000 -#define USBMIDI_ROLAND_MPU64 0x0002 -#define USBMIDI_ROLAND_SC8850 0x0003 -#define USBMIDI_ROLAND_SC8820 0x0007 -#define USBMIDI_ROLAND_UM2 0x0005 -#define USBMIDI_ROLAND_UM1 0x0009 -#define USBMIDI_ROLAND_PC300 0x0008 - -/* YAMAHA MIDI Devices */ -#define USB_VENDOR_ID_YAMAHA 0x0499 -#define USBMIDI_YAMAHA_MU1000 0x1001 - -/* Steinberg MIDI Devices */ -#define USB_VENDOR_ID_STEINBERG 0x0763 -#define USBMIDI_STEINBERG_USB2MIDI 0x1001 - -/* Mark of the Unicorn MIDI Devices */ -#define USB_VENDOR_ID_MOTU 0x07fd -#define USBMIDI_MOTU_FASTLANE 0x0001 - -/* ------------------------------------------------------------------------- */ -/* Supported devices */ - -struct usb_midi_endpoint { - int endpoint; - int cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */ -}; - -struct usb_midi_device { - char *deviceName; - - u16 idVendor; - u16 idProduct; - int interface; - int altSetting; /* -1: auto detect */ - - struct usb_midi_endpoint in[15]; - struct usb_midi_endpoint out[15]; -}; - -static struct usb_midi_device usb_midi_devices[] = { - { /* Roland UM-1 */ - "Roland UM-1", - USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1, - { { 0x81, 1 }, {-1, -1} }, - { { 0x01, 1,}, {-1, -1} }, - }, - - { /* Roland UM-2 */ - "Roland UM-2" , - USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1, - { { 0x81, 3 }, {-1, -1} }, - { { 0x01, 3,}, {-1, -1} }, - }, - -/** Next entry courtesy research by Michael Minn **/ - { /* Roland UA-100 */ - "Roland UA-100", - USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1, - { { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/ - { { 0x02, 7 }, {-1, -1} }, - }, - -/** Next entry courtesy research by Michael Minn **/ - { /* Roland SC8850 */ - "Roland SC8850", - USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1, - { { 0x81, 0x3f }, {-1, -1} }, - { { 0x01, 0x3f }, {-1, -1} }, - }, - - { /* Roland SC8820 */ - "Roland SC8820", - USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1, - { { 0x81, 0x13 }, {-1, -1} }, - { { 0x01, 0x13 }, {-1, -1} }, - }, - - { /* Roland SC8820 */ - "Roland SC8820", - USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1, - { { 0x81, 17 }, {-1, -1} }, - { { 0x01, 17 }, {-1, -1} }, - }, - - { /* YAMAHA MU1000 */ - "YAMAHA MU1000", - USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, - { { 0x81, 1 }, {-1, -1} }, - { { 0x01, 15 }, {-1, -1} }, - }, - { /* Roland PC-300 */ - "Roland PC-300", - USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, - { { 0x81, 1 }, {-1, -1} }, - { { 0x01, 1 }, {-1, -1} }, - }, - { /* MOTU Fastlane USB */ - "MOTU Fastlane USB", - USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE, 1, 0, - { { 0x82, 3 }, {-1, -1} }, - { { 0x02, 3 }, {-1, -1} }, - } -}; - -#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device)) - -/* for Hot-Plugging */ - -static struct usb_device_id usb_midi_ids [] = { - { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), - .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING}, - { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1 ) }, - { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2 ) }, - { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) }, - { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) }, - { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) }, - { USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820 ) }, - { USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) }, - { USB_DEVICE( USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE ) }, -/* { USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_midi_ids); - -/* ------------------------------------------------------------------------- */ -#endif /* _USB_MIDI_H_ */ - - -- cgit v1.2.2 From e266a12492f7ca9142882710bff92e902b7c95c8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 8 Nov 2005 21:05:43 +0100 Subject: [PATCH] USB: drivers/usb/core/message.c: make usb_get_string() static After the removal of usb-midi.c, there's no longer any external user of usb_get_string(). Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 7135e542679d..2f6009b0cffc 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -631,8 +631,8 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char * Returns the number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ -int usb_get_string(struct usb_device *dev, unsigned short langid, - unsigned char index, void *buf, int size) +static int usb_get_string(struct usb_device *dev, unsigned short langid, + unsigned char index, void *buf, int size) { int i; int result; @@ -1488,7 +1488,6 @@ EXPORT_SYMBOL(usb_sg_wait); // synchronous control message convenience routines EXPORT_SYMBOL(usb_get_descriptor); EXPORT_SYMBOL(usb_get_status); -EXPORT_SYMBOL(usb_get_string); EXPORT_SYMBOL(usb_string); // synchronous calls that also maintain usbcore state -- cgit v1.2.2 From 35cce732d9d4d9af6b4ad4d26d8f8c0eddb573a2 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Thu, 12 Jan 2006 20:35:25 +0200 Subject: [PATCH] USB: remove LINUX_VERSION_CODE macro usage This patch removes unnecessary LINUX_VERSION_CODE macro usage from drivers/usb/. Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/pwc/pwc-ctrl.c | 1 - drivers/usb/media/pwc/pwc-if.c | 6 +----- drivers/usb/misc/sisusbvga/sisusb.h | 8 -------- 3 files changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c index 3ebb6e9cdf92..0398b812e0ce 100644 --- a/drivers/usb/media/pwc/pwc-ctrl.c +++ b/drivers/usb/media/pwc/pwc-ctrl.c @@ -41,7 +41,6 @@ #include #endif #include -#include #include "pwc.h" #include "pwc-ioctl.h" diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c index 4f9b0dc6fd7b..db6753dc5ba5 100644 --- a/drivers/usb/media/pwc/pwc-if.c +++ b/drivers/usb/media/pwc/pwc-if.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include "pwc.h" @@ -827,13 +826,10 @@ static int pwc_isoc_init(struct pwc_device *pdev) /* Get the current alternate interface, adjust packet size */ if (!udev->actconfig) return -EFAULT; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) - idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate]; -#else + intf = usb_ifnum_to_if(udev, 0); if (intf) idesc = usb_altnum_to_altsetting(intf, pdev->valternate); -#endif if (!idesc) return -EFAULT; diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index 1d7a77cc7c4a..a716825d1f9b 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h @@ -37,24 +37,16 @@ #ifndef _SISUSB_H_ #define _SISUSB_H_ -#include #ifdef CONFIG_COMPAT -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10) -#include -#define SISUSB_OLD_CONFIG_COMPAT -#else #define SISUSB_NEW_CONFIG_COMPAT #endif -#endif /* For older kernels, support for text consoles is by default * off. To ensable text console support, change the following: */ #if 0 -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) #define CONFIG_USB_SISUSBVGA_CON #endif -#endif /* Version Information */ -- cgit v1.2.2 From 4186ecf8ad16dd05759a09594de6a87e48759ba6 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 11 Jan 2006 15:55:29 +0100 Subject: [PATCH] USB: convert a bunch of USB semaphores to mutexes the patch below converts a bunch of semaphores-used-as-mutex in the USB code to mutexes Signed-off-by: Arjan van de Ven Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 23 +++--- drivers/usb/class/usblp.c | 15 ++-- drivers/usb/core/devices.c | 7 +- drivers/usb/core/hcd.c | 25 ++++--- drivers/usb/core/hcd.h | 2 +- drivers/usb/core/hub.c | 7 +- drivers/usb/core/notify.c | 15 ++-- drivers/usb/core/usb.c | 5 +- drivers/usb/image/mdc800.c | 63 ++++++++-------- drivers/usb/input/ati_remote.c | 2 - drivers/usb/media/dabusb.c | 31 ++++---- drivers/usb/media/dabusb.h | 2 +- drivers/usb/media/ov511.c | 91 +++++++++++------------ drivers/usb/media/ov511.h | 11 ++- drivers/usb/media/se401.c | 12 +-- drivers/usb/media/se401.h | 3 +- drivers/usb/media/sn9c102.h | 5 +- drivers/usb/media/sn9c102_core.c | 156 +++++++++++++++++++-------------------- drivers/usb/media/stv680.c | 13 ++-- drivers/usb/media/stv680.h | 2 +- drivers/usb/media/usbvideo.c | 28 +++---- drivers/usb/media/usbvideo.h | 5 +- drivers/usb/media/vicam.c | 21 +++--- drivers/usb/media/w9968cf.c | 75 ++++++++++--------- drivers/usb/media/w9968cf.h | 14 +--- drivers/usb/misc/idmouse.c | 25 ++++--- drivers/usb/misc/ldusb.c | 11 +-- drivers/usb/misc/legousbtower.c | 11 +-- drivers/usb/mon/mon_main.c | 19 ++--- drivers/usb/mon/mon_text.c | 21 +++--- drivers/usb/mon/usb_mon.h | 2 +- drivers/usb/storage/scsiglue.c | 9 ++- drivers/usb/storage/usb.c | 25 ++++--- drivers/usb/storage/usb.h | 5 +- 34 files changed, 389 insertions(+), 372 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 97bdeb1c2181..6dd339f4c0fc 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +81,7 @@ static struct usb_driver acm_driver; static struct tty_driver *acm_tty_driver; static struct acm *acm_table[ACM_TTY_MINORS]; -static DECLARE_MUTEX(open_sem); +static DEFINE_MUTEX(open_mutex); #define ACM_READY(acm) (acm && acm->dev && acm->used) @@ -431,8 +432,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) int rv = -EINVAL; int i; dbg("Entering acm_tty_open.\n"); - - down(&open_sem); + + mutex_lock(&open_mutex); acm = acm_table[tty->index]; if (!acm || !acm->dev) @@ -474,14 +475,14 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) done: err_out: - up(&open_sem); + mutex_unlock(&open_mutex); return rv; full_bailout: usb_kill_urb(acm->ctrlurb); bail_out: acm->used--; - up(&open_sem); + mutex_unlock(&open_mutex); return -EIO; } @@ -507,7 +508,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) if (!acm || !acm->used) return; - down(&open_sem); + mutex_lock(&open_mutex); if (!--acm->used) { if (acm->dev) { acm_set_control(acm, acm->ctrlout = 0); @@ -518,7 +519,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) } else acm_tty_unregister(acm); } - up(&open_sem); + mutex_unlock(&open_mutex); } static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -1013,9 +1014,9 @@ static void acm_disconnect(struct usb_interface *intf) return; } - down(&open_sem); + mutex_lock(&open_mutex); if (!usb_get_intfdata(intf)) { - up(&open_sem); + mutex_unlock(&open_mutex); return; } acm->dev = NULL; @@ -1045,11 +1046,11 @@ static void acm_disconnect(struct usb_interface *intf) if (!acm->used) { acm_tty_unregister(acm); - up(&open_sem); + mutex_unlock(&open_mutex); return; } - up(&open_sem); + mutex_unlock(&open_mutex); if (acm->tty) tty_hangup(acm->tty); diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index d34848ac30b0..48dee4b8d8e5 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -55,6 +55,7 @@ #include #include #include +#include #undef DEBUG #include @@ -223,7 +224,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp); /* forward reference to make our lives easier */ static struct usb_driver usblp_driver; -static DECLARE_MUTEX(usblp_sem); /* locks the existence of usblp's */ +static DEFINE_MUTEX(usblp_mutex); /* locks the existence of usblp's */ /* * Functions for usblp control messages. @@ -351,7 +352,7 @@ static int usblp_open(struct inode *inode, struct file *file) if (minor < 0) return -ENODEV; - down (&usblp_sem); + mutex_lock (&usblp_mutex); retval = -ENODEV; intf = usb_find_interface(&usblp_driver, minor); @@ -399,7 +400,7 @@ static int usblp_open(struct inode *inode, struct file *file) } } out: - up (&usblp_sem); + mutex_unlock (&usblp_mutex); return retval; } @@ -425,13 +426,13 @@ static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; - down (&usblp_sem); + mutex_lock (&usblp_mutex); usblp->used = 0; if (usblp->present) { usblp_unlink_urbs(usblp); } else /* finish cleanup from disconnect */ usblp_cleanup (usblp); - up (&usblp_sem); + mutex_unlock (&usblp_mutex); return 0; } @@ -1152,7 +1153,7 @@ static void usblp_disconnect(struct usb_interface *intf) device_remove_file(&intf->dev, &dev_attr_ieee1284_id); - down (&usblp_sem); + mutex_lock (&usblp_mutex); down (&usblp->sem); usblp->present = 0; usb_set_intfdata (intf, NULL); @@ -1166,7 +1167,7 @@ static void usblp_disconnect(struct usb_interface *intf) if (!usblp->used) usblp_cleanup (usblp); - up (&usblp_sem); + mutex_unlock (&usblp_mutex); } static struct usb_device_id usblp_ids [] = { diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 2684e15b813b..c0f37343a276 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include "usb.h" @@ -570,7 +571,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte if (!access_ok(VERIFY_WRITE, buf, nbytes)) return -EFAULT; - down (&usb_bus_list_lock); + mutex_lock(&usb_bus_list_lock); /* print devices for all busses */ list_for_each_entry(bus, &usb_bus_list, bus_list) { /* recurse through all children of the root hub */ @@ -580,12 +581,12 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0); usb_unlock_device(bus->root_hub); if (ret < 0) { - up(&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); return ret; } total_written += ret; } - up (&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); return total_written; } diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0018bbc4de34..9223f2869674 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -93,7 +94,7 @@ struct usb_busmap { static struct usb_busmap busmap; /* used when updating list of hcds */ -DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ +DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */ EXPORT_SYMBOL_GPL (usb_bus_list_lock); /* used for controlling access to virtual root hubs */ @@ -761,14 +762,14 @@ static int usb_register_bus(struct usb_bus *bus) { int busnum; - down (&usb_bus_list_lock); + mutex_lock(&usb_bus_list_lock); busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); if (busnum < USB_MAXBUS) { set_bit (busnum, busmap.busmap); bus->busnum = busnum; } else { printk (KERN_ERR "%s: too many buses\n", usbcore_name); - up(&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); return -E2BIG; } @@ -776,7 +777,7 @@ static int usb_register_bus(struct usb_bus *bus) bus->controller, "usb_host%d", busnum); if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); - up(&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); return PTR_ERR(bus->class_dev); } @@ -784,7 +785,7 @@ static int usb_register_bus(struct usb_bus *bus) /* Add it to the local list of buses */ list_add (&bus->bus_list, &usb_bus_list); - up (&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); usb_notify_add_bus(bus); @@ -809,9 +810,9 @@ static void usb_deregister_bus (struct usb_bus *bus) * controller code, as well as having it call this when cleaning * itself up */ - down (&usb_bus_list_lock); + mutex_lock(&usb_bus_list_lock); list_del (&bus->bus_list); - up (&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); usb_notify_remove_bus(bus); @@ -844,14 +845,14 @@ static int register_root_hub (struct usb_device *usb_dev, set_bit (devnum, usb_dev->bus->devmap.devicemap); usb_set_device_state(usb_dev, USB_STATE_ADDRESS); - down (&usb_bus_list_lock); + mutex_lock(&usb_bus_list_lock); usb_dev->bus->root_hub = usb_dev; usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); if (retval != sizeof usb_dev->descriptor) { usb_dev->bus->root_hub = NULL; - up (&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); dev_dbg (parent_dev, "can't read %s device descriptor %d\n", usb_dev->dev.bus_id, retval); return (retval < 0) ? retval : -EMSGSIZE; @@ -863,7 +864,7 @@ static int register_root_hub (struct usb_device *usb_dev, dev_err (parent_dev, "can't register root hub for %s, %d\n", usb_dev->dev.bus_id, retval); } - up (&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); if (retval == 0) { spin_lock_irq (&hcd_root_hub_lock); @@ -1891,9 +1892,9 @@ void usb_remove_hcd(struct usb_hcd *hcd) hcd->rh_registered = 0; spin_unlock_irq (&hcd_root_hub_lock); - down(&usb_bus_list_lock); + mutex_lock(&usb_bus_list_lock); usb_disconnect(&hcd->self.root_hub); - up(&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); hcd->poll_rh = 0; del_timer_sync(&hcd->rh_timer); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 591b5aad1a18..f44a2fe62a9d 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -364,7 +364,7 @@ extern void usb_set_device_state(struct usb_device *udev, /* exported only within usbcore */ extern struct list_head usb_bus_list; -extern struct semaphore usb_bus_list_lock; +extern struct mutex usb_bus_list_lock; extern wait_queue_head_t usb_kill_urb_queue; extern struct usb_bus *usb_bus_get (struct usb_bus *bus); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 650d5ee5871b..867fa8130238 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -2162,7 +2163,7 @@ static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter) { - static DECLARE_MUTEX(usb_address0_sem); + static DEFINE_MUTEX(usb_address0_mutex); struct usb_device *hdev = hub->hdev; int i, j, retval; @@ -2183,7 +2184,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (oldspeed == USB_SPEED_LOW) delay = HUB_LONG_RESET_TIME; - down(&usb_address0_sem); + mutex_lock(&usb_address0_mutex); /* Reset the device; full speed may morph to high speed */ retval = hub_port_reset(hub, port1, udev, delay); @@ -2381,7 +2382,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, fail: if (retval) hub_port_disable(hub, port1, 0); - up(&usb_address0_sem); + mutex_unlock(&usb_address0_mutex); return retval; } diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index fbbebab52fbd..4b55285de9a0 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -13,16 +13,17 @@ #include #include #include +#include #include "usb.h" static struct notifier_block *usb_notifier_list; -static DECLARE_MUTEX(usb_notifier_lock); +static DEFINE_MUTEX(usb_notifier_lock); static void usb_notifier_chain_register(struct notifier_block **list, struct notifier_block *n) { - down(&usb_notifier_lock); + mutex_lock(&usb_notifier_lock); while (*list) { if (n->priority > (*list)->priority) break; @@ -30,13 +31,13 @@ static void usb_notifier_chain_register(struct notifier_block **list, } n->next = *list; *list = n; - up(&usb_notifier_lock); + mutex_unlock(&usb_notifier_lock); } static void usb_notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n) { - down(&usb_notifier_lock); + mutex_lock(&usb_notifier_lock); while ((*nl)!=NULL) { if ((*nl)==n) { *nl = n->next; @@ -45,7 +46,7 @@ static void usb_notifier_chain_unregister(struct notifier_block **nl, nl=&((*nl)->next); } exit: - up(&usb_notifier_lock); + mutex_unlock(&usb_notifier_lock); } static int usb_notifier_call_chain(struct notifier_block **n, @@ -54,7 +55,7 @@ static int usb_notifier_call_chain(struct notifier_block **n, int ret=NOTIFY_DONE; struct notifier_block *nb = *n; - down(&usb_notifier_lock); + mutex_lock(&usb_notifier_lock); while (nb) { ret = nb->notifier_call(nb,val,v); if (ret&NOTIFY_STOP_MASK) { @@ -63,7 +64,7 @@ static int usb_notifier_call_chain(struct notifier_block **n, nb = nb->next; } exit: - up(&usb_notifier_lock); + mutex_unlock(&usb_notifier_lock); return ret; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 13d1d367f7f1..d7352aa73b5e 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -639,7 +640,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) struct usb_bus *bus; struct usb_device *dev = NULL; - down(&usb_bus_list_lock); + mutex_lock(&usb_bus_list_lock); for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { @@ -653,7 +654,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) goto exit; } exit: - up(&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); return dev; } diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 4e3e4d048c14..08daf400f985 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -96,6 +96,7 @@ #include #include #include +#include #include #include @@ -169,7 +170,7 @@ struct mdc800_data int out_count; // Bytes in the buffer int open; // Camera device open ? - struct semaphore io_lock; // IO -lock + struct mutex io_lock; // IO -lock char in [8]; // Command Input Buffer int in_count; @@ -497,7 +498,7 @@ static int mdc800_usb_probe (struct usb_interface *intf, info ("Found Mustek MDC800 on USB."); - down (&mdc800->io_lock); + mutex_lock(&mdc800->io_lock); retval = usb_register_dev(intf, &mdc800_class); if (retval) { @@ -542,7 +543,7 @@ static int mdc800_usb_probe (struct usb_interface *intf, mdc800->state=READY; - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); usb_set_intfdata(intf, mdc800); return 0; @@ -620,7 +621,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file) int retval=0; int errn=0; - down (&mdc800->io_lock); + mutex_lock(&mdc800->io_lock); if (mdc800->state == NOT_CONNECTED) { @@ -656,7 +657,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file) dbg ("Mustek MDC800 device opened."); error_out: - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return errn; } @@ -669,7 +670,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file) int retval=0; dbg ("Mustek MDC800 device closed."); - down (&mdc800->io_lock); + mutex_lock(&mdc800->io_lock); if (mdc800->open && (mdc800->state != NOT_CONNECTED)) { usb_kill_urb(mdc800->irq_urb); @@ -682,7 +683,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file) retval=-EIO; } - up(&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return retval; } @@ -695,21 +696,21 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l size_t left=len, sts=len; /* single transfer size */ char __user *ptr = buf; - down (&mdc800->io_lock); + mutex_lock(&mdc800->io_lock); if (mdc800->state == NOT_CONNECTED) { - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EBUSY; } if (mdc800->state == WORKING) { warn ("Illegal State \"working\" reached during read ?!"); - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EBUSY; } if (!mdc800->open) { - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EBUSY; } @@ -717,7 +718,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l { if (signal_pending (current)) { - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EINTR; } @@ -736,7 +737,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL)) { err ("Can't submit download urb (status=%i)",mdc800->download_urb->status); - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return len-left; } wait_event_timeout(mdc800->download_wait, mdc800->downloaded, @@ -745,14 +746,14 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l if (mdc800->download_urb->status != 0) { err ("request download-bytes fails (status=%i)",mdc800->download_urb->status); - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return len-left; } } else { /* No more bytes -> that's an error*/ - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EIO; } } @@ -761,7 +762,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l /* Copy Bytes */ if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr], sts)) { - up(&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EFAULT; } ptr+=sts; @@ -770,7 +771,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l } } - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return len-left; } @@ -785,15 +786,15 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s { size_t i=0; - down (&mdc800->io_lock); + mutex_lock(&mdc800->io_lock); if (mdc800->state != READY) { - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EBUSY; } if (!mdc800->open ) { - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EBUSY; } @@ -802,13 +803,13 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s unsigned char c; if (signal_pending (current)) { - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EINTR; } if(get_user(c, buf+i)) { - up(&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EFAULT; } @@ -829,7 +830,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s } else { - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EIO; } @@ -841,7 +842,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s if (mdc800_usb_waitForIRQ (0,TO_GET_READY)) { err ("Camera didn't get ready.\n"); - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EIO; } @@ -853,7 +854,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL)) { err ("submitting write urb fails (status=%i)", mdc800->write_urb->status); - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EIO; } wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000); @@ -861,7 +862,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s if (mdc800->state == WORKING) { usb_kill_urb(mdc800->write_urb); - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EIO; } @@ -873,7 +874,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s { err ("call 0x07 before 0x05,0x3e"); mdc800->state=READY; - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EIO; } mdc800->pic_len=-1; @@ -892,7 +893,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ)) { err ("requesting answer from irq fails"); - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EIO; } @@ -920,7 +921,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND)) { err ("Command Timeout."); - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return -EIO; } } @@ -930,7 +931,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s } i++; } - up (&mdc800->io_lock); + mutex_unlock(&mdc800->io_lock); return i; } @@ -984,7 +985,7 @@ static int __init usb_mdc800_init (void) mdc800->dev = NULL; mdc800->state=NOT_CONNECTED; - init_MUTEX (&mdc800->io_lock); + mutex_init (&mdc800->io_lock); init_waitqueue_head (&mdc800->irq_wait); init_waitqueue_head (&mdc800->write_wait); diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index f7bdc506e613..99f986cb6e95 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -159,8 +159,6 @@ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; */ #define FILTER_TIME (HZ / 20) -static DECLARE_MUTEX(disconnect_sem); - struct ati_remote { struct input_dev *idev; struct usb_device *udev; diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c index 6f560fe9a519..1774ab7a40d2 100644 --- a/drivers/usb/media/dabusb.c +++ b/drivers/usb/media/dabusb.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "dabusb.h" #include "dabfirmware.h" @@ -570,7 +571,7 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l s->readptr = 0; } } - err: //up(&s->mutex); + err: //mutex_unlock(&s->mutex); return ret; } @@ -585,10 +586,10 @@ static int dabusb_open (struct inode *inode, struct file *file) s = &dabusb[devnum - DABUSB_MINOR]; dbg("dabusb_open"); - down (&s->mutex); + mutex_lock(&s->mutex); while (!s->usbdev || s->opened) { - up (&s->mutex); + mutex_unlock(&s->mutex); if (file->f_flags & O_NONBLOCK) { return -EBUSY; @@ -598,15 +599,15 @@ static int dabusb_open (struct inode *inode, struct file *file) if (signal_pending (current)) { return -EAGAIN; } - down (&s->mutex); + mutex_lock(&s->mutex); } if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { - up(&s->mutex); + mutex_unlock(&s->mutex); err("set_interface failed"); return -EINVAL; } s->opened = 1; - up (&s->mutex); + mutex_unlock(&s->mutex); file->f_pos = 0; file->private_data = s; @@ -620,10 +621,10 @@ static int dabusb_release (struct inode *inode, struct file *file) dbg("dabusb_release"); - down (&s->mutex); + mutex_lock(&s->mutex); dabusb_stop (s); dabusb_free_buffers (s); - up (&s->mutex); + mutex_unlock(&s->mutex); if (!s->remove_pending) { if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) @@ -648,10 +649,10 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm if (s->remove_pending) return -EIO; - down (&s->mutex); + mutex_lock(&s->mutex); if (!s->usbdev) { - up (&s->mutex); + mutex_unlock(&s->mutex); return -EIO; } @@ -691,7 +692,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm ret = -ENOIOCTLCMD; break; } - up (&s->mutex); + mutex_unlock(&s->mutex); return ret; } @@ -737,7 +738,7 @@ static int dabusb_probe (struct usb_interface *intf, s = &dabusb[intf->minor]; - down (&s->mutex); + mutex_lock(&s->mutex); s->remove_pending = 0; s->usbdev = usbdev; s->devnum = intf->minor; @@ -760,7 +761,7 @@ static int dabusb_probe (struct usb_interface *intf, } dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber); usb_set_intfdata (intf, s); - up (&s->mutex); + mutex_unlock(&s->mutex); retval = usb_register_dev(intf, &dabusb_class); if (retval) { @@ -771,7 +772,7 @@ static int dabusb_probe (struct usb_interface *intf, return 0; reject: - up (&s->mutex); + mutex_unlock(&s->mutex); s->usbdev = NULL; return -ENODEV; } @@ -828,7 +829,7 @@ static int __init dabusb_init (void) for (u = 0; u < NRDABUSB; u++) { pdabusb_t s = &dabusb[u]; memset (s, 0, sizeof (dabusb_t)); - init_MUTEX (&s->mutex); + mutex_init (&s->mutex); s->usbdev = NULL; s->total_buffer_size = buffers; init_waitqueue_head (&s->wait); diff --git a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h index 10b666e43abc..96b03e4af8b9 100644 --- a/drivers/usb/media/dabusb.h +++ b/drivers/usb/media/dabusb.h @@ -18,7 +18,7 @@ typedef enum { _stopped=0, _started } driver_state_t; typedef struct { - struct semaphore mutex; + struct mutex mutex; struct usb_device *usbdev; wait_queue_head_t wait; wait_queue_head_t remove_ok; diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c index 51e9cc06f7e3..cfec8c61574e 100644 --- a/drivers/usb/media/ov511.c +++ b/drivers/usb/media/ov511.c @@ -365,14 +365,14 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) PDEBUG(5, "0x%02X:0x%02X", reg, value); - down(&ov->cbuf_lock); + mutex_lock(&ov->cbuf_lock); ov->cbuf[0] = value; rc = usb_control_msg(ov->dev, usb_sndctrlpipe(ov->dev, 0), (ov->bclass == BCL_OV518)?1:2 /* REG_IO */, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, (__u16)reg, &ov->cbuf[0], 1, 1000); - up(&ov->cbuf_lock); + mutex_unlock(&ov->cbuf_lock); if (rc < 0) err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc)); @@ -387,7 +387,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg) { int rc; - down(&ov->cbuf_lock); + mutex_lock(&ov->cbuf_lock); rc = usb_control_msg(ov->dev, usb_rcvctrlpipe(ov->dev, 0), (ov->bclass == BCL_OV518)?1:3 /* REG_IO */, @@ -401,7 +401,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg) PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); } - up(&ov->cbuf_lock); + mutex_unlock(&ov->cbuf_lock); return rc; } @@ -444,7 +444,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); - down(&ov->cbuf_lock); + mutex_lock(&ov->cbuf_lock); *((__le32 *)ov->cbuf) = __cpu_to_le32(val); @@ -453,7 +453,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) 1 /* REG_IO */, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, (__u16)reg, ov->cbuf, n, 1000); - up(&ov->cbuf_lock); + mutex_unlock(&ov->cbuf_lock); if (rc < 0) err("reg write multiple: error %d: %s", rc, @@ -768,14 +768,14 @@ i2c_r(struct usb_ov511 *ov, unsigned char reg) { int rc; - down(&ov->i2c_lock); + mutex_lock(&ov->i2c_lock); if (ov->bclass == BCL_OV518) rc = ov518_i2c_read_internal(ov, reg); else rc = ov511_i2c_read_internal(ov, reg); - up(&ov->i2c_lock); + mutex_unlock(&ov->i2c_lock); return rc; } @@ -785,14 +785,14 @@ i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) { int rc; - down(&ov->i2c_lock); + mutex_lock(&ov->i2c_lock); if (ov->bclass == BCL_OV518) rc = ov518_i2c_write_internal(ov, reg, value); else rc = ov511_i2c_write_internal(ov, reg, value); - up(&ov->i2c_lock); + mutex_unlock(&ov->i2c_lock); return rc; } @@ -842,9 +842,9 @@ i2c_w_mask(struct usb_ov511 *ov, { int rc; - down(&ov->i2c_lock); + mutex_lock(&ov->i2c_lock); rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); - up(&ov->i2c_lock); + mutex_unlock(&ov->i2c_lock); return rc; } @@ -880,7 +880,7 @@ i2c_w_slave(struct usb_ov511 *ov, { int rc = 0; - down(&ov->i2c_lock); + mutex_lock(&ov->i2c_lock); /* Set new slave IDs */ rc = i2c_set_slave_internal(ov, slave); @@ -894,7 +894,7 @@ out: if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) err("Couldn't restore primary I2C slave"); - up(&ov->i2c_lock); + mutex_unlock(&ov->i2c_lock); return rc; } @@ -906,7 +906,7 @@ i2c_r_slave(struct usb_ov511 *ov, { int rc; - down(&ov->i2c_lock); + mutex_lock(&ov->i2c_lock); /* Set new slave IDs */ rc = i2c_set_slave_internal(ov, slave); @@ -923,7 +923,7 @@ out: if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) err("Couldn't restore primary I2C slave"); - up(&ov->i2c_lock); + mutex_unlock(&ov->i2c_lock); return rc; } @@ -933,7 +933,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) { int rc; - down(&ov->i2c_lock); + mutex_lock(&ov->i2c_lock); rc = i2c_set_slave_internal(ov, sid); if (rc < 0) @@ -942,7 +942,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) // FIXME: Is this actually necessary? rc = ov51x_reset(ov, OV511_RESET_NOREGS); out: - up(&ov->i2c_lock); + mutex_unlock(&ov->i2c_lock); return rc; } @@ -3832,7 +3832,7 @@ ov51x_alloc(struct usb_ov511 *ov) const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); PDEBUG(4, "entered"); - down(&ov->buf_lock); + mutex_lock(&ov->buf_lock); if (ov->buf_state == BUF_ALLOCATED) goto out; @@ -3879,12 +3879,12 @@ ov51x_alloc(struct usb_ov511 *ov) ov->buf_state = BUF_ALLOCATED; out: - up(&ov->buf_lock); + mutex_unlock(&ov->buf_lock); PDEBUG(4, "leaving"); return 0; error: ov51x_do_dealloc(ov); - up(&ov->buf_lock); + mutex_unlock(&ov->buf_lock); PDEBUG(4, "errored"); return -ENOMEM; } @@ -3893,9 +3893,9 @@ static void ov51x_dealloc(struct usb_ov511 *ov) { PDEBUG(4, "entered"); - down(&ov->buf_lock); + mutex_lock(&ov->buf_lock); ov51x_do_dealloc(ov); - up(&ov->buf_lock); + mutex_unlock(&ov->buf_lock); PDEBUG(4, "leaving"); } @@ -3914,7 +3914,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file) PDEBUG(4, "opening"); - down(&ov->lock); + mutex_lock(&ov->lock); err = -EBUSY; if (ov->user) @@ -3958,7 +3958,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file) ov51x_led_control(ov, 1); out: - up(&ov->lock); + mutex_unlock(&ov->lock); return err; } @@ -3970,7 +3970,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file) PDEBUG(4, "ov511_close"); - down(&ov->lock); + mutex_lock(&ov->lock); ov->user--; ov51x_stop_isoc(ov); @@ -3981,15 +3981,15 @@ ov51x_v4l1_close(struct inode *inode, struct file *file) if (ov->dev) ov51x_dealloc(ov); - up(&ov->lock); + mutex_unlock(&ov->lock); /* Device unplugged while open. Only a minimum of unregistration is done * here; the disconnect callback already did the rest. */ if (!ov->dev) { - down(&ov->cbuf_lock); + mutex_lock(&ov->cbuf_lock); kfree(ov->cbuf); ov->cbuf = NULL; - up(&ov->cbuf_lock); + mutex_unlock(&ov->cbuf_lock); ov51x_dealloc(ov); kfree(ov); @@ -4449,12 +4449,12 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file, struct usb_ov511 *ov = video_get_drvdata(vdev); int rc; - if (down_interruptible(&ov->lock)) + if (mutex_lock_interruptible(&ov->lock)) return -EINTR; rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal); - up(&ov->lock); + mutex_unlock(&ov->lock); return rc; } @@ -4468,7 +4468,7 @@ ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos) int i, rc = 0, frmx = -1; struct ov511_frame *frame; - if (down_interruptible(&ov->lock)) + if (mutex_lock_interruptible(&ov->lock)) return -EINTR; PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); @@ -4604,11 +4604,11 @@ restart: PDEBUG(4, "read finished, returning %ld (sweet)", count); - up(&ov->lock); + mutex_unlock(&ov->lock); return count; error: - up(&ov->lock); + mutex_unlock(&ov->lock); return rc; } @@ -4631,14 +4631,14 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) return -EINVAL; - if (down_interruptible(&ov->lock)) + if (mutex_lock_interruptible(&ov->lock)) return -EINTR; pos = (unsigned long)ov->fbuf; while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&ov->lock); + mutex_unlock(&ov->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -4649,7 +4649,7 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) size = 0; } - up(&ov->lock); + mutex_unlock(&ov->lock); return 0; } @@ -5738,11 +5738,10 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) init_waitqueue_head(&ov->wq); - init_MUTEX(&ov->lock); /* to 1 == available */ - init_MUTEX(&ov->buf_lock); - init_MUTEX(&ov->param_lock); - init_MUTEX(&ov->i2c_lock); - init_MUTEX(&ov->cbuf_lock); + mutex_init(&ov->lock); /* to 1 == available */ + mutex_init(&ov->buf_lock); + mutex_init(&ov->i2c_lock); + mutex_init(&ov->cbuf_lock); ov->buf_state = BUF_NOT_ALLOCATED; @@ -5833,10 +5832,10 @@ error: } if (ov->cbuf) { - down(&ov->cbuf_lock); + mutex_lock(&ov->cbuf_lock); kfree(ov->cbuf); ov->cbuf = NULL; - up(&ov->cbuf_lock); + mutex_unlock(&ov->cbuf_lock); } kfree(ov); @@ -5881,10 +5880,10 @@ ov51x_disconnect(struct usb_interface *intf) /* Free the memory */ if (ov && !ov->user) { - down(&ov->cbuf_lock); + mutex_lock(&ov->cbuf_lock); kfree(ov->cbuf); ov->cbuf = NULL; - up(&ov->cbuf_lock); + mutex_unlock(&ov->cbuf_lock); ov51x_dealloc(ov); kfree(ov); diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h index 086509a137c6..bce9b3633889 100644 --- a/drivers/usb/media/ov511.h +++ b/drivers/usb/media/ov511.h @@ -5,6 +5,7 @@ #include #include #include +#include #define OV511_DEBUG /* Turn on debug messages */ @@ -435,7 +436,7 @@ struct usb_ov511 { int led_policy; /* LED: off|on|auto; OV511+ only */ - struct semaphore lock; /* Serializes user-accessible operations */ + struct mutex lock; /* Serializes user-accessible operations */ int user; /* user count for exclusive use */ int streaming; /* Are we streaming Isochronous? */ @@ -473,11 +474,9 @@ struct usb_ov511 { int packet_size; /* Frame size per isoc desc */ int packet_numbering; /* Is ISO frame numbering enabled? */ - struct semaphore param_lock; /* params lock for this camera */ - /* Framebuffer/sbuf management */ int buf_state; - struct semaphore buf_lock; + struct mutex buf_lock; struct ov51x_decomp_ops *decomp_ops; @@ -494,12 +493,12 @@ struct usb_ov511 { int pal; /* Device is designed for PAL resolution */ /* I2C interface */ - struct semaphore i2c_lock; /* Protect I2C controller regs */ + struct mutex i2c_lock; /* Protect I2C controller regs */ unsigned char primary_i2c_slave; /* I2C write id of sensor */ /* Control transaction stuff */ unsigned char *cbuf; /* Buffer for payload */ - struct semaphore cbuf_lock; + struct mutex cbuf_lock; }; /* Used to represent a list of values and their respective symbolic names */ diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c index 2ba562285fda..8c3b1ad8a8fd 100644 --- a/drivers/usb/media/se401.c +++ b/drivers/usb/media/se401.c @@ -1157,21 +1157,21 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma) unsigned long size = vma->vm_end-vma->vm_start; unsigned long page, pos; - down(&se401->lock); + mutex_lock(&se401->lock); if (se401->dev == NULL) { - up(&se401->lock); + mutex_unlock(&se401->lock); return -EIO; } if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { - up(&se401->lock); + mutex_unlock(&se401->lock); return -EINVAL; } pos = (unsigned long)se401->fbuf; while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&se401->lock); + mutex_unlock(&se401->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -1181,7 +1181,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma) else size = 0; } - up(&se401->lock); + mutex_unlock(&se401->lock); return 0; } @@ -1366,7 +1366,7 @@ static int se401_probe(struct usb_interface *intf, memcpy(&se401->vdev, &se401_template, sizeof(se401_template)); memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name)); init_waitqueue_head(&se401->wq); - init_MUTEX(&se401->lock); + mutex_init(&se401->lock); wmb(); if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { diff --git a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h index 2e5846f1eb20..e88a40d4c86a 100644 --- a/drivers/usb/media/se401.h +++ b/drivers/usb/media/se401.h @@ -5,6 +5,7 @@ #include #include #include +#include #define se401_DEBUG /* Turn on debug messages */ @@ -189,7 +190,7 @@ struct usb_se401 { int maxframesize; int cframesize; /* current framesize */ - struct semaphore lock; + struct mutex lock; int user; /* user count for exclusive use */ int removed; /* device disconnected */ diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h index 17d60c1eea7e..59e44be27cb4 100644 --- a/drivers/usb/media/sn9c102.h +++ b/drivers/usb/media/sn9c102.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "sn9c102_sensor.h" @@ -109,7 +110,7 @@ struct sn9c102_module_param { u8 force_munmap; }; -static DECLARE_MUTEX(sn9c102_sysfs_lock); +static DEFINE_MUTEX(sn9c102_sysfs_lock); static DECLARE_RWSEM(sn9c102_disconnect); struct sn9c102_device { @@ -141,7 +142,7 @@ struct sn9c102_device { enum sn9c102_dev_state state; u8 users; - struct semaphore dev_sem, fileop_sem; + struct mutex dev_mutex, fileop_mutex; spinlock_t queue_lock; wait_queue_head_t open, wait_frame, wait_stream; }; diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c index c81397e4714b..30119080871b 100644 --- a/drivers/usb/media/sn9c102_core.c +++ b/drivers/usb/media/sn9c102_core.c @@ -866,18 +866,18 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) struct sn9c102_device* cam; ssize_t count; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } count = sprintf(buf, "%u\n", cam->sysfs.reg); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return count; } @@ -890,18 +890,18 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) u8 index; ssize_t count; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } index = sn9c102_strtou8(buf, len, &count); if (index > 0x1f || !count) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -EINVAL; } @@ -910,7 +910,7 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg); DBG(3, "Written bytes: %zd", count); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return count; } @@ -922,17 +922,17 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) ssize_t count; int val; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -EIO; } @@ -940,7 +940,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return count; } @@ -954,24 +954,24 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) ssize_t count; int err; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } value = sn9c102_strtou8(buf, len, &count); if (!count) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -EINVAL; } err = sn9c102_write_reg(cam, value, cam->sysfs.reg); if (err) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -EIO; } @@ -979,7 +979,7 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) cam->sysfs.reg, value); DBG(3, "Written bytes: %zd", count); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return count; } @@ -990,12 +990,12 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) struct sn9c102_device* cam; ssize_t count; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } @@ -1003,7 +1003,7 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return count; } @@ -1016,18 +1016,18 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) u8 index; ssize_t count; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } index = sn9c102_strtou8(buf, len, &count); if (!count) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -EINVAL; } @@ -1036,7 +1036,7 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); DBG(3, "Written bytes: %zd", count); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return count; } @@ -1048,22 +1048,22 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) ssize_t count; int val; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENOSYS; } if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -EIO; } @@ -1071,7 +1071,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return count; } @@ -1085,29 +1085,29 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) ssize_t count; int err; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENOSYS; } value = sn9c102_strtou8(buf, len, &count); if (!count) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -EINVAL; } err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); if (err) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -EIO; } @@ -1115,7 +1115,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) cam->sysfs.i2c_reg, value); DBG(3, "Written bytes: %zd", count); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return count; } @@ -1130,18 +1130,18 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) u8 value; ssize_t count; - if (down_interruptible(&sn9c102_sysfs_lock)) + if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); return -ENODEV; } bridge = cam->bridge; - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); value = sn9c102_strtou8(buf, len, &count); if (!count) @@ -1404,7 +1404,7 @@ static int sn9c102_init(struct sn9c102_device* cam) } if (!(cam->state & DEV_INITIALIZED)) { - init_MUTEX(&cam->fileop_sem); + mutex_init(&cam->fileop_mutex); spin_lock_init(&cam->queue_lock); init_waitqueue_head(&cam->wait_frame); init_waitqueue_head(&cam->wait_stream); @@ -1422,13 +1422,13 @@ static int sn9c102_init(struct sn9c102_device* cam) static void sn9c102_release_resources(struct sn9c102_device* cam) { - down(&sn9c102_sysfs_lock); + mutex_lock(&sn9c102_sysfs_lock); DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); - up(&sn9c102_sysfs_lock); + mutex_unlock(&sn9c102_sysfs_lock); kfree(cam->control_buffer); } @@ -1449,7 +1449,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp) cam = video_get_drvdata(video_devdata(filp)); - if (down_interruptible(&cam->dev_sem)) { + if (mutex_lock_interruptible(&cam->dev_mutex)) { up_read(&sn9c102_disconnect); return -ERESTARTSYS; } @@ -1461,7 +1461,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp) err = -EWOULDBLOCK; goto out; } - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); err = wait_event_interruptible_exclusive(cam->open, cam->state & DEV_DISCONNECTED || !cam->users); @@ -1473,7 +1473,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp) up_read(&sn9c102_disconnect); return -ENODEV; } - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); } @@ -1501,7 +1501,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); out: - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); up_read(&sn9c102_disconnect); return err; } @@ -1511,7 +1511,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp) { struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); - down(&cam->dev_sem); /* prevent disconnect() to be called */ + mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ sn9c102_stop_transfer(cam); @@ -1519,7 +1519,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp) if (cam->state & DEV_DISCONNECTED) { sn9c102_release_resources(cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); kfree(cam); return 0; } @@ -1529,7 +1529,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); return 0; } @@ -1543,33 +1543,33 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) unsigned long lock_flags; int err = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } if (cam->io == IO_MMAP) { DBG(3, "Close and open the device again to choose " "the read method"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } if (cam->io == IO_NONE) { if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { DBG(1, "read() failed, not enough memory"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENOMEM; } cam->io = IO_READ; @@ -1583,13 +1583,13 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) } if (!count) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return 0; } if (list_empty(&cam->outqueue)) { if (filp->f_flags & O_NONBLOCK) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } err = wait_event_interruptible @@ -1598,15 +1598,15 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) (cam->state & DEV_DISCONNECTED) || (cam->state & DEV_MISCONFIGURED) ); if (err) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return err; } if (cam->state & DEV_DISCONNECTED) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } } @@ -1634,7 +1634,7 @@ exit: PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index, count); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return count; } @@ -1647,7 +1647,7 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) unsigned long lock_flags; unsigned int mask = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return POLLERR; if (cam->state & DEV_DISCONNECTED) { @@ -1685,12 +1685,12 @@ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) if (!list_empty(&cam->outqueue)) mask |= POLLIN | POLLRDNORM; - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return mask; error: - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return POLLERR; } @@ -1724,25 +1724,25 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) void *pos; u32 i; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(cam->frame[0].buf.length)) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } @@ -1751,7 +1751,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) break; } if (i == cam->nbuffers) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } @@ -1761,7 +1761,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) pos = cam->frame[i].bufmem; while (size > 0) { /* size is page-aligned */ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } start += PAGE_SIZE; @@ -1774,7 +1774,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) sn9c102_vm_open(vma); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return 0; } @@ -2655,19 +2655,19 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp, struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); int err = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } @@ -2675,7 +2675,7 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp, err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return err; } @@ -2722,7 +2722,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - init_MUTEX(&cam->dev_sem); + mutex_init(&cam->dev_mutex); r = sn9c102_read_reg(cam, 0x00); if (r < 0 || r != 0x10) { @@ -2776,7 +2776,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); @@ -2786,7 +2786,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "Free /dev/videoX node not found"); video_nr[dev_nr] = -1; dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); goto fail; } @@ -2803,7 +2803,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) usb_set_intfdata(intf, cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); return 0; @@ -2827,7 +2827,7 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf) down_write(&sn9c102_disconnect); - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); DBG(2, "Disconnecting %s...", cam->v4ldev->name); @@ -2847,7 +2847,7 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf) sn9c102_release_resources(cam); } - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); if (!cam->users) kfree(cam); diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c index b497a6a0a206..b1a6be2958ed 100644 --- a/drivers/usb/media/stv680.c +++ b/drivers/usb/media/stv680.c @@ -67,6 +67,7 @@ #include #include #include +#include #include "stv680.h" @@ -1258,22 +1259,22 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma) unsigned long size = vma->vm_end-vma->vm_start; unsigned long page, pos; - down (&stv680->lock); + mutex_lock(&stv680->lock); if (stv680->udev == NULL) { - up (&stv680->lock); + mutex_unlock(&stv680->lock); return -EIO; } if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { - up (&stv680->lock); + mutex_unlock(&stv680->lock); return -EINVAL; } pos = (unsigned long) stv680->fbuf; while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up (&stv680->lock); + mutex_unlock(&stv680->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -1283,7 +1284,7 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma) else size = 0; } - up (&stv680->lock); + mutex_unlock(&stv680->lock); return 0; } @@ -1409,7 +1410,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); init_waitqueue_head (&stv680->wq); - init_MUTEX (&stv680->lock); + mutex_init (&stv680->lock); wmb (); if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h index b0551cdb280b..ea46e0001e6d 100644 --- a/drivers/usb/media/stv680.h +++ b/drivers/usb/media/stv680.h @@ -118,7 +118,7 @@ struct usb_stv { int origGain; int origMode; /* original camera mode */ - struct semaphore lock; /* to lock the structure */ + struct mutex lock; /* to lock the structure */ int user; /* user count for exclusive use */ int removed; /* device disconnected */ int streaming; /* Are we streaming video? */ diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c index 63d279ec722b..0b51fae720a9 100644 --- a/drivers/usb/media/usbvideo.c +++ b/drivers/usb/media/usbvideo.c @@ -714,7 +714,7 @@ int usbvideo_register( cams->md_module = md; if (cams->md_module == NULL) warn("%s: module == NULL!", __FUNCTION__); - init_MUTEX(&cams->lock); /* to 1 == available */ + mutex_init(&cams->lock); /* to 1 == available */ for (i = 0; i < num_cams; i++) { struct uvd *up = &cams->cam[i]; @@ -862,7 +862,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf) if (uvd->debug > 0) info("%s(%p.)", __FUNCTION__, intf); - down(&uvd->lock); + mutex_lock(&uvd->lock); uvd->remove_pending = 1; /* Now all ISO data will be ignored */ /* At this time we ask to cancel outstanding URBs */ @@ -882,7 +882,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf) info("%s: In use, disconnect pending.", __FUNCTION__); else usbvideo_CameraRelease(uvd); - up(&uvd->lock); + mutex_unlock(&uvd->lock); info("USB camera disconnected."); usbvideo_ClientDecModCount(uvd); @@ -929,19 +929,19 @@ static int usbvideo_find_struct(struct usbvideo *cams) err("No usbvideo handle?"); return -1; } - down(&cams->lock); + mutex_lock(&cams->lock); for (u = 0; u < cams->num_cameras; u++) { struct uvd *uvd = &cams->cam[u]; if (!uvd->uvd_used) /* This one is free */ { uvd->uvd_used = 1; /* In use now */ - init_MUTEX(&uvd->lock); /* to 1 == available */ + mutex_init(&uvd->lock); /* to 1 == available */ uvd->dev = NULL; rv = u; break; } } - up(&cams->lock); + mutex_unlock(&cams->lock); return rv; } @@ -983,7 +983,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams) /* Not relying upon caller we increase module counter ourselves */ usbvideo_ClientIncModCount(uvd); - down(&uvd->lock); + mutex_lock(&uvd->lock); for (i=0; i < USBVIDEO_NUMSBUF; i++) { uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); if (uvd->sbuf[i].urb == NULL) { @@ -1006,7 +1006,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams) * return control to the client's probe function right now. */ allocate_done: - up (&uvd->lock); + mutex_unlock(&uvd->lock); usbvideo_ClientDecModCount(uvd); return uvd; } @@ -1120,7 +1120,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file) info("%s($%p)", __FUNCTION__, dev); usbvideo_ClientIncModCount(uvd); - down(&uvd->lock); + mutex_lock(&uvd->lock); if (uvd->user) { err("%s: Someone tried to open an already opened device!", __FUNCTION__); @@ -1201,7 +1201,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file) } } } - up(&uvd->lock); + mutex_unlock(&uvd->lock); if (errCode != 0) usbvideo_ClientDecModCount(uvd); if (uvd->debug > 0) @@ -1230,7 +1230,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file) if (uvd->debug > 1) info("%s($%p)", __FUNCTION__, dev); - down(&uvd->lock); + mutex_lock(&uvd->lock); GET_CALLBACK(uvd, stopDataPump)(uvd); usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); uvd->fbuf = NULL; @@ -1251,7 +1251,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file) info("usbvideo_v4l_close: Final disconnect."); usbvideo_CameraRelease(uvd); } - up(&uvd->lock); + mutex_unlock(&uvd->lock); usbvideo_ClientDecModCount(uvd); if (uvd->debug > 1) @@ -1511,7 +1511,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, if (uvd->debug >= 1) info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock); - down(&uvd->lock); + mutex_lock(&uvd->lock); /* See if a frame is completed, then use it. */ for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { @@ -1643,7 +1643,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, } } read_done: - up(&uvd->lock); + mutex_unlock(&uvd->lock); return count; } diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h index 6c390a1f981b..135433c2680a 100644 --- a/drivers/usb/media/usbvideo.h +++ b/drivers/usb/media/usbvideo.h @@ -19,6 +19,7 @@ #include #include #include +#include /* Most helpful debugging aid */ #define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) @@ -213,7 +214,7 @@ struct uvd { unsigned long flags; /* FLAGS_USBVIDEO_xxx */ unsigned long paletteBits; /* Which palettes we accept? */ unsigned short defaultPalette; /* What palette to use for read() */ - struct semaphore lock; + struct mutex lock; int user; /* user count for exclusive use */ videosize_t videosize; /* Current setting */ @@ -272,7 +273,7 @@ struct usbvideo { int num_cameras; /* As allocated */ struct usb_driver usbdrv; /* Interface to the USB stack */ char drvName[80]; /* Driver name */ - struct semaphore lock; /* Mutex protecting camera structures */ + struct mutex lock; /* Mutex protecting camera structures */ struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */ struct video_device vdt; /* Video device template */ struct uvd *cam; /* Array of camera structures */ diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c index 5df144073871..8cfc47b831fb 100644 --- a/drivers/usb/media/vicam.c +++ b/drivers/usb/media/vicam.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "usbvideo.h" // #define VICAM_DEBUG @@ -407,7 +408,7 @@ struct vicam_camera { struct usb_device *udev; // usb device /* guard against simultaneous accesses to the camera */ - struct semaphore cam_lock; + struct mutex cam_lock; int is_initialized; u8 open_count; @@ -461,12 +462,12 @@ static int send_control_msg(struct vicam_camera *cam, u16 size) { int status = -ENODEV; - down(&cam->cam_lock); + mutex_lock(&cam->cam_lock); if (cam->udev) { status = __send_control_msg(cam, request, value, index, cp, size); } - up(&cam->cam_lock); + mutex_unlock(&cam->cam_lock); return status; } static int @@ -831,13 +832,13 @@ vicam_close(struct inode *inode, struct file *file) rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); kfree(cam->cntrlbuf); - down(&cam->cam_lock); + mutex_lock(&cam->cam_lock); cam->open_count--; open_count = cam->open_count; udev = cam->udev; - up(&cam->cam_lock); + mutex_unlock(&cam->cam_lock); if (!open_count && !udev) { kfree(cam); @@ -960,7 +961,7 @@ read_frame(struct vicam_camera *cam, int framenum) request[8] = 0; // bytes 9-15 do not seem to affect exposure or image quality - down(&cam->cam_lock); + mutex_lock(&cam->cam_lock); if (!cam->udev) { goto done; @@ -985,7 +986,7 @@ read_frame(struct vicam_camera *cam, int framenum) } done: - up(&cam->cam_lock); + mutex_unlock(&cam->cam_lock); } static ssize_t @@ -1309,7 +1310,7 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) cam->shutter_speed = 15; - init_MUTEX(&cam->cam_lock); + mutex_init(&cam->cam_lock); memcpy(&cam->vdev, &vicam_template, sizeof (vicam_template)); @@ -1351,7 +1352,7 @@ vicam_disconnect(struct usb_interface *intf) /* stop the camera from being used */ - down(&cam->cam_lock); + mutex_lock(&cam->cam_lock); /* mark the camera as gone */ @@ -1368,7 +1369,7 @@ vicam_disconnect(struct usb_interface *intf) open_count = cam->open_count; - up(&cam->cam_lock); + mutex_unlock(&cam->cam_lock); if (!open_count) { kfree(cam); diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c index 78cd1a577d26..b57dec3782e0 100644 --- a/drivers/usb/media/w9968cf.c +++ b/drivers/usb/media/w9968cf.c @@ -47,6 +47,13 @@ #include "w9968cf.h" #include "w9968cf_decoder.h" +static struct w9968cf_vpp_t* w9968cf_vpp; +static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); + +static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ +static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */ + +static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ /**************************************************************************** @@ -2418,7 +2425,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam, enum w9968cf_model_id mod_id, const unsigned short dev_nr) { - init_MUTEX(&cam->fileop_sem); + mutex_init(&cam->fileop_mutex); init_waitqueue_head(&cam->open); spin_lock_init(&cam->urb_lock); spin_lock_init(&cam->flist_lock); @@ -2646,7 +2653,7 @@ static void w9968cf_adjust_configuration(struct w9968cf_device* cam) --------------------------------------------------------------------------*/ static void w9968cf_release_resources(struct w9968cf_device* cam) { - down(&w9968cf_devlist_sem); + mutex_lock(&w9968cf_devlist_mutex); DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) @@ -2657,7 +2664,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) kfree(cam->control_buffer); kfree(cam->data_buffer); - up(&w9968cf_devlist_sem); + mutex_unlock(&w9968cf_devlist_mutex); } @@ -2677,14 +2684,14 @@ static int w9968cf_open(struct inode* inode, struct file* filp) cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); if (cam->sensor == CC_UNKNOWN) { DBG(2, "No supported image sensor has been detected by the " "'ovcamchip' module for the %s (/dev/video%d). Make " "sure it is loaded *before* (re)connecting the camera.", symbolic(camlist, cam->id), cam->v4ldev->minor) - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); up_read(&w9968cf_disconnect); return -ENODEV; } @@ -2693,11 +2700,11 @@ static int w9968cf_open(struct inode* inode, struct file* filp) DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); up_read(&w9968cf_disconnect); return -EWOULDBLOCK; } - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); err = wait_event_interruptible_exclusive(cam->open, cam->disconnected || !cam->users); @@ -2709,7 +2716,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) up_read(&w9968cf_disconnect); return -ENODEV; } - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); } DBG(5, "Opening '%s', /dev/video%d ...", @@ -2738,7 +2745,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) DBG(5, "Video device is open") - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); up_read(&w9968cf_disconnect); return 0; @@ -2746,7 +2753,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) deallocate_memory: w9968cf_deallocate_memory(cam); DBG(2, "Failed to open the video device") - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); up_read(&w9968cf_disconnect); return err; } @@ -2758,13 +2765,13 @@ static int w9968cf_release(struct inode* inode, struct file* filp) cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); - down(&cam->dev_sem); /* prevent disconnect() to be called */ + mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ w9968cf_stop_transfer(cam); if (cam->disconnected) { w9968cf_release_resources(cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); kfree(cam); return 0; } @@ -2774,7 +2781,7 @@ static int w9968cf_release(struct inode* inode, struct file* filp) wake_up_interruptible_nr(&cam->open, 1); DBG(5, "Video device closed") - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); return 0; } @@ -2791,18 +2798,18 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) if (filp->f_flags & O_NONBLOCK) return -EWOULDBLOCK; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->disconnected) { DBG(2, "Device not present") - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->misconfigured) { DBG(2, "The camera is misconfigured. Close and open it again.") - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } @@ -2817,11 +2824,11 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) cam->frame[1].status == F_READY || cam->disconnected); if (err) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return err; } if (cam->disconnected) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } @@ -2835,7 +2842,7 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) if (copy_to_user(buf, fr->buffer, count)) { fr->status = F_UNUSED; - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EFAULT; } *f_pos += count; @@ -2844,7 +2851,7 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) DBG(5, "%zu bytes read", count) - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return count; } @@ -2898,24 +2905,24 @@ w9968cf_ioctl(struct inode* inode, struct file* filp, cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->disconnected) { DBG(2, "Device not present") - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->misconfigured) { DBG(2, "The camera is misconfigured. Close and open it again.") - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return err; } @@ -3502,8 +3509,8 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) if (!cam) return -ENOMEM; - init_MUTEX(&cam->dev_sem); - down(&cam->dev_sem); + mutex_init(&cam->dev_mutex); + mutex_lock(&cam->dev_mutex); cam->usbdev = udev; /* NOTE: a local copy is used to avoid possible race conditions */ @@ -3515,10 +3522,10 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) simcams = W9968CF_SIMCAMS; /* How many cameras are connected ? */ - down(&w9968cf_devlist_sem); + mutex_lock(&w9968cf_devlist_mutex); list_for_each(ptr, &w9968cf_dev_list) sc++; - up(&w9968cf_devlist_sem); + mutex_unlock(&w9968cf_devlist_mutex); if (sc >= simcams) { DBG(2, "Device rejected: too many connected cameras " @@ -3578,9 +3585,9 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) w9968cf_configure_camera(cam, udev, mod_id, dev_nr); /* Add a new entry into the list of V4L registered devices */ - down(&w9968cf_devlist_sem); + mutex_lock(&w9968cf_devlist_mutex); list_add(&cam->v4llist, &w9968cf_dev_list); - up(&w9968cf_devlist_sem); + mutex_unlock(&w9968cf_devlist_mutex); dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; w9968cf_turn_on_led(cam); @@ -3588,7 +3595,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) w9968cf_i2c_init(cam); usb_set_intfdata(intf, cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); return 0; fail: /* Free unused memory */ @@ -3596,7 +3603,7 @@ fail: /* Free unused memory */ kfree(cam->data_buffer); if (cam->v4ldev) video_device_release(cam->v4ldev); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); kfree(cam); return err; } @@ -3611,7 +3618,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) if (cam) { /* Prevent concurrent accesses to data */ - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); cam->disconnected = 1; @@ -3630,7 +3637,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) } else w9968cf_release_resources(cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); if (!cam->users) kfree(cam); diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h index 47a6ff794171..a87be719a281 100644 --- a/drivers/usb/media/w9968cf.h +++ b/drivers/usb/media/w9968cf.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include @@ -194,14 +194,6 @@ enum w9968cf_vpp_flag { VPP_UYVY_TO_RGBX = 0x08, }; -static struct w9968cf_vpp_t* w9968cf_vpp; -static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); - -static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ -static DECLARE_MUTEX(w9968cf_devlist_sem); /* semaphore for list traversal */ - -static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ - /* Main device driver structure */ struct w9968cf_device { struct device dev; /* device structure */ @@ -277,8 +269,8 @@ struct w9968cf_device { struct i2c_client* sensor_client; /* Locks */ - struct semaphore dev_sem, /* for probe, disconnect,open and close */ - fileop_sem; /* for read and ioctl */ + struct mutex dev_mutex, /* for probe, disconnect,open and close */ + fileop_mutex; /* for read and ioctl */ spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */ flist_lock; /* for requested frame list accesses */ wait_queue_head_t open, wait_queue; diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index b3aca5124339..d0b167256699 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -121,7 +122,7 @@ static struct usb_driver idmouse_driver = { }; /* prevent races between open() and disconnect() */ -static DECLARE_MUTEX(disconnect_sem); +static DEFINE_MUTEX(disconnect_mutex); static int idmouse_create_image(struct usb_idmouse *dev) { @@ -213,18 +214,18 @@ static int idmouse_open(struct inode *inode, struct file *file) int result = 0; /* prevent disconnects */ - down(&disconnect_sem); + mutex_lock(&disconnect_mutex); /* get the interface from minor number and driver information */ interface = usb_find_interface (&idmouse_driver, iminor (inode)); if (!interface) { - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); return -ENODEV; } /* get the device information block from the interface */ dev = usb_get_intfdata(interface); if (!dev) { - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); return -ENODEV; } @@ -258,7 +259,7 @@ error: up(&dev->sem); /* unlock the disconnect semaphore */ - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); return result; } @@ -267,12 +268,12 @@ static int idmouse_release(struct inode *inode, struct file *file) struct usb_idmouse *dev; /* prevent a race condition with open() */ - down(&disconnect_sem); + mutex_lock(&disconnect_mutex); dev = (struct usb_idmouse *) file->private_data; if (dev == NULL) { - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); return -ENODEV; } @@ -282,7 +283,7 @@ static int idmouse_release(struct inode *inode, struct file *file) /* are we really open? */ if (dev->open <= 0) { up(&dev->sem); - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); return -ENODEV; } @@ -292,12 +293,12 @@ static int idmouse_release(struct inode *inode, struct file *file) /* the device was unplugged before the file was released */ up(&dev->sem); idmouse_delete(dev); - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); return 0; } up(&dev->sem); - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); return 0; } @@ -399,7 +400,7 @@ static void idmouse_disconnect(struct usb_interface *interface) struct usb_idmouse *dev; /* prevent races with open() */ - down(&disconnect_sem); + mutex_lock(&disconnect_mutex); /* get device structure */ dev = usb_get_intfdata(interface); @@ -421,7 +422,7 @@ static void idmouse_disconnect(struct usb_interface *interface) if (!dev->open) idmouse_delete(dev); - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); info("%s disconnected", DRIVER_DESC); } diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index f6bdaf08a80f..966acb474f67 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -172,7 +173,7 @@ struct ld_usb { }; /* prevent races between open() and disconnect() */ -static DECLARE_MUTEX(disconnect_sem); +static DEFINE_MUTEX(disconnect_mutex); static struct usb_driver ld_usb_driver; @@ -293,7 +294,7 @@ static int ld_usb_open(struct inode *inode, struct file *file) nonseekable_open(inode, file); subminor = iminor(inode); - down(&disconnect_sem); + mutex_lock(&disconnect_mutex); interface = usb_find_interface(&ld_usb_driver, subminor); @@ -355,7 +356,7 @@ unlock_exit: up(&dev->sem); unlock_disconnect_exit: - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); return retval; } @@ -740,7 +741,7 @@ static void ld_usb_disconnect(struct usb_interface *intf) struct ld_usb *dev; int minor; - down(&disconnect_sem); + mutex_lock(&disconnect_mutex); dev = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); @@ -761,7 +762,7 @@ static void ld_usb_disconnect(struct usb_interface *intf) up(&dev->sem); } - up(&disconnect_sem); + mutex_unlock(&disconnect_mutex); dev_info(&intf->dev, "LD USB Device #%d now disconnected\n", (minor - USB_LD_MINOR_BASE)); diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 1336745b8f55..779bcf0373ad 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -83,6 +83,7 @@ #include #include #include +#include #include #include #include @@ -256,7 +257,7 @@ static void tower_disconnect (struct usb_interface *interface); /* prevent races between open() and disconnect */ -static DECLARE_MUTEX (disconnect_sem); +static DEFINE_MUTEX (disconnect_mutex); /* file operations needed when we register this driver */ static struct file_operations tower_fops = { @@ -349,7 +350,7 @@ static int tower_open (struct inode *inode, struct file *file) nonseekable_open(inode, file); subminor = iminor(inode); - down (&disconnect_sem); + mutex_lock (&disconnect_mutex); interface = usb_find_interface (&tower_driver, subminor); @@ -427,7 +428,7 @@ unlock_exit: up (&dev->sem); unlock_disconnect_exit: - up (&disconnect_sem); + mutex_unlock (&disconnect_mutex); dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval); @@ -1005,7 +1006,7 @@ static void tower_disconnect (struct usb_interface *interface) dbg(2, "%s: enter", __FUNCTION__); - down (&disconnect_sem); + mutex_lock (&disconnect_mutex); dev = usb_get_intfdata (interface); usb_set_intfdata (interface, NULL); @@ -1027,7 +1028,7 @@ static void tower_disconnect (struct usb_interface *interface) up (&dev->sem); } - up (&disconnect_sem); + mutex_unlock (&disconnect_mutex); info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE)); diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index c34944c75047..b03e346e33f1 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "usb_mon.h" #include "../core/hcd.h" @@ -23,7 +24,7 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); static void mon_bus_drop(struct kref *r); static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus); -DECLARE_MUTEX(mon_lock); +DEFINE_MUTEX(mon_lock); static struct dentry *mon_dir; /* /dbg/usbmon */ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ @@ -196,14 +197,14 @@ static void mon_bus_remove(struct usb_bus *ubus) { struct mon_bus *mbus = ubus->mon_bus; - down(&mon_lock); + mutex_lock(&mon_lock); list_del(&mbus->bus_link); debugfs_remove(mbus->dent_t); debugfs_remove(mbus->dent_s); mon_dissolve(mbus, ubus); kref_put(&mbus->ref, mon_bus_drop); - up(&mon_lock); + mutex_unlock(&mon_lock); } static int mon_notify(struct notifier_block *self, unsigned long action, @@ -307,9 +308,9 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) goto err_create_s; mbus->dent_s = d; - down(&mon_lock); + mutex_lock(&mon_lock); list_add_tail(&mbus->bus_link, &mon_buses); - up(&mon_lock); + mutex_unlock(&mon_lock); return; err_create_s: @@ -347,11 +348,11 @@ static int __init mon_init(void) usb_register_notify(&mon_nb); - down(&usb_bus_list_lock); + mutex_lock(&usb_bus_list_lock); list_for_each_entry (ubus, &usb_bus_list, bus_list) { mon_bus_init(mondir, ubus); } - up(&usb_bus_list_lock); + mutex_unlock(&usb_bus_list_lock); return 0; } @@ -363,7 +364,7 @@ static void __exit mon_exit(void) usb_unregister_notify(&mon_nb); usb_mon_deregister(); - down(&mon_lock); + mutex_lock(&mon_lock); while (!list_empty(&mon_buses)) { p = mon_buses.next; mbus = list_entry(p, struct mon_bus, bus_link); @@ -387,7 +388,7 @@ static void __exit mon_exit(void) mon_dissolve(mbus, mbus->u_bus); kref_put(&mbus->ref, mon_bus_drop); } - up(&mon_lock); + mutex_unlock(&mon_lock); debugfs_remove(mon_dir); } diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 611612146ae9..59089e8b7e5e 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "usb_mon.h" @@ -54,7 +55,7 @@ struct mon_reader_text { wait_queue_head_t wait; int printf_size; char *printf_buf; - struct semaphore printf_lock; + struct mutex printf_lock; char slab_name[SLAB_NAME_SZ]; }; @@ -208,7 +209,7 @@ static int mon_text_open(struct inode *inode, struct file *file) struct mon_reader_text *rp; int rc; - down(&mon_lock); + mutex_lock(&mon_lock); mbus = inode->u.generic_ip; ubus = mbus->u_bus; @@ -220,7 +221,7 @@ static int mon_text_open(struct inode *inode, struct file *file) memset(rp, 0, sizeof(struct mon_reader_text)); INIT_LIST_HEAD(&rp->e_list); init_waitqueue_head(&rp->wait); - init_MUTEX(&rp->printf_lock); + mutex_init(&rp->printf_lock); rp->printf_size = PRINTF_DFL; rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL); @@ -247,7 +248,7 @@ static int mon_text_open(struct inode *inode, struct file *file) mon_reader_add(mbus, &rp->r); file->private_data = rp; - up(&mon_lock); + mutex_unlock(&mon_lock); return 0; // err_busy: @@ -257,7 +258,7 @@ err_slab: err_alloc_pr: kfree(rp); err_alloc: - up(&mon_lock); + mutex_unlock(&mon_lock); return rc; } @@ -301,7 +302,7 @@ static ssize_t mon_text_read(struct file *file, char __user *buf, set_current_state(TASK_RUNNING); remove_wait_queue(&rp->wait, &waita); - down(&rp->printf_lock); + mutex_lock(&rp->printf_lock); cnt = 0; pbuf = rp->printf_buf; limit = rp->printf_size; @@ -358,7 +359,7 @@ static ssize_t mon_text_read(struct file *file, char __user *buf, if (copy_to_user(buf, rp->printf_buf, cnt)) cnt = -EFAULT; - up(&rp->printf_lock); + mutex_unlock(&rp->printf_lock); kmem_cache_free(rp->e_slab, ep); return cnt; } @@ -371,12 +372,12 @@ static int mon_text_release(struct inode *inode, struct file *file) struct list_head *p; struct mon_event_text *ep; - down(&mon_lock); + mutex_lock(&mon_lock); mbus = inode->u.generic_ip; if (mbus->nreaders <= 0) { printk(KERN_ERR TAG ": consistency error on close\n"); - up(&mon_lock); + mutex_unlock(&mon_lock); return 0; } mon_reader_del(mbus, &rp->r); @@ -402,7 +403,7 @@ static int mon_text_release(struct inode *inode, struct file *file) kfree(rp->printf_buf); kfree(rp); - up(&mon_lock); + mutex_unlock(&mon_lock); return 0; } diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index 4be0f9346071..8e0613c350cc 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -49,7 +49,7 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r); */ extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len); -extern struct semaphore mon_lock; +extern struct mutex mon_lock; extern struct file_operations mon_fops_text; extern struct file_operations mon_fops_stat; diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 4ef5527028c5..5f11e19eaae3 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -47,6 +47,7 @@ #include #include +#include #include #include @@ -271,9 +272,9 @@ static int device_reset(struct scsi_cmnd *srb) US_DEBUGP("%s called\n", __FUNCTION__); /* lock the device pointers and do the reset */ - down(&(us->dev_semaphore)); + mutex_lock(&(us->dev_mutex)); result = us->transport_reset(us); - up(&(us->dev_semaphore)); + mutex_unlock(&us->dev_mutex); return result < 0 ? FAILED : SUCCESS; } @@ -286,9 +287,9 @@ static int bus_reset(struct scsi_cmnd *srb) US_DEBUGP("%s called\n", __FUNCTION__); - down(&(us->dev_semaphore)); + mutex_lock(&(us->dev_mutex)); result = usb_stor_port_reset(us); - up(&(us->dev_semaphore)); + mutex_unlock(&us->dev_mutex); return result < 0 ? FAILED : SUCCESS; } diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index dbcf23980ff1..dd108634348e 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -188,7 +189,7 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message) struct us_data *us = usb_get_intfdata(iface); /* Wait until no command is running */ - down(&us->dev_semaphore); + mutex_lock(&us->dev_mutex); US_DEBUGP("%s\n", __FUNCTION__); if (us->suspend_resume_hook) @@ -198,7 +199,7 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message) /* When runtime PM is working, we'll set a flag to indicate * whether we should autoresume when a SCSI request arrives. */ - up(&us->dev_semaphore); + mutex_unlock(&us->dev_mutex); return 0; } @@ -206,14 +207,14 @@ static int storage_resume(struct usb_interface *iface) { struct us_data *us = usb_get_intfdata(iface); - down(&us->dev_semaphore); + mutex_lock(&us->dev_mutex); US_DEBUGP("%s\n", __FUNCTION__); if (us->suspend_resume_hook) (us->suspend_resume_hook)(us, US_RESUME); iface->dev.power.power_state.event = PM_EVENT_ON; - up(&us->dev_semaphore); + mutex_unlock(&us->dev_mutex); return 0; } @@ -276,12 +277,12 @@ static int usb_stor_control_thread(void * __us) US_DEBUGP("*** thread awakened.\n"); /* lock the device pointers */ - down(&(us->dev_semaphore)); + mutex_lock(&(us->dev_mutex)); /* if the device has disconnected, we are free to exit */ if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { US_DEBUGP("-- exiting\n"); - up(&(us->dev_semaphore)); + mutex_unlock(&us->dev_mutex); break; } @@ -370,7 +371,7 @@ SkipForAbort: scsi_unlock(host); /* unlock the device pointers */ - up(&(us->dev_semaphore)); + mutex_unlock(&us->dev_mutex); } /* for (;;) */ scsi_host_put(host); @@ -815,8 +816,8 @@ static void quiesce_and_remove_host(struct us_data *us) * The thread will exit when it sees the DISCONNECTING flag. */ /* Wait for the current command to finish, then remove the host */ - down(&us->dev_semaphore); - up(&us->dev_semaphore); + mutex_lock(&us->dev_mutex); + mutex_unlock(&us->dev_mutex); /* queuecommand won't accept any new commands and the control * thread won't execute a previously-queued command. If there @@ -870,9 +871,9 @@ retry: /* For bulk-only devices, determine the max LUN value */ if (us->protocol == US_PR_BULK && !(us->flags & US_FL_SINGLE_LUN)) { - down(&us->dev_semaphore); + mutex_lock(&us->dev_mutex); us->max_lun = usb_stor_Bulk_max_lun(us); - up(&us->dev_semaphore); + mutex_unlock(&us->dev_mutex); } scsi_scan_host(us_to_host(us)); printk(KERN_DEBUG "usb-storage: device scan complete\n"); @@ -912,7 +913,7 @@ static int storage_probe(struct usb_interface *intf, us = host_to_us(host); memset(us, 0, sizeof(struct us_data)); - init_MUTEX(&(us->dev_semaphore)); + mutex_init(&(us->dev_mutex)); init_MUTEX_LOCKED(&(us->sema)); init_completion(&(us->notify)); init_waitqueue_head(&us->delay_wait); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 7259fd1f6b0d..009fb0953a56 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -49,6 +49,7 @@ #include #include #include +#include #include struct us_data; @@ -103,9 +104,9 @@ typedef void (*pm_hook)(struct us_data *, int); /* power management hook */ struct us_data { /* The device we're working with * It's important to note: - * (o) you must hold dev_semaphore to change pusb_dev + * (o) you must hold dev_mutex to change pusb_dev */ - struct semaphore dev_semaphore; /* protect pusb_dev */ + struct mutex dev_mutex; /* protect pusb_dev */ struct usb_device *pusb_dev; /* this usb_device */ struct usb_interface *pusb_intf; /* this interface */ struct us_unusual_dev *unusual_dev; /* device-filter entry */ -- cgit v1.2.2 From f8aeb3bb8657b207895aa10f75e63f2c48d08985 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 20 Jan 2006 13:55:14 -0800 Subject: [PATCH] USB: EHCI and NF2 quirk This teaches the EHCI driver about a quirk seen in older NForce2 chips, adding a workaround to ignore selective suspend requests. Bus-wide (so-called "global") suspend still works, as does USB wakeup of a root hub that's globally suspended. There's still a hole in this support though. Strictly speaking, this should _fail_ selective suspend requests, rather than ignoring them, since doing it this way means that devices which should be able to issue remote wakeup are not going to be able to do that. For now, we'll just live with that problem ... since usbcore expects to do selective suspend on the way towards a full bus suspend, and usbcore needs to be able to do full bus suspend. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 4 ++++ drivers/usb/host/ehci-pci.c | 25 ++++++++++++++++++++++++- drivers/usb/host/ehci.h | 3 ++- 3 files changed, 30 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 69b0b9be7a64..d03e3cad5ca8 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -359,6 +359,8 @@ static int ehci_hub_control ( case USB_PORT_FEAT_SUSPEND: if (temp & PORT_RESET) goto error; + if (ehci->no_selective_suspend) + break; if (temp & PORT_SUSPEND) { if ((temp & PORT_PE) == 0) goto error; @@ -514,6 +516,8 @@ static int ehci_hub_control ( temp &= ~PORT_RWC_BITS; switch (wValue) { case USB_PORT_FEAT_SUSPEND: + if (ehci->no_selective_suspend) + break; if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) goto error; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 3a6687df5594..1e03f1a5a5fd 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -106,11 +106,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd) } break; case PCI_VENDOR_ID_NVIDIA: + switch (pdev->device) { /* NVidia reports that certain chips don't handle * QH, ITD, or SITD addresses above 2GB. (But TD, * data buffer, and periodic schedule are normal.) */ - switch (pdev->device) { case 0x003c: /* MCP04 */ case 0x005b: /* CK804 */ case 0x00d8: /* CK8 */ @@ -120,6 +120,14 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ehci_warn(ehci, "can't enable NVidia " "workaround for >2GB RAM\n"); break; + /* Some NForce2 chips have problems with selective suspend; + * fixed in newer silicon. + */ + case 0x0068: + pci_read_config_dword(pdev, PCI_REVISION_ID, &temp); + if ((temp & 0xff) < 0xa4) + ehci->no_selective_suspend = 1; + break; } break; } @@ -163,6 +171,21 @@ static int ehci_pci_setup(struct usb_hcd *hcd) device_init_wakeup(&pdev->dev, 1); } +#ifdef CONFIG_USB_SUSPEND + /* REVISIT: the controller works fine for wakeup iff the root hub + * itself is "globally" suspended, but usbcore currently doesn't + * understand such things. + * + * System suspend currently expects to be able to suspend the entire + * device tree, device-at-a-time. If we failed selective suspend + * reports, system suspend would fail; so the root hub code must claim + * success. That's lying to usbcore, and it matters for for runtime + * PM scenarios with selective suspend and remote wakeup... + */ + if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev)) + ehci_warn(ehci, "selective suspend/wakeup unavailable\n"); +#endif + retval = ehci_pci_reinit(ehci, pdev); done: return retval; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 18e257c2bdb5..86af41c41de1 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -89,6 +89,8 @@ struct ehci_hcd { /* one per controller */ u32 command; unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ + unsigned no_selective_suspend:1; + u8 sbrn; /* packed release number */ /* irq statistics */ #ifdef EHCI_STATS @@ -97,7 +99,6 @@ struct ehci_hcd { /* one per controller */ #else # define COUNT(x) do {} while (0) #endif - u8 sbrn; /* packed release number */ }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ -- cgit v1.2.2 From 469d02293d494d30dba81895cd3d34b0a3a6d51a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 20 Jan 2006 13:49:10 -0800 Subject: [PATCH] USB: EHCI full speed ISO bugfixes This patch replaces the split ISO raw_mask calculation code in the iso_stream_init() function that computed incorrect numbers of high speed transactions for both input and output transfers. In the output case, it added a superfluous start-split transaction for all maxmimum packet sizes that are a multiple of 188. In the input case, it forgot to add complete-split transactions for all microframes covered by the full speed transaction, and the additional complete-split transaction needed for the case when full speed data starts arriving near the end of a microframe. These changes don't affect the lack of full speed bandwidth, but at least it removes the MMF errors that the HC raised with some input streams. Signed-off-by: Clemens Ladisch Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index ebcca9700671..88419c6823a8 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -707,6 +707,7 @@ iso_stream_init ( } else { u32 addr; int think_time; + int hs_transfers; addr = dev->ttport << 24; if (!ehci_is_TDI(ehci) @@ -719,6 +720,7 @@ iso_stream_init ( think_time = dev->tt ? dev->tt->think_time : 0; stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time ( dev->speed, is_input, 1, maxp)); + hs_transfers = max (1u, (maxp + 187) / 188); if (is_input) { u32 tmp; @@ -727,12 +729,11 @@ iso_stream_init ( stream->usecs = HS_USECS_ISO (1); stream->raw_mask = 1; - /* pessimistic c-mask */ - tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp) - / (125 * 1000); - stream->raw_mask |= 3 << (tmp + 9); + /* c-mask as specified in USB 2.0 11.18.4 3.c */ + tmp = (1 << (hs_transfers + 2)) - 1; + stream->raw_mask |= tmp << (8 + 2); } else - stream->raw_mask = smask_out [maxp / 188]; + stream->raw_mask = smask_out [hs_transfers - 1]; bandwidth = stream->usecs + stream->c_usecs; bandwidth /= 1 << (interval + 2); -- cgit v1.2.2 From 80cb9aee01245b38325dd84f1359b14a3f01f10d Mon Sep 17 00:00:00 2001 From: Randy Vinson Date: Fri, 20 Jan 2006 13:53:38 -0800 Subject: [PATCH] USB: EHCI for Freescale 83xx Adding a Host Mode USB driver for the Freescale 83xx. This driver supports both the Dual-Role (DR) controller and the Multi-Port-Host (MPH) controller present in the Freescale MPC8349. It has been tested with the MPC8349CDS reference system. This driver depends on platform support code for setting up the pins on the device package in a manner appropriate for the board in use. Note that this patch requires selecting the EHCI controller option under the USB Host menu. Signed-off-by: Randy Vinson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 1 + drivers/usb/host/Kconfig | 2 +- drivers/usb/host/ehci-fsl.c | 357 ++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci-fsl.h | 37 +++++ drivers/usb/host/ehci-hcd.c | 8 +- 5 files changed, 403 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/host/ehci-fsl.c create mode 100644 drivers/usb/host/ehci-fsl.h (limited to 'drivers/usb') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 85dacc92545a..7772e28a303f 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -11,6 +11,7 @@ config USB_ARCH_HAS_HCD boolean default y if USB_ARCH_HAS_OHCI default y if ARM # SL-811 + default y if PPC_83xx default PCI # many non-PCI SOC chips embed OHCI diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index be3fd9bce573..a45293673906 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -6,7 +6,7 @@ comment "USB Host Controller Drivers" config USB_EHCI_HCD tristate "EHCI HCD (USB 2.0) support" - depends on USB && PCI + depends on USB && (PCI || PPC_83xx) ---help--- The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c new file mode 100644 index 000000000000..c6012d6cd527 --- /dev/null +++ b/drivers/usb/host/ehci-fsl.c @@ -0,0 +1,357 @@ +/* + * (C) Copyright David Brownell 2000-2002 + * Copyright (c) 2005 MontaVista Software + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Ported to 834x by Randy Vinson using code provided + * by Hunter Wu. + */ + +#include +#include + +#include "ehci-fsl.h" + +/* FIXME: Power Managment is un-ported so temporarily disable it */ +#undef CONFIG_PM + +/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_hcd_fsl_probe - initialize FSL-based HCDs + * @drvier: Driver to be used for this HCD + * @pdev: USB Host Controller being probed + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller. + * + */ +int usb_hcd_fsl_probe(const struct hc_driver *driver, + struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata; + struct usb_hcd *hcd; + struct resource *res; + int irq; + int retval; + unsigned int temp; + + pr_debug("initializing FSL-SOC USB Controller\n"); + + /* Need platform data for setup */ + pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, + "No platform data for %s.\n", pdev->dev.bus_id); + return -ENODEV; + } + + /* + * This is a host mode driver, verify that we're supposed to be + * in host mode. + */ + if (!((pdata->operating_mode == FSL_USB2_DR_HOST) || + (pdata->operating_mode == FSL_USB2_MPH_HOST))) { + dev_err(&pdev->dev, + "Non Host Mode configured for %s. Wrong driver linked.\n", + pdev->dev.bus_id); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no IRQ. Check %s setup!\n", + pdev->dev.bus_id); + return -ENODEV; + } + irq = res->start; + + hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + retval = -ENOMEM; + goto err1; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Found HC with no register addr. Check %s setup!\n", + pdev->dev.bus_id); + retval = -ENODEV; + goto err2; + } + hcd->rsrc_start = res->start; + hcd->rsrc_len = res->end - res->start + 1; + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, + driver->description)) { + dev_dbg(&pdev->dev, "controller already in use\n"); + retval = -EBUSY; + goto err2; + } + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + + if (hcd->regs == NULL) { + dev_dbg(&pdev->dev, "error mapping memory\n"); + retval = -EFAULT; + goto err3; + } + + /* Enable USB controller */ + temp = in_be32(hcd->regs + 0x500); + out_be32(hcd->regs + 0x500, temp | 0x4); + + /* Set to Host mode */ + temp = in_le32(hcd->regs + 0x1a8); + out_le32(hcd->regs + 0x1a8, temp | 0x3); + + retval = usb_add_hcd(hcd, irq, SA_SHIRQ); + if (retval != 0) + goto err4; + return retval; + + err4: + iounmap(hcd->regs); + err3: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + err2: + usb_put_hcd(hcd); + err1: + dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval); + return retval; +} + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_fsl_probe(). + * + */ +void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev) +{ + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); +} + +static void mpc83xx_setup_phy(struct ehci_hcd *ehci, + enum fsl_usb2_phy_modes phy_mode, + unsigned int port_offset) +{ + u32 portsc = readl(&ehci->regs->port_status[port_offset]); + portsc &= ~PORT_PTS_MSK; + switch (phy_mode) { + case FSL_USB2_PHY_ULPI: + portsc |= PORT_PTS_ULPI; + break; + case FSL_USB2_PHY_SERIAL: + portsc |= PORT_PTS_SERIAL; + break; + case FSL_USB2_PHY_UTMI_WIDE: + portsc |= PORT_PTS_PTW; + /* fall through */ + case FSL_USB2_PHY_UTMI: + portsc |= PORT_PTS_UTMI; + break; + case FSL_USB2_PHY_NONE: + break; + } + writel(portsc, &ehci->regs->port_status[port_offset]); +} + +static void mpc83xx_usb_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct fsl_usb2_platform_data *pdata; + void __iomem *non_ehci = hcd->regs; + + pdata = + (struct fsl_usb2_platform_data *)hcd->self.controller-> + platform_data; + /* Enable PHY interface in the control reg. */ + out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004); + out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b); + + if (pdata->operating_mode == FSL_USB2_DR_HOST) + mpc83xx_setup_phy(ehci, pdata->phy_mode, 0); + + if (pdata->operating_mode == FSL_USB2_MPH_HOST) { + if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) + mpc83xx_setup_phy(ehci, pdata->phy_mode, 0); + if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) + mpc83xx_setup_phy(ehci, pdata->phy_mode, 1); + } + + /* put controller in host mode. */ + writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE); + out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); + out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); + out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); +} + +/* called after powerup, by probe or system-pm "wakeup" */ +static int ehci_fsl_reinit(struct ehci_hcd *ehci) +{ + mpc83xx_usb_setup(ehci_to_hcd(ehci)); + ehci_port_power(ehci, 0); + + return 0; +} + +/* called during probe() after chip reset completes */ +static int ehci_fsl_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + + /* EHCI registers start at offset 0x100 */ + ehci->caps = hcd->regs + 0x100; + ehci->regs = hcd->regs + 0x100 + + HC_LENGTH(readl(&ehci->caps->hc_capbase)); + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = readl(&ehci->caps->hcs_params); + + retval = ehci_halt(ehci); + if (retval) + return retval; + + /* data structure init */ + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci->is_tdi_rh_tt = 1; + + ehci->sbrn = 0x20; + + ehci_reset(ehci); + + retval = ehci_fsl_reinit(ehci); + return retval; +} + +static const struct hc_driver ehci_fsl_hc_driver = { + .description = hcd_name, + .product_desc = "Freescale On-Chip EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_fsl_setup, + .start = ehci_run, +#ifdef CONFIG_PM + .suspend = ehci_bus_suspend, + .resume = ehci_bus_resume, +#endif + .stop = ehci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +}; + +static int ehci_fsl_drv_probe(struct platform_device *pdev) +{ + if (usb_disabled()) + return -ENODEV; + + return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev); +} + +static int ehci_fsl_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_hcd_fsl_remove(hcd, pdev); + + return 0; +} + +static struct platform_driver ehci_fsl_dr_driver = { + .probe = ehci_fsl_drv_probe, + .remove = ehci_fsl_drv_remove, + .driver = { + .name = "fsl-usb2-dr", + }, +}; + +static struct platform_driver ehci_fsl_mph_driver = { + .probe = ehci_fsl_drv_probe, + .remove = ehci_fsl_drv_remove, + .driver = { + .name = "fsl-usb2-mph", + }, +}; + +static int __init ehci_fsl_init(void) +{ + int retval; + + pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", + hcd_name, + sizeof(struct ehci_qh), sizeof(struct ehci_qtd), + sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); + + retval = platform_driver_register(&ehci_fsl_dr_driver); + if (retval) + return retval; + + return platform_driver_register(&ehci_fsl_mph_driver); +} + +static void __exit ehci_fsl_cleanup(void) +{ + platform_driver_unregister(&ehci_fsl_mph_driver); + platform_driver_unregister(&ehci_fsl_dr_driver); +} + +module_init(ehci_fsl_init); +module_exit(ehci_fsl_cleanup); diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h new file mode 100644 index 000000000000..caac0d1967d0 --- /dev/null +++ b/drivers/usb/host/ehci-fsl.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2005 freescale semiconductor + * Copyright (c) 2005 MontaVista Software + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _EHCI_FSL_H +#define _EHCI_FSL_H + +/* offsets for the non-ehci registers in the FSL SOC USB controller */ +#define FSL_SOC_USB_ULPIVP 0x170 +#define FSL_SOC_USB_PORTSC1 0x184 +#define PORT_PTS_MSK (3<<30) +#define PORT_PTS_UTMI (0<<30) +#define PORT_PTS_ULPI (2<<30) +#define PORT_PTS_SERIAL (3<<30) +#define PORT_PTS_PTW (1<<28) +#define FSL_SOC_USB_PORTSC2 0x188 +#define FSL_SOC_USB_USBMODE 0x1a8 +#define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */ +#define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */ +#define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */ +#define FSL_SOC_USB_SICTRL 0x40c /* NOTE: big-endian */ +#define FSL_SOC_USB_PRICTRL 0x410 /* NOTE: big-endian */ +#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */ +#endif /* _EHCI_FSL_H */ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 9dd3d14c64f3..8730babb5771 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -891,6 +891,12 @@ MODULE_LICENSE ("GPL"); #include "ehci-pci.c" #endif -#if !defined(CONFIG_PCI) +#ifdef CONFIG_PPC_83xx +#include "ehci-fsl.c" +#endif + +#if !(defined(CONFIG_PCI) || \ + defined(CONFIG_PPC_83xx) \ + ) #error "missing bus glue for ehci-hcd" #endif -- cgit v1.2.2 From 8cd42e97bf451bbbb2f54dc571366ae5a72faaea Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 20 Jan 2006 13:57:52 -0800 Subject: [PATCH] USB: EHCI and Freescale 83xx quirk On the MPC834x processors the multiport host (MPH) EHCI controller has an erratum in which the port number in the queue head expects to be 0..N-1 instead of 1..N. If we are on one of these chips we subtract one from the port number before putting it into the queue head. Signed-off-by: Kumar Gala Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 10 ++++++++++ drivers/usb/host/ehci-q.c | 9 ++++++++- drivers/usb/host/ehci.h | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index c6012d6cd527..59f90f76ee31 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -198,6 +198,16 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd) mpc83xx_setup_phy(ehci, pdata->phy_mode, 0); if (pdata->operating_mode == FSL_USB2_MPH_HOST) { + unsigned int chip, rev, svr; + + svr = mfspr(SPRN_SVR); + chip = svr >> 16; + rev = (svr >> 4) & 0xf; + + /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */ + if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055)) + ehci->has_fsl_port_bug = 1; + if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) mpc83xx_setup_phy(ehci, pdata->phy_mode, 0); if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 9b13bf2fa98d..6e28e593c044 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -721,7 +721,14 @@ qh_make ( info1 |= maxp << 16; info2 |= (EHCI_TUNE_MULT_TT << 30); - info2 |= urb->dev->ttport << 23; + + /* Some Freescale processors have an erratum in which the + * port number in the queue head was 0..N-1 instead of 1..N. + */ + if (ehci_has_fsl_portno_bug(ehci)) + info2 |= (urb->dev->ttport-1) << 23; + else + info2 |= urb->dev->ttport << 23; /* set the address of the TT; for TDI's integrated * root hub tt, leave it zeroed. diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 86af41c41de1..679c1cdcc915 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -88,8 +88,11 @@ struct ehci_hcd { /* one per controller */ unsigned long next_statechange; u32 command; + /* SILICON QUIRKS */ unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ unsigned no_selective_suspend:1; + unsigned has_fsl_port_bug:1; /* FreeScale */ + u8 sbrn; /* packed release number */ /* irq statistics */ @@ -637,6 +640,18 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) #define ehci_port_speed(ehci, portsc) (1<has_fsl_port_bug) +#else +#define ehci_has_fsl_portno_bug(e) (0) +#endif + + /*-------------------------------------------------------------------------*/ #ifndef DEBUG -- cgit v1.2.2 From 76fa9a240de4294a097235c9ddd470c21eb3449e Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 20 Jan 2006 14:06:09 -0800 Subject: [PATCH] USB: EHCI for AU1200 ALCHEMY: Add EHCI support for AU1200 Updated by removing the OHCI support Signed-off-by: Jordan Crouse Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 9 +- drivers/usb/host/Kconfig | 2 +- drivers/usb/host/ehci-au1xxx.c | 297 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci-hcd.c | 11 +- 4 files changed, 314 insertions(+), 5 deletions(-) create mode 100644 drivers/usb/host/ehci-au1xxx.c (limited to 'drivers/usb') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 7772e28a303f..0e865975899f 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -10,8 +10,8 @@ menu "USB support" config USB_ARCH_HAS_HCD boolean default y if USB_ARCH_HAS_OHCI + default y if USB_ARCH_HAS_EHCI default y if ARM # SL-811 - default y if PPC_83xx default PCI # many non-PCI SOC chips embed OHCI @@ -31,6 +31,13 @@ config USB_ARCH_HAS_OHCI # more: default PCI +# some non-PCI hcds implement EHCI +config USB_ARCH_HAS_EHCI + boolean + default y if PPC_83xx + default y if SOC_AU1200 + default PCI + # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. config USB tristate "Support for Host-side USB" diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index a45293673906..e27b79a3c05f 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -6,7 +6,7 @@ comment "USB Host Controller Drivers" config USB_EHCI_HCD tristate "EHCI HCD (USB 2.0) support" - depends on USB && (PCI || PPC_83xx) + depends on USB && USB_ARCH_HAS_EHCI ---help--- The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c new file mode 100644 index 000000000000..63eadeec1324 --- /dev/null +++ b/drivers/usb/host/ehci-au1xxx.c @@ -0,0 +1,297 @@ +/* + * EHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 2000-2004 David Brownell + * + * Bus Glue for AMD Alchemy Au1xxx + * + * Based on "ohci-au1xxx.c" by Matt Porter + * + * Modified for AMD Alchemy Au1200 EHC + * by K.Boge + * + * This file is licenced under the GPL. + */ + +#include +#include + +#ifndef CONFIG_SOC_AU1200 +#error "this Alchemy chip doesn't have EHCI" +#else /* Au1200 */ + +#define USB_HOST_CONFIG (USB_MSR_BASE + USB_MSR_MCFG) +#define USB_MCFG_PFEN (1<<31) +#define USB_MCFG_RDCOMB (1<<30) +#define USB_MCFG_SSDEN (1<<23) +#define USB_MCFG_PHYPLLEN (1<<19) +#define USB_MCFG_EHCCLKEN (1<<17) +#define USB_MCFG_UCAM (1<<7) +#define USB_MCFG_EBMEN (1<<3) +#define USB_MCFG_EMEMEN (1<<2) + +#define USBH_ENABLE_CE (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN) + +#ifdef CONFIG_DMA_COHERENT +#define USBH_ENABLE_INIT (USBH_ENABLE_CE \ + | USB_MCFG_PFEN | USB_MCFG_RDCOMB \ + | USB_MCFG_SSDEN | USB_MCFG_UCAM \ + | USB_MCFG_EBMEN | USB_MCFG_EMEMEN) +#else +#define USBH_ENABLE_INIT (USBH_ENABLE_CE \ + | USB_MCFG_PFEN | USB_MCFG_RDCOMB \ + | USB_MCFG_SSDEN \ + | USB_MCFG_EBMEN | USB_MCFG_EMEMEN) +#endif +#define USBH_DISABLE (USB_MCFG_EBMEN | USB_MCFG_EMEMEN) + +#endif /* Au1200 */ + +extern int usb_disabled(void); + +/*-------------------------------------------------------------------------*/ + +static void au1xxx_start_ehc(struct platform_device *dev) +{ + pr_debug(__FILE__ ": starting Au1xxx EHCI USB Controller\n"); + + /* write HW defaults again in case Yamon cleared them */ + if (au_readl(USB_HOST_CONFIG) == 0) { + au_writel(0x00d02000, USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + } + /* enable host controller */ + au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG), + USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + + pr_debug(__FILE__ ": Clock to USB host has been enabled\n"); +} + +static void au1xxx_stop_ehc(struct platform_device *dev) +{ + pr_debug(__FILE__ ": stopping Au1xxx EHCI USB Controller\n"); + + /* Disable mem */ + au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG); + udelay(1000); + /* Disable clock */ + au_writel(~USB_MCFG_EHCCLKEN & au_readl(USB_HOST_CONFIG), + USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); +} + +/*-------------------------------------------------------------------------*/ + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + +/** + * usb_ehci_au1xxx_probe - initialize Au1xxx-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + */ +int usb_ehci_au1xxx_probe(const struct hc_driver *driver, + struct usb_hcd **hcd_out, struct platform_device *dev) +{ + int retval; + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + +#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT) + + /* Au1200 AB USB does not support coherent memory */ + if (!(read_c0_prid() & 0xff)) { + pr_info("%s: this is chip revision AB!\n", dev->dev.name); + pr_info("%s: update your board or re-configure the kernel\n", + dev->dev.name); + return -ENODEV; + } +#endif + + au1xxx_start_ehc(dev); + + if (dev->resource[1].flags != IORESOURCE_IRQ) { + pr_debug("resource[1] is not IORESOURCE_IRQ"); + retval = -ENOMEM; + } + hcd = usb_create_hcd(driver, &dev->dev, "Au1xxx"); + if (!hcd) + return -ENOMEM; + hcd->rsrc_start = dev->resource[0].start; + hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + pr_debug("request_mem_region failed"); + retval = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + pr_debug("ioremap failed"); + retval = -ENOMEM; + goto err2; + } + + ehci = hcd_to_ehci(hcd); + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase)); + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = readl(&ehci->caps->hcs_params); + + /* ehci_hcd_init(hcd_to_ehci(hcd)); */ + + retval = + usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ); + if (retval == 0) + return retval; + + au1xxx_stop_ehc(dev); + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return retval; +} + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_ehci_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_ehci_hcd_au1xxx_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +void usb_ehci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev) +{ + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + au1xxx_stop_ehc(dev); +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ehci_au1xxx_hc_driver = { + .description = hcd_name, + .product_desc = "Au1xxx EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ehci_init, + .start = ehci_run, + .stop = ehci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#ifdef CONFIG_PM + .hub_suspend = ehci_hub_suspend, + .hub_resume = ehci_hub_resume, +#endif +}; + +/*-------------------------------------------------------------------------*/ + +static int ehci_hcd_au1xxx_drv_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = NULL; + int ret; + + pr_debug("In ehci_hcd_au1xxx_drv_probe\n"); + + if (usb_disabled()) + return -ENODEV; + + ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev); + return ret; +} + +static int ehci_hcd_au1xxx_drv_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + usb_ehci_au1xxx_remove(hcd, pdev); + return 0; +} + + /*TBD*/ +/*static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return 0; +} +static int ehci_hcd_au1xxx_drv_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct usb_hcd *hcd = dev_get_drvdata(dev); + + return 0; +} +*/ +static struct device_driver ehci_hcd_au1xxx_driver = { + .name = "au1xxx-ehci", + .bus = &platform_bus_type, + .probe = ehci_hcd_au1xxx_drv_probe, + .remove = ehci_hcd_au1xxx_drv_remove, + /*.suspend = ehci_hcd_au1xxx_drv_suspend, */ + /*.resume = ehci_hcd_au1xxx_drv_resume, */ +}; + +static int __init ehci_hcd_au1xxx_init(void) +{ + pr_debug(DRIVER_INFO " (Au1xxx)\n"); + + return driver_register(&ehci_hcd_au1xxx_driver); +} + +static void __exit ehci_hcd_au1xxx_cleanup(void) +{ + driver_unregister(&ehci_hcd_au1xxx_driver); +} + +module_init(ehci_hcd_au1xxx_init); +module_exit(ehci_hcd_au1xxx_cleanup); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8730babb5771..79f2d8b9bfb6 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -889,14 +889,19 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_PCI #include "ehci-pci.c" +#define EHCI_BUS_GLUED #endif #ifdef CONFIG_PPC_83xx #include "ehci-fsl.c" +#define EHCI_BUS_GLUED #endif -#if !(defined(CONFIG_PCI) || \ - defined(CONFIG_PPC_83xx) \ - ) +#ifdef CONFIG_SOC_AU1X00 +#include "ehci-au1xxx.c" +#define EHCI_BUS_GLUED +#endif + +#ifndef EHCI_BUS_GLUED #error "missing bus glue for ehci-hcd" #endif -- cgit v1.2.2 From d5fb7f1b5b832946eaf450b2a695ec3e7fd2d351 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 20 Jan 2006 14:09:54 -0800 Subject: [PATCH] USB: OHCI for AU1200 ALCHEMY: Add OHCI support for AU1200 Updated by moving the OHCI support out of the EHCI patch. Signed-off-by: Jordan Crouse Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-au1xxx.c | 102 +++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 15 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index db280ca7b7a0..a1c8b3b2fcc7 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -23,6 +23,8 @@ #include +#ifndef CONFIG_SOC_AU1200 + #define USBH_ENABLE_BE (1<<0) #define USBH_ENABLE_C (1<<1) #define USBH_ENABLE_E (1<<2) @@ -37,21 +39,68 @@ #error not byte order defined #endif +#else /* Au1200 */ + +#define USB_HOST_CONFIG (USB_MSR_BASE + USB_MSR_MCFG) +#define USB_MCFG_PFEN (1<<31) +#define USB_MCFG_RDCOMB (1<<30) +#define USB_MCFG_SSDEN (1<<23) +#define USB_MCFG_OHCCLKEN (1<<16) +#define USB_MCFG_UCAM (1<<7) +#define USB_MCFG_OBMEN (1<<1) +#define USB_MCFG_OMEMEN (1<<0) + +#define USBH_ENABLE_CE USB_MCFG_OHCCLKEN +#ifdef CONFIG_DMA_COHERENT +#define USBH_ENABLE_INIT (USB_MCFG_OHCCLKEN \ + | USB_MCFG_PFEN | USB_MCFG_RDCOMB \ + | USB_MCFG_SSDEN | USB_MCFG_UCAM \ + | USB_MCFG_OBMEN | USB_MCFG_OMEMEN) +#else +#define USBH_ENABLE_INIT (USB_MCFG_OHCCLKEN \ + | USB_MCFG_PFEN | USB_MCFG_RDCOMB \ + | USB_MCFG_SSDEN \ + | USB_MCFG_OBMEN | USB_MCFG_OMEMEN) +#endif +#define USBH_DISABLE (USB_MCFG_OBMEN | USB_MCFG_OMEMEN) + +#endif /* Au1200 */ + extern int usb_disabled(void); /*-------------------------------------------------------------------------*/ -static void au1xxx_start_hc(struct platform_device *dev) +static void au1xxx_start_ohc(struct platform_device *dev) { printk(KERN_DEBUG __FILE__ ": starting Au1xxx OHCI USB Controller\n"); /* enable host controller */ + +#ifndef CONFIG_SOC_AU1200 + au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG); udelay(1000); au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG); udelay(1000); +#else /* Au1200 */ + + /* write HW defaults again in case Yamon cleared them */ + if (au_readl(USB_HOST_CONFIG) == 0) { + au_writel(0x00d02000, USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + } + au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); + udelay(1000); + +#endif /* Au1200 */ + /* wait for reset complete (read register twice; see au1500 errata) */ while (au_readl(USB_HOST_CONFIG), !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD)) @@ -61,13 +110,25 @@ static void au1xxx_start_hc(struct platform_device *dev) ": Clock to USB host has been enabled \n"); } -static void au1xxx_stop_hc(struct platform_device *dev) +static void au1xxx_stop_ohc(struct platform_device *dev) { printk(KERN_DEBUG __FILE__ ": stopping Au1xxx OHCI USB Controller\n"); +#ifndef CONFIG_SOC_AU1200 + /* Disable clock */ au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG); + +#else /* Au1200 */ + + /* Disable mem */ + au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG); + udelay(1000); + /* Disable clock */ + au_writel(~USBH_ENABLE_CE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG); + au_readl(USB_HOST_CONFIG); +#endif /* Au1200 */ } @@ -78,7 +139,7 @@ static void au1xxx_stop_hc(struct platform_device *dev) /** - * usb_hcd_au1xxx_probe - initialize Au1xxx-based HCDs + * usb_ohci_au1xxx_probe - initialize Au1xxx-based HCDs * Context: !in_interrupt() * * Allocates basic resources for this USB host controller, and @@ -86,14 +147,25 @@ static void au1xxx_stop_hc(struct platform_device *dev) * through the hotplug entry's driver_data. * */ -int usb_hcd_au1xxx_probe (const struct hc_driver *driver, +static int usb_ohci_au1xxx_probe(const struct hc_driver *driver, struct platform_device *dev) { int retval; struct usb_hcd *hcd; - if(dev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug ("resource[1] is not IORESOURCE_IRQ"); +#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT) + /* Au1200 AB USB does not support coherent memory */ + if (!(read_c0_prid() & 0xff)) { + pr_info("%s: this is chip revision AB !!\n", + dev->dev.name); + pr_info("%s: update your board or re-configure the kernel\n", + dev->dev.name); + return -ENODEV; + } +#endif + + if (dev->resource[1].flags != IORESOURCE_IRQ) { + pr_debug("resource[1] is not IORESOURCE_IRQ\n"); return -ENOMEM; } @@ -104,26 +176,26 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver, hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); + pr_debug("request_mem_region failed\n"); retval = -EBUSY; goto err1; } hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { - pr_debug("ioremap failed"); + pr_debug("ioremap failed\n"); retval = -ENOMEM; goto err2; } - au1xxx_start_hc(dev); + au1xxx_start_ohc(dev); ohci_hcd_init(hcd_to_ohci(hcd)); - retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); + retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ); if (retval == 0) return retval; - au1xxx_stop_hc(dev); + au1xxx_stop_ohc(dev); iounmap(hcd->regs); err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); @@ -146,10 +218,10 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver, * context, normally "rmmod", "apmd", or something similar. * */ -void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev) +static void usb_ohci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev) { usb_remove_hcd(hcd); - au1xxx_stop_hc(dev); + au1xxx_stop_ohc(dev); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); @@ -235,7 +307,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; - ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev); + ret = usb_ohci_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev); return ret; } @@ -243,7 +315,7 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - usb_hcd_au1xxx_remove(hcd, pdev); + usb_ohci_au1xxx_remove(hcd, pdev); return 0; } /*TBD*/ -- cgit v1.2.2 From d0852299381326c5d8eb67771aa98108050e6901 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Fri, 20 Jan 2006 14:35:55 -0800 Subject: [PATCH] USB: EHCI unlink tweaks This patch modifies the behavior of the EHCI driver in an unlink path that seems to be causing various issues on some systems. Those problems have included issues with disconnection, driver unbinding, and similar cases where urb unlinking would just not work right. This patch should help avoid those problems by not turning off the async (control/bulk) schedule until it's not expecting an "async advance" IRQ, which comes from the processing passing the schedule head. Whether the driver attempts to do such things is dependent on system timings, so many folk would never have seen these problems. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 6e28e593c044..5ada7cd5698b 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1022,12 +1022,14 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) /* stop async schedule right now? */ if (unlikely (qh == ehci->async)) { /* can't get here without STS_ASS set */ - if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) { + if (ehci_to_hcd(ehci)->state != HC_STATE_HALT + && !ehci->reclaim) { + /* ... and CMD_IAAD clear */ writel (cmd & ~CMD_ASE, &ehci->regs->command); wmb (); // handshake later, if we need to + timer_action_done (ehci, TIMER_ASYNC_OFF); } - timer_action_done (ehci, TIMER_ASYNC_OFF); return; } -- cgit v1.2.2 From 39a269c09f854d3d98cbb755b3568175f04efa10 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Sun, 22 Jan 2006 10:32:13 -0800 Subject: [PATCH] USB: add support for OCHI on AT91rm9200 This adds support for OHCI on AT91rm9200 based boards. Possibly of interest here is the way this uses to gate clocks on/off during system pm state transitions. That's typical for non-PCI systems. Some can go further; Mini-A host side connectors enable ID-pin sensing. From: Andrew Victor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 1 + drivers/usb/Makefile | 1 + drivers/usb/host/ohci-at91.c | 306 +++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ohci-hcd.c | 5 + 4 files changed, 313 insertions(+) create mode 100644 drivers/usb/host/ohci-at91.c (limited to 'drivers/usb') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 0e865975899f..b1222cd4aa46 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -23,6 +23,7 @@ config USB_ARCH_HAS_OHCI default y if ARCH_LH7A404 default y if ARCH_S3C2410 default y if PXA27x + default y if ARCH_AT91RM9200 # PPC: default y if STB03xxx default y if PPC_MPC52xx diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 7796ecfc0765..bb36a1c1dbb3 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_OHCI_HCD) += host/ obj-$(CONFIG_USB_UHCI_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_ETRAX_USB_HOST) += host/ +obj-$(CONFIG_USB_OHCI_AT91) += host/ obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_PRINTER) += class/ diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c new file mode 100644 index 000000000000..980030d684d5 --- /dev/null +++ b/drivers/usb/host/ohci-at91.c @@ -0,0 +1,306 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * Copyright (C) 2004 SAN People (Pty) Ltd. + * Copyright (C) 2005 Thibaut VARENE + * + * AT91RM9200 Bus Glue + * + * Based on fragments of 2.4 driver by Rick Bronson. + * Based on ohci-omap.c + * + * This file is licenced under the GPL. + */ + +#include +#include + +#include +#include +#include + +#ifndef CONFIG_ARCH_AT91RM9200 +#error "This file is AT91RM9200 bus glue. CONFIG_ARCH_AT91RM9200 must be defined." +#endif + +/* interface and function clocks */ +static struct clk *iclk, *fclk; + +extern int usb_disabled(void); + +/*-------------------------------------------------------------------------*/ + +static void at91_start_hc(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_regs __iomem *regs = hcd->regs; + + dev_dbg(&pdev->dev, "starting AT91RM9200 OHCI USB Controller\n"); + + /* + * Start the USB clocks. + */ + clk_enable(iclk); + clk_enable(fclk); + + /* + * The USB host controller must remain in reset. + */ + writel(0, ®s->control); +} + +static void at91_stop_hc(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_regs __iomem *regs = hcd->regs; + + dev_dbg(&pdev->dev, "stopping AT91RM9200 OHCI USB Controller\n"); + + /* + * Put the USB host controller into reset. + */ + writel(0, ®s->control); + + /* + * Stop the USB clocks. + */ + clk_disable(fclk); + clk_disable(iclk); +} + + +/*-------------------------------------------------------------------------*/ + +static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); + +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ + + +/** + * usb_hcd_at91_probe - initialize AT91RM9200-based HCDs + * Context: !in_interrupt() + * + * Allocates basic resources for this USB host controller, and + * then invokes the start() method for the HCD associated with it + * through the hotplug entry's driver_data. + * + * Store this function in the HCD's struct pci_driver as probe(). + */ +int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev) +{ + int retval; + struct usb_hcd *hcd = NULL; + + if (pdev->num_resources != 2) { + pr_debug("hcd probe: invalid num_resources"); + return -ENODEV; + } + + if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) { + pr_debug("hcd probe: invalid resource type\n"); + return -ENODEV; + } + + hcd = usb_create_hcd(driver, &pdev->dev, "at91rm9200"); + if (!hcd) + return -ENOMEM; + hcd->rsrc_start = pdev->resource[0].start; + hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + pr_debug("request_mem_region failed\n"); + retval = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + pr_debug("ioremap failed\n"); + retval = -EIO; + goto err2; + } + + iclk = clk_get(&pdev->dev, "ohci_clk"); + fclk = clk_get(&pdev->dev, "uhpck"); + + at91_start_hc(pdev); + ohci_hcd_init(hcd_to_ohci(hcd)); + + retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT); + if (retval == 0) + return retval; + + /* Error handling */ + at91_stop_hc(pdev); + + clk_put(fclk); + clk_put(iclk); + + iounmap(hcd->regs); + + err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + err1: + usb_put_hcd(hcd); + return retval; +} + + +/* may be called without controller electrically present */ +/* may be called with controller, bus, and devices active */ + +/** + * usb_hcd_at91_remove - shutdown processing for AT91RM9200-based HCDs + * @dev: USB Host Controller being removed + * Context: !in_interrupt() + * + * Reverses the effect of usb_hcd_at91_probe(), first invoking + * the HCD's stop() method. It is always called from a thread + * context, normally "rmmod", "apmd", or something similar. + * + */ +static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pdev) +{ + usb_remove_hcd(hcd); + at91_stop_hc(pdev); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + clk_put(fclk); + clk_put(iclk); + fclk = iclk = NULL; + + dev_set_drvdata(&pdev->dev, NULL); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static int __devinit +ohci_at91_start (struct usb_hcd *hcd) +{ +// struct at91_ohci_data *board = hcd->self.controller->platform_data; + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + err("can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + return ret; + } +// hcd->self.root_hub->maxchild = board->ports; + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static const struct hc_driver ohci_at91_hc_driver = { + .description = hcd_name, + .product_desc = "AT91RM9200 OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_at91_start, + .stop = ohci_stop, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + +#ifdef CONFIG_PM + .hub_suspend = ohci_hub_suspend, + .hub_resume = ohci_hub_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + +/*-------------------------------------------------------------------------*/ + +static int ohci_hcd_at91_drv_probe(struct platform_device *dev) +{ + return usb_hcd_at91_probe(&ohci_at91_hc_driver, dev); +} + +static int ohci_hcd_at91_drv_remove(struct platform_device *dev) +{ + return usb_hcd_at91_remove(platform_get_drvdata(dev), dev); +} + +#ifdef CONFIG_PM +static int ohci_hcd_at91_drv_suspend(struct platform_device *dev, u32 state, u32 level) +{ + printk("%s(%s:%d): not implemented yet\n", + __func__, __FILE__, __LINE__); + + clk_disable(fclk); + + return 0; +} + +static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state) +{ + printk("%s(%s:%d): not implemented yet\n", + __func__, __FILE__, __LINE__); + + clk_enable(fclk); + + return 0; +} +#else +#define ohci_hcd_at91_drv_suspend NULL +#define ohci_hcd_at91_drv_resume NULL +#endif + +static struct platform_driver ohci_hcd_at91_driver = { + .probe = ohci_hcd_at91_drv_probe, + .remove = ohci_hcd_at91_drv_remove, + .suspend = ohci_hcd_at91_drv_suspend, + .resume = ohci_hcd_at91_drv_resume, + .driver = { + .name = "at91rm9200-ohci", + .owner = THIS_MODULE, + }, +}; + +static int __init ohci_hcd_at91_init (void) +{ + if (usb_disabled()) + return -ENODEV; + + return platform_driver_register(&ohci_hcd_at91_driver); +} + +static void __exit ohci_hcd_at91_cleanup (void) +{ + platform_driver_unregister(&ohci_hcd_at91_driver); +} + +module_init (ohci_hcd_at91_init); +module_exit (ohci_hcd_at91_cleanup); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index a4b12404ae08..2990be269000 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -905,6 +905,10 @@ MODULE_LICENSE ("GPL"); #include "ohci-ppc-soc.c" #endif +#ifdef CONFIG_ARCH_AT91RM9200 +#include "ohci-at91.c" +#endif + #if !(defined(CONFIG_PCI) \ || defined(CONFIG_SA1111) \ || defined(CONFIG_ARCH_S3C2410) \ @@ -913,6 +917,7 @@ MODULE_LICENSE ("GPL"); || defined (CONFIG_PXA27x) \ || defined (CONFIG_SOC_AU1X00) \ || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ + || defined (CONFIG_ARCH_AT91RM9200) \ ) #error "missing bus glue for ohci-hcd" #endif -- cgit v1.2.2 From bae4bd848dc0b7e6defc7a5d62834a35d1eed06d Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 22 Jan 2006 10:32:37 -0800 Subject: [PATCH] USB: add support for AT91 gadget This adds support for the USB peripheral controller on AT91 (rm9200, eventually also sam9261 or uClinux) platforms. More SOC support for Linux-USB ... an uncomplicated pure PIO driver. It'd be worth using this as a model, if you're starting a driver for some other peripheral controller. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/Kconfig | 17 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/at91_udc.c | 1773 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/at91_udc.h | 181 +++++ 4 files changed, 1972 insertions(+) create mode 100644 drivers/usb/gadget/at91_udc.c create mode 100644 drivers/usb/gadget/at91_udc.h (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index ff075a53c8d6..d80f71877d68 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -187,6 +187,23 @@ config USB_OTG Select this only if your OMAP board has a Mini-AB connector. +config USB_GADGET_AT91 + boolean "AT91 USB Device Port" + depends on ARCH_AT91RM9200 + select USB_GADGET_SELECTED + help + Many Atmel AT91 processors (such as the AT91RM2000) have a + full speed USB Device Port with support for five configurable + endpoints (plus endpoint zero). + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "at91_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_AT91 + tristate + depends on USB_GADGET_AT91 + default USB_GADGET config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index d5fd04d886e6..5a28e61392ec 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o +obj-$(CONFIG_USB_AT91) += at91_udc.o # # USB gadget drivers diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c new file mode 100644 index 000000000000..865858cfd1c2 --- /dev/null +++ b/drivers/usb/gadget/at91_udc.c @@ -0,0 +1,1773 @@ +/* + * at91_udc -- driver for at91-series USB peripheral controller + * + * Copyright (C) 2004 by Thomas Rathbone + * Copyright (C) 2005 by HP Labs + * Copyright (C) 2005 by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#undef DEBUG +#undef VERBOSE +#undef PACKET_TRACE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "at91_udc.h" + + +/* + * This controller is simple and PIO-only. It's used in many AT91-series + * ARMv4T controllers, including the at91rm9200 (arm920T, with MMU), + * at91sam9261 (arm926ejs, with MMU), and several no-mmu versions. + * + * This driver expects the board has been wired with two GPIOs suppporting + * a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the + * testing hasn't covered such cases.) The pullup is most important; it + * provides software control over whether the host enumerates the device. + * The VBUS sensing helps during enumeration, and allows both USB clocks + * (and the transceiver) to stay gated off until they're necessary, saving + * power. During USB suspend, the 48 MHz clock is gated off. + */ + +#define DRIVER_VERSION "8 March 2005" + +static const char driver_name [] = "at91_udc"; +static const char ep0name[] = "ep0"; + +/*-------------------------------------------------------------------------*/ + +/* + * Read from a UDP register. + */ +static inline unsigned long at91_udp_read(unsigned int reg) +{ + void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP; + + return __raw_readl(udp_base + reg); +} + +/* + * Write to a UDP register. + */ +static inline void at91_udp_write(unsigned int reg, unsigned long value) +{ + void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP; + + __raw_writel(value, udp_base + reg); +} + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +#include + +static const char debug_filename[] = "driver/udc"; + +#define FOURBITS "%s%s%s%s" +#define EIGHTBITS FOURBITS FOURBITS + +static void proc_ep_show(struct seq_file *s, struct at91_ep *ep) +{ + static char *types[] = { + "control", "out-iso", "out-bulk", "out-int", + "BOGUS", "in-iso", "in-bulk", "in-int"}; + + u32 csr; + struct at91_request *req; + unsigned long flags; + + local_irq_save(flags); + + csr = __raw_readl(ep->creg); + + /* NOTE: not collecting per-endpoint irq statistics... */ + + seq_printf(s, "\n"); + seq_printf(s, "%s, maxpacket %d %s%s %s%s\n", + ep->ep.name, ep->ep.maxpacket, + ep->is_in ? "in" : "out", + ep->is_iso ? " iso" : "", + ep->is_pingpong + ? (ep->fifo_bank ? "pong" : "ping") + : "", + ep->stopped ? " stopped" : ""); + seq_printf(s, "csr %08x rxbytes=%d %s %s %s" EIGHTBITS "\n", + csr, + (csr & 0x07ff0000) >> 16, + (csr & (1 << 15)) ? "enabled" : "disabled", + (csr & (1 << 11)) ? "DATA1" : "DATA0", + types[(csr & 0x700) >> 8], + + /* iff type is control then print current direction */ + (!(csr & 0x700)) + ? ((csr & (1 << 7)) ? " IN" : " OUT") + : "", + (csr & (1 << 6)) ? " rxdatabk1" : "", + (csr & (1 << 5)) ? " forcestall" : "", + (csr & (1 << 4)) ? " txpktrdy" : "", + + (csr & (1 << 3)) ? " stallsent" : "", + (csr & (1 << 2)) ? " rxsetup" : "", + (csr & (1 << 1)) ? " rxdatabk0" : "", + (csr & (1 << 0)) ? " txcomp" : ""); + if (list_empty (&ep->queue)) + seq_printf(s, "\t(queue empty)\n"); + + else list_for_each_entry (req, &ep->queue, queue) { + unsigned length = req->req.actual; + + seq_printf(s, "\treq %p len %d/%d buf %p\n", + &req->req, length, + req->req.length, req->req.buf); + } + local_irq_restore(flags); +} + +static void proc_irq_show(struct seq_file *s, const char *label, u32 mask) +{ + int i; + + seq_printf(s, "%s %04x:%s%s" FOURBITS, label, mask, + (mask & (1 << 13)) ? " wakeup" : "", + (mask & (1 << 12)) ? " endbusres" : "", + + (mask & (1 << 11)) ? " sofint" : "", + (mask & (1 << 10)) ? " extrsm" : "", + (mask & (1 << 9)) ? " rxrsm" : "", + (mask & (1 << 8)) ? " rxsusp" : ""); + for (i = 0; i < 8; i++) { + if (mask & (1 << i)) + seq_printf(s, " ep%d", i); + } + seq_printf(s, "\n"); +} + +static int proc_udc_show(struct seq_file *s, void *unused) +{ + struct at91_udc *udc = s->private; + struct at91_ep *ep; + u32 tmp; + + seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION); + + seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n", + udc->vbus ? "present" : "off", + udc->enabled + ? (udc->vbus ? "active" : "enabled") + : "disabled", + udc->selfpowered ? "self" : "VBUS", + udc->suspended ? ", suspended" : "", + udc->driver ? udc->driver->driver.name : "(none)"); + + /* don't access registers when interface isn't clocked */ + if (!udc->clocked) { + seq_printf(s, "(not clocked)\n"); + return 0; + } + + tmp = at91_udp_read(AT91_UDP_FRM_NUM); + seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp, + (tmp & AT91_UDP_FRM_OK) ? " ok" : "", + (tmp & AT91_UDP_FRM_ERR) ? " err" : "", + (tmp & AT91_UDP_NUM)); + + tmp = at91_udp_read(AT91_UDP_GLB_STAT); + seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp, + (tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "", + (tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "", + (tmp & AT91_UDP_ESR) ? " esr" : "", + (tmp & AT91_UDP_CONFG) ? " confg" : "", + (tmp & AT91_UDP_FADDEN) ? " fadden" : ""); + + tmp = at91_udp_read(AT91_UDP_FADDR); + seq_printf(s, "faddr %03x:%s fadd=%d\n", tmp, + (tmp & AT91_UDP_FEN) ? " fen" : "", + (tmp & AT91_UDP_FADD)); + + proc_irq_show(s, "imr ", at91_udp_read(AT91_UDP_IMR)); + proc_irq_show(s, "isr ", at91_udp_read(AT91_UDP_ISR)); + + if (udc->enabled && udc->vbus) { + proc_ep_show(s, &udc->ep[0]); + list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) + proc_ep_show(s, ep); + } + } + return 0; +} + +static int proc_udc_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_udc_show, PDE(inode)->data); +} + +static struct file_operations proc_ops = { + .open = proc_udc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void create_debug_file(struct at91_udc *udc) +{ + struct proc_dir_entry *pde; + + pde = create_proc_entry (debug_filename, 0, NULL); + udc->pde = pde; + if (pde == NULL) + return; + + pde->proc_fops = &proc_ops; + pde->data = udc; +} + +static void remove_debug_file(struct at91_udc *udc) +{ + if (udc->pde) + remove_proc_entry(debug_filename, NULL); +} + +#else + +static inline void create_debug_file(struct at91_udc *udc) {} +static inline void remove_debug_file(struct at91_udc *udc) {} + +#endif + + +/*-------------------------------------------------------------------------*/ + +static void done(struct at91_ep *ep, struct at91_request *req, int status) +{ + unsigned stopped = ep->stopped; + + list_del_init(&req->queue); + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + if (status && status != -ESHUTDOWN) + VDBG("%s done %p, status %d\n", ep->ep.name, req, status); + + ep->stopped = 1; + req->req.complete(&ep->ep, &req->req); + ep->stopped = stopped; + + /* ep0 is always ready; other endpoints need a non-empty queue */ + if (list_empty(&ep->queue) && ep->int_mask != (1 << 0)) + at91_udp_write(AT91_UDP_IDR, ep->int_mask); +} + +/*-------------------------------------------------------------------------*/ + +/* bits indicating OUT fifo has data ready */ +#define RX_DATA_READY (AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1) + +/* + * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write + * back most of the value you just read (because of side effects, including + * bits that may change after reading and before writing). + * + * Except when changing a specific bit, always write values which: + * - clear SET_FX bits (setting them could change something) + * - set CLR_FX bits (clearing them could change something) + * + * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE + * that shouldn't normally be changed. + */ +#define SET_FX (AT91_UDP_TXPKTRDY) +#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP) + +/* pull OUT packet data from the endpoint's fifo */ +static int read_fifo (struct at91_ep *ep, struct at91_request *req) +{ + u32 __iomem *creg = ep->creg; + u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); + u32 csr; + u8 *buf; + unsigned int count, bufferspace, is_done; + + buf = req->req.buf + req->req.actual; + bufferspace = req->req.length - req->req.actual; + + /* + * there might be nothing to read if ep_queue() calls us, + * or if we already emptied both pingpong buffers + */ +rescan: + csr = __raw_readl(creg); + if ((csr & RX_DATA_READY) == 0) + return 0; + + count = (csr & AT91_UDP_RXBYTECNT) >> 16; + if (count > ep->ep.maxpacket) + count = ep->ep.maxpacket; + if (count > bufferspace) { + DBG("%s buffer overflow\n", ep->ep.name); + req->req.status = -EOVERFLOW; + count = bufferspace; + } + __raw_readsb(dreg, buf, count); + + /* release and swap pingpong mem bank */ + csr |= CLR_FX; + if (ep->is_pingpong) { + if (ep->fifo_bank == 0) { + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); + ep->fifo_bank = 1; + } else { + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1); + ep->fifo_bank = 0; + } + } else + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); + __raw_writel(csr, creg); + + req->req.actual += count; + is_done = (count < ep->ep.maxpacket); + if (count == bufferspace) + is_done = 1; + + PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count, + is_done ? " (done)" : ""); + + /* + * avoid extra trips through IRQ logic for packets already in + * the fifo ... maybe preventing an extra (expensive) OUT-NAK + */ + if (is_done) + done(ep, req, 0); + else if (ep->is_pingpong) { + bufferspace -= count; + buf += count; + goto rescan; + } + + return is_done; +} + +/* load fifo for an IN packet */ +static int write_fifo(struct at91_ep *ep, struct at91_request *req) +{ + u32 __iomem *creg = ep->creg; + u32 csr = __raw_readl(creg); + u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); + unsigned total, count, is_last; + + /* + * TODO: allow for writing two packets to the fifo ... that'll + * reduce the amount of IN-NAKing, but probably won't affect + * throughput much. (Unlike preventing OUT-NAKing!) + */ + + /* + * If ep_queue() calls us, the queue is empty and possibly in + * odd states like TXCOMP not yet cleared (we do it, saving at + * least one IRQ) or the fifo not yet being free. Those aren't + * issues normally (IRQ handler fast path). + */ + if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) { + if (csr & AT91_UDP_TXCOMP) { + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_TXCOMP); + __raw_writel(csr, creg); + csr = __raw_readl(creg); + } + if (csr & AT91_UDP_TXPKTRDY) + return 0; + } + + total = req->req.length - req->req.actual; + if (ep->ep.maxpacket < total) { + count = ep->ep.maxpacket; + is_last = 0; + } else { + count = total; + is_last = (count < ep->ep.maxpacket) || !req->req.zero; + } + + /* + * Write the packet, maybe it's a ZLP. + * + * NOTE: incrementing req->actual before we receive the ACK means + * gadget driver IN bytecounts can be wrong in fault cases. That's + * fixable with PIO drivers like this one (save "count" here, and + * do the increment later on TX irq), but not for most DMA hardware. + * + * So all gadget drivers must accept that potential error. Some + * hardware supports precise fifo status reporting, letting them + * recover when the actual bytecount matters (e.g. for USB Test + * and Measurement Class devices). + */ + __raw_writesb(dreg, req->req.buf + req->req.actual, count); + csr &= ~SET_FX; + csr |= CLR_FX | AT91_UDP_TXPKTRDY; + __raw_writel(csr, creg); + req->req.actual += count; + + PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count, + is_last ? " (done)" : ""); + if (is_last) + done(ep, req, 0); + return is_last; +} + +static void nuke(struct at91_ep *ep, int status) +{ + struct at91_request *req; + + // terminer chaque requete dans la queue + ep->stopped = 1; + if (list_empty(&ep->queue)) + return; + + VDBG("%s %s\n", __FUNCTION__, ep->ep.name); + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct at91_request, queue); + done(ep, req, status); + } +} + +/*-------------------------------------------------------------------------*/ + +static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + struct at91_udc *dev = ep->udc; + u16 maxpacket; + u32 tmp; + unsigned long flags; + + if (!_ep || !ep + || !desc || ep->desc + || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT + || (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0 + || maxpacket > ep->maxpacket) { + DBG("bad ep or descriptor\n"); + return -EINVAL; + } + + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + DBG("bogus device state\n"); + return -ESHUTDOWN; + } + + tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + switch (tmp) { + case USB_ENDPOINT_XFER_CONTROL: + DBG("only one control endpoint\n"); + return -EINVAL; + case USB_ENDPOINT_XFER_INT: + if (maxpacket > 64) + goto bogus_max; + break; + case USB_ENDPOINT_XFER_BULK: + switch (maxpacket) { + case 8: + case 16: + case 32: + case 64: + goto ok; + } +bogus_max: + DBG("bogus maxpacket %d\n", maxpacket); + return -EINVAL; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->is_pingpong) { + DBG("iso requires double buffering\n"); + return -EINVAL; + } + break; + } + +ok: + local_irq_save(flags); + + /* initialize endpoint to match this descriptor */ + ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0; + ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); + ep->stopped = 0; + if (ep->is_in) + tmp |= 0x04; + tmp <<= 8; + tmp |= AT91_UDP_EPEDS; + __raw_writel(tmp, ep->creg); + + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + /* + * reset/init endpoint fifo. NOTE: leaves fifo_bank alone, + * since endpoint resets don't reset hw pingpong state. + */ + at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(AT91_UDP_RST_EP, 0); + + local_irq_restore(flags); + return 0; +} + +static int at91_ep_disable (struct usb_ep * _ep) +{ + struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + unsigned long flags; + + if (ep == &ep->udc->ep[0]) + return -EINVAL; + + local_irq_save(flags); + + nuke(ep, -ESHUTDOWN); + + /* restore the endpoint's pristine config */ + ep->desc = NULL; + ep->ep.maxpacket = ep->maxpacket; + + /* reset fifos and endpoint */ + if (ep->udc->clocked) { + at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(AT91_UDP_RST_EP, 0); + __raw_writel(0, ep->creg); + } + + local_irq_restore(flags); + return 0; +} + +/* + * this is a PIO-only driver, so there's nothing + * interesting for request or buffer allocation. + */ + +static struct usb_request *at91_ep_alloc_request (struct usb_ep *_ep, unsigned int gfp_flags) +{ + struct at91_request *req; + + req = kcalloc(1, sizeof (struct at91_request), SLAB_KERNEL); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + return &req->req; +} + +static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct at91_request *req; + + req = container_of(_req, struct at91_request, req); + BUG_ON(!list_empty(&req->queue)); + kfree(req); +} + +static void *at91_ep_alloc_buffer( + struct usb_ep *_ep, + unsigned bytes, + dma_addr_t *dma, + gfp_t gfp_flags) +{ + *dma = ~0; + return kmalloc(bytes, gfp_flags); +} + +static void at91_ep_free_buffer( + struct usb_ep *ep, + void *buf, + dma_addr_t dma, + unsigned bytes) +{ + kfree(buf); +} + +static int at91_ep_queue(struct usb_ep *_ep, + struct usb_request *_req, gfp_t gfp_flags) +{ + struct at91_request *req; + struct at91_ep *ep; + struct at91_udc *dev; + int status; + unsigned long flags; + + req = container_of(_req, struct at91_request, req); + ep = container_of(_ep, struct at91_ep, ep); + + if (!_req || !_req->complete + || !_req->buf || !list_empty(&req->queue)) { + DBG("invalid request\n"); + return -EINVAL; + } + + if (!_ep || (!ep->desc && ep->ep.name != ep0name)) { + DBG("invalid ep\n"); + return -EINVAL; + } + + dev = ep->udc; + + if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + DBG("invalid device\n"); + return -EINVAL; + } + + _req->status = -EINPROGRESS; + _req->actual = 0; + + local_irq_save(flags); + + /* try to kickstart any empty and idle queue */ + if (list_empty(&ep->queue) && !ep->stopped) { + int is_ep0; + + /* + * If this control request has a non-empty DATA stage, this + * will start that stage. It works just like a non-control + * request (until the status stage starts, maybe early). + * + * If the data stage is empty, then this starts a successful + * IN/STATUS stage. (Unsuccessful ones use set_halt.) + */ + is_ep0 = (ep->ep.name == ep0name); + if (is_ep0) { + u32 tmp; + + if (!dev->req_pending) { + status = -EINVAL; + goto done; + } + + /* + * defer changing CONFG until after the gadget driver + * reconfigures the endpoints. + */ + if (dev->wait_for_config_ack) { + tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp ^= AT91_UDP_CONFG; + VDBG("toggle config\n"); + at91_udp_write(AT91_UDP_GLB_STAT, tmp); + } + if (req->req.length == 0) { +ep0_in_status: + PACKET("ep0 in/status\n"); + status = 0; + tmp = __raw_readl(ep->creg); + tmp &= ~SET_FX; + tmp |= CLR_FX | AT91_UDP_TXPKTRDY; + __raw_writel(tmp, ep->creg); + dev->req_pending = 0; + goto done; + } + } + + if (ep->is_in) + status = write_fifo(ep, req); + else { + status = read_fifo(ep, req); + + /* IN/STATUS stage is otherwise triggered by irq */ + if (status && is_ep0) + goto ep0_in_status; + } + } else + status = 0; + + if (req && !status) { + list_add_tail (&req->queue, &ep->queue); + at91_udp_write(AT91_UDP_IER, ep->int_mask); + } +done: + local_irq_restore(flags); + return (status < 0) ? status : 0; +} + +static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct at91_ep *ep; + struct at91_request *req; + + ep = container_of(_ep, struct at91_ep, ep); + if (!_ep || ep->ep.name == ep0name) + return -EINVAL; + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry (req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) + return -EINVAL; + + done(ep, req, -ECONNRESET); + return 0; +} + +static int at91_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + u32 __iomem *creg; + u32 csr; + unsigned long flags; + int status = 0; + + if (!_ep || ep->is_iso || !ep->udc->clocked) + return -EINVAL; + + creg = ep->creg; + local_irq_save(flags); + + csr = __raw_readl(creg); + + /* + * fail with still-busy IN endpoints, ensuring correct sequencing + * of data tx then stall. note that the fifo rx bytecount isn't + * completely accurate as a tx bytecount. + */ + if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0)) + status = -EAGAIN; + else { + csr |= CLR_FX; + csr &= ~SET_FX; + if (value) { + csr |= AT91_UDP_FORCESTALL; + VDBG("halt %s\n", ep->ep.name); + } else { + at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(AT91_UDP_RST_EP, 0); + csr &= ~AT91_UDP_FORCESTALL; + } + __raw_writel(csr, creg); + } + + local_irq_restore(flags); + return status; +} + +static struct usb_ep_ops at91_ep_ops = { + .enable = at91_ep_enable, + .disable = at91_ep_disable, + .alloc_request = at91_ep_alloc_request, + .free_request = at91_ep_free_request, + .alloc_buffer = at91_ep_alloc_buffer, + .free_buffer = at91_ep_free_buffer, + .queue = at91_ep_queue, + .dequeue = at91_ep_dequeue, + .set_halt = at91_ep_set_halt, + // there's only imprecise fifo status reporting +}; + +/*-------------------------------------------------------------------------*/ + +static int at91_get_frame(struct usb_gadget *gadget) +{ + if (!to_udc(gadget)->clocked) + return -EINVAL; + return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM; +} + +static int at91_wakeup(struct usb_gadget *gadget) +{ + struct at91_udc *udc = to_udc(gadget); + u32 glbstate; + int status = -EINVAL; + unsigned long flags; + + DBG("%s\n", __FUNCTION__ ); + local_irq_save(flags); + + if (!udc->clocked || !udc->suspended) + goto done; + + /* NOTE: some "early versions" handle ESR differently ... */ + + glbstate = at91_udp_read(AT91_UDP_GLB_STAT); + if (!(glbstate & AT91_UDP_ESR)) + goto done; + glbstate |= AT91_UDP_ESR; + at91_udp_write(AT91_UDP_GLB_STAT, glbstate); + +done: + local_irq_restore(flags); + return status; +} + +/* reinit == restore inital software state */ +static void udc_reinit(struct at91_udc *udc) +{ + u32 i; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct at91_ep *ep = &udc->ep[i]; + + if (i != 0) + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + ep->desc = NULL; + ep->stopped = 0; + ep->fifo_bank = 0; + ep->ep.maxpacket = ep->maxpacket; + // initialiser une queue par endpoint + INIT_LIST_HEAD(&ep->queue); + } +} + +static void stop_activity(struct at91_udc *udc) +{ + struct usb_gadget_driver *driver = udc->driver; + int i; + + if (udc->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + udc->gadget.speed = USB_SPEED_UNKNOWN; + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct at91_ep *ep = &udc->ep[i]; + ep->stopped = 1; + nuke(ep, -ESHUTDOWN); + } + if (driver) + driver->disconnect(&udc->gadget); + + udc_reinit(udc); +} + +static void clk_on(struct at91_udc *udc) +{ + if (udc->clocked) + return; + udc->clocked = 1; + clk_enable(udc->iclk); + clk_enable(udc->fclk); +} + +static void clk_off(struct at91_udc *udc) +{ + if (!udc->clocked) + return; + udc->clocked = 0; + udc->gadget.speed = USB_SPEED_UNKNOWN; + clk_disable(udc->iclk); + clk_disable(udc->fclk); +} + +/* + * activate/deactivate link with host; minimize power usage for + * inactive links by cutting clocks and transceiver power. + */ +static void pullup(struct at91_udc *udc, int is_on) +{ + if (!udc->enabled || !udc->vbus) + is_on = 0; + DBG("%sactive\n", is_on ? "" : "in"); + if (is_on) { + clk_on(udc); + at91_udp_write(AT91_UDP_TXVC, 0); + at91_set_gpio_value(udc->board.pullup_pin, 1); + } else { + stop_activity(udc); + at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + at91_set_gpio_value(udc->board.pullup_pin, 0); + clk_off(udc); + + // REVISIT: with transceiver disabled, will D- float + // so that a host would falsely detect a device? + } +} + +/* vbus is here! turn everything on that's ready */ +static int at91_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct at91_udc *udc = to_udc(gadget); + unsigned long flags; + + // VDBG("vbus %s\n", is_active ? "on" : "off"); + local_irq_save(flags); + udc->vbus = (is_active != 0); + pullup(udc, is_active); + local_irq_restore(flags); + return 0; +} + +static int at91_pullup(struct usb_gadget *gadget, int is_on) +{ + struct at91_udc *udc = to_udc(gadget); + unsigned long flags; + + local_irq_save(flags); + udc->enabled = is_on = !!is_on; + pullup(udc, is_on); + local_irq_restore(flags); + return 0; +} + +static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) +{ + struct at91_udc *udc = to_udc(gadget); + unsigned long flags; + + local_irq_save(flags); + udc->selfpowered = (is_on != 0); + local_irq_restore(flags); + return 0; +} + +static const struct usb_gadget_ops at91_udc_ops = { + .get_frame = at91_get_frame, + .wakeup = at91_wakeup, + .set_selfpowered = at91_set_selfpowered, + .vbus_session = at91_vbus_session, + .pullup = at91_pullup, + + /* + * VBUS-powered devices may also also want to support bigger + * power budgets after an appropriate SET_CONFIGURATION. + */ + // .vbus_power = at91_vbus_power, +}; + +/*-------------------------------------------------------------------------*/ + +static int handle_ep(struct at91_ep *ep) +{ + struct at91_request *req; + u32 __iomem *creg = ep->creg; + u32 csr = __raw_readl(creg); + + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct at91_request, queue); + else + req = NULL; + + if (ep->is_in) { + if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) { + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP); + __raw_writel(csr, creg); + } + if (req) + return write_fifo(ep, req); + + } else { + if (csr & AT91_UDP_STALLSENT) { + /* STALLSENT bit == ISOERR */ + if (ep->is_iso && req) + req->req.status = -EILSEQ; + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_STALLSENT); + __raw_writel(csr, creg); + csr = __raw_readl(creg); + } + if (req && (csr & RX_DATA_READY)) + return read_fifo(ep, req); + } + return 0; +} + +union setup { + u8 raw[8]; + struct usb_ctrlrequest r; +}; + +static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) +{ + u32 __iomem *creg = ep->creg; + u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); + unsigned rxcount, i = 0; + u32 tmp; + union setup pkt; + int status = 0; + + /* read and ack SETUP; hard-fail for bogus packets */ + rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16; + if (likely(rxcount == 8)) { + while (rxcount--) + pkt.raw[i++] = __raw_readb(dreg); + if (pkt.r.bRequestType & USB_DIR_IN) { + csr |= AT91_UDP_DIR; + ep->is_in = 1; + } else { + csr &= ~AT91_UDP_DIR; + ep->is_in = 0; + } + } else { + // REVISIT this happens sometimes under load; why?? + ERR("SETUP len %d, csr %08x\n", rxcount, csr); + status = -EINVAL; + } + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_RXSETUP); + __raw_writel(csr, creg); + udc->wait_for_addr_ack = 0; + udc->wait_for_config_ack = 0; + ep->stopped = 0; + if (unlikely(status != 0)) + goto stall; + +#define w_index le16_to_cpu(pkt.r.wIndex) +#define w_value le16_to_cpu(pkt.r.wValue) +#define w_length le16_to_cpu(pkt.r.wLength) + + VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", + pkt.r.bRequestType, pkt.r.bRequest, + w_value, w_index, w_length); + + /* + * A few standard requests get handled here, ones that touch + * hardware ... notably for device and endpoint features. + */ + udc->req_pending = 1; + csr = __raw_readl(creg); + csr |= CLR_FX; + csr &= ~SET_FX; + switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) { + + case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_SET_ADDRESS: + __raw_writel(csr | AT91_UDP_TXPKTRDY, creg); + udc->addr = w_value; + udc->wait_for_addr_ack = 1; + udc->req_pending = 0; + /* FADDR is set later, when we ack host STATUS */ + return; + + case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_SET_CONFIGURATION: + tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG; + if (pkt.r.wValue) + udc->wait_for_config_ack = (tmp == 0); + else + udc->wait_for_config_ack = (tmp != 0); + if (udc->wait_for_config_ack) + VDBG("wait for config\n"); + /* CONFG is toggled later, if gadget driver succeeds */ + break; + + /* + * Hosts may set or clear remote wakeup status, and + * devices may report they're VBUS powered. + */ + case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_GET_STATUS: + tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED); + if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR) + tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP); + PACKET("get device status\n"); + __raw_writeb(tmp, dreg); + __raw_writeb(0, dreg); + goto write_in; + /* then STATUS starts later, automatically */ + case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_SET_FEATURE: + if (w_value != USB_DEVICE_REMOTE_WAKEUP) + goto stall; + tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp |= AT91_UDP_ESR; + at91_udp_write(AT91_UDP_GLB_STAT, tmp); + goto succeed; + case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_CLEAR_FEATURE: + if (w_value != USB_DEVICE_REMOTE_WAKEUP) + goto stall; + tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp &= ~AT91_UDP_ESR; + at91_udp_write(AT91_UDP_GLB_STAT, tmp); + goto succeed; + + /* + * Interfaces have no feature settings; this is pretty useless. + * we won't even insist the interface exists... + */ + case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) + | USB_REQ_GET_STATUS: + PACKET("get interface status\n"); + __raw_writeb(0, dreg); + __raw_writeb(0, dreg); + goto write_in; + /* then STATUS starts later, automatically */ + case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) + | USB_REQ_SET_FEATURE: + case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) + | USB_REQ_CLEAR_FEATURE: + goto stall; + + /* + * Hosts may clear bulk/intr endpoint halt after the gadget + * driver sets it (not widely used); or set it (for testing) + */ + case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) + | USB_REQ_GET_STATUS: + tmp = w_index & USB_ENDPOINT_NUMBER_MASK; + ep = &udc->ep[tmp]; + if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc)) + goto stall; + + if (tmp) { + if ((w_index & USB_DIR_IN)) { + if (!ep->is_in) + goto stall; + } else if (ep->is_in) + goto stall; + } + PACKET("get %s status\n", ep->ep.name); + if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL) + tmp = (1 << USB_ENDPOINT_HALT); + else + tmp = 0; + __raw_writeb(tmp, dreg); + __raw_writeb(0, dreg); + goto write_in; + /* then STATUS starts later, automatically */ + case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) + | USB_REQ_SET_FEATURE: + tmp = w_index & USB_ENDPOINT_NUMBER_MASK; + ep = &udc->ep[tmp]; + if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS) + goto stall; + if (!ep->desc || ep->is_iso) + goto stall; + if ((w_index & USB_DIR_IN)) { + if (!ep->is_in) + goto stall; + } else if (ep->is_in) + goto stall; + + tmp = __raw_readl(ep->creg); + tmp &= ~SET_FX; + tmp |= CLR_FX | AT91_UDP_FORCESTALL; + __raw_writel(tmp, ep->creg); + goto succeed; + case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) + | USB_REQ_CLEAR_FEATURE: + tmp = w_index & USB_ENDPOINT_NUMBER_MASK; + ep = &udc->ep[tmp]; + if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS) + goto stall; + if (tmp == 0) + goto succeed; + if (!ep->desc || ep->is_iso) + goto stall; + if ((w_index & USB_DIR_IN)) { + if (!ep->is_in) + goto stall; + } else if (ep->is_in) + goto stall; + + at91_udp_write(AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(AT91_UDP_RST_EP, 0); + tmp = __raw_readl(ep->creg); + tmp |= CLR_FX; + tmp &= ~(SET_FX | AT91_UDP_FORCESTALL); + __raw_writel(tmp, ep->creg); + if (!list_empty(&ep->queue)) + handle_ep(ep); + goto succeed; + } + +#undef w_value +#undef w_index +#undef w_length + + /* pass request up to the gadget driver */ + status = udc->driver->setup(&udc->gadget, &pkt.r); + if (status < 0) { +stall: + VDBG("req %02x.%02x protocol STALL; stat %d\n", + pkt.r.bRequestType, pkt.r.bRequest, status); + csr |= AT91_UDP_FORCESTALL; + __raw_writel(csr, creg); + udc->req_pending = 0; + } + return; + +succeed: + /* immediate successful (IN) STATUS after zero length DATA */ + PACKET("ep0 in/status\n"); +write_in: + csr |= AT91_UDP_TXPKTRDY; + __raw_writel(csr, creg); + udc->req_pending = 0; + return; +} + +static void handle_ep0(struct at91_udc *udc) +{ + struct at91_ep *ep0 = &udc->ep[0]; + u32 __iomem *creg = ep0->creg; + u32 csr = __raw_readl(creg); + struct at91_request *req; + + if (unlikely(csr & AT91_UDP_STALLSENT)) { + nuke(ep0, -EPROTO); + udc->req_pending = 0; + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL); + __raw_writel(csr, creg); + VDBG("ep0 stalled\n"); + csr = __raw_readl(creg); + } + if (csr & AT91_UDP_RXSETUP) { + nuke(ep0, 0); + udc->req_pending = 0; + handle_setup(udc, ep0, csr); + return; + } + + if (list_empty(&ep0->queue)) + req = NULL; + else + req = list_entry(ep0->queue.next, struct at91_request, queue); + + /* host ACKed an IN packet that we sent */ + if (csr & AT91_UDP_TXCOMP) { + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_TXCOMP); + + /* write more IN DATA? */ + if (req && ep0->is_in) { + if (handle_ep(ep0)) + udc->req_pending = 0; + + /* + * Ack after: + * - last IN DATA packet (including GET_STATUS) + * - IN/STATUS for OUT DATA + * - IN/STATUS for any zero-length DATA stage + * except for the IN DATA case, the host should send + * an OUT status later, which we'll ack. + */ + } else { + udc->req_pending = 0; + __raw_writel(csr, creg); + + /* + * SET_ADDRESS takes effect only after the STATUS + * (to the original address) gets acked. + */ + if (udc->wait_for_addr_ack) { + u32 tmp; + + at91_udp_write(AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr); + tmp = at91_udp_read(AT91_UDP_GLB_STAT); + tmp &= ~AT91_UDP_FADDEN; + if (udc->addr) + tmp |= AT91_UDP_FADDEN; + at91_udp_write(AT91_UDP_GLB_STAT, tmp); + + udc->wait_for_addr_ack = 0; + VDBG("address %d\n", udc->addr); + } + } + } + + /* OUT packet arrived ... */ + else if (csr & AT91_UDP_RX_DATA_BK0) { + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); + + /* OUT DATA stage */ + if (!ep0->is_in) { + if (req) { + if (handle_ep(ep0)) { + /* send IN/STATUS */ + PACKET("ep0 in/status\n"); + csr = __raw_readl(creg); + csr &= ~SET_FX; + csr |= CLR_FX | AT91_UDP_TXPKTRDY; + __raw_writel(csr, creg); + udc->req_pending = 0; + } + } else if (udc->req_pending) { + /* + * AT91 hardware has a hard time with this + * "deferred response" mode for control-OUT + * transfers. (For control-IN it's fine.) + * + * The normal solution leaves OUT data in the + * fifo until the gadget driver is ready. + * We couldn't do that here without disabling + * the IRQ that tells about SETUP packets, + * e.g. when the host gets impatient... + * + * Working around it by copying into a buffer + * would almost be a non-deferred response, + * except that it wouldn't permit reliable + * stalling of the request. Instead, demand + * that gadget drivers not use this mode. + */ + DBG("no control-OUT deferred responses!\n"); + __raw_writel(csr | AT91_UDP_FORCESTALL, creg); + udc->req_pending = 0; + } + + /* STATUS stage for control-IN; ack. */ + } else { + PACKET("ep0 out/status ACK\n"); + __raw_writel(csr, creg); + + /* "early" status stage */ + if (req) + done(ep0, req, 0); + } + } +} + +static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r) +{ + struct at91_udc *udc = _udc; + u32 rescans = 5; + + while (rescans--) { + u32 status = at91_udp_read(AT91_UDP_ISR); + + status &= at91_udp_read(AT91_UDP_IMR); + if (!status) + break; + + /* USB reset irq: not maskable */ + if (status & AT91_UDP_ENDBUSRES) { + at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS); + at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS); + /* Atmel code clears this irq twice */ + at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES); + at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES); + VDBG("end bus reset\n"); + udc->addr = 0; + stop_activity(udc); + + /* enable ep0 */ + at91_udp_write(AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); + udc->gadget.speed = USB_SPEED_FULL; + udc->suspended = 0; + at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0)); + + /* + * NOTE: this driver keeps clocks off unless the + * USB host is present. That saves power, and also + * eliminates IRQs (reset, resume, suspend) that can + * otherwise flood from the controller. If your + * board doesn't support VBUS detection, suspend and + * resume irq logic may need more attention... + */ + + /* host initiated suspend (3+ms bus idle) */ + } else if (status & AT91_UDP_RXSUSP) { + at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP); + at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM); + at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP); + // VDBG("bus suspend\n"); + if (udc->suspended) + continue; + udc->suspended = 1; + + /* + * NOTE: when suspending a VBUS-powered device, the + * gadget driver should switch into slow clock mode + * and then into standby to avoid drawing more than + * 500uA power (2500uA for some high-power configs). + */ + if (udc->driver && udc->driver->suspend) + udc->driver->suspend(&udc->gadget); + + /* host initiated resume */ + } else if (status & AT91_UDP_RXRSM) { + at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM); + at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP); + at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM); + // VDBG("bus resume\n"); + if (!udc->suspended) + continue; + udc->suspended = 0; + + /* + * NOTE: for a VBUS-powered device, the gadget driver + * would normally want to switch out of slow clock + * mode into normal mode. + */ + if (udc->driver && udc->driver->resume) + udc->driver->resume(&udc->gadget); + + /* endpoint IRQs are cleared by handling them */ + } else { + int i; + unsigned mask = 1; + struct at91_ep *ep = &udc->ep[1]; + + if (status & mask) + handle_ep0(udc); + for (i = 1; i < NUM_ENDPOINTS; i++) { + mask <<= 1; + if (status & mask) + handle_ep(ep); + ep++; + } + } + } + + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +static struct at91_udc controller = { + .gadget = { + .ops = &at91_udc_ops, + .ep0 = &controller.ep[0].ep, + .name = driver_name, + .dev = { + .bus_id = "gadget" + } + }, + .ep[0] = { + .ep = { + .name = ep0name, + .ops = &at91_ep_ops, + }, + .udc = &controller, + .maxpacket = 8, + .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(0)), + .int_mask = 1 << 0, + }, + .ep[1] = { + .ep = { + .name = "ep1", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .is_pingpong = 1, + .maxpacket = 64, + .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(1)), + .int_mask = 1 << 1, + }, + .ep[2] = { + .ep = { + .name = "ep2", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .is_pingpong = 1, + .maxpacket = 64, + .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(2)), + .int_mask = 1 << 2, + }, + .ep[3] = { + .ep = { + /* could actually do bulk too */ + .name = "ep3-int", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .maxpacket = 8, + .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(3)), + .int_mask = 1 << 3, + }, + .ep[4] = { + .ep = { + .name = "ep4", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .is_pingpong = 1, + .maxpacket = 256, + .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(4)), + .int_mask = 1 << 4, + }, + .ep[5] = { + .ep = { + .name = "ep5", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .is_pingpong = 1, + .maxpacket = 256, + .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(5)), + .int_mask = 1 << 5, + }, + /* ep6 and ep7 are also reserved */ +}; + +static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r) +{ + struct at91_udc *udc = _udc; + unsigned value; + + /* vbus needs at least brief debouncing */ + udelay(10); + value = at91_get_gpio_value(udc->board.vbus_pin); + if (value != udc->vbus) + at91_vbus_session(&udc->gadget, value); + + return IRQ_HANDLED; +} + +int usb_gadget_register_driver (struct usb_gadget_driver *driver) +{ + struct at91_udc *udc = &controller; + int retval; + + if (!driver + || driver->speed != USB_SPEED_FULL + || !driver->bind + || !driver->unbind + || !driver->setup) { + DBG("bad parameter.\n"); + return -EINVAL; + } + + if (udc->driver) { + DBG("UDC already has a gadget driver\n"); + return -EBUSY; + } + + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + udc->gadget.dev.driver_data = &driver->driver; + udc->enabled = 1; + udc->selfpowered = 1; + + retval = driver->bind(&udc->gadget); + if (retval) { + DBG("driver->bind() returned %d\n", retval); + udc->driver = NULL; + return retval; + } + + local_irq_disable(); + pullup(udc, 1); + local_irq_enable(); + + DBG("bound to %s\n", driver->driver.name); + return 0; +} +EXPORT_SYMBOL (usb_gadget_register_driver); + +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +{ + struct at91_udc *udc = &controller; + + if (!driver || driver != udc->driver) + return -EINVAL; + + local_irq_disable(); + udc->enabled = 0; + pullup(udc, 0); + local_irq_enable(); + + driver->unbind(&udc->gadget); + udc->driver = NULL; + + DBG("unbound from %s\n", driver->driver.name); + return 0; +} +EXPORT_SYMBOL (usb_gadget_unregister_driver); + +/*-------------------------------------------------------------------------*/ + +static void at91udc_shutdown(struct platform_device *dev) +{ + /* force disconnect on reboot */ + pullup(platform_get_drvdata(dev), 0); +} + +static int __devinit at91udc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct at91_udc *udc; + int retval; + + if (!dev->platform_data) { + /* small (so we copy it) but critical! */ + DBG("missing platform_data\n"); + return -ENODEV; + } + + if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) { + DBG("someone's using UDC memory\n"); + return -EBUSY; + } + + /* init software state */ + udc = &controller; + udc->gadget.dev.parent = dev; + udc->board = *(struct at91_udc_data *) dev->platform_data; + udc->pdev = pdev; + udc_reinit(udc); + udc->enabled = 0; + + /* get interface and function clocks */ + udc->iclk = clk_get(dev, "udc_clk"); + udc->fclk = clk_get(dev, "udpck"); + if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { + DBG("clocks missing\n"); + return -ENODEV; + } + + retval = device_register(&udc->gadget.dev); + if (retval < 0) + goto fail0; + + /* disable everything until there's a gadget driver and vbus */ + pullup(udc, 0); + + /* request UDC and maybe VBUS irqs */ + if (request_irq(AT91_ID_UDP, at91_udc_irq, SA_INTERRUPT, driver_name, udc)) { + DBG("request irq %d failed\n", AT91_ID_UDP); + retval = -EBUSY; + goto fail1; + } + if (udc->board.vbus_pin > 0) { + if (request_irq(udc->board.vbus_pin, at91_vbus_irq, SA_INTERRUPT, driver_name, udc)) { + DBG("request vbus irq %d failed\n", udc->board.vbus_pin); + free_irq(AT91_ID_UDP, udc); + retval = -EBUSY; + goto fail1; + } + } else { + DBG("no VBUS detection, assuming always-on\n"); + udc->vbus = 1; + } + dev_set_drvdata(dev, udc); + create_debug_file(udc); + + INFO("%s version %s\n", driver_name, DRIVER_VERSION); + return 0; + +fail1: + device_unregister(&udc->gadget.dev); +fail0: + release_mem_region(AT91_VA_BASE_UDP, SZ_16K); + DBG("%s probe failed, %d\n", driver_name, retval); + return retval; +} + +static int __devexit at91udc_remove(struct platform_device *dev) +{ + struct at91_udc *udc = platform_get_drvdata(dev); + + DBG("remove\n"); + + pullup(udc, 0); + + if (udc->driver != 0) + usb_gadget_unregister_driver(udc->driver); + + remove_debug_file(udc); + if (udc->board.vbus_pin > 0) + free_irq(udc->board.vbus_pin, udc); + free_irq(AT91_ID_UDP, udc); + device_unregister(&udc->gadget.dev); + release_mem_region(AT91_BASE_UDP, SZ_16K); + + clk_put(udc->iclk); + clk_put(udc->fclk); + + return 0; +} + +#ifdef CONFIG_PM +static int at91udc_suspend(struct platform_device *dev, u32 state, u32 level) +{ + struct at91_udc *udc = platform_get_drvdata(dev); + + /* + * The "safe" suspend transitions are opportunistic ... e.g. when + * the USB link is suspended (48MHz clock autogated off), or when + * it's disconnected (programmatically gated off, elsewhere). + * Then we can suspend, and the chip can enter slow clock mode. + * + * The problem case is some component (user mode?) suspending this + * device while it's active, with the 48 MHz clock in use. There + * are two basic approaches: (a) veto suspend levels involving slow + * clock mode, (b) disconnect, so 48 MHz will no longer be in use + * and we can enter slow clock mode. This uses (b) for now, since + * it's simplest until AT91 PM exists and supports the other option. + */ + if (udc->vbus && !udc->suspended) + pullup(udc, 0); + return 0; +} + +static int at91udc_resume(struct platform_device *dev, u32 level) +{ + struct at91_udc *udc = platform_get_drvdata(dev); + + /* maybe reconnect to host; if so, clocks on */ + pullup(udc, 1); + return 0; +} +#else +#define at91udc_suspend NULL +#define at91udc_resume NULL +#endif + +static struct platform_driver at91_udc = { + .probe = at91udc_probe, + .remove = __devexit_p(at91udc_remove), + .shutdown = at91udc_shutdown, + .suspend = at91udc_suspend, + .resume = at91udc_resume, + .driver = { + .name = (char *) driver_name, + .owner = THIS_MODULE, + }, +}; + +static int __devinit udc_init_module(void) +{ + return platform_driver_register(&at91_udc); +} +module_init(udc_init_module); + +static void __devexit udc_exit_module(void) +{ + platform_driver_unregister(&at91_udc); +} +module_exit(udc_exit_module); + +MODULE_DESCRIPTION("AT91RM9200 udc driver"); +MODULE_AUTHOR("Thomas Rathbone, David Brownell"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h new file mode 100644 index 000000000000..5a4799cedd19 --- /dev/null +++ b/drivers/usb/gadget/at91_udc.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2004 by Thomas Rathbone, HP Labs + * Copyright (C) 2005 by Ivan Kokshaysky + * Copyright (C) 2006 by SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef AT91_UDC_H +#define AT91_UDC_H + +/* + * USB Device Port (UDP) registers. + * Based on AT91RM9200 datasheet revision E. + */ + +#define AT91_UDP_FRM_NUM 0x00 /* Frame Number Register */ +#define AT91_UDP_NUM (0x7ff << 0) /* Frame Number */ +#define AT91_UDP_FRM_ERR (1 << 16) /* Frame Error */ +#define AT91_UDP_FRM_OK (1 << 17) /* Frame OK */ + +#define AT91_UDP_GLB_STAT 0x04 /* Global State Register */ +#define AT91_UDP_FADDEN (1 << 0) /* Function Address Enable */ +#define AT91_UDP_CONFG (1 << 1) /* Configured */ +#define AT91_UDP_ESR (1 << 2) /* Enable Send Resume */ +#define AT91_UDP_RSMINPR (1 << 3) /* Resume has been sent */ +#define AT91_UDP_RMWUPE (1 << 4) /* Remote Wake Up Enable */ + +#define AT91_UDP_FADDR 0x08 /* Function Address Register */ +#define AT91_UDP_FADD (0x7f << 0) /* Function Address Value */ +#define AT91_UDP_FEN (1 << 8) /* Function Enable */ + +#define AT91_UDP_IER 0x10 /* Interrupt Enable Register */ +#define AT91_UDP_IDR 0x14 /* Interrupt Disable Register */ +#define AT91_UDP_IMR 0x18 /* Interrupt Mask Register */ + +#define AT91_UDP_ISR 0x1c /* Interrupt Status Register */ +#define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */ +#define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */ +#define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ +#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status */ +#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ +#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrpt Status */ +#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status */ + +#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ +#define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */ + +#define AT91_UDP_CSR(n) (0x30+((n)*4)) /* Endpoint Control/Status Registers 0-7 */ +#define AT91_UDP_TXCOMP (1 << 0) /* Generates IN packet with data previously written in DPR */ +#define AT91_UDP_RX_DATA_BK0 (1 << 1) /* Receive Data Bank 0 */ +#define AT91_UDP_RXSETUP (1 << 2) /* Send STALL to the host */ +#define AT91_UDP_STALLSENT (1 << 3) /* Stall Sent / Isochronous error (Isochronous endpoints) */ +#define AT91_UDP_TXPKTRDY (1 << 4) /* Transmit Packet Ready */ +#define AT91_UDP_FORCESTALL (1 << 5) /* Force Stall */ +#define AT91_UDP_RX_DATA_BK1 (1 << 6) /* Receive Data Bank 1 */ +#define AT91_UDP_DIR (1 << 7) /* Transfer Direction */ +#define AT91_UDP_EPTYPE (7 << 8) /* Endpoint Type */ +#define AT91_UDP_EPTYPE_CTRL (0 << 8) +#define AT91_UDP_EPTYPE_ISO_OUT (1 << 8) +#define AT91_UDP_EPTYPE_BULK_OUT (2 << 8) +#define AT91_UDP_EPTYPE_INT_OUT (3 << 8) +#define AT91_UDP_EPTYPE_ISO_IN (5 << 8) +#define AT91_UDP_EPTYPE_BULK_IN (6 << 8) +#define AT91_UDP_EPTYPE_INT_IN (7 << 8) +#define AT91_UDP_DTGLE (1 << 11) /* Data Toggle */ +#define AT91_UDP_EPEDS (1 << 15) /* Endpoint Enable/Disable */ +#define AT91_UDP_RXBYTECNT (0x7ff << 16) /* Number of bytes in FIFO */ + +#define AT91_UDP_FDR(n) (0x50+((n)*4)) /* Endpoint FIFO Data Registers 0-7 */ + +#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */ +#define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */ + + +/*-------------------------------------------------------------------------*/ + +/* + * controller driver data structures + */ + +#define NUM_ENDPOINTS 6 + +/* + * hardware won't disable bus reset, or resume while the controller + * is suspended ... watching suspend helps keep the logic symmetric. + */ +#define MINIMUS_INTERRUPTUS \ + (AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP) + +struct at91_ep { + struct usb_ep ep; + struct list_head queue; + struct at91_udc *udc; + void __iomem *creg; + + unsigned maxpacket:16; + u8 int_mask; + unsigned is_pingpong:1; + + unsigned stopped:1; + unsigned is_in:1; + unsigned is_iso:1; + unsigned fifo_bank:1; + + const struct usb_endpoint_descriptor + *desc; +}; + +/* + * driver is non-SMP, and just blocks IRQs whenever it needs + * access protection for chip registers or driver state + */ +struct at91_udc { + struct usb_gadget gadget; + struct at91_ep ep[NUM_ENDPOINTS]; + struct usb_gadget_driver *driver; + unsigned vbus:1; + unsigned enabled:1; + unsigned clocked:1; + unsigned suspended:1; + unsigned req_pending:1; + unsigned wait_for_addr_ack:1; + unsigned wait_for_config_ack:1; + unsigned selfpowered:1; + u8 addr; + struct at91_udc_data board; + struct clk *iclk, *fclk; + struct platform_device *pdev; + struct proc_dir_entry *pde; +}; + +static inline struct at91_udc *to_udc(struct usb_gadget *g) +{ + return container_of(g, struct at91_udc, gadget); +} + +struct at91_request { + struct usb_request req; + struct list_head queue; +}; + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +#define DBG(stuff...) printk(KERN_DEBUG "udc: " stuff) +#else +#define DBG(stuff...) do{}while(0) +#endif + +#ifdef VERBOSE +# define VDBG DBG +#else +# define VDBG(stuff...) do{}while(0) +#endif + +#ifdef PACKET_TRACE +# define PACKET VDBG +#else +# define PACKET(stuff...) do{}while(0) +#endif + +#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) +#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) +#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) + +#endif + -- cgit v1.2.2 From 7802ac5c29d135345db1b06f9167075cd9f2d675 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 22 Jan 2006 10:33:27 -0800 Subject: [PATCH] USB: minor gadget/rndis tweak Resove a minor FIXME: don't change MTU while RNDIS link is active, the other end won't expect such things... Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index afc84cfb61f9..04b9743c1c1f 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1549,7 +1549,8 @@ static int eth_change_mtu (struct net_device *net, int new_mtu) { struct eth_dev *dev = netdev_priv(net); - // FIXME if rndis, don't change while link's live + if (dev->rndis) + return -EBUSY; if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN) return -ERANGE; -- cgit v1.2.2 From 1c05ad4447e4ecbd61647c102fb6f2f5a6634ff3 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 25 Jan 2006 08:45:59 -0800 Subject: [PATCH] recognize three more usb peripheral controllers This adds declarations for three USB peripheral controllers: - Two high speed USB cores that can be licensed from Mentor Graphics to be integrated into silicon: * "musbhsfc" is for peripherals only, as found in for example the IBM/AMCC 44EP processors. * "musbhdrc" is OTG-capable (dual role), and is found in various products including OMAP 2430 and the new DaVinci SOCs. The "musbh" standing for "Mentor USB Highspeed", the rest standing for "Function Controller" or "Dual Role Controller" (OTG-capable). - The full speed controller on the FreeScale MPC8272. Adding these definitions just allows gadget driver code to handle any controller-specific logic; controller drivers are quite separate. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 8 ++++++++ drivers/usb/gadget/gadget_chips.h | 30 ++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 04b9743c1c1f..3d2603e31808 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -253,6 +253,14 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_MUSBHSFC +#define DEV_CONFIG_CDC +#endif + +#ifdef CONFIG_USB_GADGET_MUSBHDRC +#define DEV_CONFIG_CDC +#endif + /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 8cbae21d84b9..c4081407171f 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -3,9 +3,9 @@ * gadget drivers or other code that needs to deal with them, and which * autoconfigures instead of using early binding to the hardware. * - * This could eventually work like the ARM mach_is_*() stuff, driven by + * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by * some config file that gets updated as new hardware is supported. - * (And avoiding the runtime comparisons in typical one-choice cases.) + * (And avoiding all runtime comparisons in typical one-choice configs!) * * NOTE: some of these controller drivers may not be available yet. */ @@ -93,6 +93,26 @@ #define gadget_is_imx(g) 0 #endif +/* Mentor high speed function controller */ +#ifdef CONFIG_USB_GADGET_MUSBHSFC +#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name) +#else +#define gadget_is_musbhsfc(g) 0 +#endif + +/* Mentor high speed "dual role" controller, peripheral mode */ +#ifdef CONFIG_USB_GADGET_MUSBHDRC +#define gadget_is_musbhdrc(g) !strcmp("musbhdrc_udc", (g)->name) +#else +#define gadget_is_musbhdrc(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_MPC8272 +#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name) +#else +#define gadget_is_mpc8272(g) 0 +#endif + // CONFIG_USB_GADGET_SX2 // CONFIG_USB_GADGET_AU1X00 // ... @@ -143,5 +163,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x13; else if (gadget_is_imx(gadget)) return 0x14; + else if (gadget_is_musbhsfc(gadget)) + return 0x15; + else if (gadget_is_musbhdrc(gadget)) + return 0x16; + else if (gadget_is_mpc8272(gadget)) + return 0x17; return -ENOENT; } -- cgit v1.2.2 From b1e8f0a6a8805c971857cd10a65cf8caa4c1a672 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 23 Jan 2006 15:25:40 -0800 Subject: [PATCH] USB: usbcore sets up root hubs earlier Make the HCD initialization sequence more sane ... notably, setting up root hubs before HCDs are asked to do their one-time init. Among other things, that lets the HCDs do custom root hub init along with all the other one-time initialization done in the (now misnamed) reset() method. This also copies the controller wakeup flags into the root hub; it's done a bit later than would be ideal, but that'll be necessary until the PCI code initializes them correctly. (The PCI patch breaks on PPC due to how it sequences PCI initialization.) Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 104 ++++++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 49 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 9223f2869674..6368562d73ca 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -823,18 +823,17 @@ static void usb_deregister_bus (struct usb_bus *bus) /** * register_root_hub - called by usb_add_hcd() to register a root hub - * @usb_dev: the usb root hub device to be registered. * @hcd: host controller for this root hub * * This function registers the root hub with the USB subsystem. It sets up - * the device properly in the device tree and stores the root_hub pointer - * in the bus structure, then calls usb_new_device() to register the usb - * device. It also assigns the root hub's USB address (always 1). + * the device properly in the device tree and then calls usb_new_device() + * to register the usb device. It also assigns the root hub's USB address + * (always 1). */ -static int register_root_hub (struct usb_device *usb_dev, - struct usb_hcd *hcd) +static int register_root_hub(struct usb_hcd *hcd) { struct device *parent_dev = hcd->self.controller; + struct usb_device *usb_dev = hcd->self.root_hub; const int devnum = 1; int retval; @@ -846,12 +845,10 @@ static int register_root_hub (struct usb_device *usb_dev, usb_set_device_state(usb_dev, USB_STATE_ADDRESS); mutex_lock(&usb_bus_list_lock); - usb_dev->bus->root_hub = usb_dev; usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); if (retval != sizeof usb_dev->descriptor) { - usb_dev->bus->root_hub = NULL; mutex_unlock(&usb_bus_list_lock); dev_dbg (parent_dev, "can't read %s device descriptor %d\n", usb_dev->dev.bus_id, retval); @@ -860,7 +857,6 @@ static int register_root_hub (struct usb_device *usb_dev, retval = usb_new_device (usb_dev); if (retval) { - usb_dev->bus->root_hub = NULL; dev_err (parent_dev, "can't register root hub for %s, %d\n", usb_dev->dev.bus_id, retval); } @@ -1772,12 +1768,10 @@ int usb_add_hcd(struct usb_hcd *hcd, set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /* till now HC has been in an indeterminate state ... */ - if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { - dev_err(hcd->self.controller, "can't reset\n"); - return retval; - } - + /* HC is in reset state, but accessible. Now do the one-time init, + * bottom up so that hcds can customize the root hubs before khubd + * starts talking to them. (Note, bus id is assigned early too.) + */ if ((retval = hcd_buffer_create(hcd)) != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); return retval; @@ -1786,6 +1780,42 @@ int usb_add_hcd(struct usb_hcd *hcd, if ((retval = usb_register_bus(&hcd->self)) < 0) goto err_register_bus; + if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { + dev_err(hcd->self.controller, "unable to allocate root hub\n"); + retval = -ENOMEM; + goto err_allocate_root_hub; + } + rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : + USB_SPEED_FULL; + hcd->self.root_hub = rhdev; + + /* "reset" is misnamed; its role is now one-time init. the controller + * should already have been reset (and boot firmware kicked off etc). + */ + if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { + dev_err(hcd->self.controller, "can't setup\n"); + goto err_hcd_driver_setup; + } + + /* wakeup flag init is in transition; for now we can't rely on PCI to + * initialize these bits properly, so we let reset() override it. + * This init should _precede_ the reset() once PCI behaves. + */ + device_init_wakeup(&rhdev->dev, + device_can_wakeup(hcd->self.controller)); + + // ... all these hcd->*_wakeup flags will vanish + hcd->can_wakeup = device_can_wakeup(hcd->self.controller); + + /* hcd->driver->reset() reported can_wakeup, probably with + * assistance from board's boot firmware. + * NOTE: normal devices won't enable wakeup by default. + */ + if (hcd->can_wakeup) + dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); + hcd->remote_wakeup = hcd->can_wakeup; + + /* enable irqs just before we start the controller */ if (hcd->driver->irq) { char buf[8], *bufp = buf; @@ -1817,56 +1847,32 @@ int usb_add_hcd(struct usb_hcd *hcd, (unsigned long long)hcd->rsrc_start); } - /* Allocate the root hub before calling hcd->driver->start(), - * but don't register it until afterward so that the hardware - * is running. - */ - if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { - dev_err(hcd->self.controller, "unable to allocate root hub\n"); - retval = -ENOMEM; - goto err_allocate_root_hub; - } - - /* Although in principle hcd->driver->start() might need to use rhdev, - * none of the current drivers do. - */ if ((retval = hcd->driver->start(hcd)) < 0) { dev_err(hcd->self.controller, "startup error %d\n", retval); goto err_hcd_driver_start; } - /* hcd->driver->start() reported can_wakeup, probably with - * assistance from board's boot firmware. - * NOTE: normal devices won't enable wakeup by default. - */ - if (hcd->can_wakeup) - dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); - hcd->remote_wakeup = hcd->can_wakeup; - - rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH : - USB_SPEED_FULL; + /* starting here, usbcore will pay attention to this root hub */ rhdev->bus_mA = min(500u, hcd->power_budget); - if ((retval = register_root_hub(rhdev, hcd)) != 0) + if ((retval = register_root_hub(hcd)) != 0) goto err_register_root_hub; if (hcd->uses_new_polling && hcd->poll_rh) usb_hcd_poll_rh_status(hcd); return retval; - err_register_root_hub: +err_register_root_hub: hcd->driver->stop(hcd); - - err_hcd_driver_start: - usb_put_dev(rhdev); - - err_allocate_root_hub: +err_hcd_driver_start: if (hcd->irq >= 0) free_irq(irqnum, hcd); - - err_request_irq: +err_request_irq: +err_hcd_driver_setup: + hcd->self.root_hub = NULL; + usb_put_dev(rhdev); +err_allocate_root_hub: usb_deregister_bus(&hcd->self); - - err_register_bus: +err_register_bus: hcd_buffer_destroy(hcd); return retval; } -- cgit v1.2.2 From 6a9062f393fa48125df23c5491543828a21e1ae0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 23 Jan 2006 15:28:07 -0800 Subject: [PATCH] USB: ohci uses driver model wakeup flags This makes OHCI use the driver model wakeup control bits for its root hub (e.g. disable on amd756, because of chip erratum) and for the controller itself. It no longer uses the hcd glue bits with those roles, and depends on the previous patch making the root hub available earlier. Note that on most platforms (boot code properly setting the RWC bit) this gives a partial workaround for the way PCI isn't currently flagging devices that support PME# signals. (Because of odd PCI init sequencing on PPC.) That's because many OHCI controllers support "legacy PCI PM" ... without involving any PCI PM capability. USB wakeup from STR, if it works on your system, may still involve tweaking things by hand in /proc/acpi/wakeup. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 49 +++++++++++++++++++++++++-------------------- drivers/usb/host/ohci-hub.c | 12 +++++------ drivers/usb/host/ohci-pci.c | 15 ++++++++++++-- 3 files changed, 46 insertions(+), 30 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 2990be269000..544f7589912f 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -443,11 +443,16 @@ ohci_reboot (struct notifier_block *block, unsigned long code, void *null) static int ohci_init (struct ohci_hcd *ohci) { int ret; + struct usb_hcd *hcd = ohci_to_hcd(ohci); disable (ohci); - ohci->regs = ohci_to_hcd(ohci)->regs; + ohci->regs = hcd->regs; ohci->next_statechange = jiffies; + /* REVISIT this BIOS handshake is now moved into PCI "quirks", and + * was never needed for most non-PCI systems ... remove the code? + */ + #ifndef IR_DISABLE /* SMM owns the HC? not for long! */ if (!no_handshake && ohci_readl (ohci, @@ -478,8 +483,10 @@ static int ohci_init (struct ohci_hcd *ohci) /* Disable HC interrupts */ ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - // flush the writes - (void) ohci_readl (ohci, &ohci->regs->control); + + /* flush the writes, and save key bits like RWC */ + if (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_RWC) + ohci->hc_control |= OHCI_CTRL_RWC; /* Read the number of ports unless overridden */ if (ohci->num_ports == 0) @@ -488,16 +495,19 @@ static int ohci_init (struct ohci_hcd *ohci) if (ohci->hcca) return 0; - ohci->hcca = dma_alloc_coherent (ohci_to_hcd(ohci)->self.controller, + ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof *ohci->hcca, &ohci->hcca_dma, 0); if (!ohci->hcca) return -ENOMEM; if ((ret = ohci_mem_init (ohci)) < 0) - ohci_stop (ohci_to_hcd(ohci)); + ohci_stop (hcd); + else { + register_reboot_notifier (&ohci->reboot_notifier); + create_debug_files (ohci); + } return ret; - } /*-------------------------------------------------------------------------*/ @@ -510,6 +520,7 @@ static int ohci_run (struct ohci_hcd *ohci) { u32 mask, temp; int first = ohci->fminterval == 0; + struct usb_hcd *hcd = ohci_to_hcd(ohci); disable (ohci); @@ -525,18 +536,17 @@ static int ohci_run (struct ohci_hcd *ohci) /* also: power/overcurrent flags in roothub.a */ } - /* Reset USB nearly "by the book". RemoteWakeupConnected - * saved if boot firmware (BIOS/SMM/...) told us it's connected - * (for OHCI integrated on mainboard, it normally is) + /* Reset USB nearly "by the book". RemoteWakeupConnected was + * saved if boot firmware (BIOS/SMM/...) told us it's connected, + * or if bus glue did the same (e.g. for PCI add-in cards with + * PCI PM support). */ - ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n", hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), - ohci->hc_control); - - if (ohci->hc_control & OHCI_CTRL_RWC - && !(ohci->flags & OHCI_QUIRK_AMD756)) - ohci_to_hcd(ohci)->can_wakeup = 1; + ohci_readl (ohci, &ohci->regs->control)); + if ((ohci->hc_control & OHCI_CTRL_RWC) != 0 + && !device_may_wakeup(hcd->self.controller)) + device_init_wakeup(hcd->self.controller, 1); switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_OPER: @@ -632,7 +642,7 @@ retry: ohci->hc_control &= OHCI_CTRL_RWC; ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - ohci_to_hcd(ohci)->state = HC_STATE_RUNNING; + hcd->state = HC_STATE_RUNNING; /* wake on ConnectStatusChange, matching external hubs */ ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status); @@ -667,15 +677,10 @@ retry: // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((temp >> 23) & 0x1fe); - ohci_to_hcd(ohci)->state = HC_STATE_RUNNING; + hcd->state = HC_STATE_RUNNING; ohci_dump (ohci, 1); - if (ohci_to_hcd(ohci)->self.root_hub == NULL) { - register_reboot_notifier (&ohci->reboot_notifier); - create_debug_files (ohci); - } - return 0; } diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 4b2226d77b34..0bb972b58336 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -107,7 +107,7 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) &ohci->regs->intrstatus); /* maybe resume can wake root hub */ - if (hcd->remote_wakeup) + if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev)) ohci->hc_control |= OHCI_CTRL_RWE; else ohci->hc_control &= ~OHCI_CTRL_RWE; @@ -246,9 +246,9 @@ static int ohci_bus_resume (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); msleep (3); - temp = OHCI_CONTROL_INIT | OHCI_USB_OPER; - if (hcd->can_wakeup) - temp |= OHCI_CTRL_RWC; + temp = ohci->hc_control; + temp &= OHCI_CTRL_RWC; + temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci->hc_control = temp; ohci_writel (ohci, temp, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); @@ -302,7 +302,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; - int can_suspend = hcd->can_wakeup; + int can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); @@ -354,7 +354,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) */ if (!(status & RH_PS_CCS)) continue; - if ((status & RH_PS_PSS) && hcd->remote_wakeup) + if ((status & RH_PS_PSS) && can_suspend) continue; can_suspend = 0; } diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 1b09dde068e1..1bfe96f4d045 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -35,7 +35,10 @@ ohci_pci_start (struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) { + /* REVISIT this whole block should move to reset(), which handles + * all the other one-time init. + */ + if (hcd->self.controller) { struct pci_dev *pdev = to_pci_dev(hcd->self.controller); /* AMD 756, for most chips (early revs), corrupts register @@ -45,7 +48,8 @@ ohci_pci_start (struct usb_hcd *hcd) && pdev->device == 0x740c) { ohci->flags = OHCI_QUIRK_AMD756; ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); - // also somewhat erratum 10 (suspend/resume issues) + /* also erratum 10 (suspend/resume issues) */ + device_init_wakeup(&hcd->self.root_hub->dev, 0); } /* FIXME for some of the early AMD 760 southbridges, OHCI @@ -88,6 +92,13 @@ ohci_pci_start (struct usb_hcd *hcd) ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); } + + /* RWC may not be set for add-in PCI cards, since boot + * firmware probably ignored them. This transfers PCI + * PM wakeup capabilities (once the PCI layer is fixed). + */ + if (device_may_wakeup(&pdev->dev)) + ohci->hc_control |= OHCI_CTRL_RWC; } /* NOTE: there may have already been a first reset, to -- cgit v1.2.2 From fb669cc01ed778c4926f395e44a9b61644597d38 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 24 Jan 2006 08:40:27 -0800 Subject: [PATCH] USB: remove usbcore-specific wakeup flags This makes usbcore use the driver model wakeup flags for host controllers and for their root hubs. Since previous patches have removed all users of the HCD flags they replace, this converts the last users of those flags. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd-pci.c | 11 ++++++++--- drivers/usb/core/hcd.c | 40 ++++++++++++++++++++++++++-------------- drivers/usb/core/hcd.h | 2 -- drivers/usb/core/hub.c | 22 ++++++++++++++-------- 4 files changed, 48 insertions(+), 27 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 29b5b2a6e183..e0afb5ad29e5 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -264,14 +264,19 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) */ retval = pci_set_power_state (dev, PCI_D3hot); if (retval == 0) { - dev_dbg (hcd->self.controller, "--> PCI D3\n"); + int wake = device_can_wakeup(&hcd->self.root_hub->dev); + + wake = wake && device_may_wakeup(hcd->self.controller); + + dev_dbg (hcd->self.controller, "--> PCI D3%s\n", + wake ? "/wakeup" : ""); /* Ignore these return values. We rely on pci code to * reject requests the hardware can't implement, rather * than coding the same thing. */ - (void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup); - (void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup); + (void) pci_enable_wake (dev, PCI_D3hot, wake); + (void) pci_enable_wake (dev, PCI_D3cold, wake); } else { dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n", retval); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6368562d73ca..a98d978d76e2 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -367,21 +367,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) /* DEVICE REQUESTS */ + /* The root hub's remote wakeup enable bit is implemented using + * driver model wakeup flags. If this system supports wakeup + * through USB, userspace may change the default "allow wakeup" + * policy through sysfs or these calls. + * + * Most root hubs support wakeup from downstream devices, for + * runtime power management (disabling USB clocks and reducing + * VBUS power usage). However, not all of them do so; silicon, + * board, and BIOS bugs here are not uncommon, so these can't + * be treated quite like external hubs. + * + * Likewise, not all root hubs will pass wakeup events upstream, + * to wake up the whole system. So don't assume root hub and + * controller capabilities are identical. + */ + case DeviceRequest | USB_REQ_GET_STATUS: - tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) + tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev) + << USB_DEVICE_REMOTE_WAKEUP) | (1 << USB_DEVICE_SELF_POWERED); tbuf [1] = 0; len = 2; break; case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (wValue == USB_DEVICE_REMOTE_WAKEUP) - hcd->remote_wakeup = 0; + device_set_wakeup_enable(&hcd->self.root_hub->dev, 0); else goto error; break; case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP) - hcd->remote_wakeup = 1; + if (device_can_wakeup(&hcd->self.root_hub->dev) + && wValue == USB_DEVICE_REMOTE_WAKEUP) + device_set_wakeup_enable(&hcd->self.root_hub->dev, 1); else goto error; break; @@ -410,7 +428,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) bufp = fs_rh_config_descriptor; len = sizeof fs_rh_config_descriptor; } - if (hcd->can_wakeup) + if (device_can_wakeup(&hcd->self.root_hub->dev)) patch_wakeup = 1; break; case USB_DT_STRING << 8: @@ -1804,16 +1822,10 @@ int usb_add_hcd(struct usb_hcd *hcd, device_init_wakeup(&rhdev->dev, device_can_wakeup(hcd->self.controller)); - // ... all these hcd->*_wakeup flags will vanish - hcd->can_wakeup = device_can_wakeup(hcd->self.controller); - - /* hcd->driver->reset() reported can_wakeup, probably with - * assistance from board's boot firmware. - * NOTE: normal devices won't enable wakeup by default. - */ - if (hcd->can_wakeup) + /* NOTE: root hub and controller capabilities may not be the same */ + if (device_can_wakeup(hcd->self.controller) + && device_can_wakeup(&hcd->self.root_hub->dev)) dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); - hcd->remote_wakeup = hcd->can_wakeup; /* enable irqs just before we start the controller */ if (hcd->driver->irq) { diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index f44a2fe62a9d..7022aafb2ae8 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -78,8 +78,6 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ #define HCD_FLAG_HW_ACCESSIBLE 0x00000001 #define HCD_FLAG_SAW_IRQ 0x00000002 - unsigned can_wakeup:1; /* hw supports wakeup? */ - unsigned remote_wakeup:1;/* sw should use wakeup? */ unsigned rh_registered:1;/* is root hub registered? */ /* The next flag is a stopgap, to be removed when all the HCDs diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 867fa8130238..f1d64d4bbf5f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1006,12 +1006,18 @@ void usb_set_device_state(struct usb_device *udev, ; /* do nothing */ else if (new_state != USB_STATE_NOTATTACHED) { udev->state = new_state; - if (new_state == USB_STATE_CONFIGURED) - device_init_wakeup(&udev->dev, - (udev->actconfig->desc.bmAttributes - & USB_CONFIG_ATT_WAKEUP)); - else if (new_state != USB_STATE_SUSPENDED) - device_init_wakeup(&udev->dev, 0); + + /* root hub wakeup capabilities are managed out-of-band + * and may involve silicon errata ... ignore them here. + */ + if (udev->parent) { + if (new_state == USB_STATE_CONFIGURED) + device_init_wakeup(&udev->dev, + (udev->actconfig->desc.bmAttributes + & USB_CONFIG_ATT_WAKEUP)); + else if (new_state != USB_STATE_SUSPENDED) + device_init_wakeup(&udev->dev, 0); + } } else recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); @@ -1877,9 +1883,9 @@ int usb_resume_device(struct usb_device *udev) if (udev->state == USB_STATE_NOTATTACHED) return -ENODEV; -#ifdef CONFIG_USB_SUSPEND /* selective resume of one downstream hub-to-device port */ if (udev->parent) { +#ifdef CONFIG_USB_SUSPEND if (udev->state == USB_STATE_SUSPENDED) { // NOTE swsusp may bork us, device state being wrong... // NOTE this fails if parent is also suspended... @@ -1887,8 +1893,8 @@ int usb_resume_device(struct usb_device *udev) udev->portnum, udev); } else status = 0; - } else #endif + } else status = finish_device_resume(udev); if (status < 0) dev_dbg(&udev->dev, "can't resume, status %d\n", -- cgit v1.2.2 From aef4e266964bc15861b5835c1f5b9d2ebc155c2a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 31 Jan 2006 12:58:38 -0500 Subject: [PATCH] usbhid: add error handling This patch (as628c) adds error handling to the USB HID core. When an error is reported for an interrupt URB, the driver will do delayed retries, at increasing intervals, for up to one second. If that doesn't work, it will try to reset the device. Testing by users has shown that both the retries and the resets end up getting used. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 153 +++++++++++++++++++++++++++++++++++++------ drivers/usb/input/hid.h | 10 +++ 2 files changed, 142 insertions(+), 21 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index f187a719f17e..6b8a51cad375 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -902,6 +902,99 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_ return 0; } +/* + * Input submission and I/O error handler. + */ + +static void hid_io_error(struct hid_device *hid); + +/* Start up the input URB */ +static int hid_start_in(struct hid_device *hid) +{ + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&hid->inlock, flags); + if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) && + !test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) { + rc = usb_submit_urb(hid->urbin, GFP_ATOMIC); + if (rc != 0) + clear_bit(HID_IN_RUNNING, &hid->iofl); + } + spin_unlock_irqrestore(&hid->inlock, flags); + return rc; +} + +/* I/O retry timer routine */ +static void hid_retry_timeout(unsigned long _hid) +{ + struct hid_device *hid = (struct hid_device *) _hid; + + dev_dbg(&hid->intf->dev, "retrying intr urb\n"); + if (hid_start_in(hid)) + hid_io_error(hid); +} + +/* Workqueue routine to reset the device */ +static void hid_reset(void *_hid) +{ + struct hid_device *hid = (struct hid_device *) _hid; + int rc_lock, rc; + + dev_dbg(&hid->intf->dev, "resetting device\n"); + rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); + if (rc_lock >= 0) { + rc = usb_reset_device(hid->dev); + if (rc_lock) + usb_unlock_device(hid->dev); + } + clear_bit(HID_RESET_PENDING, &hid->iofl); + + if (rc == 0) { + hid->retry_delay = 0; + if (hid_start_in(hid)) + hid_io_error(hid); + } else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR)) + err("can't reset device, %s-%s/input%d, status %d", + hid->dev->bus->bus_name, + hid->dev->devpath, + hid->ifnum, rc); +} + +/* Main I/O error handler */ +static void hid_io_error(struct hid_device *hid) +{ + unsigned long flags; + + spin_lock_irqsave(&hid->inlock, flags); + + /* Stop when disconnected */ + if (usb_get_intfdata(hid->intf) == NULL) + goto done; + + /* When an error occurs, retry at increasing intervals */ + if (hid->retry_delay == 0) { + hid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ + hid->stop_retry = jiffies + msecs_to_jiffies(1000); + } else if (hid->retry_delay < 100) + hid->retry_delay *= 2; + + if (time_after(jiffies, hid->stop_retry)) { + + /* Retries failed, so do a port reset */ + if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) { + if (schedule_work(&hid->reset_work)) + goto done; + clear_bit(HID_RESET_PENDING, &hid->iofl); + } + } + + mod_timer(&hid->io_retry, + jiffies + msecs_to_jiffies(hid->retry_delay)); +done: + spin_unlock_irqrestore(&hid->inlock, flags); +} + /* * Input interrupt completion handler. */ @@ -913,25 +1006,35 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs) switch (urb->status) { case 0: /* success */ + hid->retry_delay = 0; hid_input_report(HID_INPUT_REPORT, urb, 1, regs); break; case -ECONNRESET: /* unlink */ case -ENOENT: - case -EPERM: case -ESHUTDOWN: /* unplug */ - case -EILSEQ: /* unplug timeout on uhci */ + clear_bit(HID_IN_RUNNING, &hid->iofl); return; + case -EILSEQ: /* protocol error or unplug */ + case -EPROTO: /* protocol error or unplug */ case -ETIMEDOUT: /* NAK */ - break; + clear_bit(HID_IN_RUNNING, &hid->iofl); + hid_io_error(hid); + return; default: /* error */ warn("input irq status %d received", urb->status); } status = usb_submit_urb(urb, SLAB_ATOMIC); - if (status) - err("can't resubmit intr, %s-%s/input%d, status %d", - hid->dev->bus->bus_name, hid->dev->devpath, - hid->ifnum, status); + if (status) { + clear_bit(HID_IN_RUNNING, &hid->iofl); + if (status != -EPERM) { + err("can't resubmit intr, %s-%s/input%d, status %d", + hid->dev->bus->bus_name, + hid->dev->devpath, + hid->ifnum, status); + hid_io_error(hid); + } + } } /* @@ -1093,8 +1196,9 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) case 0: /* success */ break; case -ESHUTDOWN: /* unplug */ - case -EILSEQ: /* unplug timeout on uhci */ unplug = 1; + case -EILSEQ: /* protocol error or unplug */ + case -EPROTO: /* protocol error or unplug */ case -ECONNRESET: /* unlink */ case -ENOENT: break; @@ -1141,8 +1245,9 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs); break; case -ESHUTDOWN: /* unplug */ - case -EILSEQ: /* unplug timectrl on uhci */ unplug = 1; + case -EILSEQ: /* protocol error or unplug */ + case -EPROTO: /* protocol error or unplug */ case -ECONNRESET: /* unlink */ case -ENOENT: case -EPIPE: /* report not available */ @@ -1255,14 +1360,9 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, int hid_open(struct hid_device *hid) { - if (hid->open++) - return 0; - - hid->urbin->dev = hid->dev; - - if (usb_submit_urb(hid->urbin, GFP_KERNEL)) - return -EIO; - + ++hid->open; + if (hid_start_in(hid)) + hid_io_error(hid); return 0; } @@ -1787,6 +1887,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) init_waitqueue_head(&hid->wait); + INIT_WORK(&hid->reset_work, hid_reset, hid); + setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid); + + spin_lock_init(&hid->inlock); spin_lock_init(&hid->outlock); spin_lock_init(&hid->ctrllock); @@ -1855,11 +1959,16 @@ static void hid_disconnect(struct usb_interface *intf) if (!hid) return; + spin_lock_irq(&hid->inlock); /* Sync with error handler */ usb_set_intfdata(intf, NULL); + spin_unlock_irq(&hid->inlock); usb_kill_urb(hid->urbin); usb_kill_urb(hid->urbout); usb_kill_urb(hid->urbctrl); + del_timer_sync(&hid->io_retry); + flush_scheduled_work(); + if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); if (hid->claimed & HID_CLAIMED_HIDDEV) @@ -1934,6 +2043,10 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) { struct hid_device *hid = usb_get_intfdata (intf); + spin_lock_irq(&hid->inlock); /* Sync with error handler */ + set_bit(HID_SUSPENDED, &hid->iofl); + spin_unlock_irq(&hid->inlock); + del_timer(&hid->io_retry); usb_kill_urb(hid->urbin); dev_dbg(&intf->dev, "suspend\n"); return 0; @@ -1944,10 +2057,8 @@ static int hid_resume(struct usb_interface *intf) struct hid_device *hid = usb_get_intfdata (intf); int status; - if (hid->open) - status = usb_submit_urb(hid->urbin, GFP_NOIO); - else - status = 0; + clear_bit(HID_SUSPENDED, &hid->iofl); + status = hid_start_in(hid); dev_dbg(&intf->dev, "resume status %d\n", status); return status; } diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 8b0d4346ce9c..4e1b784fe527 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -31,6 +31,8 @@ #include #include #include +#include +#include /* * USB HID (Human Interface Device) interface class code @@ -370,6 +372,9 @@ struct hid_control_fifo { #define HID_CTRL_RUNNING 1 #define HID_OUT_RUNNING 2 +#define HID_IN_RUNNING 3 +#define HID_RESET_PENDING 4 +#define HID_SUSPENDED 5 struct hid_input { struct list_head list; @@ -393,12 +398,17 @@ struct hid_device { /* device report descriptor */ int ifnum; /* USB interface number */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ + struct timer_list io_retry; /* Retry timer */ + unsigned long stop_retry; /* Time to give up, in jiffies */ + unsigned int retry_delay; /* Delay length in ms */ + struct work_struct reset_work; /* Task context for resets */ unsigned int bufsize; /* URB buffer size */ struct urb *urbin; /* Input URB */ char *inbuf; /* Input buffer */ dma_addr_t inbuf_dma; /* Input buffer dma */ + spinlock_t inlock; /* Input fifo spinlock */ struct urb *urbctrl; /* Control URB */ struct usb_ctrlrequest *cr; /* Control request struct */ -- cgit v1.2.2 From efafe6fb72b2bbab40080a08f7946f1eadb9bad9 Mon Sep 17 00:00:00 2001 From: Malte Doersam Date: Sat, 28 Jan 2006 17:48:33 +0100 Subject: [PATCH] USB: Pegasus: Linksys USBVPN1 support + cleanup This patch adds a second linksys vendor-id (077b) and the product id of the pegasus based adapter USBVPN1 http://www1.linksys.com/Products/product.asp?prid=3D543&scid=3D30 Furthermore it replaces all LINKSYS_GPIO_RESET with DEFAULT_GPIO_RESET as both are declared like this: #define DEFAULT_GPIO_RESET 0x24 #define LINKSYS_GPIO_RESET 0x24 This is misleading and confusing. The check is now done via the VENDOR_ID in pegasus.c: if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS Signed-off-by: Malte Doersam Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/pegasus.c | 1 + drivers/usb/net/pegasus.h | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 156a2f1cb39a..5b6675684567 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -524,6 +524,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) ret = set_registers(pegasus, EthCtrl0, 3, data); if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || + usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 || usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { u16 auxmode; read_mii_word(pegasus, 0, 0x1b, &auxmode); diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 9fbd59b55cb6..a54752ce1493 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -25,7 +25,6 @@ #define PHY_READ 0x40 #define PHY_WRITE 0x20 #define DEFAULT_GPIO_RESET 0x24 -#define LINKSYS_GPIO_RESET 0x24 #define DEFAULT_GPIO_SET 0x26 #define PEGASUS_PRESENT 0x00000001 @@ -140,6 +139,7 @@ struct usb_eth_dev { #define VENDOR_KINGSTON 0x0951 #define VENDOR_LANEED 0x056e #define VENDOR_LINKSYS 0x066b +#define VENDOR_LINKSYS2 0x077b #define VENDOR_MELCO 0x0411 #define VENDOR_MICROSOFT 0x045e #define VENDOR_MOBILITY 0x1342 @@ -218,15 +218,15 @@ PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004, PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001, - LINKSYS_GPIO_RESET ) + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002, - LINKSYS_GPIO_RESET ) + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102, - LINKSYS_GPIO_RESET | PEGASUS_II ) + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b, - LINKSYS_GPIO_RESET | PEGASUS_II ) + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c, - LINKSYS_GPIO_RESET | PEGASUS_II ) + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003, DEFAULT_GPIO_RESET | HAS_HOME_PNA ) PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1, @@ -260,17 +260,19 @@ PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1, PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202, - LINKSYS_GPIO_RESET ) + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203, - LINKSYS_GPIO_RESET ) + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204, - LINKSYS_GPIO_RESET | HAS_HOME_PNA ) + DEFAULT_GPIO_RESET | HAS_HOME_PNA ) PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206, - LINKSYS_GPIO_RESET | PEGASUS_II) + DEFAULT_GPIO_RESET | PEGASUS_II) +PEGASUS_DEV( "Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4, + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b, - LINKSYS_GPIO_RESET | PEGASUS_II ) + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c, - LINKSYS_GPIO_RESET | PEGASUS_II ) + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005, -- cgit v1.2.2 From 0eb8c7cafe8d4fa9a90ea8680200e3ae3d57b1bd Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Tue, 7 Feb 2006 09:06:17 +0100 Subject: [PATCH] USB: Zero driver: Removed duplicated code Signed-off-by: Franck Bui-Huu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/zero.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index ae7a1c0f5748..5e9fe8a70543 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1224,12 +1224,6 @@ autoconf_fail: loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - if (gadget->is_otg) { - otg_descriptor.bmAttributes |= USB_OTG_HNP, - source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - usb_gadget_set_selfpowered (gadget); init_timer (&dev->resume); -- cgit v1.2.2 From 499003e815344304c7b0c93aad923ddf644d24e0 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 24 Jan 2006 08:11:27 -0800 Subject: [PATCH] USB: Fix masking bug initialization of Freescale EHCI controller In setting up the of PHY we masked off too many bits, instead just initialize PORTSC for the type of PHY we are using. Signed-off-by: Kumar Gala Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 59f90f76ee31..f985f121a245 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -160,8 +160,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc = readl(&ehci->regs->port_status[port_offset]); - portsc &= ~PORT_PTS_MSK; + u32 portsc = 0; switch (phy_mode) { case FSL_USB2_PHY_ULPI: portsc |= PORT_PTS_ULPI; -- cgit v1.2.2 From dccf4a48d47120a42382ba526f1a0848c13ba2a4 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 17 Dec 2005 17:58:46 -0500 Subject: [PATCH] UHCI: use one QH per endpoint, not per URB This patch (as623) changes the uhci-hcd driver to make it use one QH per device endpoint, instead of a QH per URB as it does now. Numerous areas of the code are affected by this. For example, the distinction between "queued" URBs and non-"queued" URBs no longer exists; all URBs belong to a queue and some just happen to be at the queue's head. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 320 ++++---------- drivers/usb/host/uhci-hcd.c | 65 ++- drivers/usb/host/uhci-hcd.h | 177 ++++---- drivers/usb/host/uhci-q.c | 985 +++++++++++++++++++----------------------- 4 files changed, 685 insertions(+), 862 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 5832953086f8..3faccbd68547 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -90,13 +90,60 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) return out - buf; } -static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) +static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) { char *out = buf; - struct urb_priv *urbp; - struct list_head *head, *tmp; struct uhci_td *td; - int i = 0, checked = 0, prevactive = 0; + int i, nactive, ninactive; + + if (len < 200) + return 0; + + out += sprintf(out, "urb_priv [%p] ", urbp); + out += sprintf(out, "urb [%p] ", urbp->urb); + out += sprintf(out, "qh [%p] ", urbp->qh); + out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe)); + out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), + (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); + + switch (usb_pipetype(urbp->urb->pipe)) { + case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break; + case PIPE_INTERRUPT: out += sprintf(out, "INT"); break; + case PIPE_BULK: out += sprintf(out, "BLK"); break; + case PIPE_CONTROL: out += sprintf(out, "CTL"); break; + } + + out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : "")); + out += sprintf(out, "%s", (urbp->fsbr_timeout ? " FSBR_TO" : "")); + + if (urbp->urb->status != -EINPROGRESS) + out += sprintf(out, " Status=%d", urbp->urb->status); + out += sprintf(out, "\n"); + + i = nactive = ninactive = 0; + list_for_each_entry(td, &urbp->td_list, list) { + if (++i <= 10 || debug > 2) { + out += sprintf(out, "%*s%d: ", space + 2, "", i); + out += uhci_show_td(td, out, len - (out - buf), 0); + } else { + if (td_status(td) & TD_CTRL_ACTIVE) + ++nactive; + else + ++ninactive; + } + } + if (nactive + ninactive > 0) + out += sprintf(out, "%*s[skipped %d inactive and %d active " + "TDs]\n", + space, "", ninactive, nactive); + + return out - buf; +} + +static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) +{ + char *out = buf; + int i, nurbs; __le32 element = qh_element(qh); /* Try to make sure there's enough memory */ @@ -118,86 +165,36 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH))) out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); - if (!qh->urbp) { - out += sprintf(out, "%*s urbp == NULL\n", space, ""); - goto out; - } - - urbp = qh->urbp; - - head = &urbp->td_list; - tmp = head->next; - - td = list_entry(tmp, struct uhci_td, list); - - if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS)) - out += sprintf(out, "%*s Element != First TD\n", space, ""); - - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - - out += sprintf(out, "%*s%d: ", space + 2, "", i++); - out += uhci_show_td(td, out, len - (out - buf), 0); - - if (i > 10 && !checked && prevactive && tmp != head && - debug <= 2) { - struct list_head *ntmp = tmp; - struct uhci_td *ntd = td; - int active = 1, ni = i; - - checked = 1; - - while (ntmp != head && ntmp->next != head && active) { - ntd = list_entry(ntmp, struct uhci_td, list); - - ntmp = ntmp->next; - - active = td_status(ntd) & TD_CTRL_ACTIVE; - - ni++; - } - - if (active && ni > i) { - out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i); - tmp = ntmp; - td = ntd; - i = ni; - } + if (list_empty(&qh->queue)) { + out += sprintf(out, "%*s queue is empty\n", space, ""); + } else { + struct urb_priv *urbp = list_entry(qh->queue.next, + struct urb_priv, node); + struct uhci_td *td = list_entry(urbp->td_list.next, + struct uhci_td, list); + + if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS)) + out += sprintf(out, "%*s Element != First TD\n", + space, ""); + i = nurbs = 0; + list_for_each_entry(urbp, &qh->queue, node) { + if (++i <= 10) + out += uhci_show_urbp(urbp, out, + len - (out - buf), space + 2); + else + ++nurbs; } - - prevactive = td_status(td) & TD_CTRL_ACTIVE; - } - - if (list_empty(&urbp->queue_list) || urbp->queued) - goto out; - - out += sprintf(out, "%*sQueued QHs:\n", -space, "--"); - - head = &urbp->queue_list; - tmp = head->next; - - while (tmp != head) { - struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, - queue_list); - tmp = tmp->next; - - out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space); + if (nurbs > 0) + out += sprintf(out, "%*s Skipped %d URBs\n", + space, "", nurbs); } -out: return out - buf; } -#define show_frame_num() \ - if (!shown) { \ - shown = 1; \ - out += sprintf(out, "- Frame %d\n", i); \ - } - #ifdef CONFIG_PROC_FS static const char * const qh_names[] = { + "skel_unlink_qh", "skel_iso_qh", "skel_int128_qh", "skel_int64_qh", "skel_int32_qh", "skel_int16_qh", "skel_int8_qh", "skel_int4_qh", @@ -206,12 +203,6 @@ static const char * const qh_names[] = { "skel_bulk_qh", "skel_term_qh" }; -#define show_qh_name() \ - if (!shown) { \ - shown = 1; \ - out += sprintf(out, "- %s\n", qh_names[i]); \ - } - static int uhci_show_sc(int port, unsigned short status, char *buf, int len) { char *out = buf; @@ -321,139 +312,29 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) return out - buf; } -static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len) -{ - struct list_head *tmp; - char *out = buf; - int count = 0; - - if (len < 200) - return 0; - - out += sprintf(out, "urb_priv [%p] ", urbp); - out += sprintf(out, "urb [%p] ", urbp->urb); - out += sprintf(out, "qh [%p] ", urbp->qh); - out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe)); - out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); - - switch (usb_pipetype(urbp->urb->pipe)) { - case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break; - case PIPE_INTERRUPT: out += sprintf(out, "INT "); break; - case PIPE_BULK: out += sprintf(out, "BLK "); break; - case PIPE_CONTROL: out += sprintf(out, "CTL "); break; - } - - out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : "")); - out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : "")); - - if (urbp->urb->status != -EINPROGRESS) - out += sprintf(out, "Status=%d ", urbp->urb->status); - //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); - - count = 0; - list_for_each(tmp, &urbp->td_list) - count++; - out += sprintf(out, "TDs=%d ",count); - - if (urbp->queued) - out += sprintf(out, "queued\n"); - else { - count = 0; - list_for_each(tmp, &urbp->queue_list) - count++; - out += sprintf(out, "queued URBs=%d\n", count); - } - - return out - buf; -} - -static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len) -{ - char *out = buf; - struct list_head *head, *tmp; - int count; - - out += sprintf(out, "Main list URBs:"); - if (list_empty(&uhci->urb_list)) - out += sprintf(out, " Empty\n"); - else { - out += sprintf(out, "\n"); - count = 0; - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); - - out += sprintf(out, " %d: ", ++count); - out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); - tmp = tmp->next; - } - } - - out += sprintf(out, "Remove list URBs:"); - if (list_empty(&uhci->urb_remove_list)) - out += sprintf(out, " Empty\n"); - else { - out += sprintf(out, "\n"); - count = 0; - head = &uhci->urb_remove_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); - - out += sprintf(out, " %d: ", ++count); - out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); - tmp = tmp->next; - } - } - - out += sprintf(out, "Complete list URBs:"); - if (list_empty(&uhci->complete_list)) - out += sprintf(out, " Empty\n"); - else { - out += sprintf(out, "\n"); - count = 0; - head = &uhci->complete_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); - - out += sprintf(out, " %d: ", ++count); - out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); - tmp = tmp->next; - } - } - - return out - buf; -} - static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) { - unsigned long flags; char *out = buf; int i, j; struct uhci_qh *qh; struct uhci_td *td; struct list_head *tmp, *head; - spin_lock_irqsave(&uhci->lock, flags); - out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); out += sprintf(out, "HC status\n"); out += uhci_show_status(uhci, out, len - (out - buf)); + if (debug <= 1) + return out - buf; out += sprintf(out, "Frame List\n"); for (i = 0; i < UHCI_NUMFRAMES; ++i) { - int shown = 0; td = uhci->frame_cpu[i]; if (!td) continue; - if (td->dma_handle != (dma_addr_t)uhci->frame[i]) { - show_frame_num(); + out += sprintf(out, "- Frame %d\n", i); \ + if (td->dma_handle != (dma_addr_t)uhci->frame[i]) out += sprintf(out, " frame list does not match td->dma_handle!\n"); - } - show_frame_num(); head = &td->fl_list; tmp = head; @@ -467,14 +348,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) out += sprintf(out, "Skeleton QHs\n"); for (i = 0; i < UHCI_NUM_SKELQH; ++i) { - int shown = 0; + int cnt = 0; qh = uhci->skelqh[i]; - - if (debug > 1) { - show_qh_name(); - out += uhci_show_qh(qh, out, len - (out - buf), 4); - } + out += sprintf(out, "- %s\n", qh_names[i]); \ + out += uhci_show_qh(qh, out, len - (out - buf), 4); /* Last QH is the Terminating QH, it's different */ if (i == UHCI_NUM_SKELQH - 1) { @@ -487,44 +365,27 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) continue; } - j = (i < 7) ? 7 : i+1; /* Next skeleton */ - if (list_empty(&qh->list)) { - if (i < UHCI_NUM_SKELQH - 1) { - if (qh->link != - (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) { - show_qh_name(); - out += sprintf(out, " skeleton QH not linked to next skeleton QH!\n"); - } - } - - continue; - } - - show_qh_name(); - - head = &qh->list; + j = (i < 9) ? 9 : i+1; /* Next skeleton */ + head = &qh->node; tmp = head->next; while (tmp != head) { - qh = list_entry(tmp, struct uhci_qh, list); - + qh = list_entry(tmp, struct uhci_qh, node); tmp = tmp->next; - - out += uhci_show_qh(qh, out, len - (out - buf), 4); + if (++cnt <= 10) + out += uhci_show_qh(qh, out, + len - (out - buf), 4); } + if ((cnt -= 10) > 0) + out += sprintf(out, " Skipped %d QHs\n", cnt); - if (i < UHCI_NUM_SKELQH - 1) { + if (i > 1 && i < UHCI_NUM_SKELQH - 1) { if (qh->link != (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) out += sprintf(out, " last QH not linked to next skeleton!\n"); } } - if (debug > 2) - out += uhci_show_lists(uhci, out, len - (out - buf)); - - spin_unlock_irqrestore(&uhci->lock, flags); - return out - buf; } @@ -541,6 +402,7 @@ static int uhci_debug_open(struct inode *inode, struct file *file) struct uhci_hcd *uhci = inode->u.generic_ip; struct uhci_debug *up; int ret = -ENOMEM; + unsigned long flags; lock_kernel(); up = kmalloc(sizeof(*up), GFP_KERNEL); @@ -553,7 +415,9 @@ static int uhci_debug_open(struct inode *inode, struct file *file) goto out; } + spin_lock_irqsave(&uhci->lock, flags); up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); + spin_unlock_irqrestore(&uhci->lock, flags); file->private_data = up; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index dfe121d35887..1ff4b8806372 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -54,7 +54,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v2.3" +#define DRIVER_VERSION "v3.0" #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \ Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ Alan Stern" @@ -489,15 +489,11 @@ static int uhci_start(struct usb_hcd *hcd) uhci->fsbrtimeout = 0; spin_lock_init(&uhci->lock); - INIT_LIST_HEAD(&uhci->qh_remove_list); INIT_LIST_HEAD(&uhci->td_remove_list); - - INIT_LIST_HEAD(&uhci->urb_remove_list); - INIT_LIST_HEAD(&uhci->urb_list); - INIT_LIST_HEAD(&uhci->complete_list); + INIT_LIST_HEAD(&uhci->idle_qh_list); init_waitqueue_head(&uhci->waitqh); @@ -540,7 +536,7 @@ static int uhci_start(struct usb_hcd *hcd) } for (i = 0; i < UHCI_NUM_SKELQH; i++) { - uhci->skelqh[i] = uhci_alloc_qh(uhci); + uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL); if (!uhci->skelqh[i]) { dev_err(uhci_dev(uhci), "unable to allocate QH\n"); goto err_alloc_skelqh; @@ -557,13 +553,17 @@ static int uhci_start(struct usb_hcd *hcd) uhci->skel_int16_qh->link = uhci->skel_int8_qh->link = uhci->skel_int4_qh->link = - uhci->skel_int2_qh->link = - cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH; - uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH; - - uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH; - uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH; - uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH; + uhci->skel_int2_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_int1_qh->dma_handle); + + uhci->skel_int1_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_ls_control_qh->dma_handle); + uhci->skel_ls_control_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_fs_control_qh->dma_handle); + uhci->skel_fs_control_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_bulk_qh->dma_handle); + uhci->skel_bulk_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_term_qh->dma_handle); /* This dummy TD is to work around a bug in Intel PIIX controllers */ uhci_fill_td(uhci->term_td, 0, uhci_explen(0) | @@ -589,15 +589,15 @@ static int uhci_start(struct usb_hcd *hcd) /* * ffs (Find First bit Set) does exactly what we need: - * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[6], - * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc. - * ffs > 6 => not on any high-period queue, so use - * skel_int1_qh = skelqh[7]. + * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], + * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. + * ffs >= 7 => not on any high-period queue, so use + * skel_int1_qh = skelqh[9]. * Add UHCI_NUMFRAMES to insure at least one bit is set. */ - irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES); - if (irq < 0) - irq = 7; + irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES); + if (irq <= 1) + irq = 9; /* Only place we don't use the frame list routines */ uhci->frame[i] = UHCI_PTR_QH | @@ -767,13 +767,30 @@ static int uhci_resume(struct usb_hcd *hcd) } #endif -/* Wait until all the URBs for a particular device/endpoint are gone */ +/* Wait until a particular device/endpoint's QH is idle, and free it */ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) + struct usb_host_endpoint *hep) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); + struct uhci_qh *qh; + + spin_lock_irq(&uhci->lock); + qh = (struct uhci_qh *) hep->hcpriv; + if (qh == NULL) + goto done; - wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list)); + while (qh->state != QH_STATE_IDLE) { + ++uhci->num_waiting; + spin_unlock_irq(&uhci->lock); + wait_event_interruptible(uhci->waitqh, + qh->state == QH_STATE_IDLE); + spin_lock_irq(&uhci->lock); + --uhci->num_waiting; + } + + uhci_free_qh(uhci, qh); +done: + spin_unlock_irq(&uhci->lock); } static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 8b4b887a7d41..7a9481c09a05 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -28,8 +28,9 @@ #define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ #define USBSTS_ERROR 0x0002 /* Interrupt due to error */ #define USBSTS_RD 0x0004 /* Resume Detect */ -#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */ -#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */ +#define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */ +#define USBSTS_HCPE 0x0010 /* Host Controller Process Error: + * the schedule is buggy */ #define USBSTS_HCH 0x0020 /* HC Halted */ /* Interrupt enable register */ @@ -47,7 +48,8 @@ /* USB port status and control registers */ #define USBPORTSC1 16 #define USBPORTSC2 18 -#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */ +#define USBPORTSC_CCS 0x0001 /* Current Connect Status + * ("device present") */ #define USBPORTSC_CSC 0x0002 /* Connect Status Change */ #define USBPORTSC_PE 0x0004 /* Port Enable */ #define USBPORTSC_PEC 0x0008 /* Port Enable Change */ @@ -71,15 +73,16 @@ #define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ #define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ -#define UHCI_PTR_BITS cpu_to_le32(0x000F) -#define UHCI_PTR_TERM cpu_to_le32(0x0001) -#define UHCI_PTR_QH cpu_to_le32(0x0002) -#define UHCI_PTR_DEPTH cpu_to_le32(0x0004) -#define UHCI_PTR_BREADTH cpu_to_le32(0x0000) +#define UHCI_PTR_BITS __constant_cpu_to_le32(0x000F) +#define UHCI_PTR_TERM __constant_cpu_to_le32(0x0001) +#define UHCI_PTR_QH __constant_cpu_to_le32(0x0002) +#define UHCI_PTR_DEPTH __constant_cpu_to_le32(0x0004) +#define UHCI_PTR_BREADTH __constant_cpu_to_le32(0x0000) #define UHCI_NUMFRAMES 1024 /* in the frame list [array] */ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ -#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */ +#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames + * can be scheduled */ /* @@ -87,38 +90,54 @@ */ /* - * One role of a QH is to hold a queue of TDs for some endpoint. Each QH is - * used with one URB, and qh->element (updated by the HC) is either: - * - the next unprocessed TD for the URB, or - * - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or - * - the QH for the next URB queued to the same endpoint. + * One role of a QH is to hold a queue of TDs for some endpoint. One QH goes + * with each endpoint, and qh->element (updated by the HC) is either: + * - the next unprocessed TD in the endpoint's queue, or + * - UHCI_PTR_TERM (when there's no more traffic for this endpoint). * * The other role of a QH is to serve as a "skeleton" framelist entry, so we * can easily splice a QH for some endpoint into the schedule at the right * place. Then qh->element is UHCI_PTR_TERM. * - * In the frame list, qh->link maintains a list of QHs seen by the HC: + * In the schedule, qh->link maintains a list of QHs seen by the HC: * skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ... + * + * qh->node is the software equivalent of qh->link. The differences + * are that the software list is doubly-linked and QHs in the UNLINKING + * state are on the software list but not the hardware schedule. + * + * For bookkeeping purposes we maintain QHs even for Isochronous endpoints, + * but they never get added to the hardware schedule. */ +#define QH_STATE_IDLE 1 /* QH is not being used */ +#define QH_STATE_UNLINKING 2 /* QH has been removed from the + * schedule but the hardware may + * still be using it */ +#define QH_STATE_ACTIVE 3 /* QH is on the schedule */ + struct uhci_qh { /* Hardware fields */ - __le32 link; /* Next queue */ - __le32 element; /* Queue element pointer */ + __le32 link; /* Next QH in the schedule */ + __le32 element; /* Queue element (TD) pointer */ /* Software fields */ dma_addr_t dma_handle; - struct urb_priv *urbp; + struct list_head node; /* Node in the list of QHs */ + struct usb_host_endpoint *hep; /* Endpoint information */ + struct usb_device *udev; + struct list_head queue; /* Queue of urbps for this QH */ + struct uhci_qh *skel; /* Skeleton for this QH */ - struct list_head list; - struct list_head remove_list; + unsigned int unlink_frame; /* When the QH was unlinked */ + int state; /* QH_STATE_xxx; see above */ } __attribute__((aligned(16))); /* * We need a special accessor for the element pointer because it is * subject to asynchronous updates by the controller. */ -static __le32 inline qh_element(struct uhci_qh *qh) { +static inline __le32 qh_element(struct uhci_qh *qh) { __le32 element = qh->element; barrier(); @@ -149,11 +168,13 @@ static __le32 inline qh_element(struct uhci_qh *qh) { #define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */ #define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \ - TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF) + TD_CTRL_BABBLE | TD_CTRL_CRCTIME | \ + TD_CTRL_BITSTUFF) #define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT) #define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xF60000) -#define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ +#define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & \ + TD_CTRL_ACTLEN_MASK) /* 1-based */ /* * for TD : (a.k.a. Token) @@ -163,7 +184,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) { #define TD_TOKEN_TOGGLE_SHIFT 19 #define TD_TOKEN_TOGGLE (1 << 19) #define TD_TOKEN_EXPLEN_SHIFT 21 -#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n - 1 */ +#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n-1 */ #define TD_TOKEN_PID_MASK 0xFF #define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \ @@ -187,7 +208,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) { * sw space after the TD entry. * * td->link points to either another TD (not necessarily for the same urb or - * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs). + * even the same endpoint), or nothing (PTR_TERM), or a QH. */ struct uhci_td { /* Hardware fields */ @@ -210,7 +231,7 @@ struct uhci_td { * We need a special accessor for the control/status word because it is * subject to asynchronous updates by the controller. */ -static u32 inline td_status(struct uhci_td *td) { +static inline u32 td_status(struct uhci_td *td) { __le32 status = td->status; barrier(); @@ -223,17 +244,14 @@ static u32 inline td_status(struct uhci_td *td) { */ /* - * The UHCI driver places Interrupt, Control and Bulk into QHs both - * to group together TDs for one transfer, and also to facilitate queuing - * of URBs. To make it easy to insert entries into the schedule, we have - * a skeleton of QHs for each predefined Interrupt latency, low-speed - * control, full-speed control and terminating QH (see explanation for - * the terminating QH below). + * The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for + * automatic queuing. To make it easy to insert entries into the schedule, + * we have a skeleton of QHs for each predefined Interrupt latency, + * low-speed control, full-speed control, bulk, and terminating QH + * (see explanation for the terminating QH below). * * When we want to add a new QH, we add it to the end of the list for the - * skeleton QH. - * - * For instance, the queue can look like this: + * skeleton QH. For instance, the schedule list can look like this: * * skel int128 QH * dev 1 interrupt QH @@ -256,26 +274,31 @@ static u32 inline td_status(struct uhci_td *td) { * - To loop back to the full-speed control queue for full-speed bandwidth * reclamation. * - * Isochronous transfers are stored before the start of the skeleton - * schedule and don't use QHs. While the UHCI spec doesn't forbid the - * use of QHs for Isochronous, it doesn't use them either. And the spec - * says that queues never advance on an error completion status, which - * makes them totally unsuitable for Isochronous transfers. + * There's a special skeleton QH for Isochronous QHs. It never appears + * on the schedule, and Isochronous TDs go on the schedule before the + * the skeleton QHs. The hardware accesses them directly rather than + * through their QH, which is used only for bookkeeping purposes. + * While the UHCI spec doesn't forbid the use of QHs for Isochronous, + * it doesn't use them either. And the spec says that queues never + * advance on an error completion status, which makes them totally + * unsuitable for Isochronous transfers. */ -#define UHCI_NUM_SKELQH 12 -#define skel_int128_qh skelqh[0] -#define skel_int64_qh skelqh[1] -#define skel_int32_qh skelqh[2] -#define skel_int16_qh skelqh[3] -#define skel_int8_qh skelqh[4] -#define skel_int4_qh skelqh[5] -#define skel_int2_qh skelqh[6] -#define skel_int1_qh skelqh[7] -#define skel_ls_control_qh skelqh[8] -#define skel_fs_control_qh skelqh[9] -#define skel_bulk_qh skelqh[10] -#define skel_term_qh skelqh[11] +#define UHCI_NUM_SKELQH 14 +#define skel_unlink_qh skelqh[0] +#define skel_iso_qh skelqh[1] +#define skel_int128_qh skelqh[2] +#define skel_int64_qh skelqh[3] +#define skel_int32_qh skelqh[4] +#define skel_int16_qh skelqh[5] +#define skel_int8_qh skelqh[6] +#define skel_int4_qh skelqh[7] +#define skel_int2_qh skelqh[8] +#define skel_int1_qh skelqh[9] +#define skel_ls_control_qh skelqh[10] +#define skel_fs_control_qh skelqh[11] +#define skel_bulk_qh skelqh[12] +#define skel_term_qh skelqh[13] /* * Search tree for determining where fits in the skelqh[] @@ -293,21 +316,21 @@ static inline int __interval_to_skel(int interval) if (interval < 16) { if (interval < 4) { if (interval < 2) - return 7; /* int1 for 0-1 ms */ - return 6; /* int2 for 2-3 ms */ + return 9; /* int1 for 0-1 ms */ + return 8; /* int2 for 2-3 ms */ } if (interval < 8) - return 5; /* int4 for 4-7 ms */ - return 4; /* int8 for 8-15 ms */ + return 7; /* int4 for 4-7 ms */ + return 6; /* int8 for 8-15 ms */ } if (interval < 64) { if (interval < 32) - return 3; /* int16 for 16-31 ms */ - return 2; /* int32 for 32-63 ms */ + return 5; /* int16 for 16-31 ms */ + return 4; /* int32 for 32-63 ms */ } if (interval < 128) - return 1; /* int64 for 64-127 ms */ - return 0; /* int128 for 128-255 ms (Max.) */ + return 3; /* int64 for 64-127 ms */ + return 2; /* int128 for 128-255 ms (Max.) */ } @@ -363,12 +386,12 @@ struct uhci_hcd { spinlock_t lock; - dma_addr_t frame_dma_handle; /* Hardware frame list */ + dma_addr_t frame_dma_handle; /* Hardware frame list */ __le32 *frame; - void **frame_cpu; /* CPU's frame list */ + void **frame_cpu; /* CPU's frame list */ - int fsbr; /* Full-speed bandwidth reclamation */ - unsigned long fsbrtimeout; /* FSBR delay */ + int fsbr; /* Full-speed bandwidth reclamation */ + unsigned long fsbrtimeout; /* FSBR delay */ enum uhci_rh_state rh_state; unsigned long auto_stop_time; /* When to AUTO_STOP */ @@ -392,24 +415,19 @@ struct uhci_hcd { /* Main list of URBs currently controlled by this HC */ struct list_head urb_list; - /* List of QHs that are done, but waiting to be unlinked (race) */ - struct list_head qh_remove_list; - unsigned int qh_remove_age; /* Age in frames */ - /* List of TDs that are done, but waiting to be freed (race) */ struct list_head td_remove_list; unsigned int td_remove_age; /* Age in frames */ - /* List of asynchronously unlinked URBs */ - struct list_head urb_remove_list; - unsigned int urb_remove_age; /* Age in frames */ - /* List of URBs awaiting completion callback */ struct list_head complete_list; + struct list_head idle_qh_list; /* Where the idle QHs live */ + int rh_numports; /* Number of root-hub ports */ wait_queue_head_t waitqh; /* endpoint_disable waiters */ + int num_waiting; /* Number of waiters */ }; /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */ @@ -430,22 +448,19 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci) */ struct urb_priv { struct list_head urb_list; + struct list_head node; /* Node in the QH's urbp list */ struct urb *urb; struct uhci_qh *qh; /* QH for this URB */ struct list_head td_list; - unsigned fsbr : 1; /* URB turned on FSBR */ - unsigned fsbr_timeout : 1; /* URB timed out on FSBR */ - unsigned queued : 1; /* QH was queued (not linked in) */ - unsigned short_control_packet : 1; /* If we get a short packet during */ - /* a control transfer, retrigger */ - /* the status phase */ - unsigned long fsbrtime; /* In jiffies */ - struct list_head queue_list; + unsigned fsbr : 1; /* URB turned on FSBR */ + unsigned fsbr_timeout : 1; /* URB timed out on FSBR */ + unsigned short_transfer : 1; /* URB got a short transfer, no + * need to rescan */ }; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 782398045f9f..b1b551a3d14e 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -13,13 +13,9 @@ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) - * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu + * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu */ -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb); -static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb); -static void uhci_remove_pending_urbps(struct uhci_hcd *uhci); -static void uhci_free_pending_qhs(struct uhci_hcd *uhci); static void uhci_free_pending_tds(struct uhci_hcd *uhci); /* @@ -30,7 +26,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci); * games with the FSBR code to make sure we get the correct order in all * the cases. I don't think it's worth the effort */ -static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) +static void uhci_set_next_interrupt(struct uhci_hcd *uhci) { if (uhci->is_stopped) mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); @@ -42,12 +38,6 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); } -static inline void uhci_moveto_complete(struct uhci_hcd *uhci, - struct urb_priv *urbp) -{ - list_move_tail(&urbp->urb_list, &uhci->complete_list); -} - static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) { dma_addr_t dma_handle; @@ -71,6 +61,18 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) return td; } +static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) +{ + if (!list_empty(&td->list)) + dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); + if (!list_empty(&td->remove_list)) + dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td); + if (!list_empty(&td->fl_list)) + dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); + + dma_pool_free(uhci->td_pool, td, td->dma_handle); +} + static inline void uhci_fill_td(struct uhci_td *td, u32 status, u32 token, u32 buffer) { @@ -82,7 +84,8 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status, /* * We insert Isochronous URBs directly into the frame list at the beginning */ -static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum) +static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci, + struct uhci_td *td, unsigned framenum) { framenum &= (UHCI_NUMFRAMES - 1); @@ -108,7 +111,7 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, } } -static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci, +static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci, struct uhci_td *td) { /* If it's not inserted, don't remove it */ @@ -139,48 +142,68 @@ static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci, td->frame = -1; } -static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) +/* + * Remove all the TDs for an Isochronous URB from the frame list + */ +static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; struct uhci_td *td; list_for_each_entry(td, &urbp->td_list, list) - uhci_remove_td_frame_list(uhci, td); + uhci_remove_td_from_frame_list(uhci, td); wmb(); } /* - * Inserts a td list into qh. + * Remove an URB's TDs from the hardware schedule */ -static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth) +static void uhci_remove_tds_from_schedule(struct uhci_hcd *uhci, + struct urb *urb, int status) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - __le32 *plink; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - /* Ordering isn't important here yet since the QH hasn't been */ - /* inserted into the schedule yet */ - plink = &qh->element; - list_for_each_entry(td, &urbp->td_list, list) { - *plink = cpu_to_le32(td->dma_handle) | breadth; - plink = &td->link; + /* Isochronous TDs get unlinked directly from the frame list */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + uhci_unlink_isochronous_tds(uhci, urb); + return; } - *plink = UHCI_PTR_TERM; -} -static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) -{ - if (!list_empty(&td->list)) - dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); - if (!list_empty(&td->remove_list)) - dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td); - if (!list_empty(&td->fl_list)) - dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); + /* If the URB isn't first on its queue, adjust the link pointer + * of the last TD in the previous URB. */ + if (urbp->node.prev != &urbp->qh->queue) { + struct urb_priv *purbp; + struct uhci_td *ptd, *ltd; + + if (status == -EINPROGRESS) + status = 0; + purbp = list_entry(urbp->node.prev, struct urb_priv, node); + ptd = list_entry(purbp->td_list.prev, struct uhci_td, + list); + ltd = list_entry(urbp->td_list.prev, struct uhci_td, + list); + ptd->link = ltd->link; + } - dma_pool_free(uhci->td_pool, td, td->dma_handle); + /* If the URB completed with an error, then the QH element certainly + * points to one of the URB's TDs. If it completed normally then + * the QH element has certainly moved on to the next URB. And if + * the URB is still in progress then it must have been dequeued. + * The QH element either hasn't reached it yet or is somewhere in + * the middle. If the URB wasn't first we can assume that it + * hasn't started yet (see above): Otherwise all the preceding URBs + * would have completed and been removed from the queue, so this one + * _would_ be first. + * + * If the QH element is inside this URB, clear it. It will be + * set properly when the QH is activated. + */ + if (status < 0) + urbp->qh->element = UHCI_PTR_TERM; } -static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci) +static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, + struct usb_device *udev, struct usb_host_endpoint *hep) { dma_addr_t dma_handle; struct uhci_qh *qh; @@ -194,256 +217,120 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci) qh->element = UHCI_PTR_TERM; qh->link = UHCI_PTR_TERM; - qh->urbp = NULL; + INIT_LIST_HEAD(&qh->queue); + INIT_LIST_HEAD(&qh->node); - INIT_LIST_HEAD(&qh->list); - INIT_LIST_HEAD(&qh->remove_list); + if (udev) { /* Normal QH */ + qh->state = QH_STATE_IDLE; + qh->hep = hep; + qh->udev = udev; + hep->hcpriv = qh; + usb_get_dev(udev); + } else { /* Skeleton QH */ + qh->state = QH_STATE_ACTIVE; + qh->udev = NULL; + } return qh; } static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { - if (!list_empty(&qh->list)) + WARN_ON(qh->state != QH_STATE_IDLE && qh->udev); + if (!list_empty(&qh->queue)) dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh); - if (!list_empty(&qh->remove_list)) - dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh); + list_del(&qh->node); + if (qh->udev) { + qh->hep->hcpriv = NULL; + usb_put_dev(qh->udev); + } dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); } /* - * Append this urb's qh after the last qh in skelqh->list - * - * Note that urb_priv.queue_list doesn't have a separate queue head; - * it's a ring with every element "live". + * Put a QH on the schedule in both hardware and software */ -static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) +static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct urb_priv *turbp; - struct uhci_qh *lqh; + struct uhci_qh *pqh; - /* Grab the last QH */ - lqh = list_entry(skelqh->list.prev, struct uhci_qh, list); + WARN_ON(list_empty(&qh->queue)); - /* Point to the next skelqh */ - urbp->qh->link = lqh->link; - wmb(); /* Ordering is important */ + /* Set the element pointer if it isn't set already. + * This isn't needed for Isochronous queues, but it doesn't hurt. */ + if (qh_element(qh) == UHCI_PTR_TERM) { + struct urb_priv *urbp = list_entry(qh->queue.next, + struct urb_priv, node); + struct uhci_td *td = list_entry(urbp->td_list.next, + struct uhci_td, list); - /* - * Patch QHs for previous endpoint's queued URBs? HC goes - * here next, not to the next skelqh it now points to. - * - * lqh --> td ... --> qh ... --> td --> qh ... --> td - * | | | - * v v v - * +<----------------+-----------------+ - * v - * newqh --> td ... --> td - * | - * v - * ... - * - * The HC could see (and use!) any of these as we write them. - */ - lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; - if (lqh->urbp) { - list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list) - turbp->qh->link = lqh->link; + qh->element = cpu_to_le32(td->dma_handle); } - list_add_tail(&urbp->qh->list, &skelqh->list); + if (qh->state == QH_STATE_ACTIVE) + return; + qh->state = QH_STATE_ACTIVE; + + /* Move the QH from its old list to the end of the appropriate + * skeleton's list */ + list_move_tail(&qh->node, &qh->skel->node); + + /* Link it into the schedule */ + pqh = list_entry(qh->node.prev, struct uhci_qh, node); + qh->link = pqh->link; + wmb(); + pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle); } /* - * Start removal of QH from schedule; it finishes next frame. - * TDs should be unlinked before this is called. + * Take a QH off the hardware schedule */ -static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) +static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { struct uhci_qh *pqh; - __le32 newlink; - if (!qh) + if (qh->state == QH_STATE_UNLINKING) return; + WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev); + qh->state = QH_STATE_UNLINKING; - /* - * Only go through the hoops if it's actually linked in - */ - if (!list_empty(&qh->list)) { - - /* If our queue is nonempty, make the next URB the head */ - if (!list_empty(&qh->urbp->queue_list)) { - struct urb_priv *nurbp; - - nurbp = list_entry(qh->urbp->queue_list.next, - struct urb_priv, queue_list); - nurbp->queued = 0; - list_add(&nurbp->qh->list, &qh->list); - newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - } else - newlink = qh->link; - - /* Fix up the previous QH's queue to link to either - * the new head of this queue or the start of the - * next endpoint's queue. */ - pqh = list_entry(qh->list.prev, struct uhci_qh, list); - pqh->link = newlink; - if (pqh->urbp) { - struct urb_priv *turbp; - - list_for_each_entry(turbp, &pqh->urbp->queue_list, - queue_list) - turbp->qh->link = newlink; - } - wmb(); - - /* Leave qh->link in case the HC is on the QH now, it will */ - /* continue the rest of the schedule */ - qh->element = UHCI_PTR_TERM; - - list_del_init(&qh->list); - } - - list_del_init(&qh->urbp->queue_list); - qh->urbp = NULL; + /* Unlink the QH from the schedule and record when we did it */ + pqh = list_entry(qh->node.prev, struct uhci_qh, node); + pqh->link = qh->link; + mb(); uhci_get_current_frame_number(uhci); - if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) { - uhci_free_pending_qhs(uhci); - uhci->qh_remove_age = uhci->frame_number; - } + qh->unlink_frame = uhci->frame_number; - /* Check to see if the remove list is empty. Set the IOC bit */ - /* to force an interrupt so we can remove the QH */ - if (list_empty(&uhci->qh_remove_list)) + /* Force an interrupt so we know when the QH is fully unlinked */ + if (list_empty(&uhci->skel_unlink_qh->node)) uhci_set_next_interrupt(uhci); - list_add(&qh->remove_list, &uhci->qh_remove_list); + /* Move the QH from its old list to the end of the unlinking list */ + list_move_tail(&qh->node, &uhci->skel_unlink_qh->node); } -static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - - list_for_each_entry(td, &urbp->td_list, list) { - if (toggle) - td->token |= cpu_to_le32(TD_TOKEN_TOGGLE); - else - td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE); - - toggle ^= 1; - } - - return toggle; -} - -/* This function will append one URB's QH to another URB's QH. This is for */ -/* queuing interrupt, control or bulk transfers */ -static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb) -{ - struct urb_priv *eurbp, *urbp, *furbp, *lurbp; - struct uhci_td *lltd; - - eurbp = eurb->hcpriv; - urbp = urb->hcpriv; - - /* Find the first URB in the queue */ - furbp = eurbp; - if (eurbp->queued) { - list_for_each_entry(furbp, &eurbp->queue_list, queue_list) - if (!furbp->queued) - break; - } - - lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list); - - lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list); - - /* Control transfers always start with toggle 0 */ - if (!usb_pipecontrol(urb->pipe)) - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), - uhci_fixup_toggle(urb, - uhci_toggle(td_token(lltd)) ^ 1)); - - /* All qhs in the queue need to link to the next queue */ - urbp->qh->link = eurbp->qh->link; - - wmb(); /* Make sure we flush everything */ - - lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; - - list_add_tail(&urbp->queue_list, &furbp->queue_list); - - urbp->queued = 1; -} - -static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb) +/* + * When we and the controller are through with a QH, it becomes IDLE. + * This happens when a QH has been off the schedule (on the unlinking + * list) for more than one frame, or when an error occurs while adding + * the first URB onto a new QH. + */ +static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh) { - struct urb_priv *urbp, *nurbp, *purbp, *turbp; - struct uhci_td *pltd; - unsigned int toggle; - - urbp = urb->hcpriv; - - if (list_empty(&urbp->queue_list)) - return; - - nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list); - - /* - * Fix up the toggle for the following URBs in the queue. - * Only needed for bulk and interrupt: control and isochronous - * endpoints don't propagate toggles between messages. - */ - if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) { - if (!urbp->queued) - /* We just set the toggle in uhci_unlink_generic */ - toggle = usb_gettoggle(urb->dev, - usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - else { - /* If we're in the middle of the queue, grab the */ - /* toggle from the TD previous to us */ - purbp = list_entry(urbp->queue_list.prev, - struct urb_priv, queue_list); - pltd = list_entry(purbp->td_list.prev, - struct uhci_td, list); - toggle = uhci_toggle(td_token(pltd)) ^ 1; - } - - list_for_each_entry(turbp, &urbp->queue_list, queue_list) { - if (!turbp->queued) - break; - toggle = uhci_fixup_toggle(turbp->urb, toggle); - } + WARN_ON(qh->state == QH_STATE_ACTIVE); - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), toggle); - } - - if (urbp->queued) { - /* We're somewhere in the middle (or end). The case where - * we're at the head is handled in uhci_remove_qh(). */ - purbp = list_entry(urbp->queue_list.prev, struct urb_priv, - queue_list); - - pltd = list_entry(purbp->td_list.prev, struct uhci_td, list); - if (nurbp->queued) - pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - else - /* The next URB happens to be the beginning, so */ - /* we're the last, end the chain */ - pltd->link = UHCI_PTR_TERM; - } + list_move(&qh->node, &uhci->idle_qh_list); + qh->state = QH_STATE_IDLE; - /* urbp->queue_list is handled in uhci_remove_qh() */ + /* If anyone is waiting for a QH to become idle, wake them up */ + if (uhci->num_waiting) + wake_up_all(&uhci->waitqh); } -static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) +static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, + struct urb *urb) { struct urb_priv *urbp; @@ -453,17 +340,14 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u memset((void *)urbp, 0, sizeof(*urbp)); - urbp->fsbrtime = jiffies; urbp->urb = urb; + urb->hcpriv = urbp; + urbp->fsbrtime = jiffies; + INIT_LIST_HEAD(&urbp->node); INIT_LIST_HEAD(&urbp->td_list); - INIT_LIST_HEAD(&urbp->queue_list); INIT_LIST_HEAD(&urbp->urb_list); - list_add_tail(&urbp->urb_list, &uhci->urb_list); - - urb->hcpriv = urbp; - return urbp; } @@ -482,18 +366,17 @@ static void uhci_remove_td_from_urb(struct uhci_td *td) list_del_init(&td->list); } -static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) +static void uhci_free_urb_priv(struct uhci_hcd *uhci, + struct urb_priv *urbp) { struct uhci_td *td, *tmp; - struct urb_priv *urbp; - - urbp = (struct urb_priv *)urb->hcpriv; - if (!urbp) - return; if (!list_empty(&urbp->urb_list)) - dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list " - "or uhci->remove_list!\n", urb); + dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list!\n", + urbp->urb); + if (!list_empty(&urbp->node)) + dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n", + urbp->urb); uhci_get_current_frame_number(uhci); if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) { @@ -502,7 +385,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) } /* Check to see if the remove list is empty. Set the IOC bit */ - /* to force an interrupt so we can remove the TDs*/ + /* to force an interrupt so we can remove the TDs. */ if (list_empty(&uhci->td_remove_list)) uhci_set_next_interrupt(uhci); @@ -511,7 +394,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) list_add(&td->remove_list, &uhci->td_remove_list); } - urb->hcpriv = NULL; + urbp->urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } @@ -567,18 +450,83 @@ static int uhci_map_status(int status, int dir_out) return 0; } +/* + * Fix up the data toggles for URBs in a queue, when one of them + * terminates early (short transfer, error, or dequeued). + */ +static void uhci_fixup_toggles(struct urb *urb) +{ + struct list_head *head; + struct uhci_td *td; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; + int prevactive = 0; + unsigned int toggle = 0; + struct urb_priv *turbp, *list_end; + + /* + * We need to find out what the last successful toggle was so + * we can update the data toggles for the following transfers. + * + * There are 2 ways the last successful completed TD is found: + * + * 1) The TD is NOT active and the actual length < expected length + * 2) The TD is NOT active and it's the last TD in the chain + * + * and a third way the first uncompleted TD is found: + * + * 3) The TD is active and the previous TD is NOT active + */ + head = &urbp->td_list; + list_for_each_entry(td, head, list) { + unsigned int ctrlstat = td_status(td); + + if (!(ctrlstat & TD_CTRL_ACTIVE) && + (uhci_actual_length(ctrlstat) < + uhci_expected_length(td_token(td)) || + td->list.next == head)) + toggle = uhci_toggle(td_token(td)) ^ 1; + else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive) + toggle = uhci_toggle(td_token(td)); + + prevactive = ctrlstat & TD_CTRL_ACTIVE; + } + + /* + * Fix up the toggle for the following URBs in the queue. + * + * We can stop as soon as we find an URB with toggles set correctly, + * because then all the following URBs will be correct also. + */ + list_end = list_entry(&urbp->qh->queue, struct urb_priv, node); + turbp = urbp; + while ((turbp = list_entry(turbp->node.next, struct urb_priv, node)) + != list_end) { + td = list_entry(turbp->td_list.next, struct uhci_td, list); + if (uhci_toggle(td_token(td)) == toggle) + return; + + list_for_each_entry(td, &turbp->td_list, list) { + td->token ^= __constant_cpu_to_le32(TD_TOKEN_TOGGLE); + toggle ^= 1; + } + } + + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), toggle); +} + /* * Control transfers */ -static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) +static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci_td *td; - struct uhci_qh *qh, *skelqh; unsigned long destination, status; - int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); int len = urb->transfer_buffer_length; dma_addr_t data = urb->transfer_dma; + __le32 *plink; /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; @@ -597,7 +545,8 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | uhci_explen(8), - urb->setup_dma); + urb->setup_dma); + plink = &td->link; /* * If direction is "send", change the packet ID from SETUP (0x2D) @@ -615,21 +564,20 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur * Build the DATA TDs */ while (len > 0) { - int pktsze = len; - - if (pktsze > maxsze) - pktsze = maxsze; + int pktsze = min(len, maxsze); td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; + *plink = cpu_to_le32(td->dma_handle); /* Alternate Data0/1 (start with Data1) */ destination ^= TD_TOKEN_TOGGLE; uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | uhci_explen(pktsze), - data); + data); + plink = &td->link; data += pktsze; len -= pktsze; @@ -641,6 +589,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; + *plink = cpu_to_le32(td->dma_handle); /* * It's IN if the pipe is an output pipe or we're not expecting @@ -658,16 +607,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status | TD_CTRL_IOC, - destination | uhci_explen(0), 0); - - qh = uhci_alloc_qh(uhci); - if (!qh) - return -ENOMEM; - - urbp->qh = qh; - qh->urbp = urbp; - - uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); + destination | uhci_explen(0), 0); /* Low-speed transfers get a different queue, and won't hog the bus. * Also, some devices enumerate better without FSBR; the easiest way @@ -675,18 +615,13 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur * isn't in the CONFIGURED state. */ if (urb->dev->speed == USB_SPEED_LOW || urb->dev->state != USB_STATE_CONFIGURED) - skelqh = uhci->skel_ls_control_qh; + qh->skel = uhci->skel_ls_control_qh; else { - skelqh = uhci->skel_fs_control_qh; + qh->skel = uhci->skel_fs_control_qh; uhci_inc_fsbr(uhci, urb); } - if (eurb) - uhci_append_queued_urb(uhci, eurb, urb); - else - uhci_insert_qh(uhci, skelqh, urb); - - return -EINPROGRESS; + return 0; } /* @@ -703,7 +638,7 @@ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb) struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci_td *td; - urbp->short_control_packet = 1; + urbp->short_transfer = 1; td = list_entry(urbp->td_list.prev, struct uhci_td, list); urbp->qh->element = cpu_to_le32(td->dma_handle); @@ -720,16 +655,14 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) unsigned int status; int ret = 0; - if (list_empty(&urbp->td_list)) - return -EINVAL; - head = &urbp->td_list; - - if (urbp->short_control_packet) { + if (urbp->short_transfer) { tmp = head->prev; goto status_stage; } + urb->actual_length = 0; + tmp = head->next; td = list_entry(tmp, struct uhci_td, list); @@ -742,8 +675,6 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) if (status) goto td_error; - urb->actual_length = 0; - /* The rest of the TDs (but the last) are data */ tmp = tmp->next; while (tmp != head && tmp->next != head) { @@ -770,10 +701,7 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) goto err; } - if (uhci_packetid(td_token(td)) == USB_PID_IN) - return usb_control_retrigger_status(uhci, urb); - else - return 0; + return usb_control_retrigger_status(uhci, urb); } } @@ -825,15 +753,15 @@ err: /* * Common submit for bulk and interrupt */ -static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh) +static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { struct uhci_td *td; - struct uhci_qh *qh; unsigned long destination, status; - int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); int len = urb->transfer_buffer_length; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; dma_addr_t data = urb->transfer_dma; + __le32 *plink, fake_link; if (len < 0) return -EINVAL; @@ -841,7 +769,8 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - status = uhci_maxerr(3) | TD_CTRL_ACTIVE; + /* 3 errors */ + status = TD_CTRL_ACTIVE | uhci_maxerr(3); if (urb->dev->speed == USB_SPEED_LOW) status |= TD_CTRL_LS; if (usb_pipein(urb->pipe)) @@ -850,10 +779,11 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb /* * Build the DATA TDs */ + plink = &fake_link; do { /* Allow zero length packets */ int pktsze = maxsze; - if (pktsze >= len) { + if (len <= pktsze) { /* The last packet */ pktsze = len; if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) status &= ~TD_CTRL_SPD; @@ -862,12 +792,15 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; + *plink = cpu_to_le32(td->dma_handle); uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(pktsze) | + uhci_fill_td(td, status, + destination | uhci_explen(pktsze) | (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT), data); + plink = &td->link; data += pktsze; len -= maxsze; @@ -883,11 +816,13 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb * however, if transfer_length == 0, the zero packet was already * prepared above. */ - if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) && - !len && urb->transfer_buffer_length) { + if ((urb->transfer_flags & URB_ZERO_PACKET) && + usb_pipeout(urb->pipe) && len == 0 && + urb->transfer_buffer_length > 0) { td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; + *plink = cpu_to_le32(td->dma_handle); uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | uhci_explen(0) | @@ -905,24 +840,9 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb * fast side but not enough to justify delaying an interrupt * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT * flag setting. */ - td->status |= cpu_to_le32(TD_CTRL_IOC); - - qh = uhci_alloc_qh(uhci); - if (!qh) - return -ENOMEM; - - urbp->qh = qh; - qh->urbp = urbp; + td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); - /* Always breadth first */ - uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); - - if (eurb) - uhci_append_queued_urb(uhci, eurb, urb); - else - uhci_insert_qh(uhci, skelqh, urb); - - return -EINPROGRESS; + return 0; } /* @@ -954,8 +874,24 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) if (urb->transfer_flags & URB_SHORT_NOT_OK) { ret = -EREMOTEIO; goto err; - } else - return 0; + } + + /* + * This URB stopped short of its end. We have to + * fix up the toggles of the following URBs on the + * queue and restart the queue. + * + * Do this only the first time we encounter the + * short URB. + */ + if (!urbp->short_transfer) { + urbp->short_transfer = 1; + uhci_fixup_toggles(urb); + td = list_entry(urbp->td_list.prev, + struct uhci_td, list); + urbp->qh->element = td->link; + } + break; } } @@ -988,7 +924,8 @@ err: return ret; } -static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) +static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { int ret; @@ -996,21 +933,22 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struc if (urb->dev->speed == USB_SPEED_LOW) return -EINVAL; - ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh); - if (ret == -EINPROGRESS) + qh->skel = uhci->skel_bulk_qh; + ret = uhci_submit_common(uhci, urb, qh); + if (ret == 0) uhci_inc_fsbr(uhci, urb); - return ret; } -static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) +static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { - /* USB 1.1 interrupt transfers only involve one packet per interval; - * that's the uhci_submit_common() "breadth first" policy. Drivers - * can submit urbs of any length, but longer ones might need many - * intervals to complete. + /* USB 1.1 interrupt transfers only involve one packet per interval. + * Drivers can submit URBs of any length, but longer ones will need + * multiple intervals to complete. */ - return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]); + qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)]; + return uhci_submit_common(uhci, urb, qh); } /* @@ -1072,11 +1010,12 @@ static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb) /* * Isochronous transfers */ -static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) +static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { - struct uhci_td *td; + struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ int i, ret, frame; - int status, destination; + unsigned long destination, status; struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; status = TD_CTRL_ACTIVE | TD_CTRL_IOS; @@ -1092,20 +1031,25 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) return -ENOMEM; uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length), - urb->transfer_dma + urb->iso_frame_desc[i].offset); - - if (i + 1 >= urb->number_of_packets) - td->status |= cpu_to_le32(TD_CTRL_IOC); + uhci_fill_td(td, status, destination | + uhci_explen(urb->iso_frame_desc[i].length), + urb->transfer_dma + + urb->iso_frame_desc[i].offset); } + /* Set the interrupt-on-completion flag on the last packet. */ + td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); + + qh->skel = uhci->skel_iso_qh; + + /* Add the TDs to the frame list */ frame = urb->start_frame; list_for_each_entry(td, &urbp->td_list, list) { - uhci_insert_td_frame_list(uhci, td, frame); + uhci_insert_td_in_frame_list(uhci, td, frame); frame += urb->interval; } - return -EINPROGRESS; + return 0; } static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) @@ -1139,80 +1083,67 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) i++; } - unlink_isochronous_tds(uhci, urb); return ret; } -static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *up; - - /* We don't match Isoc transfers since they are special */ - if (usb_pipeisoc(urb->pipe)) - return NULL; - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - if (u->dev == urb->dev && u->status == -EINPROGRESS) { - /* For control, ignore the direction */ - if (usb_pipecontrol(urb->pipe) && - (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN)) - return u; - else if (u->pipe == urb->pipe) - return u; - } - } - - return NULL; -} - static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *ep, + struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb *eurb; + struct urb_priv *urbp; + struct uhci_qh *qh; int bustime; spin_lock_irqsave(&uhci->lock, flags); ret = urb->status; if (ret != -EINPROGRESS) /* URB already unlinked! */ - goto out; + goto done; - eurb = uhci_find_urb_ep(uhci, urb); + ret = -ENOMEM; + urbp = uhci_alloc_urb_priv(uhci, urb); + if (!urbp) + goto done; - if (!uhci_alloc_urb_priv(uhci, urb)) { - ret = -ENOMEM; - goto out; + if (hep->hcpriv) + qh = (struct uhci_qh *) hep->hcpriv; + else { + qh = uhci_alloc_qh(uhci, urb->dev, hep); + if (!qh) + goto err_no_qh; } + urbp->qh = qh; switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: - ret = uhci_submit_control(uhci, urb, eurb); + ret = uhci_submit_control(uhci, urb, qh); + break; + case PIPE_BULK: + ret = uhci_submit_bulk(uhci, urb, qh); break; case PIPE_INTERRUPT: - if (!eurb) { + if (list_empty(&qh->queue)) { bustime = usb_check_bandwidth(urb->dev, urb); if (bustime < 0) ret = bustime; else { - ret = uhci_submit_interrupt(uhci, urb, eurb); - if (ret == -EINPROGRESS) + ret = uhci_submit_interrupt(uhci, urb, qh); + if (ret == 0) usb_claim_bandwidth(urb->dev, urb, bustime, 0); } } else { /* inherit from parent */ - urb->bandwidth = eurb->bandwidth; - ret = uhci_submit_interrupt(uhci, urb, eurb); + struct urb_priv *eurbp; + + eurbp = list_entry(qh->queue.prev, struct urb_priv, + node); + urb->bandwidth = eurbp->urb->bandwidth; + ret = uhci_submit_interrupt(uhci, urb, qh); } break; - case PIPE_BULK: - ret = uhci_submit_bulk(uhci, urb, eurb); - break; case PIPE_ISOCHRONOUS: bustime = usb_check_bandwidth(urb->dev, urb); if (bustime < 0) { @@ -1220,22 +1151,59 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, break; } - ret = uhci_submit_isochronous(uhci, urb); - if (ret == -EINPROGRESS) + ret = uhci_submit_isochronous(uhci, urb, qh); + if (ret == 0) usb_claim_bandwidth(urb->dev, urb, bustime, 1); break; } + if (ret != 0) + goto err_submit_failed; - if (ret != -EINPROGRESS) { - /* Submit failed, so delete it from the urb_list */ - struct urb_priv *urbp = urb->hcpriv; + /* Add this URB to the QH */ + urbp->qh = qh; + list_add_tail(&urbp->node, &qh->queue); + list_add_tail(&urbp->urb_list, &uhci->urb_list); - list_del_init(&urbp->urb_list); - uhci_destroy_urb_priv(uhci, urb); - } else - ret = 0; + /* If the new URB is the first and only one on this QH then either + * the QH is new and idle or else it's unlinked and waiting to + * become idle, so we can activate it right away. */ + if (qh->queue.next == &urbp->node) + uhci_activate_qh(uhci, qh); + + /* If the QH is already active, we have a race with the hardware. + * This won't get fixed until dummy TDs are added. */ + else if (qh->state == QH_STATE_ACTIVE) { + + /* If the URB isn't first on its queue, adjust the link pointer + * of the last TD in the previous URB. */ + if (urbp->node.prev != &urbp->qh->queue) { + struct urb_priv *purbp = list_entry(urbp->node.prev, + struct urb_priv, node); + struct uhci_td *ptd = list_entry(purbp->td_list.prev, + struct uhci_td, list); + struct uhci_td *td = list_entry(urbp->td_list.next, + struct uhci_td, list); + + ptd->link = cpu_to_le32(td->dma_handle); + + } + if (qh_element(qh) == UHCI_PTR_TERM) { + struct uhci_td *td = list_entry(urbp->td_list.next, + struct uhci_td, list); + + qh->element = cpu_to_le32(td->dma_handle); + } + } + goto done; + +err_submit_failed: + if (qh->state == QH_STATE_IDLE) + uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */ -out: +err_no_qh: + uhci_free_urb_priv(uhci, urbp); + +done: spin_unlock_irqrestore(&uhci->lock, flags); return ret; } @@ -1245,119 +1213,115 @@ out: */ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) { - int ret = -EINPROGRESS; - struct urb_priv *urbp; - - spin_lock(&urb->lock); - - urbp = (struct urb_priv *)urb->hcpriv; - - if (urb->status != -EINPROGRESS) /* URB already dequeued */ - goto out; + int status; + int okay_to_giveback = 0; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: - ret = uhci_result_control(uhci, urb); - break; - case PIPE_BULK: - case PIPE_INTERRUPT: - ret = uhci_result_common(uhci, urb); + status = uhci_result_control(uhci, urb); break; case PIPE_ISOCHRONOUS: - ret = uhci_result_isochronous(uhci, urb); + status = uhci_result_isochronous(uhci, urb); + break; + default: /* PIPE_BULK or PIPE_INTERRUPT */ + status = uhci_result_common(uhci, urb); break; } - if (ret == -EINPROGRESS) - goto out; - urb->status = ret; + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) { /* Not yet dequeued */ + if (status != -EINPROGRESS) { /* URB has completed */ + urb->status = status; + + /* If the URB got a real error (as opposed to + * simply being dequeued), we don't have to + * unlink the QH. Fix this later... */ + if (status < 0) + uhci_unlink_qh(uhci, urbp->qh); + else + okay_to_giveback = 1; + } + } else { /* Already dequeued */ + if (urbp->qh->state == QH_STATE_UNLINKING && + uhci->frame_number + uhci->is_stopped != + urbp->qh->unlink_frame) + okay_to_giveback = 1; + } + spin_unlock(&urb->lock); + if (!okay_to_giveback) + return; switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - case PIPE_BULK: case PIPE_ISOCHRONOUS: /* Release bandwidth for Interrupt or Isoc. transfers */ if (urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 1); - uhci_unlink_generic(uhci, urb); break; case PIPE_INTERRUPT: /* Release bandwidth for Interrupt or Isoc. transfers */ /* Make sure we don't release if we have a queued URB */ - if (list_empty(&urbp->queue_list) && urb->bandwidth) + if (list_empty(&urbp->qh->queue) && urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 0); else /* bandwidth was passed on to queued URB, */ /* so don't let usb_unlink_urb() release it */ urb->bandwidth = 0; - uhci_unlink_generic(uhci, urb); + /* Falls through */ + case PIPE_BULK: + if (status < 0) + uhci_fixup_toggles(urb); + break; + default: /* PIPE_CONTROL */ break; - default: - dev_info(uhci_dev(uhci), "%s: unknown pipe type %d " - "for urb %p\n", - __FUNCTION__, usb_pipetype(urb->pipe), urb); } - /* Move it from uhci->urb_list to uhci->complete_list */ - uhci_moveto_complete(uhci, urbp); + /* Take the URB's TDs off the hardware schedule */ + uhci_remove_tds_from_schedule(uhci, urb, status); -out: - spin_unlock(&urb->lock); -} - -static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb) -{ - struct list_head *head; - struct uhci_td *td; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - int prevactive = 0; + /* Take the URB off the QH's queue and see if the QH is now unused */ + list_del_init(&urbp->node); + if (list_empty(&urbp->qh->queue)) + uhci_unlink_qh(uhci, urbp->qh); uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ - /* - * Now we need to find out what the last successful toggle was - * so we can update the local data toggle for the next transfer - * - * There are 2 ways the last successful completed TD is found: - * - * 1) The TD is NOT active and the actual length < expected length - * 2) The TD is NOT active and it's the last TD in the chain - * - * and a third way the first uncompleted TD is found: - * - * 3) The TD is active and the previous TD is NOT active - * - * Control and Isochronous ignore the toggle, so this is safe - * for all types - * - * FIXME: The toggle fixups won't be 100% reliable until we - * change over to using a single queue for each endpoint and - * stop the queue before unlinking. - */ - head = &urbp->td_list; - list_for_each_entry(td, head, list) { - unsigned int ctrlstat = td_status(td); + /* Queue it for giving back */ + list_move_tail(&urbp->urb_list, &uhci->complete_list); +} - if (!(ctrlstat & TD_CTRL_ACTIVE) && - (uhci_actual_length(ctrlstat) < - uhci_expected_length(td_token(td)) || - td->list.next == head)) - usb_settoggle(urb->dev, uhci_endpoint(td_token(td)), - uhci_packetout(td_token(td)), - uhci_toggle(td_token(td)) ^ 1); - else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive) - usb_settoggle(urb->dev, uhci_endpoint(td_token(td)), - uhci_packetout(td_token(td)), - uhci_toggle(td_token(td))); +/* + * Check out the QHs waiting to be fully unlinked + */ +static void uhci_scan_unlinking_qhs(struct uhci_hcd *uhci) +{ + struct uhci_qh *qh, *tmp; - prevactive = ctrlstat & TD_CTRL_ACTIVE; - } + list_for_each_entry_safe(qh, tmp, &uhci->skel_unlink_qh->node, node) { - uhci_delete_queued_urb(uhci, urb); + /* If the queue is empty and the QH is fully unlinked then + * it can become IDLE. */ + if (list_empty(&qh->queue)) { + if (uhci->frame_number + uhci->is_stopped != + qh->unlink_frame) + uhci_make_qh_idle(uhci, qh); - /* The interrupt loop will reclaim the QHs */ - uhci_remove_qh(uhci, urbp->qh); - urbp->qh = NULL; + /* If none of the QH's URBs have been dequeued then the QH + * should be re-activated. */ + } else { + struct urb_priv *urbp; + int any_dequeued = 0; + + list_for_each_entry(urbp, &qh->queue, node) { + if (urbp->urb->status != -EINPROGRESS) { + any_dequeued = 1; + break; + } + } + if (!any_dequeued) + uhci_activate_qh(uhci, qh); + } + } } static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) @@ -1370,22 +1334,11 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) urbp = urb->hcpriv; if (!urbp) /* URB was never linked! */ goto done; - list_del_init(&urbp->urb_list); + /* Remove Isochronous TDs from the frame list ASAP */ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) - unlink_isochronous_tds(uhci, urb); - uhci_unlink_generic(uhci, urb); - - uhci_get_current_frame_number(uhci); - if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) { - uhci_remove_pending_urbps(uhci); - uhci->urb_remove_age = uhci->frame_number; - } - - /* If we're the first, set the next interrupt bit */ - if (list_empty(&uhci->urb_remove_list)) - uhci_set_next_interrupt(uhci); - list_add_tail(&urbp->urb_list, &uhci->urb_remove_list); + uhci_unlink_isochronous_tds(uhci, urb); + uhci_unlink_qh(uhci, urbp->qh); done: spin_unlock_irqrestore(&uhci->lock, flags); @@ -1426,17 +1379,6 @@ static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb) return 0; } -static void uhci_free_pending_qhs(struct uhci_hcd *uhci) -{ - struct uhci_qh *qh, *tmp; - - list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) { - list_del_init(&qh->remove_list); - - uhci_free_qh(uhci, qh); - } -} - static void uhci_free_pending_tds(struct uhci_hcd *uhci) { struct uhci_td *td, *tmp; @@ -1455,7 +1397,7 @@ __acquires(uhci->lock) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - uhci_destroy_urb_priv(uhci, urb); + uhci_free_urb_priv(uhci, (struct urb_priv *) (urb->hcpriv)); spin_unlock(&uhci->lock); usb_hcd_giveback_urb(hcd, urb, regs); @@ -1474,13 +1416,6 @@ static void uhci_finish_completion(struct uhci_hcd *uhci, struct pt_regs *regs) } } -static void uhci_remove_pending_urbps(struct uhci_hcd *uhci) -{ - - /* Splice the urb_remove_list onto the end of the complete_list */ - list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev); -} - /* Process events in the schedule, but only in one thread at a time */ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) { @@ -1498,12 +1433,8 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) uhci_clear_next_interrupt(uhci); uhci_get_current_frame_number(uhci); - if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) - uhci_free_pending_qhs(uhci); if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) uhci_free_pending_tds(uhci); - if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) - uhci_remove_pending_urbps(uhci); /* Walk the list of pending URBs to see which ones completed * (must be _safe because uhci_transfer_result() dequeues URBs) */ @@ -1516,25 +1447,21 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) uhci_finish_completion(uhci, regs); /* If the controller is stopped, we can finish these off right now */ - if (uhci->is_stopped) { - uhci_free_pending_qhs(uhci); + if (uhci->is_stopped) uhci_free_pending_tds(uhci); - uhci_remove_pending_urbps(uhci); - } if (uhci->need_rescan) goto rescan; uhci->scan_in_progress = 0; - if (list_empty(&uhci->urb_remove_list) && - list_empty(&uhci->td_remove_list) && - list_empty(&uhci->qh_remove_list)) + /* Check out the QHs waiting for unlinking */ + uhci_scan_unlinking_qhs(uhci); + + if (list_empty(&uhci->td_remove_list) && + list_empty(&uhci->skel_unlink_qh->node)) uhci_clear_next_interrupt(uhci); else uhci_set_next_interrupt(uhci); - - /* Wake up anyone waiting for an URB to complete */ - wake_up_all(&uhci->waitqh); } static void check_fsbr(struct uhci_hcd *uhci) -- cgit v1.2.2 From af0bb5998abe8ed28ee354dd4c71689cacdc91e9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 17 Dec 2005 18:00:12 -0500 Subject: [PATCH] UHCI: use dummy TDs This patch (as624) fixes a hardware race in uhci-hcd by adding a dummy TD to the end of each endpoint's queue. Without the dummy the host controller will effectively turn off the queue when it reaches the end, which happens asynchronously. This leads to a potential problem when new transfer descriptors are added to the end of the queue; they may never get used. With a dummy TD present the controller never turns off the queue; instead it just stops at the dummy and leaves the queue on but inactive. When new TDs are added to the end of the queue, the first new one gets written over the dummy. Thus there's never any question about whether the queue is running or needs to be restarted. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 5 ++ drivers/usb/host/uhci-hcd.h | 1 + drivers/usb/host/uhci-q.c | 138 +++++++++++++++++++++++------------------- 3 files changed, 83 insertions(+), 61 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 3faccbd68547..6814783adf91 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -189,6 +189,11 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) space, "", nurbs); } + if (qh->udev) { + out += sprintf(out, "%*s Dummy TD\n", space, ""); + out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0); + } + return out - buf; } diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 7a9481c09a05..c057956667b5 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -128,6 +128,7 @@ struct uhci_qh { struct usb_device *udev; struct list_head queue; /* Queue of urbps for this QH */ struct uhci_qh *skel; /* Skeleton for this QH */ + struct uhci_td *dummy_td; /* Dummy TD to end the queue */ unsigned int unlink_frame; /* When the QH was unlinked */ int state; /* QH_STATE_xxx; see above */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index b1b551a3d14e..c4194182dcc4 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -48,10 +48,6 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) return NULL; td->dma_handle = dma_handle; - - td->link = UHCI_PTR_TERM; - td->buffer = 0; - td->frame = -1; INIT_LIST_HEAD(&td->list); @@ -221,6 +217,11 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, INIT_LIST_HEAD(&qh->node); if (udev) { /* Normal QH */ + qh->dummy_td = uhci_alloc_td(uhci); + if (!qh->dummy_td) { + dma_pool_free(uhci->qh_pool, qh, dma_handle); + return NULL; + } qh->state = QH_STATE_IDLE; qh->hep = hep; qh->udev = udev; @@ -244,6 +245,7 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) if (qh->udev) { qh->hep->hcpriv = NULL; usb_put_dev(qh->udev); + uhci_free_td(uhci, qh->dummy_td); } dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); } @@ -531,22 +533,20 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; - /* 3 errors */ - status = TD_CTRL_ACTIVE | uhci_maxerr(3); + /* 3 errors, dummy TD remains inactive */ + status = uhci_maxerr(3); if (urb->dev->speed == USB_SPEED_LOW) status |= TD_CTRL_LS; /* * Build the TD for the control request setup packet */ - td = uhci_alloc_td(uhci); - if (!td) - return -ENOMEM; - + td = qh->dummy_td; uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | uhci_explen(8), urb->setup_dma); plink = &td->link; + status |= TD_CTRL_ACTIVE; /* * If direction is "send", change the packet ID from SETUP (0x2D) @@ -568,7 +568,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, td = uhci_alloc_td(uhci); if (!td) - return -ENOMEM; + goto nomem; *plink = cpu_to_le32(td->dma_handle); /* Alternate Data0/1 (start with Data1) */ @@ -588,7 +588,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, */ td = uhci_alloc_td(uhci); if (!td) - return -ENOMEM; + goto nomem; *plink = cpu_to_le32(td->dma_handle); /* @@ -608,6 +608,20 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status | TD_CTRL_IOC, destination | uhci_explen(0), 0); + plink = &td->link; + + /* + * Build the new dummy TD and activate the old one + */ + td = uhci_alloc_td(uhci); + if (!td) + goto nomem; + *plink = cpu_to_le32(td->dma_handle); + + uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0); + wmb(); + qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE); + qh->dummy_td = td; /* Low-speed transfers get a different queue, and won't hog the bus. * Also, some devices enumerate better without FSBR; the easiest way @@ -620,8 +634,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, qh->skel = uhci->skel_fs_control_qh; uhci_inc_fsbr(uhci, urb); } - return 0; + +nomem: + /* Remove the dummy TD from the td_list so it doesn't get freed */ + uhci_remove_td_from_urb(qh->dummy_td); + return -ENOMEM; } /* @@ -761,16 +779,19 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); int len = urb->transfer_buffer_length; dma_addr_t data = urb->transfer_dma; - __le32 *plink, fake_link; + __le32 *plink; + unsigned int toggle; if (len < 0) return -EINVAL; /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); + toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe)); - /* 3 errors */ - status = TD_CTRL_ACTIVE | uhci_maxerr(3); + /* 3 errors, dummy TD remains inactive */ + status = uhci_maxerr(3); if (urb->dev->speed == USB_SPEED_LOW) status |= TD_CTRL_LS; if (usb_pipein(urb->pipe)) @@ -779,7 +800,8 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, /* * Build the DATA TDs */ - plink = &fake_link; + plink = NULL; + td = qh->dummy_td; do { /* Allow zero length packets */ int pktsze = maxsze; @@ -789,24 +811,23 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, status &= ~TD_CTRL_SPD; } - td = uhci_alloc_td(uhci); - if (!td) - return -ENOMEM; - *plink = cpu_to_le32(td->dma_handle); - + if (plink) { + td = uhci_alloc_td(uhci); + if (!td) + goto nomem; + *plink = cpu_to_le32(td->dma_handle); + } uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, - destination | uhci_explen(pktsze) | - (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT), - data); + destination | uhci_explen(pktsze) | + (toggle << TD_TOKEN_TOGGLE_SHIFT), + data); plink = &td->link; + status |= TD_CTRL_ACTIVE; data += pktsze; len -= maxsze; - - usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); + toggle ^= 1; } while (len > 0); /* @@ -821,17 +842,17 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, urb->transfer_buffer_length > 0) { td = uhci_alloc_td(uhci); if (!td) - return -ENOMEM; + goto nomem; *plink = cpu_to_le32(td->dma_handle); uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(0) | - (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT), - data); + uhci_fill_td(td, status, + destination | uhci_explen(0) | + (toggle << TD_TOKEN_TOGGLE_SHIFT), + data); + plink = &td->link; - usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); + toggle ^= 1; } /* Set the interrupt-on-completion flag on the last packet. @@ -842,7 +863,27 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, * flag setting. */ td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); + /* + * Build the new dummy TD and activate the old one + */ + td = uhci_alloc_td(uhci); + if (!td) + goto nomem; + *plink = cpu_to_le32(td->dma_handle); + + uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0); + wmb(); + qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE); + qh->dummy_td = td; + + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), toggle); return 0; + +nomem: + /* Remove the dummy TD from the td_list so it doesn't get freed */ + uhci_remove_td_from_urb(qh->dummy_td); + return -ENOMEM; } /* @@ -1169,31 +1210,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, * become idle, so we can activate it right away. */ if (qh->queue.next == &urbp->node) uhci_activate_qh(uhci, qh); - - /* If the QH is already active, we have a race with the hardware. - * This won't get fixed until dummy TDs are added. */ - else if (qh->state == QH_STATE_ACTIVE) { - - /* If the URB isn't first on its queue, adjust the link pointer - * of the last TD in the previous URB. */ - if (urbp->node.prev != &urbp->qh->queue) { - struct urb_priv *purbp = list_entry(urbp->node.prev, - struct urb_priv, node); - struct uhci_td *ptd = list_entry(purbp->td_list.prev, - struct uhci_td, list); - struct uhci_td *td = list_entry(urbp->td_list.next, - struct uhci_td, list); - - ptd->link = cpu_to_le32(td->dma_handle); - - } - if (qh_element(qh) == UHCI_PTR_TERM) { - struct uhci_td *td = list_entry(urbp->td_list.next, - struct uhci_td, list); - - qh->element = cpu_to_le32(td->dma_handle); - } - } goto done; err_submit_failed: -- cgit v1.2.2 From 0ed8fee1c1d38a62e981025ba40b5eba30c4ce2a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 17 Dec 2005 18:02:38 -0500 Subject: [PATCH] UHCI: remove main list of URBs As part of reorienting uhci-hcd away from URBs and toward endpoint queues, this patch (as625) eliminates the driver's main list of URBs. The list wsa used mainly in checking for URB completions; now the driver goes through the list of active endpoints and checks the members of the queues. As a side effect, I had to remove the code that looks for FSBR timeouts. For now, FSBR will remain on so long as any URBs on a full-speed control or bulk queue request it, even if the queue isn't advancing. A later patch can add more intelligent handling. This isn't a huge drawback; it's pretty rare for an URB to get stuck for more than a fraction of a second. (And it will help the people trying to use those insane HP USB devices.) Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 1 - drivers/usb/host/uhci-hcd.c | 2 - drivers/usb/host/uhci-hcd.h | 15 +- drivers/usb/host/uhci-q.c | 631 ++++++++++++++++++------------------------ 4 files changed, 279 insertions(+), 370 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 6814783adf91..f2f5f8ce1715 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -114,7 +114,6 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) } out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : "")); - out += sprintf(out, "%s", (urbp->fsbr_timeout ? " FSBR_TO" : "")); if (urbp->urb->status != -EINPROGRESS) out += sprintf(out, " Status=%d", urbp->urb->status); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 1ff4b8806372..9865f303d3fc 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -491,8 +491,6 @@ static int uhci_start(struct usb_hcd *hcd) spin_lock_init(&uhci->lock); INIT_LIST_HEAD(&uhci->td_remove_list); - INIT_LIST_HEAD(&uhci->urb_list); - INIT_LIST_HEAD(&uhci->complete_list); INIT_LIST_HEAD(&uhci->idle_qh_list); init_waitqueue_head(&uhci->waitqh); diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index c057956667b5..7e96bef2e88f 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -132,6 +132,10 @@ struct uhci_qh { unsigned int unlink_frame; /* When the QH was unlinked */ int state; /* QH_STATE_xxx; see above */ + + unsigned int initial_toggle:1; /* Endpoint's current toggle value */ + unsigned int needs_fixup:1; /* Must fix the TD toggle values */ + unsigned int is_stopped:1; /* Queue was stopped by an error */ } __attribute__((aligned(16))); /* @@ -384,6 +388,7 @@ struct uhci_hcd { struct uhci_td *term_td; /* Terminating TD, see UHCI bug */ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QHs */ + struct uhci_qh *next_qh; /* Next QH to scan */ spinlock_t lock; @@ -413,16 +418,10 @@ struct uhci_hcd { unsigned long resuming_ports; unsigned long ports_timeout; /* Time to stop signalling */ - /* Main list of URBs currently controlled by this HC */ - struct list_head urb_list; - /* List of TDs that are done, but waiting to be freed (race) */ struct list_head td_remove_list; unsigned int td_remove_age; /* Age in frames */ - /* List of URBs awaiting completion callback */ - struct list_head complete_list; - struct list_head idle_qh_list; /* Where the idle QHs live */ int rh_numports; /* Number of root-hub ports */ @@ -448,7 +447,6 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci) * Private per-URB data */ struct urb_priv { - struct list_head urb_list; struct list_head node; /* Node in the QH's urbp list */ struct urb *urb; @@ -456,10 +454,7 @@ struct urb_priv { struct uhci_qh *qh; /* QH for this URB */ struct list_head td_list; - unsigned long fsbrtime; /* In jiffies */ - unsigned fsbr : 1; /* URB turned on FSBR */ - unsigned fsbr_timeout : 1; /* URB timed out on FSBR */ unsigned short_transfer : 1; /* URB got a short transfer, no * need to rescan */ }; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index c4194182dcc4..44bba9a6d196 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -151,53 +151,6 @@ static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) wmb(); } -/* - * Remove an URB's TDs from the hardware schedule - */ -static void uhci_remove_tds_from_schedule(struct uhci_hcd *uhci, - struct urb *urb, int status) -{ - struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - - /* Isochronous TDs get unlinked directly from the frame list */ - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - uhci_unlink_isochronous_tds(uhci, urb); - return; - } - - /* If the URB isn't first on its queue, adjust the link pointer - * of the last TD in the previous URB. */ - if (urbp->node.prev != &urbp->qh->queue) { - struct urb_priv *purbp; - struct uhci_td *ptd, *ltd; - - if (status == -EINPROGRESS) - status = 0; - purbp = list_entry(urbp->node.prev, struct urb_priv, node); - ptd = list_entry(purbp->td_list.prev, struct uhci_td, - list); - ltd = list_entry(urbp->td_list.prev, struct uhci_td, - list); - ptd->link = ltd->link; - } - - /* If the URB completed with an error, then the QH element certainly - * points to one of the URB's TDs. If it completed normally then - * the QH element has certainly moved on to the next URB. And if - * the URB is still in progress then it must have been dequeued. - * The QH element either hasn't reached it yet or is somewhere in - * the middle. If the URB wasn't first we can assume that it - * hasn't started yet (see above): Otherwise all the preceding URBs - * would have completed and been removed from the queue, so this one - * _would_ be first. - * - * If the QH element is inside this URB, clear it. It will be - * set properly when the QH is activated. - */ - if (status < 0) - urbp->qh->element = UHCI_PTR_TERM; -} - static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *udev, struct usb_host_endpoint *hep) { @@ -250,6 +203,90 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); } +/* + * When the currently executing URB is dequeued, save its current toggle value + */ +static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb) +{ + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; + struct uhci_td *td; + + /* If the QH element pointer is UHCI_PTR_TERM then then currently + * executing URB has already been unlinked, so this one isn't it. */ + if (qh_element(qh) == UHCI_PTR_TERM || + qh->queue.next != &urbp->node) + return; + qh->element = UHCI_PTR_TERM; + + /* Only bulk and interrupt pipes have to worry about toggles */ + if (!(usb_pipetype(urb->pipe) == PIPE_BULK || + usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) + return; + + /* Find the first active TD; that's the device's toggle state */ + list_for_each_entry(td, &urbp->td_list, list) { + if (td_status(td) & TD_CTRL_ACTIVE) { + qh->needs_fixup = 1; + qh->initial_toggle = uhci_toggle(td_token(td)); + return; + } + } + + WARN_ON(1); +} + +/* + * Fix up the data toggles for URBs in a queue, when one of them + * terminates early (short transfer, error, or dequeued). + */ +static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first) +{ + struct urb_priv *urbp = NULL; + struct uhci_td *td; + unsigned int toggle = qh->initial_toggle; + unsigned int pipe; + + /* Fixups for a short transfer start with the second URB in the + * queue (the short URB is the first). */ + if (skip_first) + urbp = list_entry(qh->queue.next, struct urb_priv, node); + + /* When starting with the first URB, if the QH element pointer is + * still valid then we know the URB's toggles are okay. */ + else if (qh_element(qh) != UHCI_PTR_TERM) + toggle = 2; + + /* Fix up the toggle for the URBs in the queue. Normally this + * loop won't run more than once: When an error or short transfer + * occurs, the queue usually gets emptied. */ + list_prepare_entry(urbp, &qh->queue, node); + list_for_each_entry_continue(urbp, &qh->queue, node) { + + /* If the first TD has the right toggle value, we don't + * need to change any toggles in this URB */ + td = list_entry(urbp->td_list.next, struct uhci_td, list); + if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) { + td = list_entry(urbp->td_list.next, struct uhci_td, + list); + toggle = uhci_toggle(td_token(td)) ^ 1; + + /* Otherwise all the toggles in the URB have to be switched */ + } else { + list_for_each_entry(td, &urbp->td_list, list) { + td->token ^= __constant_cpu_to_le32( + TD_TOKEN_TOGGLE); + toggle ^= 1; + } + } + } + + wmb(); + pipe = list_entry(qh->queue.next, struct urb_priv, node)->urb->pipe; + usb_settoggle(qh->udev, usb_pipeendpoint(pipe), + usb_pipeout(pipe), toggle); + qh->needs_fixup = 0; +} + /* * Put a QH on the schedule in both hardware and software */ @@ -276,6 +313,9 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) /* Move the QH from its old list to the end of the appropriate * skeleton's list */ + if (qh == uhci->next_qh) + uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, + node); list_move_tail(&qh->node, &qh->skel->node); /* Link it into the schedule */ @@ -310,6 +350,9 @@ static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) uhci_set_next_interrupt(uhci); /* Move the QH from its old list to the end of the unlinking list */ + if (qh == uhci->next_qh) + uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, + node); list_move_tail(&qh->node, &uhci->skel_unlink_qh->node); } @@ -323,6 +366,9 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh) { WARN_ON(qh->state == QH_STATE_ACTIVE); + if (qh == uhci->next_qh) + uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, + node); list_move(&qh->node, &uhci->idle_qh_list); qh->state = QH_STATE_IDLE; @@ -344,11 +390,9 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, urbp->urb = urb; urb->hcpriv = urbp; - urbp->fsbrtime = jiffies; INIT_LIST_HEAD(&urbp->node); INIT_LIST_HEAD(&urbp->td_list); - INIT_LIST_HEAD(&urbp->urb_list); return urbp; } @@ -373,9 +417,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, { struct uhci_td *td, *tmp; - if (!list_empty(&urbp->urb_list)) - dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list!\n", - urbp->urb); if (!list_empty(&urbp->node)) dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n", urbp->urb); @@ -452,71 +493,6 @@ static int uhci_map_status(int status, int dir_out) return 0; } -/* - * Fix up the data toggles for URBs in a queue, when one of them - * terminates early (short transfer, error, or dequeued). - */ -static void uhci_fixup_toggles(struct urb *urb) -{ - struct list_head *head; - struct uhci_td *td; - struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - int prevactive = 0; - unsigned int toggle = 0; - struct urb_priv *turbp, *list_end; - - /* - * We need to find out what the last successful toggle was so - * we can update the data toggles for the following transfers. - * - * There are 2 ways the last successful completed TD is found: - * - * 1) The TD is NOT active and the actual length < expected length - * 2) The TD is NOT active and it's the last TD in the chain - * - * and a third way the first uncompleted TD is found: - * - * 3) The TD is active and the previous TD is NOT active - */ - head = &urbp->td_list; - list_for_each_entry(td, head, list) { - unsigned int ctrlstat = td_status(td); - - if (!(ctrlstat & TD_CTRL_ACTIVE) && - (uhci_actual_length(ctrlstat) < - uhci_expected_length(td_token(td)) || - td->list.next == head)) - toggle = uhci_toggle(td_token(td)) ^ 1; - else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive) - toggle = uhci_toggle(td_token(td)); - - prevactive = ctrlstat & TD_CTRL_ACTIVE; - } - - /* - * Fix up the toggle for the following URBs in the queue. - * - * We can stop as soon as we find an URB with toggles set correctly, - * because then all the following URBs will be correct also. - */ - list_end = list_entry(&urbp->qh->queue, struct urb_priv, node); - turbp = urbp; - while ((turbp = list_entry(turbp->node.next, struct urb_priv, node)) - != list_end) { - td = list_entry(turbp->td_list.next, struct uhci_td, list); - if (uhci_toggle(td_token(td)) == toggle) - return; - - list_for_each_entry(td, &turbp->td_list, list) { - td->token ^= __constant_cpu_to_le32(TD_TOKEN_TOGGLE); - toggle ^= 1; - } - } - - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), toggle); -} - /* * Control transfers */ @@ -765,6 +741,9 @@ err: } } + /* Note that the queue has stopped */ + urbp->qh->element = UHCI_PTR_TERM; + urbp->qh->is_stopped = 1; return ret; } @@ -927,7 +906,10 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) */ if (!urbp->short_transfer) { urbp->short_transfer = 1; - uhci_fixup_toggles(urb); + urbp->qh->initial_toggle = + uhci_toggle(td_token(td)) ^ 1; + uhci_fixup_toggles(urbp->qh, 1); + td = list_entry(urbp->td_list.prev, struct uhci_td, list); urbp->qh->element = td->link; @@ -962,6 +944,13 @@ err: } } #endif + + /* Note that the queue has stopped and save the next toggle value */ + urbp->qh->element = UHCI_PTR_TERM; + urbp->qh->is_stopped = 1; + urbp->qh->needs_fixup = 1; + urbp->qh->initial_toggle = uhci_toggle(td_token(td)) ^ + (ret == -EREMOTEIO); return ret; } @@ -995,76 +984,39 @@ static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, /* * Isochronous transfers */ -static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end) -{ - struct urb *last_urb = NULL; - struct urb_priv *up; - int ret = 0; - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - /* look for pending URBs with identical pipe handle */ - if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && - (u->status == -EINPROGRESS) && (u != urb)) { - if (!last_urb) - *start = u->start_frame; - last_urb = u; - } - } - - if (last_urb) { - *end = (last_urb->start_frame + last_urb->number_of_packets * - last_urb->interval) & (UHCI_NUMFRAMES-1); - ret = 0; - } else - ret = -1; /* no previous urb found */ - - return ret; -} - -static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb) +static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { - int limits; - unsigned int start = 0, end = 0; + struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ + int i, frame; + unsigned long destination, status; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; if (urb->number_of_packets > 900) /* 900? Why? */ return -EFBIG; - limits = isochronous_find_limits(uhci, urb, &start, &end); + status = TD_CTRL_ACTIVE | TD_CTRL_IOS; + destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); + /* Figure out the starting frame number */ if (urb->transfer_flags & URB_ISO_ASAP) { - if (limits) { + if (list_empty(&qh->queue)) { uhci_get_current_frame_number(uhci); - urb->start_frame = (uhci->frame_number + 10) - & (UHCI_NUMFRAMES - 1); - } else - urb->start_frame = end; + urb->start_frame = (uhci->frame_number + 10); + + } else { /* Go right after the last one */ + struct urb *last_urb; + + last_urb = list_entry(qh->queue.prev, + struct urb_priv, node)->urb; + urb->start_frame = (last_urb->start_frame + + last_urb->number_of_packets * + last_urb->interval); + } } else { - urb->start_frame &= (UHCI_NUMFRAMES - 1); /* FIXME: Sanity check */ } - - return 0; -} - -/* - * Isochronous transfers - */ -static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, - struct uhci_qh *qh) -{ - struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ - int i, ret, frame; - unsigned long destination, status; - struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - - status = TD_CTRL_ACTIVE | TD_CTRL_IOS; - destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - - ret = isochronous_find_start(uhci, urb); - if (ret) - return ret; + urb->start_frame &= (UHCI_NUMFRAMES - 1); for (i = 0; i < urb->number_of_packets; i++) { td = uhci_alloc_td(uhci); @@ -1203,7 +1155,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, /* Add this URB to the QH */ urbp->qh = qh; list_add_tail(&urbp->node, &qh->queue); - list_add_tail(&urbp->urb_list, &uhci->urb_list); /* If the new URB is the first and only one on this QH then either * the QH is new and idle or else it's unlinked and waiting to @@ -1224,49 +1175,66 @@ done: return ret; } +static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + unsigned long flags; + struct urb_priv *urbp; + + spin_lock_irqsave(&uhci->lock, flags); + urbp = urb->hcpriv; + if (!urbp) /* URB was never linked! */ + goto done; + + /* Remove Isochronous TDs from the frame list ASAP */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + uhci_unlink_isochronous_tds(uhci, urb); + uhci_unlink_qh(uhci, urbp->qh); + +done: + spin_unlock_irqrestore(&uhci->lock, flags); + return 0; +} + /* - * Return the result of a transfer + * Finish unlinking an URB and give it back */ -static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) +static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, + struct urb *urb, struct pt_regs *regs) +__releases(uhci->lock) +__acquires(uhci->lock) { - int status; - int okay_to_giveback = 0; struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - status = uhci_result_control(uhci, urb); - break; - case PIPE_ISOCHRONOUS: - status = uhci_result_isochronous(uhci, urb); - break; - default: /* PIPE_BULK or PIPE_INTERRUPT */ - status = uhci_result_common(uhci, urb); - break; - } + /* Isochronous TDs get unlinked directly from the frame list */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + uhci_unlink_isochronous_tds(uhci, urb); - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) { /* Not yet dequeued */ - if (status != -EINPROGRESS) { /* URB has completed */ - urb->status = status; + /* If the URB isn't first on its queue, adjust the link pointer + * of the last TD in the previous URB. */ + else if (qh->queue.next != &urbp->node) { + struct urb_priv *purbp; + struct uhci_td *ptd, *ltd; - /* If the URB got a real error (as opposed to - * simply being dequeued), we don't have to - * unlink the QH. Fix this later... */ - if (status < 0) - uhci_unlink_qh(uhci, urbp->qh); - else - okay_to_giveback = 1; - } - } else { /* Already dequeued */ - if (urbp->qh->state == QH_STATE_UNLINKING && - uhci->frame_number + uhci->is_stopped != - urbp->qh->unlink_frame) - okay_to_giveback = 1; + purbp = list_entry(urbp->node.prev, struct urb_priv, node); + ptd = list_entry(purbp->td_list.prev, struct uhci_td, + list); + ltd = list_entry(urbp->td_list.prev, struct uhci_td, + list); + ptd->link = ltd->link; } - spin_unlock(&urb->lock); - if (!okay_to_giveback) - return; + + /* Take the URB off the QH's queue. If the queue is now empty, + * this is a perfect time for a toggle fixup. */ + list_del_init(&urbp->node); + if (list_empty(&qh->queue) && qh->needs_fixup) { + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), qh->initial_toggle); + qh->needs_fixup = 0; + } + + uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ + uhci_free_urb_priv(uhci, urbp); switch (usb_pipetype(urb->pipe)) { case PIPE_ISOCHRONOUS: @@ -1277,122 +1245,107 @@ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) case PIPE_INTERRUPT: /* Release bandwidth for Interrupt or Isoc. transfers */ /* Make sure we don't release if we have a queued URB */ - if (list_empty(&urbp->qh->queue) && urb->bandwidth) + if (list_empty(&qh->queue) && urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 0); else /* bandwidth was passed on to queued URB, */ /* so don't let usb_unlink_urb() release it */ urb->bandwidth = 0; - /* Falls through */ - case PIPE_BULK: - if (status < 0) - uhci_fixup_toggles(urb); - break; - default: /* PIPE_CONTROL */ break; } - /* Take the URB's TDs off the hardware schedule */ - uhci_remove_tds_from_schedule(uhci, urb, status); - - /* Take the URB off the QH's queue and see if the QH is now unused */ - list_del_init(&urbp->node); - if (list_empty(&urbp->qh->queue)) - uhci_unlink_qh(uhci, urbp->qh); + spin_unlock(&uhci->lock); + usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, regs); + spin_lock(&uhci->lock); - uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ + /* If the queue is now empty, we can unlink the QH and give up its + * reserved bandwidth. */ + if (list_empty(&qh->queue)) { + uhci_unlink_qh(uhci, qh); - /* Queue it for giving back */ - list_move_tail(&urbp->urb_list, &uhci->complete_list); + /* Bandwidth stuff not yet implemented */ + } } /* - * Check out the QHs waiting to be fully unlinked + * Scan the URBs in a QH's queue */ -static void uhci_scan_unlinking_qhs(struct uhci_hcd *uhci) -{ - struct uhci_qh *qh, *tmp; +#define QH_FINISHED_UNLINKING(qh) \ + (qh->state == QH_STATE_UNLINKING && \ + uhci->frame_number + uhci->is_stopped != qh->unlink_frame) - list_for_each_entry_safe(qh, tmp, &uhci->skel_unlink_qh->node, node) { - - /* If the queue is empty and the QH is fully unlinked then - * it can become IDLE. */ - if (list_empty(&qh->queue)) { - if (uhci->frame_number + uhci->is_stopped != - qh->unlink_frame) - uhci_make_qh_idle(uhci, qh); - - /* If none of the QH's URBs have been dequeued then the QH - * should be re-activated. */ - } else { - struct urb_priv *urbp; - int any_dequeued = 0; - - list_for_each_entry(urbp, &qh->queue, node) { - if (urbp->urb->status != -EINPROGRESS) { - any_dequeued = 1; - break; - } - } - if (!any_dequeued) - uhci_activate_qh(uhci, qh); - } - } -} - -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, + struct pt_regs *regs) { - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long flags; struct urb_priv *urbp; + struct urb *urb; + int status; - spin_lock_irqsave(&uhci->lock, flags); - urbp = urb->hcpriv; - if (!urbp) /* URB was never linked! */ - goto done; + while (!list_empty(&qh->queue)) { + urbp = list_entry(qh->queue.next, struct urb_priv, node); + urb = urbp->urb; - /* Remove Isochronous TDs from the frame list ASAP */ - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) - uhci_unlink_isochronous_tds(uhci, urb); - uhci_unlink_qh(uhci, urbp->qh); + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + status = uhci_result_control(uhci, urb); + break; + case PIPE_ISOCHRONOUS: + status = uhci_result_isochronous(uhci, urb); + break; + default: /* PIPE_BULK or PIPE_INTERRUPT */ + status = uhci_result_common(uhci, urb); + break; + } + if (status == -EINPROGRESS) + break; -done: - spin_unlock_irqrestore(&uhci->lock, flags); - return 0; -} + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) /* Not dequeued */ + urb->status = status; + else + status = -ECONNRESET; + spin_unlock(&urb->lock); -static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *head; - struct uhci_td *td; - int count = 0; + /* Dequeued but completed URBs can't be given back unless + * the QH is stopped or has finished unlinking. */ + if (status == -ECONNRESET && + !(qh->is_stopped || QH_FINISHED_UNLINKING(qh))) + return; - uhci_dec_fsbr(uhci, urb); + uhci_giveback_urb(uhci, qh, urb, regs); + if (qh->is_stopped) + break; + } - urbp->fsbr_timeout = 1; + /* If the QH is neither stopped nor finished unlinking (normal case), + * our work here is done. */ + restart: + if (!(qh->is_stopped || QH_FINISHED_UNLINKING(qh))) + return; - /* - * Ideally we would want to fix qh->element as well, but it's - * read/write by the HC, so that can introduce a race. It's not - * really worth the hassle - */ + /* Otherwise give back each of the dequeued URBs */ + list_for_each_entry(urbp, &qh->queue, node) { + urb = urbp->urb; + if (urb->status != -EINPROGRESS) { + uhci_save_toggle(qh, urb); + uhci_giveback_urb(uhci, qh, urb, regs); + goto restart; + } + } + qh->is_stopped = 0; - head = &urbp->td_list; - list_for_each_entry(td, head, list) { - /* - * Make sure we don't do the last one (since it'll have the - * TERM bit set) as well as we skip every so many TDs to - * make sure it doesn't hog the bandwidth - */ - if (td->list.next != head && (count % DEPTH_INTERVAL) == - (DEPTH_INTERVAL - 1)) - td->link |= UHCI_PTR_DEPTH; - - count++; + /* There are no more dequeued URBs. If there are still URBs on the + * queue, the QH can now be re-activated. */ + if (!list_empty(&qh->queue)) { + if (qh->needs_fixup) + uhci_fixup_toggles(qh, 0); + uhci_activate_qh(uhci, qh); } - return 0; + /* The queue is empty. The QH can become idle if it is fully + * unlinked. */ + else if (QH_FINISHED_UNLINKING(qh)) + uhci_make_qh_idle(uhci, qh); } static void uhci_free_pending_tds(struct uhci_hcd *uhci) @@ -1406,36 +1359,13 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci) } } -static void -uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) -__releases(uhci->lock) -__acquires(uhci->lock) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - - uhci_free_urb_priv(uhci, (struct urb_priv *) (urb->hcpriv)); - - spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(hcd, urb, regs); - spin_lock(&uhci->lock); -} - -static void uhci_finish_completion(struct uhci_hcd *uhci, struct pt_regs *regs) -{ - struct urb_priv *urbp, *tmp; - - list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) { - struct urb *urb = urbp->urb; - - list_del_init(&urbp->urb_list); - uhci_finish_urb(uhci_to_hcd(uhci), urb, regs); - } -} - -/* Process events in the schedule, but only in one thread at a time */ +/* + * Process events in the schedule, but only in one thread at a time + */ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) { - struct urb_priv *urbp, *tmp; + int i; + struct uhci_qh *qh; /* Don't allow re-entrant calls */ if (uhci->scan_in_progress) { @@ -1452,26 +1382,24 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) uhci_free_pending_tds(uhci); - /* Walk the list of pending URBs to see which ones completed - * (must be _safe because uhci_transfer_result() dequeues URBs) */ - list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) { - struct urb *urb = urbp->urb; - - /* Checks the status and does all of the magic necessary */ - uhci_transfer_result(uhci, urb); + /* Go through all the QH queues and process the URBs in each one */ + for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { + uhci->next_qh = list_entry(uhci->skelqh[i]->node.next, + struct uhci_qh, node); + while ((qh = uhci->next_qh) != uhci->skelqh[i]) { + uhci->next_qh = list_entry(qh->node.next, + struct uhci_qh, node); + uhci_scan_qh(uhci, qh, regs); + } } - uhci_finish_completion(uhci, regs); - - /* If the controller is stopped, we can finish these off right now */ - if (uhci->is_stopped) - uhci_free_pending_tds(uhci); if (uhci->need_rescan) goto rescan; uhci->scan_in_progress = 0; - /* Check out the QHs waiting for unlinking */ - uhci_scan_unlinking_qhs(uhci); + /* If the controller is stopped, we can finish these off right now */ + if (uhci->is_stopped) + uhci_free_pending_tds(uhci); if (list_empty(&uhci->td_remove_list) && list_empty(&uhci->skel_unlink_qh->node)) @@ -1482,19 +1410,8 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) static void check_fsbr(struct uhci_hcd *uhci) { - struct urb_priv *up; - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - spin_lock(&u->lock); - - /* Check if the FSBR timed out */ - if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) - uhci_fsbr_timeout(uhci, u); - - spin_unlock(&u->lock); - } + /* For now, don't scan URBs for FSBR timeouts. + * Add it back in later... */ /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { -- cgit v1.2.2 From 8d402e1ae03656c1ad215514f8885ef4793f0948 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 17 Dec 2005 18:03:37 -0500 Subject: [PATCH] UHCI: improve debugging code This patch (as626) makes some improvements to the debugging code in uhci-hcd. The main change is that now the code won't get compiled if CONFIG_USB_DEBUG isn't set. But there are other changes too, like adding a missing .owner field and printing a debugging dump if the controller dies. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 36 +++++++++++++++++++++----- drivers/usb/host/uhci-hcd.c | 60 ++++++++++++++++++++++++++++--------------- drivers/usb/host/uhci-hcd.h | 1 + drivers/usb/host/uhci-q.c | 12 +-------- 4 files changed, 70 insertions(+), 39 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index f2f5f8ce1715..e1239319655c 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -17,10 +17,13 @@ #include "uhci-hcd.h" -static struct dentry *uhci_debugfs_root = NULL; +#define uhci_debug_operations (* (struct file_operations *) NULL) +static struct dentry *uhci_debugfs_root; + +#ifdef DEBUG /* Handle REALLY large printks so we don't overflow buffers */ -static inline void lprintk(char *buf) +static void lprintk(char *buf) { char *p; @@ -196,7 +199,6 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) return out - buf; } -#ifdef CONFIG_PROC_FS static const char * const qh_names[] = { "skel_unlink_qh", "skel_iso_qh", "skel_int128_qh", "skel_int64_qh", @@ -393,12 +395,13 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) return out - buf; } +#ifdef CONFIG_DEBUG_FS + #define MAX_OUTPUT (64 * 1024) struct uhci_debug { int size; char *data; - struct uhci_hcd *uhci; }; static int uhci_debug_open(struct inode *inode, struct file *file) @@ -419,8 +422,10 @@ static int uhci_debug_open(struct inode *inode, struct file *file) goto out; } + up->size = 0; spin_lock_irqsave(&uhci->lock, flags); - up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); + if (uhci->is_initialized) + up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); spin_unlock_irqrestore(&uhci->lock, flags); file->private_data = up; @@ -472,15 +477,32 @@ static int uhci_debug_release(struct inode *inode, struct file *file) return 0; } +#undef uhci_debug_operations static struct file_operations uhci_debug_operations = { + .owner = THIS_MODULE, .open = uhci_debug_open, .llseek = uhci_debug_lseek, .read = uhci_debug_read, .release = uhci_debug_release, }; -#else /* CONFIG_DEBUG_FS */ +#endif /* CONFIG_DEBUG_FS */ -#define uhci_debug_operations (* (struct file_operations *) NULL) +#else /* DEBUG */ + +static inline void lprintk(char *buf) +{} + +static inline int uhci_show_qh(struct uhci_qh *qh, char *buf, + int len, int space) +{ + return 0; +} + +static inline int uhci_sprint_schedule(struct uhci_hcd *uhci, + char *buf, int len) +{ + return 0; +} #endif diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 9865f303d3fc..4edb8330c440 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -68,12 +68,16 @@ Alan Stern" * debug = 3, show all TDs in URBs when dumping */ #ifdef DEBUG +#define DEBUG_CONFIGURED 1 static int debug = 1; -#else -static int debug = 0; -#endif module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level"); + +#else +#define DEBUG_CONFIGURED 0 +#define debug 0 +#endif + static char *errbuf; #define ERRBUF_LEN (32 * 1024) @@ -338,6 +342,12 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) dev_err(uhci_dev(uhci), "host controller halted, " "very bad!\n"); + if (debug > 1 && errbuf) { + /* Print the schedule for debugging */ + uhci_sprint_schedule(uhci, + errbuf, ERRBUF_LEN); + lprintk(errbuf); + } hc_died(uhci); /* Force a callback in case there are @@ -376,6 +386,14 @@ static void release_uhci(struct uhci_hcd *uhci) { int i; + if (DEBUG_CONFIGURED) { + spin_lock_irq(&uhci->lock); + uhci->is_initialized = 0; + spin_unlock_irq(&uhci->lock); + + debugfs_remove(uhci->dentry); + } + for (i = 0; i < UHCI_NUM_SKELQH; i++) uhci_free_qh(uhci, uhci->skelqh[i]); @@ -390,8 +408,6 @@ static void release_uhci(struct uhci_hcd *uhci) dma_free_coherent(uhci_dev(uhci), UHCI_NUMFRAMES * sizeof(*uhci->frame), uhci->frame, uhci->frame_dma_handle); - - debugfs_remove(uhci->dentry); } static int uhci_reset(struct usb_hcd *hcd) @@ -474,17 +490,6 @@ static int uhci_start(struct usb_hcd *hcd) hcd->uses_new_polling = 1; - dentry = debugfs_create_file(hcd->self.bus_name, - S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, - &uhci_debug_operations); - if (!dentry) { - dev_err(uhci_dev(uhci), - "couldn't create uhci debugfs entry\n"); - retval = -ENOMEM; - goto err_create_debug_entry; - } - uhci->dentry = dentry; - uhci->fsbr = 0; uhci->fsbrtimeout = 0; @@ -495,6 +500,19 @@ static int uhci_start(struct usb_hcd *hcd) init_waitqueue_head(&uhci->waitqh); + if (DEBUG_CONFIGURED) { + dentry = debugfs_create_file(hcd->self.bus_name, + S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, + uhci, &uhci_debug_operations); + if (!dentry) { + dev_err(uhci_dev(uhci), "couldn't create uhci " + "debugfs entry\n"); + retval = -ENOMEM; + goto err_create_debug_entry; + } + uhci->dentry = dentry; + } + uhci->frame = dma_alloc_coherent(uhci_dev(uhci), UHCI_NUMFRAMES * sizeof(*uhci->frame), &uhci->frame_dma_handle, 0); @@ -609,6 +627,7 @@ static int uhci_start(struct usb_hcd *hcd) mb(); configure_hc(uhci); + uhci->is_initialized = 1; start_rh(uhci); return 0; @@ -872,16 +891,15 @@ static int __init uhci_hcd_init(void) if (usb_disabled()) return -ENODEV; - if (debug) { + if (DEBUG_CONFIGURED) { errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); if (!errbuf) goto errbuf_failed; + uhci_debugfs_root = debugfs_create_dir("uhci", NULL); + if (!uhci_debugfs_root) + goto debug_failed; } - uhci_debugfs_root = debugfs_create_dir("uhci", NULL); - if (!uhci_debugfs_root) - goto debug_failed; - uhci_up_cachep = kmem_cache_create("uhci_urb_priv", sizeof(struct urb_priv), 0, 0, NULL, NULL); if (!uhci_up_cachep) diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 7e96bef2e88f..4a69c7eb09bd 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -411,6 +411,7 @@ struct uhci_hcd { unsigned int hc_inaccessible:1; /* HC is suspended or dead */ unsigned int working_RD:1; /* Suspended root hub doesn't need to be polled */ + unsigned int is_initialized:1; /* Data structure is usable */ /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 44bba9a6d196..5d6c4f75d0d8 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -736,7 +736,6 @@ err: if (errbuf) { /* Print the chain for debugging purposes */ uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0); - lprintk(errbuf); } } @@ -924,26 +923,17 @@ td_error: ret = uhci_map_status(status, uhci_packetout(td_token(td))); err: - /* - * Enable this chunk of code if you want to see some more debugging. - * But be careful, it has the tendancy to starve out khubd and prevent - * disconnects from happening successfully if you have a slow debug - * log interface (like a serial console. - */ -#if 0 if ((debug == 1 && ret != -EPIPE) || debug > 1) { /* Some debugging code */ dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n", __FUNCTION__, status); - if (errbuf) { + if (debug > 1 && errbuf) { /* Print the chain for debugging purposes */ uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0); - lprintk(errbuf); } } -#endif /* Note that the queue has stopped and save the next toggle value */ urbp->qh->element = UHCI_PTR_TERM; -- cgit v1.2.2 From dbf4fcad62467ce1bd6966292b6850fc7a210e0b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 20 Dec 2005 09:58:08 -0500 Subject: [PATCH] UHCI: Don't log short transfers Even when the URB_SHORT_NOT_OK flag is set, a short transfer shouldn't generate a debugging log message. Especially not one with the confusing claim that the transfer "failed with status 0". This patch (as627) fixes that behavior in uhci-hcd. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-q.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 5d6c4f75d0d8..0c1b12091c48 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -922,7 +922,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) td_error: ret = uhci_map_status(status, uhci_packetout(td_token(td))); -err: if ((debug == 1 && ret != -EPIPE) || debug > 1) { /* Some debugging code */ dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n", @@ -934,6 +933,7 @@ err: lprintk(errbuf); } } +err: /* Note that the queue has stopped and save the next toggle value */ urbp->qh->element = UHCI_PTR_TERM; -- cgit v1.2.2 From 1393adb2ebb00a2cd54b293cd7ee71e3376f4e9f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 31 Jan 2006 10:02:55 -0500 Subject: [PATCH] uhci-hcd: fix mistaken usage of list_prepare_entry A recent update to the uhci-hcd driver invoked the list_prepare_entry macro incorrectly. This patch (as646) corrects it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-q.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 0c1b12091c48..5d2f9575ab4f 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -259,7 +259,7 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first) /* Fix up the toggle for the URBs in the queue. Normally this * loop won't run more than once: When an error or short transfer * occurs, the queue usually gets emptied. */ - list_prepare_entry(urbp, &qh->queue, node); + urbp = list_prepare_entry(urbp, &qh->queue, node); list_for_each_entry_continue(urbp, &qh->queue, node) { /* If the first TD has the right toggle value, we don't -- cgit v1.2.2 From 6a8e87b23ff4a979bde5451a242466a4b3f9fe7d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 19 Jan 2006 10:46:27 -0500 Subject: [PATCH] USB core and HCDs: don't put_device while atomic This patch (as640) removes several put_device and the corresponding get_device calls from the USB core and HCDs. Some of the puts were done in atomic contexts, and none of them are needed since the core now guarantees that every endpoint will be disabled and every URB completed before a USB device is released. Signed-off-by: Alan Stern Acked-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 -- drivers/usb/host/ehci-mem.c | 1 - drivers/usb/host/ehci-q.c | 2 +- drivers/usb/host/ehci-sched.c | 6 ++---- drivers/usb/host/isp116x-hcd.c | 3 +-- drivers/usb/host/sl811-hcd.c | 3 +-- drivers/usb/host/uhci-q.c | 2 -- 7 files changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a98d978d76e2..fbd938d4ea58 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1105,7 +1105,6 @@ static void urb_unlink (struct urb *urb) spin_lock_irqsave (&hcd_data_lock, flags); list_del_init (&urb->urb_list); spin_unlock_irqrestore (&hcd_data_lock, flags); - usb_put_dev (urb->dev); } @@ -1145,7 +1144,6 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags) case HC_STATE_RUNNING: case HC_STATE_RESUMING: doit: - usb_get_dev (urb->dev); list_add_tail (&urb->urb_list, &ep->urb_list); status = 0; break; diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 91c2ab43cbcc..ec7eb3f4f867 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -75,7 +75,6 @@ static void qh_destroy (struct kref *kref) } if (qh->dummy) ehci_qtd_free (ehci, qh->dummy); - usb_put_dev (qh->dev); dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 5ada7cd5698b..e469221e7ec3 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -702,7 +702,7 @@ qh_make ( } /* support for tt scheduling, and access to toggles */ - qh->dev = usb_get_dev (urb->dev); + qh->dev = urb->dev; /* using TT? */ switch (urb->dev->speed) { diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 88419c6823a8..90d6900a37f4 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1399,7 +1399,7 @@ itd_complete ( */ /* give urb back to the driver ... can be out-of-order */ - dev = usb_get_dev (urb->dev); + dev = urb->dev; ehci_urb_done (ehci, urb, regs); urb = NULL; @@ -1418,7 +1418,6 @@ itd_complete ( (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); } iso_stream_put (ehci, stream); - usb_put_dev (dev); return 1; } @@ -1765,7 +1764,7 @@ sitd_complete ( */ /* give urb back to the driver */ - dev = usb_get_dev (urb->dev); + dev = urb->dev; ehci_urb_done (ehci, urb, regs); urb = NULL; @@ -1784,7 +1783,6 @@ sitd_complete ( (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); } iso_stream_put (ehci, stream); - usb_put_dev (dev); return 1; } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 972ce04889f8..fea5dcbec7c4 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -724,7 +724,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, ep = hep->hcpriv; else { INIT_LIST_HEAD(&ep->schedule); - ep->udev = usb_get_dev(udev); + ep->udev = udev; ep->epnum = epnum; ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out); usb_settoggle(udev, epnum, is_out, 0); @@ -891,7 +891,6 @@ static void isp116x_endpoint_disable(struct usb_hcd *hcd, if (!list_empty(&hep->urb_list)) WARN("ep %p not empty?\n", ep); - usb_put_dev(ep->udev); kfree(ep); hep->hcpriv = NULL; } diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 517360b77d8e..a92343052751 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -853,7 +853,7 @@ static int sl811h_urb_enqueue( } else { INIT_LIST_HEAD(&ep->schedule); - ep->udev = usb_get_dev(udev); + ep->udev = udev; ep->epnum = epnum; ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out); ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE; @@ -1052,7 +1052,6 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) if (!list_empty(&hep->urb_list)) WARN("ep %p not empty?\n", ep); - usb_put_dev(ep->udev); kfree(ep); hep->hcpriv = NULL; } diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 5d2f9575ab4f..a06d84c19e13 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -179,7 +179,6 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, qh->hep = hep; qh->udev = udev; hep->hcpriv = qh; - usb_get_dev(udev); } else { /* Skeleton QH */ qh->state = QH_STATE_ACTIVE; @@ -197,7 +196,6 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) list_del(&qh->node); if (qh->udev) { qh->hep->hcpriv = NULL; - usb_put_dev(qh->udev); uhci_free_td(uhci, qh->dummy_td); } dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); -- cgit v1.2.2 From 43c5d5aaafef56618a6efbcab7f91615da1a8659 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 1 Feb 2006 10:47:11 -0500 Subject: [PATCH] usbcore: fix compile error with CONFIG_USB_SUSPEND=n This patch (as647) fixes a small error introduced by a recent change to the USB core suspend/resume code. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index f1d64d4bbf5f..7dd28f8e1cea 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1892,8 +1892,8 @@ int usb_resume_device(struct usb_device *udev) status = hub_port_resume(hdev_to_hub(udev->parent), udev->portnum, udev); } else - status = 0; #endif + status = 0; } else status = finish_device_resume(udev); if (status < 0) -- cgit v1.2.2 From 329af28b141ab4ae847aff1362864c4cc332641f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 18 Feb 2006 12:31:05 -0800 Subject: [PATCH] USB: gadget driver section fixups This adds __init section annotations to gadget driver bind() routines to remove calls from .text into .init sections (for endpoint autoconfig). Likewise it adds __exit section annotations to their unbind() routines. The specification of the gadget driver register/unregister functions is updated to explicitly allow use of those sections. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 4 ++-- drivers/usb/gadget/file_storage.c | 4 ++-- drivers/usb/gadget/serial.c | 6 +++--- drivers/usb/gadget/zero.c | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 3d2603e31808..0d9d9bbb73f0 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2125,7 +2125,7 @@ eth_req_free (struct usb_ep *ep, struct usb_request *req) } -static void +static void __exit eth_unbind (struct usb_gadget *gadget) { struct eth_dev *dev = get_gadget_data (gadget); @@ -2532,7 +2532,7 @@ static struct usb_gadget_driver eth_driver = { .function = (char *) driver_desc, .bind = eth_bind, - .unbind = eth_unbind, + .unbind = __exit_p(eth_unbind), .setup = eth_setup, .disconnect = eth_disconnect, diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index de59c58896d6..cf3be299e353 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3678,7 +3678,7 @@ static void lun_release(struct device *dev) kref_put(&fsg->ref, fsg_release); } -static void fsg_unbind(struct usb_gadget *gadget) +static void __exit fsg_unbind(struct usb_gadget *gadget) { struct fsg_dev *fsg = get_gadget_data(gadget); int i; @@ -4064,7 +4064,7 @@ static struct usb_gadget_driver fsg_driver = { #endif .function = (char *) longname, .bind = fsg_bind, - .unbind = fsg_unbind, + .unbind = __exit_p(fsg_unbind), .disconnect = fsg_disconnect, .setup = fsg_setup, .suspend = fsg_suspend, diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ba9acd531024..548feaac4553 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -369,7 +369,7 @@ static struct usb_gadget_driver gs_gadget_driver = { #endif /* CONFIG_USB_GADGET_DUALSPEED */ .function = GS_LONG_NAME, .bind = gs_bind, - .unbind = gs_unbind, + .unbind = __exit_p(gs_unbind), .setup = gs_setup, .disconnect = gs_disconnect, .driver = { @@ -1413,7 +1413,7 @@ requeue: * Called on module load. Allocates and initializes the device * structure and a control request. */ -static int gs_bind(struct usb_gadget *gadget) +static int __init gs_bind(struct usb_gadget *gadget) { int ret; struct usb_ep *ep; @@ -1538,7 +1538,7 @@ autoconf_fail: * Called on module unload. Frees the control request and device * structure. */ -static void gs_unbind(struct usb_gadget *gadget) +static void __exit gs_unbind(struct usb_gadget *gadget) { struct gs_dev *dev = get_gadget_data(gadget); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 5e9fe8a70543..44d8e5e77da7 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1119,7 +1119,7 @@ zero_autoresume (unsigned long _dev) /*-------------------------------------------------------------------------*/ -static void +static void __exit zero_unbind (struct usb_gadget *gadget) { struct zero_dev *dev = get_gadget_data (gadget); @@ -1136,7 +1136,7 @@ zero_unbind (struct usb_gadget *gadget) set_gadget_data (gadget, NULL); } -static int +static int __init zero_bind (struct usb_gadget *gadget) { struct zero_dev *dev; @@ -1288,7 +1288,7 @@ static struct usb_gadget_driver zero_driver = { #endif .function = (char *) longname, .bind = zero_bind, - .unbind = zero_unbind, + .unbind = __exit_p(zero_unbind), .setup = zero_setup, .disconnect = zero_disconnect, -- cgit v1.2.2 From 1afc64a3d68174fe524f11d92e045a30eacc927e Mon Sep 17 00:00:00 2001 From: Aras Vaichas Date: Sat, 18 Feb 2006 12:31:23 -0800 Subject: [PATCH] USB: ethernet gadget driver section fixups This patch allows you to set the iSerialNumber field in the usb_device_descriptor structure for your USB ethernet gadget. It also changes the parameters shown through sysfs so they're no longer declared as __initdata, preventing potential oopses. That's most useful for the Ethernet addresses, which may in some cases be random "locally administered" addresses. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 0d9d9bbb73f0..c3d8e5c5bf28 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -182,33 +182,37 @@ struct eth_dev { * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ -static ushort __initdata idVendor; +static ushort idVendor; module_param(idVendor, ushort, S_IRUGO); MODULE_PARM_DESC(idVendor, "USB Vendor ID"); -static ushort __initdata idProduct; +static ushort idProduct; module_param(idProduct, ushort, S_IRUGO); MODULE_PARM_DESC(idProduct, "USB Product ID"); -static ushort __initdata bcdDevice; +static ushort bcdDevice; module_param(bcdDevice, ushort, S_IRUGO); MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); -static char *__initdata iManufacturer; +static char *iManufacturer; module_param(iManufacturer, charp, S_IRUGO); MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); -static char *__initdata iProduct; +static char *iProduct; module_param(iProduct, charp, S_IRUGO); MODULE_PARM_DESC(iProduct, "USB Product string"); +static char *iSerialNumber; +module_param(iSerialNumber, charp, S_IRUGO); +MODULE_PARM_DESC(iSerialNumber, "SerialNumber"); + /* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */ -static char *__initdata dev_addr; +static char *dev_addr; module_param(dev_addr, charp, S_IRUGO); MODULE_PARM_DESC(dev_addr, "Device Ethernet Address"); /* this address is invisible to ifconfig */ -static char *__initdata host_addr; +static char *host_addr; module_param(host_addr, charp, S_IRUGO); MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); @@ -403,6 +407,7 @@ static inline int BITRATE(struct usb_gadget *g) #define STRING_CDC 7 #define STRING_SUBSET 8 #define STRING_RNDIS 9 +#define STRING_SERIALNUMBER 10 /* holds our biggest descriptor (or RNDIS response) */ #define USB_BUFSIZ 256 @@ -870,6 +875,7 @@ static inline void __init hs_subset_descriptors(void) static char manufacturer [50]; static char product_desc [40] = DRIVER_DESC; +static char serial_number [20]; #ifdef DEV_CONFIG_CDC /* address that the host will use ... usually assigned at random */ @@ -880,6 +886,7 @@ static char ethaddr [2 * ETH_ALEN + 1]; static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, product_desc, }, + { STRING_SERIALNUMBER, serial_number, }, { STRING_DATA, "Ethernet Data", }, #ifdef DEV_CONFIG_CDC { STRING_CDC, "CDC Ethernet", }, @@ -2162,7 +2169,7 @@ static u8 __init nibble (unsigned char c) return 0; } -static void __init get_ether_addr (const char *str, u8 *dev_addr) +static int __init get_ether_addr(const char *str, u8 *dev_addr) { if (str) { unsigned i; @@ -2177,9 +2184,10 @@ static void __init get_ether_addr (const char *str, u8 *dev_addr) dev_addr [i] = num; } if (is_valid_ether_addr (dev_addr)) - return; + return 0; } random_ether_addr(dev_addr); + return 1; } static int __init @@ -2277,6 +2285,10 @@ eth_bind (struct usb_gadget *gadget) strlcpy (manufacturer, iManufacturer, sizeof manufacturer); if (iProduct) strlcpy (product_desc, iProduct, sizeof product_desc); + if (iSerialNumber) { + device_desc.iSerialNumber = STRING_SERIALNUMBER, + strlcpy(serial_number, iSerialNumber, sizeof serial_number); + } /* all we really need is bulk IN/OUT */ usb_ep_autoconfig_reset (gadget); @@ -2386,9 +2398,13 @@ autoconf_fail: * The host side address is used with CDC and RNDIS, and commonly * ends up in a persistent config database. */ - get_ether_addr(dev_addr, net->dev_addr); + if (get_ether_addr(dev_addr, net->dev_addr)) + dev_warn(&gadget->dev, + "using random %s ethernet address\n", "self"); if (cdc || rndis) { - get_ether_addr(host_addr, dev->host_mac); + if (get_ether_addr(host_addr, dev->host_mac)) + dev_warn(&gadget->dev, + "using random %s ethernet address\n", "host"); #ifdef DEV_CONFIG_CDC snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", dev->host_mac [0], dev->host_mac [1], -- cgit v1.2.2 From addf36fec058691f7ba4f95b5487d140f4a86f5a Mon Sep 17 00:00:00 2001 From: Matthew Martin Date: Wed, 15 Feb 2006 15:41:25 -0600 Subject: [PATCH] USB: Fix warning in drivers/usb/media/ov511.c Gcc 4.0.2 had the warning: drivers/usb/media/ov511.c: In function 'show_exposure': drivers/usb/media/ov511.c:5642: warning: 'exp' may be used uninitialized in this function Here is the patch to fix that warning. Signed-off-by: Matthew Martin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/ov511.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c index cfec8c61574e..1d887ec06080 100644 --- a/drivers/usb/media/ov511.c +++ b/drivers/usb/media/ov511.c @@ -5639,7 +5639,7 @@ static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); static ssize_t show_exposure(struct class_device *cd, char *buf) { struct usb_ov511 *ov = cd_to_ov(cd); - unsigned char exp; + unsigned char exp = 0; if (!ov->dev) return -ENODEV; -- cgit v1.2.2 From 9e47a52bf36fa4a24f56f878f4ca57eb885c78dd Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Wed, 8 Feb 2006 00:05:27 +0000 Subject: [PATCH] USB: ZC0301 driver updates "Cosmetic" driver updates for the ZC0301 driver: - Fix stream_interrupt() (and work around a possible kernel bug); - Fix vidioc_enum_input() and split vidioc_gs_input() in two parts; - Use wait_event_interruptible_timeout() instead of wait_event_interruptible() when waiting for video frames; - replace erroneous wake_up_interruptible(&wait_stream) with wake_up(&wait_stream); - Cosmetic cleanups in the documentation. Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/zc0301.h | 2 +- drivers/usb/media/zc0301_core.c | 43 +++++++++++++++++++++++------------- drivers/usb/media/zc0301_pas202bcb.c | 2 +- 3 files changed, 30 insertions(+), 17 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h index 6fa5075f1e3d..cb1a0823bc63 100644 --- a/drivers/usb/media/zc0301.h +++ b/drivers/usb/media/zc0301.h @@ -45,7 +45,7 @@ #define ZC0301_MAX_DEVICES 64 #define ZC0301_FORCE_MUNMAP 0 #define ZC0301_MAX_FRAMES 32 -#define ZC0301_COMPRESSION_QUALITY 2 +#define ZC0301_COMPRESSION_QUALITY 0 #define ZC0301_URBS 2 #define ZC0301_ISO_PACKETS 7 #define ZC0301_ALTERNATE_SETTING 7 diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c index 238f60f7f472..7e8b1676d144 100644 --- a/drivers/usb/media/zc0301_core.c +++ b/drivers/usb/media/zc0301_core.c @@ -3,9 +3,9 @@ * * * Copyright (C) 2006 by Luca Risolia * * * - * Informations about the chip internals to enable the I2C protocol have * - * been taken from the documentation of the ZC030x Video4Linux1 driver * - * written by Andrew Birkett * + * Informations about the chip internals needed to enable the I2C protocol * + * have been taken from the documentation of the ZC030x Video4Linux1 * + * driver written by Andrew Birkett * * * * 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 * @@ -54,8 +54,8 @@ #define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia" #define ZC0301_AUTHOR_EMAIL "" #define ZC0301_MODULE_LICENSE "GPL" -#define ZC0301_MODULE_VERSION "1:1.00" -#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 0) +#define ZC0301_MODULE_VERSION "1:1.01" +#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1) /*****************************************************************************/ @@ -314,7 +314,7 @@ static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs) if ((*f)) (*f)->state = F_QUEUED; DBG(3, "Stream interrupted"); - wake_up_interruptible(&cam->wait_stream); + wake_up(&cam->wait_stream); } if (cam->state & DEV_DISCONNECTED) @@ -526,7 +526,7 @@ static int zc0301_stream_interrupt(struct zc0301_device* cam) ZC0301_URB_TIMEOUT); if (cam->state & DEV_DISCONNECTED) return -ENODEV; - else if (!timeout) { + else if (cam->stream != STREAM_OFF) { cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. To " "use it, close and open /dev/video%d again.", @@ -547,8 +547,7 @@ zc0301_set_compression(struct zc0301_device* cam, if ((r = zc0301_read_reg(cam, 0x0008)) < 0) err += r; - err += zc0301_write_reg(cam, 0x0008, - r | 0x11 | (compression->quality >> 1)); + err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality); return err ? -EIO : 0; } @@ -737,8 +736,7 @@ static int zc0301_release(struct inode* inode, struct file* filp) static ssize_t -zc0301_read(struct file* filp, char __user * buf, - size_t count, loff_t* f_pos) +zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) { struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); struct zc0301_frame_t* f, * i; @@ -1019,6 +1017,7 @@ zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg) memset(&i, 0, sizeof(i)); strcpy(i.name, "Camera"); + i.type = V4L2_INPUT_TYPE_CAMERA; if (copy_to_user(arg, &i, sizeof(i))) return -EFAULT; @@ -1028,7 +1027,19 @@ zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg) static int -zc0301_vidioc_gs_input(struct zc0301_device* cam, void __user * arg) +zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg) +{ + int index = 0; + + if (copy_to_user(arg, &index, sizeof(index))) + return -EFAULT; + + return 0; +} + + +static int +zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg) { int index; @@ -1446,7 +1457,7 @@ zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg) if (copy_from_user(&jc, arg, sizeof(jc))) return -EFAULT; - if (jc.quality < 0 || jc.quality > 3) + if (jc.quality != 0) return -EINVAL; if (cam->stream == STREAM_ON) @@ -1738,8 +1749,10 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp, return zc0301_vidioc_enuminput(cam, arg); case VIDIOC_G_INPUT: + return zc0301_vidioc_g_input(cam, arg); + case VIDIOC_S_INPUT: - return zc0301_vidioc_gs_input(cam, arg); + return zc0301_vidioc_s_input(cam, arg); case VIDIOC_QUERYCTRL: return zc0301_vidioc_query_ctrl(cam, arg); @@ -1980,7 +1993,7 @@ static void zc0301_usb_disconnect(struct usb_interface* intf) zc0301_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); - wake_up_interruptible(&cam->wait_stream); + wake_up(&cam->wait_stream); } else { cam->state |= DEV_DISCONNECTED; zc0301_release_resources(cam); diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c index 83b45f1c0f4e..32b9b9329cbf 100644 --- a/drivers/usb/media/zc0301_pas202bcb.c +++ b/drivers/usb/media/zc0301_pas202bcb.c @@ -318,7 +318,7 @@ static struct zc0301_sensor pas202bcb = { .width = 640, .height = 480, .pixelformat = V4L2_PIX_FMT_JPEG, - .priv = 16, + .priv = 8, }, }; -- cgit v1.2.2 From 80b6ca48321974a6566a1c9048ba34f60420bca6 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 27 Feb 2006 21:29:43 +0100 Subject: [PATCH] USB: kzalloc() conversion for rest of drivers/usb Signed-off-by: Eric Sesterhenn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-mem.c | 10 +++------- drivers/usb/host/ehci-sched.c | 3 +-- drivers/usb/host/hc_crisv10.c | 12 ++++-------- drivers/usb/media/ov511.c | 4 +--- drivers/usb/media/pwc/pwc-if.c | 3 +-- drivers/usb/media/se401.c | 4 +--- drivers/usb/media/stv680.c | 7 ++----- drivers/usb/misc/auerswald.c | 6 ++---- drivers/usb/misc/usblcd.c | 3 +-- drivers/usb/misc/usbtest.c | 9 +++------ drivers/usb/mon/mon_main.c | 3 +-- drivers/usb/mon/mon_text.c | 3 +-- drivers/usb/net/zd1201.c | 9 +++------ drivers/usb/serial/cp2101.c | 4 +--- drivers/usb/serial/cypress_m8.c | 3 +-- drivers/usb/serial/ftdi_sio.c | 3 +-- drivers/usb/serial/garmin_gps.c | 3 +-- drivers/usb/serial/io_edgeport.c | 3 +-- drivers/usb/serial/io_ti.c | 6 ++---- drivers/usb/serial/ir-usb.c | 3 +-- drivers/usb/serial/keyspan.c | 6 ++---- drivers/usb/serial/kobil_sct.c | 16 +++++----------- drivers/usb/serial/mct_u232.c | 3 +-- drivers/usb/serial/option.c | 3 +-- drivers/usb/serial/pl2303.c | 6 ++---- drivers/usb/serial/ti_usb_3410_5052.c | 3 +-- drivers/usb/serial/usb-serial.c | 6 ++---- drivers/usb/serial/visor.c | 3 +-- drivers/usb/storage/isd200.c | 2 +- 29 files changed, 48 insertions(+), 101 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index ec7eb3f4f867..766061e0260a 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -220,13 +220,9 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) ehci->periodic [i] = EHCI_LIST_END; /* software shadow of hardware table */ - ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags); - if (ehci->pshadow == NULL) { - goto fail; - } - memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *)); - - return 0; + ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags); + if (ehci->pshadow != NULL) + return 0; fail: ehci_dbg (ehci, "couldn't init memory\n"); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 90d6900a37f4..5871944e6145 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -864,9 +864,8 @@ iso_sched_alloc (unsigned packets, gfp_t mem_flags) int size = sizeof *iso_sched; size += packets * sizeof (struct ehci_iso_packet); - iso_sched = kmalloc (size, mem_flags); + iso_sched = kzalloc(size, mem_flags); if (likely (iso_sched != NULL)) { - memset(iso_sched, 0, size); INIT_LIST_HEAD (&iso_sched->td_list); } return iso_sched; diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 641268d7e6f3..2fe7fd19437b 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -2137,10 +2137,9 @@ static int etrax_usb_submit_bulk_urb(struct urb *urb) urb->status = -EINPROGRESS; /* Setup the hcpriv data. */ - urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); + urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); assert(urb_priv != NULL); /* This sets rx_offset to 0. */ - memset(urb_priv, 0, sizeof(etrax_urb_priv_t)); urb_priv->urb_state = NOT_STARTED; urb->hcpriv = urb_priv; @@ -2475,10 +2474,9 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb) urb->status = -EINPROGRESS; /* Setup the hcpriv data. */ - urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); + urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); assert(urb_priv != NULL); /* This sets rx_offset to 0. */ - memset(urb_priv, 0, sizeof(etrax_urb_priv_t)); urb_priv->urb_state = NOT_STARTED; urb->hcpriv = urb_priv; @@ -2767,9 +2765,8 @@ static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid) maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); interval = urb->interval; - urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); + urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG); assert(urb_priv != NULL); - memset(urb_priv, 0, sizeof(etrax_urb_priv_t)); urb->hcpriv = urb_priv; first_ep = &TxIntrEPList[0]; @@ -2997,9 +2994,8 @@ static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid) prev_sb_desc = next_sb_desc = temp_sb_desc = NULL; - urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC); + urb_priv = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC); assert(urb_priv != NULL); - memset(urb_priv, 0, sizeof(etrax_urb_priv_t)); urb->hcpriv = urb_priv; urb_priv->epid = epid; diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c index 1d887ec06080..da44579d6f29 100644 --- a/drivers/usb/media/ov511.c +++ b/drivers/usb/media/ov511.c @@ -5686,13 +5686,11 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) if (idesc->bInterfaceSubClass != 0x00) return -ENODEV; - if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { + if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { err("couldn't kmalloc ov struct"); goto error_out; } - memset(ov, 0, sizeof(*ov)); - ov->dev = dev; ov->iface = idesc->bInterfaceNumber; ov->led_policy = led; diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c index db6753dc5ba5..90eb26042817 100644 --- a/drivers/usb/media/pwc/pwc-if.c +++ b/drivers/usb/media/pwc/pwc-if.c @@ -1867,12 +1867,11 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id Info("Warning: more than 1 configuration available.\n"); /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ - pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL); + pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL); if (pdev == NULL) { Err("Oops, could not allocate memory for pwc_device.\n"); return -ENOMEM; } - memset(pdev, 0, sizeof(struct pwc_device)); pdev->type = type_id; pdev->vsize = default_size; pdev->vframes = default_fps; diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c index 8c3b1ad8a8fd..f03ea7f89596 100644 --- a/drivers/usb/media/se401.c +++ b/drivers/usb/media/se401.c @@ -1345,13 +1345,11 @@ static int se401_probe(struct usb_interface *intf, /* We found one */ info("SE401 camera found: %s", camera_name); - if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { + if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { err("couldn't kmalloc se401 struct"); return -ENOMEM; } - memset(se401, 0, sizeof(*se401)); - se401->dev = dev; se401->iface = interface->bInterfaceNumber; se401->camera_name = camera_name; diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c index b1a6be2958ed..9636da20748d 100644 --- a/drivers/usb/media/stv680.c +++ b/drivers/usb/media/stv680.c @@ -318,12 +318,11 @@ static int stv_init (struct usb_stv *stv680) unsigned char *buffer; unsigned long int bufsize; - buffer = kmalloc (40, GFP_KERNEL); + buffer = kzalloc (40, GFP_KERNEL); if (buffer == NULL) { PDEBUG (0, "STV(e): Out of (small buf) memory"); return -1; } - memset (buffer, 0, 40); udelay (100); /* set config 1, interface 0, alternate 0 */ @@ -1388,14 +1387,12 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id goto error; } /* We found one */ - if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { + if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); retval = -ENOMEM; goto error; } - memset (stv680, 0, sizeof (*stv680)); - stv680->udev = dev; stv680->camera_name = camera_name; diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index ad2f4cccd388..1fef36e71c57 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -570,10 +570,9 @@ static int auerchain_setup (pauerchain_t acp, unsigned int numElements) /* fill the list of free elements */ for (;numElements; numElements--) { - acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL); + acep = kzalloc(sizeof(auerchainelement_t), GFP_KERNEL); if (!acep) goto ac_fail; - memset (acep, 0, sizeof (auerchainelement_t)); INIT_LIST_HEAD (&acep->list); list_add_tail (&acep->list, &acp->free_list); } @@ -761,10 +760,9 @@ static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned /* fill the list of free elements */ for (;numElements; numElements--) { - bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL); + bep = kzalloc(sizeof(auerbuf_t), GFP_KERNEL); if (!bep) goto bl_fail; - memset (bep, 0, sizeof (auerbuf_t)); bep->list = bcp; INIT_LIST_HEAD (&bep->buff_list); bep->bufp = kmalloc (bufsize, GFP_KERNEL); diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index cc3dae3f34e0..c82c402285a0 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -270,12 +270,11 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id int retval = -ENOMEM; /* allocate memory for our device state and initialize it */ - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { err("Out of memory"); goto error; } - memset(dev, 0x00, sizeof(*dev)); kref_init(&dev->kref); dev->udev = usb_get_dev(interface_to_usbdev(interface)); diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 84fa1728f052..9d59b901841c 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -382,12 +382,11 @@ alloc_sglist (int nents, int max, int vary) for (i = 0; i < nents; i++) { char *buf; - buf = kmalloc (size, SLAB_KERNEL); + buf = kzalloc (size, SLAB_KERNEL); if (!buf) { free_sglist (sg, i); return NULL; } - memset (buf, 0, size); /* kmalloc pages are always physically contiguous! */ sg_init_one(&sg[i], buf, size); @@ -842,10 +841,9 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) * as with bulk/intr sglists, sglen is the queue depth; it also * controls which subtests run (more tests than sglen) or rerun. */ - urb = kmalloc (param->sglen * sizeof (struct urb *), SLAB_KERNEL); + urb = kcalloc(param->sglen, sizeof(struct urb *), SLAB_KERNEL); if (!urb) return -ENOMEM; - memset (urb, 0, param->sglen * sizeof (struct urb *)); for (i = 0; i < param->sglen; i++) { int pipe = usb_rcvctrlpipe (udev, 0); unsigned len; @@ -1865,10 +1863,9 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) } #endif - dev = kmalloc (sizeof *dev, SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), SLAB_KERNEL); if (!dev) return -ENOMEM; - memset (dev, 0, sizeof *dev); info = (struct usbtest_info *) id->driver_info; dev->info = info; init_MUTEX (&dev->sem); diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index b03e346e33f1..6ecc27302211 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -277,9 +277,8 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) char name[NAMESZ]; int rc; - if ((mbus = kmalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL) + if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL) goto err_alloc; - memset(mbus, 0, sizeof(struct mon_bus)); kref_init(&mbus->ref); spin_lock_init(&mbus->lock); INIT_LIST_HEAD(&mbus->r_list); diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 59089e8b7e5e..ac043ec2b8dc 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -213,12 +213,11 @@ static int mon_text_open(struct inode *inode, struct file *file) mbus = inode->u.generic_ip; ubus = mbus->u_bus; - rp = kmalloc(sizeof(struct mon_reader_text), GFP_KERNEL); + rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL); if (rp == NULL) { rc = -ENOMEM; goto err_alloc; } - memset(rp, 0, sizeof(struct mon_reader_text)); INIT_LIST_HEAD(&rp->e_list); init_waitqueue_head(&rp->wait); mutex_init(&rp->printf_lock); diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index f3a8e2807c3b..fe9b60cd8d95 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -621,10 +621,9 @@ static int zd1201_drvr_start(struct zd1201 *zd) __le16 zdmax; unsigned char *buffer; - buffer = kmalloc(ZD1201_RXSIZE, GFP_KERNEL); + buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL); if (!buffer) return -ENOMEM; - memset(buffer, 0, ZD1201_RXSIZE); usb_fill_bulk_urb(zd->rx_urb, zd->usb, usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE, @@ -1750,11 +1749,9 @@ static int zd1201_probe(struct usb_interface *interface, usb = interface_to_usbdev(interface); - zd = kmalloc(sizeof(struct zd1201), GFP_KERNEL); - if (!zd) { + zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL); + if (!zd) return -ENOMEM; - } - memset(zd, 0, sizeof(struct zd1201)); zd->ap = ap; zd->usb = usb; zd->removed = 0; diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index dc7a069503e0..9ea7b4a4a22b 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -169,9 +169,7 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request, /* Number of integers required to contain the array */ length = (((size - 1) | 3) + 1)/4; - buf = kmalloc (length * sizeof(u32), GFP_KERNEL); - memset(buf, 0, length * sizeof(u32)); - + buf = kcalloc(length, sizeof(u32), GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); return -ENOMEM; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 68067fe117a4..71af3bf5adb7 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -435,11 +435,10 @@ static int generic_startup (struct usb_serial *serial) dbg("%s - port %d", __FUNCTION__, serial->port[0]->number); - priv = kmalloc(sizeof (struct cypress_private), GFP_KERNEL); + priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL); if (!priv) return -ENOMEM; - memset(priv, 0x00, sizeof (struct cypress_private)); spin_lock_init(&priv->lock); priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE); if (priv->buf == NULL) { diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c145e1ed8429..ece52a6328b5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1141,12 +1141,11 @@ static int ftdi_sio_attach (struct usb_serial *serial) dbg("%s",__FUNCTION__); - priv = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private)); return -ENOMEM; } - memset(priv, 0, sizeof(*priv)); spin_lock_init(&priv->rx_lock); init_waitqueue_head(&priv->delta_msr_wait); diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index d6f55e9dccae..5ec9bf5bac8d 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1422,12 +1422,11 @@ static int garmin_attach (struct usb_serial *serial) dbg("%s", __FUNCTION__); - garmin_data_p = kmalloc (sizeof(struct garmin_data), GFP_KERNEL); + garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); if (garmin_data_p == NULL) { dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__); return -ENOMEM; } - memset (garmin_data_p, 0, sizeof(struct garmin_data)); init_timer(&garmin_data_p->timer); spin_lock_init(&garmin_data_p->lock); INIT_LIST_HEAD(&garmin_data_p->pktlist); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 3f29e6b0fd19..b606c5968102 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2725,12 +2725,11 @@ static int edge_startup (struct usb_serial *serial) dev = serial->dev; /* create our private serial structure */ - edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL); + edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); if (edge_serial == NULL) { dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); return -ENOMEM; } - memset (edge_serial, 0, sizeof(struct edgeport_serial)); spin_lock_init(&edge_serial->es_lock); edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index afc0f34b3a46..8e1e2253748b 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2727,12 +2727,11 @@ static int edge_startup (struct usb_serial *serial) dev = serial->dev; /* create our private serial structure */ - edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL); + edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); if (edge_serial == NULL) { dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); return -ENOMEM; } - memset (edge_serial, 0, sizeof(struct edgeport_serial)); sema_init(&edge_serial->es_sem, 1); edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); @@ -2745,12 +2744,11 @@ static int edge_startup (struct usb_serial *serial) /* set up our port private structures */ for (i = 0; i < serial->num_ports; ++i) { - edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); + edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL); if (edge_port == NULL) { dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); goto cleanup; } - memset (edge_port, 0, sizeof(struct edgeport_port)); spin_lock_init(&edge_port->ep_lock); edge_port->ep_out_buf = edge_buf_alloc(EDGE_OUT_BUF_SIZE); if (edge_port->ep_out_buf == NULL) { diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index a59010421444..426182ddc42a 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -184,10 +184,9 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, struct irda_class_desc *desc; int ret; - desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL); + desc = kzalloc(sizeof (struct irda_class_desc), GFP_KERNEL); if (desc == NULL) return NULL; - memset(desc, 0, sizeof(struct irda_class_desc)); ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), IU_REQ_GET_CLASS_DESC, diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 3b958e60f5e8..052b735c4fbd 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -2250,12 +2250,11 @@ static int keyspan_startup (struct usb_serial *serial) } /* Setup private data for serial driver */ - s_priv = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); + s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); if (!s_priv) { dbg("%s - kmalloc for keyspan_serial_private failed.", __FUNCTION__); return -ENOMEM; } - memset(s_priv, 0, sizeof(struct keyspan_serial_private)); s_priv->device_details = d_details; usb_set_serial_data(serial, s_priv); @@ -2263,12 +2262,11 @@ static int keyspan_startup (struct usb_serial *serial) /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - p_priv = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL); + p_priv = kzalloc(sizeof(struct keyspan_port_private), GFP_KERNEL); if (!p_priv) { dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __FUNCTION__, i); return (1); } - memset(p_priv, 0, sizeof(struct keyspan_port_private)); p_priv->device_details = d_details; usb_set_serial_port_data(port, p_priv); } diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index b8b213185d0f..87dfcd89ffab 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -255,11 +255,9 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) } // allocate memory for transfer buffer - transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL); + transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { return -ENOMEM; - } else { - memset(transfer_buffer, 0, transfer_buffer_length); } // allocate write_urb @@ -383,11 +381,10 @@ static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs) // BEGIN DEBUG /* - dbg_data = (unsigned char *) kmalloc((3 * purb->actual_length + 10) * sizeof(char), GFP_KERNEL); + dbg_data = kzalloc((3 * purb->actual_length + 10) * sizeof(char), GFP_KERNEL); if (! dbg_data) { return; } - memset(dbg_data, 0, (3 * purb->actual_length + 10)); for (i = 0; i < purb->actual_length; i++) { sprintf(dbg_data +3*i, "%02X ", data[i]); } @@ -518,11 +515,10 @@ static int kobil_tiocmget(struct usb_serial_port *port, struct file *file) } // allocate memory for transfer buffer - transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL); + transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (!transfer_buffer) { return -ENOMEM; } - memset(transfer_buffer, 0, transfer_buffer_length); result = usb_control_msg( port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0 ), @@ -564,11 +560,10 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file, } // allocate memory for transfer buffer - transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL); + transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { return -ENOMEM; } - memset(transfer_buffer, 0, transfer_buffer_length); if (set & TIOCM_RTS) rts = 1; @@ -655,11 +650,10 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, (struct termios __user *)arg)) return -EFAULT; - settings = (unsigned char *) kmalloc(50, GFP_KERNEL); + settings = kzalloc(50, GFP_KERNEL); if (! settings) { return -ENOBUFS; } - memset(settings, 0, 50); switch (priv->internal_termios.c_cflag & CBAUD) { case B1200: diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index b6d6cab9c859..35bd29b6c408 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -348,10 +348,9 @@ static int mct_u232_startup (struct usb_serial *serial) struct mct_u232_private *priv; struct usb_serial_port *port, *rport; - priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL); if (!priv) return -ENOMEM; - memset(priv, 0, sizeof(struct mct_u232_private)); spin_lock_init(&priv->lock); usb_set_serial_port_data(serial->port[0], priv); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 52bdf6fe46f2..a8455c9e79dd 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -631,13 +631,12 @@ static int option_startup(struct usb_serial *serial) /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; - portdata = kmalloc(sizeof(*portdata), GFP_KERNEL); + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); if (!portdata) { dbg("%s: kmalloc for option_port_private (%d) failed!.", __FUNCTION__, i); return (1); } - memset(portdata, 0, sizeof(struct option_port_private)); usb_set_serial_port_data(port, portdata); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 37c81c08faad..cf2213bae0e0 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -218,10 +218,9 @@ static int pl2303_startup (struct usb_serial *serial) dbg("device type: %d", type); for (i = 0; i < serial->num_ports; ++i) { - priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL); if (!priv) goto cleanup; - memset (priv, 0x00, sizeof (struct pl2303_private)); spin_lock_init(&priv->lock); priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); if (priv->buf == NULL) { @@ -383,12 +382,11 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol } } - buf = kmalloc (7, GFP_KERNEL); + buf = kzalloc (7, GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); return; } - memset (buf, 0x00, 0x07); i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index c18db3257073..c3a2071b802d 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -416,12 +416,11 @@ static int ti_startup(struct usb_serial *serial) dev->actconfig->desc.bConfigurationValue); /* create device structure */ - tdev = kmalloc(sizeof(struct ti_device), GFP_KERNEL); + tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL); if (tdev == NULL) { dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } - memset(tdev, 0, sizeof(struct ti_device)); sema_init(&tdev->td_open_close_sem, 1); tdev->td_serial = serial; usb_set_serial_data(serial, tdev); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index b5c96e74a903..097f4e8488fe 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -564,12 +564,11 @@ static struct usb_serial * create_serial (struct usb_device *dev, { struct usb_serial *serial; - serial = kmalloc (sizeof (*serial), GFP_KERNEL); + serial = kzalloc(sizeof(*serial), GFP_KERNEL); if (!serial) { dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__); return NULL; } - memset (serial, 0, sizeof(*serial)); serial->dev = usb_get_dev(dev); serial->type = driver; serial->interface = interface; @@ -778,10 +777,9 @@ int usb_serial_probe(struct usb_interface *interface, serial->num_port_pointers = max_endpoints; dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); for (i = 0; i < max_endpoints; ++i) { - port = kmalloc(sizeof(struct usb_serial_port), GFP_KERNEL); + port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); if (!port) goto probe_error; - memset(port, 0x00, sizeof(struct usb_serial_port)); port->number = i + serial->minor; port->serial = serial; spin_lock_init(&port->lock); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 11a48d874752..f5c3841d4843 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -763,10 +763,9 @@ static int generic_startup(struct usb_serial *serial) int i; for (i = 0; i < serial->num_ports; ++i) { - priv = kmalloc (sizeof(*priv), GFP_KERNEL); + priv = kzalloc (sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - memset (priv, 0x00, sizeof(*priv)); spin_lock_init(&priv->lock); usb_set_serial_port_data(serial->port[i], priv); } diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 7308e8cbe8f9..6831dca93c1b 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1382,7 +1382,7 @@ static int isd200_init_info(struct us_data *us) } else US_DEBUGP("ERROR - kmalloc failure\n"); - return(retStatus); + return retStatus; } /************************************************************************** -- cgit v1.2.2 From 7039f4224d4e40b06308d5c1a97427af1a142459 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Mon, 27 Feb 2006 13:34:10 -0800 Subject: [PATCH] USB: kzalloc() conversion in drivers/usb/gadget this patch converts drivers/usb to kzalloc usage. Compile tested with allyes config. I think there was a bug in drivers/usb/gadget/inode.c because it used sizeof(*data) for the kmalloc() and sizeof(data) for the memset(), since sizeof(data) just returns the size for a pointer. Signed-off-by: Eric Sesterhenn Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/dummy_hcd.c | 3 +-- drivers/usb/gadget/goku_udc.c | 3 +-- drivers/usb/gadget/inode.c | 6 ++---- drivers/usb/gadget/lh7a40x_udc.c | 3 +-- drivers/usb/gadget/net2280.c | 3 +-- drivers/usb/gadget/omap_udc.c | 6 ++---- drivers/usb/gadget/pxa2xx_udc.c | 3 +-- drivers/usb/gadget/serial.c | 3 +-- drivers/usb/gadget/zero.c | 3 +-- 9 files changed, 11 insertions(+), 22 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 9734cb76dd6c..42ce41d71b7f 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -478,10 +478,9 @@ dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags) return NULL; ep = usb_ep_to_dummy_ep (_ep); - req = kmalloc (sizeof *req, mem_flags); + req = kzalloc(sizeof(*req), mem_flags); if (!req) return NULL; - memset (req, 0, sizeof *req); INIT_LIST_HEAD (&req->queue); return &req->req; } diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index b0f3cd63e3b9..66b81bbf6bee 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -275,11 +275,10 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) if (!_ep) return NULL; - req = kmalloc(sizeof *req, gfp_flags); + req = kzalloc(sizeof *req, gfp_flags); if (!req) return NULL; - memset(req, 0, sizeof *req); req->req.dma = DMA_ADDR_INVALID; INIT_LIST_HEAD(&req->queue); return &req->req; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 0aab7d24c768..b44cfda76b61 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -170,10 +170,9 @@ static struct dev_data *dev_new (void) { struct dev_data *dev; - dev = kmalloc (sizeof *dev, GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; - memset (dev, 0, sizeof *dev); dev->state = STATE_DEV_DISABLED; atomic_set (&dev->count, 1); spin_lock_init (&dev->lock); @@ -1592,10 +1591,9 @@ static int activate_ep_files (struct dev_data *dev) gadget_for_each_ep (ep, dev->gadget) { struct ep_data *data; - data = kmalloc (sizeof *data, GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) goto enomem; - memset (data, 0, sizeof data); data->state = STATE_EP_DISABLED; init_MUTEX (&data->lock); init_waitqueue_head (&data->wait); diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 1a362c5e7f3d..0d3424eda038 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -1114,11 +1114,10 @@ static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, DEBUG("%s, %p\n", __FUNCTION__, ep); - req = kmalloc(sizeof *req, gfp_flags); + req = kzalloc(sizeof(*req), gfp_flags); if (!req) return 0; - memset(req, 0, sizeof *req); INIT_LIST_HEAD(&req->queue); return &req->req; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 67b13ab2f3f5..fb73dc100535 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -386,11 +386,10 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) return NULL; ep = container_of (_ep, struct net2280_ep, ep); - req = kmalloc (sizeof *req, gfp_flags); + req = kzalloc(sizeof(*req), gfp_flags); if (!req) return NULL; - memset (req, 0, sizeof *req); req->req.dma = DMA_ADDR_INVALID; INIT_LIST_HEAD (&req->queue); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index a8972d7c97be..fbea51448909 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -273,9 +273,8 @@ omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { struct omap_req *req; - req = kmalloc(sizeof *req, gfp_flags); + req = kzalloc(sizeof(*req), gfp_flags); if (req) { - memset (req, 0, sizeof *req); req->req.dma = DMA_ADDR_INVALID; INIT_LIST_HEAD (&req->queue); } @@ -2586,11 +2585,10 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) /* UDC_PULLUP_EN gates the chip clock */ // OTG_SYSCON_1_REG |= DEV_IDLE_EN; - udc = kmalloc (sizeof *udc, SLAB_KERNEL); + udc = kzalloc(sizeof(*udc), SLAB_KERNEL); if (!udc) return -ENOMEM; - memset(udc, 0, sizeof *udc); spin_lock_init (&udc->lock); udc->gadget.ops = &omap_gadget_ops; diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index bb028c5b8952..680f7fc5b171 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -335,11 +335,10 @@ pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) { struct pxa2xx_request *req; - req = kmalloc (sizeof *req, gfp_flags); + req = kzalloc(sizeof(*req), gfp_flags); if (!req) return NULL; - memset (req, 0, sizeof *req); INIT_LIST_HEAD (&req->queue); return &req->req; } diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 548feaac4553..b992546c394d 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -2178,10 +2178,9 @@ static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags) return -EIO; for (i=0; iport_dev = dev; port->port_num = i; port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 44d8e5e77da7..51424f66a765 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1188,10 +1188,9 @@ autoconf_fail: /* ok, we made sense of the hardware ... */ - dev = kmalloc (sizeof *dev, SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), SLAB_KERNEL); if (!dev) return -ENOMEM; - memset (dev, 0, sizeof *dev); spin_lock_init (&dev->lock); dev->gadget = gadget; set_gadget_data (gadget, dev); -- cgit v1.2.2 From 2ffab02fea5880da284dc5511479b25a796a8dee Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Sat, 25 Feb 2006 06:50:47 +0000 Subject: [PATCH] USB: SN9C10x driver updates SN9C10x driver updates. Changes: + new, - removed, * cleanup, @ bugfix @ Fix stream_interrupt() @ Fix vidioc_enum_input() and split vidioc_gs_input() @ Need usb_get|put_dev() when disconnecting, if the device is open * Use wait_event_interruptible_timeout() instead of wait_event_interruptible() when waiting for video frames * replace wake_up_interruptible(&wait_stream) with wake_up(&wait_stream) * Cleanups and updates in the documentation + Use per-device sensor structures + Add support for PAS202BCA image sensors + Add frame_timeout module parameter Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/Makefile | 5 +- drivers/usb/media/sn9c102.h | 23 +++- drivers/usb/media/sn9c102_core.c | 170 +++++++++++++---------- drivers/usb/media/sn9c102_ov7630.c | 33 +++-- drivers/usb/media/sn9c102_pas202bca.c | 238 +++++++++++++++++++++++++++++++++ drivers/usb/media/sn9c102_pas202bcb.c | 2 +- drivers/usb/media/sn9c102_sensor.h | 15 ++- drivers/usb/media/sn9c102_tas5110c1b.c | 14 +- drivers/usb/media/sn9c102_tas5130d1b.c | 12 +- 9 files changed, 405 insertions(+), 107 deletions(-) create mode 100644 drivers/usb/media/sn9c102_pas202bca.c (limited to 'drivers/usb') diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile index 333bf09ca2d6..50e89a33b85e 100644 --- a/drivers/usb/media/Makefile +++ b/drivers/usb/media/Makefile @@ -2,7 +2,10 @@ # Makefile for USB Media drivers # -sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ + sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \ + sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ + sn9c102_tas5130d1b.o et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o zc0301-objs := zc0301_core.o zc0301_pas202bcb.o diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h index 59e44be27cb4..1d70a62b9f23 100644 --- a/drivers/usb/media/sn9c102.h +++ b/drivers/usb/media/sn9c102.h @@ -34,7 +34,8 @@ #include #include #include -#include +#include +#include #include "sn9c102_sensor.h" @@ -51,6 +52,7 @@ #define SN9C102_ALTERNATE_SETTING 8 #define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) #define SN9C102_CTRL_TIMEOUT 300 +#define SN9C102_FRAME_TIMEOUT 2 /*****************************************************************************/ @@ -108,6 +110,7 @@ struct sn9c102_sysfs_attr { struct sn9c102_module_param { u8 force_munmap; + u16 frame_timeout; }; static DEFINE_MUTEX(sn9c102_sysfs_lock); @@ -117,7 +120,7 @@ struct sn9c102_device { struct video_device* v4ldev; enum sn9c102_bridge bridge; - struct sn9c102_sensor* sensor; + struct sn9c102_sensor sensor; struct usb_device* usbdev; struct urb* urb[SN9C102_URBS]; @@ -149,12 +152,21 @@ struct sn9c102_device { /*****************************************************************************/ +struct sn9c102_device* +sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) +{ + if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) + return cam; + + return NULL; +} + + void sn9c102_attach_sensor(struct sn9c102_device* cam, struct sn9c102_sensor* sensor) { - cam->sensor = sensor; - cam->sensor->usbdev = cam->usbdev; + memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); } /*****************************************************************************/ @@ -197,7 +209,8 @@ do { \ #undef PDBG #define PDBG(fmt, args...) \ -dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args) +dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args) #undef PDBGG #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c index 30119080871b..4c6cc6395723 100644 --- a/drivers/usb/media/sn9c102_core.c +++ b/drivers/usb/media/sn9c102_core.c @@ -25,11 +25,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -49,8 +47,8 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.26" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 26) +#define SN9C102_MODULE_VERSION "1:1.27" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 27) /*****************************************************************************/ @@ -89,6 +87,15 @@ MODULE_PARM_DESC(force_munmap, "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." "\n"); +static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = + SN9C102_FRAME_TIMEOUT}; +module_param_array(frame_timeout, uint, NULL, 0644); +MODULE_PARM_DESC(frame_timeout, + "\n Timeout for a video frame in seconds." + "\nThis parameter is specific for each detected camera." + "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." + "\n"); + #ifdef SN9C102_DEBUG static unsigned short debug = SN9C102_DEBUG_LEVEL; module_param(debug, ushort, 0644); @@ -128,8 +135,8 @@ static u32 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, enum sn9c102_io_method io) { - struct v4l2_pix_format* p = &(cam->sensor->pix_format); - struct v4l2_rect* r = &(cam->sensor->cropcap.bounds); + struct v4l2_pix_format* p = &(cam->sensor.pix_format); + struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); const size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? (p->width * p->height * p->priv) / 8 : @@ -449,19 +456,13 @@ sn9c102_i2c_try_write(struct sn9c102_device* cam, int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) { - if (!cam->sensor) - return -1; - - return sn9c102_i2c_try_read(cam, cam->sensor, address); + return sn9c102_i2c_try_read(cam, &cam->sensor, address); } int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) { - if (!cam->sensor) - return -1; - - return sn9c102_i2c_try_write(cam, cam->sensor, address, value); + return sn9c102_i2c_try_write(cam, &cam->sensor, address, value); } /*****************************************************************************/ @@ -505,7 +506,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) size_t eoflen = sizeof(sn9c102_eof_header_t), i; unsigned j, n = sizeof(sn9c102_eof_header) / eoflen; - if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) + if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) return NULL; /* EOF header does not exist in compressed data */ for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++) @@ -535,7 +536,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) if ((*f)) (*f)->state = F_QUEUED; DBG(3, "Stream interrupted"); - wake_up_interruptible(&cam->wait_stream); + wake_up(&cam->wait_stream); } if (cam->state & DEV_DISCONNECTED) @@ -553,9 +554,9 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, frame); - imagesize = (cam->sensor->pix_format.width * - cam->sensor->pix_format.height * - cam->sensor->pix_format.priv) / 8; + imagesize = (cam->sensor.pix_format.width * + cam->sensor.pix_format.height * + cam->sensor.pix_format.priv) / 8; soflen = (cam->bridge) == BRIDGE_SN9C103 ? sizeof(sn9c103_sof_header_t) : @@ -579,7 +580,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) redo: sof = sn9c102_find_sof_header(cam, pos, len); - if (!sof) { + if (likely(!sof)) { eof = sn9c102_find_eof_header(cam, pos, len); if ((*f)->state == F_GRABBING) { end_of_frame: @@ -589,8 +590,9 @@ end_of_frame: img = (eof > pos) ? eof - pos - 1 : 0; if ((*f)->buf.bytesused+img > imagesize) { - u32 b = (*f)->buf.bytesused + img - - imagesize; + u32 b; + b = (*f)->buf.bytesused + img - + imagesize; img = imagesize - (*f)->buf.bytesused; DBG(3, "Expected EOF not found: " "video frame cut"); @@ -608,9 +610,10 @@ end_of_frame: (*f)->buf.bytesused += img; if ((*f)->buf.bytesused == imagesize || - (cam->sensor->pix_format.pixelformat == + (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X && eof)) { - u32 b = (*f)->buf.bytesused; + u32 b; + b = (*f)->buf.bytesused; (*f)->state = F_DONE; (*f)->buf.sequence= ++cam->frame_count; spin_lock(&cam->queue_lock); @@ -667,7 +670,7 @@ start_of_frame: if (eof && eof < sof) goto end_of_frame; /* (1) */ else { - if (cam->sensor->pix_format.pixelformat == + if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) { eof = sof - soflen; goto end_of_frame; @@ -808,20 +811,21 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam) static int sn9c102_stream_interrupt(struct sn9c102_device* cam) { - int err = 0; + long timeout; cam->stream = STREAM_INTERRUPT; - err = wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - SN9C102_URB_TIMEOUT); + timeout = wait_event_timeout(cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED), + SN9C102_URB_TIMEOUT); if (cam->state & DEV_DISCONNECTED) return -ENODEV; - else if (err) { + else if (cam->stream != STREAM_OFF) { cam->state |= DEV_MISCONFIGURED; - DBG(1, "The camera is misconfigured. To use it, close and " - "open /dev/video%d again.", cam->v4ldev->minor); - return err; + DBG(1, "URB timeout reached. The camera is misconfigured. " + "To use it, close and open /dev/video%d again.", + cam->v4ldev->minor); + return -EIO; } return 0; @@ -1057,7 +1061,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) return -ENODEV; } - if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) { + if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) { mutex_unlock(&sn9c102_sysfs_lock); return -ENOSYS; } @@ -1094,7 +1098,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) return -ENODEV; } - if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) { + if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) { mutex_unlock(&sn9c102_sysfs_lock); return -ENOSYS; } @@ -1249,7 +1253,7 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam) video_device_create_file(v4ldev, &class_device_attr_blue); video_device_create_file(v4ldev, &class_device_attr_red); } - if (cam->sensor && cam->sensor->sysfs_ops) { + if (cam->sensor.sysfs_ops) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); video_device_create_file(v4ldev, &class_device_attr_i2c_val); } @@ -1312,7 +1316,7 @@ static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) { - struct sn9c102_sensor* s = cam->sensor; + struct sn9c102_sensor* s = &cam->sensor; u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), v_start = (u8)(rect->top - s->cropcap.bounds.top), h_size = (u8)(rect->width / 16), @@ -1335,7 +1339,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) static int sn9c102_init(struct sn9c102_device* cam) { - struct sn9c102_sensor* s = cam->sensor; + struct sn9c102_sensor* s = &cam->sensor; struct v4l2_control ctrl; struct v4l2_queryctrl *qctrl; struct v4l2_rect* rect; @@ -1428,6 +1432,8 @@ static void sn9c102_release_resources(struct sn9c102_device* cam) video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); + usb_put_dev(cam->usbdev); + mutex_unlock(&sn9c102_sysfs_lock); kfree(cam->control_buffer); @@ -1541,6 +1547,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); struct sn9c102_frame_t* f, * i; unsigned long lock_flags; + long timeout; int err = 0; if (mutex_lock_interruptible(&cam->fileop_mutex)) @@ -1592,20 +1599,22 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) { + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) { mutex_unlock(&cam->fileop_mutex); - return err; + return timeout; } if (cam->state & DEV_DISCONNECTED) { mutex_unlock(&cam->fileop_mutex); return -ENODEV; } - if (cam->state & DEV_MISCONFIGURED) { + if (!timeout || (cam->state & DEV_MISCONFIGURED)) { mutex_unlock(&cam->fileop_mutex); return -EIO; } @@ -1816,6 +1825,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg) memset(&i, 0, sizeof(i)); strcpy(i.name, "Camera"); + i.type = V4L2_INPUT_TYPE_CAMERA; if (copy_to_user(arg, &i, sizeof(i))) return -EFAULT; @@ -1825,7 +1835,19 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg) static int -sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg) +sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg) +{ + int index = 0; + + if (copy_to_user(arg, &index, sizeof(index))) + return -EFAULT; + + return 0; +} + + +static int +sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg) { int index; @@ -1842,7 +1864,7 @@ sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg) static int sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg) { - struct sn9c102_sensor* s = cam->sensor; + struct sn9c102_sensor* s = &cam->sensor; struct v4l2_queryctrl qc; u8 i; @@ -1864,7 +1886,7 @@ sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg) static int sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg) { - struct sn9c102_sensor* s = cam->sensor; + struct sn9c102_sensor* s = &cam->sensor; struct v4l2_control ctrl; int err = 0; u8 i; @@ -1896,7 +1918,7 @@ exit: static int sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) { - struct sn9c102_sensor* s = cam->sensor; + struct sn9c102_sensor* s = &cam->sensor; struct v4l2_control ctrl; u8 i; int err = 0; @@ -1909,6 +1931,8 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) if (ctrl.id == s->qctrl[i].id) { + if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) + return -EINVAL; if (ctrl.value < s->qctrl[i].minimum || ctrl.value > s->qctrl[i].maximum) return -ERANGE; @@ -1931,7 +1955,7 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) static int sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg) { - struct v4l2_cropcap* cc = &(cam->sensor->cropcap); + struct v4l2_cropcap* cc = &(cam->sensor.cropcap); cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cc->pixelaspect.numerator = 1; @@ -1947,7 +1971,7 @@ sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg) static int sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg) { - struct sn9c102_sensor* s = cam->sensor; + struct sn9c102_sensor* s = &cam->sensor; struct v4l2_crop crop = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, }; @@ -1964,7 +1988,7 @@ sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg) static int sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) { - struct sn9c102_sensor* s = cam->sensor; + struct sn9c102_sensor* s = &cam->sensor; struct v4l2_crop crop; struct v4l2_rect* rect; struct v4l2_rect* bounds = &(s->cropcap.bounds); @@ -2105,7 +2129,7 @@ static int sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) { struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format); + struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); if (copy_from_user(&format, arg, sizeof(format))) return -EFAULT; @@ -2130,7 +2154,7 @@ static int sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, void __user * arg) { - struct sn9c102_sensor* s = cam->sensor; + struct sn9c102_sensor* s = &cam->sensor; struct v4l2_format format; struct v4l2_pix_format* pix; struct v4l2_pix_format* pfmt = &(s->pix_format); @@ -2417,7 +2441,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, struct v4l2_buffer b; struct sn9c102_frame_t *f; unsigned long lock_flags; - int err = 0; + long timeout; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; @@ -2430,16 +2454,18 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, return -EINVAL; if (filp->f_flags & O_NONBLOCK) return -EAGAIN; - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) - return err; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) + return timeout; if (cam->state & DEV_DISCONNECTED) return -ENODEV; - if (cam->state & DEV_MISCONFIGURED) + if (!timeout || (cam->state & DEV_MISCONFIGURED)) return -EIO; } @@ -2571,8 +2597,10 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, return sn9c102_vidioc_enuminput(cam, arg); case VIDIOC_G_INPUT: + return sn9c102_vidioc_g_input(cam, arg); + case VIDIOC_S_INPUT: - return sn9c102_vidioc_gs_input(cam, arg); + return sn9c102_vidioc_s_input(cam, arg); case VIDIOC_QUERYCTRL: return sn9c102_vidioc_query_ctrl(cam, arg); @@ -2752,10 +2780,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) break; } - if (!err && cam->sensor) { - DBG(2, "%s image sensor detected", cam->sensor->name); + if (!err) { + DBG(2, "%s image sensor detected", cam->sensor.name); DBG(3, "Support for %s maintained by %s", - cam->sensor->name, cam->sensor->maintainer); + cam->sensor.name, cam->sensor.maintainer); } else { DBG(1, "No supported image sensor detected"); err = -ENODEV; @@ -2793,6 +2821,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); cam->module_param.force_munmap = force_munmap[dev_nr]; + cam->module_param.frame_timeout = frame_timeout[dev_nr]; dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; @@ -2841,7 +2870,8 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf) sn9c102_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); - wake_up_interruptible(&cam->wait_stream); + wake_up(&cam->wait_stream); + usb_get_dev(cam->usbdev); } else { cam->state |= DEV_DISCONNECTED; sn9c102_release_resources(cam); diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c index 4a36519b5af4..42852b7cb042 100644 --- a/drivers/usb/media/sn9c102_ov7630.c +++ b/drivers/usb/media/sn9c102_ov7630.c @@ -34,8 +34,8 @@ static int ov7630_init(struct sn9c102_device* cam) err += sn9c102_write_reg(cam, 0x0f, 0x18); err += sn9c102_write_reg(cam, 0x50, 0x19); - err += sn9c102_i2c_write(cam, 0x12, 0x8d); - err += sn9c102_i2c_write(cam, 0x11, 0x00); + err += sn9c102_i2c_write(cam, 0x12, 0x80); + err += sn9c102_i2c_write(cam, 0x11, 0x01); err += sn9c102_i2c_write(cam, 0x15, 0x34); err += sn9c102_i2c_write(cam, 0x16, 0x03); err += sn9c102_i2c_write(cam, 0x17, 0x1c); @@ -43,12 +43,14 @@ static int ov7630_init(struct sn9c102_device* cam) err += sn9c102_i2c_write(cam, 0x19, 0x06); err += sn9c102_i2c_write(cam, 0x1a, 0xf6); err += sn9c102_i2c_write(cam, 0x1b, 0x04); - err += sn9c102_i2c_write(cam, 0x20, 0x44); + err += sn9c102_i2c_write(cam, 0x20, 0xf6); err += sn9c102_i2c_write(cam, 0x23, 0xee); err += sn9c102_i2c_write(cam, 0x26, 0xa0); err += sn9c102_i2c_write(cam, 0x27, 0x9a); - err += sn9c102_i2c_write(cam, 0x28, 0x20); + err += sn9c102_i2c_write(cam, 0x28, 0xa0); err += sn9c102_i2c_write(cam, 0x29, 0x30); + err += sn9c102_i2c_write(cam, 0x2a, 0xa0); + err += sn9c102_i2c_write(cam, 0x2b, 0x1f); err += sn9c102_i2c_write(cam, 0x2f, 0x3d); err += sn9c102_i2c_write(cam, 0x30, 0x24); err += sn9c102_i2c_write(cam, 0x32, 0x86); @@ -80,7 +82,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam, err += sn9c102_i2c_write(cam, 0x02, ctrl->value); break; case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x03, ctrl->value); + err += sn9c102_i2c_write(cam, 0x01, ctrl->value); break; case V4L2_CID_GAIN: err += sn9c102_i2c_write(cam, 0x00, ctrl->value); @@ -108,7 +110,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam, err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); break; case V4L2_CID_AUTO_WHITE_BALANCE: - err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09); + err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78); break; case V4L2_CID_AUTOGAIN: err += sn9c102_i2c_write(cam, 0x13, ctrl->value); @@ -371,26 +373,29 @@ static struct sn9c102_sensor ov7630 = { int sn9c102_probe_ov7630(struct sn9c102_device* cam) { + const struct usb_device_id ov7630_id_table[] = { + { USB_DEVICE(0x0c45, 0x602c), }, + { USB_DEVICE(0x0c45, 0x602d), }, + { USB_DEVICE(0x0c45, 0x608f), }, + { USB_DEVICE(0x0c45, 0x60b0), }, + { } + }; int err = 0; - sn9c102_attach_sensor(cam, &ov7630); - - if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c && - le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d && - le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f && - le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0) + if (!sn9c102_match_id(cam, ov7630_id_table)) return -ENODEV; err += sn9c102_write_reg(cam, 0x01, 0x01); err += sn9c102_write_reg(cam, 0x00, 0x01); err += sn9c102_write_reg(cam, 0x28, 0x17); - if (err) return -EIO; - err += sn9c102_i2c_write(cam, 0x0b, 0); + err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0); if (err) return -ENODEV; + sn9c102_attach_sensor(cam, &ov7630); + return 0; } diff --git a/drivers/usb/media/sn9c102_pas202bca.c b/drivers/usb/media/sn9c102_pas202bca.c new file mode 100644 index 000000000000..3453237055bb --- /dev/null +++ b/drivers/usb/media/sn9c102_pas202bca.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera * + * Controllers * + * * + * Copyright (C) 2006 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor pas202bca; + + +static int pas202bca_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x30, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); + + err += sn9c102_i2c_write(cam, 0x02, 0x14); + err += sn9c102_i2c_write(cam, 0x03, 0x40); + err += sn9c102_i2c_write(cam, 0x0d, 0x2c); + err += sn9c102_i2c_write(cam, 0x0e, 0x01); + err += sn9c102_i2c_write(cam, 0x0f, 0xa9); + err += sn9c102_i2c_write(cam, 0x10, 0x08); + err += sn9c102_i2c_write(cam, 0x13, 0x63); + err += sn9c102_i2c_write(cam, 0x15, 0x70); + err += sn9c102_i2c_write(cam, 0x11, 0x01); + + msleep(400); + + return err; +} + + +static int pas202bca_set_pix_format(struct sn9c102_device* cam, + const struct v4l2_pix_format* pix) +{ + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) + err += sn9c102_write_reg(cam, 0x24, 0x17); + else + err += sn9c102_write_reg(cam, 0x20, 0x17); + + return err; +} + + +static int pas202bca_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); + err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); + break; + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x09, ctrl->value); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x07, ctrl->value); + break; + case V4L2_CID_GAIN: + err += sn9c102_i2c_write(cam, 0x10, ctrl->value); + break; + case SN9C102_V4L2_CID_GREEN_BALANCE: + err += sn9c102_i2c_write(cam, 0x08, ctrl->value); + break; + case SN9C102_V4L2_CID_DAC_MAGNITUDE: + err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); + break; + default: + return -EINVAL; + } + err += sn9c102_i2c_write(cam, 0x11, 0x01); + + return err ? -EIO : 0; +} + + +static int pas202bca_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &pas202bca; + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static struct sn9c102_sensor pas202bca = { + .name = "PAS202BCA", + .maintainer = "Luca Risolia ", + .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, + .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x40, + .init = &pas202bca_init, + .qctrl = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x01e5, + .maximum = 0x3fff, + .step = 0x0001, + .default_value = 0x01e5, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x0c, + .flags = 0, + }, + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x05, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_GREEN_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DAC magnitude", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x04, + .flags = 0, + }, + }, + .set_ctrl = &pas202bca_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &pas202bca_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &pas202bca_set_pix_format +}; + + +int sn9c102_probe_pas202bca(struct sn9c102_device* cam) +{ + const struct usb_device_id pas202bca_id_table[] = { + { USB_DEVICE(0x0c45, 0x60af), }, + { } + }; + int err = 0; + + if (!sn9c102_match_id(cam,pas202bca_id_table)) + return -ENODEV; + + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x40, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); + if (err) + return -EIO; + + if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */ + return -ENODEV; + + sn9c102_attach_sensor(cam, &pas202bca); + + return 0; +} diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c index 5ca54c7daaf2..d068616ab337 100644 --- a/drivers/usb/media/sn9c102_pas202bcb.c +++ b/drivers/usb/media/sn9c102_pas202bcb.c @@ -263,7 +263,7 @@ static struct sn9c102_sensor pas202bcb = { int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) -{ +{ int r0 = 0, r1 = 0, err = 0; unsigned int pid = 0; diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h index 7d953b24f2f2..2afd9e9d09bb 100644 --- a/drivers/usb/media/sn9c102_sensor.h +++ b/drivers/usb/media/sn9c102_sensor.h @@ -66,6 +66,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); +extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam); extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); @@ -81,12 +82,17 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \ + &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \ &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ NULL, \ }; +/* Device identification */ +extern struct sn9c102_device* +sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); + /* Attach a probed sensor to the camera. */ extern void sn9c102_attach_sensor(struct sn9c102_device* cam, @@ -108,6 +114,7 @@ sn9c102_attach_sensor(struct sn9c102_device* cam, static const struct usb_device_id sn9c102_id_table[] = { \ { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \ { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \ + { USB_DEVICE(0x0c45, 0x6007), }, \ { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \ { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \ { USB_DEVICE(0x0c45, 0x6024), }, \ @@ -126,7 +133,7 @@ static const struct usb_device_id sn9c102_id_table[] = { \ { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \ { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \ { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */ \ + { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \ { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \ { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \ { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \ @@ -359,12 +366,6 @@ struct sn9c102_sensor { error code without rolling back. */ - const struct usb_device* usbdev; - /* - Points to the usb_device struct after the sensor is attached. - Do not touch unless you know what you are doing. - */ - /* Do NOT write to the data below, it's READ ONLY. It is used by the core module to store successfully updated values of the above diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c index 32ddf236cafe..2e08c552f40a 100644 --- a/drivers/usb/media/sn9c102_tas5110c1b.c +++ b/drivers/usb/media/sn9c102_tas5110c1b.c @@ -142,14 +142,18 @@ static struct sn9c102_sensor tas5110c1b = { int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) { - /* This sensor has no identifiers, so let's attach it anyway */ - sn9c102_attach_sensor(cam, &tas5110c1b); + const struct usb_device_id tas5110c1b_id_table[] = { + { USB_DEVICE(0x0c45, 0x6001), }, + { USB_DEVICE(0x0c45, 0x6005), }, + { USB_DEVICE(0x0c45, 0x60ab), }, + { } + }; /* Sensor detection is based on USB pid/vid */ - if (le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6001 && - le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6005 && - le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x60ab) + if (!sn9c102_match_id(cam, tas5110c1b_id_table)) return -ENODEV; + sn9c102_attach_sensor(cam, &tas5110c1b); + return 0; } diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c index a0728f0ae00c..c7b339740bbf 100644 --- a/drivers/usb/media/sn9c102_tas5130d1b.c +++ b/drivers/usb/media/sn9c102_tas5130d1b.c @@ -153,13 +153,17 @@ static struct sn9c102_sensor tas5130d1b = { int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) { - /* This sensor has no identifiers, so let's attach it anyway */ - sn9c102_attach_sensor(cam, &tas5130d1b); + const struct usb_device_id tas5130d1b_id_table[] = { + { USB_DEVICE(0x0c45, 0x6025), }, + { USB_DEVICE(0x0c45, 0x60aa), }, + { } + }; /* Sensor detection is based on USB pid/vid */ - if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6025 && - le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x60aa) + if (!sn9c102_match_id(cam, tas5130d1b_id_table)) return -ENODEV; + sn9c102_attach_sensor(cam, &tas5130d1b); + return 0; } -- cgit v1.2.2 From ccad7789d5e557644d1c866b018394872af0ec5b Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Sat, 25 Feb 2006 06:54:18 +0000 Subject: [PATCH] USB: ET61X[12]51 driver updates USB: ET61X[12]51 driver updates Changes: + new, - removed, * cleanup, @ bugfix @ Fix stream_interrupt() @ Fix vidioc_enum_input() and split vidioc_gs_input() @ Need usb_get|put_dev() when disconnecting, if the device is open * Use wait_event_interruptible_timeout() instead of wait_event_interruptible() when waiting for video frames * replace wake_up_interruptible(&wait_stream) with wake_up(&wait_stream) * Cleanups and updates in the documentation * Use mutexes instead of semaphores + Use per-device sensor structures + Add support for PAS202BCA image sensors + Add frame_timeout module parameter Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/et61x251.h | 28 ++- drivers/usb/media/et61x251_core.c | 321 +++++++++++++++++--------------- drivers/usb/media/et61x251_sensor.h | 5 +- drivers/usb/media/et61x251_tas5130d1b.c | 10 +- 4 files changed, 204 insertions(+), 160 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/et61x251.h b/drivers/usb/media/et61x251.h index 652238f329f3..eee8afc9be72 100644 --- a/drivers/usb/media/et61x251.h +++ b/drivers/usb/media/et61x251.h @@ -33,7 +33,9 @@ #include #include #include -#include +#include +#include +#include #include "et61x251_sensor.h" @@ -51,6 +53,7 @@ #define ET61X251_ALTERNATE_SETTING 13 #define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS) #define ET61X251_CTRL_TIMEOUT 100 +#define ET61X251_FRAME_TIMEOUT 2 /*****************************************************************************/ @@ -127,15 +130,16 @@ struct et61x251_sysfs_attr { struct et61x251_module_param { u8 force_munmap; + u16 frame_timeout; }; -static DECLARE_MUTEX(et61x251_sysfs_lock); +static DEFINE_MUTEX(et61x251_sysfs_lock); static DECLARE_RWSEM(et61x251_disconnect); struct et61x251_device { struct video_device* v4ldev; - struct et61x251_sensor* sensor; + struct et61x251_sensor sensor; struct usb_device* usbdev; struct urb* urb[ET61X251_URBS]; @@ -157,19 +161,28 @@ struct et61x251_device { enum et61x251_dev_state state; u8 users; - struct semaphore dev_sem, fileop_sem; + struct mutex dev_mutex, fileop_mutex; spinlock_t queue_lock; wait_queue_head_t open, wait_frame, wait_stream; }; /*****************************************************************************/ +struct et61x251_device* +et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id) +{ + if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) + return cam; + + return NULL; +} + + void et61x251_attach_sensor(struct et61x251_device* cam, struct et61x251_sensor* sensor) { - cam->sensor = sensor; - cam->sensor->usbdev = cam->usbdev; + memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor)); } /*****************************************************************************/ @@ -212,7 +225,8 @@ do { \ #undef PDBG #define PDBG(fmt, args...) \ -dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args) +dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ + __FUNCTION__, __LINE__ , ## args) #undef PDBGG #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ diff --git a/drivers/usb/media/et61x251_core.c b/drivers/usb/media/et61x251_core.c index 2c0171a5ad62..7cc01b828b3d 100644 --- a/drivers/usb/media/et61x251_core.c +++ b/drivers/usb/media/et61x251_core.c @@ -25,11 +25,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -50,8 +48,8 @@ #define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia" #define ET61X251_AUTHOR_EMAIL "" #define ET61X251_MODULE_LICENSE "GPL" -#define ET61X251_MODULE_VERSION "1:1.01" -#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1) +#define ET61X251_MODULE_VERSION "1:1.02" +#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2) /*****************************************************************************/ @@ -90,6 +88,16 @@ MODULE_PARM_DESC(force_munmap, "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." "\n"); +static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] = + ET61X251_FRAME_TIMEOUT}; +module_param_array(frame_timeout, uint, NULL, 0644); +MODULE_PARM_DESC(frame_timeout, + "\n Timeout for a video frame in seconds." + "\nThis parameter is specific for each detected camera." + "\nDefault value is " + __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"." + "\n"); + #ifdef ET61X251_DEBUG static unsigned short debug = ET61X251_DEBUG_LEVEL; module_param(debug, ushort, 0644); @@ -111,8 +119,8 @@ static u32 et61x251_request_buffers(struct et61x251_device* cam, u32 count, enum et61x251_io_method io) { - struct v4l2_pix_format* p = &(cam->sensor->pix_format); - struct v4l2_rect* r = &(cam->sensor->cropcap.bounds); + struct v4l2_pix_format* p = &(cam->sensor.pix_format); + struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); const size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? (p->width * p->height * p->priv) / 8 : @@ -268,8 +276,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam, int err = 0, res; data[0] = address; - data[1] = cam->sensor->i2c_slave_id; - data[2] = cam->sensor->rsta | 0x10; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x10; data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); @@ -301,8 +309,8 @@ et61x251_i2c_try_write(struct et61x251_device* cam, int err = 0, res; data[0] = address; - data[1] = cam->sensor->i2c_slave_id; - data[2] = cam->sensor->rsta | 0x12; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x12; res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); if (res < 0) @@ -334,9 +342,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, u8* data = cam->control_buffer; int err = 0, res; - if (!cam->sensor) - return -1; - data[0] = data2; data[1] = data3; data[2] = data4; @@ -350,8 +355,8 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, err += res; data[0] = address; - data[1] = cam->sensor->i2c_slave_id; - data[2] = cam->sensor->rsta | 0x02 | (n << 4); + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x02 | (n << 4); res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); if (res < 0) @@ -364,11 +369,11 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, if (res < 0) err += res; - err += et61x251_i2c_wait(cam, cam->sensor); + err += et61x251_i2c_wait(cam, &cam->sensor); if (err) DBG(3, "I2C raw write failed for %s image sensor", - cam->sensor->name); + cam->sensor.name); PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, " "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X," @@ -382,19 +387,13 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, int et61x251_i2c_read(struct et61x251_device* cam, u8 address) { - if (!cam->sensor) - return -1; - - return et61x251_i2c_try_read(cam, cam->sensor, address); + return et61x251_i2c_try_read(cam, &cam->sensor, address); } int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) { - if (!cam->sensor) - return -1; - - return et61x251_i2c_try_write(cam, cam->sensor, address, value); + return et61x251_i2c_try_write(cam, &cam->sensor, address, value); } /*****************************************************************************/ @@ -417,7 +416,7 @@ static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs) if ((*f)) (*f)->state = F_QUEUED; DBG(3, "Stream interrupted"); - wake_up_interruptible(&cam->wait_stream); + wake_up(&cam->wait_stream); } if (cam->state & DEV_DISCONNECTED) @@ -435,9 +434,9 @@ static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs) (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t, frame); - imagesize = (cam->sensor->pix_format.width * - cam->sensor->pix_format.height * - cam->sensor->pix_format.priv) / 8; + imagesize = (cam->sensor.pix_format.width * + cam->sensor.pix_format.height * + cam->sensor.pix_format.priv) / 8; for (i = 0; i < urb->number_of_packets; i++) { unsigned int len, status; @@ -476,7 +475,7 @@ start_of_frame: if ((*f)->state == F_GRABBING) { if (sof && (*f)->buf.bytesused) { - if (cam->sensor->pix_format.pixelformat == + if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) goto end_of_frame; else { @@ -521,7 +520,7 @@ end_of_frame: goto resubmit_urb; if (sof && - cam->sensor->pix_format.pixelformat == + cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) goto start_of_frame; } @@ -650,21 +649,21 @@ static int et61x251_stop_transfer(struct et61x251_device* cam) static int et61x251_stream_interrupt(struct et61x251_device* cam) { - int err = 0; + long timeout; cam->stream = STREAM_INTERRUPT; - err = wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - ET61X251_URB_TIMEOUT); + timeout = wait_event_timeout(cam->wait_stream, + (cam->stream == STREAM_OFF) || + (cam->state & DEV_DISCONNECTED), + ET61X251_URB_TIMEOUT); if (cam->state & DEV_DISCONNECTED) return -ENODEV; - else if (err) { + else if (cam->stream != STREAM_OFF) { cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. To " "use it, close and open /dev/video%d again.", cam->v4ldev->minor); - return err; + return -EIO; } return 0; @@ -709,18 +708,18 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) struct et61x251_device* cam; ssize_t count; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } count = sprintf(buf, "%u\n", cam->sysfs.reg); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -733,18 +732,18 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) u8 index; ssize_t count; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } index = et61x251_strtou8(buf, len, &count); if (index > 0x8e || !count) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EINVAL; } @@ -753,7 +752,7 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg); DBG(3, "Written bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -765,17 +764,17 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf) ssize_t count; int val; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EIO; } @@ -783,7 +782,7 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -797,24 +796,24 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len) ssize_t count; int err; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } value = et61x251_strtou8(buf, len, &count); if (!count) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EINVAL; } err = et61x251_write_reg(cam, value, cam->sysfs.reg); if (err) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EIO; } @@ -822,7 +821,7 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len) cam->sysfs.reg, value); DBG(3, "Written bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -833,12 +832,12 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) struct et61x251_device* cam; ssize_t count; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } @@ -846,7 +845,7 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -859,18 +858,18 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) u8 index; ssize_t count; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } index = et61x251_strtou8(buf, len, &count); if (!count) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EINVAL; } @@ -879,7 +878,7 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); DBG(3, "Written bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -891,22 +890,22 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) ssize_t count; int val; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } - if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) { - up(&et61x251_sysfs_lock); + if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { + mutex_unlock(&et61x251_sysfs_lock); return -ENOSYS; } if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EIO; } @@ -914,7 +913,7 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) DBG(3, "Read bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -928,29 +927,29 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) ssize_t count; int err; - if (down_interruptible(&et61x251_sysfs_lock)) + if (mutex_lock_interruptible(&et61x251_sysfs_lock)) return -ERESTARTSYS; cam = video_get_drvdata(to_video_device(cd)); if (!cam) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -ENODEV; } - if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) { - up(&et61x251_sysfs_lock); + if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { + mutex_unlock(&et61x251_sysfs_lock); return -ENOSYS; } value = et61x251_strtou8(buf, len, &count); if (!count) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EINVAL; } err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value); if (err) { - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return -EIO; } @@ -958,7 +957,7 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) cam->sysfs.i2c_reg, value); DBG(3, "Written bytes: %zd", count); - up(&et61x251_sysfs_lock); + mutex_unlock(&et61x251_sysfs_lock); return count; } @@ -980,7 +979,7 @@ static void et61x251_create_sysfs(struct et61x251_device* cam) video_device_create_file(v4ldev, &class_device_attr_reg); video_device_create_file(v4ldev, &class_device_attr_val); - if (cam->sensor && cam->sensor->sysfs_ops) { + if (cam->sensor.sysfs_ops) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); video_device_create_file(v4ldev, &class_device_attr_i2c_val); } @@ -1048,7 +1047,7 @@ static int et61x251_set_scale(struct et61x251_device* cam, u8 scale) static int et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left + s->active_pixel.left), fmw_sy = (u16)(rect->top - s->cropcap.bounds.top + @@ -1076,7 +1075,7 @@ et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) static int et61x251_init(struct et61x251_device* cam) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_control ctrl; struct v4l2_queryctrl *qctrl; struct v4l2_rect* rect; @@ -1143,7 +1142,7 @@ static int et61x251_init(struct et61x251_device* cam) } if (!(cam->state & DEV_INITIALIZED)) { - init_MUTEX(&cam->fileop_sem); + mutex_init(&cam->fileop_mutex); spin_lock_init(&cam->queue_lock); init_waitqueue_head(&cam->wait_frame); init_waitqueue_head(&cam->wait_stream); @@ -1161,13 +1160,15 @@ static int et61x251_init(struct et61x251_device* cam) static void et61x251_release_resources(struct et61x251_device* cam) { - down(&et61x251_sysfs_lock); + mutex_lock(&et61x251_sysfs_lock); DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); - up(&et61x251_sysfs_lock); + usb_put_dev(cam->usbdev); + + mutex_unlock(&et61x251_sysfs_lock); kfree(cam->control_buffer); } @@ -1188,7 +1189,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) cam = video_get_drvdata(video_devdata(filp)); - if (down_interruptible(&cam->dev_sem)) { + if (mutex_lock_interruptible(&cam->dev_mutex)) { up_read(&et61x251_disconnect); return -ERESTARTSYS; } @@ -1200,7 +1201,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) err = -EWOULDBLOCK; goto out; } - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); err = wait_event_interruptible_exclusive(cam->open, cam->state & DEV_DISCONNECTED || !cam->users); @@ -1212,7 +1213,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) up_read(&et61x251_disconnect); return -ENODEV; } - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); } @@ -1240,7 +1241,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); out: - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); up_read(&et61x251_disconnect); return err; } @@ -1250,7 +1251,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) { struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - down(&cam->dev_sem); /* prevent disconnect() to be called */ + mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ et61x251_stop_transfer(cam); @@ -1258,7 +1259,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) if (cam->state & DEV_DISCONNECTED) { et61x251_release_resources(cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); kfree(cam); return 0; } @@ -1268,7 +1269,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); return 0; } @@ -1281,28 +1282,29 @@ et61x251_read(struct file* filp, char __user * buf, struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); struct et61x251_frame_t* f, * i; unsigned long lock_flags; + long timeout; int err = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } if (cam->io == IO_MMAP) { DBG(3, "Close and open the device again to choose the read " "method"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } @@ -1310,7 +1312,7 @@ et61x251_read(struct file* filp, char __user * buf, if (!et61x251_request_buffers(cam, cam->nreadbuffers, IO_READ)) { DBG(1, "read() failed, not enough memory"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENOMEM; } cam->io = IO_READ; @@ -1324,30 +1326,32 @@ et61x251_read(struct file* filp, char __user * buf, } if (!count) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return 0; } if (list_empty(&cam->outqueue)) { if (filp->f_flags & O_NONBLOCK) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) { - up(&cam->fileop_sem); - return err; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) { + mutex_unlock(&cam->fileop_mutex); + return timeout; } if (cam->state & DEV_DISCONNECTED) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } - if (cam->state & DEV_MISCONFIGURED) { - up(&cam->fileop_sem); + if (!timeout || (cam->state & DEV_MISCONFIGURED)) { + mutex_unlock(&cam->fileop_mutex); return -EIO; } } @@ -1375,7 +1379,7 @@ exit: PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index, count); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return err ? err : count; } @@ -1388,7 +1392,7 @@ static unsigned int et61x251_poll(struct file *filp, poll_table *wait) unsigned long lock_flags; unsigned int mask = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return POLLERR; if (cam->state & DEV_DISCONNECTED) { @@ -1426,12 +1430,12 @@ static unsigned int et61x251_poll(struct file *filp, poll_table *wait) if (!list_empty(&cam->outqueue)) mask |= POLLIN | POLLRDNORM; - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return mask; error: - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return POLLERR; } @@ -1465,25 +1469,25 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) void *pos; u32 i; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(cam->frame[0].buf.length)) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } @@ -1492,7 +1496,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) break; } if (i == cam->nbuffers) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EINVAL; } @@ -1502,7 +1506,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) pos = cam->frame[i].bufmem; while (size > 0) { /* size is page-aligned */ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EAGAIN; } start += PAGE_SIZE; @@ -1515,7 +1519,7 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) et61x251_vm_open(vma); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return 0; } @@ -1557,6 +1561,7 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) memset(&i, 0, sizeof(i)); strcpy(i.name, "Camera"); + i.type = V4L2_INPUT_TYPE_CAMERA; if (copy_to_user(arg, &i, sizeof(i))) return -EFAULT; @@ -1566,7 +1571,19 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) static int -et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg) +et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg) +{ + int index = 0; + + if (copy_to_user(arg, &index, sizeof(index))) + return -EFAULT; + + return 0; +} + + +static int +et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg) { int index; @@ -1583,7 +1600,7 @@ et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_queryctrl qc; u8 i; @@ -1605,7 +1622,7 @@ et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_control ctrl; int err = 0; u8 i; @@ -1637,7 +1654,7 @@ exit: static int et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_control ctrl; u8 i; int err = 0; @@ -1650,6 +1667,8 @@ et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) if (ctrl.id == s->qctrl[i].id) { + if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) + return -EINVAL; if (ctrl.value < s->qctrl[i].minimum || ctrl.value > s->qctrl[i].maximum) return -ERANGE; @@ -1669,7 +1688,7 @@ et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) { - struct v4l2_cropcap* cc = &(cam->sensor->cropcap); + struct v4l2_cropcap* cc = &(cam->sensor.cropcap); cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cc->pixelaspect.numerator = 1; @@ -1685,7 +1704,7 @@ et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_crop crop = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, }; @@ -1702,7 +1721,7 @@ et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) static int et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_crop crop; struct v4l2_rect* rect; struct v4l2_rect* bounds = &(s->cropcap.bounds); @@ -1843,7 +1862,7 @@ static int et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg) { struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format); + struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); if (copy_from_user(&format, arg, sizeof(format))) return -EFAULT; @@ -1868,7 +1887,7 @@ static int et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, void __user * arg) { - struct et61x251_sensor* s = cam->sensor; + struct et61x251_sensor* s = &cam->sensor; struct v4l2_format format; struct v4l2_pix_format* pix; struct v4l2_pix_format* pfmt = &(s->pix_format); @@ -2155,7 +2174,7 @@ et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, struct v4l2_buffer b; struct et61x251_frame_t *f; unsigned long lock_flags; - int err = 0; + long timeout; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; @@ -2168,16 +2187,18 @@ et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, return -EINVAL; if (filp->f_flags & O_NONBLOCK) return -EAGAIN; - err = wait_event_interruptible - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED) ); - if (err) - return err; + timeout = wait_event_interruptible_timeout + ( cam->wait_frame, + (!list_empty(&cam->outqueue)) || + (cam->state & DEV_DISCONNECTED) || + (cam->state & DEV_MISCONFIGURED), + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); + if (timeout < 0) + return timeout; if (cam->state & DEV_DISCONNECTED) return -ENODEV; - if (cam->state & DEV_MISCONFIGURED) + if (!timeout || (cam->state & DEV_MISCONFIGURED)) return -EIO; } @@ -2309,8 +2330,10 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp, return et61x251_vidioc_enuminput(cam, arg); case VIDIOC_G_INPUT: + return et61x251_vidioc_g_input(cam, arg); + case VIDIOC_S_INPUT: - return et61x251_vidioc_gs_input(cam, arg); + return et61x251_vidioc_s_input(cam, arg); case VIDIOC_QUERYCTRL: return et61x251_vidioc_query_ctrl(cam, arg); @@ -2393,19 +2416,19 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp, struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); int err = 0; - if (down_interruptible(&cam->fileop_sem)) + if (mutex_lock_interruptible(&cam->fileop_mutex)) return -ERESTARTSYS; if (cam->state & DEV_DISCONNECTED) { DBG(1, "Device not present"); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -ENODEV; } if (cam->state & DEV_MISCONFIGURED) { DBG(1, "The camera is misconfigured. Close and open it " "again."); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return -EIO; } @@ -2413,7 +2436,7 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp, err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); - up(&cam->fileop_sem); + mutex_unlock(&cam->fileop_mutex); return err; } @@ -2459,7 +2482,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - init_MUTEX(&cam->dev_sem); + mutex_init(&cam->dev_mutex); DBG(2, "ET61X[12]51 PC Camera Controller detected " "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); @@ -2470,8 +2493,8 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) break; } - if (!err && cam->sensor) - DBG(2, "%s image sensor detected", cam->sensor->name); + if (!err) + DBG(2, "%s image sensor detected", cam->sensor.name); else { DBG(1, "No supported image sensor detected"); err = -ENODEV; @@ -2492,7 +2515,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, video_nr[dev_nr]); @@ -2502,13 +2525,14 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "Free /dev/videoX node not found"); video_nr[dev_nr] = -1; dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); goto fail; } DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); cam->module_param.force_munmap = force_munmap[dev_nr]; + cam->module_param.frame_timeout = frame_timeout[dev_nr]; dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; @@ -2519,7 +2543,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) usb_set_intfdata(intf, cam); - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); return 0; @@ -2543,7 +2567,7 @@ static void et61x251_usb_disconnect(struct usb_interface* intf) down_write(&et61x251_disconnect); - down(&cam->dev_sem); + mutex_lock(&cam->dev_mutex); DBG(2, "Disconnecting %s...", cam->v4ldev->name); @@ -2557,13 +2581,14 @@ static void et61x251_usb_disconnect(struct usb_interface* intf) et61x251_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); - wake_up_interruptible(&cam->wait_stream); + wake_up(&cam->wait_stream); + usb_get_dev(cam->usbdev); } else { cam->state |= DEV_DISCONNECTED; et61x251_release_resources(cam); } - up(&cam->dev_sem); + mutex_unlock(&cam->dev_mutex); if (!cam->users) kfree(cam); diff --git a/drivers/usb/media/et61x251_sensor.h b/drivers/usb/media/et61x251_sensor.h index b9df91062fc0..56841ae8a207 100644 --- a/drivers/usb/media/et61x251_sensor.h +++ b/drivers/usb/media/et61x251_sensor.h @@ -42,6 +42,9 @@ static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \ NULL, \ }; +extern struct et61x251_device* +et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id); + extern void et61x251_attach_sensor(struct et61x251_device* cam, struct et61x251_sensor* sensor); @@ -105,8 +108,6 @@ struct et61x251_sensor { int (*set_pix_format)(struct et61x251_device* cam, const struct v4l2_pix_format* pix); - const struct usb_device* usbdev; - /* Private */ struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS]; struct v4l2_rect _rect; diff --git a/drivers/usb/media/et61x251_tas5130d1b.c b/drivers/usb/media/et61x251_tas5130d1b.c index 65f1ae9cf2b3..3998d76a307a 100644 --- a/drivers/usb/media/et61x251_tas5130d1b.c +++ b/drivers/usb/media/et61x251_tas5130d1b.c @@ -126,12 +126,16 @@ static struct et61x251_sensor tas5130d1b = { int et61x251_probe_tas5130d1b(struct et61x251_device* cam) { - /* This sensor has no identifiers, so let's attach it anyway */ - et61x251_attach_sensor(cam, &tas5130d1b); + const struct usb_device_id tas5130d1b_id_table[] = { + { USB_DEVICE(0x102c, 0x6251), }, + { } + }; /* Sensor detection is based on USB pid/vid */ - if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6251) + if (!et61x251_match_id(cam, tas5130d1b_id_table)) return -ENODEV; + et61x251_attach_sensor(cam, &tas5130d1b); + return 0; } -- cgit v1.2.2 From a847423905c6a8ccd6671d05f5877d893d10cd9f Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Sat, 25 Feb 2006 06:57:49 +0000 Subject: [PATCH] USB: ZC0301 driver updates ZC0301 driver updates. Changes: + new, - removed, * cleanup, @ bugfix @ Need usb_get|put_dev() when disconnecting, if the device is open * Cleanups and updates in the documentation + Use per-device sensor structures + Add frame_timeout module parameter Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/zc0301.h | 20 +++++++++---- drivers/usb/media/zc0301_core.c | 58 ++++++++++++++++++++++-------------- drivers/usb/media/zc0301_pas202bcb.c | 38 +++++++++++++---------- drivers/usb/media/zc0301_sensor.h | 25 +++++++++------- 4 files changed, 89 insertions(+), 52 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h index cb1a0823bc63..9ba9135e824b 100644 --- a/drivers/usb/media/zc0301.h +++ b/drivers/usb/media/zc0301.h @@ -34,7 +34,8 @@ #include #include #include -#include +#include +#include #include "zc0301_sensor.h" @@ -51,7 +52,7 @@ #define ZC0301_ALTERNATE_SETTING 7 #define ZC0301_URB_TIMEOUT msecs_to_jiffies(2 * ZC0301_ISO_PACKETS) #define ZC0301_CTRL_TIMEOUT 100 -#define ZC0301_FRAME_TIMEOUT 2 * 1000 * msecs_to_jiffies(1) +#define ZC0301_FRAME_TIMEOUT 2 /*****************************************************************************/ @@ -94,6 +95,7 @@ enum zc0301_stream_state { struct zc0301_module_param { u8 force_munmap; + u16 frame_timeout; }; static DECLARE_RWSEM(zc0301_disconnect); @@ -101,7 +103,7 @@ static DECLARE_RWSEM(zc0301_disconnect); struct zc0301_device { struct video_device* v4ldev; - struct zc0301_sensor* sensor; + struct zc0301_sensor sensor; struct usb_device* usbdev; struct urb* urb[ZC0301_URBS]; @@ -129,11 +131,19 @@ struct zc0301_device { /*****************************************************************************/ +struct zc0301_device* +zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id) +{ + if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) + return cam; + + return NULL; +} + void zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor) { - cam->sensor = sensor; - cam->sensor->usbdev = cam->usbdev; + memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor)); } /*****************************************************************************/ diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c index 7e8b1676d144..5773688d3dae 100644 --- a/drivers/usb/media/zc0301_core.c +++ b/drivers/usb/media/zc0301_core.c @@ -29,11 +29,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -54,8 +52,8 @@ #define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia" #define ZC0301_AUTHOR_EMAIL "" #define ZC0301_MODULE_LICENSE "GPL" -#define ZC0301_MODULE_VERSION "1:1.01" -#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1) +#define ZC0301_MODULE_VERSION "1:1.02" +#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2) /*****************************************************************************/ @@ -94,6 +92,15 @@ MODULE_PARM_DESC(force_munmap, "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." "\n"); +static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] = + ZC0301_FRAME_TIMEOUT}; +module_param_array(frame_timeout, uint, NULL, 0644); +MODULE_PARM_DESC(frame_timeout, + "\n Timeout for a video frame in seconds." + "\nThis parameter is specific for each detected camera." + "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"." + "\n"); + #ifdef ZC0301_DEBUG static unsigned short debug = ZC0301_DEBUG_LEVEL; module_param(debug, ushort, 0644); @@ -115,8 +122,8 @@ static u32 zc0301_request_buffers(struct zc0301_device* cam, u32 count, enum zc0301_io_method io) { - struct v4l2_pix_format* p = &(cam->sensor->pix_format); - struct v4l2_rect* r = &(cam->sensor->cropcap.bounds); + struct v4l2_pix_format* p = &(cam->sensor.pix_format); + struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); const size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? (p->width * p->height * p->priv) / 8 : @@ -332,9 +339,9 @@ static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs) (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t, frame); - imagesize = (cam->sensor->pix_format.width * - cam->sensor->pix_format.height * - cam->sensor->pix_format.priv) / 8; + imagesize = (cam->sensor.pix_format.width * + cam->sensor.pix_format.height * + cam->sensor.pix_format.priv) / 8; for (i = 0; i < urb->number_of_packets; i++) { unsigned int len, status; @@ -555,7 +562,7 @@ zc0301_set_compression(struct zc0301_device* cam, static int zc0301_init(struct zc0301_device* cam) { - struct zc0301_sensor* s = cam->sensor; + struct zc0301_sensor* s = &cam->sensor; struct v4l2_control ctrl; struct v4l2_queryctrl *qctrl; struct v4l2_rect* rect; @@ -630,6 +637,7 @@ static void zc0301_release_resources(struct zc0301_device* cam) DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); + usb_put_dev(cam->usbdev); kfree(cam->control_buffer); } @@ -798,7 +806,8 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) (!list_empty(&cam->outqueue)) || (cam->state & DEV_DISCONNECTED) || (cam->state & DEV_MISCONFIGURED), - ZC0301_FRAME_TIMEOUT ); + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); if (timeout < 0) { mutex_unlock(&cam->fileop_mutex); return timeout; @@ -1056,7 +1065,7 @@ zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg) static int zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg) { - struct zc0301_sensor* s = cam->sensor; + struct zc0301_sensor* s = &cam->sensor; struct v4l2_queryctrl qc; u8 i; @@ -1078,7 +1087,7 @@ zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg) static int zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg) { - struct zc0301_sensor* s = cam->sensor; + struct zc0301_sensor* s = &cam->sensor; struct v4l2_control ctrl; int err = 0; u8 i; @@ -1110,7 +1119,7 @@ exit: static int zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg) { - struct zc0301_sensor* s = cam->sensor; + struct zc0301_sensor* s = &cam->sensor; struct v4l2_control ctrl; u8 i; int err = 0; @@ -1123,6 +1132,8 @@ zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg) for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) if (ctrl.id == s->qctrl[i].id) { + if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) + return -EINVAL; if (ctrl.value < s->qctrl[i].minimum || ctrl.value > s->qctrl[i].maximum) return -ERANGE; @@ -1142,7 +1153,7 @@ zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg) static int zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg) { - struct v4l2_cropcap* cc = &(cam->sensor->cropcap); + struct v4l2_cropcap* cc = &(cam->sensor.cropcap); cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cc->pixelaspect.numerator = 1; @@ -1158,7 +1169,7 @@ zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg) static int zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg) { - struct zc0301_sensor* s = cam->sensor; + struct zc0301_sensor* s = &cam->sensor; struct v4l2_crop crop = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, }; @@ -1175,7 +1186,7 @@ zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg) static int zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) { - struct zc0301_sensor* s = cam->sensor; + struct zc0301_sensor* s = &cam->sensor; struct v4l2_crop crop; struct v4l2_rect* rect; struct v4l2_rect* bounds = &(s->cropcap.bounds); @@ -1304,7 +1315,7 @@ static int zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg) { struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format); + struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); if (copy_from_user(&format, arg, sizeof(format))) return -EFAULT; @@ -1328,7 +1339,7 @@ static int zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, void __user * arg) { - struct zc0301_sensor* s = cam->sensor; + struct zc0301_sensor* s = &cam->sensor; struct v4l2_format format; struct v4l2_pix_format* pix; struct v4l2_pix_format* pfmt = &(s->pix_format); @@ -1612,7 +1623,8 @@ zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp, (!list_empty(&cam->outqueue)) || (cam->state & DEV_DISCONNECTED) || (cam->state & DEV_MISCONFIGURED), - ZC0301_FRAME_TIMEOUT ); + cam->module_param.frame_timeout * + 1000 * msecs_to_jiffies(1) ); if (timeout < 0) return timeout; if (cam->state & DEV_DISCONNECTED) @@ -1911,8 +1923,8 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) break; } - if (!err && cam->sensor) - DBG(2, "%s image sensor detected", cam->sensor->name); + if (!err) + DBG(2, "%s image sensor detected", cam->sensor.name); else { DBG(1, "No supported image sensor detected"); err = -ENODEV; @@ -1950,6 +1962,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); cam->module_param.force_munmap = force_munmap[dev_nr]; + cam->module_param.frame_timeout = frame_timeout[dev_nr]; dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; @@ -1994,6 +2007,7 @@ static void zc0301_usb_disconnect(struct usb_interface* intf) cam->state |= DEV_DISCONNECTED; wake_up_interruptible(&cam->wait_frame); wake_up(&cam->wait_stream); + usb_get_dev(cam->usbdev); } else { cam->state |= DEV_DISCONNECTED; zc0301_release_resources(cam); diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c index 32b9b9329cbf..9d282a22c15f 100644 --- a/drivers/usb/media/zc0301_pas202bcb.c +++ b/drivers/usb/media/zc0301_pas202bcb.c @@ -22,6 +22,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ***************************************************************************/ +/* + NOTE: Sensor controls are disabled for now, becouse changing them while + streaming sometimes results in out-of-sync video frames. We'll use + the default initialization, until we know how to stop and start video + in the chip. However, the image quality still looks good under various + light conditions. +*/ + #include #include "zc0301_sensor.h" @@ -245,7 +253,7 @@ static struct zc0301_sensor pas202bcb = { .maximum = 0x3fff, .step = 0x0001, .default_value = 0x01e5, - .flags = 0, + .flags = V4L2_CTRL_FLAG_DISABLED, }, { .id = V4L2_CID_GAIN, @@ -255,7 +263,17 @@ static struct zc0301_sensor pas202bcb = { .maximum = 0x1f, .step = 0x01, .default_value = 0x0c, - .flags = 0, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = ZC0301_V4L2_CID_DAC_MAGNITUDE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "DAC magnitude", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x00, + .flags = V4L2_CTRL_FLAG_DISABLED, }, { .id = V4L2_CID_RED_BALANCE, @@ -265,7 +283,7 @@ static struct zc0301_sensor pas202bcb = { .maximum = 0x0f, .step = 0x01, .default_value = 0x01, - .flags = 0, + .flags = V4L2_CTRL_FLAG_DISABLED, }, { .id = V4L2_CID_BLUE_BALANCE, @@ -275,7 +293,7 @@ static struct zc0301_sensor pas202bcb = { .maximum = 0x0f, .step = 0x01, .default_value = 0x05, - .flags = 0, + .flags = V4L2_CTRL_FLAG_DISABLED, }, { .id = ZC0301_V4L2_CID_GREEN_BALANCE, @@ -285,17 +303,7 @@ static struct zc0301_sensor pas202bcb = { .maximum = 0x0f, .step = 0x01, .default_value = 0x00, - .flags = 0, - }, - { - .id = ZC0301_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x04, - .flags = 0, + .flags = V4L2_CTRL_FLAG_DISABLED, }, }, .get_ctrl = &pas202bcb_get_ctrl, diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h index 8890e32405d4..e3cb6cc920ca 100644 --- a/drivers/usb/media/zc0301_sensor.h +++ b/drivers/usb/media/zc0301_sensor.h @@ -43,9 +43,11 @@ static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \ NULL, \ }; +extern struct zc0301_device* +zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id); + extern void -zc0301_attach_sensor(struct zc0301_device* cam, - struct zc0301_sensor* sensor); +zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor); #define ZC0301_USB_DEVICE(vend, prod, intclass) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ @@ -56,7 +58,14 @@ zc0301_attach_sensor(struct zc0301_device* cam, #define ZC0301_ID_TABLE \ static const struct usb_device_id zc0301_id_table[] = { \ + { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \ + { ZC0301_USB_DEVICE(0x041e, 0x0417, 0xff), }, \ + { ZC0301_USB_DEVICE(0x041e, 0x041e, 0xff), }, /* HV7131B */ \ + { ZC0301_USB_DEVICE(0x041e, 0x081c, 0xff), }, /* PAS106 */ \ + { ZC0301_USB_DEVICE(0x041e, 0x0834, 0xff), }, /* PAS106 */ \ + { ZC0301_USB_DEVICE(0x041e, 0x0835, 0xff), }, /* PAS106 */ \ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \ + { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ { } \ }; @@ -80,15 +89,11 @@ struct zc0301_sensor { struct v4l2_cropcap cropcap; struct v4l2_pix_format pix_format; - int (*init)(struct zc0301_device* cam); - int (*get_ctrl)(struct zc0301_device* cam, - struct v4l2_control* ctrl); - int (*set_ctrl)(struct zc0301_device* cam, + int (*init)(struct zc0301_device*); + int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl); + int (*set_ctrl)(struct zc0301_device*, const struct v4l2_control* ctrl); - int (*set_crop)(struct zc0301_device* cam, - const struct v4l2_rect* rect); - - const struct usb_device* usbdev; + int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect); /* Private */ struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS]; -- cgit v1.2.2 From a5c44e29e5637b5e6fe59d225eb4f438688b3849 Mon Sep 17 00:00:00 2001 From: Lonnie Mendez Date: Wed, 1 Mar 2006 10:45:24 -0600 Subject: [PATCH] USB: cypress_m8: add support for the Nokia ca42-version 2 cable This patch adds support for the Nokia ca42 version 2 cable to the cypress_m8 driver. The device was tested by others with this patch and found to be compatible with the cypress_m8 driver. A special note should be taken that this cable seems to vary in the type of chipset used. This patch supports the cable with product id 0x4101. Signed-off-by: Lonnie Mendez Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cypress_m8.c | 70 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/serial/cypress_m8.h | 5 +++ 2 files changed, 75 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 71af3bf5adb7..7212fbe3b6f2 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -98,10 +98,16 @@ static struct usb_device_id id_table_cyphidcomrs232 [] = { { } /* Terminating entry */ }; +static struct usb_device_id id_table_nokiaca42v2 [] = { + { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, + { } /* Terminating entry */ +}; + static struct usb_device_id id_table_combined [] = { { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, + { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, { } /* Terminating entry */ }; @@ -149,6 +155,7 @@ struct cypress_buf { /* function prototypes for the Cypress USB to serial device */ static int cypress_earthmate_startup (struct usb_serial *serial); static int cypress_hidcom_startup (struct usb_serial *serial); +static int cypress_ca42v2_startup (struct usb_serial *serial); static void cypress_shutdown (struct usb_serial *serial); static int cypress_open (struct usb_serial_port *port, struct file *filp); static void cypress_close (struct usb_serial_port *port, struct file *filp); @@ -235,6 +242,34 @@ static struct usb_serial_driver cypress_hidcom_device = { .write_int_callback = cypress_write_int_callback, }; +static struct usb_serial_driver cypress_ca42v2_device = { + .driver = { + .owner = THIS_MODULE, + .name = "nokiaca42v2", + }, + .description = "Nokia CA-42 V2 Adapter", + .id_table = id_table_nokiaca42v2, + .num_interrupt_in = 1, + .num_interrupt_out = 1, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, + .attach = cypress_ca42v2_startup, + .shutdown = cypress_shutdown, + .open = cypress_open, + .close = cypress_close, + .write = cypress_write, + .write_room = cypress_write_room, + .ioctl = cypress_ioctl, + .set_termios = cypress_set_termios, + .tiocmget = cypress_tiocmget, + .tiocmset = cypress_tiocmset, + .chars_in_buffer = cypress_chars_in_buffer, + .throttle = cypress_throttle, + .unthrottle = cypress_unthrottle, + .read_int_callback = cypress_read_int_callback, + .write_int_callback = cypress_write_int_callback, +}; /***************************************************************************** * Cypress serial helper functions @@ -286,6 +321,12 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m __FUNCTION__); new_baudrate = priv->baud_rate; } + } else if (priv->chiptype == CT_CA42V2) { + if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) { + err("%s - failed setting baud rate, unsupported speed", + __FUNCTION__); + new_baudrate = priv->baud_rate; + } } else if (priv->chiptype == CT_GENERIC) { if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) { err("%s - failed setting baud rate, unsupported speed", @@ -499,6 +540,25 @@ static int cypress_hidcom_startup (struct usb_serial *serial) } /* cypress_hidcom_startup */ +static int cypress_ca42v2_startup (struct usb_serial *serial) +{ + struct cypress_private *priv; + + dbg("%s", __FUNCTION__); + + if (generic_startup(serial)) { + dbg("%s - Failed setting up port %d", __FUNCTION__, + serial->port[0]->number); + return 1; + } + + priv = usb_get_serial_port_data(serial->port[0]); + priv->chiptype = CT_CA42V2; + + return 0; +} /* cypress_ca42v2_startup */ + + static void cypress_shutdown (struct usb_serial *serial) { struct cypress_private *priv; @@ -943,6 +1003,10 @@ static void cypress_set_termios (struct usb_serial_port *port, *(tty->termios) = tty_std_termios; tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + } else if (priv->chiptype == CT_CA42V2) { + *(tty->termios) = tty_std_termios; + tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | + CLOCAL; } priv->termios_initialized = 1; } @@ -1541,6 +1605,9 @@ static int __init cypress_init(void) retval = usb_serial_register(&cypress_hidcom_device); if (retval) goto failed_hidcom_register; + retval = usb_serial_register(&cypress_ca42v2_device); + if (retval) + goto failed_ca42v2_register; retval = usb_register(&cypress_driver); if (retval) goto failed_usb_register; @@ -1549,6 +1616,8 @@ static int __init cypress_init(void) return 0; failed_usb_register: usb_deregister(&cypress_driver); +failed_ca42v2_register: + usb_serial_deregister(&cypress_ca42v2_device); failed_hidcom_register: usb_serial_deregister(&cypress_hidcom_device); failed_em_register: @@ -1565,6 +1634,7 @@ static void __exit cypress_exit (void) usb_deregister (&cypress_driver); usb_serial_deregister (&cypress_earthmate_device); usb_serial_deregister (&cypress_hidcom_device); + usb_serial_deregister (&cypress_ca42v2_device); } diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h index 1fa119efe41a..e1c7c27e18b7 100644 --- a/drivers/usb/serial/cypress_m8.h +++ b/drivers/usb/serial/cypress_m8.h @@ -18,6 +18,10 @@ /* Cypress HID->COM RS232 Adapter */ #define VENDOR_ID_CYPRESS 0x04b4 #define PRODUCT_ID_CYPHIDCOM 0x5500 + +/* Nokia CA-42 USB to serial cable */ +#define VENDOR_ID_DAZZLE 0x07d0 +#define PRODUCT_ID_CA42 0x4101 /* End of device listing */ /* Used for setting / requesting serial line settings */ @@ -34,6 +38,7 @@ #define CT_EARTHMATE 0x01 #define CT_CYPHIDCOM 0x02 +#define CT_CA42V2 0x03 #define CT_GENERIC 0x0F /* End of chiptype definitions */ -- cgit v1.2.2 From 96050b11f690878c19c1cd39970ab7325d91e18b Mon Sep 17 00:00:00 2001 From: Julian Bradfield Date: Wed, 1 Mar 2006 10:19:44 +0000 Subject: [PATCH] USB: PL2303 and TIOCMIWAIT A while ago, I posted about TIOCMIWAIT not working with the PL2303 USB-serial adapter. After a brief exchange with Greg, I tracked this to a missing wake-up in the USB interrupt procedures. I got our systems staff to install the enclosed very simple patch to our 2.6.12 kernels, and it all works fine as expected. I guess this should also apply to the latest version and go into the mainstream. Apologies for the long delay in posting the result. The routine being patched is pl2303_update_line_status Signed-off-by: Julian Bradfield Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index cf2213bae0e0..fb3b6b7b9065 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -826,6 +826,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port, spin_lock_irqsave(&priv->lock, flags); priv->line_status = data[status_idx]; spin_unlock_irqrestore(&priv->lock, flags); + wake_up_interruptible (&priv->delta_msr_wait); exit: return; -- cgit v1.2.2 From 491b04ce1c9adfa0cd73f095086f3c37da81b667 Mon Sep 17 00:00:00 2001 From: Dick Streefland Date: Wed, 1 Mar 2006 00:53:33 -0800 Subject: [PATCH] USB: support for USB-to-serial cable from Speed Dragon Multimedia The USB data cable for my Samsung GSM phone contains the USB-to-serial converter chip MS3303H from Speed Dragon Multimedia, Inc. that appears to be compatible with the PL2303 chip. The following patch adds support for this chip to the pl2303 driver. Signed-off-by: Dick Streefland Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index fb3b6b7b9065..b3014fda645c 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -77,6 +77,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, + { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 9bc4755162ad..77901d143979 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -75,3 +75,7 @@ /* Leadtek GPS 9531 (ID 0413:2101) */ #define LEADTEK_VENDOR_ID 0x0413 #define LEADTEK_9531_PRODUCT_ID 0x2101 + +/* USB GSM cable from Speed Dragon Multimedia, Ltd */ +#define SPEEDDRAGON_VENDOR_ID 0x0e55 +#define SPEEDDRAGON_PRODUCT_ID 0x110b -- cgit v1.2.2 From ae55717584431761b70215d3d574c13fe97093f2 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 28 Feb 2006 10:16:12 -0500 Subject: [PATCH] USB: UHCI: Increase port-reset completion delay for HP controllers This patch (as657) increases the port-reset completion delay in uhci-hcd for HP's embedded controllers. Unlike other UHCI controllers, the HP chips can take as long as 250 us to carry out the processing associated with finishing a port reset. This fixes Novell bug #148761. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hub.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index a71e48a66805..152971d16769 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -99,6 +99,21 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, } } +/* Wait for the UHCI controller in HP's iLO2 server management chip. + * It can take up to 250 us to finish a reset and set the CSC bit. + */ +static void wait_for_HP(unsigned long port_addr) +{ + int i; + + for (i = 10; i < 250; i += 10) { + if (inw(port_addr) & USBPORTSC_CSC) + return; + udelay(10); + } + /* Log a warning? */ +} + static void uhci_check_ports(struct uhci_hcd *uhci) { unsigned int port; @@ -113,6 +128,12 @@ static void uhci_check_ports(struct uhci_hcd *uhci) CLR_RH_PORTSTAT(USBPORTSC_PR); udelay(10); + /* HP's server management chip requires + * a longer delay. */ + if (to_pci_dev(uhci_dev(uhci))->vendor == + PCI_VENDOR_ID_HP) + wait_for_HP(port_addr); + /* If the port was enabled before, turning * reset on caused a port enable change. * Turning reset off causes a port connect -- cgit v1.2.2 From 6aa35675bbc370e5f11baae7e01a9ab255d8030c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 8 Mar 2006 15:14:09 -0500 Subject: [PATCH] USB: usbcore: Don't assume a USB configuration includes any interfaces In a couple of places, usbcore assumes that a USB device configuration will have a nonzero number of interfaces. Having no interfaces may or may not be allowed by the USB spec; in any event we shouldn't die if we encounter such a thing. This patch (as662) removes the assumptions. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7dd28f8e1cea..8e65f7a237e4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1179,8 +1179,11 @@ static int choose_configuration(struct usb_device *udev) c = udev->config; num_configs = udev->descriptor.bNumConfigurations; for (i = 0; i < num_configs; (i++, c++)) { - struct usb_interface_descriptor *desc = - &c->intf_cache[0]->altsetting->desc; + struct usb_interface_descriptor *desc = NULL; + + /* It's possible that a config has no interfaces! */ + if (c->desc.bNumInterfaces > 0) + desc = &c->intf_cache[0]->altsetting->desc; /* * HP's USB bus-powered keyboard has only one configuration @@ -1215,7 +1218,8 @@ static int choose_configuration(struct usb_device *udev) /* If the first config's first interface is COMM/2/0xff * (MSFT RNDIS), rule it out unless Linux has host-side * RNDIS support. */ - if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM + if (i == 0 && desc + && desc->bInterfaceClass == USB_CLASS_COMM && desc->bInterfaceSubClass == 2 && desc->bInterfaceProtocol == 0xff) { #ifndef CONFIG_USB_NET_RNDIS @@ -1231,8 +1235,8 @@ static int choose_configuration(struct usb_device *udev) * than a vendor-specific driver. */ else if (udev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC && - desc->bInterfaceClass != - USB_CLASS_VENDOR_SPEC) { + (!desc || desc->bInterfaceClass != + USB_CLASS_VENDOR_SPEC)) { best = c; break; } @@ -3024,7 +3028,7 @@ int usb_reset_device(struct usb_device *udev) parent_hub = hdev_to_hub(parent_hdev); /* If we're resetting an active hub, take some special actions */ - if (udev->actconfig && + if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 && udev->actconfig->interface[0]->dev.driver == &hub_driver.driver && (hub = hdev_to_hub(udev)) != NULL) { -- cgit v1.2.2 From f48219db93eaee644e9fd9f22fb6421f38059cc5 Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Thu, 9 Mar 2006 14:10:49 +0100 Subject: [PATCH] USB: usbcore: usb_set_configuration oops (NULL ptr dereference) When trying to deconfigure a device via usb_set_configuration(dev, 0), 2.6.16-rc kernels after 55c527187c9d78f840b284d596a0b298bc1493af oops with "Unable to handle NULL pointer dereference at...". This is due to an unchecked dereference of cp in the power budget part. Signed-off-by: Horst Schirmeier Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 2f6009b0cffc..08fb20f06f3e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1388,11 +1388,13 @@ free_interfaces: if (dev->state != USB_STATE_ADDRESS) usb_disable_device (dev, 1); // Skip ep0 - i = dev->bus_mA - cp->desc.bMaxPower * 2; - if (i < 0) - dev_warn(&dev->dev, "new config #%d exceeds power " - "limit by %dmA\n", - configuration, -i); + if (cp) { + i = dev->bus_mA - cp->desc.bMaxPower * 2; + if (i < 0) + dev_warn(&dev->dev, "new config #%d exceeds power " + "limit by %dmA\n", + configuration, -i); + } if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, 0, configuration, 0, -- cgit v1.2.2 From b712548c5d88f2e4672f8482c3904e8c5728dbf1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Mar 2006 17:40:08 -0800 Subject: [PATCH] USB: fix initdata issue in isp116x-hcd As found by Sam's scripts. Cc: Sam Ravnborg Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp116x-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index fea5dcbec7c4..e99210b7909b 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1552,7 +1552,7 @@ static struct hc_driver isp116x_hc_driver = { /*----------------------------------------------------------------*/ -static int __init_or_module isp116x_remove(struct platform_device *pdev) +static int isp116x_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct isp116x *isp116x; -- cgit v1.2.2 From 1e7a5a84e407dfa20813a7f55413be8193ee5380 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Sun, 5 Mar 2006 21:36:51 -0800 Subject: [PATCH] USB: storage: sandisk unusual_devices entry The following adds an unusual_devs entry for the SanDisk ImageMate CompactFlash USB drive, for the US_FL_FIX_CAPACITY flag. Additionally, it removes trailing whitespace from the previous entry. It's based on the patch sent by Roman Hodek . Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 31ca92056c27..a0d355831204 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -760,12 +760,19 @@ UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), -UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, +/* Submitted by Roman Hodek */ +UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk", "ImageMate SDDR-05a", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN ), +UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, + "SanDisk Corporation", + "ImageMate CompactFlash USB", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + #ifdef CONFIG_USB_STORAGE_USBAT UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005, "Sandisk", -- cgit v1.2.2 From c713c973fb4bfdb22cce488cca4f9f8006ed58ce Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sun, 5 Mar 2006 21:43:40 -0800 Subject: [PATCH] USB: storage: another unusual_devs.h entry Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index a0d355831204..5d78fb42cb04 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1080,6 +1080,16 @@ UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff, 0), #endif +/* + * Pete Zaitcev , bz#164688. + * The device blatantly ignores LUN and returns 1 in GetMaxLUN. + */ +UNUSUAL_DEV( 0x0c45, 0x1060, 0x0100, 0x0100, + "Unknown", + "Unknown", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_SINGLE_LUN ), + /* Submitted by Joris Struyve */ UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff, "Medion", -- cgit v1.2.2 From 23b7885d50c5f5fe6dca93d4b0913f6e7b878dad Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sun, 5 Mar 2006 21:45:44 -0800 Subject: [PATCH] USB: storage: unusual_devs.h entry 0420:0001 Ref https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=176584 Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 5d78fb42cb04..8310e86d745d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -120,6 +120,12 @@ UNUSUAL_DEV( 0x0419, 0xaaf6, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Pete Zaitcev , bz#176584 */ +UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100, + "GENERIC", "MP3 PLAYER", /* MyMusix PD-205 on the outside. */ + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Reported by Olaf Hering from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", -- cgit v1.2.2 From 9d5847bc1a3977fbfb4057aad41458df89792309 Mon Sep 17 00:00:00 2001 From: Rodolfo Quesada Date: Mon, 6 Mar 2006 10:45:42 -0500 Subject: [PATCH] USB: storage: new unusual_devs.h entry: Mitsumi 7in1 Card Reader This patch (as661) adds an unusual_devs entry for the Mitsumi 7in1 Card Reader. From: Rodolfo Quesada Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 8310e86d745d..c4a9dcff5f2b 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -62,6 +62,13 @@ UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN ), +/* Reported by Rodolfo Quesada */ +UNUSUAL_DEV( 0x03ee, 0x6906, 0x0003, 0x0003, + "VIA Technologies Inc.", + "Mitsumi multi cardreader", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200, "HP", "CD-Writer+", -- cgit v1.2.2 From 2e56222ed52cec40427fa89f23b228232e3e327e Mon Sep 17 00:00:00 2001 From: Wolfgang Rohdewald Date: Wed, 8 Mar 2006 16:59:44 +0100 Subject: [PATCH] USB: add support for Creativelabs Silvercrest USB keyboard Signed-off-by: Wolfgang Rohdewald Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 6b8a51cad375..58b59f6e9881 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1552,6 +1552,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_HP 0x03f0 #define USB_DEVICE_ID_HP_USBHUB_KB 0x020c +#define USB_VENDOR_ID_CREATIVELABS 0x062a +#define USB_DEVICE_ID_CREATIVELABS_SILVERCREST 0x0201 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -1668,6 +1671,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET}, { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET}, + { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET }, { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.2 From 6e0755a4b2a41a8cd5839db69532d07262294b41 Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Fri, 3 Mar 2006 09:58:39 +0000 Subject: [PATCH] USB: ZC0301 driver bugfix ZC0301 driver bugfix. Use correct PID/VID USB entries. Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/zc0301.h | 5 +---- drivers/usb/media/zc0301_core.c | 6 +++--- drivers/usb/media/zc0301_sensor.h | 12 ++++++------ 3 files changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h index 9ba9135e824b..8e0655140e60 100644 --- a/drivers/usb/media/zc0301.h +++ b/drivers/usb/media/zc0301.h @@ -134,10 +134,7 @@ struct zc0301_device { struct zc0301_device* zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id) { - if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) - return cam; - - return NULL; + return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; } void diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c index 5773688d3dae..4036c6268bff 100644 --- a/drivers/usb/media/zc0301_core.c +++ b/drivers/usb/media/zc0301_core.c @@ -52,8 +52,8 @@ #define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia" #define ZC0301_AUTHOR_EMAIL "" #define ZC0301_MODULE_LICENSE "GPL" -#define ZC0301_MODULE_VERSION "1:1.02" -#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2) +#define ZC0301_MODULE_VERSION "1:1.03" +#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 3) /*****************************************************************************/ @@ -637,7 +637,6 @@ static void zc0301_release_resources(struct zc0301_device* cam) DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); - usb_put_dev(cam->usbdev); kfree(cam->control_buffer); } @@ -727,6 +726,7 @@ static int zc0301_release(struct inode* inode, struct file* filp) if (cam->state & DEV_DISCONNECTED) { zc0301_release_resources(cam); + usb_put_dev(cam->usbdev); mutex_unlock(&cam->dev_mutex); kfree(cam); return 0; diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h index e3cb6cc920ca..cf0965a81d01 100644 --- a/drivers/usb/media/zc0301_sensor.h +++ b/drivers/usb/media/zc0301_sensor.h @@ -58,14 +58,14 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor); #define ZC0301_ID_TABLE \ static const struct usb_device_id zc0301_id_table[] = { \ - { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \ - { ZC0301_USB_DEVICE(0x041e, 0x0417, 0xff), }, \ - { ZC0301_USB_DEVICE(0x041e, 0x041e, 0xff), }, /* HV7131B */ \ - { ZC0301_USB_DEVICE(0x041e, 0x081c, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x0834, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x0835, 0xff), }, /* PAS106 */ \ + { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, \ + { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \ + { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */ \ + { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \ + { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \ { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ + { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \ { } \ }; -- cgit v1.2.2 From f88f8295d8a9229fc8b647baf4f15959384d7bb7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 10 Mar 2006 23:25:06 +0100 Subject: [PATCH] USB: vicam.c: fix a NULL pointer dereference This patch fixes a NULL pointer dereference spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/vicam.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c index 8cfc47b831fb..1d06e53ec7c5 100644 --- a/drivers/usb/media/vicam.c +++ b/drivers/usb/media/vicam.c @@ -764,6 +764,7 @@ vicam_open(struct inode *inode, struct file *file) if (!cam) { printk(KERN_ERR "vicam video_device improperly initialized"); + return -EINVAL; } /* the videodev_lock held above us protects us from -- cgit v1.2.2 From 24f8b116c45e46779dec553f934c3d74f79c06fb Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Sat, 11 Mar 2006 00:16:55 -0800 Subject: [PATCH] USB: fix check_ctrlrecip to allow control transfers in state ADDRESS check_ctrlrecip() disallows any control transfers if the device is deconfigured (in configuration 0, ie. state ADDRESS). This for example makes it impossible to read the device descriptors without configuring the device, although most standard device requests are allowed in this state by the spec. This patch allows control transfers for the ADDRESS state, too. Signed-off-by: Horst Schirmeier Cc: Alan Stern Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index de6a7c07cf97..545da37afca7 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -493,7 +493,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig { int ret = 0; - if (ps->dev->state != USB_STATE_CONFIGURED) + if (ps->dev->state != USB_STATE_ADDRESS + && ps->dev->state != USB_STATE_CONFIGURED) return -EHOSTUNREACH; if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype)) return 0; -- cgit v1.2.2 From 59224f5352542b968c41200954e56c26c4f0a075 Mon Sep 17 00:00:00 2001 From: Craig Shelley Date: Sat, 11 Mar 2006 11:29:02 +0000 Subject: [PATCH] USB: cp2101: add new device IDs This patch adds a new device ID to the cp2101 driver Signed-off-by: Craig Shelley Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp2101.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 9ea7b4a4a22b..e0c2acdb3f06 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -32,7 +32,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.06" +#define DRIVER_VERSION "v0.07" #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver" /* @@ -58,6 +58,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ + { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ -- cgit v1.2.2 From bf58fbd5e86a43466e638407ff8a4eb7766a3b68 Mon Sep 17 00:00:00 2001 From: "A. Maitland Bottoms" Date: Tue, 14 Mar 2006 18:44:23 -0500 Subject: [PATCH] USB: ftdi_sio: add Icom ID1 USB product and vendor ids The Icom ID-1 1.2 GHz band digital transceiver is a new radio that has a USB interface. With this patch, the ftdi_sio driver will report "Detected FT8U232AM" and provide a serial device interface. Signed-off-by: "A. Maitland Bottoms" Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio.h | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ece52a6328b5..f3af81b4dd29 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -492,6 +492,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) }, { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, + { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index bdef3b8c731f..8da773c2744d 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -145,6 +145,13 @@ #define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */ #define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */ +/* + * Icom ID-1 digital transceiver + */ + +#define ICOM_ID1_VID 0x0C26 +#define ICOM_ID1_PID 0x0004 + /* * DSS-20 Sync Station for Sony Ericsson P800 */ -- cgit v1.2.2 From 09abfa8048de8e68eaa09eb07ac18f2d549dfe58 Mon Sep 17 00:00:00 2001 From: Petko Manolov Date: Wed, 15 Mar 2006 16:29:38 +0200 Subject: [PATCH] USB: rtl8150 small fix This one is about announcing the device registration after the last check has been made. From: Petko Manolov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/net/rtl8150.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 8ca52be23976..1bbbae283c0b 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -880,7 +880,6 @@ static int rtl8150_probe(struct usb_interface *intf, } fill_skb_pool(dev); set_ethernet_addr(dev); - info("%s: rtl8150 is detected", netdev->name); usb_set_intfdata(intf, dev); SET_NETDEV_DEV(netdev, &intf->dev); @@ -888,6 +887,9 @@ static int rtl8150_probe(struct usb_interface *intf, err("couldn't register the device"); goto out2; } + + info("%s: rtl8150 is detected", netdev->name); + return 0; out2: -- cgit v1.2.2 From e9a66c64bb7033cb0180d419b2008acf7a141adc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Mar 2006 17:40:08 -0800 Subject: [PATCH] USB serial: add navman driver Thanks to Warren Lewis for the information needed to write the driver and for testing it out. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 7 ++ drivers/usb/serial/Makefile | 1 + drivers/usb/serial/navman.c | 157 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 drivers/usb/serial/navman.c (limited to 'drivers/usb') diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index be5dc80836c3..5a8a2c91c2b2 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -403,6 +403,13 @@ config USB_SERIAL_MCT_U232 To compile this driver as a module, choose M here: the module will be called mct_u232. +config USB_SERIAL_NAVMAN + tristate "USB Navman GPS device" + depends on USB_SERIAL + help + To compile this driver as a module, choose M here: the + module will be called navman. + config USB_SERIAL_PL2303 tristate "USB Prolific 2303 Single Port Serial Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index f0b04420cea1..f7fe4172efed 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_OPTION) += option.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c new file mode 100644 index 000000000000..7f544081032e --- /dev/null +++ b/drivers/usb/serial/navman.c @@ -0,0 +1,157 @@ +/* + * Navman Serial USB driver + * + * Copyright (C) 2006 Greg Kroah-Hartman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include "usb-serial.h" + +static int debug; + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver navman_driver = { + .name = "navman", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static void navman_read_int_callback(struct urb *urb, struct pt_regs *regs) +{ + struct usb_serial_port *port = urb->context; + unsigned char *data = urb->transfer_buffer; + struct tty_struct *tty; + int result; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, + urb->actual_length, data); + + tty = port->tty; + if (tty && urb->actual_length) { + tty_buffer_request_room(tty, urb->actual_length); + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } + +exit: + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) + dev_err(&urb->dev->dev, + "%s - Error %d submitting interrupt urb\n", + __FUNCTION__, result); +} + +static int navman_open(struct usb_serial_port *port, struct file *filp) +{ + int result = 0; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (port->interrupt_in_urb) { + dbg("%s - adding interrupt input for treo", __FUNCTION__); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (result) + dev_err(&port->dev, + "%s - failed submitting interrupt urb, error %d\n", + __FUNCTION__, result); + } + return result; +} + +static void navman_close(struct usb_serial_port *port, struct file *filp) +{ + dbg("%s - port %d", __FUNCTION__, port->number); + + if (port->interrupt_in_urb) + usb_kill_urb(port->interrupt_in_urb); +} + +static int navman_write(struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + dbg("%s - port %d", __FUNCTION__, port->number); + + /* + * This device can't write any data, only read from the device + * so we just silently eat all data sent to us and say it was + * successfully sent. + * Evil, I know, but do you have a better idea? + */ + + return count; +} + +static struct usb_serial_driver navman_device = { + .driver = { + .owner = THIS_MODULE, + .name = "navman", + }, + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, + .open = navman_open, + .close = navman_close, + .write = navman_write, + .read_int_callback = navman_read_int_callback, +}; + +static int __init navman_init(void) +{ + int retval; + + retval = usb_serial_register(&navman_device); + if (retval) + return retval; + retval = usb_register(&navman_driver); + if (retval) + usb_serial_deregister(&navman_device); + return retval; +} + +static void __exit navman_exit(void) +{ + usb_deregister(&navman_driver); + usb_serial_deregister(&navman_device); +} + +module_init(navman_init); +module_exit(navman_exit); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); -- cgit v1.2.2 From 71a8924bee63d891f6256d560e32416a458440b3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Mar 2006 17:28:39 -0500 Subject: [PATCH] USB: omninet: fix up debugging comments Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/omninet.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 762d8ff9a1e4..4d40704dea2c 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -204,7 +204,7 @@ static void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs) int i; int result; -// dbg("omninet_read_bulk_callback"); + dbg("%s - port %d", __FUNCTION__, port->number); if (urb->status) { dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); @@ -250,7 +250,7 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf int result; -// dbg("omninet_write port %d", port->number); + dbg("%s - port %d", __FUNCTION__, port->number); if (count == 0) { dbg("%s - write request of 0 bytes", __FUNCTION__); @@ -302,7 +302,7 @@ static int omninet_write_room (struct usb_serial_port *port) if (wport->write_urb_busy) room = wport->bulk_out_size - OMNINET_HEADERLEN; -// dbg("omninet_write_room returns %d", room); + dbg("%s - returns %d", __FUNCTION__, room); return (room); } @@ -312,7 +312,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs) /* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */ struct usb_serial_port *port = (struct usb_serial_port *) urb->context; -// dbg("omninet_write_bulk_callback, port %0x\n", port); + dbg("%s - port %0x\n", __FUNCTION__, port->number); port->write_urb_busy = 0; if (urb->status) { @@ -321,8 +321,6 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs) } schedule_work(&port->work); - -// dbg("omninet_write_bulk_callback, tty %0x\n", tty); } -- cgit v1.2.2 From 53b3531bbbf70ac7551b32d1acc229d94de52658 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 24 Mar 2006 03:16:13 -0800 Subject: [PATCH] s/;;/;/g Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/image/microtek.c | 2 +- drivers/usb/input/hid-core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 28538db9eaf3..2a0e18a48748 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -360,7 +360,7 @@ static int mts_scsi_host_reset (Scsi_Cmnd *srb) rc = usb_lock_device_for_reset(desc->usb_dev, desc->usb_intf); if (rc < 0) return FAILED; - result = usb_reset_device(desc->usb_dev);; + result = usb_reset_device(desc->usb_dev); if (rc) usb_unlock_device(desc->usb_dev); return result ? FAILED : SUCCESS; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 58b59f6e9881..d4bf1701046b 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1215,7 +1215,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) if (hid->outhead != hid->outtail) { if (hid_submit_out(hid)) { - clear_bit(HID_OUT_RUNNING, &hid->iofl);; + clear_bit(HID_OUT_RUNNING, &hid->iofl); wake_up(&hid->wait); } spin_unlock_irqrestore(&hid->outlock, flags); -- cgit v1.2.2 From c30fe7f73194650148b58ee80908c1bc38246397 Mon Sep 17 00:00:00 2001 From: Uwe Zeisberger Date: Fri, 24 Mar 2006 18:23:14 +0100 Subject: fix typos "wich" -> "which" Signed-off-by: Uwe Zeisberger Signed-off-by: Adrian Bunk --- drivers/usb/serial/option.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index a8455c9e79dd..495db5755df9 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -102,7 +102,7 @@ static struct usb_driver option_driver = { .no_dynamic_id = 1, }; -/* The card has three separate interfaces, wich the serial driver +/* The card has three separate interfaces, which the serial driver * recognizes separately, thus num_port=1. */ static struct usb_serial_driver option_3port_device = { -- cgit v1.2.2 From 9f6933be665ce3b049c274c99810ac754edabf19 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 25 Mar 2006 09:05:39 -0300 Subject: V4L/DVB (3599a): Move drivers/usb/media to drivers/media/video Because of historic reasons, there are two separate directories with V4L stuff. Most drivers are located at driver/media/video. However, some code for USB Webcams were inserted under drivers/usb/media. This makes difficult for module authors to know were things should be. Also, makes Kconfig menu confusing for normal users. This patch moves all V4L content under drivers/usb/media to drivers/media/video, and fixes Kconfig/Makefile entries. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Mauro Carvalho Chehab --- drivers/usb/Kconfig | 2 - drivers/usb/Makefile | 14 - drivers/usb/media/Kconfig | 241 -- drivers/usb/media/Makefile | 24 - drivers/usb/media/dabfirmware.h | 1408 -------- drivers/usb/media/dabusb.c | 874 ----- drivers/usb/media/dabusb.h | 85 - drivers/usb/media/dsbr100.c | 429 --- drivers/usb/media/et61x251.h | 234 -- drivers/usb/media/et61x251_core.c | 2630 -------------- drivers/usb/media/et61x251_sensor.h | 116 - drivers/usb/media/et61x251_tas5130d1b.c | 141 - drivers/usb/media/ibmcam.c | 3932 -------------------- drivers/usb/media/konicawc.c | 978 ----- drivers/usb/media/ov511.c | 5932 ------------------------------- drivers/usb/media/ov511.h | 568 --- drivers/usb/media/pwc/Makefile | 20 - drivers/usb/media/pwc/philips.txt | 236 -- drivers/usb/media/pwc/pwc-ctrl.c | 1541 -------- drivers/usb/media/pwc/pwc-if.c | 2205 ------------ drivers/usb/media/pwc/pwc-ioctl.h | 292 -- drivers/usb/media/pwc/pwc-kiara.c | 318 -- drivers/usb/media/pwc/pwc-kiara.h | 45 - drivers/usb/media/pwc/pwc-misc.c | 140 - drivers/usb/media/pwc/pwc-nala.h | 66 - drivers/usb/media/pwc/pwc-timon.c | 316 -- drivers/usb/media/pwc/pwc-timon.h | 61 - drivers/usb/media/pwc/pwc-uncompress.c | 146 - drivers/usb/media/pwc/pwc-uncompress.h | 41 - drivers/usb/media/pwc/pwc.h | 272 -- drivers/usb/media/se401.c | 1435 -------- drivers/usb/media/se401.h | 234 -- drivers/usb/media/sn9c102.h | 218 -- drivers/usb/media/sn9c102_core.c | 2919 --------------- drivers/usb/media/sn9c102_hv7131d.c | 271 -- drivers/usb/media/sn9c102_mi0343.c | 363 -- drivers/usb/media/sn9c102_ov7630.c | 401 --- drivers/usb/media/sn9c102_pas106b.c | 307 -- drivers/usb/media/sn9c102_pas202bca.c | 238 -- drivers/usb/media/sn9c102_pas202bcb.c | 293 -- drivers/usb/media/sn9c102_sensor.h | 389 -- drivers/usb/media/sn9c102_tas5110c1b.c | 159 - drivers/usb/media/sn9c102_tas5130d1b.c | 169 - drivers/usb/media/stv680.c | 1508 -------- drivers/usb/media/stv680.h | 227 -- drivers/usb/media/ultracam.c | 679 ---- drivers/usb/media/usbvideo.c | 2190 ------------ drivers/usb/media/usbvideo.h | 394 -- drivers/usb/media/vicam.c | 1411 -------- drivers/usb/media/w9968cf.c | 3691 ------------------- drivers/usb/media/w9968cf.h | 330 -- drivers/usb/media/w9968cf_decoder.h | 86 - drivers/usb/media/w9968cf_vpp.h | 40 - drivers/usb/media/zc0301.h | 192 - drivers/usb/media/zc0301_core.c | 2055 ----------- drivers/usb/media/zc0301_pas202bcb.c | 361 -- drivers/usb/media/zc0301_sensor.h | 103 - 57 files changed, 43970 deletions(-) delete mode 100644 drivers/usb/media/Kconfig delete mode 100644 drivers/usb/media/Makefile delete mode 100644 drivers/usb/media/dabfirmware.h delete mode 100644 drivers/usb/media/dabusb.c delete mode 100644 drivers/usb/media/dabusb.h delete mode 100644 drivers/usb/media/dsbr100.c delete mode 100644 drivers/usb/media/et61x251.h delete mode 100644 drivers/usb/media/et61x251_core.c delete mode 100644 drivers/usb/media/et61x251_sensor.h delete mode 100644 drivers/usb/media/et61x251_tas5130d1b.c delete mode 100644 drivers/usb/media/ibmcam.c delete mode 100644 drivers/usb/media/konicawc.c delete mode 100644 drivers/usb/media/ov511.c delete mode 100644 drivers/usb/media/ov511.h delete mode 100644 drivers/usb/media/pwc/Makefile delete mode 100644 drivers/usb/media/pwc/philips.txt delete mode 100644 drivers/usb/media/pwc/pwc-ctrl.c delete mode 100644 drivers/usb/media/pwc/pwc-if.c delete mode 100644 drivers/usb/media/pwc/pwc-ioctl.h delete mode 100644 drivers/usb/media/pwc/pwc-kiara.c delete mode 100644 drivers/usb/media/pwc/pwc-kiara.h delete mode 100644 drivers/usb/media/pwc/pwc-misc.c delete mode 100644 drivers/usb/media/pwc/pwc-nala.h delete mode 100644 drivers/usb/media/pwc/pwc-timon.c delete mode 100644 drivers/usb/media/pwc/pwc-timon.h delete mode 100644 drivers/usb/media/pwc/pwc-uncompress.c delete mode 100644 drivers/usb/media/pwc/pwc-uncompress.h delete mode 100644 drivers/usb/media/pwc/pwc.h delete mode 100644 drivers/usb/media/se401.c delete mode 100644 drivers/usb/media/se401.h delete mode 100644 drivers/usb/media/sn9c102.h delete mode 100644 drivers/usb/media/sn9c102_core.c delete mode 100644 drivers/usb/media/sn9c102_hv7131d.c delete mode 100644 drivers/usb/media/sn9c102_mi0343.c delete mode 100644 drivers/usb/media/sn9c102_ov7630.c delete mode 100644 drivers/usb/media/sn9c102_pas106b.c delete mode 100644 drivers/usb/media/sn9c102_pas202bca.c delete mode 100644 drivers/usb/media/sn9c102_pas202bcb.c delete mode 100644 drivers/usb/media/sn9c102_sensor.h delete mode 100644 drivers/usb/media/sn9c102_tas5110c1b.c delete mode 100644 drivers/usb/media/sn9c102_tas5130d1b.c delete mode 100644 drivers/usb/media/stv680.c delete mode 100644 drivers/usb/media/stv680.h delete mode 100644 drivers/usb/media/ultracam.c delete mode 100644 drivers/usb/media/usbvideo.c delete mode 100644 drivers/usb/media/usbvideo.h delete mode 100644 drivers/usb/media/vicam.c delete mode 100644 drivers/usb/media/w9968cf.c delete mode 100644 drivers/usb/media/w9968cf.h delete mode 100644 drivers/usb/media/w9968cf_decoder.h delete mode 100644 drivers/usb/media/w9968cf_vpp.h delete mode 100644 drivers/usb/media/zc0301.h delete mode 100644 drivers/usb/media/zc0301_core.c delete mode 100644 drivers/usb/media/zc0301_pas202bcb.c delete mode 100644 drivers/usb/media/zc0301_sensor.h (limited to 'drivers/usb') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index b1222cd4aa46..7fdbc5dad5fd 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -87,8 +87,6 @@ source "drivers/usb/input/Kconfig" source "drivers/usb/image/Kconfig" -source "drivers/usb/media/Kconfig" - source "drivers/usb/net/Kconfig" source "drivers/usb/mon/Kconfig" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index bb36a1c1dbb3..9b7d9769fdcc 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -35,20 +35,6 @@ obj-$(CONFIG_USB_WACOM) += input/ obj-$(CONFIG_USB_ACECAD) += input/ obj-$(CONFIG_USB_XPAD) += input/ -obj-$(CONFIG_USB_DABUSB) += media/ -obj-$(CONFIG_USB_DSBR) += media/ -obj-$(CONFIG_USB_ET61X251) += media/ -obj-$(CONFIG_USB_IBMCAM) += media/ -obj-$(CONFIG_USB_KONICAWC) += media/ -obj-$(CONFIG_USB_OV511) += media/ -obj-$(CONFIG_USB_PWC) += media/ -obj-$(CONFIG_USB_SE401) += media/ -obj-$(CONFIG_USB_SN9C102) += media/ -obj-$(CONFIG_USB_STV680) += media/ -obj-$(CONFIG_USB_VICAM) += media/ -obj-$(CONFIG_USB_W9968CF) += media/ -obj-$(CONFIG_USB_ZC0301) += media/ - obj-$(CONFIG_USB_CATC) += net/ obj-$(CONFIG_USB_KAWETH) += net/ obj-$(CONFIG_USB_PEGASUS) += net/ diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig deleted file mode 100644 index 189d40f96be5..000000000000 --- a/drivers/usb/media/Kconfig +++ /dev/null @@ -1,241 +0,0 @@ -# -# USB Multimedia device configuration -# -comment "USB Multimedia devices" - depends on USB - -config USB_DABUSB - tristate "DABUSB driver" - depends on USB - ---help--- - A Digital Audio Broadcasting (DAB) Receiver for USB and Linux - brought to you by the DAB-Team - . This driver can be taken - as an example for URB-based bulk, control, and isochronous - transactions. URB's are explained in - . - - To compile this driver as a module, choose M here: the - module will be called dabusb. - -comment "Video4Linux support is needed for USB Multimedia device support" - depends on USB && VIDEO_DEV=n - -config USB_VICAM - tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)" - depends on USB && VIDEO_DEV && EXPERIMENTAL - ---help--- - Say Y here if you have 3com homeconnect camera (vicam). - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Multimedia Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called vicam. - -config USB_DSBR - tristate "D-Link USB FM radio support (EXPERIMENTAL)" - depends on USB && VIDEO_DEV && EXPERIMENTAL - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - This driver uses the Video For Linux API. You must enable - (Y or M in config) Video For Linux (under Character Devices) - to use this driver. Information on this API and pointers to - "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called dsbr100. - -config USB_ET61X251 - tristate "USB ET61X[12]51 PC Camera Controller support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want support for cameras based on Etoms ET61X151 - or ET61X251 PC Camera Controllers. - - See for more informations. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as a module, choose M here: the - module will be called et61x251. - -config USB_IBMCAM - tristate "USB IBM (Xirlink) C-it Camera support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want to connect a IBM "C-It" camera, also known as - "Xirlink PC Camera" to your computer's USB port. For more - information, read . - - This driver uses the Video For Linux API. You must enable - (Y or M in config) Video For Linux (under Character Devices) - to use this driver. Information on this API and pointers to - "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called ibmcam. - - This camera has several configuration options which - can be specified when you load the module. Read - to learn more. - -config USB_KONICAWC - tristate "USB Konica Webcam support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want support for webcams based on a Konica - chipset. This is known to work with the Intel YC76 webcam. - - This driver uses the Video For Linux API. You must enable - (Y or M in config) Video For Linux (under Character Devices) - to use this driver. Information on this API and pointers to - "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called konicawc. - -config USB_OV511 - tristate "USB OV511 Camera support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. See for more - information and for a list of supported cameras. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Character Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called ov511. - -config USB_SE401 - tristate "USB SE401 Camera support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. See for more - information and for a list of supported cameras. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Multimedia Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called se401. - -config USB_SN9C102 - tristate "USB SN9C10x PC Camera Controller support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want support for cameras based on SONiX SN9C101, - SN9C102 or SN9C103 PC Camera Controllers. - - See for more informations. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as a module, choose M here: the - module will be called sn9c102. - -config USB_STV680 - tristate "USB STV680 (Pencam) Camera support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. This includes the Pencam line of cameras. - See for more information and for - a list of supported cameras. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Multimedia Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called stv680. - -config USB_W9968CF - tristate "USB W996[87]CF JPEG Dual Mode Camera support" - depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP - ---help--- - Say Y here if you want support for cameras based on OV681 or - Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. - - This driver has an optional plugin, which is distributed as a - separate module only (released under GPL). It allows to use higher - resolutions and framerates, but cannot be included in the official - Linux kernel for performance purposes. - - See for more informations. - - This driver uses the Video For Linux and the I2C APIs. It needs the - OmniVision Camera Chip support as well. You must say Y or M to - "Video For Linux", "I2C Support" and "OmniVision Camera Chip - support" to use this driver. - - To compile this driver as a module, choose M here: the - module will be called w9968cf. - -config USB_ZC0301 - tristate "USB ZC0301 Image Processor and Control Chip support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want support for cameras based on the ZC0301 - Image Processor and Control Chip. - - See for more informations. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as a module, choose M here: the - module will be called zc0301. - -config USB_PWC - tristate "USB Philips Cameras" - depends on USB && VIDEO_DEV - ---help--- - Say Y or M here if you want to use one of these Philips & OEM - webcams: - * Philips PCA645, PCA646 - * Philips PCVC675, PCVC680, PCVC690 - * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 - * Askey VC010 - * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' - and 'Orbit'/'Sphere' - * Samsung MPC-C10, MPC-C30 - * Creative Webcam 5, Pro Ex - * SOTEC Afina Eye - * Visionite VCS-UC300, VCS-UM100 - - The PCA635, PCVC665 and PCVC720/20 are not supported by this driver - and never will be, but the 665 and 720/20 are supported by other - drivers. - - See for more information and - installation instructions. - - The built-in microphone is enabled by selecting USB Audio support. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Character Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called pwc. diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile deleted file mode 100644 index 50e89a33b85e..000000000000 --- a/drivers/usb/media/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# -# Makefile for USB Media drivers -# - -sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ - sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \ - sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ - sn9c102_tas5130d1b.o -et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o -zc0301-objs := zc0301_core.o zc0301_pas202bcb.o - -obj-$(CONFIG_USB_DABUSB) += dabusb.o -obj-$(CONFIG_USB_DSBR) += dsbr100.o -obj-$(CONFIG_USB_ET61X251) += et61x251.o -obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o -obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o -obj-$(CONFIG_USB_OV511) += ov511.o -obj-$(CONFIG_USB_SE401) += se401.o -obj-$(CONFIG_USB_SN9C102) += sn9c102.o -obj-$(CONFIG_USB_STV680) += stv680.o -obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o -obj-$(CONFIG_USB_W9968CF) += w9968cf.o -obj-$(CONFIG_USB_ZC0301) += zc0301.o -obj-$(CONFIG_USB_PWC) += pwc/ diff --git a/drivers/usb/media/dabfirmware.h b/drivers/usb/media/dabfirmware.h deleted file mode 100644 index d14d803566a3..000000000000 --- a/drivers/usb/media/dabfirmware.h +++ /dev/null @@ -1,1408 +0,0 @@ -/* - * dabdata.h - dab usb firmware and bitstream data - */ - -static INTEL_HEX_RECORD firmware[] = { - -{ 2, 0x0000, 0, {0x21,0x57} }, -{ 3, 0x0003, 0, {0x02,0x01,0x66} }, -{ 3, 0x000b, 0, {0x02,0x01,0x66} }, -{ 3, 0x0013, 0, {0x02,0x01,0x66} }, -{ 3, 0x001b, 0, {0x02,0x01,0x66} }, -{ 3, 0x0023, 0, {0x02,0x01,0x66} }, -{ 3, 0x002b, 0, {0x02,0x01,0x66} }, -{ 3, 0x0033, 0, {0x02,0x03,0x0f} }, -{ 3, 0x003b, 0, {0x02,0x01,0x66} }, -{ 3, 0x0043, 0, {0x02,0x01,0x00} }, -{ 3, 0x004b, 0, {0x02,0x01,0x66} }, -{ 3, 0x0053, 0, {0x02,0x01,0x66} }, -{ 3, 0x005b, 0, {0x02,0x04,0xbd} }, -{ 3, 0x0063, 0, {0x02,0x01,0x67} }, -{ 3, 0x0100, 0, {0x02,0x0c,0x5a} }, -{ 3, 0x0104, 0, {0x02,0x01,0xed} }, -{ 3, 0x0108, 0, {0x02,0x02,0x51} }, -{ 3, 0x010c, 0, {0x02,0x02,0x7c} }, -{ 3, 0x0110, 0, {0x02,0x02,0xe4} }, -{ 1, 0x0114, 0, {0x32} }, -{ 1, 0x0118, 0, {0x32} }, -{ 3, 0x011c, 0, {0x02,0x05,0xfd} }, -{ 3, 0x0120, 0, {0x02,0x00,0x00} }, -{ 3, 0x0124, 0, {0x02,0x00,0x00} }, -{ 3, 0x0128, 0, {0x02,0x04,0x3c} }, -{ 3, 0x012c, 0, {0x02,0x04,0x6a} }, -{ 3, 0x0130, 0, {0x02,0x00,0x00} }, -{ 3, 0x0134, 0, {0x02,0x00,0x00} }, -{ 3, 0x0138, 0, {0x02,0x00,0x00} }, -{ 3, 0x013c, 0, {0x02,0x00,0x00} }, -{ 3, 0x0140, 0, {0x02,0x00,0x00} }, -{ 3, 0x0144, 0, {0x02,0x00,0x00} }, -{ 3, 0x0148, 0, {0x02,0x00,0x00} }, -{ 3, 0x014c, 0, {0x02,0x00,0x00} }, -{ 3, 0x0150, 0, {0x02,0x00,0x00} }, -{ 3, 0x0154, 0, {0x02,0x00,0x00} }, -{ 10, 0x0157, 0, {0x75,0x81,0x7f,0xe5,0x82,0x60,0x03,0x02,0x01,0x61} }, -{ 5, 0x0161, 0, {0x12,0x07,0x6f,0x21,0x64} }, -{ 1, 0x0166, 0, {0x32} }, -{ 14, 0x0167, 0, {0xc0,0xd0,0xc0,0x86,0xc0,0x82,0xc0,0x83,0xc0,0xe0,0x90,0x7f,0x97,0xe0} }, -{ 14, 0x0175, 0, {0x44,0x80,0xf0,0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, -{ 14, 0x0183, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, -{ 14, 0x0191, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x90,0x7f,0x97,0xe0} }, -{ 3, 0x019f, 0, {0x55,0x7f,0xf0} }, -{ 14, 0x01a2, 0, {0x90,0x7f,0x9a,0xe0,0x30,0xe4,0x23,0x90,0x7f,0x68,0xf0,0xf0,0xf0,0xf0} }, -{ 14, 0x01b0, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, -{ 14, 0x01be, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} }, -{ 14, 0x01cc, 0, {0xe5,0xd8,0xc2,0xe3,0xf5,0xd8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0xd0,0x86} }, -{ 3, 0x01da, 0, {0xd0,0xd0,0x32} }, -{ 8, 0x01dd, 0, {0x75,0x86,0x00,0x90,0xff,0xc3,0x7c,0x05} }, -{ 7, 0x01e5, 0, {0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} }, -{ 1, 0x01ec, 0, {0x22} }, -{ 14, 0x01ed, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0xd0} }, -{ 14, 0x01fb, 0, {0x75,0xd0,0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91} }, -{ 13, 0x0209, 0, {0x90,0x88,0x00,0xe0,0xf5,0x41,0x90,0x7f,0xab,0x74,0x02,0xf0,0x90} }, -{ 9, 0x0216, 0, {0x7f,0xab,0x74,0x02,0xf0,0xe5,0x32,0x60,0x21} }, -{ 4, 0x021f, 0, {0x7a,0x00,0x7b,0x00} }, -{ 11, 0x0223, 0, {0xc3,0xea,0x94,0x18,0xeb,0x64,0x80,0x94,0x80,0x50,0x12} }, -{ 14, 0x022e, 0, {0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0a,0xba,0x00} }, -{ 2, 0x023c, 0, {0x01,0x0b} }, -{ 2, 0x023e, 0, {0x80,0xe3} }, -{ 2, 0x0240, 0, {0xd0,0x86} }, -{ 14, 0x0242, 0, {0xd0,0xd0,0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0} }, -{ 1, 0x0250, 0, {0x32} }, -{ 14, 0x0251, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, -{ 14, 0x025f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} }, -{ 4, 0x026d, 0, {0x04,0xf0,0xd0,0x86} }, -{ 11, 0x0271, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 14, 0x027c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, -{ 14, 0x028a, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, -{ 13, 0x0298, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, -{ 12, 0x02a5, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0x6e,0x00,0x75,0x6f,0x02,0x12} }, -{ 6, 0x02b1, 0, {0x11,0x44,0x75,0x70,0x39,0x75} }, -{ 6, 0x02b7, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} }, -{ 12, 0x02bd, 0, {0x11,0x75,0x90,0x7f,0xd6,0xe4,0xf0,0x75,0xd8,0x20,0xd0,0x86} }, -{ 14, 0x02c9, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, -{ 13, 0x02d7, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 14, 0x02e4, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, -{ 14, 0x02f2, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} }, -{ 4, 0x0300, 0, {0x10,0xf0,0xd0,0x86} }, -{ 11, 0x0304, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 14, 0x030f, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, -{ 14, 0x031d, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, -{ 12, 0x032b, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0x75,0x6e,0x00,0x75,0x6f,0x02} }, -{ 7, 0x0337, 0, {0x12,0x11,0x44,0x75,0x70,0x40,0x75} }, -{ 6, 0x033e, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} }, -{ 14, 0x0344, 0, {0x11,0x75,0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0} }, -{ 5, 0x0352, 0, {0x75,0xd8,0x10,0xd0,0x86} }, -{ 14, 0x0357, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, -{ 13, 0x0365, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 13, 0x0372, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} }, -{ 12, 0x037f, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x42,0xf0,0x12,0x10,0x1b,0x90} }, -{ 13, 0x038b, 0, {0x7f,0xa6,0xe5,0x43,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40} }, -{ 1, 0x0398, 0, {0xf0} }, -{ 1, 0x0399, 0, {0x22} }, -{ 13, 0x039a, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} }, -{ 12, 0x03a7, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x44,0xf0,0x12,0x10,0x1b,0x90} }, -{ 12, 0x03b3, 0, {0x7f,0xa6,0xe5,0x45,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0xe5} }, -{ 11, 0x03bf, 0, {0x46,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40,0xf0} }, -{ 1, 0x03ca, 0, {0x22} }, -{ 10, 0x03cb, 0, {0x75,0x44,0x02,0x75,0x45,0x00,0x75,0x46,0x00,0x12} }, -{ 9, 0x03d5, 0, {0x03,0x9a,0x75,0x42,0x03,0x75,0x43,0x00,0x12} }, -{ 2, 0x03de, 0, {0x03,0x72} }, -{ 1, 0x03e0, 0, {0x22} }, -{ 12, 0x03e1, 0, {0x90,0x88,0x00,0xe5,0x36,0xf0,0x90,0x88,0x00,0x74,0x10,0x25} }, -{ 9, 0x03ed, 0, {0x36,0xf0,0x12,0x01,0xdd,0x75,0x42,0x01,0x75} }, -{ 9, 0x03f6, 0, {0x43,0x18,0x12,0x03,0x72,0x75,0x44,0x02,0x75} }, -{ 9, 0x03ff, 0,{0x45,0x00,0x75,0x46,0x00,0x12,0x03,0x9a,0x75} }, -{ 8, 0x0408, 0,{0x42,0x03,0x75,0x43,0x44,0x12,0x03,0x72} }, -{ 1, 0x0410, 0,{0x22} }, -{ 14, 0x0411, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, -{ 14, 0x041f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} }, -{ 4, 0x042d, 0, {0x02,0xf0,0xd0,0x86} }, -{ 11, 0x0431, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 14, 0x043c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, -{ 14, 0x044a, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xa9,0x74} }, -{ 7, 0x0458, 0, {0x04,0xf0,0x75,0x30,0x01,0xd0,0x86} }, -{ 11, 0x045f, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 14, 0x046a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, -{ 14, 0x0478, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} }, -{ 7, 0x0486, 0, {0x04,0xf0,0x75,0x31,0x01,0xd0,0x86} }, -{ 11, 0x048d, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 14, 0x0498, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, -{ 12, 0x04a6, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe5,0xf5,0x91,0xd0,0x86} }, -{ 11, 0x04b2, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 14, 0x04bd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} }, -{ 12, 0x04cb, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe7,0xf5,0x91,0xd0,0x86} }, -{ 11, 0x04d7, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 12, 0x04e2, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x20,0x90,0x7f,0x96,0xe4,0xf0} }, -{ 1, 0x04ee, 0, {0x22} }, -{ 7, 0x04ef, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x21} }, -{ 1, 0x04f6, 0, {0x22} }, -{ 14, 0x04f7, 0, {0x90,0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xe0,0xfb,0x74,0x80,0x2a,0xfa} }, -{ 14, 0x0505, 0, {0x74,0x80,0x2b,0xfb,0xea,0x03,0x03,0x54,0x3f,0xfc,0xea,0xc4,0x23,0x54} }, -{ 14, 0x0513, 0, {0x1f,0xfa,0x2c,0xfa,0xeb,0x03,0x03,0x54,0x3f,0xfc,0xeb,0xc4,0x23,0x54} }, -{ 11, 0x0521, 0, {0x1f,0xfb,0x2c,0xfb,0x90,0x17,0x0a,0xe0,0xfc,0x60,0x02} }, -{ 2, 0x052c, 0, {0x7a,0x00} }, -{ 7, 0x052e, 0, {0x90,0x17,0x0c,0xe0,0xfc,0x60,0x02} }, -{ 2, 0x0535, 0, {0x7b,0x00} }, -{ 11, 0x0537, 0, {0xea,0x2b,0xfc,0xc3,0x13,0xf5,0x3a,0x75,0x44,0x02,0x8b} }, -{ 7, 0x0542, 0, {0x45,0x8a,0x46,0x12,0x03,0x9a,0x75} }, -{ 9, 0x0549, 0, {0x6e,0x08,0x75,0x6f,0x00,0x12,0x11,0x44,0x75} }, -{ 4, 0x0552, 0, {0x70,0x47,0x75,0x71} }, -{ 8, 0x0556, 0, {0x0c,0x75,0x72,0x02,0x12,0x11,0x75,0x85} }, -{ 5, 0x055e, 0, {0x3a,0x73,0x12,0x11,0xa0} }, -{ 1, 0x0563, 0, {0x22} }, -{ 14, 0x0564, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} }, -{ 14, 0x0572, 0, {0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xef,0xe0,0xfc} }, -{ 14, 0x0580, 0, {0x33,0x95,0xe0,0xfd,0x8c,0x05,0x7c,0x00,0x90,0x7f,0xee,0xe0,0xfe,0x33} }, -{ 14, 0x058e, 0, {0x95,0xe0,0xff,0xec,0x2e,0xfc,0xed,0x3f,0xfd,0x90,0x7f,0xe9,0xe0,0xfe} }, -{ 5, 0x059c, 0, {0xbe,0x01,0x02,0x80,0x03} }, -{ 3, 0x05a1, 0, {0x02,0x05,0xf9} }, -{ 6, 0x05a4, 0, {0xbc,0x01,0x21,0xbd,0x00,0x1e} }, -{ 14, 0x05aa, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfc,0xeb,0x25,0xe0,0xfd,0x2c,0x24,0x00,0xfc} }, -{ 14, 0x05b8, 0, {0xe4,0x34,0x17,0xfd,0x90,0x7e,0xc0,0xe0,0xfe,0x8c,0x82,0x8d,0x83,0xf0} }, -{ 2, 0x05c6, 0, {0x80,0x31} }, -{ 14, 0x05c8, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfa,0xeb,0x25,0xe0,0xfb,0x2a,0xfa,0x24,0x00} }, -{ 14, 0x05d6, 0, {0xfb,0xe4,0x34,0x17,0xfc,0x90,0x7e,0xc0,0xe0,0xfd,0x8b,0x82,0x8c,0x83} }, -{ 14, 0x05e4, 0, {0xf0,0x74,0x01,0x2a,0x24,0x00,0xfa,0xe4,0x34,0x17,0xfb,0x90,0x7e,0xc1} }, -{ 7, 0x05f2, 0, {0xe0,0xfc,0x8a,0x82,0x8b,0x83,0xf0} }, -{ 3, 0x05f9, 0, {0x75,0x38,0x01} }, -{ 1, 0x05fc, 0, {0x22} }, -{ 14, 0x05fd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, -{ 14, 0x060b, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, -{ 13, 0x0619, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, -{ 13, 0x0626, 0, {0x7f,0xaa,0x74,0x01,0xf0,0x12,0x05,0x64,0x75,0x37,0x00,0xd0,0x86} }, -{ 14, 0x0633, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, -{ 13, 0x0641, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 14, 0x064e, 0, {0x90,0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xee,0xe0} }, -{ 14, 0x065c, 0, {0xfc,0x33,0x95,0xe0,0xfd,0x90,0x7f,0x96,0xe0,0xfe,0x90,0x7f,0x96,0x74} }, -{ 14, 0x066a, 0, {0x80,0x65,0x06,0xf0,0x90,0x7f,0x00,0x74,0x01,0xf0,0xea,0xc4,0x03,0x54} }, -{ 14, 0x0678, 0, {0xf8,0xfe,0xeb,0x25,0xe0,0xfb,0x2e,0xfe,0x24,0x00,0xfb,0xe4,0x34,0x17} }, -{ 14, 0x0686, 0, {0xff,0x8b,0x82,0x8f,0x83,0xe0,0xfb,0x74,0x01,0x2e,0x24,0x00,0xfe,0xe4} }, -{ 14, 0x0694, 0, {0x34,0x17,0xff,0x8e,0x82,0x8f,0x83,0xe0,0xfe,0x90,0x7f,0xe9,0xe0,0xff} }, -{ 3, 0x06a2, 0, {0xbf,0x81,0x0a} }, -{ 10, 0x06a5, 0, {0x90,0x7f,0x00,0xeb,0xf0,0x90,0x7f,0x01,0xee,0xf0} }, -{ 8, 0x06af, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x82,0x1a} }, -{ 3, 0x06b7, 0, {0xba,0x01,0x0c} }, -{ 12, 0x06ba, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} }, -{ 11, 0x06c6, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0xb5,0xf0} }, -{ 8, 0x06d1, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x83,0x1b} }, -{ 3, 0x06d9, 0, {0xba,0x01,0x0d} }, -{ 13, 0x06dc, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} }, -{ 11, 0x06e9, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0x12,0xf0} }, -{ 8, 0x06f4, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x84,0x1c} }, -{ 3, 0x06fc, 0, {0xba,0x01,0x0d} }, -{ 13, 0x06ff, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0c} }, -{ 12, 0x070c, 0, {0x90,0x7f,0x00,0x74,0x80,0xf0,0x90,0x7f,0x01,0x74,0x01,0xf0} }, -{ 5, 0x0718, 0, {0x90,0x7f,0xb5,0xec,0xf0} }, -{ 1, 0x071d, 0, {0x22} }, -{ 12, 0x071e, 0, {0x75,0x36,0x0d,0x90,0x88,0x00,0x74,0x1d,0xf0,0x75,0x6b,0x80} }, -{ 10, 0x072a, 0, {0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, -{ 9, 0x0734, 0, {0x6c,0x0f,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, -{ 9, 0x073d, 0, {0x6c,0x06,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} }, -{ 7, 0x0746, 0, {0x6c,0x01,0x12,0x10,0xe2,0x7a,0x00} }, -{ 3, 0x074d, 0, {0xba,0xff,0x00} }, -{ 2, 0x0750, 0, {0x50,0x0a} }, -{ 10, 0x0752, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} }, -{ 10, 0x075c, 0, {0x75,0x6b,0x80,0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75} }, -{ 8, 0x0766, 0, {0x6b,0x80,0x75,0x6c,0x0f,0x12,0x10,0xe2} }, -{ 1, 0x076e, 0, {0x22} }, -{ 14, 0x076f, 0, {0x90,0x7f,0xa1,0xe4,0xf0,0x90,0x7f,0xaf,0x74,0x01,0xf0,0x90,0x7f,0x92} }, -{ 14, 0x077d, 0, {0x74,0x02,0xf0,0x75,0x8e,0x31,0x75,0x89,0x21,0x75,0x88,0x00,0x75,0xc8} }, -{ 14, 0x078b, 0, {0x00,0x75,0x8d,0x40,0x75,0x98,0x40,0x75,0xc0,0x40,0x75,0x87,0x00,0x75} }, -{ 9, 0x0799, 0, {0x20,0x00,0x75,0x21,0x00,0x75,0x22,0x00,0x75} }, -{ 5, 0x07a2, 0, {0x23,0x00,0x75,0x47,0x00} }, -{ 7, 0x07a7, 0, {0xc3,0xe5,0x47,0x94,0x20,0x50,0x11} }, -{ 13, 0x07ae, 0, {0xe5,0x47,0x24,0x00,0xf5,0x82,0xe4,0x34,0x17,0xf5,0x83,0xe4,0xf0} }, -{ 4, 0x07bb, 0, {0x05,0x47,0x80,0xe8} }, -{ 9, 0x07bf, 0, {0xe4,0xf5,0x40,0xf5,0x3f,0xe4,0xf5,0x3c,0xf5} }, -{ 7, 0x07c8, 0, {0x3b,0xe4,0xf5,0x3e,0xf5,0x3d,0x75} }, -{ 11, 0x07cf, 0, {0x32,0x00,0x75,0x37,0x00,0x75,0x39,0x00,0x90,0x7f,0x93} }, -{ 14, 0x07da, 0, {0x74,0x3c,0xf0,0x90,0x7f,0x9c,0x74,0xff,0xf0,0x90,0x7f,0x96,0x74,0x80} }, -{ 14, 0x07e8, 0, {0xf0,0x90,0x7f,0x94,0x74,0x70,0xf0,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} }, -{ 14, 0x07f6, 0, {0x7f,0x97,0xe4,0xf0,0x90,0x7f,0x95,0x74,0xc2,0xf0,0x90,0x7f,0x98,0x74} }, -{ 14, 0x0804, 0, {0x28,0xf0,0x90,0x7f,0x9e,0x74,0x28,0xf0,0x90,0x7f,0xf0,0xe4,0xf0,0x90} }, -{ 14, 0x0812, 0, {0x7f,0xf1,0xe4,0xf0,0x90,0x7f,0xf2,0xe4,0xf0,0x90,0x7f,0xf3,0xe4,0xf0} }, -{ 14, 0x0820, 0, {0x90,0x7f,0xf4,0xe4,0xf0,0x90,0x7f,0xf5,0xe4,0xf0,0x90,0x7f,0xf6,0xe4} }, -{ 14, 0x082e, 0, {0xf0,0x90,0x7f,0xf7,0xe4,0xf0,0x90,0x7f,0xf8,0xe4,0xf0,0x90,0x7f,0xf9} }, -{ 14, 0x083c, 0, {0x74,0x38,0xf0,0x90,0x7f,0xfa,0x74,0xa0,0xf0,0x90,0x7f,0xfb,0x74,0xa0} }, -{ 14, 0x084a, 0, {0xf0,0x90,0x7f,0xfc,0x74,0xa0,0xf0,0x90,0x7f,0xfd,0x74,0xa0,0xf0,0x90} }, -{ 14, 0x0858, 0, {0x7f,0xfe,0x74,0xa0,0xf0,0x90,0x7f,0xff,0x74,0xa0,0xf0,0x90,0x7f,0xe0} }, -{ 14, 0x0866, 0, {0x74,0x03,0xf0,0x90,0x7f,0xe1,0x74,0x01,0xf0,0x90,0x7f,0xdd,0x74,0x80} }, -{ 11, 0x0874, 0, {0xf0,0x12,0x12,0x43,0x12,0x07,0x1e,0x7a,0x00,0x7b,0x00} }, -{ 9, 0x087f, 0, {0xc3,0xea,0x94,0x1e,0xeb,0x94,0x00,0x50,0x17} }, -{ 12, 0x0888, 0, {0x90,0x88,0x00,0xe0,0xf5,0x47,0x90,0x88,0x0b,0xe0,0xf5,0x47} }, -{ 9, 0x0894, 0, {0x90,0x7f,0x68,0xf0,0x0a,0xba,0x00,0x01,0x0b} }, -{ 2, 0x089d, 0, {0x80,0xe0} }, -{ 12, 0x089f, 0, {0x12,0x03,0xe1,0x90,0x7f,0xd6,0xe4,0xf0,0x7a,0x00,0x7b,0x00} }, -{ 13, 0x08ab, 0, {0x8a,0x04,0x8b,0x05,0xc3,0xea,0x94,0xe0,0xeb,0x94,0x2e,0x50,0x1a} }, -{ 14, 0x08b8, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, -{ 10, 0x08c6, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} }, -{ 2, 0x08d0, 0, {0x80,0xd9} }, -{ 13, 0x08d2, 0, {0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0,0x90} }, -{ 14, 0x08df, 0, {0x7f,0xde,0x74,0x05,0xf0,0x90,0x7f,0xdf,0x74,0x05,0xf0,0x90,0x7f,0xac} }, -{ 14, 0x08ed, 0, {0xe4,0xf0,0x90,0x7f,0xad,0x74,0x05,0xf0,0x75,0xa8,0x80,0x75,0xf8,0x10} }, -{ 13, 0x08fb, 0, {0x90,0x7f,0xae,0x74,0x0b,0xf0,0x90,0x7f,0xe2,0x74,0x88,0xf0,0x90} }, -{ 12, 0x0908, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0xe8,0x11,0x75,0x32,0x01,0x75} }, -{ 12, 0x0914, 0, {0x31,0x00,0x75,0x30,0x00,0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7} }, -{ 10, 0x0920, 0, {0xd0,0x05,0xd0,0x04,0x75,0x34,0x00,0x75,0x35,0x01} }, -{ 13, 0x092a, 0, {0x90,0x7f,0xae,0x74,0x03,0xf0,0x8c,0x02,0xba,0x00,0x02,0x80,0x03} }, -{ 3, 0x0937, 0, {0x02,0x0a,0x3f} }, -{ 12, 0x093a, 0, {0x85,0x33,0x34,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90,0x7f,0x97} }, -{ 14, 0x0946, 0, {0x74,0x08,0xf0,0x90,0x7f,0x9d,0x74,0x88,0xf0,0x90,0x7f,0x9a,0xe0,0xfa} }, -{ 12, 0x0954, 0, {0x74,0x05,0x5a,0xf5,0x33,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} }, -{ 13, 0x0960, 0, {0x7f,0x97,0x74,0x02,0xf0,0x90,0x7f,0x9d,0x74,0x82,0xf0,0xe5,0x33} }, -{ 13, 0x096d, 0, {0x25,0xe0,0xfa,0x90,0x7f,0x9a,0xe0,0x54,0x05,0xfb,0x4a,0xf5,0x33} }, -{ 2, 0x097a, 0, {0x60,0x0c} }, -{ 12, 0x097c, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x4a,0xf0} }, -{ 11, 0x0988, 0, {0x75,0x6e,0x00,0x75,0x6f,0x00,0xc0,0x04,0xc0,0x05,0x12} }, -{ 14, 0x0993, 0, {0x11,0x44,0xd0,0x05,0xd0,0x04,0x90,0x17,0x13,0xe0,0xfa,0x74,0x80,0x2a} }, -{ 6, 0x09a1, 0, {0xfa,0xe5,0x33,0xb4,0x04,0x29} }, -{ 3, 0x09a7, 0, {0xba,0xa0,0x00} }, -{ 2, 0x09aa, 0, {0x50,0x24} }, -{ 13, 0x09ac, 0, {0x90,0x17,0x13,0xe0,0x04,0xfb,0x0b,0x90,0x17,0x13,0xeb,0xf0,0x90} }, -{ 14, 0x09b9, 0, {0x17,0x13,0xe0,0xfb,0x90,0x17,0x15,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05} }, -{ 9, 0x09c7, 0, {0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02} }, -{ 5, 0x09d0, 0, {0xe5,0x33,0xb4,0x02,0x26} }, -{ 6, 0x09d5, 0, {0xc3,0x74,0x04,0x9a,0x50,0x20} }, -{ 13, 0x09db, 0, {0x90,0x17,0x13,0xe0,0xfa,0x1a,0x1a,0x90,0x17,0x13,0xea,0xf0,0x90} }, -{ 13, 0x09e8, 0, {0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xf0,0xc0,0x04,0xc0,0x05,0x12} }, -{ 6, 0x09f5, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04} }, -{ 5, 0x09fb, 0, {0xe5,0x33,0xb4,0x08,0x1d} }, -{ 4, 0x0a00, 0, {0xe5,0x34,0x70,0x19} }, -{ 10, 0x0a04, 0, {0x74,0x01,0x25,0x35,0x54,0x0f,0xf5,0x35,0x85,0x35} }, -{ 12, 0x0a0e, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} }, -{ 3, 0x0a1a, 0, {0x05,0xd0,0x04} }, -{ 5, 0x0a1d, 0, {0xe5,0x33,0xb4,0x01,0x1d} }, -{ 4, 0x0a22, 0, {0xe5,0x34,0x70,0x19} }, -{ 10, 0x0a26, 0, {0xe5,0x35,0x24,0xff,0x54,0x0f,0xf5,0x35,0x85,0x35} }, -{ 12, 0x0a30, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} }, -{ 3, 0x0a3c, 0, {0x05,0xd0,0x04} }, -{ 14, 0x0a3f, 0, {0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0,0x04,0x90,0x7f,0x96} }, -{ 14, 0x0a4d, 0, {0xe0,0xfa,0x90,0x7f,0x96,0x74,0x7f,0x5a,0xf0,0x90,0x7f,0x97,0x74,0x08} }, -{ 10, 0x0a5b, 0, {0xf0,0xc3,0xec,0x94,0x00,0xed,0x94,0x02,0x40,0x08} }, -{ 8, 0x0a65, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x20,0xe6,0x08} }, -{ 8, 0x0a6d, 0, {0xc3,0xe4,0x9c,0x74,0x08,0x9d,0x50,0x13} }, -{ 14, 0x0a75, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x40,0x65,0x02,0xf0,0x7c} }, -{ 5, 0x0a83, 0, {0x00,0x7d,0x00,0x80,0x05} }, -{ 5, 0x0a88, 0, {0x0c,0xbc,0x00,0x01,0x0d} }, -{ 5, 0x0a8d, 0, {0xe5,0x38,0xb4,0x01,0x0e} }, -{ 13, 0x0a92, 0, {0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0x75,0x38} }, -{ 1, 0x0a9f, 0, {0x00} }, -{ 7, 0x0aa0, 0, {0xe5,0x31,0x70,0x03,0x02,0x09,0x2a} }, -{ 10, 0x0aa7, 0, {0x90,0x7f,0xc9,0xe0,0xfa,0x70,0x03,0x02,0x0c,0x2d} }, -{ 14, 0x0ab1, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} }, -{ 9, 0x0abf, 0, {0x7d,0xc0,0xe0,0xfa,0xba,0x2c,0x02,0x80,0x03} }, -{ 3, 0x0ac8, 0, {0x02,0x0b,0x36} }, -{ 5, 0x0acb, 0, {0x75,0x32,0x00,0x7b,0x00} }, -{ 3, 0x0ad0, 0, {0xbb,0x64,0x00} }, -{ 2, 0x0ad3, 0, {0x50,0x1c} }, -{ 14, 0x0ad5, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, -{ 13, 0x0ae3, 0, {0x04,0xd0,0x03,0xd0,0x02,0x90,0x88,0x0f,0xe0,0xf5,0x47,0x0b,0x80} }, -{ 1, 0x0af0, 0, {0xdf} }, -{ 13, 0x0af1, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x07,0x1e,0x12,0x03,0xe1,0x12} }, -{ 12, 0x0afe, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x75,0x6e,0x00,0x75} }, -{ 13, 0x0b0a, 0, {0x6f,0x01,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0x44,0xd0,0x05} }, -{ 9, 0x0b17, 0, {0xd0,0x04,0xd0,0x02,0x75,0x70,0x4d,0x75,0x71} }, -{ 11, 0x0b20, 0, {0x0c,0x75,0x72,0x02,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} }, -{ 11, 0x0b2b, 0, {0x11,0x75,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x02,0x0c,0x2d} }, -{ 3, 0x0b36, 0, {0xba,0x2a,0x3b} }, -{ 13, 0x0b39, 0, {0x90,0x7f,0x98,0x74,0x20,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} }, -{ 14, 0x0b46, 0, {0x01,0xdd,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x90,0x7f,0x98,0x74,0x28,0xf0} }, -{ 2, 0x0b54, 0, {0x7b,0x00} }, -{ 3, 0x0b56, 0, {0xbb,0x0a,0x00} }, -{ 5, 0x0b59, 0, {0x40,0x03,0x02,0x0c,0x2d} }, -{ 14, 0x0b5e, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} }, -{ 8, 0x0b6c, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0b,0x80,0xe2} }, -{ 3, 0x0b74, 0, {0xba,0x2b,0x1a} }, -{ 8, 0x0b77, 0, {0x90,0x7f,0xc9,0xe0,0xfb,0xbb,0x40,0x12} }, -{ 14, 0x0b7f, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x12,0x05,0xd0,0x05,0xd0,0x04,0xd0} }, -{ 4, 0x0b8d, 0, {0x02,0x02,0x0c,0x2d} }, -{ 3, 0x0b91, 0, {0xba,0x10,0x1f} }, -{ 14, 0x0b94, 0, {0x90,0x7f,0x96,0xe0,0xfb,0x90,0x7f,0x96,0x74,0x80,0x65,0x03,0xf0,0xc0} }, -{ 14, 0x0ba2, 0, {0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x3d,0xd0,0x05,0xd0,0x04,0xd0,0x02} }, -{ 3, 0x0bb0, 0, {0x02,0x0c,0x2d} }, -{ 3, 0x0bb3, 0, {0xba,0x11,0x12} }, -{ 14, 0x0bb6, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x6a,0xd0,0x05,0xd0,0x04,0xd0} }, -{ 4, 0x0bc4, 0, {0x02,0x02,0x0c,0x2d} }, -{ 3, 0x0bc8, 0, {0xba,0x12,0x12} }, -{ 14, 0x0bcb, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x8f,0xd0,0x05,0xd0,0x04,0xd0} }, -{ 4, 0x0bd9, 0, {0x02,0x02,0x0c,0x2d} }, -{ 3, 0x0bdd, 0, {0xba,0x13,0x0b} }, -{ 11, 0x0be0, 0, {0x90,0x7d,0xc1,0xe0,0xfb,0x90,0x88,0x00,0xf0,0x80,0x42} }, -{ 3, 0x0beb, 0, {0xba,0x14,0x11} }, -{ 14, 0x0bee, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0xdd,0xd0,0x05,0xd0,0x04,0xd0} }, -{ 3, 0x0bfc, 0, {0x02,0x80,0x2e} }, -{ 3, 0x0bff, 0, {0xba,0x15,0x1d} }, -{ 12, 0x0c02, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x75,0x90,0x7d,0xc2,0xe0,0xf5,0x76} }, -{ 14, 0x0c0e, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0,0x05,0xd0,0x04,0xd0} }, -{ 3, 0x0c1c, 0, {0x02,0x80,0x0e} }, -{ 3, 0x0c1f, 0, {0xba,0x16,0x0b} }, -{ 11, 0x0c22, 0, {0xc0,0x04,0xc0,0x05,0x12,0x13,0xa3,0xd0,0x05,0xd0,0x04} }, -{ 11, 0x0c2d, 0, {0x90,0x7f,0xc9,0xe4,0xf0,0x75,0x31,0x00,0x02,0x09,0x2a} }, -{ 1, 0x0c38, 0, {0x22} }, -{ 7, 0x0c39, 0, {0x53,0x55,0x50,0x45,0x4e,0x44,0x00} }, -{ 7, 0x0c40, 0, {0x52,0x45,0x53,0x55,0x4d,0x45,0x00} }, -{ 6, 0x0c47, 0, {0x20,0x56,0x6f,0x6c,0x20,0x00} }, -{ 13, 0x0c4d, 0, {0x44,0x41,0x42,0x55,0x53,0x42,0x20,0x76,0x31,0x2e,0x30,0x30,0x00} }, -{ 14, 0x0c5a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} }, -{ 14, 0x0c68, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} }, -{ 13, 0x0c76, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} }, -{ 14, 0x0c83, 0, {0x7f,0xab,0x74,0x01,0xf0,0x90,0x7f,0xe8,0xe0,0xfa,0x90,0x7f,0xe9,0xe0} }, -{ 6, 0x0c91, 0, {0xfb,0xbb,0x00,0x02,0x80,0x03} }, -{ 3, 0x0c97, 0, {0x02,0x0d,0x38} }, -{ 3, 0x0c9a, 0, {0xba,0x80,0x14} }, -{ 14, 0x0c9d, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5} }, -{ 6, 0x0cab, 0, {0x74,0x02,0xf0,0x02,0x0e,0xcd} }, -{ 5, 0x0cb1, 0, {0xba,0x82,0x02,0x80,0x03} }, -{ 3, 0x0cb6, 0, {0x02,0x0d,0x1d} }, -{ 8, 0x0cb9, 0, {0x90,0x7f,0xec,0xe0,0xfc,0xbc,0x01,0x00} }, -{ 2, 0x0cc1, 0, {0x40,0x21} }, -{ 6, 0x0cc3, 0, {0xc3,0x74,0x07,0x9c,0x40,0x1b} }, -{ 14, 0x0cc9, 0, {0xec,0x24,0xff,0x25,0xe0,0xfd,0x24,0xc6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} }, -{ 13, 0x0cd7, 0, {0x83,0xe0,0xfd,0x53,0x05,0x01,0x90,0x7f,0x00,0xed,0xf0,0x80,0x2b} }, -{ 3, 0x0ce4, 0, {0xbc,0x81,0x00} }, -{ 2, 0x0ce7, 0, {0x40,0x21} }, -{ 6, 0x0ce9, 0, {0xc3,0x74,0x87,0x9c,0x40,0x1b} }, -{ 14, 0x0cef, 0, {0xec,0x24,0x7f,0x25,0xe0,0xfc,0x24,0xb6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} }, -{ 13, 0x0cfd, 0, {0x83,0xe0,0xfc,0x53,0x04,0x01,0x90,0x7f,0x00,0xec,0xf0,0x80,0x05} }, -{ 5, 0x0d0a, 0, {0x90,0x7f,0x00,0xe4,0xf0} }, -{ 14, 0x0d0f, 0, {0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x02,0x0e,0xcd} }, -{ 5, 0x0d1d, 0, {0xba,0x81,0x02,0x80,0x03} }, -{ 3, 0x0d22, 0, {0x02,0x0e,0xc5} }, -{ 14, 0x0d25, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74} }, -{ 5, 0x0d33, 0, {0x02,0xf0,0x02,0x0e,0xcd} }, -{ 3, 0x0d38, 0, {0xbb,0x01,0x2d} }, -{ 6, 0x0d3b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} }, -{ 3, 0x0d41, 0, {0xba,0x02,0x11} }, -{ 13, 0x0d44, 0, {0x75,0x59,0x00,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} }, -{ 4, 0x0d51, 0, {0x02,0x02,0x0e,0xcd} }, -{ 5, 0x0d55, 0, {0xba,0x21,0x02,0x80,0x03} }, -{ 3, 0x0d5a, 0, {0x02,0x0e,0xcd} }, -{ 11, 0x0d5d, 0, {0x75,0x37,0x01,0x90,0x7f,0xc5,0xe4,0xf0,0x02,0x0e,0xcd} }, -{ 3, 0x0d68, 0, {0xbb,0x03,0x1f} }, -{ 6, 0x0d6b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} }, -{ 5, 0x0d71, 0, {0xba,0x02,0x02,0x80,0x03} }, -{ 3, 0x0d76, 0, {0x02,0x0e,0xcd} }, -{ 13, 0x0d79, 0, {0x75,0x59,0x01,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} }, -{ 4, 0x0d86, 0, {0x02,0x02,0x0e,0xcd} }, -{ 3, 0x0d8a, 0, {0xbb,0x06,0x54} }, -{ 5, 0x0d8d, 0, {0xba,0x80,0x02,0x80,0x03} }, -{ 3, 0x0d92, 0, {0x02,0x0e,0xc5} }, -{ 8, 0x0d95, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x01,0x15} }, -{ 12, 0x0d9d, 0, {0x7c,0xfb,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} }, -{ 9, 0x0da9, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} }, -{ 10, 0x0db2, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x02,0x02,0x80,0x03} }, -{ 3, 0x0dbc, 0, {0x02,0x0e,0xc5} }, -{ 10, 0x0dbf, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x02,0x80,0x03} }, -{ 3, 0x0dc9, 0, {0x02,0x0e,0xc5} }, -{ 12, 0x0dcc, 0, {0x7c,0x3b,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} }, -{ 9, 0x0dd8, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} }, -{ 6, 0x0de1, 0, {0xbb,0x07,0x03,0x02,0x0e,0xc5} }, -{ 3, 0x0de7, 0, {0xbb,0x08,0x10} }, -{ 13, 0x0dea, 0, {0xac,0x48,0x90,0x7f,0x00,0xec,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} }, -{ 3, 0x0df7, 0, {0x02,0x0e,0xcd} }, -{ 3, 0x0dfa, 0, {0xbb,0x09,0x31} }, -{ 5, 0x0dfd, 0, {0xba,0x00,0x02,0x80,0x03} }, -{ 3, 0x0e02, 0, {0x02,0x0e,0xc5} }, -{ 14, 0x0e05, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xc3,0x74,0x01,0x9c,0x50,0x03,0x02,0x0e,0xc5} }, -{ 8, 0x0e13, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x0a} }, -{ 10, 0x0e1b, 0, {0x90,0x17,0x21,0xe4,0xf0,0x90,0x17,0x22,0xe4,0xf0} }, -{ 9, 0x0e25, 0, {0x90,0x7f,0xea,0xe0,0xf5,0x48,0x02,0x0e,0xcd} }, -{ 3, 0x0e2e, 0, {0xbb,0x0a,0x27} }, -{ 5, 0x0e31, 0, {0xba,0x81,0x02,0x80,0x03} }, -{ 3, 0x0e36, 0, {0x02,0x0e,0xc5} }, -{ 14, 0x0e39, 0, {0x90,0x7f,0xec,0xe0,0xfa,0x24,0x20,0xfa,0xe4,0x34,0x17,0xfc,0x8a,0x82} }, -{ 14, 0x0e47, 0, {0x8c,0x83,0xe0,0xfa,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} }, -{ 3, 0x0e55, 0, {0x02,0x0e,0xcd} }, -{ 5, 0x0e58, 0, {0xbb,0x0b,0x02,0x80,0x03} }, -{ 3, 0x0e5d, 0, {0x02,0x0e,0xa9} }, -{ 13, 0x0e60, 0, {0x90,0x17,0x20,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0xfa,0xba,0x01,0x1a} }, -{ 8, 0x0e6d, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x12} }, -{ 14, 0x0e75, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x90,0x17,0x21,0xf0,0xc0,0x03,0x12,0x04,0xe2} }, -{ 4, 0x0e83, 0, {0xd0,0x03,0x80,0x46} }, -{ 8, 0x0e87, 0, {0x90,0x7f,0xec,0xe0,0xfa,0xba,0x02,0x3e} }, -{ 8, 0x0e8f, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x36} }, -{ 13, 0x0e97, 0, {0xc0,0x03,0x12,0x04,0xef,0xd0,0x03,0x90,0x7f,0xea,0xe0,0xfa,0x90} }, -{ 5, 0x0ea4, 0, {0x17,0x22,0xf0,0x80,0x24} }, -{ 5, 0x0ea9, 0, {0xbb,0x12,0x02,0x80,0x17} }, -{ 5, 0x0eae, 0, {0xbb,0x81,0x02,0x80,0x0d} }, -{ 5, 0x0eb3, 0, {0xbb,0x83,0x02,0x80,0x08} }, -{ 5, 0x0eb8, 0, {0xbb,0x82,0x02,0x80,0x03} }, -{ 3, 0x0ebd, 0, {0xbb,0x84,0x05} }, -{ 5, 0x0ec0, 0, {0x12,0x06,0x4e,0x80,0x08} }, -{ 8, 0x0ec5, 0, {0x90,0x7f,0xb4,0x74,0x03,0xf0,0x80,0x06} }, -{ 6, 0x0ecd, 0, {0x90,0x7f,0xb4,0x74,0x02,0xf0} }, -{ 2, 0x0ed3, 0, {0xd0,0x86} }, -{ 14, 0x0ed5, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} }, -{ 13, 0x0ee3, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} }, -{ 11, 0x0ef0, 0, {0x90,0x7f,0xec,0xe0,0xf5,0x5a,0xc3,0x94,0x01,0x40,0x1d} }, -{ 7, 0x0efb, 0, {0xc3,0x74,0x07,0x95,0x5a,0x40,0x16} }, -{ 13, 0x0f02, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xc6,0xf5,0x82,0xe4,0x34} }, -{ 9, 0x0f0f, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0,0x80,0x22} }, -{ 7, 0x0f18, 0, {0xc3,0xe5,0x5a,0x94,0x81,0x40,0x1b} }, -{ 7, 0x0f1f, 0, {0xc3,0x74,0x87,0x95,0x5a,0x40,0x14} }, -{ 13, 0x0f26, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xb6,0xf5,0x82,0xe4,0x34} }, -{ 7, 0x0f33, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0} }, -{ 1, 0x0f3a, 0, {0x22} }, -{ 14, 0x0f3b, 0, {0x09,0x02,0xba,0x00,0x03,0x01,0x00,0x40,0x00,0x09,0x04,0x00,0x00,0x00} }, -{ 14, 0x0f49, 0, {0x01,0x01,0x00,0x00,0x09,0x24,0x01,0x00,0x01,0x3d,0x00,0x01,0x01,0x0c} }, -{ 14, 0x0f57, 0, {0x24,0x02,0x01,0x10,0x07,0x00,0x02,0x03,0x00,0x00,0x00,0x0d,0x24,0x06} }, -{ 14, 0x0f65, 0, {0x03,0x01,0x02,0x15,0x00,0x03,0x00,0x03,0x00,0x00,0x09,0x24,0x03,0x02} }, -{ 14, 0x0f73, 0, {0x01,0x01,0x00,0x01,0x00,0x09,0x24,0x03,0x04,0x02,0x03,0x00,0x03,0x00} }, -{ 14, 0x0f81, 0, {0x09,0x24,0x03,0x05,0x03,0x06,0x00,0x01,0x00,0x09,0x04,0x01,0x00,0x00} }, -{ 14, 0x0f8f, 0, {0x01,0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00,0x07} }, -{ 14, 0x0f9d, 0, {0x24,0x01,0x02,0x01,0x01,0x00,0x0b,0x24,0x02,0x01,0x02,0x02,0x10,0x01} }, -{ 14, 0x0fab, 0, {0x80,0xbb,0x00,0x09,0x05,0x88,0x05,0x00,0x01,0x01,0x00,0x00,0x07,0x25} }, -{ 14, 0x0fb9, 0, {0x01,0x00,0x00,0x00,0x00,0x09,0x04,0x02,0x00,0x02,0x00,0x00,0x00,0x00} }, -{ 14, 0x0fc7, 0, {0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00} }, -{ 14, 0x0fd5, 0, {0x09,0x04,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x07,0x05,0x82,0x02,0x40} }, -{ 14, 0x0fe3, 0, {0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00,0x09,0x05,0x89,0x05,0xa0} }, -{ 10, 0x0ff1, 0, {0x01,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00} }, -{ 14, 0x0ffb, 0, {0x12,0x01,0x00,0x01,0x00,0x00,0x00,0x40,0x47,0x05,0x99,0x99,0x00,0x01} }, -{ 14, 0x1009, 0, {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x02,0xba} }, -{ 4, 0x1017, 0, {0x00,0x03,0x01,0x00} }, -{ 2, 0x101b, 0, {0x7a,0x00} }, -{ 3, 0x101d, 0, {0xba,0x05,0x00} }, -{ 2, 0x1020, 0, {0x50,0x17} }, -{ 8, 0x1022, 0, {0x90,0x7f,0xa5,0xe0,0xfb,0x30,0xe0,0x05} }, -{ 5, 0x102a, 0, {0x90,0x00,0x01,0x80,0x0d} }, -{ 10, 0x102f, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xe4} }, -{ 3, 0x1039, 0, {0x90,0x00,0x01} }, -{ 1, 0x103c, 0, {0x22} }, -{ 14, 0x103d, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0x00,0x7d} }, -{ 4, 0x104b, 0, {0x7e,0xeb,0x60,0x12} }, -{ 14, 0x104f, 0, {0x89,0x82,0x8a,0x83,0xe0,0xa3,0xa9,0x82,0xaa,0x83,0x8c,0x82,0x8d,0x83} }, -{ 4, 0x105d, 0, {0xf0,0x0c,0xdb,0xee} }, -{ 8, 0x1061, 0, {0x90,0x7d,0xc3,0xe0,0x90,0x7f,0xb9,0xf0} }, -{ 1, 0x1069, 0, {0x22} }, -{ 14, 0x106a, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0xc4,0x7d} }, -{ 4, 0x1078, 0, {0x7d,0xeb,0x60,0xe5} }, -{ 14, 0x107c, 0, {0x8c,0x82,0x8d,0x83,0xe0,0x0c,0x89,0x82,0x8a,0x83,0xf0,0xa3,0xa9,0x82} }, -{ 4, 0x108a, 0, {0xaa,0x83,0xdb,0xee} }, -{ 1, 0x108e, 0, {0x22} }, -{ 14, 0x108f, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x05,0x86,0x90,0x7d,0xc1,0xe0,0x05,0x86} }, -{ 14, 0x109d, 0, {0xa3,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0x05,0x86,0xa3,0xa3,0xe0,0xf9} }, -{ 5, 0x10ab, 0, {0x60,0x16,0xa3,0x05,0x86} }, -{ 13, 0x10b0, 0, {0x90,0x7f,0xa6,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xc0,0x01,0x12} }, -{ 6, 0x10bd, 0, {0x10,0x1b,0xd0,0x01,0xd9,0xed} }, -{ 6, 0x10c3, 0, {0x90,0x7f,0xa5,0x74,0x40,0xf0} }, -{ 1, 0x10c9, 0, {0x22} }, -{ 8, 0x10ca, 0, {0x90,0x88,0x02,0x74,0x01,0xf0,0x7a,0x00} }, -{ 3, 0x10d2, 0, {0xba,0xff,0x00} }, -{ 2, 0x10d5, 0, {0x50,0x0a} }, -{ 10, 0x10d7, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} }, -{ 1, 0x10e1, 0, {0x22} }, -{ 5, 0x10e2, 0, {0xe5,0x6b,0xb4,0xc0,0x08} }, -{ 8, 0x10e7, 0, {0x90,0x88,0x03,0xe5,0x6c,0xf0,0x80,0x06} }, -{ 6, 0x10ef, 0, {0x90,0x88,0x02,0xe5,0x6c,0xf0} }, -{ 4, 0x10f5, 0, {0x7a,0x00,0x7b,0x00} }, -{ 11, 0x10f9, 0, {0xc3,0xea,0x94,0x32,0xeb,0x64,0x80,0x94,0x80,0x50,0x07} }, -{ 5, 0x1104, 0, {0x0a,0xba,0x00,0x01,0x0b} }, -{ 2, 0x1109, 0, {0x80,0xee} }, -{ 1, 0x110b, 0, {0x22} }, -{ 10, 0x110c, 0, {0x90,0x88,0x03,0xe5,0x6d,0xf0,0x05,0x39,0x7a,0x00} }, -{ 3, 0x1116, 0, {0xba,0x28,0x00} }, -{ 2, 0x1119, 0, {0x50,0x03} }, -{ 3, 0x111b, 0, {0x0a,0x80,0xf8} }, -{ 5, 0x111e, 0, {0xe5,0x39,0xb4,0x10,0x08} }, -{ 8, 0x1123, 0, {0x90,0x88,0x02,0x74,0xc0,0xf0,0x80,0x0e} }, -{ 5, 0x112b, 0, {0xe5,0x39,0xb4,0x20,0x09} }, -{ 9, 0x1130, 0, {0x90,0x88,0x02,0x74,0x80,0xf0,0x75,0x39,0x00} }, -{ 2, 0x1139, 0, {0x7a,0x00} }, -{ 3, 0x113b, 0, {0xba,0x28,0x00} }, -{ 2, 0x113e, 0, {0x50,0x03} }, -{ 3, 0x1140, 0, {0x0a,0x80,0xf8} }, -{ 1, 0x1143, 0, {0x22} }, -{ 4, 0x1144, 0, {0xe5,0x6f,0x60,0x02} }, -{ 2, 0x1148, 0, {0x80,0x07} }, -{ 7, 0x114a, 0, {0x7a,0x00,0x75,0x39,0x00,0x80,0x05} }, -{ 5, 0x1151, 0, {0x7a,0x40,0x75,0x39,0x10} }, -{ 9, 0x1156, 0, {0xe5,0x6e,0x2a,0xfa,0xe5,0x6e,0x25,0x39,0xf5} }, -{ 10, 0x115f, 0, {0x39,0x90,0x88,0x02,0x74,0x80,0x2a,0xf0,0x7a,0x00} }, -{ 8, 0x1169, 0, {0xc3,0xea,0x64,0x80,0x94,0xa8,0x50,0x03} }, -{ 3, 0x1171, 0, {0x0a,0x80,0xf5} }, -{ 1, 0x1174, 0, {0x22} }, -{ 6, 0x1175, 0, {0xaa,0x70,0xab,0x71,0xac,0x72} }, -{ 12, 0x117b, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x12,0x14,0xee,0xfd,0x60,0x18} }, -{ 13, 0x1187, 0, {0x8d,0x6d,0xc0,0x02,0xc0,0x03,0xc0,0x04,0x12,0x11,0x0c,0xd0,0x04} }, -{ 9, 0x1194, 0, {0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} }, -{ 2, 0x119d, 0, {0x80,0xdc} }, -{ 1, 0x119f, 0, {0x22} }, -{ 13, 0x11a0, 0, {0xe5,0x73,0xc4,0x54,0x0f,0xfa,0x53,0x02,0x0f,0xc3,0x74,0x09,0x9a} }, -{ 2, 0x11ad, 0, {0x50,0x06} }, -{ 6, 0x11af, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} }, -{ 4, 0x11b5, 0, {0x74,0x30,0x2a,0xfb} }, -{ 12, 0x11b9, 0, {0x8b,0x6d,0xc0,0x03,0x12,0x11,0x0c,0xd0,0x03,0xaa,0x73,0x53} }, -{ 8, 0x11c5, 0, {0x02,0x0f,0xc3,0x74,0x09,0x9a,0x50,0x06} }, -{ 6, 0x11cd, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} }, -{ 4, 0x11d3, 0, {0x74,0x30,0x2a,0xfb} }, -{ 5, 0x11d7, 0, {0x8b,0x6d,0x12,0x11,0x0c} }, -{ 1, 0x11dc, 0, {0x22} }, -{ 7, 0x11dd, 0, {0x90,0x7d,0xc3,0xe0,0xfa,0x60,0x0f} }, -{ 12, 0x11e4, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x6e,0x90,0x7d,0xc2,0xe0,0xf5,0x6f} }, -{ 3, 0x11f0, 0, {0x12,0x11,0x44} }, -{ 12, 0x11f3, 0, {0x90,0x7d,0xff,0xe4,0xf0,0x75,0x70,0xc4,0x75,0x71,0x7d,0x75} }, -{ 5, 0x11ff, 0, {0x72,0x01,0x12,0x11,0x75} }, -{ 1, 0x1204, 0, {0x22} }, -{ 2, 0x1205, 0, {0x7a,0x04} }, -{ 3, 0x1207, 0, {0xba,0x40,0x00} }, -{ 2, 0x120a, 0, {0x50,0x36} }, -{ 14, 0x120c, 0, {0xea,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfb,0x7c,0x00} }, -{ 3, 0x121a, 0, {0xbc,0x08,0x00} }, -{ 2, 0x121d, 0, {0x50,0x20} }, -{ 6, 0x121f, 0, {0x8b,0x05,0xed,0x30,0xe7,0x0b} }, -{ 11, 0x1225, 0, {0x90,0x7f,0x96,0x74,0x42,0xf0,0x74,0xc3,0xf0,0x80,0x08} }, -{ 8, 0x1230, 0, {0x90,0x7f,0x96,0xe4,0xf0,0x74,0x81,0xf0} }, -{ 7, 0x1238, 0, {0xeb,0x25,0xe0,0xfb,0x0c,0x80,0xdb} }, -{ 3, 0x123f, 0, {0x0a,0x80,0xc5} }, -{ 1, 0x1242, 0, {0x22} }, -{ 4, 0x1243, 0, {0x7a,0x00,0x7b,0xef} }, -{ 3, 0x1247, 0, {0xba,0x10,0x00} }, -{ 2, 0x124a, 0, {0x50,0x20} }, -{ 14, 0x124c, 0, {0x74,0x11,0x2b,0xfb,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0x8c,0x82,0x8d} }, -{ 14, 0x125a, 0, {0x83,0xe4,0xf0,0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe4} }, -{ 4, 0x1268, 0, {0xf0,0x0a,0x80,0xdb} }, -{ 1, 0x126c, 0, {0x22} }, -{ 14, 0x126d, 0, {0x74,0xf8,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, -{ 14, 0x127b, 0, {0x74,0xf9,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, -{ 14, 0x1289, 0, {0x74,0xfa,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, -{ 14, 0x1297, 0, {0x74,0xfb,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, -{ 14, 0x12a5, 0, {0x74,0xff,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} }, -{ 1, 0x12b3, 0, {0x22} }, -{ 14, 0x12b4, 0, {0x12,0x03,0xcb,0x12,0x12,0x6d,0x7a,0xc0,0x7b,0x87,0x7c,0x01,0x74,0x01} }, -{ 14, 0x12c2, 0, {0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74} }, -{ 14, 0x12d0, 0, {0x01,0x12,0x14,0xbf,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e} }, -{ 14, 0x12de, 0, {0x83,0x8f,0xf0,0x74,0x06,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b} }, -{ 14, 0x12ec, 0, {0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74} }, -{ 14, 0x12fa, 0, {0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0} }, -{ 14, 0x1308, 0, {0x74,0x0b,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07} }, -{ 14, 0x1316, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74,0x08,0x12,0x14,0xbf,0x74,0x01,0x2d} }, -{ 14, 0x1324, 0, {0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x01} }, -{ 14, 0x1332, 0, {0x12,0x14,0xbf,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83} }, -{ 14, 0x1340, 0, {0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74,0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f} }, -{ 14, 0x134e, 0, {0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x03,0x12,0x14,0xbf,0x7d,0x00} }, -{ 3, 0x135c, 0, {0xbd,0x06,0x00} }, -{ 2, 0x135f, 0, {0x50,0x12} }, -{ 11, 0x1361, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x0a,0xba,0x00,0x01,0x0b} }, -{ 7, 0x136c, 0, {0xe4,0x12,0x14,0xbf,0x0d,0x80,0xe9} }, -{ 13, 0x1373, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe5,0x74,0x12,0x14,0xbf,0x74,0xf9} }, -{ 14, 0x1380, 0, {0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x0f,0xf0,0x74} }, -{ 14, 0x138e, 0, {0xfe,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x01,0xf0} }, -{ 6, 0x139c, 0, {0x12,0x03,0xe1,0x12,0x04,0xf7} }, -{ 1, 0x13a2, 0, {0x22} }, -{ 13, 0x13a3, 0, {0x90,0x7d,0xc1,0xe0,0xfa,0x24,0x00,0xfb,0xe4,0x34,0x19,0xfc,0x90} }, -{ 14, 0x13b0, 0, {0x7d,0xc2,0xe0,0xfd,0x8b,0x82,0x8c,0x83,0xf0,0x75,0xf0,0x11,0xea,0xa4} }, -{ 3, 0x13be, 0, {0xfa,0x7b,0x00} }, -{ 3, 0x13c1, 0, {0xbb,0x10,0x00} }, -{ 2, 0x13c4, 0, {0x50,0x24} }, -{ 14, 0x13c6, 0, {0xea,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0xeb,0x2c,0xfc,0xe4,0x3d,0xfd} }, -{ 14, 0x13d4, 0, {0x74,0x04,0x2b,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfe} }, -{ 8, 0x13e2, 0, {0x8c,0x82,0x8d,0x83,0xf0,0x0b,0x80,0xd7} }, -{ 14, 0x13ea, 0, {0xea,0x24,0x00,0xfa,0xe4,0x34,0x18,0xfb,0x74,0x10,0x2a,0xf5,0x82,0xe4} }, -{ 5, 0x13f8, 0, {0x3b,0xf5,0x83,0xe4,0xf0} }, -{ 1, 0x13fd, 0, {0x22} }, -{ 4, 0x13fe, 0, {0xe5,0x76,0x60,0x02} }, -{ 2, 0x1402, 0, {0x80,0x16} }, -{ 12, 0x1404, 0, {0x74,0x0f,0x55,0x75,0xfa,0x8a,0x75,0x24,0x00,0xf5,0x82,0xe4} }, -{ 10, 0x1410, 0, {0x34,0x19,0xf5,0x83,0xe0,0xf5,0x74,0x12,0x12,0xb4} }, -{ 10, 0x141a, 0, {0x12,0x10,0xca,0x75,0x6e,0x00,0x75,0x6f,0x00,0x12} }, -{ 6, 0x1424, 0, {0x11,0x44,0x75,0x70,0xb9,0x75} }, -{ 6, 0x142a, 0, {0x71,0x14,0x75,0x72,0x02,0x12} }, -{ 11, 0x1430, 0, {0x11,0x75,0xe5,0x76,0xb4,0x02,0x04,0x74,0x01,0x80,0x01} }, -{ 1, 0x143b, 0, {0xe4} }, -{ 3, 0x143c, 0, {0xfa,0x70,0x0f} }, -{ 12, 0x143f, 0, {0x74,0x01,0x25,0x75,0xf5,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0} }, -{ 3, 0x144b, 0, {0x02,0x80,0x0a} }, -{ 10, 0x144e, 0, {0x85,0x75,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0,0x02} }, -{ 12, 0x1458, 0, {0x75,0x6e,0x00,0x75,0x6f,0x01,0xc0,0x02,0x12,0x11,0x44,0xd0} }, -{ 4, 0x1464, 0, {0x02,0xea,0x70,0x1a} }, -{ 13, 0x1468, 0, {0x75,0xf0,0x11,0xe5,0x75,0xa4,0xfa,0x24,0x00,0xfa,0xe4,0x34,0x18} }, -{ 9, 0x1475, 0, {0xfb,0x8a,0x70,0x8b,0x71,0x75,0x72,0x01,0x12} }, -{ 4, 0x147e, 0, {0x11,0x75,0x80,0x36} }, -{ 2, 0x1482, 0, {0x7a,0x00} }, -{ 3, 0x1484, 0, {0xba,0x10,0x00} }, -{ 2, 0x1487, 0, {0x50,0x2f} }, -{ 13, 0x1489, 0, {0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe0,0xfb,0xe5} }, -{ 4, 0x1496, 0, {0x75,0xb5,0x03,0x1b} }, -{ 14, 0x149a, 0, {0x75,0xf0,0x11,0xea,0xa4,0xfb,0x24,0x00,0xfb,0xe4,0x34,0x18,0xfc,0x8b} }, -{ 9, 0x14a8, 0, {0x70,0x8c,0x71,0x75,0x72,0x01,0xc0,0x02,0x12} }, -{ 4, 0x14b1, 0, {0x11,0x75,0xd0,0x02} }, -{ 3, 0x14b5, 0, {0x0a,0x80,0xcc} }, -{ 1, 0x14b8, 0, {0x22} }, -{ 6, 0x14b9, 0, {0x50,0x72,0x6f,0x67,0x20,0x00} }, -{ 14, 0x14bf, 0, {0xc8,0xc0,0xe0,0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0b,0x14,0x60,0x0f,0x14} }, -{ 7, 0x14cd, 0, {0x60,0x11,0x14,0x60,0x12,0x80,0x15} }, -{ 7, 0x14d4, 0, {0xd0,0xe0,0xa8,0x82,0xf6,0x80,0x0e} }, -{ 5, 0x14db, 0, {0xd0,0xe0,0xf0,0x80,0x09} }, -{ 4, 0x14e0, 0, {0xd0,0xe0,0x80,0x05} }, -{ 5, 0x14e4, 0, {0xd0,0xe0,0xa8,0x82,0xf2} }, -{ 4, 0x14e9, 0, {0xc8,0xd0,0xe0,0xc8} }, -{ 1, 0x14ed, 0, {0x22} }, -{ 14, 0x14ee, 0, {0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0d,0x14,0x60,0x0f,0x14,0x60,0x0f,0x14} }, -{ 6, 0x14fc, 0, {0x60,0x10,0x74,0xff,0x80,0x0f} }, -{ 5, 0x1502, 0, {0xa8,0x82,0xe6,0x80,0x0a} }, -{ 3, 0x1507, 0, {0xe0,0x80,0x07} }, -{ 4, 0x150a, 0, {0xe4,0x93,0x80,0x03} }, -{ 3, 0x150e, 0, {0xa8,0x82,0xe2} }, -{ 4, 0x1511, 0, {0xf8,0xd0,0xe0,0xc8} }, -{ 1, 0x1515, 0, {0x22} }, -{ 0, 0x0000, 1, {0} } - -}; - -static unsigned char bitstream[] = { - -0x00,0x09,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0, 0x0F,0xF0,0x00,0x00,0x01,0x61,0x00,0x0D, -0x64,0x61,0x62,0x75,0x73,0x62,0x74,0x72, 0x2E,0x6E,0x63,0x64,0x00,0x62,0x00,0x0B, -0x73,0x31,0x30,0x78,0x6C,0x76,0x71,0x31, 0x30,0x30,0x00,0x63,0x00,0x0B,0x31,0x39, -0x39,0x39,0x2F,0x30,0x39,0x2F,0x32,0x34, 0x00,0x64,0x00,0x09,0x31,0x30,0x3A,0x34, -0x32,0x3A,0x34,0x36,0x00,0x65,0x00,0x00, 0x2E,0xC0,0xFF,0x20,0x17,0x5F,0x9F,0x5B, -0xFE,0xFB,0xBB,0xB7,0xBB,0xBB,0xFB,0xBF, 0xAF,0xEF,0xFB,0xDF,0xB7,0xFB,0xFB,0x7F, -0xBF,0xB7,0xEF,0xF2,0xFF,0xFB,0xFE,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xBF,0xFF,0xFF, -0xFF,0xFF,0xAF,0xFF,0xFA,0xFF,0xFF,0xFF, 0xC9,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xA3,0xFF,0xFB, -0xFE,0xFF,0xBF,0xEF,0xE3,0xFE,0xFF,0xBF, 0xE3,0xFE,0xFF,0xBF,0x6F,0xFB,0xF6,0xFF, -0xBF,0xFF,0x47,0xFF,0xFF,0x9F,0xEE,0xF9, 0xFE,0xCF,0x9F,0xEF,0xFB,0xCF,0x9B,0xEE, -0xF8,0xFE,0xEF,0x8F,0xEE,0xFB,0xFE,0x0B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xBF,0xFF,0xFF,0xFB,0xFF,0xFF, 0xBF,0xFF,0xFF,0xFC,0x17,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFB,0xFF,0xFF,0x7F,0xFF,0xFF, -0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0xFF, 0xFF,0xFD,0xFF,0xFF,0xDB,0xFF,0xFD,0xFF, -0x77,0xFF,0xFD,0xFF,0xFF,0xDF,0xFE,0xFD, 0xFF,0xFF,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1, -0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xE3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, -0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x67,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0x7F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0x2F,0xFF, -0xF3,0xFD,0xFF,0x7F,0xDE,0xF7,0xFD,0xFF, 0x7F,0xF7,0x7D,0xFF,0x7F,0xDF,0xF7,0xBD, -0xFF,0x7F,0xFF,0x1F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xEF,0xFB, -0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, 0x3F,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F, -0x9F,0xE7,0xFA,0x7F,0x9F,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xFF,0xFC,0x7F,0xBF,0xBF, -0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xB7, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, -0xFF,0xE0,0xFD,0xF9,0xFE,0x7F,0x9F,0xE7, 0xF9,0xFE,0x7F,0x9D,0xF9,0xFE,0x7D,0x9D, -0xE7,0xF9,0xFE,0x7F,0x9F,0xED,0xED,0xFF, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, -0xDF,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF, 0x7F,0xDF,0xFF,0x9B,0xFF,0xEF,0xFB,0xFE, -0xFB,0xBF,0xEF,0xBB,0xFE,0xFF,0xAF,0xBB, 0xBE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, -0xB7,0xBF,0xDB,0xF6,0xBD,0xBF,0x6B,0xDB, 0xF6,0xF9,0xBF,0x5B,0xD6,0xF9,0xBF,0x6F, -0xDB,0xF6,0xFD,0xBF,0xFF,0x0E,0xFF,0xFF, 0xFF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0x7F, -0xF7,0xBD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xDF,0x9F,0xFF,0xFF,0xFF,0xFE,0xFF, -0xFF,0xEF,0xFE,0xFE,0xFF,0xFF,0x77,0xFF, 0xFB,0xFB,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F, -0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xF4,0x7F,0xFF,0xFE,0xFD, 0xBE,0xFF,0xDF,0xFE,0xFF,0xFF,0xEF,0x7F, -0xFF,0xCF,0xFF,0xCF,0xFF,0xFF,0xFF,0xDF, 0xE6,0xFF,0xFF,0x7F,0xDF,0xF7,0xDD,0x7F, -0x7F,0xDF,0xF7,0xFF,0x7F,0xDF,0xD7,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFF,0xCD,0xFF,0xF2, -0xFF,0xFF,0x4F,0x7F,0xF4,0xFF,0xFF,0xFF, 0xE7,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xBB,0xFF,0xEF,0xFF,0xFE,0xFF, 0xFF,0xFF,0xEF,0xFF,0xFF,0xEF,0xFF,0xFB, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x65, 0xEF,0xFF,0xFF,0x7F,0xFF,0xFD,0xEF,0xFF, -0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xCF,0xDF,0xFE,0xFF, -0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xF3,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFE,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xEF,0xEB,0xFF,0xFE,0xBF,0xFF, 0xEB,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xEE, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xD6,0xFF,0xFD,0xBF,0xFF,0xFB,0xFF,0xFE, -0xFD,0xFF,0xFF,0xFD,0xEF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xDE,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0x7F,0xBF, 0xFF,0x5F,0xDF,0xFF,0xFF,0xBF,0x77,0xFF, -0xFF,0xFF,0x7F,0xD7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF, -0xFF,0xFF,0xFE,0xFB,0xFF,0xFF,0xDF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xB7,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xAF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xBF,0xDF,0xF3,0xFD,0xFB,0xFF,0x5B, -0xFD,0xFF,0xBF,0xEF,0xF7,0xFF,0xFF,0x7D, 0xFF,0xFF,0xFF,0xFF,0xF8,0x3B,0xFF,0xBF, -0x6F,0xFF,0xFE,0xFF,0xBF,0xFF,0xEB,0x7D, 0xFF,0xEF,0xFB,0xFE,0xFF,0xFF,0xFF,0xFF, -0xFF,0xF2,0x7F,0xFC,0xFF,0x3F,0xDF,0xED, 0xFE,0xFF,0xFF,0xFF,0xFF,0xEF,0x5F,0xF7, -0xB5,0xFF,0xEF,0xFF,0xFF,0xFF,0xE0,0x3F, 0x9F,0x9E,0xFF,0xFF,0xEF,0xFF,0xDF,0xFF, -0xBF,0x5F,0xBF,0xCF,0xF3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x69,0xAF,0x33,0xFD,0xFF, -0xFB,0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0x7F, 0xD9,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xF5, -0xA3,0xDF,0x6E,0xDE,0xFF,0xFF,0xBD,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xE7,0xFD, -0xFF,0xFF,0xFF,0xF9,0xEF,0xC6,0xFE,0xB7, 0xAD,0xE5,0xF9,0xFF,0xFF,0xFF,0xCF,0xFF, -0xFF,0xFF,0xCD,0xFB,0x7F,0xFF,0xFF,0xFF, 0xF9,0xF6,0x0F,0xDF,0xEC,0xCF,0x7F,0xFF, -0xFB,0x7F,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE, 0xF9,0xFD,0x7F,0xFF,0x7F,0xFF,0xF9,0x5B, -0xFF,0x73,0xDC,0xFD,0x7B,0xDF,0xFF,0xFF, 0xFF,0x7B,0xFF,0xFF,0xF7,0x53,0xD6,0xFF, -0xFF,0xFF,0xFF,0xD8,0x9F,0xFE,0xFF,0xEF, 0x7F,0xEE,0xFF,0xFF,0xFF,0xFB,0xED,0xED, -0xFD,0xFF,0xFE,0xFF,0xFF,0xFB,0x7F,0xFF, 0xE2,0x7F,0xFF,0x6F,0xD8,0x57,0xF7,0xFF, -0xFF,0xFF,0xDF,0xFF,0xE8,0xFF,0xFF,0xFD, 0xFF,0xFF,0xFC,0x7F,0xFF,0xE4,0xFF,0xFB, -0xEF,0xFB,0xFE,0xDF,0xB7,0xED,0xFF,0xFE, 0xDF,0x7F,0xFF,0xFE,0x7F,0xB7,0xFF,0xFF, -0xFF,0xFF,0x89,0xFF,0xFF,0xCF,0xF3,0xFE, 0x7F,0xFF,0xEF,0xFF,0xFE,0x7E,0x7F,0xFB, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF1, 0xFF,0xEB,0x7A,0xD5,0xBF,0x6F,0xDB,0xBE, -0xFD,0xB7,0xD8,0xF6,0xE5,0xBF,0x6F,0xFB, 0xFE,0xF5,0xBD,0x7E,0x06,0xFF,0xDF,0xF7, -0xFB,0xF6,0xFF,0x3F,0xFF,0xDB,0xFF,0xFF, 0x6F,0xFB,0xF7,0xFF,0xFF,0xFF,0xFB,0xFE, -0xF7,0xAF,0xFF,0xB7,0xED,0xEF,0xF7,0xFE, 0xFF,0xFF,0xDF,0xFF,0xFE,0xFF,0xEF,0xFF, -0xFF,0xFF,0xFF,0xBF,0xF7,0xFC,0x1F,0xEE, 0xFB,0xFE,0xBD,0xFF,0x7F,0x5F,0xD7,0xFD, -0xFB,0x43,0xFF,0xFF,0xFD,0xFF,0x5F,0xFF, 0xF7,0xFF,0xF9,0x3F,0xFF,0xCF,0xF3,0xFD, -0xF7,0x7E,0xEF,0xA7,0xF9,0xFE,0x8F,0xA7, 0xE9,0xF3,0x7E,0x9F,0xFB,0xF8,0xFF,0xFF, -0x3F,0xFD,0x7F,0x5F,0xDF,0xFD,0xFF,0xFF, 0x5F,0xFF,0xFD,0x5F,0xFF,0xFF,0x7F,0xFD, -0x7F,0xFD,0x9F,0xFF,0xE0,0xFF,0xFA,0xF8, 0xBE,0x6F,0x9F,0xE6,0xF8,0xBE,0x3F,0x9A, -0xF9,0xBE,0x6F,0x9F,0xE2,0xF9,0xFE,0x6F, 0x9F,0xF9,0xFF,0xF5,0xFD,0x7F,0xCF,0xDF, -0xFD,0xFD,0x7F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xF7,0xF5,0xFD,0x0F,0xDB,0xFF,0xD3,0xFF, -0xEB,0xFA,0xFF,0xFF,0xBF,0xFF,0xFA,0xFF, 0xFF,0xCB,0xFB,0xFE,0xFF,0xFF,0xEB,0xFA, -0xFE,0xFF,0xFF,0xB7,0xFF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xDF,0xF5,0xFF,0xFF,0xD7,0xFF, -0xFF,0xFF,0xDF,0xD7,0xF5,0xFF,0x7F,0xFE, 0x4F,0xFF,0xFD,0xFF,0x7F,0x7F,0xFF,0xAD, -0xEB,0xFB,0xFF,0xAD,0xFF,0xFF,0xFF,0xFF, 0xAF,0xEB,0xFB,0xFF,0xFC,0x0D,0xFF,0xFF, -0xDF,0xD2,0xFD,0xFF,0xFF,0xFD,0xF6,0xFF, 0xFF,0x7F,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF, -0xFF,0xFB,0x3F,0x7D,0xEB,0x32,0xFE,0xBF, 0x2F,0xEB,0xFA,0xAE,0xBD,0xE0,0xFA,0x7E, -0xBF,0xAD,0xEB,0xFA,0xFE,0xBF,0xF5,0x7F, 0xFF,0xDE,0xFE,0xE3,0xFB,0xFF,0xFF,0xFF, -0xDF,0xEF,0x4F,0xDF,0xFF,0x7F,0xDF,0xFF, 0xF7,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xEF, -0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xDF, 0xED,0xFB,0xDF,0xFF,0xBF,0xFF,0xFF,0xFF, -0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFF,0xFE,0xDD,0xFE,0xEF,0xFD,0xFF, -0xFF,0xFB,0xFE,0xF7,0xFF,0x93,0xFD,0xFB, 0x7E,0xFF,0xFE,0x87,0xE9,0xFF,0x7F,0xB3, -0x9F,0xFE,0xFE,0xFF,0xAF,0xFD,0xFE,0x7E, 0x3F,0xFE,0x67,0xFF,0xFF,0xF7,0xFF,0xFF, -0xFC,0xF7,0xDF,0xFD,0xFF,0x7F,0xFF,0xFF, 0x7F,0x6D,0xFF,0xFF,0xFE,0xFF,0xFF,0x2F, -0xFF,0xBF,0xFF,0xFF,0xEE,0xFF,0xBE,0xFF, 0xFF,0xFE,0xFF,0xEF,0xFF,0xFF,0xFE,0xFF, -0xEF,0xFF,0xFF,0xFA,0x5F,0xFF,0xFF,0xFB, 0xFF,0xFF,0xEF,0xFF,0xFB,0xFE,0xFD,0xFF, -0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFE,0xBF,0xDF,0xFF,0xFB,0xFF,0xFF,0xF7, -0xFC,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,0x7F,0xFF, -0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xF3,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF, -0xFF,0xDF,0xE2,0xFF,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xE7,0xFF,0xFD, -0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xED, 0xEF,0xFD,0xFF,0xFF,0xDF,0xD7,0xF5,0xFD, -0x7F,0x5D,0xFD,0xFF,0x7F,0xDF,0x97,0xF4, 0xFD,0x7B,0x5F,0xFF,0xC9,0xFF,0xFB,0xFE, -0xFF,0xBF,0xFF,0x5F,0xFF,0xFF,0xF7,0xFF, 0xEF,0xFD,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xF7,0xFF,0xD7,0xFD,0x7D,0x7F,0xFF, 0xFF,0xFF,0xFF,0xEF,0xDF,0xF7,0xFD,0xFF, -0xBB,0xFF,0xFF,0x7F,0xFF,0xFE,0xE3,0xFF, 0xF9,0xFE,0x7F,0xBF,0xEF,0xFB,0xFE,0xFF, -0xBF,0xF9,0xFE,0xFF,0x9F,0xEF,0xF9,0xFE, 0xFF,0xBF,0xF3,0xDA,0xFF,0x37,0xCD,0xF3, -0x7C,0xDF,0x37,0xCD,0xF3,0x7F,0x37,0xCD, 0xF3,0x7C,0xDF,0x37,0xCC,0xF3,0x7F,0x5A, -0xBD,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFD, 0xBF,0x6F,0xDE,0xFD,0xBF,0x6F,0xDB,0xF6, -0xFD,0xBF,0x6F,0xFE,0xF1,0x6F,0xEB,0x7A, 0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7,0xAF, -0x7A,0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7, 0xFF,0x7E,0xFF,0xFE,0xCD,0xB3,0x6C,0xDB, -0x36,0xCD,0xB3,0x6C,0xDE,0xCD,0xB3,0x6C, 0xDB,0x36,0xCD,0xB3,0x6C,0xDF,0xC9,0xBF, -0xF7,0xBD,0xEF,0x7A,0x9E,0xA7,0xA9,0xEA, 0x7A,0xB7,0xBD,0xEA,0x7B,0xDE,0xA7,0xBD, -0xCA,0x72,0x8D,0x91,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xF7,0xEF,0xFB, -0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFE, 0x87,0xFF,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6, -0xFD,0xBF,0x6F,0xF6,0xFD,0xBF,0x6F,0xDB, 0xF6,0xFD,0xBF,0x6F,0xFE,0x4F,0xFF,0xBF, -0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,0xEF, 0xBE,0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB, -0xEF,0xFC,0x5F,0xFF,0xFF,0xFF,0x3F,0xCF, 0xF3,0xFC,0xFF,0x3F,0xCF,0xFC,0xFF,0x3F, -0xCF,0xF3,0xFC,0xFF,0x3F,0xCF,0xFD,0x9F, 0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF, -0xEB,0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFF,0xE1,0x6F,0xFD,0xFF,0x7F, -0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFD,0xFF, 0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF, -0x7A,0xBF,0xFB,0xFE,0xDF,0xB7,0xED,0xFB, 0x7E,0xDF,0xB7,0xFB,0x7E,0xDF,0xB7,0xED, -0xFB,0x7E,0xDF,0xB7,0xFF,0xC9,0xFF,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, -0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEE, 0xFB,0xFE,0xBB,0xFF,0xFE,0xFF,0xBF,0xEF, -0xFB,0xFE,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0x3F,0xCF,0xFF,0xE7, -0xFE,0xFF,0xF5,0xFD,0x77,0x5D,0xD7,0x35, 0xDD,0x77,0xD7,0xF5,0xCD,0x7B,0x5D,0xD7, -0xF5,0xDD,0x77,0xFE,0x27,0xFF,0xFF,0x8B, 0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9,0xAF, -0x8B,0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9, 0xFE,0x1F,0xFF,0x5F,0xD7,0xF5,0xFD,0x7F, -0x5F,0xD7,0xF5,0xFF,0x5F,0xD7,0xF5,0xFD, 0x7F,0x5F,0xD7,0xF5,0xFF,0xFA,0x3F,0xFE, -0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xEB, 0xEC,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF, -0xEB,0xFF,0xFE,0x7F,0xFD,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6, 0xFF,0xFA,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF, -0xF7,0xFC,0xFF,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFD,0xFF,0xF5,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0x02,0xFF,0xFE,0xBF,0xAB,0xEB,0xFA, 0xBE,0xBF,0x23,0xEB,0xDE,0x1F,0xAF,0xEA, -0xFA,0xFE,0xAF,0xAF,0xEB,0xFD,0x97,0xFF, 0xF3,0xFC,0x7B,0x1F,0xCF,0xF1,0xFC,0x7F, -0x1F,0xF1,0xFC,0x77,0x1F,0xCD,0xF1,0xFC, 0xFF,0x1F,0xFE,0x87,0xFF,0xAF,0xEF,0xFA, -0xFE,0xFF,0xAF,0xEF,0xFA,0xFD,0xBF,0x2B, 0xFB,0x7E,0xBF,0xBF,0xEB,0xFB,0xFB,0xFB, -0xDF,0xFF,0xFB,0xF7,0xFF,0xFF,0x7F,0xF7, 0xF7,0xFF,0xFD,0xDF,0xFE,0xFC,0xDF,0xFF, -0xDF,0xFF,0xFD,0xFF,0xDA,0xBF,0xFF,0xBB, 0xEF,0xFB,0xF9,0xFF,0xBE,0xEF,0xFB,0xFB, -0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xF7,0x7F,0xFD,0xD7,0xFF,0xFF,0x7F, -0xFF,0xFF,0xFF,0xFE,0xF7,0xFF,0xFE,0xFF, 0xF7,0xFF,0xFF,0x7F,0xFF,0xFF,0xEC,0xFF, -0xFF,0xFE,0xDF,0xBF,0xFF,0xFB,0xFE,0xFF, 0xBB,0x68,0xAE,0x1F,0xAE,0xFB,0xFB,0xFF, -0xFF,0xBF,0xFF,0xD5,0xFF,0x7F,0xFF,0xFF, 0xF7,0xFE,0xFE,0xFF,0xBF,0xEF,0x9F,0xFD, -0x7F,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,0xFF, 0xBB,0xF7,0xBF,0xFF,0xFF,0xFF,0xFF,0xDF, -0xFF,0xBF,0xFB,0xFF,0xFF,0xFF,0xDE,0x3F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xA7,0xFF,0xFF, -0xFF,0xFF,0xEF,0xFF,0x7F,0xFB,0xFD,0xFB, 0x7F,0xFF,0xFF,0xFF,0xFF,0xCF,0xF3,0x7C, -0xFF,0x7F,0x8D,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFB,0xFF,0xF7,0xFB,0xFE,0xFD,0xFF,0xFF, -0xFF,0xFF,0xF7,0xFD,0xFF,0x7F,0xFD,0x1F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xBF,0xDF,0xFF, -0xFF,0xFE,0x5C,0xFF,0x6D,0xFF,0x7F,0xAB, 0xE7,0xF1,0xFF,0xFD,0x9F,0xFF,0xFF,0xAD, -0xEB,0x7A,0x3F,0x1F,0xFF,0xFF,0xFE,0xBF, 0xAF,0xF3,0xDE,0xF5,0xFF,0x8F,0xFB,0xDF, -0xE6,0x7F,0xFF,0xDF,0xF3,0xFD,0xFF,0x7E, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xF7,0xF3, -0x7F,0xDF,0xF7,0xEF,0xFF,0xF6,0x3F,0x9F, 0xDF,0xFF,0xFF,0xEE,0xFF,0xFF,0xEF,0xFB, -0xFF,0xFF,0xF9,0xFB,0xFE,0x4F,0xBF,0xEF, 0xBB,0xFF,0x69,0xAF,0xAF,0xFC,0xFF,0x3F, -0xDD,0xFF,0xFC,0xBF,0x8F,0xFF,0xFD,0xF3, 0xBF,0xED,0x9E,0xFC,0xBF,0x6F,0xF5,0xD3, -0xDF,0xFF,0xDB,0xD6,0xF5,0xEF,0xFD,0xFE, 0xFF,0xB9,0xFF,0x1F,0xD2,0xA9,0xAF,0xFF, -0xDB,0xF7,0xBF,0xEF,0x46,0xFF,0xFF,0xAD, 0xEB,0x7A,0xDF,0xEF,0xF7,0xFF,0x7F,0xF7, -0x9F,0xED,0xFF,0x7F,0xFF,0xAD,0xEB,0x7F, 0xF5,0x6F,0xFF,0xFD,0xFB,0xD6,0xF4,0xF7, -0xFB,0xF9,0x7E,0x7F,0xFF,0x5F,0xC2,0xFE, 0xBF,0xFD,0xFB,0x33,0xDF,0xF9,0x5B,0xFF, -0xFF,0xDD,0x67,0x7D,0xCF,0xEF,0xDB,0xEC, 0xFF,0x77,0xDD,0xF7,0xFD,0xFF,0xFF,0xDE, -0xA7,0xBF,0xD4,0x9F,0xFF,0xFF,0xBF,0xEF, 0xFE,0xFF,0xDF,0xEF,0xBB,0xFF,0xFF,0xEF, -0xEB,0xFA,0xFF,0xEF,0xBD,0xFB,0xFF,0xE2, 0x7F,0xFF,0xDF,0xDF,0xF7,0xFD,0xBF,0xBB, -0x73,0xF7,0xFD,0x7F,0xDF,0xDE,0xF7,0xBF, 0xEA,0xDB,0xF6,0xFF,0xD6,0xFF,0xFF,0x66, -0xFF,0xBE,0xFF,0xBF,0x6B,0xD9,0xF6,0xDF, 0xFF,0xFB,0x7E,0x7F,0xB7,0x7E,0xFF,0xFE, -0xFF,0xCD,0xFF,0xFE,0x7F,0xFF,0xFC,0xFD, 0x3F,0xFB,0xFB,0xF7,0xFF,0xFF,0xFB,0xF6, -0x7D,0xFE,0x7F,0xFF,0xFC,0xFF,0xB9,0xFF, 0xF9,0xFA,0xFE,0xBF,0xAF,0x5B,0xD6,0xED, -0xAD,0x7B,0xF6,0xF9,0xBF,0xEF,0xF8,0xFA, 0xFE,0xBF,0xFE,0xE6,0xFF,0xFF,0xF7,0xFD, -0xFF,0x7F,0xBF,0xEF,0xF3,0xFF,0xFF,0x6F, 0xF7,0xFE,0xFF,0xFF,0xF7,0xFD,0xFE,0xF7, -0xEF,0xFF,0xFB,0xEF,0xFB,0x7E,0xDE,0xFE, 0xFF,0xBF,0xFF,0xFE,0xFF,0xFF,0xFB,0xFF, -0xFF,0xEF,0xFB,0x6F,0xFC,0x1F,0xFE,0xE7, 0xFF,0xFF,0xFF,0xEF,0xFF,0xD3,0xB4,0xBB, -0xFF,0xFF,0xFD,0xBF,0x6F,0xE3,0xFE,0xFF, 0xBF,0xFC,0xBF,0xF7,0xCF,0xF7,0xFD,0xFF, -0x2F,0xDF,0xAB,0xEA,0xFF,0xDF,0xE7,0xEA, 0x9A,0xAF,0xEF,0xFB,0xFE,0xFF,0xF5,0x3F, -0xFD,0x7E,0xFF,0xD7,0xF5,0xFB,0xFF,0xFD, 0xF7,0xFF,0x7F,0xFE,0xF7,0xFD,0xFF,0xD7, -0xFF,0xD7,0x7F,0xEE,0x7F,0xFA,0x79,0xFE, 0x2F,0x8B,0xE6,0xF9,0xFE,0x3F,0x9E,0xF9, -0xBE,0x2F,0x0B,0xE7,0xF9,0xFE,0x2F,0x9F, 0xFD,0xFF,0xFE,0x7D,0x7F,0x5F,0xD7,0xFF, -0xFF,0x7F,0xFF,0xFD,0xFF,0x7F,0x5F,0x97, 0xFF,0xFD,0x7F,0x5F,0xFF,0xE3,0xFF,0xFF, -0xFA,0xFE,0xBF,0xAF,0xFB,0xFB,0xFF,0xFF, 0xCF,0xEB,0xFE,0xBF,0xAF,0xFF,0xFA,0xFE, -0xBF,0xFF,0x87,0xFF,0xFF,0xF5,0xFF,0xFF, 0xFF,0xFF,0xFD,0xFF,0x7F,0xFF,0xFF,0xFF, -0xFB,0xFF,0xFF,0xF5,0xFF,0xFF,0xFE,0x0F, 0xFF,0xFD,0xEB,0xFF,0xFF,0xF7,0xFF,0xEF, -0x7B,0xDF,0xFE,0xFF,0xFF,0xDF,0xF7,0xFD, 0xEB,0x7F,0xDF,0xFF,0x5F,0xFF,0xFF,0xFF, -0xFF,0xFD,0xBF,0xFF,0x7E,0xFA,0xBF,0xC7, 0xDB,0xF7,0xBD,0x3F,0xFB,0xFF,0xF6,0xFF, -0xFA,0xAF,0xFF,0xEB,0xFA,0xFE,0x3F,0x2F, 0xEA,0xFA,0x3E,0xAD,0xC9,0xBA,0xF6,0xAD, -0xAF,0xEB,0xFA,0xF6,0xBF,0xFE,0x7F,0xFF, 0xFF,0xFD,0xFF,0xF1,0x7F,0x3F,0xCF,0xF1, -0xEF,0xFF,0x7F,0xFF,0xBC,0xDF,0xDF,0xF7, 0xDD,0xFF,0xE0,0x7F,0xFF,0xFF,0xFE,0xFF, -0xFA,0xEC,0xBB,0x7F,0x5F,0xFF,0xFB,0xEC, 0xFF,0xEF,0xB7,0xFF,0xF7,0xFF,0xFF,0xB5, -0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xEE,0xDF, 0x5F,0xDF,0xDE,0xFF,0xAE,0xE7,0x77,0xFF, -0xFF,0xDF,0xF7,0xFF,0xE3,0xFF,0xFA,0xBB, 0xFE,0xFF,0xAF,0xFD,0xFB,0xFE,0xBF,0xAB, -0xF9,0xFE,0xFF,0xBF,0x7F,0xBF,0xFE,0xBD, 0xFE,0xD7,0xFF,0x9F,0xFD,0xFF,0xBE,0xEF, -0xFF,0xEE,0xFD,0xBB,0x5B,0xEF,0xFF,0x7F, 0xEF,0xFF,0xEF,0xFF,0x7F,0xFF,0x4F,0xFF, -0xEF,0xFB,0xBC,0xFC,0xFF,0xFF,0xFF,0xFE, 0xFE,0xFD,0xFA,0xFE,0xFB,0xFF,0xFD,0xF3, -0xFB,0xFF,0xF8,0x5F,0xFF,0xFF,0xD7,0xF5, 0xFD,0xDF,0xEF,0xFF,0xF3,0xDC,0x5F,0xCE, -0xF5,0xBD,0xFF,0xFF,0xD7,0xFF,0xFF,0xF9, 0x3F,0xFF,0xDF,0xF7,0xFF,0xFE,0xFF,0xFD, -0xFF,0xFB,0xFF,0xF7,0xB9,0x7D,0xFE,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF9,0x7F,0xFF,0xFE, -0xFF,0xFF,0x7F,0xFF,0xFE,0xFF,0xFF,0xF7, 0xF6,0xFF,0xBF,0xF1,0xF8,0xFF,0xFF,0xFF, -0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEF,0xEF,0xFF,0xFF, -0x9B,0xFB,0x7F,0xFF,0xFF,0xFF,0xC1,0xFF, 0xDF,0xFF,0x3F,0x5F,0xD7,0xBF,0xEF,0xBB, -0xDE,0xEE,0xFF,0x7F,0xDF,0xFF,0xFE,0xF5, 0x7F,0xDF,0xFF,0x99,0xFF,0xFF,0xFA,0xFF, -0xBF,0xFD,0xEB,0x7A,0xFF,0xB7,0xFE,0xFE, 0xFF,0xFF,0xEF,0xFF,0xFF,0xFD,0xBF,0xFF, -0x97,0xFF,0xFD,0xF7,0xFF,0x7F,0xF7,0xFF, 0xFF,0xFD,0x5F,0xFE,0xF3,0xF9,0xDF,0xDF, -0xFF,0xFF,0xFC,0xFF,0xFF,0x83,0xFF,0xFF, 0xFE,0xFF,0x9E,0xEC,0xFB,0xEE,0xFF,0x9F, -0xBF,0xEF,0xFF,0xFE,0xED,0x7B,0xFF,0xFF, 0xFF,0xF1,0x5A,0xFF,0xFF,0xFD,0xFF,0x7C, -0x69,0x3B,0xDF,0xFF,0x7F,0x1F,0xDF,0xFF, 0xFD,0xBA,0xFF,0xFF,0xFB,0xFF,0x5B,0xBD, -0xFF,0xFF,0xFF,0xFF,0xD7,0xB6,0xED,0xE9, 0xFF,0xD6,0xBD,0x6F,0x5F,0xFB,0xFF,0xEF, -0xFF,0x5F,0xFE,0xF6,0x6F,0xFF,0xFF,0xFF, 0xFF,0xF7,0xEB,0x7A,0xDF,0xFF,0x9F,0x7F, -0x7F,0xFF,0xB7,0xFF,0xFF,0xFE,0xDF,0xFF, 0x6C,0xFF,0xFB,0xFF,0xBB,0x6F,0xEB,0xFE, -0xCC,0xF7,0xA5,0xFA,0x5C,0xF5,0x75,0xBB, 0xB7,0xDF,0xFE,0x6F,0x5F,0xC5,0xBF,0xFD, -0x7B,0xFE,0xFF,0x95,0xE7,0x29,0xCF,0x4F, 0xF5,0x91,0xEE,0x6B,0xDF,0xEF,0xFD,0x54, -0xF5,0xBD,0xB1,0xFF,0xEF,0xEE,0xFB,0xBE, 0xBF,0xAF,0xFE,0xDE,0xBD,0x6F,0xDA,0xF2, -0xFF,0xAF,0xBE,0xFF,0xFF,0xFD,0x7E,0xA7, 0xFF,0xF7,0xFF,0xBF,0xEF,0x7B,0xF6,0xFD, -0xBD,0x4A,0xF2,0x85,0x85,0xBF,0x5B,0xFE, 0xB5,0xFD,0xFA,0xFF,0x4F,0xFF,0xFE,0xDF, -0xFF,0xED,0xFF,0xBF,0xFF,0xBF,0x7F,0xFE, 0xFF,0xB7,0x6D,0xFF,0xF7,0xBF,0xBF,0xEF, -0xFD,0x1F,0xFF,0xFE,0x7D,0xFF,0x67,0xFF, 0xFF,0xFF,0x3F,0x7F,0xFE,0xBF,0xFF,0xE7, -0xDF,0xE7,0xFF,0xEF,0x6B,0xFC,0x1F,0xFF, 0xBF,0xEF,0xFB,0xFE,0xDE,0xBF,0xAF,0xFA, -0xFF,0xB6,0xEF,0xF9,0xFE,0xFF,0x8F,0xEF, 0xDB,0xEF,0xAB,0x6F,0xFB,0xFE,0xFF,0xFF, -0xEF,0xFD,0xFF,0x7F,0xFF,0xFF,0xDE,0xFF, 0xFF,0xEF,0xFF,0xFF,0xFF,0x3F,0xFF,0x6C, -0xFF,0xBF,0xFB,0xFF,0xFE,0xFF,0xFB,0xFE, 0xDF,0xFF,0xFF,0xEF,0xFF,0xFF,0xBF,0xFF, -0xFF,0xFE,0xFB,0xFF,0xD5,0x7F,0xFF,0xFF, 0xEF,0xFB,0xFF,0xFF,0xBF,0xEF,0x43,0xB5, -0xFD,0x6F,0xCF,0xD6,0xBE,0x3F,0x7F,0xDB, 0xFE,0xC3,0xFF,0xFD,0xFF,0xAF,0xEB,0xFB, -0xFC,0xFF,0x3E,0xEF,0xE8,0xFA,0xBD,0xCD, 0xAA,0xFE,0xFE,0x7D,0xCF,0xFF,0xB7,0xFF, -0xF7,0xFF,0xFF,0xFF,0xFD,0xFF,0x75,0xCD, 0x52,0xD7,0xFD,0xFB,0xF7,0xDD,0xFB,0xEF, -0xEB,0xFF,0xFF,0x4F,0xFF,0xBF,0x9F,0xE7, 0xF9,0xFC,0x7F,0x8B,0xC3,0xF9,0xAF,0x8F, -0xE7,0xE9,0xBE,0x7F,0x9F,0xE6,0xF9,0xFC, 0x5F,0xFF,0xFF,0xF7,0xFD,0xFF,0x7A,0x5F, -0xD7,0xED,0xFF,0xFF,0xD7,0xFF,0xDD,0x7F, 0xE7,0xFF,0xFC,0xFF,0xFC,0x3F,0xFF,0xFF, -0xFF,0xFB,0xFF,0xFE,0xBF,0xAF,0xFF,0xFD, 0xFF,0xEF,0xFF,0xEB,0xFF,0xFF,0xFF,0xFF, -0xFF,0xF7,0x7F,0xFF,0x7F,0xDF,0xFF,0xFD, 0xFD,0x7F,0xFE,0xF7,0xFD,0x7F,0xDF,0xFF, -0xFD,0xFF,0xFF,0xDF,0xFB,0xFF,0xEE,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7A,0xDF,0xF5, -0xFD,0xFA,0xDF,0xF7,0xFC,0xFF,0x7F,0xDF, 0xBF,0xED,0xFF,0xC9,0xFF,0xDF,0xFF,0xBF, -0x2F,0xFB,0xFF,0xBC,0xAD,0xFF,0xF7,0xFF, 0xFF,0xEF,0xD3,0xFF,0x7D,0xBF,0x6F,0xFF, -0xFA,0xFF,0xFE,0xBF,0xAE,0xEA,0xFA,0xBE, 0xAD,0xA5,0xEB,0xCE,0xBF,0xA7,0xEB,0x5A, -0xDE,0xBD,0xAF,0x6B,0xFD,0x57,0xFF,0xFF, 0xF4,0x7F,0x1F,0x7F,0xFD,0xFF,0x7F,0x36, -0xF0,0xDF,0x79,0xFF,0xFF,0xFF,0xF7,0xFD, 0xBF,0xFF,0x87,0xFF,0xFB,0xF3,0xFC,0xFF, -0xFF,0xFF,0xFF,0x7E,0xFF,0xBF,0xDF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xF8,0x9F, -0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFD, 0xF7,0xFC,0xBD,0xFF,0xFE,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFB,0xF9,0xBF,0xFF,0xFF,0xEB, 0xE2,0xFE,0xFF,0xBF,0xEF,0xA9,0xBA,0x2F, -0xEB,0xF9,0xFE,0x77,0xDF,0xF7,0xFF,0xFF, 0xF9,0x7F,0xFF,0xFF,0x7F,0xEF,0xD7,0xFF, -0xFD,0xFF,0xFB,0xF5,0xFF,0xBF,0x6F,0xDF, 0xFF,0xFF,0xFD,0xFF,0xFF,0xF0,0xFF,0xFF, -0xFF,0x3F,0xCF,0xFF,0xBA,0xEE,0x9B,0xBF, 0xEE,0xD7,0xFE,0xCD,0xEF,0xFF,0xDF,0xBF, -0xFF,0xFF,0xC5,0xFF,0xFF,0xFD,0x7F,0x4F, 0xFD,0xF6,0xD9,0xFF,0x4F,0xD6,0xFD,0xBF, -0x6E,0xFF,0xFF,0xF4,0x7F,0xFF,0x7F,0x8B, 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xF9,0xFE, -0x37,0xFF,0xD9,0xFB,0xF5,0xAF,0xFD,0xFF, 0xFF,0xFB,0xFF,0xFF,0x07,0xFF,0xFF,0xFF, -0xFB,0xF7,0xFF,0xFD,0xFF,0x7C,0xFA,0x7E, 0x4F,0xFC,0xDF,0x1D,0xC7,0xFF,0xFF,0xFF, -0xFF,0xAE,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB, 0xFF,0xFF,0xFE,0xFE,0xFC,0xFF,0x7F,0x7F, -0xBF,0xEF,0xFE,0xFF,0xFF,0xFF,0x5F,0xFD, 0xFF,0xFF,0xFF,0xFD,0x6F,0x5A,0xD7,0x7B, -0xBE,0x5F,0xFE,0x39,0xFF,0xF7,0xFF,0xF7, 0xFD,0xFE,0xAA,0x1F,0xFF,0xFF,0xFF,0xFF, -0xFE,0xFE,0xAB,0xAF,0xFD,0xFE,0xBF,0xFF, 0xF7,0xFF,0x7F,0xFE,0x8F,0xE3,0xFB,0xEE, -0x7F,0xFF,0xFF,0xFF,0xFF,0xEB,0xFB,0xFF, 0xFD,0xBF,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFB,0xE4,0x3F,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF3,0xEF,0xBB,0xFB, -0xBF,0xEF,0xBB,0xFF,0xD7,0xBF,0xFF,0xFF, 0xFF,0x29,0xAF,0xF7,0xFF,0xFF,0xFB,0xFF, -0xFB,0xE6,0xFF,0x0F,0xFB,0x3F,0xDF,0x0F, 0xFF,0xAF,0xFF,0xFF,0xFF,0xF5,0xC3,0xDF, -0x5F,0xFF,0xFF,0xFF,0xFE,0x6B,0xCA,0xBE, 0xBC,0xFF,0x9F,0xF2,0xBF,0xFF,0xFE,0xFA, -0xFF,0xFF,0xEF,0x16,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFC,0xDF,0x97,0xFD,0x79,0xFF,0x37, -0xE7,0x7F,0xFF,0xFF,0xB5,0xFF,0xFF,0xF6, 0x2F,0xFF,0xFD,0xFB,0xFE,0xFF,0xFF,0xFD, -0x5F,0x57,0x5F,0xFF,0xDB,0x52,0xDF,0xFF, 0xFD,0xBF,0xFF,0xFF,0xFC,0xDB,0xFF,0x7B, -0xB5,0xFD,0x7F,0xFF,0x71,0x9C,0x6E,0xFF, 0xF6,0x35,0xA5,0x9B,0xFF,0xFF,0xFD,0xFF, -0xFF,0xDB,0x9E,0x7F,0xFE,0xEF,0xFB,0xFF, 0xFF,0xBD,0xEF,0xFF,0xDE,0xB7,0xF9,0x4B, -0xFF,0xF5,0xEF,0xFF,0xFF,0xFF,0xE8,0x7E, 0xFF,0xEA,0xDF,0xF7,0xFF,0xFD,0x69,0x5B, -0xFC,0x9F,0xEF,0x78,0xD6,0xFF,0xEB,0xEF, 0xFF,0xFF,0xFF,0xE8,0xFF,0xFF,0xED,0xFF, -0xFF,0xFF,0xFF,0xE3,0xF9,0xF6,0xBF,0xFF, 0xFF,0xFE,0xDF,0xFF,0x7F,0xFF,0xFF,0xFF, -0xD1,0xFF,0xFF,0xE7,0xFF,0xFF,0xFF,0xFF, 0xE7,0xF9,0xFF,0xBF,0x7F,0xD9,0xFF,0xFD, -0xFE,0x7F,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB, 0xD6,0xDF,0xBF,0xEF,0x5B,0xD6,0xFF,0xBF, -0xFB,0xF6,0xFF,0xBF,0xEF,0xF8,0xF6,0xDD, 0xBE,0xFE,0x16,0xFF,0xBF,0xEF,0xFF,0xFE, -0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0x6F,0xFB, 0xFF,0xFF,0xFF,0x6F,0xF3,0xFF,0xF7,0xEF, -0xFB,0xFF,0xBF,0xFF,0xEF,0xFE,0xFF,0xBF, 0xFF,0xFF,0xFF,0xBE,0xBF,0xFF,0xEF,0xFF, -0x7F,0xEF,0xFF,0xFD,0x17,0xFB,0x7B,0xFF, 0xFF,0xFD,0x7F,0xDB,0xF6,0xF4,0x7F,0xFA, -0xFE,0xF5,0xBF,0xEB,0xE3,0xF7,0xFF,0xFF, 0xE9,0xBF,0xFF,0xAF,0xF7,0xFD,0xF3,0x7E, -0x8F,0xA3,0xEA,0xFF,0xCB,0xF3,0xEE,0xFF, 0xBF,0xEF,0xF7,0xF9,0xFF,0xFE,0x7F,0xFF, -0xFF,0xFF,0xFF,0xF5,0xFB,0xF6,0xFF,0xF5, 0x2F,0xFE,0xFB,0xD7,0xBF,0xFF,0xBE,0xDF, -0x9F,0xFF,0xF0,0xFF,0xFF,0xF9,0xFE,0x7F, 0x8F,0xA3,0xF8,0xFE,0x6F,0x9F,0xF9,0xF6, -0x2F,0x9F,0xE7,0xF9,0xFE,0x2F,0x9F,0xE1, 0xFF,0xFF,0xFF,0x7F,0xDF,0xF7,0xF5,0xFD, -0x7F,0x7F,0xF5,0xFF,0x9F,0x5F,0xFB,0xFE, 0xFF,0x7F,0xFF,0xFF,0xCB,0xFF,0xFF,0xFB, -0xFE,0xFF,0xBF,0xAF,0xFB,0xFE,0xFF,0xDF, 0xFE,0xFE,0xBF,0xF7,0xFF,0xFF,0xFF,0xFF, -0xFF,0xC7,0xFF,0xFF,0xFD,0xFF,0x7F,0xDD, 0xF7,0xFD,0xFF,0xFF,0xD7,0xFF,0xFD,0x7F, -0xFF,0xFB,0xFD,0xFF,0xFF,0xFE,0xEF,0x7F, 0xFD,0xEF,0xFB,0xFE,0xFB,0xFD,0xFF,0x7F, -0xDF,0xFD,0xFF,0x7A,0xDF,0xF7,0xFD,0xFF, 0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xD3,0xF7, -0xFF,0xFF,0x6F,0xDB,0xFF,0xFF,0xEF,0xCB, 0xF4,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, -0x29,0xFF,0xE8,0xDA,0x76,0x9F,0xAF,0x6A, 0xDA,0xFE,0x35,0xEB,0xDA,0xD6,0xBF,0xAB, -0xEB,0x7A,0xDE,0xBF,0xD7,0x7F,0xFF,0xFE, 0xFF,0xBF,0xEF,0xFD,0xDF,0x77,0xBF,0xFD, -0x37,0xEF,0xFF,0xEF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xF7,0x7E, -0xDF,0xFF,0xFF,0xFF,0xFA,0xB7,0x7F,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x89,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x9F,0xFB,0xFF,0xFF,0xFF,0xE7,0xFF, -0xFF,0xFF,0xFF,0xAA,0xFF,0xAB,0xFB,0xFA, 0xEF,0xBF,0xFF,0xDF,0xFA,0x7B,0xB9,0xFE, -0xFE,0xFF,0xFD,0xFF,0xF7,0xFE,0x3F,0xFF, 0xB7,0xFF,0xF7,0xEE,0xFF,0x7F,0xEF,0xFF, -0xFF,0x7F,0xFF,0x1F,0xFB,0xFF,0xBF,0xFB, 0xFE,0xFF,0xBD,0xFF,0xFF,0x2F,0xFF,0xBF, -0xFF,0x7F,0xDF,0xFA,0xFF,0xFF,0xFC,0xEE, 0xF5,0xF3,0xBE,0xFB,0x0F,0xEF,0xF3,0xBE, -0xEF,0xFC,0x5F,0xFF,0x5A,0xFF,0xF7,0xDF, 0xFF,0xFF,0xFE,0xD5,0xFC,0x5F,0xFB,0xF2, -0xFF,0xFF,0x2F,0xBB,0xF3,0xFF,0xFF,0xBF, 0xFF,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, -0xBF,0xFF,0xFF,0xFD,0x7B,0xFF,0xDF,0xB9, 0xFF,0xFB,0xFF,0xD8,0x7F,0xFF,0xFF,0xFF, -0xFB,0xFF,0xFC,0x7F,0x1F,0xBF,0xE0,0xDF, 0xF7,0xEF,0xFF,0xFD,0x7F,0xFE,0xDF,0xFF, -0xE0,0xFF,0xFF,0xFD,0xEF,0xFB,0xFF,0xFE, 0xF7,0xDF,0xFF,0xEB,0x5F,0xFF,0xF7,0xFF, -0xFF,0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0xFD, 0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,0x3B,0xDC, -0xFD,0x6D,0x7B,0x5F,0x57,0xF5,0xFD,0x7F, 0x5F,0xFF,0xB1,0xFF,0xEB,0xFF,0xFF,0xFF, -0xFB,0xFB,0xFE,0xFF,0xBF,0xFB,0xBE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xAF,0xFE,0xF7, -0xDF,0xDF,0xFF,0xFF,0xFF,0x7F,0xCF,0xF3, 0xF8,0xFF,0xD7,0xFB,0xFF,0x5F,0xBF,0xF7, -0xFB,0xFF,0x7F,0xFE,0x23,0xFF,0xFF,0xFE, 0x7F,0xF3,0xFF,0xFB,0xFE,0xFF,0xFF,0xF3, -0xFF,0xFF,0xF5,0xF9,0xFF,0x3F,0xFF,0xFF, 0xF0,0x9A,0xFF,0xBE,0x7F,0xFF,0xFC,0xF9, -0xFF,0xFD,0xAF,0xEB,0xFE,0xBF,0xFF,0xCF, 0xF3,0xFE,0x7F,0xFF,0xFF,0x5B,0xBD,0xFF, -0xBC,0xEB,0xFF,0xD7,0xD4,0xAF,0xAF,0xFD, 0xFF,0xCF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, -0xFD,0xFE,0xFF,0x6F,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFD,0x7F,0x5E,0xFD,0xBF,0xDB,0xF6, -0xFD,0xBF,0x6F,0xFB,0xEE,0xFD,0xFF,0x7A, 0xFF,0xFA,0xFB,0xFF,0x3F,0xFB,0xB7,0x5F, -0xD6,0xF7,0x1F,0x71,0xDC,0x77,0x1D,0xC7, 0x31,0xDC,0x77,0xDF,0xF9,0xBF,0xF5,0x5B, -0xF4,0xD7,0x9D,0xAE,0xFF,0xBF,0xFD,0xBF, 0xDB,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFE, -0x3D,0x81,0xFF,0xEB,0xFE,0xFE,0xFE,0xFF, 0xEB,0x7A,0xDF,0x7D,0x77,0x7D,0xF5,0x79, -0xDF,0x57,0xDD,0xF5,0x7D,0x7E,0xE6,0xFF, 0xD6,0x3F,0xBF,0x7F,0xFF,0xD4,0xF5,0x3F, -0xBF,0xFB,0xBE,0xEF,0xB3,0xEE,0xFB,0x9E, 0xEF,0xBB,0xFE,0x8B,0xFF,0xFE,0xDF,0xB7, -0xED,0xFF,0xF7,0xFD,0xFE,0xFF,0xEF,0xBB, 0xEE,0xFF,0xBE,0xEF,0xBB,0xEE,0xEB,0xFC, -0x1F,0xFF,0xFF,0xFD,0xFF,0xE7,0xFF,0xF7, 0xFD,0xFF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, -0xFE,0xFF,0xBF,0xEB,0xFA,0x1F,0xFF,0xB7, 0xEF,0x5B,0xFE,0xFF,0xAF,0xEB,0xDD,0xE7, -0xDE,0x77,0x9D,0xE7,0x79,0xDE,0x77,0x9D, 0xBF,0xE6,0x6F,0xFF,0xFE,0xFF,0xBF,0xEF, -0xFB,0xFE,0xFD,0xBF,0x6F,0xF6,0xFD,0xBF, 0x6F,0xDB,0xF6,0xFD,0xBF,0xFF,0x7E,0xFF, -0xFF,0xFB,0xFE,0xFE,0xFF,0xEF,0xFB,0xFD, 0xEF,0x7E,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7, -0xBD,0xEF,0xFF,0xD5,0xFF,0xBF,0xFF,0xEF, 0xFE,0xFF,0xFC,0x3F,0x0F,0xE7,0xFE,0x7F, -0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFE, 0xF3,0xFF,0xFE,0xDF,0xAD,0xDF,0x67,0xEE, -0xFB,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFF,0x23,0xFF,0xFF, -0xFF,0xFF,0x7F,0xFF,0xF3,0xBC,0xDB,0xFE, 0xFB,0xFF,0xFB,0xBE,0xF7,0xFB,0xFF,0x7F, -0xDF,0xFF,0xCF,0xFB,0xFF,0x9F,0xE3,0xF9, 0xBE,0x3F,0x8F,0xE7,0x79,0xFF,0x9D,0xE7, -0xF9,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x5F, 0xFF,0xCF,0xF7,0xFF,0xFF,0xFF,0xDF,0xF7, -0xFE,0x7F,0xE7,0xF9,0xFE,0x7F,0xFF,0xFF, 0xFB,0xFE,0xFF,0xFF,0xBF,0xFF,0xBF,0xBF, -0xFF,0xFE,0xFF,0xBF,0xEF,0xFF,0xFD,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFD,0xFF, -0xFF,0x3F,0xFF,0xBF,0xFF,0xF7,0xFF,0xFF, 0x7F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xE8,0xEF,0xFF, 0x5F,0xF7,0xBF,0xF9,0xFE,0xDF,0xB7,0xFD, -0xFF,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xDD,0xFF,0xF2,0xFF,0xBF,0xFF, -0xFF,0xBF,0xFF,0xFF,0x2F,0xF2,0xFF,0xBF, 0x2F,0x7B,0xD2,0xF7,0xBF,0x2F,0xFF,0xBB, -0xFF,0xEE,0x8F,0xAF,0xEB,0xFA,0xFE,0x3F, 0xA7,0x69,0xCE,0x8F,0xA4,0xEA,0xFA,0xEE, -0xB7,0xAE,0xEB,0xFD,0xC7,0xFF,0xF7,0xF7, 0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3E,0xF3, -0x74,0xFF,0x3F,0x4F,0xFF,0xE7,0xFF,0x3F, 0xFE,0xA7,0xFF,0xFF,0xDF,0xF7,0xB7,0xFF, -0xF7,0xFF,0xBA,0xEF,0x37,0xEB,0xFB,0xFE, 0xBF,0xFB,0xFE,0xF3,0xFF,0xF9,0xDF,0xFF, -0xBF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFD,0xDF,0xFF,0xFD,0xFF,0xFF,0xFB,0xFE, -0xFD,0xFF,0xFB,0xBF,0xFE,0x3F,0xED,0xFF, 0xDF,0xBE,0x3D,0xA7,0xFB,0xFA,0x3F,0xE6, -0xE1,0xFE,0xFE,0x3F,0xEF,0xE3,0xDF,0xF5, 0x7F,0xFE,0xFF,0x7E,0xFF,0xFF,0xFF,0xFF, -0xEF,0x6F,0xF6,0xFF,0x7D,0xEF,0xD7,0xDE, 0xFF,0x7D,0xEF,0xFF,0xF2,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0x7B,0xDE,0xFB,0xE6,0xEE, 0xEF,0x37,0x6E,0xF3,0x7E,0xEB,0x37,0xEF, -0xFF,0xC1,0xFF,0xFE,0xFF,0xF7,0xEF,0xFF, 0xFF,0xFF,0xBF,0x3F,0xD2,0xDF,0xBF,0x2F, -0x7B,0xE2,0xFF,0xFE,0x3B,0xBD,0xDB,0xFF, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFE, -0xFF,0xFB,0xFF,0xFF,0xBF,0xFF,0xFB,0xDF, 0xFF,0xBF,0xFF,0xB7,0xFF,0xFF,0xBF,0xEF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, 0x7F,0xFF,0x1F,0xEF,0xF1,0xFD,0xFF,0xF6, -0xAF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF, 0xFF,0xFF,0xFE,0x9F,0xFF,0xFF,0xFF,0x77, -0xEF,0xF7,0xFB,0xFF,0xFE,0x5F,0xFF,0xFF, 0xBF,0xCF,0xFB,0xF7,0xDD,0xF7,0xF5,0xFF, -0x5F,0xD5,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5, 0xFF,0xFB,0x0F,0xFF,0xFF,0xA9,0xEA,0x7A, -0xFF,0xAF,0x8F,0xFE,0xDF,0xAF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFB,0xDF,0xE5,0x5F, -0xFF,0xFF,0xFF,0xFF,0xFF,0xBD,0x57,0xFF, 0xFF,0x6F,0x77,0xBF,0xF7,0xFB,0xFF,0x7F, -0xBF,0xF7,0xFF,0xFC,0xBF,0xFF,0x9F,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF,0x1F, -0xCF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFF,0xFB, 0x65,0xAF,0xF3,0x7C,0xFF,0x3F,0xDF,0xFF, -0xFD,0xE9,0xFE,0x7F,0xE7,0xFF,0xFE,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFD,0xE3,0xDF,0xFB, -0xDB,0xF6,0xFD,0xEF,0x5B,0xFB,0xFF,0xDF, 0xFC,0xFF,0x3F,0xDF,0xF3,0xFD,0xFF,0x7F, -0xDF,0xEF,0x66,0xFF,0xDF,0xAD,0xEB,0x7A, 0xDE,0xF7,0xF7,0xE7,0xD9,0xFD,0x9F,0x67, -0xD9,0xF6,0x7D,0x9F,0xE7,0xDF,0xF5,0x47, 0xFD,0x65,0x5B,0xD6,0xF4,0xFE,0xFF,0xEF, -0xFF,0x6D,0xF6,0xDD,0xB7,0x6D,0xDB,0x76, 0xDC,0xB7,0x7D,0xFA,0x9B,0xF6,0x6D,0x9D, -0x67,0x59,0xDF,0xF7,0xDD,0xFF,0xEB,0xFE, 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xE3, -0xD1,0x9F,0xFF,0xBD,0xBF,0xEF,0xFE,0xF7, 0xBF,0xBF,0xF7,0xD7,0x7F,0xDD,0xF7,0x9D, -0xDF,0x7F,0xDF,0xF7,0xFF,0xE0,0x7F,0xFD, 0xC1,0xDF,0xF7,0xFD,0xC7,0x7F,0x7F,0xFB, -0xFF,0xBB,0xEC,0xFB,0x3E,0xFF,0xBF,0xEC, 0xFB,0xFF,0xD8,0x7F,0xBF,0x6C,0xFF,0xBE, -0xFF,0xBF,0xED,0xFF,0xEF,0xFE,0xFB,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEE,0xFF,0xC5, -0xFF,0xAF,0x6F,0xFF,0xFC,0xFD,0x3F,0xE7, 0xFF,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, -0xEF,0xFB,0xFE,0xBF,0x89,0xFE,0xFA,0xBA, 0xFE,0xBF,0xAF,0xFB,0xF6,0xF5,0xD9,0x7D, -0x97,0x65,0xD9,0x74,0x5D,0x97,0x65,0xD3, 0xFE,0xD6,0xFF,0xBF,0xF7,0xFD,0xFF,0x7F, -0xBF,0xCF,0xFB,0xFE,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFF,0xF6,0x8F,0xFB, -0xFF,0xEF,0xFB,0x7E,0xDB,0xFE,0xFF,0xBE, 0xEF,0xEE,0xFB,0xBE,0xEF,0xBB,0xEE,0xFB, -0xBE,0xFF,0xFF,0xDF,0xFF,0x43,0xFF,0xFF, 0xFB,0xEF,0x5F,0xB7,0xFE,0x7F,0xE7,0xF9, -0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xF9, 0xBF,0xFE,0xAF,0x77,0xFD,0xFF,0x2F,0xAF, -0xA7,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xF1,0x7F,0xEF,0xDF, -0xFF,0x97,0xF5,0xEF,0xFF,0xDF,0xFF,0xFF, 0xBF,0xFF,0xBF,0xFF,0xFF,0xFE,0xFF,0xFF, -0xFF,0xE0,0xFF,0xFF,0xF9,0xFE,0x2F,0x8B, 0xE3,0xF8,0xBE,0x77,0x9F,0xF9,0xDA,0x77, -0x9D,0xE7,0x79,0xDE,0x77,0x9F,0xDD,0xFF, 0xFD,0xFD,0x7F,0x5F,0xD7,0xFD,0xFF,0x7F, -0xE7,0xFE,0x7F,0x97,0xE7,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFF,0xAB,0xFF,0xEF,0xFA,0xFE, -0xBF,0xAF,0xFF,0xFA,0xFF,0xFF,0xDF,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF, -0x67,0xFF,0xF7,0xF5,0xFF,0xFF,0xFF,0xDF, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xBD, 0xEB,0xFF,0xFF,0xF7,0xAD,0xEB,0xFF,0xDF, -0xFD,0xFF,0x3F,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0xFD, -0xBF,0xFF,0xCB,0xF4,0xFF,0x7F,0xD3,0xF7, 0xFD,0x3F,0x7F,0xD3,0xF7,0xFF,0xFC,0x3F, -0xFF,0xEA,0xFA,0xBE,0xAF,0xAB,0xEB,0xBA, 0xF4,0x95,0x6B,0x52,0xD4,0xAD,0x2F,0x4A, -0xD2,0xF6,0xBF,0xD2,0x7F,0xF7,0x3F,0xFF, 0xFF,0xF3,0x7F,0xFF,0xFF,0xF7,0xFF,0xBA, -0xDF,0xFB,0xFD,0xFF,0xBF,0xFF,0xFB,0xFF, 0xF8,0x7F,0xEA,0xFF,0xFE,0xFE,0xDF,0xFF, -0xF7,0xFF,0x7F,0xBB,0xFF,0xFF,0xBF,0xDF, 0xFB,0xFF,0xFF,0xBF,0xFF,0xB1,0x7F,0xFF, -0xFB,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, 0xCF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF7,0xFF, -0xFF,0xFF,0xF1,0xFF,0x69,0xBE,0xFA,0xBF, 0xAF,0xE2,0xFF,0xFE,0xFD,0xAF,0xF3,0xFE, -0xFF,0xBF,0xEF,0xFB,0xFC,0xFF,0xFF,0x07, 0xFD,0x95,0xDB,0xDF,0x7F,0xDF,0xAF,0xFF, -0xF7,0xAF,0x36,0xFE,0xBF,0x65,0xEB,0xF6, 0xFE,0x9F,0x6F,0xFE,0x07,0xFF,0xCF,0xFF, -0xF8,0xFE,0xFF,0xCF,0xFF,0xF6,0xFA,0xE7, 0xFB,0xFE,0xFF,0xBB,0xED,0xF9,0xFF,0xFF, -0xFF,0x5F,0xFF,0xFF,0xFF,0x75,0xFF,0xEF, 0x7E,0xFD,0xE0,0xE8,0x5E,0xD3,0xE5,0xF9, -0x3E,0x5F,0xD7,0xF7,0xFF,0xFA,0x2F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0x7F, -0x7F,0xD7,0xF5,0x7D,0x5F,0x57,0xD5,0xF5, 0xEF,0xFF,0xF3,0x7F,0xFC,0x7F,0xFF,0xC7, -0xF1,0xFF,0xFF,0x1F,0xCF,0xB0,0xFF,0x3F, 0xCF,0xF3,0xFC,0xFF,0x3F,0xCE,0xFF,0xE4, -0xFF,0xDF,0x7F,0xFE,0xF7,0xBB,0xFF,0xFF, 0xDF,0xEF,0xEE,0xFF,0xBF,0xEF,0xFB,0xFE, -0xBF,0xBF,0xEF,0xFF,0xD1,0xFF,0xFF,0xFF, 0xFD,0xFB,0xFF,0xFD,0xFF,0xFB,0x9F,0xE9, -0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xBF, 0xFF,0xB3,0xFF,0xFF,0xF7,0xFF,0xFF,0xAF, -0xF7,0xFF,0xB6,0x3F,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFA,0xFE,0xBF,0xFE,0xA7,0xFF, -0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF, 0xFE,0x9F,0xF7,0xF9,0xFF,0x7F,0x9F,0xE7, -0xFF,0xFF,0xFE,0xAF,0x6F,0xFF,0xFF,0xFF, 0x9F,0xFF,0xDF,0xFF,0x7D,0x5F,0xDD,0xFF, -0xFB,0xBF,0xE7,0xBB,0xFF,0xFB,0xDF,0x6D, 0x5F,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xEB,0xF7,0xFF,0xE7,0xEF,0xF7,0xFF,0xFF, 0x7F,0xFF,0xF7,0xFF,0xFC,0x8F,0xFF,0xEF, -0xFD,0xFE,0xFF,0xBE,0xF4,0xF2,0x7D,0xD7, 0xCF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xCF,0x6B,0xFF,0xBF,0x3F,0xFB,0xF2, 0xFC,0x7F,0xEB,0xFF,0x9F,0xFA,0xFF,0xFF, -0x3F,0xFF,0xF3,0xFF,0xFF,0xFD,0x70,0xF7, 0xFF,0xFF,0xBF,0xFF,0xFB,0xD7,0xFE,0xF5, -0x77,0xFF,0x15,0xDD,0x77,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFB,0xCD,0xBF,0xFF,0xFD,0xFF, -0xFF,0xDF,0x37,0xCD,0xF9,0xEC,0xFE,0xEF, 0xBB,0xF4,0xFB,0x3F,0x4F,0xB3,0xFF,0xFD, -0xCB,0xFF,0xE9,0x7E,0x54,0x9F,0xE5,0x4B, 0xB7,0xFF,0xDD,0x7D,0xC7,0x71,0xDD,0x77, -0x5D,0xD7,0x75,0xCD,0x7F,0xD6,0xFF,0xD3, 0xF6,0xF9,0x3F,0x6D,0x95,0xAF,0x7F,0xFE, -0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xF6,0xC7,0xFF,0xAD,0x7B,0xCA,0xFF, -0xBF,0xBF,0xEF,0xFD,0xE3,0xDF,0xB7,0xED, 0xFB,0x7E,0xDF,0x37,0xED,0xE3,0xFB,0xDF, -0xFF,0x52,0x5C,0x15,0xFD,0xCF,0x7F,0xDF, 0xFE,0xEF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEC, -0x7B,0xFE,0xFF,0xFE,0x3E,0x7F,0xDA,0xF7, 0xFD,0xFF,0x7F,0xFF,0xFF,0xFB,0xEF,0xBB, -0x6F,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, 0xF7,0x7D,0xFF,0xD8,0xFF,0xFD,0xBF,0x7F, -0xFB,0xFF,0xFF,0x9F,0xFB,0xFE,0x7F,0x9F, 0xE7,0xF9,0xFE,0x7F,0x9F,0xEA,0x7F,0xF6, -0xBF,0xBD,0x6A,0x5A,0xF6,0xE5,0xBF,0x77, 0x5F,0x6D,0xDD,0x77,0x5D,0xD7,0x75,0xDD, -0x77,0xFF,0xA5,0xBF,0xCF,0xFB,0xFF,0xFF, 0xBF,0xCF,0xFB,0xFD,0xFF,0xBF,0xF3,0xFE, -0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD,0xAB, 0xFF,0xBF,0xBF,0xFF,0xFB,0xFF,0x7F,0xEF, -0xFF,0xBE,0xFB,0xEE,0xFB,0xBE,0xEF,0xBB, 0xEE,0xFB,0xBF,0xFF,0xB5,0xFF,0xD0,0xBC, -0xFD,0x2F,0x4B,0xF7,0xFF,0xFF,0x9F,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x9F, -0xFA,0x8F,0xFD,0xAB,0xFA,0xDA,0xBF,0xAF, 0xB3,0xFD,0xFF,0xBF,0xFB,0xFE,0xFF,0xBF, -0xEF,0xFB,0xFE,0xF7,0xBF,0xFF,0x9F,0xFF, 0x77,0xF7,0xBD,0xFD,0x77,0xDF,0xFF,0x7E, -0xDF,0xED,0xBB,0xFE,0xFF,0xBE,0xEF,0xFB, 0xFE,0xFF,0xFA,0x3F,0xFF,0xBE,0x6F,0x8F, -0xE6,0xF9,0xFE,0x7F,0x9F,0xC7,0xFE,0x7F, 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFB, -0x7F,0xFF,0x7F,0xCF,0xFF,0xFD,0xFF,0xFF, 0xDF,0xFB,0xAF,0xBF,0xEF,0xFF,0xFE,0xFF, -0x9F,0xEF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFE, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xF7, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF5,0xFF,0xFF,0xFF,0x3F,0xDF,0xF7, -0xFF,0xFF,0x7F,0xEF,0xFE,0xFF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xEF,0xFF,0xB3,0x7F, -0xFF,0x7B,0x5E,0xF7,0xFD,0xFF,0x7B,0x7F, 0xF7,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, -0xDF,0xF7,0xFF,0x17,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xDD,0xF6,0xFC,0xBF,0xCB,0xF2, -0xBC,0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xFE, 0x8F,0xFF,0xFA,0x7E,0xBF,0xA7,0xEB,0xDA, -0xFC,0xBF,0xAF,0x7A,0xFE,0xBF,0xAF,0xEA, 0xFA,0xFE,0xBF,0xAF,0xF4,0xDF,0xFE,0xFF, -0xF3,0x3C,0x7F,0x3E,0xFF,0xCF,0xF8,0xBF, 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xE7,0xE8, -0xFF,0xFC,0x9F,0xFF,0xFF,0xCF,0xEB,0xB3, 0xE7,0xFB,0x7B,0xF3,0xFE,0xFF,0xCF,0xDB, -0xFB,0xFB,0xBF,0x6F,0x6F,0xDF,0xEC,0x7F, 0xFF,0xFF,0xF7,0xFD,0xFD,0xFF,0xFF,0xFF, -0xFF,0xB2,0xBF,0xFF,0xDE,0xFD,0xBD,0xEF, 0xFB,0xF6,0xDF,0xEA,0xE7,0xDB,0xFE,0xBB, -0xFF,0xEB,0xFB,0xBF,0x9F,0x8F,0xE8,0xFE, 0x3F,0x8F,0xA3,0xF8,0xFE,0x3F,0x8F,0xFF, -0xF8,0x7E,0xFD,0xFD,0x7F,0xFF,0xFB,0xCD, 0xFF,0xFD,0xFF,0x5F,0xEF,0xFD,0xFF,0xFF, -0xDF,0xF7,0xFD,0xFF,0xBE,0x90,0xFF,0xFF, 0xEE,0xFF,0x3F,0xBF,0xF3,0xBB,0xFE,0xB7, -0xAB,0xFA,0xFE,0xAF,0xAD,0xEA,0xFA,0xDE, 0xAB,0xFF,0x63,0xFF,0xFE,0xF2,0xFF,0xB3, -0xFF,0xDF,0xEE,0x7D,0xFF,0x03,0xF1,0xF4, 0x3F,0x1F,0xC3,0xF1,0xEC,0x7F,0xFE,0x6F, -0xFF,0xFB,0xFB,0xFF,0x9F,0xFF,0xBF,0xFF, 0x7B,0x5F,0xFD,0xFF,0xDF,0xF7,0xFD,0xFD, -0x7F,0x7F,0xDF,0xFE,0xCF,0xFB,0xFF,0xFF, 0xAF,0xFB,0xFF,0x1F,0xEF,0xA5,0xFD,0xBF, -0xDF,0xFB,0x7D,0xFF,0xBF,0xDF,0xFB,0xFF, 0xFD,0x3B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, -0xAF,0xF3,0xFF,0xFB,0x7F,0xBF,0xD7,0xFB, 0xBF,0x7F,0xBB,0xF7,0xFF,0xF8,0x7F,0xFF, -0xFA,0x5F,0xD7,0xFF,0xDF,0x7F,0xEF,0xFF, 0xFF,0x7F,0xDB,0xF7,0xFD,0xFF,0x7F,0xDF, -0xB7,0xFB,0xEC,0xFF,0xFF,0xF7,0xBF,0xEF, 0xFD,0xFC,0xFB,0xFF,0xEF,0xF0,0xFE,0x3F, -0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xEF,0x8D, 0xFF,0xFF,0xEF,0x7F,0xBF,0xFF,0xFB,0xFF, -0xDB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0xD8,0xFF,0x2E,0x7F, -0xBE,0xEF,0xFE,0x6E,0xFF,0xBF,0xF9,0xFF, 0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFC,0x66,0xBE,0x47,0xF3,0x7F,0xDF,0xFE, 0x87,0x9F,0xFF,0xFF,0xFF,0xFF,0xE7,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xD6,0x6F,0x7C, 0xFB,0x4F,0xD2,0xFF,0xFD,0x2B,0xFE,0xFF, -0xFF,0xFD,0x5F,0xD7,0xD5,0xF5,0x7D,0xFF, 0xFF,0xFF,0xBF,0x9B,0xFF,0xFF,0xDF,0xB7, -0xFF,0xFF,0xDF,0xFF,0x3F,0xCF,0xFE,0x7F, 0xBF,0xEF,0xFB,0xFC,0xFF,0x3F,0xFF,0xD9, -0xBF,0xFE,0x97,0xEC,0x8F,0xB7,0xFE,0x9B, 0x7D,0xFD,0xB7,0xDD,0x77,0x1D,0xC7,0x71, -0xDD,0x77,0x5D,0xD7,0xF3,0x6F,0xFD,0x3F, 0x73,0xDD,0xAF,0xFD,0x7A,0xFF,0xFF,0xAF, -0xFE,0xFD,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0x66,0x7F,0xFF,0xFF,0xBF,0xBF,0xFF, -0xFB,0xFF,0xF7,0xDF,0xFD,0xFB,0x7D,0xDF, 0xB7,0xCD,0xF3,0x7C,0x5F,0x3F,0x91,0x3F, -0xFF,0x3D,0xEF,0x7B,0xFF,0xFC,0xFF,0xCA, 0xEF,0xFE,0xFF,0xBD,0xEF,0xFB,0x1E,0xE7, -0xBB,0xEC,0x7F,0xB3,0xFF,0xFD,0x9F,0xFF, 0xFF,0xFE,0xFF,0xFF,0x7F,0xBF,0xFB,0xFE, -0xFF,0xBF,0xEF,0xFB,0xEE,0xFB,0xBF,0xDF, 0x67,0xFF,0xFF,0xBF,0xEF,0xDB,0xFF,0xBC, -0xFE,0x7F,0xFB,0xFF,0x9F,0xEF,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x87,0xFF,0xEE, -0xFB,0xBE,0xE5,0xBF,0xEF,0xF9,0xD7,0x65, 0xF7,0xDD,0xE7,0x7D,0xDF,0x77,0x5D,0xD7, -0x7F,0xF8,0x9B,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xBF,0xEF,0xFB,0xFF,0x7F,0xCF, -0xF3,0xFC,0xFF,0xBF,0xEF,0xFF,0xDB,0x3F, 0xEF,0xFB,0xFE,0xFF,0xDF,0xFF,0xFE,0xFB, -0xBB,0xEF,0xBF,0xEF,0xBB,0xEE,0xFB,0xBE, 0xEF,0xBB,0xFF,0xFC,0x7F,0xFD,0x3B,0x5B, -0xD6,0xE5,0xFD,0x4F,0xC3,0xFB,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, -0xB4,0xFF,0xFA,0xBC,0x8F,0xB2,0xE9,0xD2, 0x2E,0xCF,0xFB,0xFF,0xBF,0xEF,0xFB,0xFE, -0xFF,0xBF,0xEF,0xFB,0xFF,0xEC,0xFF,0xFD, 0xFD,0x7F,0xDF,0xF7,0xE4,0xDF,0x5F,0xFF, -0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xC3,0xFF,0xEF,0xE6,0xF8,0xFE, -0x3F,0x8B,0x83,0xF9,0xFE,0x7F,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x17, -0xFD,0xFF,0xFF,0xFF,0x7F,0x5F,0xF7,0x2C, 0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xE7,0xF9, -0xFE,0x7F,0x9F,0xFE,0x2F,0xFF,0xFF,0xEF, 0xFF,0xFE,0xBF,0xEF,0xAD,0xFF,0xFF,0x7F, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFE,0xDF,0xFF,0xDF,0xFF,0xFD,0xFD,0x7F, -0xDF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0x3F,0xFE, -0xF7,0xFD,0xEF,0x7A,0xFF,0xB1,0xBD,0xFF, 0x7F,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD, -0xFF,0x7F,0xF3,0x27,0xFF,0xDF,0xFF,0xDD, 0xFF,0xFC,0x9B,0xFF,0xCB,0xFC,0xBF,0x2F, -0xCB,0xF2,0xFC,0xBF,0x2F,0xC9,0xFF,0xDE, 0xFF,0xDF,0xAF,0xEB,0xDA,0xFE,0xBB,0xAF, -0xEB,0xF8,0xF7,0xAF,0xE8,0xFA,0xFE,0xBF, 0xAF,0xEB,0xF2,0xFF,0xFD,0xFF,0xFF,0xEF, -0xBD,0xD7,0xBF,0xFF,0xFF,0xDE,0x8F,0xB8, 0xDE,0x37,0x8D,0xA3,0x78,0xDA,0x3F,0x8F, -0xFF,0xA1,0xFF,0xFF,0xFB,0xFB,0xFF,0xFF, 0xFF,0xFF,0xA7,0xBD,0xFB,0x76,0xFD,0xBF, -0xEF,0xDB,0xFE,0xBB,0xBF,0xFE,0x27,0x7F, 0xFF,0xFE,0xFE,0xFD,0xF5,0xFF,0xEF,0xF5, -0xDF,0x1F,0xE7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xFF,0xCD,0xFD,0xAE,0xFF,0xFA, -0x3E,0x3F,0xAB,0xFD,0xF8,0x7E,0x8F,0xE3, 0xF8,0xFE,0x3E,0x8F,0xE3,0xF8,0xFF,0xFE, -0x1F,0xEF,0xDF,0xBF,0xFE,0xDE,0xDF,0xD9, 0xFF,0xDF,0xBC,0xFF,0xFF,0x7F,0xFF,0xEF, -0xFD,0x7F,0xDF,0xF7,0xF9,0x3F,0xFE,0xFF, 0xFF,0x6F,0xFE,0xDE,0xBF,0xF7,0xED,0xEA, -0xFD,0x8F,0x83,0xF8,0xEA,0x3F,0x8F,0xEF, 0xFF,0xF4,0x7F,0xFF,0xEF,0xEF,0x7B,0xF3, -0xF1,0x5F,0xFF,0xFF,0xF1,0x3B,0x7F,0xDF, 0xF7,0xFD,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF, -0xFF,0xFF,0xF7,0xFF,0x6F,0xFF,0x7F,0xFF, 0xFF,0xF7,0xDE,0xF7,0xBF,0xEF,0xFB,0xF7, -0xFD,0xFF,0xFF,0xF5,0xFA,0xFF,0xFF,0xFB, 0xE7,0xFF,0xF3,0xF8,0x7F,0xF3,0xDF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xEF, 0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, -0xFF,0x7F,0xFF,0x9F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xCF,0xFF,0x37,0xFF,0xFF, -0x7F,0xDF,0x77,0x5D,0xE7,0xFC,0xFF,0xBF, 0xF7,0xF5,0xFB,0xFF,0xFF,0xD7,0xF5,0xFB, -0xFF,0xFF,0x45,0xFD,0x7F,0xEA,0xFD,0xBE, 0xBF,0xDF,0xF7,0xFF,0xFF,0xDB,0xFB,0xFE, -0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0xFB,0x5F, 0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFE,0xFF,0xEF,0xFD,0xFF,0x7F,0xDF, 0xFF,0xEF,0xFB,0xF8,0x0F,0xF3,0xFF,0xF9, -0x2E,0xFB,0xFE,0xFC,0xF3,0xEF,0xFF,0xFF, 0xBF,0xFF,0xFB,0xE7,0xFF,0xFE,0x7E,0xFF, -0xC0,0x6B,0xCF,0xFF,0x34,0xDF,0xF1,0xFD, 0xFF,0xEF,0xFF,0xFF,0xFF,0xDF,0xF7,0xFD, -0xCF,0x7F,0x9C,0xFD,0xFD,0x6C,0xF7,0xFF, 0xF6,0xFD,0xEB,0x2B,0x9F,0xFF,0xFC,0xFE, -0x7E,0xFF,0xFF,0xFF,0xFF,0xD7,0xF3,0xF7, 0xFF,0xFB,0xE1,0xBF,0xFF,0xEB,0x7A,0xDE, -0xD7,0xFB,0xFF,0xF9,0xFE,0xFF,0xFF,0xF3, 0xDE,0x7F,0xFD,0xE7,0x7F,0xFF,0xFD,0xBB, -0xFF,0xFF,0x7E,0xCC,0xF6,0xAF,0x5F,0x7F, 0xFE,0xF4,0x7D,0xF7,0xFD,0xBB,0x6E,0xDB, -0xB7,0xFF,0xF7,0xDF,0x66,0xFF,0xFF,0xF7, 0x3D,0xCF,0xDE,0xBD,0xFF,0xFF,0xDE,0xDB, -0x8D,0xF7,0x7E,0xDF,0xB7,0xEF,0x7F,0xFF, 0xF6,0x87,0xFF,0xFF,0xEF,0xFE,0xDE,0xBF, -0xFF,0xFF,0xFF,0xBB,0xEF,0xFD,0xFF,0x7B, 0xDE,0xF7,0x3F,0xFF,0xBF,0xFB,0xDB,0xFF, -0xF2,0xB6,0xFD,0xBD,0x7F,0xE7,0xFF,0xFF, 0xFF,0x6F,0xF7,0xFF,0xFF,0xFF,0xFE,0x77, -0xFF,0xBF,0xF8,0xAF,0xFF,0xDF,0xBF,0xFF, 0xBF,0x7F,0xFB,0xFF,0xFF,0xFF,0xDB,0xFE, -0xFF,0xBF,0xFF,0xFA,0xFF,0xFD,0xFF,0xF6, 0x7F,0xFF,0x9F,0xFF,0xFF,0x3F,0xEF,0xF8, -0xEE,0x7E,0x9F,0xBA,0xFE,0xBF,0x8F,0xEF, 0xFE,0xFE,0xF9,0xFF,0xFA,0x7F,0xFE,0x7E, -0xBF,0xAF,0xFB,0x96,0xFD,0x9F,0xEF,0x5E, 0x65,0xBE,0xEF,0x5B,0xB6,0xFF,0xBE,0xE3, -0xFF,0xB5,0xBF,0xFF,0xFD,0xFF,0x7F,0xFF, 0xEF,0xDF,0xFE,0xFF,0xBF,0xFB,0xFE,0xFF, -0xBF,0xCF,0xFF,0xFF,0xFF,0xFD,0x9B,0xFF, 0xFE,0xFB,0xFE,0xDF,0xFF,0x7F,0xFF,0xF7, -0xFE,0xFF,0xDF,0xFB,0xFB,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xB7,0xFE,0xFA,0xFF,0xAB, -0xEF,0xFF,0xFD,0xB5,0x7B,0x7F,0xFB,0xF7, 0xFD,0xFF,0xFF,0xDD,0xFF,0xEF,0x8F,0xFF, -0x2F,0xFF,0xFB,0x7C,0xFF,0x3F,0xDF,0x73, 0xEB,0xFE,0x3F,0xFF,0xEF,0xFB,0xFE,0xFF, -0xEF,0xFD,0xFF,0xBF,0xFD,0x0F,0xFF,0xFF, 0xFF,0xF5,0xF9,0xFF,0x7F,0xD7,0xFD,0xFF, -0xDF,0xFF,0xF7,0xFB,0xFF,0x7F,0xBF,0xFF, 0xFF,0xF0,0x9F,0xFF,0xFE,0x7F,0x8B,0xE3, -0xF9,0xDE,0x27,0x9B,0xE6,0xBE,0x7F,0x9B, 0xC3,0xF8,0xDE,0x7F,0x9D,0xE7,0xFE,0x7F, -0xFF,0xFF,0x5F,0xD7,0xFF,0xFF,0xFF,0x4F, 0xFB,0xFF,0xFF,0x7F,0xFF,0xAF,0xFF,0x9F, -0x7F,0xFB,0xFF,0xE8,0xFF,0xFF,0xFE,0xBF, 0xAF,0xFF,0xFF,0xFE,0xBF,0xEF,0xF7,0xFF, -0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFC,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, -0xFD,0x3F,0xCF,0xFF,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFD,0x7F,0xFF,0xFF,0x93,0xFF,0xFF, -0x7A,0xDF,0xF7,0xFF,0xFF,0x7B,0x7F,0xB7, 0xEF,0xFF,0xFF,0xFD,0xBF,0xFD,0xFB,0xFF, -0xF7,0xFF,0xD7,0xFF,0xFF,0xFF,0xFC,0x9F, 0x6F,0xCB,0xFF,0xF4,0xBB,0xDF,0xD6,0xFD, -0xBF,0x2F,0xD3,0xF7,0xFF,0xDF,0xFF,0xCF, 0xFF,0xFA,0xBE,0xBD,0xAF,0x6A,0xDA,0xBE, -0xBB,0xAB,0x3A,0xBE,0x2D,0xAE,0xEB,0xDA, 0xF6,0x3F,0xAD,0xF5,0xDD,0xFF,0xCF,0xF1, -0xFF,0xF9,0x7F,0xFF,0x73,0xFE,0xFF,0xCF, 0xC3,0xF4,0xF7,0x2F,0xF3,0xFF,0xFC,0xFF, -0x7C,0x1F,0xFF,0x3F,0x4F,0xFF,0x7E,0xFF, 0xEF,0xBD,0xF6,0xFE,0xFF,0x2B,0xEF,0xDC, -0xFB,0xFD,0xFF,0xFB,0xFF,0xEA,0x7B,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xF7,0xDF,0xFF, -0xE3,0x7D,0xFF,0xB7,0xFF,0xBF,0xFF,0xFF, 0xDF,0xFF,0xF8,0xFF,0xBF,0xFF,0xBF,0xEB, -0xE7,0xFA,0xFE,0x3D,0xBF,0xE9,0xFC,0xBF, 0xFF,0xFA,0xFB,0xFE,0xFF,0xFF,0xFF,0xD9, -0xFF,0xFF,0xFF,0xF6,0x7F,0xFF,0xF6,0x7D, 0xFF,0xDF,0xCF,0xFD,0xBF,0xFB,0xEF,0x7E, -0xFF,0x7F,0xFF,0xFF,0xD3,0xFF,0xFD,0xFB, 0xFF,0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xBF, -0xFE,0xFF,0xF7,0xEF,0xFF,0xFF,0xFF,0xFB, 0xFF,0x87,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF, -0x7B,0xFE,0xFF,0xFE,0x3B,0xF7,0xF7,0xFF, 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, -0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFF,0xAD,0xFF,0xFE,0xF7,0xFF,0xFF, -0x5F,0xFF,0xFF,0xDF,0xFF,0xFD,0xFF,0xF5, 0xFF,0xDF,0xFF,0xBD,0xFF,0xE9,0xFF,0xC7, -0xF3,0xFF,0xFF,0xF7,0xFF,0xF3,0xFF,0xF8, 0x3B,0xFF,0xFF,0x7B,0xDF,0xBF,0xFB,0xEF, -0xFB,0xFF,0xFB,0xF7,0xF7,0xBB,0xFF,0xFF, 0xFF,0xFF,0xFB,0xFF,0xFE,0x7F,0xF3,0x7F, -0x5E,0xB7,0xBF,0xFD,0x7F,0xFF,0xF9,0x7F, 0xFB,0xFF,0xEB,0xFD,0x7F,0x7F,0xFF,0xEF, -0xFB,0xE0,0x3F,0xFE,0xBF,0xBF,0xDF,0xFF, 0x7E,0xFF,0xF7,0xFF,0xFF,0xFE,0xBF,0xFF, -0xDB,0x78,0xFF,0xFF,0xFF,0xEE,0xA1,0xBF, 0xF5,0xDE,0xFB,0xF7,0xFF,0xFB,0xFF,0xFF, -0xFF,0xFF,0xFB,0xFF,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xEF,0xF0,0xFF,0xFF,0xFF,0xF3, -0xF7,0xFF,0xEF,0xFF,0xE7,0xCF,0xFF,0xFB, 0xFF,0xEF,0xFF,0xFF,0x9F,0x9F,0xEF,0xFC, -0x16,0xBF,0xFE,0xF3,0xE4,0xFF,0xFF,0xC6, 0xFF,0xE7,0xFF,0xFF,0xFD,0xFF,0xBF,0xFF, -0xFF,0x3F,0xFF,0xBF,0xD6,0xAF,0x7F,0xFE, 0x6B,0x7E,0x7F,0xFF,0xAF,0xFF,0xFF,0xBF, -0xFF,0x5F,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF, 0xFF,0xBD,0xDB,0xFF,0xFE,0x5F,0xF2,0xFF, -0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xEF,0x7F,0xFF,0xFF,0xFF,0xFF,0xDE,0xBF, -0xFF,0xFF,0xEF,0xFB,0x77,0xFE,0xBD,0x7F, 0x5F,0xFF,0xFF,0xFF,0xDF,0x6F,0xED,0xFF, -0xFD,0xFF,0x7F,0xFD,0x6F,0xFF,0xFF,0x77, 0xDA,0xCF,0xFD,0x5F,0xFF,0xBF,0xFF,0xFF, -0xDF,0x7F,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, 0x66,0x7F,0xFF,0xFE,0xBF,0xE7,0xBF,0xFA, -0xFF,0xFE,0xFF,0xFF,0xFF,0xDF,0xFF,0x59, 0xEF,0xFF,0xEF,0xFB,0x7F,0x89,0xFF,0xFF, -0xE9,0xFF,0x6F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xFF,0xFF,0x7F,0xF2,0xF7,0xFF,0xFF,0xEF, -0xF8,0x7F,0xFB,0xFF,0xFD,0xFF,0xFF,0xD9, 0xFF,0xEF,0xBB,0xFF,0xFF,0xFF,0xBF,0xEF, -0xDE,0xFF,0xFF,0x9F,0x7F,0xDF,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xAF, -0xFF,0xFF,0xF7,0x3F,0xEB,0x9F,0xFE,0x7F, 0x9E,0x7F,0x9F,0xFE,0x87,0xFF,0xED,0xDB, -0x56,0xFF,0xBF,0xAF,0x0B,0xD2,0xFF,0xEF, 0xDB,0x6E,0x7D,0xBD,0x6F,0xF8,0xFE,0x3F, -0xFA,0x5B,0xFF,0xFD,0xBF,0xEF,0xFF,0xBF, 0x6F,0xDB,0xE6,0xFF,0xFF,0x3F,0xFF,0xDF, -0xFE,0xFF,0xFF,0xFF,0xFF,0xDA,0x3F,0xFF, 0xFB,0xFE,0xFE,0xFF,0xFF,0xDF,0xF7,0xBD, -0xFF,0xFD,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xF1,0x5F,0xFD,0x9F,0xDF,0xFD, -0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,0xFF,0x76, 0xFA,0xFF,0xFF,0x7F,0xE3,0xF8,0xFF,0xAE, -0xFF,0xFB,0x7E,0x9D,0x73,0xFF,0xFA,0x7F, 0xDF,0xFF,0xFF,0x7F,0xFF,0xFB,0xCD,0xFF, -0x7F,0xEF,0xFB,0xFF,0xFD,0xFF,0xF7,0x7F, 0x7F,0xEF,0xFF,0xED,0xFF,0xFF,0xFF,0xB5, -0xFF,0xBF,0xFF,0xBF,0xFD,0xEF,0xDB,0xF7, 0xFF,0x93,0xFF,0xEF,0xE2,0xF9,0xBE,0x7F, -0x8B,0xE7,0xF9,0xFE,0x6B,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x47,0xFF, -0xFF,0xFD,0xFF,0x9F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xF5,0xFF,0x9F,0xFF,0xF7,0xFE, -0xFF,0xBF,0xFE,0x6F,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xAF,0xFF,0xFF,0xFF,0x7F,0xFB, -0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xDF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xDF, -0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,0xFF,0xFF, 0x5F,0xFB,0xFE,0xFF,0xF8,0x37,0xFF,0xFF, -0xEF,0xFF,0x7F,0xFE,0xBF,0xFF,0xFF,0xFE, 0xBF,0xFF,0xFF,0x7F,0xFF,0xBF,0xFD,0xFF, -0x7F,0xFA,0x7F,0xFF,0xFF,0x6F,0xFF,0xFF, 0x7D,0xFF,0xCF,0xFF,0xFF,0xFF,0x4F,0xFF, -0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xBF, 0xFF,0xAE,0xEB,0xFA,0xFE,0xBB,0xAD,0xEB, -0xFA,0xF7,0xAF,0x6B,0xFA,0xF6,0xBF,0x25, 0xE9,0xF2,0x7F,0x45,0xFF,0xFF,0xFD,0xF7, -0xF7,0xBF,0xFF,0xDF,0xFF,0xFF,0xBF,0xFB, 0xFF,0xDF,0xF3,0xFF,0xF7,0x3F,0xCF,0xFF, -0xA1,0xFF,0xFF,0xBF,0xE7,0xFF,0xFF,0x7F, 0xFF,0x3D,0xFF,0xFF,0xFF,0xF7,0xFF,0x2F, -0xFF,0xFB,0xF5,0x7F,0xFE,0x57,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7, -0x3F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFE, 0xF7,0xEE,0xAF,0xFE,0xEE,0xE7,0xFA,0xFF, -0xFE,0x9D,0xF9,0x5E,0xFE,0xFF,0xEB,0xFF, 0xFF,0xDF,0xA7,0xFF,0xFF,0xFF,0xFC,0xDB, -0xFF,0xFF,0xFF,0x7E,0xFB,0xFF,0xFF,0xEF, 0xFB,0xFD,0xFF,0xDB,0xFF,0xFF,0xFF,0xEF, -0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,0xBF,0xFF, 0x6F,0x7F,0xFF,0xF7,0xFF,0xFF,0xF9,0xFF, -0xF7,0xFF,0xBF,0xDE,0xF7,0xFF,0xFF,0xFF, 0xFA,0x7F,0xFD,0xBF,0x5F,0xFF,0xFF,0xBF, -0xFF,0xED,0xFF,0xF7,0xBF,0xFF,0xFF,0xEF, 0xFF,0xDF,0xFF,0xFF,0xFF,0xE6,0xFF,0xFB, -0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xFF, -0xFD,0xFF,0xF5,0xFF,0xF6,0x7F,0xDF,0xBD, 0xCF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF, -0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3, 0xFF,0xEE,0xBF,0xFF,0x7D,0xEF,0xFE,0xFF, -0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,0xB5,0xAE, -0xFF,0xFF,0xB6,0xFE,0xBF,0xFF,0xFF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0x27,0xFF,0xEF,0xFE,0x7F,0xDF,0xFF, 0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFD,0xFF,0xF7,0xF9,0x9F,0xFF, 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, -0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x0F,0xFF,0xE7,0xBF,0xFE, -0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFC,0xBF, 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xC4, -0x6B,0xFF,0x29,0x1F,0xFB,0xAF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0x1B,0xFE,0xFF,0xFC, -0x6F,0xFF,0xFF,0xFD,0x6A,0xF7,0xD7,0xF5, 0xBF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFE,0xBF,0xFF,0xFF,0xFA,0xFF,0xFF,0xF7, 0xFB,0xDD,0xBF,0xFF,0xE7,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x7F,0xFF, 0xFF,0xF5,0xFF,0xFF,0xF7,0xFD,0xB3,0xEF, -0xFD,0x7E,0x5D,0xFF,0xFD,0xFF,0xFF,0xFF, 0xFD,0x7F,0xD2,0xF5,0xFB,0x7E,0xCB,0xB7, -0xFF,0xFF,0xFF,0xC6,0xFF,0xFD,0xEE,0x63, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xFD,0x65, -0x5B,0xDF,0xFF,0xD5,0xFF,0xFF,0xFF,0xF6, 0xE7,0xBF,0xF7,0xA9,0xFF,0xFF,0xED,0xFF, -0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFF,0xFF, 0xAF,0xFF,0xFF,0xFF,0xF8,0x1B,0xFF,0xE3, -0xD0,0xBF,0xFF,0xE1,0xFF,0xFF,0xFF,0xFF, 0xFF,0xD7,0xFF,0xFF,0xFF,0x5F,0xFF,0xFF, -0xFF,0xFF,0xAF,0xFF,0xDB,0x76,0xBF,0xFF, 0x7F,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF, -0xFB,0xFE,0xFF,0xFF,0xFF,0xBF,0xF2,0x7F, 0xFF,0x9F,0xFE,0xBD,0xFE,0x7F,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF7,0x3F,0xEC,0x7F,0xF6,0x95,0xBB, -0xEF,0xF8,0xFE,0xFC,0xBF,0x2F,0xDA,0xFC, 0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xEF,0xFF, -0xA9,0xBF,0xCF,0xFB,0xFF,0xFF,0xFF,0xFE, 0xDD,0xB7,0x6D,0xF6,0xD9,0xB6,0x6D,0x9B, -0x76,0xD9,0xBF,0xFB,0xFD,0xA3,0xFF,0xBF, 0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0x7F,0xDF, -0xFD,0xEF,0x7B,0xDE,0xF7,0xFD,0xEF,0x7F, 0xFF,0xFF,0x05,0xFF,0xFA,0xFE,0x7F,0xEF, -0xE3,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, 0xFF,0x5F,0xFF,0xFF,0xFD,0x7F,0xFB,0xAF, -0xFF,0x63,0xC8,0xFF,0xBF,0xEF,0xFF,0xFF, 0xFA,0x7F,0xFF,0xFF,0xFF,0xFE,0x9F,0xF7, -0xFF,0xFA,0xBF,0xFE,0x9F,0xFB,0x7F,0xFF, 0xFF,0xEF,0xD7,0xFF,0xFF,0xF5,0xFF,0xFF, -0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xBF,0xFF, 0xF9,0xBF,0xFF,0xBE,0x27,0x9F,0xE7,0xF9, -0xFE,0x7F,0x8B,0xE7,0xFE,0x7F,0x9F,0xE2, 0xF9,0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF, -0xFF,0xFF,0xFB,0xFE,0xFF,0xFF,0xFF,0xD7, 0xFF,0xFF,0xFF,0xFF,0xF5,0xFF,0xFF,0xFF, -0xD7,0xFF,0xFA,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF,0xAF,0xF7,0xFF,0xFF, -0xFF,0xEB,0xFF,0xFF,0xFF,0xAF,0xFF,0xC4, 0xFF,0xF7,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, -0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xD7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFB,0x7A, -0xDF,0xF7,0xFD,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0x7F,0xFF,0xAF,0xFF,0xFF,0xFF,0xF7, -0xEF,0xE3,0xFF,0xDD,0xD2,0xFF,0xDF,0xFF, 0xFF,0xF2,0xFC,0xBF,0xCB,0xF6,0xFD,0xBF, -0x2F,0xCB,0xFF,0x7F,0xDF,0xDE,0xAF,0xFF, 0xDA,0xEE,0xBF,0xAF,0xE9,0xFA,0xF4,0xBD, -0xAF,0x5A,0xAE,0xBB,0xAB,0x6B,0xDA,0xDE, 0xBF,0xAD,0xD7,0x5E,0xFF,0xFF,0xBF,0xFC, -0xFF,0xDF,0xFD,0xFF,0xFF,0xFF,0xFF,0xDF, 0xF7,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA, -0x1F,0xFF,0xFE,0xFB,0xEF,0xBF,0xFD,0xFF, 0xFD,0xBD,0x77,0xFF,0xFF,0xFF,0xFF,0x9D, -0xEF,0xFF,0xFF,0xFF,0xEF,0x7D,0xFF,0xFB, 0xFE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE, 0xBF,0xE4,0xFB,0xFF,0xFE,0x3F,0xFE,0xFF, -0xFF,0xFF,0xFF,0xAF,0xEA,0xFE,0xBF,0xAF, 0xEB,0xFA,0xFE,0xFF,0xFF,0xFF,0x55,0xF6, -0xFF,0xFE,0xF7,0xFF,0x7F,0xFF,0xEB,0xF7, 0x5F,0xC5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF, -0x6F,0xFB,0xFF,0x8A,0xFF,0xFF,0xFF,0xFF, 0xEB,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xBF, -0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0x77,0xDF,0xFB,0xFF,0xFD,0x7F,0xEF,0xFF, -0xFF,0xFF,0xBF,0x7F,0xFF,0xDF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xFF,0xFE,0xEF,0xDF,0xFF, -0xFE,0xFF,0x9F,0xEF,0x7D,0xFF,0xF7,0xFF, 0x7F,0xFF,0xFF,0xDF,0xF7,0xFD,0xFF,0xEF, -0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB, -0xFD,0xFF,0xBF,0xDF,0xD1,0xFF,0xF8,0x3B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0x7E,0xDB,0xFD,0xFF,0x77,0xDB,0xB7,0x7D, 0xBF,0xFB,0xFF,0xF8,0x7F,0xED,0x7B,0x5E, -0xFF,0xFE,0xFF,0xFF,0x4F,0xD7,0xFD,0x7F, 0xDF,0xD7,0xF5,0xFF,0x7F,0xFF,0xFF,0xFF, -0xF2,0x3F,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFF,0xBF,0xEF,0xFE,0xFF,0x3B,0xEE,0xFF, -0xFC,0xEF,0xFF,0xFF,0xFF,0x85,0xFF,0xFD, 0xFE,0xFF,0xF5,0xFF,0xFF,0xFE,0xFF,0xDF, -0xFB,0xFF,0x5F,0xBF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xA8,0xFF,0xFF,0x9F,0x9E,0xFF, -0xFF,0xFF,0x7F,0xF3,0xFF,0xFF,0xCF,0xFF, 0xF7,0xFD,0xFF,0x7F,0xFF,0xFF,0xFC,0x16, -0xBF,0xCF,0xA3,0xE5,0xEF,0x7F,0xFF,0xF3, 0xE4,0xFF,0xCF,0x93,0xFC,0xFF,0x3F,0xCF, -0xFF,0xFF,0xFF,0xD6,0x0F,0x7D,0xBF,0x6E, 0xFB,0xF4,0xFC,0xAF,0x6D,0xDB,0x77,0xB7, -0x6D,0xDB,0xF6,0xFD,0xBF,0xFF,0xFF,0xFF, 0xBF,0x9B,0xFA,0xDE,0xB7,0xB7,0xED,0xF9, -0x7E,0xB7,0xAC,0xEB,0xD6,0xB3,0xAD,0xEB, 0x7A,0xDF,0xFF,0xFF,0xFF,0xD8,0xBF,0xFF, -0xB7,0xED,0x9F,0x6F,0xDD,0xF7,0x68,0xDB, 0x37,0xB3,0x6C,0xDB,0x36,0xCD,0xB3,0x7F, -0xFF,0x7F,0xF5,0x6F,0xFD,0xEF,0x79,0x3D, 0xF7,0x93,0xE4,0x7A,0x9E,0xAD,0xEA,0x7A, -0x9E,0xF7,0xBD,0xEF,0xFF,0xFF,0xFF,0x76, 0x7F,0xFB,0xC6,0xFF,0xBB,0xEF,0xDA,0xFE, -0xFD,0xBF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xFB,0xFF,0xA5,0xFF,0xFD,0xAB, -0x6F,0x78,0xDE,0x17,0x8F,0x79,0xDF,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xFF,0xFB, -0xFF,0xFB,0xFF,0xEF,0xFB,0xEF,0xFB,0xFE, 0xFF,0xBB,0xDA,0xF3,0xEF,0x3B,0xCE,0xF3, -0xBC,0xEF,0x3F,0xCF,0xDF,0xFF,0xB7,0xFF, 0xFF,0xFF,0xCF,0x73,0xFF,0xBF,0xEF,0xFF, -0xF3,0xFF,0x3F,0xCF,0xF3,0xFC,0xFF,0x3D, 0xCF,0x9F,0xFE,0x07,0xFF,0xAF,0xEB,0xFE, -0xFD,0xBF,0xEF,0xEB,0xFA,0xFF,0xAF,0xEB, 0xFA,0xFE,0xBF,0xAF,0xFB,0xFE,0x3F,0xFB, -0x9B,0xFF,0x7F,0xDF,0xFF,0xF3,0xFE,0xFF, 0xDE,0xF7,0xBF,0x7B,0xDE,0xF7,0xBD,0xEF, -0x7B,0xFE,0xFF,0xFF,0xDF,0x3F,0xFE,0xFF, 0xB7,0xFF,0xEF,0xF7,0xFF,0xBF,0xED,0xFE, -0xDF,0xB7,0xED,0xFB,0x7E,0xDF,0xFF,0xFF, 0xFF,0xFD,0x5F,0xEF,0xEB,0xFA,0xFE,0xF5, -0xBF,0x6F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xF8,0xFF,0xA8,0xFF, -0xFF,0xBF,0xEF,0xFB,0x6A,0xFB,0xB7,0xEF, 0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, -0xEF,0xFB,0xFF,0xE0,0xFF,0xFF,0xFD,0x7F, 0x5C,0xD7,0x7D,0xDF,0xF3,0x5C,0xF5,0xCD, -0x73,0x5E,0xD7,0xB5,0xFD,0x7F,0xEF,0xFF, 0xDB,0xFF,0xFF,0xE2,0xF8,0xBE,0x2F,0x8F, -0xE7,0xF8,0xBE,0x6B,0xE2,0xF8,0xBE,0x2F, 0x8B,0xE2,0xF9,0xFE,0x7F,0xE7,0xFF,0xD7, -0xF5,0xFD,0x7F,0xFF,0xF7,0xF5,0xFD,0x7F, 0xD7,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF, -0xFF,0xFF,0x8F,0xFF,0xAF,0xEB,0xFA,0xFF, 0xFF,0xBF,0xEB,0xFA,0xFF,0x2F,0xEB,0xFA, -0xFE,0xBF,0xAF,0xEB,0xFF,0xFF,0xFE,0x5F, 0xFF,0x5F,0xFF,0xFF,0xFD,0xFF,0xFF,0xD7, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFE,0xB7,0xFD, -0xFF,0x7E,0xDF,0xF7,0xAD,0xFF,0x7F,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F, -0xF6,0x7F,0xFF,0xFF,0xFF,0xDB,0xF6,0xFC, 0xAF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xEC,0xBF,0xFF, 0xAF,0xEB,0xFA,0xF6,0xAB,0x8F,0xEB,0xFA, -0xF7,0xA5,0xEB,0xFA,0xBE,0xBF,0xAF,0xEB, 0xFA,0xFF,0x6D,0xFF,0xFF,0x7F,0xDF,0x33, -0xDD,0xFF,0x7F,0xFE,0xF7,0xFC,0x7F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA9, -0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xDF, 0xFF,0xFF,0xEF,0xEF,0xFD,0xFF,0x7F,0xFF, -0xFF,0xFF,0xFF,0xFE,0xA7,0xFF,0xFF,0xFF, 0x77,0xDF,0xF7,0xFD,0x9F,0x7F,0xFE,0x77, -0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xAF,0xBF,0xAF,0xFF,0xF9,0xBE,0xBF, -0x8F,0xFB,0xFE,0xFE,0xEF,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFF,0xFF,0xFD,0xDF,0x6F, -0xEF,0xFF,0x7F,0xFF,0xBF,0xBF,0xDF,0xFF, 0xFC,0xFF,0xDF,0xF7,0xFD,0xEF,0x7F,0xDF, -0xFF,0xFF,0xFF,0x3F,0xF6,0xFF,0xCF,0xFF, 0xDB,0xFB,0xF7,0xFF,0xEB,0x7A,0xFF,0xFF, -0xFF,0xBF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFE, 0x6D,0xFD,0xFF,0x5F,0xFB,0xFF,0xFF,0xF7, -0xFF,0x5F,0xF5,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xFB,0xFF, -0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xE7,0xF6, 0xBF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF, -0xFF,0xC9,0xFF,0xFF,0xFF,0xBD,0xFF,0xBF, 0xAF,0xEF,0xEF,0x3F,0xD1,0xFC,0x7F,0xFB, -0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xFF, 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0x77,0xFF, -0xDF,0xB7,0xFD,0xF7,0xFD,0xF7,0xFF,0xFF, 0xFF,0xFF,0xFF,0x57,0xFF,0xF7,0xA5,0xFD, -0x3F,0xDF,0xBF,0xBF,0xFE,0x7F,0xFF,0xFF, 0xFF,0xDF,0xFA,0xFD,0xFF,0xFF,0xFF,0xFE, -0x87,0xFF,0xE9,0xFF,0xFE,0xEF,0xBF,0xEF, 0xFE,0xFE,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFA,0x9F,0xFF,0x3F, 0xFF,0xFD,0xFD,0x57,0xDF,0xFD,0xF3,0xFF, -0xDF,0xFD,0xFF,0x5F,0xDF,0xF5,0xFD,0xFF, 0xFF,0xF9,0x8F,0xFF,0xFF,0xFF,0xEE,0x7F, -0xFF,0xFF,0xBF,0x5E,0xFE,0xEC,0xFB,0x3F, 0x7F,0x9F,0xEF,0xF9,0xFF,0xFF,0xCD,0x6B, -0xFF,0xFF,0xFF,0xC5,0xF3,0xFC,0xFA,0x38, 0xFF,0xAF,0x3F,0xEE,0x7F,0x9F,0xFF,0xD9, -0xFF,0xFF,0xFD,0x7A,0xF7,0xFF,0xF3,0xFF, 0xAF,0x6F,0xDB,0xF2,0xB9,0xE9,0xFB,0xFF, -0xFF,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xFB, 0xC5,0xBF,0xFF,0xEF,0xFF,0x5E,0xB7,0xAD, -0xCD,0x79,0x7C,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0x93,0xFF,0xEF, -0xEA,0xFE,0xBF,0xEF,0x5B,0xD2,0xCD,0xF5, 0x6D,0x77,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF, -0xFF,0xFF,0x66,0xFF,0xD5,0x65,0x7D,0x5F, 0x75,0x9D,0x65,0x7F,0xD6,0xFB,0x4F,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xC7, 0xFF,0xBF,0xEF,0xFA,0xFE,0xFF,0xBF,0xEB, -0xFF,0xDF,0xFF,0x7E,0xFF,0xFF,0xEF,0xFD, 0x7E,0xD7,0xFF,0x78,0xDF,0xFF,0x5F,0xDF, -0xF5,0xBF,0x7F,0xDF,0xC5,0xFF,0x3F,0xF6, 0x7E,0xFF,0x0F,0xEF,0xF2,0x3E,0xBF,0xFF, -0xFB,0x3F,0xFF,0xFB,0x7F,0xFF,0xB3,0xFE, 0xFB,0xF6,0xFD,0xFF,0xDA,0xF7,0xFD,0xFF, -0x7F,0xDF,0xF7,0xBF,0xFF,0xFA,0x7F,0xFF, 0xFF,0xFF,0xFF,0x9F,0xFF,0xF3,0xDC,0xF9, -0xBF,0xCE,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7, 0xFF,0xFF,0xE2,0x7F,0xFE,0xFF,0xBF,0xEF, -0xEB,0xFA,0xFF,0x9F,0x67,0x1E,0xFF,0x8F, 0xE7,0xF8,0xFE,0x7F,0x8F,0xEF,0xFF,0xBD, -0xBF,0xFF,0xFB,0xFF,0xFF,0xDF,0xF7,0xFF, 0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xEF, 0xFF,0xFF,0xBF,0xED,0xFF,0xFB,0xEE,0xFE, -0xFF,0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFF,0xB5,0xFF,0xB7,0xFD,0xFD,0x6E,0xFF, -0xFF,0xFE,0xFD,0x2F,0xD8,0xFE,0xBF,0x8F, 0xEB,0xF9,0xFE,0x3F,0xFF,0xFA,0xCF,0xFF, -0xE7,0xD9,0xFA,0xBF,0xDF,0x77,0xFC,0xFB, 0x3F,0xAB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFE, -0xFF,0xFF,0xEE,0x1F,0xFF,0xDF,0xF7,0xFF, 0xFF,0xFF,0x5F,0x97,0x35,0xBF,0x5E,0xFE, -0xBF,0xEF,0xFF,0xF7,0xFD,0xFF,0xFF,0xFA, 0xBF,0xFF,0xBE,0x6F,0x9F,0xE7,0xF8,0xBE, -0x2F,0x8B,0x66,0x94,0x7D,0x9D,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,0xFF, -0xFF,0xF7,0xF5,0xFD,0x7F,0x5F,0xFB,0xFD, 0x9E,0xFF,0xFB,0xFE,0xFF,0xFF,0xEF,0xFF, -0xFF,0xA0,0xFF,0xFF,0xFF,0xBF,0xEF,0xEB, 0xFA,0xFE,0xBF,0xB7,0xF7,0xF7,0xFF,0xFF, -0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xFD,0xFF,0xFF,0xFF,0xD7,0xFF,0xFF,0xFF, -0x7F,0xF5,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xFF,0xAB,0xFE,0xFB,0xFE,0xFF, -0xF7,0xAF,0xFF,0xFF,0xDE,0xF7,0xEB,0x5F, 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,0xFF, -0xB3,0xFF,0xC9,0xFE,0xFF,0xFF,0xFF,0xFF, 0xD6,0xFF,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFC,0x8F,0xFF,0xBA, 0xBE,0xBF,0xAF,0xEB,0x78,0xFE,0xB7,0xAD, -0x3A,0xFE,0xB7,0xAF,0xEB,0x7A,0xFE,0xBF, 0xAF,0xFF,0x9F,0xFF,0xFF,0xDF,0xFC,0xFF, -0xFF,0xFE,0xC3,0xFE,0xFF,0xFF,0x33,0xFC, 0xFF,0xBF,0xDF,0xF3,0xFF,0xFF,0xBB,0x9F, -0xFF,0xFF,0xFF,0xEB,0xDF,0xFF,0xFF,0xAF, 0xF7,0x6F,0xF9,0xBF,0xEF,0xFD,0xFF,0xFF, -0xFF,0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xFD,0xFB,0xF7,0xFF, -0xDF,0xF7,0xFF,0xFE,0xEF,0x5F,0xBD,0xFF, 0xFA,0xFF,0xF8,0xFF,0xBF,0xAF,0xFB,0xFE, -0xFE,0x3F,0xEF,0xE8,0xFF,0xDF,0xF3,0xFD, 0xFF,0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xFB, -0xFD,0xFF,0xAF,0xFF,0xFF,0xFE,0xFE,0xBF, 0xDB,0xFF,0xFF,0xFF,0xBF,0xFF,0xDF,0xFF, -0xFD,0xFF,0xCB,0xFF,0xFF,0xFF,0xFF,0xFF, 0xBF,0x6F,0xFF,0x7F,0xB7,0xB3,0xFF,0xFF, -0xDF,0xFF,0xFB,0xEF,0xFF,0xFF,0xFF,0x07, 0xFF,0xFB,0xFF,0xFF,0xFF,0xED,0xFF,0xF5, -0x7C,0xFF,0x7F,0xFE,0xFF,0xFF,0xEF,0xCF, 0xFF,0xFB,0xFF,0xFF,0x2F,0xFF,0xFF,0xFF, -0xFF,0xF3,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, -0xFD,0x1B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFE,0x7C,0xFF,0xFF,0xFF,0xFF, -0xEF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0x7F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xFF,0xFF,0xF0,0x7F,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xFE, -0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xEF,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xEF,0xFA,0xB5,0xFF,0xFF,0xFF, 0xF7,0xF7,0xFF,0xFF,0xFF,0xFF,0xDF,0xFB, -0xFC,0xFF,0xFF,0xFE,0xFF,0x7F,0xDF,0xBF, 0xFF,0xCB,0xBF,0xF9,0xFE,0x7F,0x9F,0xE7, -0xF9,0xFE,0x7F,0x97,0xE1,0xFE,0x79,0x9F, 0xE7,0xFD,0xFE,0x7F,0xDF,0xFE,0x37,0xFF, -0xFB,0xDE,0xDE,0xBD,0xEF,0xF3,0xFE,0xFB, 0xAF,0xEB,0xFE,0xFF,0xFF,0xCF,0xFF,0xFE, -0xFF,0xBF,0xFF,0x8F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xE7,0xF9,0x5E,0x7F,0xEF,0xFB, -0xDA,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD, 0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF, -0xFF,0xFF,0x7F,0xFF,0xFF,0xF7,0xFB,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFC,0x3F,0xFF,0xBF, -0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0x7B,0x7F, 0xBF,0xEF,0xFB,0xFE,0xFF,0xB5,0xEF,0xFB, -0xBF,0xFA,0x7F,0xFC,0xFF,0x3F,0xCF,0xF3, 0xFC,0xFF,0x3F,0xCF,0xBC,0xFF,0x3F,0xEF, -0xF3,0xFC,0xFE,0x3F,0xCF,0xFF,0xEE,0xEF, 0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0x6A,0xD7, -0xB7,0xFB,0xF8,0xFF,0xB7,0xEF,0xBA,0xFE, 0xFF,0xBF,0x7F,0xE9,0xFF,0xF9,0x7E,0x5F, -0x97,0xE5,0xF9,0xFE,0x7F,0xBF,0xF9,0x7E, 0x5F,0x9F,0xE5,0xFB,0xFE,0x5F,0xB7,0xFF, -0xA3,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0x5E,0xF7,0x7D,0xFF,0x77,0xDF, -0xF7,0xFD,0xFF,0x7F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xDF,0xFB,0x7F, -0xFF,0xFF,0xEF,0xFF,0xFE,0xFB,0xFF,0xFF, 0xBF,0xFE,0x8F,0xFF,0xDF,0xF7,0xFD,0xFD, -0x7F,0xDF,0xF7,0xFD,0x3E,0xDF,0xF5,0xBD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xF7,0xFF,0x9F, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xBE,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFD,0x3F,0xFF,0xDF,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xCF, -0x77,0xFC,0xFF,0x5F,0xDF,0xF7,0xFD,0xFF, 0xF4,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xED,0xFB,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xE9,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFB,0xFF,0xFF,0xFF,0xD3,0xFF,0xFF, -0xBF,0x3F,0xFB,0xFF,0xFF,0xFF,0xFB,0xF3, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xFF, -0xDF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xDF,0xFF,0xFD,0xFF,0xFF,0xDF,0xF7, -0xFF,0x4F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD, -0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x9F,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFF,0xFF,0x7A,0x3F,0xFF,0xFF,0xFF,0xFF, -0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF2, -0x7F,0xFF,0xFB,0xFE,0xFF,0xBF,0xEF,0xF8, 0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,0x8F,0xEC, -0xFB,0xFE,0xFF,0xBF,0xF8,0xF7,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFD,0xBF,0xCF,0xEC, -0xFF,0x3F,0xEF,0xDB,0xF8,0xFF,0xBF,0xCF, 0xFF,0xF9,0xFF,0xFF,0xBF,0xFF,0xFB,0xFF, -0xFF,0xFF,0xEF,0xFB,0xDF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xBB,0xFF, -0xEF,0xFB,0xFE,0xEF,0xBF,0xEE,0xEB,0xFB, 0xFE,0xFF,0xEF,0xFE,0xEE,0xBF,0xFE,0xEB, -0xFF,0xEF,0xFF,0x17,0xFF,0x7E,0xEB,0xBB, 0xFE,0xBF,0xBE,0xFB,0xEF,0x5B,0xF7,0xBD, -0xFB,0xCF,0xBF,0xBF,0xBB,0xFB,0x7E,0xCC, 0xEF,0xFF - -}; diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c deleted file mode 100644 index 1774ab7a40d2..000000000000 --- a/drivers/usb/media/dabusb.c +++ /dev/null @@ -1,874 +0,0 @@ -/*****************************************************************************/ - -/* - * dabusb.c -- dab usb driver. - * - * Copyright (C) 1999 Deti Fliegl (deti@fliegl.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * - * $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $ - * - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dabusb.h" -#include "dabfirmware.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.54" -#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de" -#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999" - -/* --------------------------------------------------------------------- */ - -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define NRDABUSB 256 -#else -#define NRDABUSB 4 -#endif - -/*-------------------------------------------------------------------*/ - -static dabusb_t dabusb[NRDABUSB]; -static int buffers = 256; -static struct usb_driver dabusb_driver; - -/*-------------------------------------------------------------------*/ - -static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src) -{ - unsigned long flags; - struct list_head *tmp; - int ret = 0; - - spin_lock_irqsave (&s->lock, flags); - - if (list_empty (src)) { - // no elements in source buffer - ret = -1; - goto err; - } - tmp = src->next; - list_move_tail (tmp, dst); - - err: spin_unlock_irqrestore (&s->lock, flags); - return ret; -} -/*-------------------------------------------------------------------*/ -#ifdef DEBUG -static void dump_urb (struct urb *urb) -{ - dbg("urb :%p", urb); - dbg("dev :%p", urb->dev); - dbg("pipe :%08X", urb->pipe); - dbg("status :%d", urb->status); - dbg("transfer_flags :%08X", urb->transfer_flags); - dbg("transfer_buffer :%p", urb->transfer_buffer); - dbg("transfer_buffer_length:%d", urb->transfer_buffer_length); - dbg("actual_length :%d", urb->actual_length); - dbg("setup_packet :%p", urb->setup_packet); - dbg("start_frame :%d", urb->start_frame); - dbg("number_of_packets :%d", urb->number_of_packets); - dbg("interval :%d", urb->interval); - dbg("error_count :%d", urb->error_count); - dbg("context :%p", urb->context); - dbg("complete :%p", urb->complete); -} -#endif -/*-------------------------------------------------------------------*/ -static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q) -{ - unsigned long flags; - pbuff_t b; - - dbg("dabusb_cancel_queue"); - - spin_lock_irqsave (&s->lock, flags); - - list_for_each_entry(b, q, buff_list) { -#ifdef DEBUG - dump_urb(b->purb); -#endif - usb_unlink_urb (b->purb); - } - spin_unlock_irqrestore (&s->lock, flags); - return 0; -} -/*-------------------------------------------------------------------*/ -static int dabusb_free_queue (struct list_head *q) -{ - struct list_head *tmp; - struct list_head *p; - pbuff_t b; - - dbg("dabusb_free_queue"); - for (p = q->next; p != q;) { - b = list_entry (p, buff_t, buff_list); - -#ifdef DEBUG - dump_urb(b->purb); -#endif - kfree(b->purb->transfer_buffer); - usb_free_urb(b->purb); - tmp = p->next; - list_del (p); - kfree (b); - p = tmp; - } - - return 0; -} -/*-------------------------------------------------------------------*/ -static int dabusb_free_buffers (pdabusb_t s) -{ - unsigned long flags; - dbg("dabusb_free_buffers"); - - spin_lock_irqsave(&s->lock, flags); - - dabusb_free_queue (&s->free_buff_list); - dabusb_free_queue (&s->rec_buff_list); - - spin_unlock_irqrestore(&s->lock, flags); - - s->got_mem = 0; - return 0; -} -/*-------------------------------------------------------------------*/ -static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs) -{ - pbuff_t b = purb->context; - pdabusb_t s = b->s; - int i; - int len; - int dst = 0; - void *buf = purb->transfer_buffer; - - dbg("dabusb_iso_complete"); - - // process if URB was not killed - if (purb->status != -ENOENT) { - unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE); - int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)); - for (i = 0; i < purb->number_of_packets; i++) - if (!purb->iso_frame_desc[i].status) { - len = purb->iso_frame_desc[i].actual_length; - if (len <= pipesize) { - memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len); - dst += len; - } - else - err("dabusb_iso_complete: invalid len %d", len); - } - else - warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status); - if (dst != purb->actual_length) - err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length); - } - - if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) { - s->overruns++; - err("overrun (%d)", s->overruns); - } - wake_up (&s->wait); -} -/*-------------------------------------------------------------------*/ -static int dabusb_alloc_buffers (pdabusb_t s) -{ - int buffers = 0; - pbuff_t b; - unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE); - int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe)); - int packets = _ISOPIPESIZE / pipesize; - int transfer_buffer_length = packets * pipesize; - int i; - - dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d", - pipesize, packets, transfer_buffer_length); - - while (buffers < (s->total_buffer_size << 10)) { - b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL); - if (!b) { - err("kzalloc(sizeof(buff_t))==NULL"); - goto err; - } - b->s = s; - b->purb = usb_alloc_urb(packets, GFP_KERNEL); - if (!b->purb) { - err("usb_alloc_urb == NULL"); - kfree (b); - goto err; - } - - b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL); - if (!b->purb->transfer_buffer) { - kfree (b->purb); - kfree (b); - err("kmalloc(%d)==NULL", transfer_buffer_length); - goto err; - } - - b->purb->transfer_buffer_length = transfer_buffer_length; - b->purb->number_of_packets = packets; - b->purb->complete = dabusb_iso_complete; - b->purb->context = b; - b->purb->dev = s->usbdev; - b->purb->pipe = pipe; - b->purb->transfer_flags = URB_ISO_ASAP; - - for (i = 0; i < packets; i++) { - b->purb->iso_frame_desc[i].offset = i * pipesize; - b->purb->iso_frame_desc[i].length = pipesize; - } - - buffers += transfer_buffer_length; - list_add_tail (&b->buff_list, &s->free_buff_list); - } - s->got_mem = buffers; - - return 0; - - err: - dabusb_free_buffers (s); - return -ENOMEM; -} -/*-------------------------------------------------------------------*/ -static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb) -{ - int ret; - unsigned int pipe; - int actual_length; - - dbg("dabusb_bulk"); - - if (!pb->pipe) - pipe = usb_rcvbulkpipe (s->usbdev, 2); - else - pipe = usb_sndbulkpipe (s->usbdev, 2); - - ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100); - if(ret<0) { - err("dabusb: usb_bulk_msg failed(%d)",ret); - - if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { - err("set_interface failed"); - return -EINVAL; - } - - } - - if( ret == -EPIPE ) { - warn("CLEAR_FEATURE request to remove STALL condition."); - if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe))) - err("request failed"); - } - - pb->size = actual_length; - return ret; -} -/* --------------------------------------------------------------------- */ -static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len) -{ - int ret; - unsigned char *transfer_buffer = kmalloc (len, GFP_KERNEL); - - if (!transfer_buffer) { - err("dabusb_writemem: kmalloc(%d) failed.", len); - return -ENOMEM; - } - - memcpy (transfer_buffer, data, len); - - ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300); - - kfree (transfer_buffer); - return ret; -} -/* --------------------------------------------------------------------- */ -static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit) -{ - dbg("dabusb_8051_reset: %d",reset_bit); - return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1); -} -/* --------------------------------------------------------------------- */ -static int dabusb_loadmem (pdabusb_t s, const char *fname) -{ - int ret; - PINTEL_HEX_RECORD ptr = firmware; - - dbg("Enter dabusb_loadmem (internal)"); - - ret = dabusb_8051_reset (s, 1); - while (ptr->Type == 0) { - - dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length); - - ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length); - if (ret < 0) { - err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length); - break; - } - ptr++; - } - ret = dabusb_8051_reset (s, 0); - - dbg("dabusb_loadmem: exit"); - - return ret; -} -/* --------------------------------------------------------------------- */ -static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b) -{ - b->size = 4; - b->data[0] = 0x2a; - b->data[1] = 0; - b->data[2] = 0; - b->data[3] = 0; - - dbg("dabusb_fpga_clear"); - - return dabusb_bulk (s, b); -} -/* --------------------------------------------------------------------- */ -static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b) -{ - b->size = 4; - b->data[0] = 0x2c; - b->data[1] = 0; - b->data[2] = 0; - b->data[3] = 0; - - dbg("dabusb_fpga_init"); - - return dabusb_bulk (s, b); -} -/* --------------------------------------------------------------------- */ -static int dabusb_fpga_download (pdabusb_t s, const char *fname) -{ - pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); - unsigned int blen, n; - int ret; - unsigned char *buf = bitstream; - - dbg("Enter dabusb_fpga_download (internal)"); - - if (!b) { - err("kmalloc(sizeof(bulk_transfer_t))==NULL"); - return -ENOMEM; - } - - b->pipe = 1; - ret = dabusb_fpga_clear (s, b); - mdelay (10); - blen = buf[73] + (buf[72] << 8); - - dbg("Bitstream len: %i", blen); - - b->data[0] = 0x2b; - b->data[1] = 0; - b->data[2] = 0; - b->data[3] = 60; - - for (n = 0; n <= blen + 60; n += 60) { - // some cclks for startup - b->size = 64; - memcpy (b->data + 4, buf + 74 + n, 60); - ret = dabusb_bulk (s, b); - if (ret < 0) { - err("dabusb_bulk failed."); - break; - } - mdelay (1); - } - - ret = dabusb_fpga_init (s, b); - kfree (b); - - dbg("exit dabusb_fpga_download"); - - return ret; -} - -static int dabusb_stop (pdabusb_t s) -{ - dbg("dabusb_stop"); - - s->state = _stopped; - dabusb_cancel_queue (s, &s->rec_buff_list); - - dbg("pending_io: %d", s->pending_io.counter); - - s->pending_io.counter = 0; - return 0; -} - -static int dabusb_startrek (pdabusb_t s) -{ - if (!s->got_mem && s->state != _started) { - - dbg("dabusb_startrek"); - - if (dabusb_alloc_buffers (s) < 0) - return -ENOMEM; - dabusb_stop (s); - s->state = _started; - s->readptr = 0; - } - - if (!list_empty (&s->free_buff_list)) { - pbuff_t end; - int ret; - - while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) { - - dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list); - - end = list_entry (s->rec_buff_list.prev, buff_t, buff_list); - - ret = usb_submit_urb (end->purb, GFP_KERNEL); - if (ret) { - err("usb_submit_urb returned:%d", ret); - if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) - err("startrek: dabusb_add_buf_tail failed"); - break; - } - else - atomic_inc (&s->pending_io); - } - dbg("pending_io: %d",s->pending_io.counter); - } - - return 0; -} - -static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos) -{ - pdabusb_t s = (pdabusb_t) file->private_data; - unsigned long flags; - unsigned ret = 0; - int rem; - int cnt; - pbuff_t b; - struct urb *purb = NULL; - - dbg("dabusb_read"); - - if (*ppos) - return -ESPIPE; - - if (s->remove_pending) - return -EIO; - - - if (!s->usbdev) - return -EIO; - - while (count > 0) { - dabusb_startrek (s); - - spin_lock_irqsave (&s->lock, flags); - - if (list_empty (&s->rec_buff_list)) { - - spin_unlock_irqrestore(&s->lock, flags); - - err("error: rec_buf_list is empty"); - goto err; - } - - b = list_entry (s->rec_buff_list.next, buff_t, buff_list); - purb = b->purb; - - spin_unlock_irqrestore(&s->lock, flags); - - if (purb->status == -EINPROGRESS) { - if (file->f_flags & O_NONBLOCK) // return nonblocking - { - if (!ret) - ret = -EAGAIN; - goto err; - } - - interruptible_sleep_on (&s->wait); - - if (signal_pending (current)) { - if (!ret) - ret = -ERESTARTSYS; - goto err; - } - - spin_lock_irqsave (&s->lock, flags); - - if (list_empty (&s->rec_buff_list)) { - spin_unlock_irqrestore(&s->lock, flags); - err("error: still no buffer available."); - goto err; - } - spin_unlock_irqrestore(&s->lock, flags); - s->readptr = 0; - } - if (s->remove_pending) { - ret = -EIO; - goto err; - } - - rem = purb->actual_length - s->readptr; // set remaining bytes to copy - - if (count >= rem) - cnt = rem; - else - cnt = count; - - dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt); - - if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) { - err("read: copy_to_user failed"); - if (!ret) - ret = -EFAULT; - goto err; - } - - s->readptr += cnt; - count -= cnt; - buf += cnt; - ret += cnt; - - if (s->readptr == purb->actual_length) { - // finished, take next buffer - if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) - err("read: dabusb_add_buf_tail failed"); - s->readptr = 0; - } - } - err: //mutex_unlock(&s->mutex); - return ret; -} - -static int dabusb_open (struct inode *inode, struct file *file) -{ - int devnum = iminor(inode); - pdabusb_t s; - - if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB)) - return -EIO; - - s = &dabusb[devnum - DABUSB_MINOR]; - - dbg("dabusb_open"); - mutex_lock(&s->mutex); - - while (!s->usbdev || s->opened) { - mutex_unlock(&s->mutex); - - if (file->f_flags & O_NONBLOCK) { - return -EBUSY; - } - msleep_interruptible(500); - - if (signal_pending (current)) { - return -EAGAIN; - } - mutex_lock(&s->mutex); - } - if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { - mutex_unlock(&s->mutex); - err("set_interface failed"); - return -EINVAL; - } - s->opened = 1; - mutex_unlock(&s->mutex); - - file->f_pos = 0; - file->private_data = s; - - return nonseekable_open(inode, file); -} - -static int dabusb_release (struct inode *inode, struct file *file) -{ - pdabusb_t s = (pdabusb_t) file->private_data; - - dbg("dabusb_release"); - - mutex_lock(&s->mutex); - dabusb_stop (s); - dabusb_free_buffers (s); - mutex_unlock(&s->mutex); - - if (!s->remove_pending) { - if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) - err("set_interface failed"); - } - else - wake_up (&s->remove_ok); - - s->opened = 0; - return 0; -} - -static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - pdabusb_t s = (pdabusb_t) file->private_data; - pbulk_transfer_t pbulk; - int ret = 0; - int version = DABUSB_VERSION; - - dbg("dabusb_ioctl"); - - if (s->remove_pending) - return -EIO; - - mutex_lock(&s->mutex); - - if (!s->usbdev) { - mutex_unlock(&s->mutex); - return -EIO; - } - - switch (cmd) { - - case IOCTL_DAB_BULK: - pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); - - if (!pbulk) { - ret = -ENOMEM; - break; - } - - if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) { - ret = -EFAULT; - kfree (pbulk); - break; - } - - ret=dabusb_bulk (s, pbulk); - if(ret==0) - if (copy_to_user((void __user *)arg, pbulk, - sizeof(bulk_transfer_t))) - ret = -EFAULT; - kfree (pbulk); - break; - - case IOCTL_DAB_OVERRUNS: - ret = put_user (s->overruns, (unsigned int __user *) arg); - break; - - case IOCTL_DAB_VERSION: - ret = put_user (version, (unsigned int __user *) arg); - break; - - default: - ret = -ENOIOCTLCMD; - break; - } - mutex_unlock(&s->mutex); - return ret; -} - -static struct file_operations dabusb_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = dabusb_read, - .ioctl = dabusb_ioctl, - .open = dabusb_open, - .release = dabusb_release, -}; - -static struct usb_class_driver dabusb_class = { - .name = "dabusb%d", - .fops = &dabusb_fops, - .minor_base = DABUSB_MINOR, -}; - - -/* --------------------------------------------------------------------- */ -static int dabusb_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usbdev = interface_to_usbdev(intf); - int retval; - pdabusb_t s; - - dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d", - le16_to_cpu(usbdev->descriptor.idVendor), - le16_to_cpu(usbdev->descriptor.idProduct), - intf->altsetting->desc.bInterfaceNumber); - - /* We don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && - le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999) - return -ENODEV; - - - - s = &dabusb[intf->minor]; - - mutex_lock(&s->mutex); - s->remove_pending = 0; - s->usbdev = usbdev; - s->devnum = intf->minor; - - if (usb_reset_configuration (usbdev) < 0) { - err("reset_configuration failed"); - goto reject; - } - if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) { - dabusb_loadmem (s, NULL); - goto reject; - } - else { - dabusb_fpga_download (s, NULL); - - if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) { - err("set_interface failed"); - goto reject; - } - } - dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber); - usb_set_intfdata (intf, s); - mutex_unlock(&s->mutex); - - retval = usb_register_dev(intf, &dabusb_class); - if (retval) { - usb_set_intfdata (intf, NULL); - return -ENOMEM; - } - - return 0; - - reject: - mutex_unlock(&s->mutex); - s->usbdev = NULL; - return -ENODEV; -} - -static void dabusb_disconnect (struct usb_interface *intf) -{ - wait_queue_t __wait; - pdabusb_t s = usb_get_intfdata (intf); - - dbg("dabusb_disconnect"); - - init_waitqueue_entry(&__wait, current); - - usb_set_intfdata (intf, NULL); - if (s) { - usb_deregister_dev (intf, &dabusb_class); - s->remove_pending = 1; - wake_up (&s->wait); - add_wait_queue(&s->remove_ok, &__wait); - set_current_state(TASK_UNINTERRUPTIBLE); - if (s->state == _started) - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(&s->remove_ok, &__wait); - - s->usbdev = NULL; - s->overruns = 0; - } -} - -static struct usb_device_id dabusb_ids [] = { - // { USB_DEVICE(0x0547, 0x2131) }, /* An2131 chip, no boot ROM */ - { USB_DEVICE(0x0547, 0x9999) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, dabusb_ids); - -static struct usb_driver dabusb_driver = { - .name = "dabusb", - .probe = dabusb_probe, - .disconnect = dabusb_disconnect, - .id_table = dabusb_ids, -}; - -/* --------------------------------------------------------------------- */ - -static int __init dabusb_init (void) -{ - int retval; - unsigned u; - - /* initialize struct */ - for (u = 0; u < NRDABUSB; u++) { - pdabusb_t s = &dabusb[u]; - memset (s, 0, sizeof (dabusb_t)); - mutex_init (&s->mutex); - s->usbdev = NULL; - s->total_buffer_size = buffers; - init_waitqueue_head (&s->wait); - init_waitqueue_head (&s->remove_ok); - spin_lock_init (&s->lock); - INIT_LIST_HEAD (&s->free_buff_list); - INIT_LIST_HEAD (&s->rec_buff_list); - } - - /* register misc device */ - retval = usb_register(&dabusb_driver); - if (retval) - goto out; - - dbg("dabusb_init: driver registered"); - - info(DRIVER_VERSION ":" DRIVER_DESC); - -out: - return retval; -} - -static void __exit dabusb_cleanup (void) -{ - dbg("dabusb_cleanup"); - - usb_deregister (&dabusb_driver); -} - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - -module_param(buffers, int, 0); -MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); - -module_init (dabusb_init); -module_exit (dabusb_cleanup); - -/* --------------------------------------------------------------------- */ diff --git a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h deleted file mode 100644 index 96b03e4af8b9..000000000000 --- a/drivers/usb/media/dabusb.h +++ /dev/null @@ -1,85 +0,0 @@ -#define _BULK_DATA_LEN 64 -typedef struct -{ - unsigned char data[_BULK_DATA_LEN]; - unsigned int size; - unsigned int pipe; -}bulk_transfer_t,*pbulk_transfer_t; - -#define DABUSB_MINOR 240 /* some unassigned USB minor */ -#define DABUSB_VERSION 0x1000 -#define IOCTL_DAB_BULK _IOWR('d', 0x30, bulk_transfer_t) -#define IOCTL_DAB_OVERRUNS _IOR('d', 0x15, int) -#define IOCTL_DAB_VERSION _IOR('d', 0x3f, int) - -#ifdef __KERNEL__ - -typedef enum { _stopped=0, _started } driver_state_t; - -typedef struct -{ - struct mutex mutex; - struct usb_device *usbdev; - wait_queue_head_t wait; - wait_queue_head_t remove_ok; - spinlock_t lock; - atomic_t pending_io; - driver_state_t state; - int remove_pending; - int got_mem; - int total_buffer_size; - unsigned int overruns; - int readptr; - int opened; - int devnum; - struct list_head free_buff_list; - struct list_head rec_buff_list; -} dabusb_t,*pdabusb_t; - -typedef struct -{ - pdabusb_t s; - struct urb *purb; - struct list_head buff_list; -} buff_t,*pbuff_t; - -typedef struct -{ - wait_queue_head_t wait; -} bulk_completion_context_t, *pbulk_completion_context_t; - - -#define _DABUSB_IF 2 -#define _DABUSB_ISOPIPE 0x09 -#define _ISOPIPESIZE 16384 - -#define _BULK_DATA_LEN 64 -// Vendor specific request code for Anchor Upload/Download -// This one is implemented in the core -#define ANCHOR_LOAD_INTERNAL 0xA0 - -// EZ-USB Control and Status Register. Bit 0 controls 8051 reset -#define CPUCS_REG 0x7F92 -#define _TOTAL_BUFFERS 384 - -#define MAX_INTEL_HEX_RECORD_LENGTH 16 - -#ifndef _BYTE_DEFINED -#define _BYTE_DEFINED -typedef unsigned char BYTE; -#endif // !_BYTE_DEFINED - -#ifndef _WORD_DEFINED -#define _WORD_DEFINED -typedef unsigned short WORD; -#endif // !_WORD_DEFINED - -typedef struct _INTEL_HEX_RECORD -{ - BYTE Length; - WORD Address; - BYTE Type; - BYTE Data[MAX_INTEL_HEX_RECORD_LENGTH]; -} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD; - -#endif diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c deleted file mode 100644 index 25646804d5be..000000000000 --- a/drivers/usb/media/dsbr100.c +++ /dev/null @@ -1,429 +0,0 @@ -/* A driver for the D-Link DSB-R100 USB radio. The R100 plugs - into both the USB and an analog audio input, so this thing - only deals with initialisation and frequency setting, the - audio data has to be handled by a sound driver. - - Major issue: I can't find out where the device reports the signal - strength, and indeed the windows software appearantly just looks - at the stereo indicator as well. So, scanning will only find - stereo stations. Sad, but I can't help it. - - Also, the windows program sends oodles of messages over to the - device, and I couldn't figure out their meaning. My suspicion - is that they don't have any:-) - - You might find some interesting stuff about this module at - http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr - - Copyright (c) 2000 Markus Demleitner - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - History: - - Version 0.40: - Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing - - Version 0.30: - Markus: Updates for 2.5.x kernel and more ISO compliant source - - Version 0.25: - PSL and Markus: Cleanup, radio now doesn't stop on device close - - Version 0.24: - Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally - right. Some minor cleanup, improved standalone compilation - - Version 0.23: - Markus: Sign extension bug fixed by declaring transfer_buffer unsigned - - Version 0.22: - Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, - thanks to Mike Cox for pointing the problem out. - - Version 0.21: - Markus: Minor cleanup, warnings if something goes wrong, lame attempt - to adhere to Documentation/CodingStyle - - Version 0.2: - Brad Hards : Fixes to make it work as non-module - Markus: Copyright clarification - - Version 0.01: Markus: initial release - -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.40" -#define DRIVER_AUTHOR "Markus Demleitner " -#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" - -#define DSB100_VENDOR 0x04b4 -#define DSB100_PRODUCT 0x1002 - -/* Commands the device appears to understand */ -#define DSB100_TUNE 1 -#define DSB100_ONOFF 2 - -#define TB_LEN 16 - -/* Frequency limits in MHz -- these are European values. For Japanese -devices, that would be 76 and 91. */ -#define FREQ_MIN 87.5 -#define FREQ_MAX 108.0 -#define FREQ_MUL 16000 - - -static int usb_dsbr100_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void usb_dsbr100_disconnect(struct usb_interface *intf); -static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static int usb_dsbr100_open(struct inode *inode, struct file *file); -static int usb_dsbr100_close(struct inode *inode, struct file *file); - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -/* Data for one (physical) device */ -typedef struct { - struct usb_device *usbdev; - struct video_device *videodev; - unsigned char transfer_buffer[TB_LEN]; - int curfreq; - int stereo; - int users; - int removed; -} dsbr100_device; - - -/* File system interface */ -static struct file_operations usb_dsbr100_fops = { - .owner = THIS_MODULE, - .open = usb_dsbr100_open, - .release = usb_dsbr100_close, - .ioctl = usb_dsbr100_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -/* V4L interface */ -static struct video_device dsbr100_videodev_template= -{ - .owner = THIS_MODULE, - .name = "D-Link DSB-R 100", - .type = VID_TYPE_TUNER, - .hardware = VID_HARDWARE_AZTECH, - .fops = &usb_dsbr100_fops, - .release = video_device_release, -}; - -static struct usb_device_id usb_dsbr100_device_table [] = { - { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); - -/* USB subsystem interface */ -static struct usb_driver usb_dsbr100_driver = { - .name = "dsbr100", - .probe = usb_dsbr100_probe, - .disconnect = usb_dsbr100_disconnect, - .id_table = usb_dsbr100_device_table, -}; - -/* Low-level device interface begins here */ - -/* switch on radio */ -static int dsbr100_start(dsbr100_device *radio) -{ - if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 || - usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_ONOFF, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x01, 0x00, radio->transfer_buffer, 8, 300)<0) - return -1; - return (radio->transfer_buffer)[0]; -} - - -/* switch off radio */ -static int dsbr100_stop(dsbr100_device *radio) -{ - if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 || - usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_ONOFF, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0x00, radio->transfer_buffer, 8, 300)<0) - return -1; - return (radio->transfer_buffer)[0]; -} - -/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ -static int dsbr100_setfreq(dsbr100_device *radio, int freq) -{ - freq = (freq/16*80)/1000+856; - if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - DSB100_TUNE, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - (freq>>8)&0x00ff, freq&0xff, - radio->transfer_buffer, 8, 300)<0 || - usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 || - usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) { - radio->stereo = -1; - return -1; - } - radio->stereo = ! ((radio->transfer_buffer)[0]&0x01); - return (radio->transfer_buffer)[0]; -} - -/* return the device status. This is, in effect, just whether it -sees a stereo signal or not. Pity. */ -static void dsbr100_getstat(dsbr100_device *radio) -{ - if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), - USB_REQ_GET_STATUS, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0) - radio->stereo = -1; - else - radio->stereo = ! (radio->transfer_buffer[0]&0x01); -} - - -/* USB subsystem interface begins here */ - -/* check if the device is present and register with v4l and -usb if it is */ -static int usb_dsbr100_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - dsbr100_device *radio; - - if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL))) - return -ENOMEM; - if (!(radio->videodev = video_device_alloc())) { - kfree(radio); - return -ENOMEM; - } - memcpy(radio->videodev, &dsbr100_videodev_template, - sizeof(dsbr100_videodev_template)); - radio->removed = 0; - radio->users = 0; - radio->usbdev = interface_to_usbdev(intf); - radio->curfreq = FREQ_MIN*FREQ_MUL; - video_set_drvdata(radio->videodev, radio); - if (video_register_device(radio->videodev, VFL_TYPE_RADIO, - radio_nr)) { - warn("Could not register video device"); - video_device_release(radio->videodev); - kfree(radio); - return -EIO; - } - usb_set_intfdata(intf, radio); - return 0; -} - -/* handle unplugging of the device, release data structures -if nothing keeps us from doing it. If something is still -keeping us busy, the release callback of v4l will take care -of releasing it. stv680.c does not relase its private -data, so I don't do this here either. Checking out the -code I'd expect I better did that, but if there's a memory -leak here it's tiny (~50 bytes per disconnect) */ -static void usb_dsbr100_disconnect(struct usb_interface *intf) -{ - dsbr100_device *radio = usb_get_intfdata(intf); - - usb_set_intfdata (intf, NULL); - if (radio) { - video_unregister_device(radio->videodev); - radio->videodev = NULL; - if (radio->users) { - kfree(radio); - } else { - radio->removed = 1; - } - } -} - - -/* Video for Linux interface */ - -static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - dsbr100_device *radio=video_get_drvdata(video_devdata(file)); - - if (!radio) - return -EIO; - - switch(cmd) { - case VIDIOCGCAP: { - struct video_capability *v = arg; - - memset(v, 0, sizeof(*v)); - v->type = VID_TYPE_TUNER; - v->channels = 1; - v->audios = 1; - strcpy(v->name, "D-Link R-100 USB FM Radio"); - return 0; - } - case VIDIOCGTUNER: { - struct video_tuner *v = arg; - - dsbr100_getstat(radio); - if(v->tuner) /* Only 1 tuner */ - return -EINVAL; - v->rangelow = FREQ_MIN*FREQ_MUL; - v->rangehigh = FREQ_MAX*FREQ_MUL; - v->flags = VIDEO_TUNER_LOW; - v->mode = VIDEO_MODE_AUTO; - v->signal = radio->stereo*0x7000; - /* Don't know how to get signal strength */ - v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo; - strcpy(v->name, "DSB R-100"); - return 0; - } - case VIDIOCSTUNER: { - struct video_tuner *v = arg; - - if(v->tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: { - int *freq = arg; - - if (radio->curfreq==-1) - return -EINVAL; - *freq = radio->curfreq; - return 0; - } - case VIDIOCSFREQ: { - int *freq = arg; - - radio->curfreq = *freq; - if (dsbr100_setfreq(radio, radio->curfreq)==-1) - warn("Set frequency failed"); - return 0; - } - case VIDIOCGAUDIO: { - struct video_audio *v = arg; - - memset(v, 0, sizeof(*v)); - v->flags |= VIDEO_AUDIO_MUTABLE; - v->mode = VIDEO_SOUND_STEREO; - v->volume = 1; - v->step = 1; - strcpy(v->name, "Radio"); - return 0; - } - case VIDIOCSAUDIO: { - struct video_audio *v = arg; - - if (v->audio) - return -EINVAL; - if (v->flags&VIDEO_AUDIO_MUTE) { - if (dsbr100_stop(radio)==-1) - warn("Radio did not respond properly"); - } - else - if (dsbr100_start(radio)==-1) - warn("Radio did not respond properly"); - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int usb_dsbr100_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl); -} - -static int usb_dsbr100_open(struct inode *inode, struct file *file) -{ - dsbr100_device *radio=video_get_drvdata(video_devdata(file)); - - radio->users = 1; - if (dsbr100_start(radio)<0) { - warn("Radio did not start up properly"); - radio->users = 0; - return -EIO; - } - dsbr100_setfreq(radio, radio->curfreq); - return 0; -} - -static int usb_dsbr100_close(struct inode *inode, struct file *file) -{ - dsbr100_device *radio=video_get_drvdata(video_devdata(file)); - - if (!radio) - return -ENODEV; - radio->users = 0; - if (radio->removed) { - kfree(radio); - } - return 0; -} - -static int __init dsbr100_init(void) -{ - int retval = usb_register(&usb_dsbr100_driver); - info(DRIVER_VERSION ":" DRIVER_DESC); - return retval; -} - -static void __exit dsbr100_exit(void) -{ - usb_deregister(&usb_dsbr100_driver); -} - -module_init (dsbr100_init); -module_exit (dsbr100_exit); - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/media/et61x251.h b/drivers/usb/media/et61x251.h deleted file mode 100644 index eee8afc9be72..000000000000 --- a/drivers/usb/media/et61x251.h +++ /dev/null @@ -1,234 +0,0 @@ -/*************************************************************************** - * V4L2 driver for ET61X[12]51 PC Camera Controllers * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _ET61X251_H_ -#define _ET61X251_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "et61x251_sensor.h" - -/*****************************************************************************/ - -#define ET61X251_DEBUG -#define ET61X251_DEBUG_LEVEL 2 -#define ET61X251_MAX_DEVICES 64 -#define ET61X251_PRESERVE_IMGSCALE 0 -#define ET61X251_FORCE_MUNMAP 0 -#define ET61X251_MAX_FRAMES 32 -#define ET61X251_COMPRESSION_QUALITY 0 -#define ET61X251_URBS 2 -#define ET61X251_ISO_PACKETS 7 -#define ET61X251_ALTERNATE_SETTING 13 -#define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS) -#define ET61X251_CTRL_TIMEOUT 100 -#define ET61X251_FRAME_TIMEOUT 2 - -/*****************************************************************************/ - -static const struct usb_device_id et61x251_id_table[] = { - { USB_DEVICE(0x102c, 0x6151), }, - { USB_DEVICE(0x102c, 0x6251), }, - { USB_DEVICE(0x102c, 0x6253), }, - { USB_DEVICE(0x102c, 0x6254), }, - { USB_DEVICE(0x102c, 0x6255), }, - { USB_DEVICE(0x102c, 0x6256), }, - { USB_DEVICE(0x102c, 0x6257), }, - { USB_DEVICE(0x102c, 0x6258), }, - { USB_DEVICE(0x102c, 0x6259), }, - { USB_DEVICE(0x102c, 0x625a), }, - { USB_DEVICE(0x102c, 0x625b), }, - { USB_DEVICE(0x102c, 0x625c), }, - { USB_DEVICE(0x102c, 0x625d), }, - { USB_DEVICE(0x102c, 0x625e), }, - { USB_DEVICE(0x102c, 0x625f), }, - { USB_DEVICE(0x102c, 0x6260), }, - { USB_DEVICE(0x102c, 0x6261), }, - { USB_DEVICE(0x102c, 0x6262), }, - { USB_DEVICE(0x102c, 0x6263), }, - { USB_DEVICE(0x102c, 0x6264), }, - { USB_DEVICE(0x102c, 0x6265), }, - { USB_DEVICE(0x102c, 0x6266), }, - { USB_DEVICE(0x102c, 0x6267), }, - { USB_DEVICE(0x102c, 0x6268), }, - { USB_DEVICE(0x102c, 0x6269), }, - { } -}; - -ET61X251_SENSOR_TABLE - -/*****************************************************************************/ - -enum et61x251_frame_state { - F_UNUSED, - F_QUEUED, - F_GRABBING, - F_DONE, - F_ERROR, -}; - -struct et61x251_frame_t { - void* bufmem; - struct v4l2_buffer buf; - enum et61x251_frame_state state; - struct list_head frame; - unsigned long vma_use_count; -}; - -enum et61x251_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -enum et61x251_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum et61x251_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON, -}; - -struct et61x251_sysfs_attr { - u8 reg, i2c_reg; -}; - -struct et61x251_module_param { - u8 force_munmap; - u16 frame_timeout; -}; - -static DEFINE_MUTEX(et61x251_sysfs_lock); -static DECLARE_RWSEM(et61x251_disconnect); - -struct et61x251_device { - struct video_device* v4ldev; - - struct et61x251_sensor sensor; - - struct usb_device* usbdev; - struct urb* urb[ET61X251_URBS]; - void* transfer_buffer[ET61X251_URBS]; - u8* control_buffer; - - struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES]; - struct list_head inqueue, outqueue; - u32 frame_count, nbuffers, nreadbuffers; - - enum et61x251_io_method io; - enum et61x251_stream_state stream; - - struct v4l2_jpegcompression compression; - - struct et61x251_sysfs_attr sysfs; - struct et61x251_module_param module_param; - - enum et61x251_dev_state state; - u8 users; - - struct mutex dev_mutex, fileop_mutex; - spinlock_t queue_lock; - wait_queue_head_t open, wait_frame, wait_stream; -}; - -/*****************************************************************************/ - -struct et61x251_device* -et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id) -{ - if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) - return cam; - - return NULL; -} - - -void -et61x251_attach_sensor(struct et61x251_device* cam, - struct et61x251_sensor* sensor) -{ - memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor)); -} - -/*****************************************************************************/ - -#undef DBG -#undef KDBG -#ifdef ET61X251_DEBUG -# define DBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1) \ - dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) == 2) \ - dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args); \ - } \ -} while (0) -# define KDBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1 || (level) == 2) \ - pr_info("et61x251: " fmt "\n", ## args); \ - else if ((level) == 3) \ - pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \ - __LINE__ , ## args); \ - } \ -} while (0) -# define V4LDBG(level, name, cmd) \ -do { \ - if (debug >= (level)) \ - v4l_print_ioctl(name, cmd); \ -} while (0) -#else -# define DBG(level, fmt, args...) do {;} while(0) -# define KDBG(level, fmt, args...) do {;} while(0) -# define V4LDBG(level, name, cmd) do {;} while(0) -#endif - -#undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args) - -#undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ - -#endif /* _ET61X251_H_ */ diff --git a/drivers/usb/media/et61x251_core.c b/drivers/usb/media/et61x251_core.c deleted file mode 100644 index 7cc01b828b3d..000000000000 --- a/drivers/usb/media/et61x251_core.c +++ /dev/null @@ -1,2630 +0,0 @@ -/*************************************************************************** - * V4L2 driver for ET61X[12]51 PC Camera Controllers * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "et61x251.h" - -/*****************************************************************************/ - -#define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \ - "PC Camera Controllers" -#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia" -#define ET61X251_AUTHOR_EMAIL "" -#define ET61X251_MODULE_LICENSE "GPL" -#define ET61X251_MODULE_VERSION "1:1.02" -#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2) - -/*****************************************************************************/ - -MODULE_DEVICE_TABLE(usb, et61x251_id_table); - -MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL); -MODULE_DESCRIPTION(ET61X251_MODULE_NAME); -MODULE_VERSION(ET61X251_MODULE_VERSION); -MODULE_LICENSE(ET61X251_MODULE_LICENSE); - -static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1}; -module_param_array(video_nr, short, NULL, 0444); -MODULE_PARM_DESC(video_nr, - "\n<-1|n[,...]> Specify V4L2 minor mode number." - "\n -1 = use next available (default)" - "\n n = use minor number n (integer >= 0)" - "\nYou can specify up to " - __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way." - "\nFor example:" - "\nvideo_nr=-1,2,-1 would assign minor number 2 to" - "\nthe second registered camera and use auto for the first" - "\none and for every other camera." - "\n"); - -static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = - ET61X251_FORCE_MUNMAP}; -module_param_array(force_munmap, bool, NULL, 0444); -MODULE_PARM_DESC(force_munmap, - "\n<0|1[,...]> Force the application to unmap previously" - "\nmapped buffer memory before calling any VIDIOC_S_CROP or" - "\nVIDIOC_S_FMT ioctl's. Not all the applications support" - "\nthis feature. This parameter is specific for each" - "\ndetected camera." - "\n 0 = do not force memory unmapping" - "\n 1 = force memory unmapping (save memory)" - "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." - "\n"); - -static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] = - ET61X251_FRAME_TIMEOUT}; -module_param_array(frame_timeout, uint, NULL, 0644); -MODULE_PARM_DESC(frame_timeout, - "\n Timeout for a video frame in seconds." - "\nThis parameter is specific for each detected camera." - "\nDefault value is " - __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"." - "\n"); - -#ifdef ET61X251_DEBUG -static unsigned short debug = ET61X251_DEBUG_LEVEL; -module_param(debug, ushort, 0644); -MODULE_PARM_DESC(debug, - "\n Debugging information level, from 0 to 3:" - "\n0 = none (use carefully)" - "\n1 = critical errors" - "\n2 = significant informations" - "\n3 = more verbose messages" - "\nLevel 3 is useful for testing only, when only " - "one device is used." - "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"." - "\n"); -#endif - -/*****************************************************************************/ - -static u32 -et61x251_request_buffers(struct et61x251_device* cam, u32 count, - enum et61x251_io_method io) -{ - struct v4l2_pix_format* p = &(cam->sensor.pix_format); - struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); - const size_t imagesize = cam->module_param.force_munmap || - io == IO_READ ? - (p->width * p->height * p->priv) / 8 : - (r->width * r->height * p->priv) / 8; - void* buff = NULL; - u32 i; - - if (count > ET61X251_MAX_FRAMES) - count = ET61X251_MAX_FRAMES; - - cam->nbuffers = count; - while (cam->nbuffers > 0) { - if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) - break; - cam->nbuffers--; - } - - for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.index = i; - cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.length = imagesize; - cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cam->frame[i].buf.sequence = 0; - cam->frame[i].buf.field = V4L2_FIELD_NONE; - cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; - cam->frame[i].buf.flags = 0; - } - - return cam->nbuffers; -} - - -static void et61x251_release_buffers(struct et61x251_device* cam) -{ - if (cam->nbuffers) { - vfree(cam->frame[0].bufmem); - cam->nbuffers = 0; - } - cam->frame_current = NULL; -} - - -static void et61x251_empty_framequeues(struct et61x251_device* cam) -{ - u32 i; - - INIT_LIST_HEAD(&cam->inqueue); - INIT_LIST_HEAD(&cam->outqueue); - - for (i = 0; i < ET61X251_MAX_FRAMES; i++) { - cam->frame[i].state = F_UNUSED; - cam->frame[i].buf.bytesused = 0; - } -} - - -static void et61x251_requeue_outqueue(struct et61x251_device* cam) -{ - struct et61x251_frame_t *i; - - list_for_each_entry(i, &cam->outqueue, frame) { - i->state = F_QUEUED; - list_add(&i->frame, &cam->inqueue); - } - - INIT_LIST_HEAD(&cam->outqueue); -} - - -static void et61x251_queue_unusedframes(struct et61x251_device* cam) -{ - unsigned long lock_flags; - u32 i; - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].state == F_UNUSED) { - cam->frame[i].state = F_QUEUED; - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[i].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - } -} - -/*****************************************************************************/ - -int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - *buff = value; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) { - DBG(3, "Failed to write a register (value 0x%02X, index " - "0x%02X, error %d)", value, index, res); - return -1; - } - - return 0; -} - - -int et61x251_read_reg(struct et61x251_device* cam, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0, index, buff, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - DBG(3, "Failed to read a register (index 0x%02X, error %d)", - index, res); - - return (res >= 0) ? (int)(*buff) : -1; -} - - -static int -et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor) -{ - int i, r; - - for (i = 1; i <= 8; i++) { - if (sensor->interface == ET61X251_I2C_3WIRES) { - r = et61x251_read_reg(cam, 0x8e); - if (!(r & 0x02) && (r >= 0)) - return 0; - } else { - r = et61x251_read_reg(cam, 0x8b); - if (!(r & 0x01) && (r >= 0)) - return 0; - } - if (r < 0) - return -EIO; - udelay(8*8); /* minimum for sensors at 400kHz */ - } - - return -EBUSY; -} - - -int -et61x251_i2c_try_read(struct et61x251_device* cam, - struct et61x251_sensor* sensor, u8 address) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x10; - data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, sensor); - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - if (err) - DBG(3, "I2C read failed for %s image sensor", sensor->name); - - PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); - - return err ? -1 : (int)data[0]; -} - - -int -et61x251_i2c_try_write(struct et61x251_device* cam, - struct et61x251_sensor* sensor, u8 address, u8 value) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x12; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - data[0] = value; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, sensor); - - if (err) - DBG(3, "I2C write failed for %s image sensor", sensor->name); - - PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); - - return err ? -1 : 0; -} - - -int -et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, - u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, - u8 data8, u8 address) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = data2; - data[1] = data3; - data[2] = data4; - data[3] = data5; - data[4] = data6; - data[5] = data7; - data[6] = data8; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x02 | (n << 4); - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - /* Start writing through the serial interface */ - data[0] = data1; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, &cam->sensor); - - if (err) - DBG(3, "I2C raw write failed for %s image sensor", - cam->sensor.name); - - PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, " - "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X," - " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address, - data1, data2, data3, data4, data5, data6, data7, data8); - - return err ? -1 : 0; - -} - - -int et61x251_i2c_read(struct et61x251_device* cam, u8 address) -{ - return et61x251_i2c_try_read(cam, &cam->sensor, address); -} - - -int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) -{ - return et61x251_i2c_try_write(cam, &cam->sensor, address, value); -} - -/*****************************************************************************/ - -static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs) -{ - struct et61x251_device* cam = urb->context; - struct et61x251_frame_t** f; - size_t imagesize; - u8 i; - int err = 0; - - if (urb->status == -ENOENT) - return; - - f = &cam->frame_current; - - if (cam->stream == STREAM_INTERRUPT) { - cam->stream = STREAM_OFF; - if ((*f)) - (*f)->state = F_QUEUED; - DBG(3, "Stream interrupted"); - wake_up(&cam->wait_stream); - } - - if (cam->state & DEV_DISCONNECTED) - return; - - if (cam->state & DEV_MISCONFIGURED) { - wake_up_interruptible(&cam->wait_frame); - return; - } - - if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) - goto resubmit_urb; - - if (!(*f)) - (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t, - frame); - - imagesize = (cam->sensor.pix_format.width * - cam->sensor.pix_format.height * - cam->sensor.pix_format.priv) / 8; - - for (i = 0; i < urb->number_of_packets; i++) { - unsigned int len, status; - void *pos; - u8* b1, * b2, sof; - const u8 VOID_BYTES = 6; - size_t imglen; - - len = urb->iso_frame_desc[i].actual_length; - status = urb->iso_frame_desc[i].status; - pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; - - if (status) { - DBG(3, "Error in isochronous frame"); - (*f)->state = F_ERROR; - continue; - } - - b1 = pos++; - b2 = pos++; - sof = ((*b1 & 0x3f) == 63); - imglen = ((*b1 & 0xc0) << 2) | *b2; - - PDBGG("Isochrnous frame: length %u, #%u i, image length %zu", - len, i, imglen); - - if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) -start_of_frame: - if (sof) { - (*f)->state = F_GRABBING; - (*f)->buf.bytesused = 0; - do_gettimeofday(&(*f)->buf.timestamp); - pos += 22; - DBG(3, "SOF detected: new video frame"); - } - - if ((*f)->state == F_GRABBING) { - if (sof && (*f)->buf.bytesused) { - if (cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_ET61X251) - goto end_of_frame; - else { - DBG(3, "Not expected SOF detected " - "after %lu bytes", - (unsigned long)(*f)->buf.bytesused); - (*f)->state = F_ERROR; - continue; - } - } - - if ((*f)->buf.bytesused + imglen > imagesize) { - DBG(3, "Video frame size exceeded"); - (*f)->state = F_ERROR; - continue; - } - - pos += VOID_BYTES; - - memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen); - (*f)->buf.bytesused += imglen; - - if ((*f)->buf.bytesused == imagesize) { - u32 b; -end_of_frame: - b = (*f)->buf.bytesused; - (*f)->state = F_DONE; - (*f)->buf.sequence= ++cam->frame_count; - spin_lock(&cam->queue_lock); - list_move_tail(&(*f)->frame, &cam->outqueue); - if (!list_empty(&cam->inqueue)) - (*f) = list_entry(cam->inqueue.next, - struct et61x251_frame_t, - frame); - else - (*f) = NULL; - spin_unlock(&cam->queue_lock); - DBG(3, "Video frame captured: : %lu bytes", - (unsigned long)(b)); - - if (!(*f)) - goto resubmit_urb; - - if (sof && - cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_ET61X251) - goto start_of_frame; - } - } - } - -resubmit_urb: - urb->dev = cam->usbdev; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0 && err != -EPERM) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "usb_submit_urb() failed"); - } - - wake_up_interruptible(&cam->wait_frame); -} - - -static int et61x251_start_transfer(struct et61x251_device* cam) -{ - struct usb_device *udev = cam->usbdev; - struct urb* urb; - const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832, - 864, 896, 920, 956, 980, 1000, - 1022}; - const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING]; - s8 i, j; - int err = 0; - - for (i = 0; i < ET61X251_URBS; i++) { - cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz, - GFP_KERNEL); - if (!cam->transfer_buffer[i]) { - err = -ENOMEM; - DBG(1, "Not enough memory"); - goto free_buffers; - } - } - - for (i = 0; i < ET61X251_URBS; i++) { - urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL); - cam->urb[i] = urb; - if (!urb) { - err = -ENOMEM; - DBG(1, "usb_alloc_urb() failed"); - goto free_urbs; - } - urb->dev = udev; - urb->context = cam; - urb->pipe = usb_rcvisocpipe(udev, 1); - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = ET61X251_ISO_PACKETS; - urb->complete = et61x251_urb_complete; - urb->transfer_buffer = cam->transfer_buffer[i]; - urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS; - urb->interval = 1; - for (j = 0; j < ET61X251_ISO_PACKETS; j++) { - urb->iso_frame_desc[j].offset = psz * j; - urb->iso_frame_desc[j].length = psz; - } - } - - err = et61x251_write_reg(cam, 0x01, 0x03); - err = et61x251_write_reg(cam, 0x00, 0x03); - err = et61x251_write_reg(cam, 0x08, 0x03); - if (err) { - err = -EIO; - DBG(1, "I/O hardware error"); - goto free_urbs; - } - - err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING); - if (err) { - DBG(1, "usb_set_interface() failed"); - goto free_urbs; - } - - cam->frame_current = NULL; - - for (i = 0; i < ET61X251_URBS; i++) { - err = usb_submit_urb(cam->urb[i], GFP_KERNEL); - if (err) { - for (j = i-1; j >= 0; j--) - usb_kill_urb(cam->urb[j]); - DBG(1, "usb_submit_urb() failed, error %d", err); - goto free_urbs; - } - } - - return 0; - -free_urbs: - for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++) - usb_free_urb(cam->urb[i]); - -free_buffers: - for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++) - kfree(cam->transfer_buffer[i]); - - return err; -} - - -static int et61x251_stop_transfer(struct et61x251_device* cam) -{ - struct usb_device *udev = cam->usbdev; - s8 i; - int err = 0; - - if (cam->state & DEV_DISCONNECTED) - return 0; - - for (i = ET61X251_URBS-1; i >= 0; i--) { - usb_kill_urb(cam->urb[i]); - usb_free_urb(cam->urb[i]); - kfree(cam->transfer_buffer[i]); - } - - err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ - if (err) - DBG(3, "usb_set_interface() failed"); - - return err; -} - - -static int et61x251_stream_interrupt(struct et61x251_device* cam) -{ - long timeout; - - cam->stream = STREAM_INTERRUPT; - timeout = wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - ET61X251_URB_TIMEOUT); - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - else if (cam->stream != STREAM_OFF) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "URB timeout reached. The camera is misconfigured. To " - "use it, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - return 0; -} - -/*****************************************************************************/ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) -{ - char str[5]; - char* endp; - unsigned long val; - - if (len < 4) { - strncpy(str, buff, len); - str[len+1] = '\0'; - } else { - strncpy(str, buff, 4); - str[4] = '\0'; - } - - val = simple_strtoul(str, &endp, 0); - - *count = 0; - if (val <= 0xff) - *count = (ssize_t)(endp - str); - if ((*count) && (len == *count+1) && (buff[*count] == '\n')) - *count += 1; - - return (u8)val; -} - -/* - NOTE 1: being inside one of the following methods implies that the v4l - device exists for sure (see kobjects and reference counters) - NOTE 2: buffers are PAGE_SIZE long -*/ - -static ssize_t et61x251_show_reg(struct class_device* cd, char* buf) -{ - struct et61x251_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.reg); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t -et61x251_store_reg(struct class_device* cd, const char* buf, size_t len) -{ - struct et61x251_device* cam; - u8 index; - ssize_t count; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - index = et61x251_strtou8(buf, len, &count); - if (index > 0x8e || !count) { - mutex_unlock(&et61x251_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.reg = index; - - DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t et61x251_show_val(struct class_device* cd, char* buf) -{ - struct et61x251_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) { - mutex_unlock(&et61x251_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t -et61x251_store_val(struct class_device* cd, const char* buf, size_t len) -{ - struct et61x251_device* cam; - u8 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - value = et61x251_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&et61x251_sysfs_lock); - return -EINVAL; - } - - err = et61x251_write_reg(cam, value, cam->sysfs.reg); - if (err) { - mutex_unlock(&et61x251_sysfs_lock); - return -EIO; - } - - DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X", - cam->sysfs.reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf) -{ - struct et61x251_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t -et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) -{ - struct et61x251_device* cam; - u8 index; - ssize_t count; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - index = et61x251_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&et61x251_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.i2c_reg = index; - - DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf) -{ - struct et61x251_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENOSYS; - } - - if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { - mutex_unlock(&et61x251_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static ssize_t -et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len) -{ - struct et61x251_device* cam; - u8 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&et61x251_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) { - mutex_unlock(&et61x251_sysfs_lock); - return -ENOSYS; - } - - value = et61x251_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&et61x251_sysfs_lock); - return -EINVAL; - } - - err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value); - if (err) { - mutex_unlock(&et61x251_sysfs_lock); - return -EIO; - } - - DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", - cam->sysfs.i2c_reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&et61x251_sysfs_lock); - - return count; -} - - -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - et61x251_show_reg, et61x251_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - et61x251_show_val, et61x251_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - et61x251_show_i2c_reg, et61x251_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - et61x251_show_i2c_val, et61x251_store_i2c_val); - - -static void et61x251_create_sysfs(struct et61x251_device* cam) -{ - struct video_device *v4ldev = cam->v4ldev; - - video_device_create_file(v4ldev, &class_device_attr_reg); - video_device_create_file(v4ldev, &class_device_attr_val); - if (cam->sensor.sysfs_ops) { - video_device_create_file(v4ldev, &class_device_attr_i2c_reg); - video_device_create_file(v4ldev, &class_device_attr_i2c_val); - } -} -#endif /* CONFIG_VIDEO_ADV_DEBUG */ - -/*****************************************************************************/ - -static int -et61x251_set_pix_format(struct et61x251_device* cam, - struct v4l2_pix_format* pix) -{ - int r, err = 0; - - if ((r = et61x251_read_reg(cam, 0x12)) < 0) - err += r; - if (pix->pixelformat == V4L2_PIX_FMT_ET61X251) - err += et61x251_write_reg(cam, r & 0xfd, 0x12); - else - err += et61x251_write_reg(cam, r | 0x02, 0x12); - - return err ? -EIO : 0; -} - - -static int -et61x251_set_compression(struct et61x251_device* cam, - struct v4l2_jpegcompression* compression) -{ - int r, err = 0; - - if ((r = et61x251_read_reg(cam, 0x12)) < 0) - err += r; - if (compression->quality == 0) - err += et61x251_write_reg(cam, r & 0xfb, 0x12); - else - err += et61x251_write_reg(cam, r | 0x04, 0x12); - - return err ? -EIO : 0; -} - - -static int et61x251_set_scale(struct et61x251_device* cam, u8 scale) -{ - int r = 0, err = 0; - - r = et61x251_read_reg(cam, 0x12); - if (r < 0) - err += r; - - if (scale == 1) - err += et61x251_write_reg(cam, r & ~0x01, 0x12); - else if (scale == 2) - err += et61x251_write_reg(cam, r | 0x01, 0x12); - - if (err) - return -EIO; - - PDBGG("Scaling factor: %u", scale); - - return 0; -} - - -static int -et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect) -{ - struct et61x251_sensor* s = &cam->sensor; - u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left + - s->active_pixel.left), - fmw_sy = (u16)(rect->top - s->cropcap.bounds.top + - s->active_pixel.top), - fmw_length = (u16)(rect->width), - fmw_height = (u16)(rect->height); - int err = 0; - - err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69); - err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a); - err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b); - err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c); - err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6) - | ((fmw_length & 0x300) >> 4) - | ((fmw_height & 0x300) >> 2), 0x6d); - if (err) - return -EIO; - - PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u", - fmw_sx, fmw_sy, fmw_length, fmw_height); - - return 0; -} - - -static int et61x251_init(struct et61x251_device* cam) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - struct v4l2_queryctrl *qctrl; - struct v4l2_rect* rect; - u8 i = 0; - int err = 0; - - if (!(cam->state & DEV_INITIALIZED)) { - init_waitqueue_head(&cam->open); - qctrl = s->qctrl; - rect = &(s->cropcap.defrect); - cam->compression.quality = ET61X251_COMPRESSION_QUALITY; - } else { /* use current values */ - qctrl = s->_qctrl; - rect = &(s->_rect); - } - - err += et61x251_set_scale(cam, rect->width / s->pix_format.width); - err += et61x251_set_crop(cam, rect); - if (err) - return err; - - if (s->init) { - err = s->init(cam); - if (err) { - DBG(3, "Sensor initialization failed"); - return err; - } - } - - err += et61x251_set_compression(cam, &cam->compression); - err += et61x251_set_pix_format(cam, &s->pix_format); - if (s->set_pix_format) - err += s->set_pix_format(cam, &s->pix_format); - if (err) - return err; - - if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251) - DBG(3, "Compressed video format is active, quality %d", - cam->compression.quality); - else - DBG(3, "Uncompressed video format is active"); - - if (s->set_crop) - if ((err = s->set_crop(cam, rect))) { - DBG(3, "set_crop() failed"); - return err; - } - - if (s->set_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (s->qctrl[i].id != 0 && - !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl.id = s->qctrl[i].id; - ctrl.value = qctrl[i].default_value; - err = s->set_ctrl(cam, &ctrl); - if (err) { - DBG(3, "Set %s control failed", - s->qctrl[i].name); - return err; - } - DBG(3, "Image sensor supports '%s' control", - s->qctrl[i].name); - } - } - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->fileop_mutex); - spin_lock_init(&cam->queue_lock); - init_waitqueue_head(&cam->wait_frame); - init_waitqueue_head(&cam->wait_stream); - cam->nreadbuffers = 2; - memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); - memcpy(&(s->_rect), &(s->cropcap.defrect), - sizeof(struct v4l2_rect)); - cam->state |= DEV_INITIALIZED; - } - - DBG(2, "Initialization succeeded"); - return 0; -} - - -static void et61x251_release_resources(struct et61x251_device* cam) -{ - mutex_lock(&et61x251_sysfs_lock); - - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); - video_set_drvdata(cam->v4ldev, NULL); - video_unregister_device(cam->v4ldev); - - usb_put_dev(cam->usbdev); - - mutex_unlock(&et61x251_sysfs_lock); - - kfree(cam->control_buffer); -} - -/*****************************************************************************/ - -static int et61x251_open(struct inode* inode, struct file* filp) -{ - struct et61x251_device* cam; - int err = 0; - - /* - This is the only safe way to prevent race conditions with - disconnect - */ - if (!down_read_trylock(&et61x251_disconnect)) - return -ERESTARTSYS; - - cam = video_get_drvdata(video_devdata(filp)); - - if (mutex_lock_interruptible(&cam->dev_mutex)) { - up_read(&et61x251_disconnect); - return -ERESTARTSYS; - } - - if (cam->users) { - DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); - if ((filp->f_flags & O_NONBLOCK) || - (filp->f_flags & O_NDELAY)) { - err = -EWOULDBLOCK; - goto out; - } - mutex_unlock(&cam->dev_mutex); - err = wait_event_interruptible_exclusive(cam->open, - cam->state & DEV_DISCONNECTED - || !cam->users); - if (err) { - up_read(&et61x251_disconnect); - return err; - } - if (cam->state & DEV_DISCONNECTED) { - up_read(&et61x251_disconnect); - return -ENODEV; - } - mutex_lock(&cam->dev_mutex); - } - - - if (cam->state & DEV_MISCONFIGURED) { - err = et61x251_init(cam); - if (err) { - DBG(1, "Initialization failed again. " - "I will retry on next open()."); - goto out; - } - cam->state &= ~DEV_MISCONFIGURED; - } - - if ((err = et61x251_start_transfer(cam))) - goto out; - - filp->private_data = cam; - cam->users++; - cam->io = IO_NONE; - cam->stream = STREAM_OFF; - cam->nbuffers = 0; - cam->frame_count = 0; - et61x251_empty_framequeues(cam); - - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); - -out: - mutex_unlock(&cam->dev_mutex); - up_read(&et61x251_disconnect); - return err; -} - - -static int et61x251_release(struct inode* inode, struct file* filp) -{ - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - - mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ - - et61x251_stop_transfer(cam); - - et61x251_release_buffers(cam); - - if (cam->state & DEV_DISCONNECTED) { - et61x251_release_resources(cam); - mutex_unlock(&cam->dev_mutex); - kfree(cam); - return 0; - } - - cam->users--; - wake_up_interruptible_nr(&cam->open, 1); - - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - - mutex_unlock(&cam->dev_mutex); - - return 0; -} - - -static ssize_t -et61x251_read(struct file* filp, char __user * buf, - size_t count, loff_t* f_pos) -{ - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - struct et61x251_frame_t* f, * i; - unsigned long lock_flags; - long timeout; - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io == IO_MMAP) { - DBG(3, "Close and open the device again to choose the read " - "method"); - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - if (cam->io == IO_NONE) { - if (!et61x251_request_buffers(cam, cam->nreadbuffers, - IO_READ)) { - DBG(1, "read() failed, not enough memory"); - mutex_unlock(&cam->fileop_mutex); - return -ENOMEM; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (list_empty(&cam->inqueue)) { - if (!list_empty(&cam->outqueue)) - et61x251_empty_framequeues(cam); - et61x251_queue_unusedframes(cam); - } - - if (!count) { - mutex_unlock(&cam->fileop_mutex); - return 0; - } - - if (list_empty(&cam->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) { - mutex_unlock(&cam->fileop_mutex); - return timeout; - } - if (cam->state & DEV_DISCONNECTED) { - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - if (!timeout || (cam->state & DEV_MISCONFIGURED)) { - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - } - - f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame); - - if (count > f->buf.bytesused) - count = f->buf.bytesused; - - if (copy_to_user(buf, f->bufmem, count)) { - err = -EFAULT; - goto exit; - } - *f_pos += count; - -exit: - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(i, &cam->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - et61x251_queue_unusedframes(cam); - - PDBGG("Frame #%lu, bytes read: %zu", - (unsigned long)f->buf.index, count); - - mutex_unlock(&cam->fileop_mutex); - - return err ? err : count; -} - - -static unsigned int et61x251_poll(struct file *filp, poll_table *wait) -{ - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - struct et61x251_frame_t* f; - unsigned long lock_flags; - unsigned int mask = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return POLLERR; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - goto error; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - goto error; - } - - if (cam->io == IO_NONE) { - if (!et61x251_request_buffers(cam, cam->nreadbuffers, - IO_READ)) { - DBG(1, "poll() failed, not enough memory"); - goto error; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (cam->io == IO_READ) { - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(f, &cam->outqueue, frame) - f->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - et61x251_queue_unusedframes(cam); - } - - poll_wait(filp, &cam->wait_frame, wait); - - if (!list_empty(&cam->outqueue)) - mask |= POLLIN | POLLRDNORM; - - mutex_unlock(&cam->fileop_mutex); - - return mask; - -error: - mutex_unlock(&cam->fileop_mutex); - return POLLERR; -} - - -static void et61x251_vm_open(struct vm_area_struct* vma) -{ - struct et61x251_frame_t* f = vma->vm_private_data; - f->vma_use_count++; -} - - -static void et61x251_vm_close(struct vm_area_struct* vma) -{ - /* NOTE: buffers are not freed here */ - struct et61x251_frame_t* f = vma->vm_private_data; - f->vma_use_count--; -} - - -static struct vm_operations_struct et61x251_vm_ops = { - .open = et61x251_vm_open, - .close = et61x251_vm_close, -}; - - -static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) -{ - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(cam->frame[0].buf.length)) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) { - if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == cam->nbuffers) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; - - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &et61x251_vm_ops; - vma->vm_private_data = &cam->frame[i]; - - et61x251_vm_open(vma); - - mutex_unlock(&cam->fileop_mutex); - - return 0; -} - -/*****************************************************************************/ - -static int -et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_capability cap = { - .driver = "et61x251", - .version = ET61X251_MODULE_VERSION_CODE, - .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING, - }; - - strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); - if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, - sizeof(cap.bus_info)); - - if (copy_to_user(arg, &cap, sizeof(cap))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_input i; - - if (copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - if (i.index) - return -EINVAL; - - memset(&i, 0, sizeof(i)); - strcpy(i.name, "Camera"); - i.type = V4L2_INPUT_TYPE_CAMERA; - - if (copy_to_user(arg, &i, sizeof(i))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg) -{ - int index = 0; - - if (copy_to_user(arg, &index, sizeof(index))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg) -{ - int index; - - if (copy_from_user(&index, arg, sizeof(index))) - return -EFAULT; - - if (index != 0) - return -EINVAL; - - return 0; -} - - -static int -et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_queryctrl qc; - u8 i; - - if (copy_from_user(&qc, arg, sizeof(qc))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (qc.id && qc.id == s->qctrl[i].id) { - memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); - if (copy_to_user(arg, &qc, sizeof(qc))) - return -EFAULT; - return 0; - } - - return -EINVAL; -} - - -static int -et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - int err = 0; - u8 i; - - if (!s->get_ctrl && !s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - if (!s->get_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id == s->qctrl[i].id) { - ctrl.value = s->_qctrl[i].default_value; - goto exit; - } - return -EINVAL; - } else - err = s->get_ctrl(cam, &ctrl); - -exit: - if (copy_to_user(arg, &ctrl, sizeof(ctrl))) - return -EFAULT; - - return err; -} - - -static int -et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - u8 i; - int err = 0; - - if (!s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id == s->qctrl[i].id) { - if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) - return -EINVAL; - if (ctrl.value < s->qctrl[i].minimum || - ctrl.value > s->qctrl[i].maximum) - return -ERANGE; - ctrl.value -= ctrl.value % s->qctrl[i].step; - break; - } - - if ((err = s->set_ctrl(cam, &ctrl))) - return err; - - s->_qctrl[i].default_value = ctrl.value; - - return 0; -} - - -static int -et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_cropcap* cc = &(cam->sensor.cropcap); - - cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cc->pixelaspect.numerator = 1; - cc->pixelaspect.denominator = 1; - - if (copy_to_user(arg, cc, sizeof(*cc))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_crop crop = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - }; - - memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); - - if (copy_to_user(arg, &crop, sizeof(crop))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_crop crop; - struct v4l2_rect* rect; - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_pix_format* pix_format = &(s->pix_format); - u8 scale; - const enum et61x251_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&crop, arg, sizeof(crop))) - return -EFAULT; - - rect = &(crop.c); - - if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_CROP failed. " - "Unmap the buffers first."); - return -EINVAL; - } - - /* Preserve R,G or B origin */ - rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; - rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; - - if (rect->width < 4) - rect->width = 4; - if (rect->height < 4) - rect->height = 4; - if (rect->width > bounds->width) - rect->width = bounds->width; - if (rect->height > bounds->height) - rect->height = bounds->height; - if (rect->left < bounds->left) - rect->left = bounds->left; - if (rect->top < bounds->top) - rect->top = bounds->top; - if (rect->left + rect->width > bounds->left + bounds->width) - rect->left = bounds->left+bounds->width - rect->width; - if (rect->top + rect->height > bounds->top + bounds->height) - rect->top = bounds->top+bounds->height - rect->height; - - rect->width &= ~3L; - rect->height &= ~3L; - - if (ET61X251_PRESERVE_IMGSCALE) { - /* Calculate the actual scaling factor */ - u32 a, b; - a = rect->width * rect->height; - b = pix_format->width * pix_format->height; - scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; - } else - scale = 1; - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &crop, sizeof(crop))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - et61x251_release_buffers(cam); - - err = et61x251_set_crop(cam, rect); - if (s->set_crop) - err += s->set_crop(cam, rect); - err += et61x251_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - s->pix_format.width = rect->width/scale; - s->pix_format.height = rect->height/scale; - memcpy(&(s->_rect), rect, sizeof(*rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -ENOMEM; - } - - if (cam->io == IO_READ) - et61x251_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - et61x251_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_fmtdesc fmtd; - - if (copy_from_user(&fmtd, arg, sizeof(fmtd))) - return -EFAULT; - - if (fmtd.index == 0) { - strcpy(fmtd.description, "bayer rgb"); - fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; - } else if (fmtd.index == 1) { - strcpy(fmtd.description, "compressed"); - fmtd.pixelformat = V4L2_PIX_FMT_ET61X251; - fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; - } else - return -EINVAL; - - fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); - - if (copy_to_user(arg, &fmtd, sizeof(fmtd))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251) - ? 0 : (pfmt->width * pfmt->priv) / 8; - pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); - pfmt->field = V4L2_FIELD_NONE; - memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); - - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, - void __user * arg) -{ - struct et61x251_sensor* s = &cam->sensor; - struct v4l2_format format; - struct v4l2_pix_format* pix; - struct v4l2_pix_format* pfmt = &(s->pix_format); - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_rect rect; - u8 scale; - const enum et61x251_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - pix = &(format.fmt.pix); - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memcpy(&rect, &(s->_rect), sizeof(rect)); - - { /* calculate the actual scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; - } - - rect.width = scale * pix->width; - rect.height = scale * pix->height; - - if (rect.width < 4) - rect.width = 4; - if (rect.height < 4) - rect.height = 4; - if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left + bounds->width - rect.left; - if (rect.height > bounds->top + bounds->height - rect.top) - rect.height = bounds->top + bounds->height - rect.top; - - rect.width &= ~3L; - rect.height &= ~3L; - - { /* adjust the scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1; - } - - pix->width = rect.width / scale; - pix->height = rect.height / scale; - - if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; - pix->priv = pfmt->priv; /* bpp */ - pix->colorspace = pfmt->colorspace; - pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) - ? 0 : (pix->width * pix->priv) / 8; - pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); - pix->field = V4L2_FIELD_NONE; - - if (cmd == VIDIOC_TRY_FMT) { - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - return 0; - } - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_FMT failed. " - "Unmap the buffers first."); - return -EINVAL; - } - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &format, sizeof(format))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - et61x251_release_buffers(cam); - - err += et61x251_set_pix_format(cam, pix); - err += et61x251_set_crop(cam, &rect); - if (s->set_pix_format) - err += s->set_pix_format(cam, pix); - if (s->set_crop) - err += s->set_crop(cam, &rect); - err += et61x251_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - memcpy(pfmt, pix, sizeof(*pix)); - memcpy(&(s->_rect), &rect, sizeof(rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -ENOMEM; - } - - if (cam->io == IO_READ) - et61x251_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - et61x251_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg) -{ - if (copy_to_user(arg, &cam->compression, - sizeof(cam->compression))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_jpegcompression jc; - const enum et61x251_stream_state stream = cam->stream; - int err = 0; - - if (copy_from_user(&jc, arg, sizeof(jc))) - return -EFAULT; - - if (jc.quality != 0 && jc.quality != 1) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - err += et61x251_set_compression(cam, &jc); - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " - "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->minor); - return -EIO; - } - - cam->compression.quality = jc.quality; - - cam->stream = stream; - - return 0; -} - - -static int -et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_requestbuffers rb; - u32 i; - int err; - - if (copy_from_user(&rb, arg, sizeof(rb))) - return -EFAULT; - - if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb.memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (cam->io == IO_READ) { - DBG(3, "Close and open the device again to choose the mmap " - "I/O method"); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_REQBUFS failed. " - "Previous buffers are still mapped."); - return -EINVAL; - } - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - et61x251_empty_framequeues(cam); - - et61x251_release_buffers(cam); - if (rb.count) - rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP); - - if (copy_to_user(arg, &rb, sizeof(rb))) { - et61x251_release_buffers(cam); - cam->io = IO_NONE; - return -EFAULT; - } - - cam->io = rb.count ? IO_MMAP : IO_NONE; - - return 0; -} - - -static int -et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); - - if (cam->frame[b.index].vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (cam->frame[b.index].state == F_DONE) - b.flags |= V4L2_BUF_FLAG_DONE; - else if (cam->frame[b.index].state != F_UNUSED) - b.flags |= V4L2_BUF_FLAG_QUEUED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - unsigned long lock_flags; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->frame[b.index].state != F_UNUSED) - return -EINVAL; - - cam->frame[b.index].state = F_QUEUED; - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - PDBGG("Frame #%lu queued", (unsigned long)b.index); - - return 0; -} - - -static int -et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp, - void __user * arg) -{ - struct v4l2_buffer b; - struct et61x251_frame_t *f; - unsigned long lock_flags; - long timeout; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->outqueue)) { - if (cam->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) - return timeout; - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - if (!timeout || (cam->state & DEV_MISCONFIGURED)) - return -EIO; - } - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame); - list_del(cam->outqueue.next); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - f->state = F_UNUSED; - - memcpy(&b, &f->buf, sizeof(b)); - if (f->vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); - - return 0; -} - - -static int -et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg) -{ - int type; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->inqueue)) - return -EINVAL; - - cam->stream = STREAM_ON; - - DBG(3, "Stream on"); - - return 0; -} - - -static int -et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg) -{ - int type, err; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = et61x251_stream_interrupt(cam))) - return err; - - et61x251_empty_framequeues(cam); - - DBG(3, "Stream off"); - - return 0; -} - - -static int -et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - return 0; -} - - -static int -et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - - if (sp.parm.capture.readbuffers == 0) - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES) - sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - cam->nreadbuffers = sp.parm.capture.readbuffers; - - return 0; -} - - -static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp, - unsigned int cmd, void __user * arg) -{ - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - - switch (cmd) { - - case VIDIOC_QUERYCAP: - return et61x251_vidioc_querycap(cam, arg); - - case VIDIOC_ENUMINPUT: - return et61x251_vidioc_enuminput(cam, arg); - - case VIDIOC_G_INPUT: - return et61x251_vidioc_g_input(cam, arg); - - case VIDIOC_S_INPUT: - return et61x251_vidioc_s_input(cam, arg); - - case VIDIOC_QUERYCTRL: - return et61x251_vidioc_query_ctrl(cam, arg); - - case VIDIOC_G_CTRL: - return et61x251_vidioc_g_ctrl(cam, arg); - - case VIDIOC_S_CTRL_OLD: - case VIDIOC_S_CTRL: - return et61x251_vidioc_s_ctrl(cam, arg); - - case VIDIOC_CROPCAP_OLD: - case VIDIOC_CROPCAP: - return et61x251_vidioc_cropcap(cam, arg); - - case VIDIOC_G_CROP: - return et61x251_vidioc_g_crop(cam, arg); - - case VIDIOC_S_CROP: - return et61x251_vidioc_s_crop(cam, arg); - - case VIDIOC_ENUM_FMT: - return et61x251_vidioc_enum_fmt(cam, arg); - - case VIDIOC_G_FMT: - return et61x251_vidioc_g_fmt(cam, arg); - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - return et61x251_vidioc_try_s_fmt(cam, cmd, arg); - - case VIDIOC_G_JPEGCOMP: - return et61x251_vidioc_g_jpegcomp(cam, arg); - - case VIDIOC_S_JPEGCOMP: - return et61x251_vidioc_s_jpegcomp(cam, arg); - - case VIDIOC_REQBUFS: - return et61x251_vidioc_reqbufs(cam, arg); - - case VIDIOC_QUERYBUF: - return et61x251_vidioc_querybuf(cam, arg); - - case VIDIOC_QBUF: - return et61x251_vidioc_qbuf(cam, arg); - - case VIDIOC_DQBUF: - return et61x251_vidioc_dqbuf(cam, filp, arg); - - case VIDIOC_STREAMON: - return et61x251_vidioc_streamon(cam, arg); - - case VIDIOC_STREAMOFF: - return et61x251_vidioc_streamoff(cam, arg); - - case VIDIOC_G_PARM: - return et61x251_vidioc_g_parm(cam, arg); - - case VIDIOC_S_PARM_OLD: - case VIDIOC_S_PARM: - return et61x251_vidioc_s_parm(cam, arg); - - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_QUERYSTD: - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYMENU: - return -EINVAL; - - default: - return -EINVAL; - - } -} - - -static int et61x251_ioctl(struct inode* inode, struct file* filp, - unsigned int cmd, unsigned long arg) -{ - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - V4LDBG(3, "et61x251", cmd); - - err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); - - mutex_unlock(&cam->fileop_mutex); - - return err; -} - - -static struct file_operations et61x251_fops = { - .owner = THIS_MODULE, - .open = et61x251_open, - .release = et61x251_release, - .ioctl = et61x251_ioctl, - .read = et61x251_read, - .poll = et61x251_poll, - .mmap = et61x251_mmap, - .llseek = no_llseek, -}; - -/*****************************************************************************/ - -/* It exists a single interface only. We do not need to validate anything. */ -static int -et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct et61x251_device* cam; - static unsigned int dev_nr = 0; - unsigned int i; - int err = 0; - - if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL))) - return -ENOMEM; - - cam->usbdev = udev; - - if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { - DBG(1, "kmalloc() failed"); - err = -ENOMEM; - goto fail; - } - - if (!(cam->v4ldev = video_device_alloc())) { - DBG(1, "video_device_alloc() failed"); - err = -ENOMEM; - goto fail; - } - - mutex_init(&cam->dev_mutex); - - DBG(2, "ET61X[12]51 PC Camera Controller detected " - "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); - - for (i = 0; et61x251_sensor_table[i]; i++) { - err = et61x251_sensor_table[i](cam); - if (!err) - break; - } - - if (!err) - DBG(2, "%s image sensor detected", cam->sensor.name); - else { - DBG(1, "No supported image sensor detected"); - err = -ENODEV; - goto fail; - } - - if (et61x251_init(cam)) { - DBG(1, "Initialization failed. I will retry on open()."); - cam->state |= DEV_MISCONFIGURED; - } - - strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); - cam->v4ldev->owner = THIS_MODULE; - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; - cam->v4ldev->hardware = 0; - cam->v4ldev->fops = &et61x251_fops; - cam->v4ldev->minor = video_nr[dev_nr]; - cam->v4ldev->release = video_device_release; - video_set_drvdata(cam->v4ldev, cam); - - mutex_lock(&cam->dev_mutex); - - err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, - video_nr[dev_nr]); - if (err) { - DBG(1, "V4L2 device registration failed"); - if (err == -ENFILE && video_nr[dev_nr] == -1) - DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); - goto fail; - } - - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); - - cam->module_param.force_munmap = force_munmap[dev_nr]; - cam->module_param.frame_timeout = frame_timeout[dev_nr]; - - dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; - -#ifdef CONFIG_VIDEO_ADV_DEBUG - et61x251_create_sysfs(cam); - DBG(2, "Optional device control through 'sysfs' interface ready"); -#endif - - usb_set_intfdata(intf, cam); - - mutex_unlock(&cam->dev_mutex); - - return 0; - -fail: - if (cam) { - kfree(cam->control_buffer); - if (cam->v4ldev) - video_device_release(cam->v4ldev); - kfree(cam); - } - return err; -} - - -static void et61x251_usb_disconnect(struct usb_interface* intf) -{ - struct et61x251_device* cam = usb_get_intfdata(intf); - - if (!cam) - return; - - down_write(&et61x251_disconnect); - - mutex_lock(&cam->dev_mutex); - - DBG(2, "Disconnecting %s...", cam->v4ldev->name); - - wake_up_interruptible_all(&cam->open); - - if (cam->users) { - DBG(2, "Device /dev/video%d is open! Deregistration and " - "memory deallocation are deferred on close.", - cam->v4ldev->minor); - cam->state |= DEV_MISCONFIGURED; - et61x251_stop_transfer(cam); - cam->state |= DEV_DISCONNECTED; - wake_up_interruptible(&cam->wait_frame); - wake_up(&cam->wait_stream); - usb_get_dev(cam->usbdev); - } else { - cam->state |= DEV_DISCONNECTED; - et61x251_release_resources(cam); - } - - mutex_unlock(&cam->dev_mutex); - - if (!cam->users) - kfree(cam); - - up_write(&et61x251_disconnect); -} - - -static struct usb_driver et61x251_usb_driver = { - .name = "et61x251", - .id_table = et61x251_id_table, - .probe = et61x251_usb_probe, - .disconnect = et61x251_usb_disconnect, -}; - -/*****************************************************************************/ - -static int __init et61x251_module_init(void) -{ - int err = 0; - - KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION); - KDBG(3, ET61X251_MODULE_AUTHOR); - - if ((err = usb_register(&et61x251_usb_driver))) - KDBG(1, "usb_register() failed"); - - return err; -} - - -static void __exit et61x251_module_exit(void) -{ - usb_deregister(&et61x251_usb_driver); -} - - -module_init(et61x251_module_init); -module_exit(et61x251_module_exit); diff --git a/drivers/usb/media/et61x251_sensor.h b/drivers/usb/media/et61x251_sensor.h deleted file mode 100644 index 56841ae8a207..000000000000 --- a/drivers/usb/media/et61x251_sensor.h +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************** - * API for image sensors connected to ET61X[12]51 PC Camera Controllers * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _ET61X251_SENSOR_H_ -#define _ET61X251_SENSOR_H_ - -#include -#include -#include -#include -#include -#include - -struct et61x251_device; -struct et61x251_sensor; - -/*****************************************************************************/ - -extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam); - -#define ET61X251_SENSOR_TABLE \ -/* Weak detections must go at the end of the list */ \ -static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \ - &et61x251_probe_tas5130d1b, \ - NULL, \ -}; - -extern struct et61x251_device* -et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id); - -extern void -et61x251_attach_sensor(struct et61x251_device* cam, - struct et61x251_sensor* sensor); - -/*****************************************************************************/ - -extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index); -extern int et61x251_read_reg(struct et61x251_device*, u16 index); -extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value); -extern int et61x251_i2c_read(struct et61x251_device*, u8 address); -extern int et61x251_i2c_try_write(struct et61x251_device*, - struct et61x251_sensor*, u8 address, - u8 value); -extern int et61x251_i2c_try_read(struct et61x251_device*, - struct et61x251_sensor*, u8 address); -extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, - u8 data2, u8 data3, u8 data4, u8 data5, - u8 data6, u8 data7, u8 data8, u8 address); - -/*****************************************************************************/ - -enum et61x251_i2c_sysfs_ops { - ET61X251_I2C_READ = 0x01, - ET61X251_I2C_WRITE = 0x02, -}; - -enum et61x251_i2c_interface { - ET61X251_I2C_2WIRES, - ET61X251_I2C_3WIRES, -}; - -/* Repeat start condition when RSTA is high */ -enum et61x251_i2c_rsta { - ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */ - ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */ -}; - -#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 - -struct et61x251_sensor { - char name[32]; - - enum et61x251_i2c_sysfs_ops sysfs_ops; - - enum et61x251_i2c_interface interface; - u8 i2c_slave_id; - enum et61x251_i2c_rsta rsta; - struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */ - - struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS]; - struct v4l2_cropcap cropcap; - struct v4l2_pix_format pix_format; - - int (*init)(struct et61x251_device* cam); - int (*get_ctrl)(struct et61x251_device* cam, - struct v4l2_control* ctrl); - int (*set_ctrl)(struct et61x251_device* cam, - const struct v4l2_control* ctrl); - int (*set_crop)(struct et61x251_device* cam, - const struct v4l2_rect* rect); - int (*set_pix_format)(struct et61x251_device* cam, - const struct v4l2_pix_format* pix); - - /* Private */ - struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS]; - struct v4l2_rect _rect; -}; - -#endif /* _ET61X251_SENSOR_H_ */ diff --git a/drivers/usb/media/et61x251_tas5130d1b.c b/drivers/usb/media/et61x251_tas5130d1b.c deleted file mode 100644 index 3998d76a307a..000000000000 --- a/drivers/usb/media/et61x251_tas5130d1b.c +++ /dev/null @@ -1,141 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 * - * PC Camera Controllers * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "et61x251_sensor.h" - - -static int tas5130d1b_init(struct et61x251_device* cam) -{ - int err = 0; - - err += et61x251_write_reg(cam, 0x14, 0x01); - err += et61x251_write_reg(cam, 0x1b, 0x02); - err += et61x251_write_reg(cam, 0x02, 0x12); - err += et61x251_write_reg(cam, 0x0e, 0x60); - err += et61x251_write_reg(cam, 0x80, 0x61); - err += et61x251_write_reg(cam, 0xf0, 0x62); - err += et61x251_write_reg(cam, 0x03, 0x63); - err += et61x251_write_reg(cam, 0x14, 0x64); - err += et61x251_write_reg(cam, 0xf4, 0x65); - err += et61x251_write_reg(cam, 0x01, 0x66); - err += et61x251_write_reg(cam, 0x05, 0x67); - err += et61x251_write_reg(cam, 0x8f, 0x68); - err += et61x251_write_reg(cam, 0x0f, 0x8d); - err += et61x251_write_reg(cam, 0x08, 0x8e); - - return err; -} - - -static int tas5130d1b_set_ctrl(struct et61x251_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += et61x251_i2c_raw_write(cam, 2, 0x20, - 0xf6-ctrl->value, 0, 0, 0, - 0, 0, 0, 0); - break; - case V4L2_CID_EXPOSURE: - err += et61x251_i2c_raw_write(cam, 2, 0x40, - 0x47-ctrl->value, 0, 0, 0, - 0, 0, 0, 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static struct et61x251_sensor tas5130d1b = { - .name = "TAS5130D1B", - .interface = ET61X251_I2C_3WIRES, - .rsta = ET61X251_I2C_RSTA_STOP, - .active_pixel = { - .left = 106, - .top = 13, - }, - .init = &tas5130d1b_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xf6, - .step = 0x02, - .default_value = 0x0d, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x47, - .step = 0x01, - .default_value = 0x23, - .flags = 0, - }, - }, - .set_ctrl = &tas5130d1b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, -}; - - -int et61x251_probe_tas5130d1b(struct et61x251_device* cam) -{ - const struct usb_device_id tas5130d1b_id_table[] = { - { USB_DEVICE(0x102c, 0x6251), }, - { } - }; - - /* Sensor detection is based on USB pid/vid */ - if (!et61x251_match_id(cam, tas5130d1b_id_table)) - return -ENODEV; - - et61x251_attach_sensor(cam, &tas5130d1b); - - return 0; -} diff --git a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c deleted file mode 100644 index a42c22294124..000000000000 --- a/drivers/usb/media/ibmcam.c +++ /dev/null @@ -1,3932 +0,0 @@ -/* - * USB IBM C-It Video Camera driver - * - * Supports Xirlink C-It Video Camera, IBM PC Camera, - * IBM NetCamera and Veo Stingray. - * - * This driver is based on earlier work of: - * - * (C) Copyright 1999 Johannes Erdfelt - * (C) Copyright 1999 Randy Dunlap - * - * 5/24/00 Removed optional (and unnecessary) locking of the driver while - * the device remains plugged in. Corrected race conditions in ibmcam_open - * and ibmcam_probe() routines using this as a guideline: - */ - -#include -#include -#include -#include - -#include "usbvideo.h" - -#define IBMCAM_VENDOR_ID 0x0545 -#define IBMCAM_PRODUCT_ID 0x8080 -#define NETCAM_PRODUCT_ID 0x8002 /* IBM NetCamera, close to model 2 */ -#define VEO_800C_PRODUCT_ID 0x800C /* Veo Stingray, repackaged Model 2 */ -#define VEO_800D_PRODUCT_ID 0x800D /* Veo Stingray, repackaged Model 4 */ - -#define MAX_IBMCAM 4 /* How many devices we allow to connect */ -#define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure */ - -/* Header signatures */ - -/* Model 1 header: 00 FF 00 xx */ -#define HDRSIG_MODEL1_128x96 0x06 /* U Y V Y ... */ -#define HDRSIG_MODEL1_176x144 0x0e /* U Y V Y ... */ -#define HDRSIG_MODEL1_352x288 0x00 /* V Y U Y ... */ - -#define IBMCAM_MODEL_1 1 /* XVP-501, 3 interfaces, rev. 0.02 */ -#define IBMCAM_MODEL_2 2 /* KSX-X9903, 2 interfaces, rev. 3.0a */ -#define IBMCAM_MODEL_3 3 /* KSX-X9902, 2 interfaces, rev. 3.01 */ -#define IBMCAM_MODEL_4 4 /* IBM NetCamera, 0545/8002/3.0a */ - -/* Video sizes supported */ -#define VIDEOSIZE_128x96 VIDEOSIZE(128, 96) -#define VIDEOSIZE_176x144 VIDEOSIZE(176,144) -#define VIDEOSIZE_352x288 VIDEOSIZE(352,288) -#define VIDEOSIZE_320x240 VIDEOSIZE(320,240) -#define VIDEOSIZE_352x240 VIDEOSIZE(352,240) -#define VIDEOSIZE_640x480 VIDEOSIZE(640,480) -#define VIDEOSIZE_160x120 VIDEOSIZE(160,120) - -/* Video sizes supported */ -enum { - SIZE_128x96 = 0, - SIZE_160x120, - SIZE_176x144, - SIZE_320x240, - SIZE_352x240, - SIZE_352x288, - SIZE_640x480, - /* Add/remove/rearrange items before this line */ - SIZE_LastItem -}; - -/* - * This structure lives in uvd->user field. - */ -typedef struct { - int initialized; /* Had we already sent init sequence? */ - int camera_model; /* What type of IBM camera we got? */ - int has_hdr; -} ibmcam_t; -#define IBMCAM_T(uvd) ((ibmcam_t *)((uvd)->user_data)) - -static struct usbvideo *cams; - -static int debug; - -static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ - -static const int min_canvasWidth = 8; -static const int min_canvasHeight = 4; - -static int lighting = 1; /* Medium */ - -#define SHARPNESS_MIN 0 -#define SHARPNESS_MAX 6 -static int sharpness = 4; /* Low noise, good details */ - -#define FRAMERATE_MIN 0 -#define FRAMERATE_MAX 6 -static int framerate = -1; - -static int size = SIZE_352x288; - -/* - * Here we define several initialization variables. They may - * be used to automatically set color, hue, brightness and - * contrast to desired values. This is particularly useful in - * case of webcams (which have no controls and no on-screen - * output) and also when a client V4L software is used that - * does not have some of those controls. In any case it's - * good to have startup values as options. - * - * These values are all in [0..255] range. This simplifies - * operation. Note that actual values of V4L variables may - * be scaled up (as much as << 8). User can see that only - * on overlay output, however, or through a V4L client. - */ -static int init_brightness = 128; -static int init_contrast = 192; -static int init_color = 128; -static int init_hue = 128; -static int hue_correction = 128; - -/* Settings for camera model 2 */ -static int init_model2_rg2 = -1; -static int init_model2_sat = -1; -static int init_model2_yb = -1; - -/* 01.01.08 - Added for RCA video in support -LO */ -/* Settings for camera model 3 */ -static int init_model3_input = 0; - -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -module_param(flags, int, 0); -MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames"); -module_param(framerate, int, 0); -MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); -module_param(lighting, int, 0); -MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light"); -module_param(sharpness, int, 0); -MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)"); -module_param(size, int, 0); -MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)"); -module_param(init_brightness, int, 0); -MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); -module_param(init_contrast, int, 0); -MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); -module_param(init_color, int, 0); -MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); -module_param(init_hue, int, 0); -MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); -module_param(hue_correction, int, 0); -MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); - -module_param(init_model2_rg2, int, 0); -MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)"); -module_param(init_model2_sat, int, 0); -MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)"); -module_param(init_model2_yb, int, 0); -MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)"); - -/* 01.01.08 - Added for RCA video in support -LO */ -module_param(init_model3_input, int, 0); -MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA"); - -MODULE_AUTHOR ("Dmitri"); -MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000"); -MODULE_LICENSE("GPL"); - -/* Still mysterious i2c commands */ -static const unsigned short unknown_88 = 0x0088; -static const unsigned short unknown_89 = 0x0089; -static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 }; -static const unsigned short contrast_14 = 0x0014; -static const unsigned short light_27 = 0x0027; -static const unsigned short sharp_13 = 0x0013; - -/* i2c commands for Model 2 cameras */ -static const unsigned short mod2_brightness = 0x001a; /* $5b .. $ee; default=$5a */ -static const unsigned short mod2_set_framerate = 0x001c; /* 0 (fast).. $1F (slow) */ -static const unsigned short mod2_color_balance_rg2 = 0x001e; /* 0 (red) .. $7F (green) */ -static const unsigned short mod2_saturation = 0x0020; /* 0 (b/w) - $7F (full color) */ -static const unsigned short mod2_color_balance_yb = 0x0022; /* 0..$7F, $50 is about right */ -static const unsigned short mod2_hue = 0x0024; /* 0..$7F, $70 is about right */ -static const unsigned short mod2_sensitivity = 0x0028; /* 0 (min) .. $1F (max) */ - -struct struct_initData { - unsigned char req; - unsigned short value; - unsigned short index; -}; - -/* - * ibmcam_size_to_videosize() - * - * This procedure converts module option 'size' into the actual - * videosize_t that defines the image size in pixels. We need - * simplified 'size' because user wants a simple enumerated list - * of choices, not an infinite set of possibilities. - */ -static videosize_t ibmcam_size_to_videosize(int size) -{ - videosize_t vs = VIDEOSIZE_352x288; - RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1)); - switch (size) { - case SIZE_128x96: - vs = VIDEOSIZE_128x96; - break; - case SIZE_160x120: - vs = VIDEOSIZE_160x120; - break; - case SIZE_176x144: - vs = VIDEOSIZE_176x144; - break; - case SIZE_320x240: - vs = VIDEOSIZE_320x240; - break; - case SIZE_352x240: - vs = VIDEOSIZE_352x240; - break; - case SIZE_352x288: - vs = VIDEOSIZE_352x288; - break; - case SIZE_640x480: - vs = VIDEOSIZE_640x480; - break; - default: - err("size=%d. is not valid", size); - break; - } - return vs; -} - -/* - * ibmcam_find_header() - * - * Locate one of supported header markers in the queue. - * Once found, remove all preceding bytes AND the marker (4 bytes) - * from the data pump queue. Whatever follows must be video lines. - * - * History: - * 1/21/00 Created. - */ -static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */ -{ - struct usbvideo_frame *frame; - ibmcam_t *icam; - - if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { - err("ibmcam_find_header: Illegal frame %d.", uvd->curframe); - return scan_EndParse; - } - icam = IBMCAM_T(uvd); - assert(icam != NULL); - frame = &uvd->frame[uvd->curframe]; - icam->has_hdr = 0; - switch (icam->camera_model) { - case IBMCAM_MODEL_1: - { - const int marker_len = 4; - while (RingQueue_GetLength(&uvd->dp) >= marker_len) { - if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && - (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && - (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00)) - { -#if 0 /* This code helps to detect new frame markers */ - info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3)); -#endif - frame->header = RING_QUEUE_PEEK(&uvd->dp, 3); - if ((frame->header == HDRSIG_MODEL1_128x96) || - (frame->header == HDRSIG_MODEL1_176x144) || - (frame->header == HDRSIG_MODEL1_352x288)) - { -#if 0 - info("Header found."); -#endif - RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); - icam->has_hdr = 1; - break; - } - } - /* If we are still here then this doesn't look like a header */ - RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); - } - break; - } - case IBMCAM_MODEL_2: -case IBMCAM_MODEL_4: - { - int marker_len = 0; - switch (uvd->videosize) { - case VIDEOSIZE_176x144: - marker_len = 10; - break; - default: - marker_len = 2; - break; - } - while (RingQueue_GetLength(&uvd->dp) >= marker_len) { - if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && - (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF)) - { -#if 0 - info("Header found."); -#endif - RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); - icam->has_hdr = 1; - frame->header = HDRSIG_MODEL1_176x144; - break; - } - /* If we are still here then this doesn't look like a header */ - RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); - } - break; - } - case IBMCAM_MODEL_3: - { /* - * Headers: (one precedes every frame). nc=no compression, - * bq=best quality bf=best frame rate. - * - * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf } - * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf } - * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf } - * - * Bytes '00 FF' seem to indicate header. Other two bytes - * encode the frame type. This is a set of bit fields that - * encode image size, compression type etc. These fields - * do NOT contain frame number because all frames carry - * the same header. - */ - const int marker_len = 4; - while (RingQueue_GetLength(&uvd->dp) >= marker_len) { - if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && - (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) && - (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF)) - { - /* - * Combine 2 bytes of frame type into one - * easy to use value - */ - unsigned long byte3, byte4; - - byte3 = RING_QUEUE_PEEK(&uvd->dp, 2); - byte4 = RING_QUEUE_PEEK(&uvd->dp, 3); - frame->header = (byte3 << 8) | byte4; -#if 0 - info("Header found."); -#endif - RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len); - icam->has_hdr = 1; - break; - } - /* If we are still here then this doesn't look like a header */ - RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); - } - break; - } - default: - break; - } - if (!icam->has_hdr) { - if (uvd->debug > 2) - info("Skipping frame, no header"); - return scan_EndParse; - } - - /* Header found */ - icam->has_hdr = 1; - uvd->stats.header_count++; - frame->scanstate = ScanState_Lines; - frame->curline = 0; - - if (flags & FLAGS_FORCE_TESTPATTERN) { - usbvideo_TestPattern(uvd, 1, 1); - return scan_NextFrame; - } - return scan_Continue; -} - -/* - * ibmcam_parse_lines() - * - * Parse one line (interlaced) from the buffer, put - * decoded RGB value into the current frame buffer - * and add the written number of bytes (RGB) to - * the *pcopylen. - * - * History: - * 21-Jan-2000 Created. - * 12-Oct-2000 Reworked to reflect interlaced nature of the data. - */ -static enum ParseState ibmcam_parse_lines( - struct uvd *uvd, - struct usbvideo_frame *frame, - long *pcopylen) -{ - unsigned char *f; - ibmcam_t *icam; - unsigned int len, scanLength, scanHeight, order_uv, order_yc; - int v4l_linesize; /* V4L line offset */ - const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ - const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ - const int ccm = 128; /* Color correction median - see below */ - int y, u, v, i, frame_done=0, color_corr; - static unsigned char lineBuffer[640*3]; - unsigned const char *chromaLine, *lumaLine; - - assert(uvd != NULL); - assert(frame != NULL); - icam = IBMCAM_T(uvd); - assert(icam != NULL); - color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ - RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); - - v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - - if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) { - /* Model 4 frame markers do not carry image size identification */ - switch (uvd->videosize) { - case VIDEOSIZE_128x96: - case VIDEOSIZE_160x120: - case VIDEOSIZE_176x144: - scanLength = VIDEOSIZE_X(uvd->videosize); - scanHeight = VIDEOSIZE_Y(uvd->videosize); - break; - default: - err("ibmcam_parse_lines: Wrong mode."); - return scan_Out; - } - order_yc = 1; /* order_yc: true=Yc false=cY ('c'=either U or V) */ - order_uv = 1; /* Always true in this algorithm */ - } else { - switch (frame->header) { - case HDRSIG_MODEL1_128x96: - scanLength = 128; - scanHeight = 96; - order_uv = 1; /* U Y V Y ... */ - break; - case HDRSIG_MODEL1_176x144: - scanLength = 176; - scanHeight = 144; - order_uv = 1; /* U Y V Y ... */ - break; - case HDRSIG_MODEL1_352x288: - scanLength = 352; - scanHeight = 288; - order_uv = 0; /* Y V Y V ... */ - break; - default: - err("Unknown header signature 00 FF 00 %02lX", frame->header); - return scan_NextFrame; - } - /* order_yc: true=Yc false=cY ('c'=either U or V) */ - order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2); - } - - len = scanLength * 3; - assert(len <= sizeof(lineBuffer)); - - /* - * Lines are organized this way: - * - * I420: - * ~~~~ - * - * ___________________________________ - * |-----Y-----|---UVUVUV...UVUV-----| \ - * |-----------+---------------------| \ - * |<-- 176 -->|<------ 176*2 ------>| Total 72. lines (interlaced) - * |... ... | ... | / - * |<-- 352 -->|<------ 352*2 ------>| Total 144. lines (interlaced) - * |___________|_____________________| / - * \ \ - * lumaLine chromaLine - */ - - /* Make sure there's enough data for the entire line */ - if (RingQueue_GetLength(&uvd->dp) < len) - return scan_Out; - - /* Suck one line out of the ring queue */ - RingQueue_Dequeue(&uvd->dp, lineBuffer, len); - - /* - * Make sure that our writing into output buffer - * will not exceed the buffer. Mind that we may write - * not into current output scanline but in several after - * it as well (if we enlarge image vertically.) - */ - if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request)) - return scan_NextFrame; - - /* - * Now we are sure that entire line (representing all 'scanLength' - * pixels from the camera) is available in the buffer. We - * start copying the line left-aligned to the V4L buffer. - * If the camera line is shorter then we should pad the V4L - * buffer with something (black) to complete the line. - */ - assert(frame->data != NULL); - f = frame->data + (v4l_linesize * frame->curline); - - /* - * To obtain chrominance data from the 'chromaLine' use this: - * v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]... - * u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]... - * - * Indices must be calculated this way: - * v_index = (i >> 1) << 2; - * u_index = (i >> 1) << 2 + 2; - * - * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1] - */ - lumaLine = lineBuffer; - chromaLine = lineBuffer + scanLength; - for (i = 0; i < VIDEOSIZE_X(frame->request); i++) - { - unsigned char rv, gv, bv; /* RGB components */ - - /* Check for various visual debugging hints (colorized pixels) */ - if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) { - /* - * This is bad and should not happen. This means that - * we somehow overshoot the line and encountered new - * frame! Obviously our camera/V4L frame size is out - * of whack. This cyan dot will help you to figure - * out where exactly the new frame arrived. - */ - if (icam->has_hdr == 1) { - bv = 0; /* Yellow marker */ - gv = 0xFF; - rv = 0xFF; - } else { - bv = 0xFF; /* Cyan marker */ - gv = 0xFF; - rv = 0; - } - icam->has_hdr = 0; - goto make_pixel; - } - - /* - * Check if we are still in range. We may be out of range if our - * V4L canvas is wider or taller than the camera "native" image. - * Then we quickly fill the remainder of the line with zeros to - * make black color and quit the horizontal scanning loop. - */ - if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { - const int j = i * V4L_BYTES_PER_PIXEL; -#if USES_IBMCAM_PUTPIXEL - /* Refresh 'f' because we don't use it much with PUTPIXEL */ - f = frame->data + (v4l_linesize * frame->curline) + j; -#endif - memset(f, 0, v4l_linesize - j); - break; - } - - y = lumaLine[i]; - if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */ - rv = gv = bv = y; - else { - int off_0, off_2; - - off_0 = (i >> 1) << 2; - off_2 = off_0 + 2; - - if (order_yc) { - off_0++; - off_2++; - } - if (!order_uv) { - off_0 += 2; - off_2 -= 2; - } - u = chromaLine[off_0] + hue_corr; - v = chromaLine[off_2] + hue2_corr; - - /* Apply color correction */ - if (color_corr != 0) { - /* Magnify up to 2 times, reduce down to zero saturation */ - u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; - v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; - } - YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); - } - - make_pixel: - /* - * The purpose of creating the pixel here, in one, - * dedicated place is that we may need to make the - * pixel wider and taller than it actually is. This - * may be used if camera generates small frames for - * sake of frame rate (or any other reason.) - * - * The output data consists of B, G, R bytes - * (in this order). - */ -#if USES_IBMCAM_PUTPIXEL - RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); -#else - *f++ = bv; - *f++ = gv; - *f++ = rv; -#endif - /* - * Typically we do not decide within a legitimate frame - * that we want to end the frame. However debugging code - * may detect marker of new frame within the data. Then - * this condition activates. The 'data' pointer is already - * pointing at the new marker, so we'd better leave it as is. - */ - if (frame_done) - break; /* End scanning of lines */ - } - /* - * Account for number of bytes that we wrote into output V4L frame. - * We do it here, after we are done with the scanline, because we - * may fill more than one output scanline if we do vertical - * enlargement. - */ - frame->curline += 2; - if (pcopylen != NULL) - *pcopylen += 2 * v4l_linesize; - frame->deinterlace = Deinterlace_FillOddLines; - - if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request))) - return scan_NextFrame; - else - return scan_Continue; -} - -/* - * ibmcam_model2_320x240_parse_lines() - * - * This procedure deals with a weird RGB format that is produced by IBM - * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175, - * depending on horizontal size of the picture: - * - * <--- 160 or 176 pairs of RA,RB bytes -----> - * *-----------------------------------------* \ - * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx | \ This is pair of horizontal lines, - * |-----+-----+-----+-----+ ... +-----+-----| *- or one interlaced line, total - * | B0 | G0 | B1 | G1 | ... | Bx | Gx | / 120 or 144 such pairs which yield - * |=====+=====+=====+=====+ ... +=====+=====| / 240 or 288 lines after deinterlacing. - * - * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1 - * defines ONE pixel. Therefore this format yields 176x144 "decoded" - * resolution at best. I do not know why camera sends such format - the - * previous model (1) just used interlaced I420 and everyone was happy. - * - * I do not know what is the difference between RAi and RBi bytes. Both - * seemingly represent R component, but slightly vary in value (so that - * the picture looks a bit colored if one or another is used). I use - * them both as R component in attempt to at least partially recover the - * lost resolution. - */ -static enum ParseState ibmcam_model2_320x240_parse_lines( - struct uvd *uvd, - struct usbvideo_frame *frame, - long *pcopylen) -{ - unsigned char *f, *la, *lb; - unsigned int len; - int v4l_linesize; /* V4L line offset */ - int i, j, frame_done=0, color_corr; - int scanLength, scanHeight; - static unsigned char lineBuffer[352*2]; - - switch (uvd->videosize) { - case VIDEOSIZE_320x240: - case VIDEOSIZE_352x240: - case VIDEOSIZE_352x288: - scanLength = VIDEOSIZE_X(uvd->videosize); - scanHeight = VIDEOSIZE_Y(uvd->videosize); - break; - default: - err("ibmcam_model2_320x240_parse_lines: Wrong mode."); - return scan_Out; - } - - color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */ - v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - - len = scanLength * 2; /* See explanation above */ - assert(len <= sizeof(lineBuffer)); - - /* Make sure there's enough data for the entire line */ - if (RingQueue_GetLength(&uvd->dp) < len) - return scan_Out; - - /* Suck one line out of the ring queue */ - RingQueue_Dequeue(&uvd->dp, lineBuffer, len); - - /* - * Make sure that our writing into output buffer - * will not exceed the buffer. Mind that we may write - * not into current output scanline but in several after - * it as well (if we enlarge image vertically.) - */ - if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request)) - return scan_NextFrame; - - la = lineBuffer; - lb = lineBuffer + scanLength; - - /* - * Now we are sure that entire line (representing all - * VIDEOSIZE_X(frame->request) - * pixels from the camera) is available in the scratch buffer. We - * start copying the line left-aligned to the V4L buffer (which - * might be larger - not smaller, hopefully). If the camera - * line is shorter then we should pad the V4L buffer with something - * (black in this case) to complete the line. - */ - f = frame->data + (v4l_linesize * frame->curline); - - /* Fill the 2-line strip */ - for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { - int y, rv, gv, bv; /* RGB components */ - - j = i & (~1); - - /* Check for various visual debugging hints (colorized pixels) */ - if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) { - if (IBMCAM_T(uvd)->has_hdr == 1) { - bv = 0; /* Yellow marker */ - gv = 0xFF; - rv = 0xFF; - } else { - bv = 0xFF; /* Cyan marker */ - gv = 0xFF; - rv = 0; - } - IBMCAM_T(uvd)->has_hdr = 0; - goto make_pixel; - } - - /* - * Check if we are still in range. We may be out of range if our - * V4L canvas is wider or taller than the camera "native" image. - * Then we quickly fill the remainder of the line with zeros to - * make black color and quit the horizontal scanning loop. - */ - if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { - const int j = i * V4L_BYTES_PER_PIXEL; -#if USES_IBMCAM_PUTPIXEL - /* Refresh 'f' because we don't use it much with PUTPIXEL */ - f = frame->data + (v4l_linesize * frame->curline) + j; -#endif - memset(f, 0, v4l_linesize - j); - break; - } - - /* - * Here I use RA and RB components, one per physical pixel. - * This causes fine vertical grid on the picture but may improve - * horizontal resolution. If you prefer replicating, use this: - * rv = la[j + 0]; ... or ... rv = la[j + 1]; - * then the pixel will be replicated. - */ - rv = la[i]; - gv = lb[j + 1]; - bv = lb[j + 0]; - - y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */ - - if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */ - rv = gv = bv = y; - else if (color_corr != 128) { - - /* Calculate difference between color and brightness */ - rv -= y; - gv -= y; - bv -= y; - - /* Scale differences */ - rv = (rv * color_corr) / 128; - gv = (gv * color_corr) / 128; - bv = (bv * color_corr) / 128; - - /* Reapply brightness */ - rv += y; - gv += y; - bv += y; - - /* Watch for overflows */ - RESTRICT_TO_RANGE(rv, 0, 255); - RESTRICT_TO_RANGE(gv, 0, 255); - RESTRICT_TO_RANGE(bv, 0, 255); - } - - make_pixel: - RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); - } - /* - * Account for number of bytes that we wrote into output V4L frame. - * We do it here, after we are done with the scanline, because we - * may fill more than one output scanline if we do vertical - * enlargement. - */ - frame->curline += 2; - *pcopylen += v4l_linesize * 2; - frame->deinterlace = Deinterlace_FillOddLines; - - if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request))) - return scan_NextFrame; - else - return scan_Continue; -} - -static enum ParseState ibmcam_model3_parse_lines( - struct uvd *uvd, - struct usbvideo_frame *frame, - long *pcopylen) -{ - unsigned char *data; - const unsigned char *color; - unsigned int len; - int v4l_linesize; /* V4L line offset */ - const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */ - const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ - const int ccm = 128; /* Color correction median - see below */ - int i, u, v, rw, data_w=0, data_h=0, color_corr; - static unsigned char lineBuffer[640*3]; - - color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ - RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); - - v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - - /* The header tells us what sort of data is in this frame */ - switch (frame->header) { - /* - * Uncompressed modes (that are easy to decode). - */ - case 0x0308: - data_w = 640; - data_h = 480; - break; - case 0x0208: - data_w = 320; - data_h = 240; - break; - case 0x020A: - data_w = 160; - data_h = 120; - break; - /* - * Compressed modes (ViCE - that I don't know how to decode). - */ - case 0x0328: /* 640x480, best quality compression */ - case 0x0368: /* 640x480, best frame rate compression */ - case 0x0228: /* 320x240, best quality compression */ - case 0x0268: /* 320x240, best frame rate compression */ - case 0x02CA: /* 160x120, best quality compression */ - case 0x02EA: /* 160x120, best frame rate compression */ - /* Do nothing with this - not supported */ - err("Unsupported mode $%04lx", frame->header); - return scan_NextFrame; - default: - /* Catch unknown headers, may help in learning new headers */ - err("Strange frame->header=$%08lx", frame->header); - return scan_NextFrame; - } - - /* - * Make sure that our writing into output buffer - * will not exceed the buffer. Note that we may write - * not into current output scanline but in several after - * it as well (if we enlarge image vertically.) - */ - if ((frame->curline + 1) >= data_h) { - if (uvd->debug >= 3) - info("Reached line %d. (frame is done)", frame->curline); - return scan_NextFrame; - } - - /* Make sure there's enough data for the entire line */ - len = 3 * data_w; /* */ - assert(len <= sizeof(lineBuffer)); - - /* Make sure there's enough data for the entire line */ - if (RingQueue_GetLength(&uvd->dp) < len) - return scan_Out; - - /* Suck one line out of the ring queue */ - RingQueue_Dequeue(&uvd->dp, lineBuffer, len); - - data = lineBuffer; - color = data + data_w; /* Point to where color planes begin */ - - /* Bottom-to-top scanning */ - rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1; - RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1); - - for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { - int y, rv, gv, bv; /* RGB components */ - - if (i < data_w) { - y = data[i]; /* Luminosity is the first line */ - - /* Apply static color correction */ - u = color[i*2] + hue_corr; - v = color[i*2 + 1] + hue2_corr; - - /* Apply color correction */ - if (color_corr != 0) { - /* Magnify up to 2 times, reduce down to zero saturation */ - u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; - v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; - } - } else - y = 0, u = v = 128; - - YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); - RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */ - } - frame->deinterlace = Deinterlace_FillEvenLines; - - /* - * Account for number of bytes that we wrote into output V4L frame. - * We do it here, after we are done with the scanline, because we - * may fill more than one output scanline if we do vertical - * enlargement. - */ - frame->curline += 2; - *pcopylen += 2 * v4l_linesize; - - if (frame->curline >= VIDEOSIZE_Y(frame->request)) { - if (uvd->debug >= 3) { - info("All requested lines (%ld.) done.", - VIDEOSIZE_Y(frame->request)); - } - return scan_NextFrame; - } else - return scan_Continue; -} - -/* - * ibmcam_model4_128x96_parse_lines() - * - * This decoder is for one strange data format that is produced by Model 4 - * camera only in 128x96 mode. This is RGB format and here is its description. - * First of all, this is non-interlaced stream, meaning that all scan lines - * are present in the datastream. There are 96 consecutive blocks of data - * that describe all 96 lines of the image. Each block is 5*128 bytes long - * and carries R, G, B components. The format of the block is shown in the - * code below. First 128*2 bytes are interleaved R and G components. Then - * we have a gap (junk data) 64 bytes long. Then follow B and something - * else, also interleaved (this makes another 128*2 bytes). After that - * probably another 64 bytes of junk follow. - * - * History: - * 10-Feb-2001 Created. - */ -static enum ParseState ibmcam_model4_128x96_parse_lines( - struct uvd *uvd, - struct usbvideo_frame *frame, - long *pcopylen) -{ - const unsigned char *data_rv, *data_gv, *data_bv; - unsigned int len; - int i, v4l_linesize; /* V4L line offset */ - const int data_w=128, data_h=96; - static unsigned char lineBuffer[128*5]; - - v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - - /* - * Make sure that our writing into output buffer - * will not exceed the buffer. Note that we may write - * not into current output scanline but in several after - * it as well (if we enlarge image vertically.) - */ - if ((frame->curline + 1) >= data_h) { - if (uvd->debug >= 3) - info("Reached line %d. (frame is done)", frame->curline); - return scan_NextFrame; - } - - /* - * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________ - * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 ---> - */ - - /* Make sure there's enough data for the entire line */ - len = 5 * data_w; - assert(len <= sizeof(lineBuffer)); - - /* Make sure there's enough data for the entire line */ - if (RingQueue_GetLength(&uvd->dp) < len) - return scan_Out; - - /* Suck one line out of the ring queue */ - RingQueue_Dequeue(&uvd->dp, lineBuffer, len); - - data_rv = lineBuffer; - data_gv = lineBuffer + 1; - data_bv = lineBuffer + data_w*2 + data_w/2; - for (i = 0; i < VIDEOSIZE_X(frame->request); i++) { - int rv, gv, bv; /* RGB components */ - if (i < data_w) { - const int j = i * 2; - gv = data_rv[j]; - rv = data_gv[j]; - bv = data_bv[j]; - if (flags & FLAGS_MONOCHROME) { - unsigned long y; - y = rv + gv + bv; - y /= 3; - if (y > 0xFF) - y = 0xFF; - rv = gv = bv = (unsigned char) y; - } - } else { - rv = gv = bv = 0; - } - RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv); - } - frame->deinterlace = Deinterlace_None; - frame->curline++; - *pcopylen += v4l_linesize; - - if (frame->curline >= VIDEOSIZE_Y(frame->request)) { - if (uvd->debug >= 3) { - info("All requested lines (%ld.) done.", - VIDEOSIZE_Y(frame->request)); - } - return scan_NextFrame; - } else - return scan_Continue; -} - -/* - * ibmcam_ProcessIsocData() - * - * Generic routine to parse the ring queue data. It employs either - * ibmcam_find_header() or ibmcam_parse_lines() to do most - * of work. - * - * History: - * 1/21/00 Created. - */ -static void ibmcam_ProcessIsocData(struct uvd *uvd, - struct usbvideo_frame *frame) -{ - enum ParseState newstate; - long copylen = 0; - int mod = IBMCAM_T(uvd)->camera_model; - - while (1) { - newstate = scan_Out; - if (RingQueue_GetLength(&uvd->dp) > 0) { - if (frame->scanstate == ScanState_Scanning) { - newstate = ibmcam_find_header(uvd); - } else if (frame->scanstate == ScanState_Lines) { - if ((mod == IBMCAM_MODEL_2) && - ((uvd->videosize == VIDEOSIZE_352x288) || - (uvd->videosize == VIDEOSIZE_320x240) || - (uvd->videosize == VIDEOSIZE_352x240))) - { - newstate = ibmcam_model2_320x240_parse_lines( - uvd, frame, ©len); - } else if (mod == IBMCAM_MODEL_4) { - /* - * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB) - * for 320x240 and above; 160x120 and 176x144 uses Model 1 - * decoder (YUV), and 128x96 mode uses ??? - */ - if ((uvd->videosize == VIDEOSIZE_352x288) || - (uvd->videosize == VIDEOSIZE_320x240) || - (uvd->videosize == VIDEOSIZE_352x240)) - { - newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, ©len); - } else if (uvd->videosize == VIDEOSIZE_128x96) { - newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, ©len); - } else { - newstate = ibmcam_parse_lines(uvd, frame, ©len); - } - } else if (mod == IBMCAM_MODEL_3) { - newstate = ibmcam_model3_parse_lines(uvd, frame, ©len); - } else { - newstate = ibmcam_parse_lines(uvd, frame, ©len); - } - } - } - if (newstate == scan_Continue) - continue; - else if ((newstate == scan_NextFrame) || (newstate == scan_Out)) - break; - else - return; /* scan_EndParse */ - } - - if (newstate == scan_NextFrame) { - frame->frameState = FrameState_Done; - uvd->curframe = -1; - uvd->stats.frame_num++; - if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) { - /* Need software contrast adjustment for those cameras */ - frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST; - } - } - - /* Update the frame's uncompressed length. */ - frame->seqRead_Length += copylen; - -#if 0 - { - static unsigned char j=0; - memset(frame->data, j++, uvd->max_frame_size); - frame->frameState = FrameState_Ready; - } -#endif -} - -/* - * ibmcam_veio() - * - * History: - * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. - */ -static int ibmcam_veio( - struct uvd *uvd, - unsigned char req, - unsigned short value, - unsigned short index) -{ - static const char proc[] = "ibmcam_veio"; - unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; - int i; - - if (!CAMERA_IS_OPERATIONAL(uvd)) - return 0; - - if (req == 1) { - i = usb_control_msg( - uvd->dev, - usb_rcvctrlpipe(uvd->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, - value, - index, - cp, - sizeof(cp), - 1000); -#if 0 - info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " - "(req=$%02x val=$%04x ind=$%04x)", - cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], - req, value, index); -#endif - } else { - i = usb_control_msg( - uvd->dev, - usb_sndctrlpipe(uvd->dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, - value, - index, - NULL, - 0, - 1000); - } - if (i < 0) { - err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", - proc, i); - uvd->last_error = i; - } - return i; -} - -/* - * ibmcam_calculate_fps() - * - * This procedure roughly calculates the real frame rate based - * on FPS code (framerate=NNN option). Actual FPS differs - * slightly depending on lighting conditions, so that actual frame - * rate is determined by the camera. Since I don't know how to ask - * the camera what FPS is now I have to use the FPS code instead. - * - * The FPS code is in range [0..6], 0 is slowest, 6 is fastest. - * Corresponding real FPS should be in range [3..30] frames per second. - * The conversion formula is obvious: - * - * real_fps = 3 + (fps_code * 4.5) - * - * History: - * 1/18/00 Created. - */ -static int ibmcam_calculate_fps(struct uvd *uvd) -{ - return 3 + framerate*4 + framerate/2; -} - -/* - * ibmcam_send_FF_04_02() - * - * This procedure sends magic 3-command prefix to the camera. - * The purpose of this prefix is not known. - * - * History: - * 1/2/00 Created. - */ -static void ibmcam_send_FF_04_02(struct uvd *uvd) -{ - ibmcam_veio(uvd, 0, 0x00FF, 0x0127); - ibmcam_veio(uvd, 0, 0x0004, 0x0124); - ibmcam_veio(uvd, 0, 0x0002, 0x0124); -} - -static void ibmcam_send_00_04_06(struct uvd *uvd) -{ - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x0004, 0x0124); - ibmcam_veio(uvd, 0, 0x0006, 0x0124); -} - -static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x) -{ - ibmcam_veio(uvd, 0, x, 0x0127); - ibmcam_veio(uvd, 0, 0x0000, 0x0124); -} - -static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x) -{ - ibmcam_send_x_00(uvd, x); - ibmcam_veio(uvd, 0, 0x0005, 0x0124); -} - -static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x) -{ - ibmcam_veio(uvd, 0, x, 0x0127); - ibmcam_veio(uvd, 0, 0x0000, 0x0124); - ibmcam_veio(uvd, 0, 0x0005, 0x0124); - ibmcam_veio(uvd, 0, 0x0002, 0x0124); -} - -static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x) -{ - ibmcam_veio(uvd, 0, x, 0x0127); - ibmcam_veio(uvd, 0, 0x0001, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0124); - ibmcam_veio(uvd, 0, 0x0005, 0x0124); -} - -static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x) -{ - ibmcam_veio(uvd, 0, x, 0x0127); - ibmcam_veio(uvd, 0, 0x0000, 0x0124); - ibmcam_veio(uvd, 0, 0x0005, 0x0124); - ibmcam_veio(uvd, 0, 0x0002, 0x0124); - ibmcam_veio(uvd, 0, 0x0001, 0x0124); -} - -static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x) -{ - ibmcam_veio(uvd, 0, x, 0x0127); - ibmcam_veio(uvd, 0, 0x0000, 0x0124); - ibmcam_veio(uvd, 0, 0x0005, 0x0124); - ibmcam_veio(uvd, 0, 0x0002, 0x0124); - ibmcam_veio(uvd, 0, 0x0008, 0x0124); - ibmcam_veio(uvd, 0, 0x0001, 0x0124); -} - -static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val) -{ - ibmcam_send_x_01_00_05(uvd, unknown_88); - ibmcam_send_x_00_05(uvd, fkey); - ibmcam_send_x_00_05_02_08_01(uvd, val); - ibmcam_send_x_00_05(uvd, unknown_88); - ibmcam_send_x_00_05_02_01(uvd, fkey); - ibmcam_send_x_00_05(uvd, unknown_89); - ibmcam_send_x_00(uvd, fkey); - ibmcam_send_00_04_06(uvd); - ibmcam_veio(uvd, 1, 0x0000, 0x0126); - ibmcam_send_FF_04_02(uvd); -} - -static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val) -{ - ibmcam_send_x_01_00_05 (uvd, unknown_88); - ibmcam_send_x_00_05 (uvd, fkey); - ibmcam_send_x_00_05_02 (uvd, val); -} - -static void ibmcam_model2_Packet2(struct uvd *uvd) -{ - ibmcam_veio(uvd, 0, 0x00ff, 0x012d); - ibmcam_veio(uvd, 0, 0xfea3, 0x0124); -} - -static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2) -{ - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x00ff, 0x012e); - ibmcam_veio(uvd, 0, v1, 0x012f); - ibmcam_veio(uvd, 0, 0x00ff, 0x0130); - ibmcam_veio(uvd, 0, 0xc719, 0x0124); - ibmcam_veio(uvd, 0, v2, 0x0127); - - ibmcam_model2_Packet2(uvd); -} - -/* - * ibmcam_model3_Packet1() - * - * 00_0078_012d - * 00_0097_012f - * 00_d141_0124 - * 00_0096_0127 - * 00_fea8_0124 -*/ -static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2) -{ - ibmcam_veio(uvd, 0, 0x0078, 0x012d); - ibmcam_veio(uvd, 0, v1, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, v2, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); -} - -static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i) -{ - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0026, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, i, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0038, 0x012d); - ibmcam_veio(uvd, 0, 0x0004, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); -} - -/* - * ibmcam_adjust_contrast() - * - * The contrast value changes from 0 (high contrast) to 15 (low contrast). - * This is in reverse to usual order of things (such as TV controls), so - * we reverse it again here. - * - * TODO: we probably don't need to send the setup 5 times... - * - * History: - * 1/2/00 Created. - */ -static void ibmcam_adjust_contrast(struct uvd *uvd) -{ - unsigned char a_contrast = uvd->vpic.contrast >> 12; - unsigned char new_contrast; - - if (a_contrast >= 16) - a_contrast = 15; - new_contrast = 15 - a_contrast; - if (new_contrast == uvd->vpic_old.contrast) - return; - uvd->vpic_old.contrast = new_contrast; - switch (IBMCAM_T(uvd)->camera_model) { - case IBMCAM_MODEL_1: - { - const int ntries = 5; - int i; - for (i=0; i < ntries; i++) { - ibmcam_Packet_Format1(uvd, contrast_14, new_contrast); - ibmcam_send_FF_04_02(uvd); - } - break; - } - case IBMCAM_MODEL_2: - case IBMCAM_MODEL_4: - /* Models 2, 4 do not have this control; implemented in software. */ - break; - case IBMCAM_MODEL_3: - { /* Preset hardware values */ - static const struct { - unsigned short cv1; - unsigned short cv2; - unsigned short cv3; - } cv[7] = { - { 0x05, 0x05, 0x0f }, /* Minimum */ - { 0x04, 0x04, 0x16 }, - { 0x02, 0x03, 0x16 }, - { 0x02, 0x08, 0x16 }, - { 0x01, 0x0c, 0x16 }, - { 0x01, 0x0e, 0x16 }, - { 0x01, 0x10, 0x16 } /* Maximum */ - }; - int i = a_contrast / 2; - RESTRICT_TO_RANGE(i, 0, 6); - ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ - ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1); - ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2); - ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3); - ibmcam_veio(uvd, 0, 0x0001, 0x0114); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ - usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); - break; - } - default: - break; - } -} - -/* - * ibmcam_change_lighting_conditions() - * - * Camera model 1: - * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low. - * - * Camera model 2: - * We have 16 levels of lighting, 0 for bright light and up to 15 for - * low light. But values above 5 or so are useless because camera is - * not really capable to produce anything worth viewing at such light. - * This setting may be altered only in certain camera state. - * - * Low lighting forces slower FPS. Lighting is set as a module parameter. - * - * History: - * 1/5/00 Created. - * 2/20/00 Added support for Model 2 cameras. - */ -static void ibmcam_change_lighting_conditions(struct uvd *uvd) -{ - static const char proc[] = "ibmcam_change_lighting_conditions"; - - if (debug > 0) - info("%s: Set lighting to %hu.", proc, lighting); - - switch (IBMCAM_T(uvd)->camera_model) { - case IBMCAM_MODEL_1: - { - const int ntries = 5; - int i; - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting); - break; - } - case IBMCAM_MODEL_2: -#if 0 - /* - * This command apparently requires camera to be stopped. My - * experiments showed that it -is- possible to alter the lighting - * conditions setting "on the fly", but why bother? This setting does - * not work reliably in all cases, so I decided simply to leave the - * setting where Xirlink put it - in the camera setup phase. This code - * is commented out because it does not work at -any- moment, so its - * presence makes no sense. You may use it for experiments. - */ - ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop camera */ - ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Start camera */ -#endif - break; - case IBMCAM_MODEL_3: - case IBMCAM_MODEL_4: - default: - break; - } -} - -/* - * ibmcam_set_sharpness() - * - * Cameras model 1 have internal smoothing feature. It is controlled by value in - * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess). - * Recommended value is 4. Cameras model 2 do not have this feature at all. - */ -static void ibmcam_set_sharpness(struct uvd *uvd) -{ - static const char proc[] = "ibmcam_set_sharpness"; - - switch (IBMCAM_T(uvd)->camera_model) { - case IBMCAM_MODEL_1: - { - static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; - unsigned short i, sv; - - RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); - if (debug > 0) - info("%s: Set sharpness to %hu.", proc, sharpness); - - sv = sa[sharpness - SHARPNESS_MIN]; - for (i=0; i < 2; i++) { - ibmcam_send_x_01_00_05 (uvd, unknown_88); - ibmcam_send_x_00_05 (uvd, sharp_13); - ibmcam_send_x_00_05_02 (uvd, sv); - } - break; - } - case IBMCAM_MODEL_2: - case IBMCAM_MODEL_4: - /* Models 2, 4 do not have this control */ - break; - case IBMCAM_MODEL_3: - { /* - * "Use a table of magic numbers. - * This setting doesn't really change much. - * But that's how Windows does it." - */ - static const struct { - unsigned short sv1; - unsigned short sv2; - unsigned short sv3; - unsigned short sv4; - } sv[7] = { - { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */ - { 0x01, 0x04, 0x05, 0x14 }, - { 0x02, 0x04, 0x05, 0x14 }, - { 0x03, 0x04, 0x05, 0x14 }, - { 0x03, 0x05, 0x05, 0x14 }, - { 0x03, 0x06, 0x05, 0x14 }, - { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */ - }; - RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX); - RESTRICT_TO_RANGE(sharpness, 0, 6); - ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ - ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1); - ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2); - ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3); - ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4); - ibmcam_veio(uvd, 0, 0x0001, 0x0114); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ - usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); - ibmcam_veio(uvd, 0, 0x0001, 0x0113); - break; - } - default: - break; - } -} - -/* - * ibmcam_set_brightness() - * - * This procedure changes brightness of the picture. - */ -static void ibmcam_set_brightness(struct uvd *uvd) -{ - static const char proc[] = "ibmcam_set_brightness"; - static const unsigned short n = 1; - - if (debug > 0) - info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness); - - switch (IBMCAM_T(uvd)->camera_model) { - case IBMCAM_MODEL_1: - { - unsigned short i, j, bv[3]; - bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10; - if (bv[0] == (uvd->vpic_old.brightness >> 10)) - return; - uvd->vpic_old.brightness = bv[0]; - for (j=0; j < 3; j++) - for (i=0; i < n; i++) - ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]); - break; - } - case IBMCAM_MODEL_2: - { - unsigned short i, j; - i = uvd->vpic.brightness >> 12; /* 0 .. 15 */ - j = 0x60 + i * ((0xee - 0x60) / 16); /* 0x60 .. 0xee or so */ - if (uvd->vpic_old.brightness == j) - break; - uvd->vpic_old.brightness = j; - ibmcam_model2_Packet1(uvd, mod2_brightness, j); - break; - } - case IBMCAM_MODEL_3: - { - /* Model 3: Brightness range 'i' in [0x0C..0x3F] */ - unsigned short i = - 0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1))); - RESTRICT_TO_RANGE(i, 0x0C, 0x3F); - if (uvd->vpic_old.brightness == i) - break; - uvd->vpic_old.brightness = i; - ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ - ibmcam_model3_Packet1(uvd, 0x0036, i); - ibmcam_veio(uvd, 0, 0x0001, 0x0114); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ - usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); - ibmcam_veio(uvd, 0, 0x0001, 0x0113); - break; - } - case IBMCAM_MODEL_4: - { - /* Model 4: Brightness range 'i' in [0x04..0xb4] */ - unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1))); - RESTRICT_TO_RANGE(i, 0x04, 0xb4); - if (uvd->vpic_old.brightness == i) - break; - uvd->vpic_old.brightness = i; - ibmcam_model4_BrightnessPacket(uvd, i); - break; - } - default: - break; - } -} - -static void ibmcam_set_hue(struct uvd *uvd) -{ - switch (IBMCAM_T(uvd)->camera_model) { - case IBMCAM_MODEL_2: - { - unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */ - if (uvd->vpic_old.hue == hue) - return; - uvd->vpic_old.hue = hue; - ibmcam_model2_Packet1(uvd, mod2_hue, hue); - /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */ - break; - } - case IBMCAM_MODEL_3: - { -#if 0 /* This seems not to work. No problem, will fix programmatically */ - unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1))); - RESTRICT_TO_RANGE(hue, 0x05, 0x37); - if (uvd->vpic_old.hue == hue) - return; - uvd->vpic_old.hue = hue; - ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */ - ibmcam_model3_Packet1(uvd, 0x007e, hue); - ibmcam_veio(uvd, 0, 0x0001, 0x0114); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */ - usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); - ibmcam_veio(uvd, 0, 0x0001, 0x0113); -#endif - break; - } - case IBMCAM_MODEL_4: - { - unsigned short r_gain, g_gain, b_gain, hue; - - /* - * I am not sure r/g/b_gain variables exactly control gain - * of those channels. Most likely they subtly change some - * very internal image processing settings in the camera. - * In any case, here is what they do, and feel free to tweak: - * - * r_gain: seriously affects red gain - * g_gain: seriously affects green gain - * b_gain: seriously affects blue gain - * hue: changes average color from violet (0) to red (0xFF) - * - * These settings are preset for a decent white balance in - * 320x240, 352x288 modes. Low-res modes exhibit higher contrast - * and therefore may need different values here. - */ - hue = 20 + (uvd->vpic.hue >> 9); - switch (uvd->videosize) { - case VIDEOSIZE_128x96: - r_gain = 90; - g_gain = 166; - b_gain = 175; - break; - case VIDEOSIZE_160x120: - r_gain = 70; - g_gain = 166; - b_gain = 185; - break; - case VIDEOSIZE_176x144: - r_gain = 160; - g_gain = 175; - b_gain = 185; - break; - default: - r_gain = 120; - g_gain = 166; - b_gain = 175; - break; - } - RESTRICT_TO_RANGE(hue, 1, 0x7f); - - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x001e, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, g_gain, 0x0127); /* Green gain */ - ibmcam_veio(uvd, 0, r_gain, 0x012e); /* Red gain */ - ibmcam_veio(uvd, 0, b_gain, 0x0130); /* Blue gain */ - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, hue, 0x012d); /* Hue */ - ibmcam_veio(uvd, 0, 0xf545, 0x0124); - break; - } - default: - break; - } -} - -/* - * ibmcam_adjust_picture() - * - * This procedure gets called from V4L interface to update picture settings. - * Here we change brightness and contrast. - */ -static void ibmcam_adjust_picture(struct uvd *uvd) -{ - ibmcam_adjust_contrast(uvd); - ibmcam_set_brightness(uvd); - ibmcam_set_hue(uvd); -} - -static int ibmcam_model1_setup(struct uvd *uvd) -{ - const int ntries = 5; - int i; - - ibmcam_veio(uvd, 1, 0x00, 0x0128); - ibmcam_veio(uvd, 1, 0x00, 0x0100); - ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ - ibmcam_veio(uvd, 1, 0x00, 0x0100); - ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */ - ibmcam_veio(uvd, 1, 0x00, 0x0100); - ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ - ibmcam_veio(uvd, 0, 0x01, 0x0108); - - ibmcam_veio(uvd, 0, 0x03, 0x0112); - ibmcam_veio(uvd, 1, 0x00, 0x0115); - ibmcam_veio(uvd, 0, 0x06, 0x0115); - ibmcam_veio(uvd, 1, 0x00, 0x0116); - ibmcam_veio(uvd, 0, 0x44, 0x0116); - ibmcam_veio(uvd, 1, 0x00, 0x0116); - ibmcam_veio(uvd, 0, 0x40, 0x0116); - ibmcam_veio(uvd, 1, 0x00, 0x0115); - ibmcam_veio(uvd, 0, 0x0e, 0x0115); - ibmcam_veio(uvd, 0, 0x19, 0x012c); - - ibmcam_Packet_Format1(uvd, 0x00, 0x1e); - ibmcam_Packet_Format1(uvd, 0x39, 0x0d); - ibmcam_Packet_Format1(uvd, 0x39, 0x09); - ibmcam_Packet_Format1(uvd, 0x3b, 0x00); - ibmcam_Packet_Format1(uvd, 0x28, 0x22); - ibmcam_Packet_Format1(uvd, light_27, 0); - ibmcam_Packet_Format1(uvd, 0x2b, 0x1f); - ibmcam_Packet_Format1(uvd, 0x39, 0x08); - - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x2c, 0x00); - - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x30, 0x14); - - ibmcam_PacketFormat2(uvd, 0x39, 0x02); - ibmcam_PacketFormat2(uvd, 0x01, 0xe1); - ibmcam_PacketFormat2(uvd, 0x02, 0xcd); - ibmcam_PacketFormat2(uvd, 0x03, 0xcd); - ibmcam_PacketFormat2(uvd, 0x04, 0xfa); - ibmcam_PacketFormat2(uvd, 0x3f, 0xff); - ibmcam_PacketFormat2(uvd, 0x39, 0x00); - - ibmcam_PacketFormat2(uvd, 0x39, 0x02); - ibmcam_PacketFormat2(uvd, 0x0a, 0x37); - ibmcam_PacketFormat2(uvd, 0x0b, 0xb8); - ibmcam_PacketFormat2(uvd, 0x0c, 0xf3); - ibmcam_PacketFormat2(uvd, 0x0d, 0xe3); - ibmcam_PacketFormat2(uvd, 0x0e, 0x0d); - ibmcam_PacketFormat2(uvd, 0x0f, 0xf2); - ibmcam_PacketFormat2(uvd, 0x10, 0xd5); - ibmcam_PacketFormat2(uvd, 0x11, 0xba); - ibmcam_PacketFormat2(uvd, 0x12, 0x53); - ibmcam_PacketFormat2(uvd, 0x3f, 0xff); - ibmcam_PacketFormat2(uvd, 0x39, 0x00); - - ibmcam_PacketFormat2(uvd, 0x39, 0x02); - ibmcam_PacketFormat2(uvd, 0x16, 0x00); - ibmcam_PacketFormat2(uvd, 0x17, 0x28); - ibmcam_PacketFormat2(uvd, 0x18, 0x7d); - ibmcam_PacketFormat2(uvd, 0x19, 0xbe); - ibmcam_PacketFormat2(uvd, 0x3f, 0xff); - ibmcam_PacketFormat2(uvd, 0x39, 0x00); - - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x00, 0x18); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x13, 0x18); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x14, 0x06); - - /* This is default brightness */ - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x31, 0x37); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x32, 0x46); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x33, 0x55); - - ibmcam_Packet_Format1(uvd, 0x2e, 0x04); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x2d, 0x04); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x29, 0x80); - ibmcam_Packet_Format1(uvd, 0x2c, 0x01); - ibmcam_Packet_Format1(uvd, 0x30, 0x17); - ibmcam_Packet_Format1(uvd, 0x39, 0x08); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x34, 0x00); - - ibmcam_veio(uvd, 0, 0x00, 0x0101); - ibmcam_veio(uvd, 0, 0x00, 0x010a); - - switch (uvd->videosize) { - case VIDEOSIZE_128x96: - ibmcam_veio(uvd, 0, 0x80, 0x0103); - ibmcam_veio(uvd, 0, 0x60, 0x0105); - ibmcam_veio(uvd, 0, 0x0c, 0x010b); - ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x0b, 0x011d); - ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x00, 0x0129); - break; - case VIDEOSIZE_176x144: - ibmcam_veio(uvd, 0, 0xb0, 0x0103); - ibmcam_veio(uvd, 0, 0x8f, 0x0105); - ibmcam_veio(uvd, 0, 0x06, 0x010b); - ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x0d, 0x011d); - ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x03, 0x0129); - break; - case VIDEOSIZE_352x288: - ibmcam_veio(uvd, 0, 0xb0, 0x0103); - ibmcam_veio(uvd, 0, 0x90, 0x0105); - ibmcam_veio(uvd, 0, 0x02, 0x010b); - ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x05, 0x011d); - ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x00, 0x0129); - break; - } - - ibmcam_veio(uvd, 0, 0xff, 0x012b); - - /* This is another brightness - don't know why */ - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x31, 0xc3); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x32, 0xd2); - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, 0x33, 0xe1); - - /* Default contrast */ - for (i=0; i < ntries; i++) - ibmcam_Packet_Format1(uvd, contrast_14, 0x0a); - - /* Default sharpness */ - for (i=0; i < 2; i++) - ibmcam_PacketFormat2(uvd, sharp_13, 0x1a); /* Level 4 FIXME */ - - /* Default lighting conditions */ - ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */ - - /* Assorted init */ - - switch (uvd->videosize) { - case VIDEOSIZE_128x96: - ibmcam_Packet_Format1(uvd, 0x2b, 0x1e); - ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x36, 0x0102); - ibmcam_veio(uvd, 0, 0x1a, 0x0104); - ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x2b, 0x011c); - ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ -#if 0 - ibmcam_veio(uvd, 0, 0x00, 0x0106); - ibmcam_veio(uvd, 0, 0x38, 0x0107); -#else - ibmcam_veio(uvd, 0, 0x02, 0x0106); - ibmcam_veio(uvd, 0, 0x2a, 0x0107); -#endif - break; - case VIDEOSIZE_176x144: - ibmcam_Packet_Format1(uvd, 0x2b, 0x1e); - ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x04, 0x0102); - ibmcam_veio(uvd, 0, 0x02, 0x0104); - ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x2b, 0x011c); - ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x01, 0x0106); - ibmcam_veio(uvd, 0, 0xca, 0x0107); - break; - case VIDEOSIZE_352x288: - ibmcam_Packet_Format1(uvd, 0x2b, 0x1f); - ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x08, 0x0102); - ibmcam_veio(uvd, 0, 0x01, 0x0104); - ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x2f, 0x011c); - ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */ - ibmcam_veio(uvd, 0, 0x03, 0x0106); - ibmcam_veio(uvd, 0, 0xf6, 0x0107); - break; - } - return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT); -} - -static int ibmcam_model2_setup(struct uvd *uvd) -{ - ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */ - ibmcam_veio(uvd, 1, 0x0000, 0x0116); - ibmcam_veio(uvd, 0, 0x0060, 0x0116); - ibmcam_veio(uvd, 0, 0x0002, 0x0112); - ibmcam_veio(uvd, 0, 0x00bc, 0x012c); - ibmcam_veio(uvd, 0, 0x0008, 0x012b); - ibmcam_veio(uvd, 0, 0x0000, 0x0108); - ibmcam_veio(uvd, 0, 0x0001, 0x0133); - ibmcam_veio(uvd, 0, 0x0001, 0x0102); - switch (uvd->videosize) { - case VIDEOSIZE_176x144: - ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ - ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ - ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ - ibmcam_veio(uvd, 0, 0x00b9, 0x010a); /* Unique to this mode */ - ibmcam_veio(uvd, 0, 0x0038, 0x0119); /* Unique to this mode */ - ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ - ibmcam_veio(uvd, 0, 0x0090, 0x0107); /* Unique to every mode*/ - break; - case VIDEOSIZE_320x240: - ibmcam_veio(uvd, 0, 0x0028, 0x0103); /* Unique to this mode */ - ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ - ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ - ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ - ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ - ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ - ibmcam_veio(uvd, 0, 0x0098, 0x0107); /* Unique to every mode*/ - break; - case VIDEOSIZE_352x240: - ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ - ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ - ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */ - ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ - ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ - ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ - ibmcam_veio(uvd, 0, 0x00da, 0x0107); /* Unique to every mode*/ - break; - case VIDEOSIZE_352x288: - ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */ - ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */ - ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */ - ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */ - ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */ - ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */ - ibmcam_veio(uvd, 0, 0x00fe, 0x0107); /* Unique to every mode*/ - break; - } - return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT); -} - -/* - * ibmcam_model1_setup_after_video_if() - * - * This code adds finishing touches to the video data interface. - * Here we configure the frame rate and turn on the LED. - */ -static void ibmcam_model1_setup_after_video_if(struct uvd *uvd) -{ - unsigned short internal_frame_rate; - - RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); - internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */ - ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */ - ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111); - ibmcam_veio(uvd, 0, 0x01, 0x0114); - ibmcam_veio(uvd, 0, 0xc0, 0x010c); -} - -static void ibmcam_model2_setup_after_video_if(struct uvd *uvd) -{ - unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb; - - ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */ - - switch (uvd->videosize) { - case VIDEOSIZE_176x144: - ibmcam_veio(uvd, 0, 0x0050, 0x0111); - ibmcam_veio(uvd, 0, 0x00d0, 0x0111); - break; - case VIDEOSIZE_320x240: - case VIDEOSIZE_352x240: - case VIDEOSIZE_352x288: - ibmcam_veio(uvd, 0, 0x0040, 0x0111); - ibmcam_veio(uvd, 0, 0x00c0, 0x0111); - break; - } - ibmcam_veio(uvd, 0, 0x009b, 0x010f); - ibmcam_veio(uvd, 0, 0x00bb, 0x010f); - - /* - * Hardware settings, may affect CMOS sensor; not user controls! - * ------------------------------------------------------------- - * 0x0004: no effect - * 0x0006: hardware effect - * 0x0008: no effect - * 0x000a: stops video stream, probably important h/w setting - * 0x000c: changes color in hardware manner (not user setting) - * 0x0012: changes number of colors (does not affect speed) - * 0x002a: no effect - * 0x002c: hardware setting (related to scan lines) - * 0x002e: stops video stream, probably important h/w setting - */ - ibmcam_model2_Packet1(uvd, 0x000a, 0x005c); - ibmcam_model2_Packet1(uvd, 0x0004, 0x0000); - ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb); - ibmcam_model2_Packet1(uvd, 0x0008, 0x0000); - ibmcam_model2_Packet1(uvd, 0x000c, 0x0009); - ibmcam_model2_Packet1(uvd, 0x0012, 0x000a); - ibmcam_model2_Packet1(uvd, 0x002a, 0x0000); - ibmcam_model2_Packet1(uvd, 0x002c, 0x0000); - ibmcam_model2_Packet1(uvd, 0x002e, 0x0008); - - /* - * Function 0x0030 pops up all over the place. Apparently - * it is a hardware control register, with every bit assigned to - * do something. - */ - ibmcam_model2_Packet1(uvd, 0x0030, 0x0000); - - /* - * Magic control of CMOS sensor. Only lower values like - * 0-3 work, and picture shifts left or right. Don't change. - */ - switch (uvd->videosize) { - case VIDEOSIZE_176x144: - ibmcam_model2_Packet1(uvd, 0x0014, 0x0002); - ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */ - ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */ - break; - case VIDEOSIZE_320x240: - ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); - ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */ - ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */ - break; - case VIDEOSIZE_352x240: - /* This mode doesn't work as Windows programs it; changed to work */ - ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */ - ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */ - ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */ - break; - case VIDEOSIZE_352x288: - ibmcam_model2_Packet1(uvd, 0x0014, 0x0003); - ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */ - ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */ - break; - } - - ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a); - - /* - * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest). - * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the - * slowest setting. However for all practical reasons high settings make no - * sense because USB is not fast enough to support high FPS. Be aware that - * the picture datastream will be severely disrupted if you ask for - * frame rate faster than allowed for the video size - see below: - * - * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz): - * ----------------------------------------------------------------- - * 176x144: [6..31] - * 320x240: [8..31] - * 352x240: [10..31] - * 352x288: [16..31] I have to raise lower threshold for stability... - * - * As usual, slower FPS provides better sensitivity. - */ - { - short hw_fps=31, i_framerate; - - RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); - i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN; - switch (uvd->videosize) { - case VIDEOSIZE_176x144: - hw_fps = 6 + i_framerate*4; - break; - case VIDEOSIZE_320x240: - hw_fps = 8 + i_framerate*3; - break; - case VIDEOSIZE_352x240: - hw_fps = 10 + i_framerate*2; - break; - case VIDEOSIZE_352x288: - hw_fps = 28 + i_framerate/2; - break; - } - if (uvd->debug > 0) - info("Framerate (hardware): %hd.", hw_fps); - RESTRICT_TO_RANGE(hw_fps, 0, 31); - ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps); - } - - /* - * This setting does not visibly affect pictures; left it here - * because it was present in Windows USB data stream. This function - * does not allow arbitrary values and apparently is a bit mask, to - * be activated only at appropriate time. Don't change it randomly! - */ - switch (uvd->videosize) { - case VIDEOSIZE_176x144: - ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2); - break; - case VIDEOSIZE_320x240: - ibmcam_model2_Packet1(uvd, 0x0026, 0x0044); - break; - case VIDEOSIZE_352x240: - ibmcam_model2_Packet1(uvd, 0x0026, 0x0046); - break; - case VIDEOSIZE_352x288: - ibmcam_model2_Packet1(uvd, 0x0026, 0x0048); - break; - } - - ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting); - - if (init_model2_rg2 >= 0) { - RESTRICT_TO_RANGE(init_model2_rg2, 0, 255); - setup_model2_rg2 = init_model2_rg2; - } else - setup_model2_rg2 = 0x002f; - - if (init_model2_sat >= 0) { - RESTRICT_TO_RANGE(init_model2_sat, 0, 255); - setup_model2_sat = init_model2_sat; - } else - setup_model2_sat = 0x0034; - - if (init_model2_yb >= 0) { - RESTRICT_TO_RANGE(init_model2_yb, 0, 255); - setup_model2_yb = init_model2_yb; - } else - setup_model2_yb = 0x00a0; - - ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2); - ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat); - ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb); - ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */; - - /* Hardware control command */ - ibmcam_model2_Packet1(uvd, 0x0030, 0x0004); - - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go camera, go! */ - usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); -} - -static void ibmcam_model4_setup_after_video_if(struct uvd *uvd) -{ - switch (uvd->videosize) { - case VIDEOSIZE_128x96: - ibmcam_veio(uvd, 0, 0x0000, 0x0100); - ibmcam_veio(uvd, 0, 0x00c0, 0x0111); - ibmcam_veio(uvd, 0, 0x00bc, 0x012c); - ibmcam_veio(uvd, 0, 0x0080, 0x012b); - ibmcam_veio(uvd, 0, 0x0000, 0x0108); - ibmcam_veio(uvd, 0, 0x0001, 0x0133); - ibmcam_veio(uvd, 0, 0x009b, 0x010f); - ibmcam_veio(uvd, 0, 0x00bb, 0x010f); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x000a, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x005c, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0004, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x00fb, 0x012e); - ibmcam_veio(uvd, 0, 0x0000, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x000c, 0x0127); - ibmcam_veio(uvd, 0, 0x0009, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0012, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0008, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x002a, 0x012d); - ibmcam_veio(uvd, 0, 0x0000, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0034, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x0070, 0x0119); - ibmcam_veio(uvd, 0, 0x00d2, 0x0107); - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x005e, 0x0107); - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x00d0, 0x0111); - ibmcam_veio(uvd, 0, 0x0039, 0x010a); - ibmcam_veio(uvd, 0, 0x0001, 0x0102); - ibmcam_veio(uvd, 0, 0x0028, 0x0103); - ibmcam_veio(uvd, 0, 0x0000, 0x0104); - ibmcam_veio(uvd, 0, 0x001e, 0x0105); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0016, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x000a, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0014, 0x012d); - ibmcam_veio(uvd, 0, 0x0008, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012e); - ibmcam_veio(uvd, 0, 0x001a, 0x0130); - ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); - ibmcam_veio(uvd, 0, 0x005a, 0x012d); - ibmcam_veio(uvd, 0, 0x9545, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x0127); - ibmcam_veio(uvd, 0, 0x0018, 0x012e); - ibmcam_veio(uvd, 0, 0x0043, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x001c, 0x0127); - ibmcam_veio(uvd, 0, 0x00eb, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0032, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0036, 0x012d); - ibmcam_veio(uvd, 0, 0x0008, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x001e, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0017, 0x0127); - ibmcam_veio(uvd, 0, 0x0013, 0x012e); - ibmcam_veio(uvd, 0, 0x0031, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x0017, 0x012d); - ibmcam_veio(uvd, 0, 0x0078, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0004, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); - break; - case VIDEOSIZE_160x120: - ibmcam_veio(uvd, 0, 0x0000, 0x0100); - ibmcam_veio(uvd, 0, 0x00c0, 0x0111); - ibmcam_veio(uvd, 0, 0x00bc, 0x012c); - ibmcam_veio(uvd, 0, 0x0080, 0x012b); - ibmcam_veio(uvd, 0, 0x0000, 0x0108); - ibmcam_veio(uvd, 0, 0x0001, 0x0133); - ibmcam_veio(uvd, 0, 0x009b, 0x010f); - ibmcam_veio(uvd, 0, 0x00bb, 0x010f); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x000a, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x005c, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0004, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x00fb, 0x012e); - ibmcam_veio(uvd, 0, 0x0000, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x000c, 0x0127); - ibmcam_veio(uvd, 0, 0x0009, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0012, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0008, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x002a, 0x012d); - ibmcam_veio(uvd, 0, 0x0000, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0034, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x0038, 0x0119); - ibmcam_veio(uvd, 0, 0x00d8, 0x0107); - ibmcam_veio(uvd, 0, 0x0002, 0x0106); - ibmcam_veio(uvd, 0, 0x00d0, 0x0111); - ibmcam_veio(uvd, 0, 0x00b9, 0x010a); - ibmcam_veio(uvd, 0, 0x0001, 0x0102); - ibmcam_veio(uvd, 0, 0x0028, 0x0103); - ibmcam_veio(uvd, 0, 0x0000, 0x0104); - ibmcam_veio(uvd, 0, 0x001e, 0x0105); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0016, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x000b, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0014, 0x012d); - ibmcam_veio(uvd, 0, 0x0008, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012e); - ibmcam_veio(uvd, 0, 0x001a, 0x0130); - ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); - ibmcam_veio(uvd, 0, 0x005a, 0x012d); - ibmcam_veio(uvd, 0, 0x9545, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x0127); - ibmcam_veio(uvd, 0, 0x0018, 0x012e); - ibmcam_veio(uvd, 0, 0x0043, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x001c, 0x0127); - ibmcam_veio(uvd, 0, 0x00c7, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0032, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0025, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0036, 0x012d); - ibmcam_veio(uvd, 0, 0x0008, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x001e, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0048, 0x0127); - ibmcam_veio(uvd, 0, 0x0035, 0x012e); - ibmcam_veio(uvd, 0, 0x00d0, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x0048, 0x012d); - ibmcam_veio(uvd, 0, 0x0090, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x0001, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0004, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); - break; - case VIDEOSIZE_176x144: - ibmcam_veio(uvd, 0, 0x0000, 0x0100); - ibmcam_veio(uvd, 0, 0x00c0, 0x0111); - ibmcam_veio(uvd, 0, 0x00bc, 0x012c); - ibmcam_veio(uvd, 0, 0x0080, 0x012b); - ibmcam_veio(uvd, 0, 0x0000, 0x0108); - ibmcam_veio(uvd, 0, 0x0001, 0x0133); - ibmcam_veio(uvd, 0, 0x009b, 0x010f); - ibmcam_veio(uvd, 0, 0x00bb, 0x010f); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x000a, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x005c, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0004, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x00fb, 0x012e); - ibmcam_veio(uvd, 0, 0x0000, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x000c, 0x0127); - ibmcam_veio(uvd, 0, 0x0009, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0012, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0008, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x002a, 0x012d); - ibmcam_veio(uvd, 0, 0x0000, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0034, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x0038, 0x0119); - ibmcam_veio(uvd, 0, 0x00d6, 0x0107); - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x0018, 0x0107); - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x00d0, 0x0111); - ibmcam_veio(uvd, 0, 0x00b9, 0x010a); - ibmcam_veio(uvd, 0, 0x0001, 0x0102); - ibmcam_veio(uvd, 0, 0x002c, 0x0103); - ibmcam_veio(uvd, 0, 0x0000, 0x0104); - ibmcam_veio(uvd, 0, 0x0024, 0x0105); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0016, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0007, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0014, 0x012d); - ibmcam_veio(uvd, 0, 0x0001, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012e); - ibmcam_veio(uvd, 0, 0x001a, 0x0130); - ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); - ibmcam_veio(uvd, 0, 0x005e, 0x012d); - ibmcam_veio(uvd, 0, 0x9545, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x0127); - ibmcam_veio(uvd, 0, 0x0018, 0x012e); - ibmcam_veio(uvd, 0, 0x0049, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x001c, 0x0127); - ibmcam_veio(uvd, 0, 0x00c7, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0032, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0028, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0036, 0x012d); - ibmcam_veio(uvd, 0, 0x0008, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x001e, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0010, 0x0127); - ibmcam_veio(uvd, 0, 0x0013, 0x012e); - ibmcam_veio(uvd, 0, 0x002a, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x0010, 0x012d); - ibmcam_veio(uvd, 0, 0x006d, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x0001, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0004, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); - break; - case VIDEOSIZE_320x240: - ibmcam_veio(uvd, 0, 0x0000, 0x0100); - ibmcam_veio(uvd, 0, 0x00c0, 0x0111); - ibmcam_veio(uvd, 0, 0x00bc, 0x012c); - ibmcam_veio(uvd, 0, 0x0080, 0x012b); - ibmcam_veio(uvd, 0, 0x0000, 0x0108); - ibmcam_veio(uvd, 0, 0x0001, 0x0133); - ibmcam_veio(uvd, 0, 0x009b, 0x010f); - ibmcam_veio(uvd, 0, 0x00bb, 0x010f); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x000a, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x005c, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0004, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x00fb, 0x012e); - ibmcam_veio(uvd, 0, 0x0000, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x000c, 0x0127); - ibmcam_veio(uvd, 0, 0x0009, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0012, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0008, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x002a, 0x012d); - ibmcam_veio(uvd, 0, 0x0000, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0034, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x0070, 0x0119); - ibmcam_veio(uvd, 0, 0x00d2, 0x0107); - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x005e, 0x0107); - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x00d0, 0x0111); - ibmcam_veio(uvd, 0, 0x0039, 0x010a); - ibmcam_veio(uvd, 0, 0x0001, 0x0102); - ibmcam_veio(uvd, 0, 0x0028, 0x0103); - ibmcam_veio(uvd, 0, 0x0000, 0x0104); - ibmcam_veio(uvd, 0, 0x001e, 0x0105); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0016, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x000a, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0014, 0x012d); - ibmcam_veio(uvd, 0, 0x0008, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012e); - ibmcam_veio(uvd, 0, 0x001a, 0x0130); - ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); - ibmcam_veio(uvd, 0, 0x005a, 0x012d); - ibmcam_veio(uvd, 0, 0x9545, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x0127); - ibmcam_veio(uvd, 0, 0x0018, 0x012e); - ibmcam_veio(uvd, 0, 0x0043, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x001c, 0x0127); - ibmcam_veio(uvd, 0, 0x00eb, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0032, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0036, 0x012d); - ibmcam_veio(uvd, 0, 0x0008, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x001e, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0017, 0x0127); - ibmcam_veio(uvd, 0, 0x0013, 0x012e); - ibmcam_veio(uvd, 0, 0x0031, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x0017, 0x012d); - ibmcam_veio(uvd, 0, 0x0078, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0004, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); - break; - case VIDEOSIZE_352x288: - ibmcam_veio(uvd, 0, 0x0000, 0x0100); - ibmcam_veio(uvd, 0, 0x00c0, 0x0111); - ibmcam_veio(uvd, 0, 0x00bc, 0x012c); - ibmcam_veio(uvd, 0, 0x0080, 0x012b); - ibmcam_veio(uvd, 0, 0x0000, 0x0108); - ibmcam_veio(uvd, 0, 0x0001, 0x0133); - ibmcam_veio(uvd, 0, 0x009b, 0x010f); - ibmcam_veio(uvd, 0, 0x00bb, 0x010f); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x000a, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x005c, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0004, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x00fb, 0x012e); - ibmcam_veio(uvd, 0, 0x0000, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x000c, 0x0127); - ibmcam_veio(uvd, 0, 0x0009, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0012, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0008, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x002a, 0x012d); - ibmcam_veio(uvd, 0, 0x0000, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0034, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x0070, 0x0119); - ibmcam_veio(uvd, 0, 0x00f2, 0x0107); - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x008c, 0x0107); - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x00c0, 0x0111); - ibmcam_veio(uvd, 0, 0x0039, 0x010a); - ibmcam_veio(uvd, 0, 0x0001, 0x0102); - ibmcam_veio(uvd, 0, 0x002c, 0x0103); - ibmcam_veio(uvd, 0, 0x0000, 0x0104); - ibmcam_veio(uvd, 0, 0x0024, 0x0105); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0016, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0006, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0014, 0x012d); - ibmcam_veio(uvd, 0, 0x0002, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012e); - ibmcam_veio(uvd, 0, 0x001a, 0x0130); - ibmcam_veio(uvd, 0, 0x8a0a, 0x0124); - ibmcam_veio(uvd, 0, 0x005e, 0x012d); - ibmcam_veio(uvd, 0, 0x9545, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x0127); - ibmcam_veio(uvd, 0, 0x0018, 0x012e); - ibmcam_veio(uvd, 0, 0x0049, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012f); - ibmcam_veio(uvd, 0, 0xd055, 0x0124); - ibmcam_veio(uvd, 0, 0x001c, 0x0127); - ibmcam_veio(uvd, 0, 0x00cf, 0x012e); - ibmcam_veio(uvd, 0, 0xaa28, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0032, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0x00aa, 0x0130); - ibmcam_veio(uvd, 0, 0x82a8, 0x0124); - ibmcam_veio(uvd, 0, 0x0036, 0x012d); - ibmcam_veio(uvd, 0, 0x0008, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0xfffa, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x001e, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0010, 0x0127); - ibmcam_veio(uvd, 0, 0x0013, 0x012e); - ibmcam_veio(uvd, 0, 0x0025, 0x0130); - ibmcam_veio(uvd, 0, 0x8a28, 0x0124); - ibmcam_veio(uvd, 0, 0x0010, 0x012d); - ibmcam_veio(uvd, 0, 0x0048, 0x012f); - ibmcam_veio(uvd, 0, 0xd145, 0x0124); - ibmcam_veio(uvd, 0, 0x0000, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00aa, 0x012d); - ibmcam_veio(uvd, 0, 0x0038, 0x012f); - ibmcam_veio(uvd, 0, 0xd141, 0x0124); - ibmcam_veio(uvd, 0, 0x0004, 0x0127); - ibmcam_veio(uvd, 0, 0xfea8, 0x0124); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); - break; - } - usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); -} - -static void ibmcam_model3_setup_after_video_if(struct uvd *uvd) -{ - int i; - /* - * 01.01.08 - Added for RCA video in support -LO - * This struct is used to init the Model3 cam to use the RCA video in port - * instead of the CCD sensor. - */ - static const struct struct_initData initData[] = { - {0, 0x0000, 0x010c}, - {0, 0x0006, 0x012c}, - {0, 0x0078, 0x012d}, - {0, 0x0046, 0x012f}, - {0, 0xd141, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfea8, 0x0124}, - {1, 0x0000, 0x0116}, - {0, 0x0064, 0x0116}, - {1, 0x0000, 0x0115}, - {0, 0x0003, 0x0115}, - {0, 0x0008, 0x0123}, - {0, 0x0000, 0x0117}, - {0, 0x0000, 0x0112}, - {0, 0x0080, 0x0100}, - {0, 0x0000, 0x0100}, - {1, 0x0000, 0x0116}, - {0, 0x0060, 0x0116}, - {0, 0x0002, 0x0112}, - {0, 0x0000, 0x0123}, - {0, 0x0001, 0x0117}, - {0, 0x0040, 0x0108}, - {0, 0x0019, 0x012c}, - {0, 0x0040, 0x0116}, - {0, 0x000a, 0x0115}, - {0, 0x000b, 0x0115}, - {0, 0x0078, 0x012d}, - {0, 0x0046, 0x012f}, - {0, 0xd141, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfea8, 0x0124}, - {0, 0x0064, 0x0116}, - {0, 0x0000, 0x0115}, - {0, 0x0001, 0x0115}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00aa, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00f2, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x000f, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00f8, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00fc, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00f9, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x003c, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xffff, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0027, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0019, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0021, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0006, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0045, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002a, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x000e, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002b, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00f4, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002c, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0004, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002d, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0014, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002e, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0003, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x002f, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0003, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0014, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0053, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0x0000, 0x0101}, - {0, 0x00a0, 0x0103}, - {0, 0x0078, 0x0105}, - {0, 0x0000, 0x010a}, - {0, 0x0024, 0x010b}, - {0, 0x0028, 0x0119}, - {0, 0x0088, 0x011b}, - {0, 0x0002, 0x011d}, - {0, 0x0003, 0x011e}, - {0, 0x0000, 0x0129}, - {0, 0x00fc, 0x012b}, - {0, 0x0008, 0x0102}, - {0, 0x0000, 0x0104}, - {0, 0x0008, 0x011a}, - {0, 0x0028, 0x011c}, - {0, 0x0021, 0x012a}, - {0, 0x0000, 0x0118}, - {0, 0x0000, 0x0132}, - {0, 0x0000, 0x0109}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0031, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x00dc, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0032, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0020, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0001, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0040, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0037, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0030, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0xfff9, 0x0124}, - {0, 0x0086, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0038, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0008, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0x0000, 0x0127}, - {0, 0xfff8, 0x0124}, - {0, 0xfffd, 0x0124}, - {0, 0xfffa, 0x0124}, - {0, 0x0003, 0x0106}, - {0, 0x0062, 0x0107}, - {0, 0x0003, 0x0111}, - }; -#define NUM_INIT_DATA - - unsigned short compression = 0; /* 0=none, 7=best frame rate */ - int f_rate; /* 0=Fastest 7=slowest */ - - if (IBMCAM_T(uvd)->initialized) - return; - - /* Internal frame rate is controlled by f_rate value */ - f_rate = 7 - framerate; - RESTRICT_TO_RANGE(f_rate, 0, 7); - - ibmcam_veio(uvd, 0, 0x0000, 0x0100); - ibmcam_veio(uvd, 1, 0x0000, 0x0116); - ibmcam_veio(uvd, 0, 0x0060, 0x0116); - ibmcam_veio(uvd, 0, 0x0002, 0x0112); - ibmcam_veio(uvd, 0, 0x0000, 0x0123); - ibmcam_veio(uvd, 0, 0x0001, 0x0117); - ibmcam_veio(uvd, 0, 0x0040, 0x0108); - ibmcam_veio(uvd, 0, 0x0019, 0x012c); - ibmcam_veio(uvd, 0, 0x0060, 0x0116); - ibmcam_veio(uvd, 0, 0x0002, 0x0115); - ibmcam_veio(uvd, 0, 0x0003, 0x0115); - ibmcam_veio(uvd, 1, 0x0000, 0x0115); - ibmcam_veio(uvd, 0, 0x000b, 0x0115); - ibmcam_model3_Packet1(uvd, 0x000a, 0x0040); - ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6); - ibmcam_model3_Packet1(uvd, 0x000c, 0x0002); - ibmcam_model3_Packet1(uvd, 0x000d, 0x0020); - ibmcam_model3_Packet1(uvd, 0x000e, 0x0033); - ibmcam_model3_Packet1(uvd, 0x000f, 0x0007); - ibmcam_model3_Packet1(uvd, 0x0010, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0011, 0x0070); - ibmcam_model3_Packet1(uvd, 0x0012, 0x0030); - ibmcam_model3_Packet1(uvd, 0x0013, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0014, 0x0001); - ibmcam_model3_Packet1(uvd, 0x0015, 0x0001); - ibmcam_model3_Packet1(uvd, 0x0016, 0x0001); - ibmcam_model3_Packet1(uvd, 0x0017, 0x0001); - ibmcam_model3_Packet1(uvd, 0x0018, 0x0000); - ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3); - ibmcam_model3_Packet1(uvd, 0x0020, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0028, 0x0010); - ibmcam_model3_Packet1(uvd, 0x0029, 0x0054); - ibmcam_model3_Packet1(uvd, 0x002a, 0x0013); - ibmcam_model3_Packet1(uvd, 0x002b, 0x0007); - ibmcam_model3_Packet1(uvd, 0x002d, 0x0028); - ibmcam_model3_Packet1(uvd, 0x002e, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0031, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0032, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0033, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0034, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0035, 0x0038); - ibmcam_model3_Packet1(uvd, 0x003a, 0x0001); - ibmcam_model3_Packet1(uvd, 0x003c, 0x001e); - ibmcam_model3_Packet1(uvd, 0x003f, 0x000a); - ibmcam_model3_Packet1(uvd, 0x0041, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0046, 0x003f); - ibmcam_model3_Packet1(uvd, 0x0047, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0050, 0x0005); - ibmcam_model3_Packet1(uvd, 0x0052, 0x001a); - ibmcam_model3_Packet1(uvd, 0x0053, 0x0003); - ibmcam_model3_Packet1(uvd, 0x005a, 0x006b); - ibmcam_model3_Packet1(uvd, 0x005d, 0x001e); - ibmcam_model3_Packet1(uvd, 0x005e, 0x0030); - ibmcam_model3_Packet1(uvd, 0x005f, 0x0041); - ibmcam_model3_Packet1(uvd, 0x0064, 0x0008); - ibmcam_model3_Packet1(uvd, 0x0065, 0x0015); - ibmcam_model3_Packet1(uvd, 0x0068, 0x000f); - ibmcam_model3_Packet1(uvd, 0x0079, 0x0000); - ibmcam_model3_Packet1(uvd, 0x007a, 0x0000); - ibmcam_model3_Packet1(uvd, 0x007c, 0x003f); - ibmcam_model3_Packet1(uvd, 0x0082, 0x000f); - ibmcam_model3_Packet1(uvd, 0x0085, 0x0000); - ibmcam_model3_Packet1(uvd, 0x0099, 0x0000); - ibmcam_model3_Packet1(uvd, 0x009b, 0x0023); - ibmcam_model3_Packet1(uvd, 0x009c, 0x0022); - ibmcam_model3_Packet1(uvd, 0x009d, 0x0096); - ibmcam_model3_Packet1(uvd, 0x009e, 0x0096); - ibmcam_model3_Packet1(uvd, 0x009f, 0x000a); - - switch (uvd->videosize) { - case VIDEOSIZE_160x120: - ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */ - ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */ - ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */ - ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ - ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */ - ibmcam_veio(uvd, 0, 0x00a9, 0x0119); - ibmcam_veio(uvd, 0, 0x0016, 0x011b); - ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */ - ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */ - ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ - ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ - ibmcam_veio(uvd, 0, 0x0018, 0x0102); - ibmcam_veio(uvd, 0, 0x0004, 0x0104); - ibmcam_veio(uvd, 0, 0x0004, 0x011a); - ibmcam_veio(uvd, 0, 0x0028, 0x011c); - ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ - ibmcam_veio(uvd, 0, 0x0000, 0x0118); - ibmcam_veio(uvd, 0, 0x0000, 0x0132); - ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ - ibmcam_veio(uvd, 0, compression, 0x0109); - break; - case VIDEOSIZE_320x240: - ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */ - ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */ - ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */ - ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ - ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */ - ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */ - ibmcam_veio(uvd, 0, 0x0000, 0x011e); - ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ - ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ - /* 4 commands from 160x120 skipped */ - ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ - ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ - ibmcam_veio(uvd, 0, compression, 0x0109); - ibmcam_veio(uvd, 0, 0x00d9, 0x0119); - ibmcam_veio(uvd, 0, 0x0006, 0x011b); - ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ - ibmcam_veio(uvd, 0, 0x0010, 0x0104); - ibmcam_veio(uvd, 0, 0x0004, 0x011a); - ibmcam_veio(uvd, 0, 0x003f, 0x011c); - ibmcam_veio(uvd, 0, 0x001c, 0x0118); - ibmcam_veio(uvd, 0, 0x0000, 0x0132); - break; - case VIDEOSIZE_640x480: - ibmcam_veio(uvd, 0, 0x00f0, 0x0105); - ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */ - ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */ - ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */ - ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */ - ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */ - ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */ - ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */ - ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */ - ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */ - ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */ - ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */ - ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */ - ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */ - ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */ - ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */ - ibmcam_veio(uvd, 0, compression, 0x0109); - ibmcam_veio(uvd, 0, 0x0040, 0x0101); - ibmcam_veio(uvd, 0, 0x0040, 0x0103); - ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */ - break; - } - ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); /* Hue */ - ibmcam_model3_Packet1(uvd, 0x0036, 0x0011); /* Brightness */ - ibmcam_model3_Packet1(uvd, 0x0060, 0x0002); /* Sharpness */ - ibmcam_model3_Packet1(uvd, 0x0061, 0x0004); /* Sharpness */ - ibmcam_model3_Packet1(uvd, 0x0062, 0x0005); /* Sharpness */ - ibmcam_model3_Packet1(uvd, 0x0063, 0x0014); /* Sharpness */ - ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */ - ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */ - ibmcam_model3_Packet1(uvd, 0x0067, 0x0001); /* Contrast */ - ibmcam_model3_Packet1(uvd, 0x005b, 0x000c); /* Contrast */ - ibmcam_model3_Packet1(uvd, 0x005c, 0x0016); /* Contrast */ - ibmcam_model3_Packet1(uvd, 0x0098, 0x000b); - ibmcam_model3_Packet1(uvd, 0x002c, 0x0003); /* Was 1, broke 640x480 */ - ibmcam_model3_Packet1(uvd, 0x002f, 0x002a); - ibmcam_model3_Packet1(uvd, 0x0030, 0x0029); - ibmcam_model3_Packet1(uvd, 0x0037, 0x0002); - ibmcam_model3_Packet1(uvd, 0x0038, 0x0059); - ibmcam_model3_Packet1(uvd, 0x003d, 0x002e); - ibmcam_model3_Packet1(uvd, 0x003e, 0x0028); - ibmcam_model3_Packet1(uvd, 0x0078, 0x0005); - ibmcam_model3_Packet1(uvd, 0x007b, 0x0011); - ibmcam_model3_Packet1(uvd, 0x007d, 0x004b); - ibmcam_model3_Packet1(uvd, 0x007f, 0x0022); - ibmcam_model3_Packet1(uvd, 0x0080, 0x000c); - ibmcam_model3_Packet1(uvd, 0x0081, 0x000b); - ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd); - ibmcam_model3_Packet1(uvd, 0x0086, 0x000b); - ibmcam_model3_Packet1(uvd, 0x0087, 0x000b); - ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); - ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */ - ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */ - ibmcam_model3_Packet1(uvd, 0x0098, 0x000b); - - switch (uvd->videosize) { - case VIDEOSIZE_160x120: - ibmcam_veio(uvd, 0, 0x0002, 0x0106); - ibmcam_veio(uvd, 0, 0x0008, 0x0107); - ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ - ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */ - ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */ - ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */ - ibmcam_model3_Packet1(uvd, 0x0040, 0x000a); - ibmcam_model3_Packet1(uvd, 0x0051, 0x000a); - break; - case VIDEOSIZE_320x240: - ibmcam_veio(uvd, 0, 0x0003, 0x0106); - ibmcam_veio(uvd, 0, 0x0062, 0x0107); - ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ - ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */ - ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */ - ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */ - ibmcam_model3_Packet1(uvd, 0x0040, 0x0008); - ibmcam_model3_Packet1(uvd, 0x0051, 0x000b); - break; - case VIDEOSIZE_640x480: - ibmcam_veio(uvd, 0, 0x0002, 0x0106); /* Adjustments */ - ibmcam_veio(uvd, 0, 0x00b4, 0x0107); /* Adjustments */ - ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */ - ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */ - ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */ - ibmcam_model3_Packet1(uvd, 0x0040, 0x0008); - ibmcam_model3_Packet1(uvd, 0x0051, 0x000a); - break; - } - - /* 01.01.08 - Added for RCA video in support -LO */ - if(init_model3_input) { - if (debug > 0) - info("Setting input to RCA."); - for (i=0; i < ARRAY_SIZE(initData); i++) { - ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index); - } - } - - ibmcam_veio(uvd, 0, 0x0001, 0x0114); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); - usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); -} - -/* - * ibmcam_video_stop() - * - * This code tells camera to stop streaming. The interface remains - * configured and bandwidth - claimed. - */ -static void ibmcam_video_stop(struct uvd *uvd) -{ - switch (IBMCAM_T(uvd)->camera_model) { - case IBMCAM_MODEL_1: - ibmcam_veio(uvd, 0, 0x00, 0x010c); - ibmcam_veio(uvd, 0, 0x00, 0x010c); - ibmcam_veio(uvd, 0, 0x01, 0x0114); - ibmcam_veio(uvd, 0, 0xc0, 0x010c); - ibmcam_veio(uvd, 0, 0x00, 0x010c); - ibmcam_send_FF_04_02(uvd); - ibmcam_veio(uvd, 1, 0x00, 0x0100); - ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */ - break; - case IBMCAM_MODEL_2: -case IBMCAM_MODEL_4: - ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop the camera */ - - ibmcam_model2_Packet1(uvd, 0x0030, 0x0004); - - ibmcam_veio(uvd, 0, 0x0080, 0x0100); /* LED Off */ - ibmcam_veio(uvd, 0, 0x0020, 0x0111); - ibmcam_veio(uvd, 0, 0x00a0, 0x0111); - - ibmcam_model2_Packet1(uvd, 0x0030, 0x0002); - - ibmcam_veio(uvd, 0, 0x0020, 0x0111); - ibmcam_veio(uvd, 0, 0x0000, 0x0112); - break; - case IBMCAM_MODEL_3: -#if 1 - ibmcam_veio(uvd, 0, 0x0000, 0x010c); - - /* Here we are supposed to select video interface alt. setting 0 */ - ibmcam_veio(uvd, 0, 0x0006, 0x012c); - - ibmcam_model3_Packet1(uvd, 0x0046, 0x0000); - - ibmcam_veio(uvd, 1, 0x0000, 0x0116); - ibmcam_veio(uvd, 0, 0x0064, 0x0116); - ibmcam_veio(uvd, 1, 0x0000, 0x0115); - ibmcam_veio(uvd, 0, 0x0003, 0x0115); - ibmcam_veio(uvd, 0, 0x0008, 0x0123); - ibmcam_veio(uvd, 0, 0x0000, 0x0117); - ibmcam_veio(uvd, 0, 0x0000, 0x0112); - ibmcam_veio(uvd, 0, 0x0080, 0x0100); - IBMCAM_T(uvd)->initialized = 0; -#endif - break; - } /* switch */ -} - -/* - * ibmcam_reinit_iso() - * - * This procedure sends couple of commands to the camera and then - * resets the video pipe. This sequence was observed to reinit the - * camera or, at least, to initiate ISO data stream. - * - * History: - * 1/2/00 Created. - */ -static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop) -{ - switch (IBMCAM_T(uvd)->camera_model) { - case IBMCAM_MODEL_1: - if (do_stop) - ibmcam_video_stop(uvd); - ibmcam_veio(uvd, 0, 0x0001, 0x0114); - ibmcam_veio(uvd, 0, 0x00c0, 0x010c); - usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp)); - ibmcam_model1_setup_after_video_if(uvd); - break; - case IBMCAM_MODEL_2: - ibmcam_model2_setup_after_video_if(uvd); - break; - case IBMCAM_MODEL_3: - ibmcam_video_stop(uvd); - ibmcam_model3_setup_after_video_if(uvd); - break; - case IBMCAM_MODEL_4: - ibmcam_model4_setup_after_video_if(uvd); - break; - } -} - -static void ibmcam_video_start(struct uvd *uvd) -{ - ibmcam_change_lighting_conditions(uvd); - ibmcam_set_sharpness(uvd); - ibmcam_reinit_iso(uvd, 0); -} - -/* - * Return negative code on failure, 0 on success. - */ -static int ibmcam_setup_on_open(struct uvd *uvd) -{ - int setup_ok = 0; /* Success by default */ - /* Send init sequence only once, it's large! */ - if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */ - switch (IBMCAM_T(uvd)->camera_model) { - case IBMCAM_MODEL_1: - setup_ok = ibmcam_model1_setup(uvd); - break; - case IBMCAM_MODEL_2: - setup_ok = ibmcam_model2_setup(uvd); - break; - case IBMCAM_MODEL_3: - case IBMCAM_MODEL_4: - /* We do all setup when Isoc stream is requested */ - break; - } - IBMCAM_T(uvd)->initialized = (setup_ok != 0); - } - return setup_ok; -} - -static void ibmcam_configure_video(struct uvd *uvd) -{ - if (uvd == NULL) - return; - - RESTRICT_TO_RANGE(init_brightness, 0, 255); - RESTRICT_TO_RANGE(init_contrast, 0, 255); - RESTRICT_TO_RANGE(init_color, 0, 255); - RESTRICT_TO_RANGE(init_hue, 0, 255); - RESTRICT_TO_RANGE(hue_correction, 0, 255); - - memset(&uvd->vpic, 0, sizeof(uvd->vpic)); - memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); - - uvd->vpic.colour = init_color << 8; - uvd->vpic.hue = init_hue << 8; - uvd->vpic.brightness = init_brightness << 8; - uvd->vpic.contrast = init_contrast << 8; - uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ - uvd->vpic.depth = 24; - uvd->vpic.palette = VIDEO_PALETTE_RGB24; - - memset(&uvd->vcap, 0, sizeof(uvd->vcap)); - strcpy(uvd->vcap.name, "IBM USB Camera"); - uvd->vcap.type = VID_TYPE_CAPTURE; - uvd->vcap.channels = 1; - uvd->vcap.audios = 0; - uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); - uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); - uvd->vcap.minwidth = min_canvasWidth; - uvd->vcap.minheight = min_canvasHeight; - - memset(&uvd->vchan, 0, sizeof(uvd->vchan)); - uvd->vchan.flags = 0; - uvd->vchan.tuners = 0; - uvd->vchan.channel = 0; - uvd->vchan.type = VIDEO_TYPE_CAMERA; - strcpy(uvd->vchan.name, "Camera"); -} - -/* - * ibmcam_probe() - * - * This procedure queries device descriptor and accepts the interface - * if it looks like IBM C-it camera. - * - * History: - * 22-Jan-2000 Moved camera init code to ibmcam_open() - * 27=Jan-2000 Changed to use static structures, added locking. - * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). - * 03-Jul-2000 Fixed endianness bug. - * 12-Nov-2000 Reworked to comply with new probe() signature. - * 23-Jan-2001 Added compatibility with 2.2.x kernels. - */ -static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct uvd *uvd = NULL; - int ix, i, nas, model=0, canvasX=0, canvasY=0; - int actInterface=-1, inactInterface=-1, maxPS=0; - __u8 ifnum = intf->altsetting->desc.bInterfaceNumber; - unsigned char video_ep = 0; - - if (debug >= 1) - info("ibmcam_probe(%p,%u.)", intf, ifnum); - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - /* Check the version/revision */ - switch (le16_to_cpu(dev->descriptor.bcdDevice)) { - case 0x0002: - if (ifnum != 2) - return -ENODEV; - model = IBMCAM_MODEL_1; - break; - case 0x030A: - if (ifnum != 0) - return -ENODEV; - if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) || - (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID)) - model = IBMCAM_MODEL_4; - else - model = IBMCAM_MODEL_2; - break; - case 0x0301: - if (ifnum != 0) - return -ENODEV; - model = IBMCAM_MODEL_3; - break; - default: - err("IBM camera with revision 0x%04x is not supported.", - le16_to_cpu(dev->descriptor.bcdDevice)); - return -ENODEV; - } - - /* Print detailed info on what we found so far */ - do { - char *brand = NULL; - switch (le16_to_cpu(dev->descriptor.idProduct)) { - case NETCAM_PRODUCT_ID: - brand = "IBM NetCamera"; - break; - case VEO_800C_PRODUCT_ID: - brand = "Veo Stingray [800C]"; - break; - case VEO_800D_PRODUCT_ID: - brand = "Veo Stingray [800D]"; - break; - case IBMCAM_PRODUCT_ID: - default: - brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */ - break; - } - info("%s USB camera found (model %d, rev. 0x%04x)", - brand, model, le16_to_cpu(dev->descriptor.bcdDevice)); - } while (0); - - /* Validate found interface: must have one ISO endpoint */ - nas = intf->num_altsetting; - if (debug > 0) - info("Number of alternate settings=%d.", nas); - if (nas < 2) { - err("Too few alternate settings for this camera!"); - return -ENODEV; - } - /* Validate all alternate settings */ - for (ix=0; ix < nas; ix++) { - const struct usb_host_interface *interface; - const struct usb_endpoint_descriptor *endpoint; - - interface = &intf->altsetting[ix]; - i = interface->desc.bAlternateSetting; - if (interface->desc.bNumEndpoints != 1) { - err("Interface %d. has %u. endpoints!", - ifnum, (unsigned)(interface->desc.bNumEndpoints)); - return -ENODEV; - } - endpoint = &interface->endpoint[0].desc; - if (video_ep == 0) - video_ep = endpoint->bEndpointAddress; - else if (video_ep != endpoint->bEndpointAddress) { - err("Alternate settings have different endpoint addresses!"); - return -ENODEV; - } - if ((endpoint->bmAttributes & 0x03) != 0x01) { - err("Interface %d. has non-ISO endpoint!", ifnum); - return -ENODEV; - } - if ((endpoint->bEndpointAddress & 0x80) == 0) { - err("Interface %d. has ISO OUT endpoint!", ifnum); - return -ENODEV; - } - if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { - if (inactInterface < 0) - inactInterface = i; - else { - err("More than one inactive alt. setting!"); - return -ENODEV; - } - } else { - if (actInterface < 0) { - actInterface = i; - maxPS = le16_to_cpu(endpoint->wMaxPacketSize); - if (debug > 0) - info("Active setting=%d. maxPS=%d.", i, maxPS); - } else - err("More than one active alt. setting! Ignoring #%d.", i); - } - } - if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { - err("Failed to recognize the camera!"); - return -ENODEV; - } - - /* Validate options */ - switch (model) { - case IBMCAM_MODEL_1: - RESTRICT_TO_RANGE(lighting, 0, 2); - RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288); - if (framerate < 0) - framerate = 2; - canvasX = 352; - canvasY = 288; - break; - case IBMCAM_MODEL_2: - RESTRICT_TO_RANGE(lighting, 0, 15); - RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240); - if (framerate < 0) - framerate = 2; - canvasX = 352; - canvasY = 240; - break; - case IBMCAM_MODEL_3: - RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */ - switch (size) { - case SIZE_160x120: - canvasX = 160; - canvasY = 120; - if (framerate < 0) - framerate = 2; - RESTRICT_TO_RANGE(framerate, 0, 5); - break; - default: - info("IBM camera: using 320x240"); - size = SIZE_320x240; - /* No break here */ - case SIZE_320x240: - canvasX = 320; - canvasY = 240; - if (framerate < 0) - framerate = 3; - RESTRICT_TO_RANGE(framerate, 0, 5); - break; - case SIZE_640x480: - canvasX = 640; - canvasY = 480; - framerate = 0; /* Slowest, and maybe even that is too fast */ - break; - } - break; - case IBMCAM_MODEL_4: - RESTRICT_TO_RANGE(lighting, 0, 2); - switch (size) { - case SIZE_128x96: - canvasX = 128; - canvasY = 96; - break; - case SIZE_160x120: - canvasX = 160; - canvasY = 120; - break; - default: - info("IBM NetCamera: using 176x144"); - size = SIZE_176x144; - /* No break here */ - case SIZE_176x144: - canvasX = 176; - canvasY = 144; - break; - case SIZE_320x240: - canvasX = 320; - canvasY = 240; - break; - case SIZE_352x288: - canvasX = 352; - canvasY = 288; - break; - } - break; - default: - err("IBM camera: Model %d. not supported!", model); - return -ENODEV; - } - - uvd = usbvideo_AllocateDevice(cams); - if (uvd != NULL) { - /* Here uvd is a fully allocated uvd object */ - uvd->flags = flags; - uvd->debug = debug; - uvd->dev = dev; - uvd->iface = ifnum; - uvd->ifaceAltInactive = inactInterface; - uvd->ifaceAltActive = actInterface; - uvd->video_endp = video_ep; - uvd->iso_packet_len = maxPS; - uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; - uvd->defaultPalette = VIDEO_PALETTE_RGB24; - uvd->canvas = VIDEOSIZE(canvasX, canvasY); - uvd->videosize = ibmcam_size_to_videosize(size); - - /* Initialize ibmcam-specific data */ - assert(IBMCAM_T(uvd) != NULL); - IBMCAM_T(uvd)->camera_model = model; - IBMCAM_T(uvd)->initialized = 0; - - ibmcam_configure_video(uvd); - - i = usbvideo_RegisterVideoDevice(uvd); - if (i != 0) { - err("usbvideo_RegisterVideoDevice() failed."); - uvd = NULL; - } - } - usb_set_intfdata (intf, uvd); - return 0; -} - - -static struct usb_device_id id_table[] = { - { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) }, /* Model 1 */ - { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */ - { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) }, /* Model 3 */ - { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */ - { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */ - { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */ - { } /* Terminating entry */ -}; - -/* - * ibmcam_init() - * - * This code is run to initialize the driver. - * - * History: - * 1/27/00 Reworked to use statically allocated ibmcam structures. - * 21/10/00 Completely redesigned to use usbvideo services. - */ -static int __init ibmcam_init(void) -{ - struct usbvideo_cb cbTbl; - memset(&cbTbl, 0, sizeof(cbTbl)); - cbTbl.probe = ibmcam_probe; - cbTbl.setupOnOpen = ibmcam_setup_on_open; - cbTbl.videoStart = ibmcam_video_start; - cbTbl.videoStop = ibmcam_video_stop; - cbTbl.processData = ibmcam_ProcessIsocData; - cbTbl.postProcess = usbvideo_DeinterlaceFrame; - cbTbl.adjustPicture = ibmcam_adjust_picture; - cbTbl.getFPS = ibmcam_calculate_fps; - return usbvideo_register( - &cams, - MAX_IBMCAM, - sizeof(ibmcam_t), - "ibmcam", - &cbTbl, - THIS_MODULE, - id_table); -} - -static void __exit ibmcam_cleanup(void) -{ - usbvideo_Deregister(&cams); -} - -MODULE_DEVICE_TABLE(usb, id_table); - -module_init(ibmcam_init); -module_exit(ibmcam_cleanup); diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c deleted file mode 100644 index e2ede583518f..000000000000 --- a/drivers/usb/media/konicawc.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - * konicawc.c - konica webcam driver - * - * Author: Simon Evans - * - * Copyright (C) 2002 Simon Evans - * - * Licence: GPL - * - * Driver for USB webcams based on Konica chipset. This - * chipset is used in Intel YC76 camera. - * - */ - -#include -#include -#include -#include -#include - -#include "usbvideo.h" - -#define MAX_BRIGHTNESS 108 -#define MAX_CONTRAST 108 -#define MAX_SATURATION 108 -#define MAX_SHARPNESS 108 -#define MAX_WHITEBAL 372 -#define MAX_SPEED 6 - - -#define MAX_CAMERAS 1 - -#define DRIVER_VERSION "v1.4" -#define DRIVER_DESC "Konica Webcam driver" - -enum ctrl_req { - SetWhitebal = 0x01, - SetBrightness = 0x02, - SetSharpness = 0x03, - SetContrast = 0x04, - SetSaturation = 0x05, -}; - - -enum frame_sizes { - SIZE_160X120 = 0, - SIZE_160X136 = 1, - SIZE_176X144 = 2, - SIZE_320X240 = 3, - -}; - -#define MAX_FRAME_SIZE SIZE_320X240 - -static struct usbvideo *cams; - -#ifdef CONFIG_USB_DEBUG -static int debug; -#define DEBUG(n, format, arg...) \ - if (n <= debug) { \ - printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \ - } -#else -#define DEBUG(n, arg...) -static const int debug = 0; -#endif - - -/* Some default values for initial camera settings, - can be set by modprobe */ - -static int size; -static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */ -static int brightness = MAX_BRIGHTNESS/2; -static int contrast = MAX_CONTRAST/2; -static int saturation = MAX_SATURATION/2; -static int sharpness = MAX_SHARPNESS/2; -static int whitebal = 3*(MAX_WHITEBAL/4); - -static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 }; - -/* These FPS speeds are from the windows config box. They are - * indexed on size (0-2) and speed (0-6). Divide by 3 to get the - * real fps. - */ - -static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 }, - { 24, 40, 48, 60, 72, 80, 100 }, - { 18, 30, 36, 45, 54, 60, 75 }, - { 6, 10, 12, 15, 18, 21, 25 } }; - -struct cam_size { - u16 width; - u16 height; - u8 cmd; -}; - -static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 }, - { 160, 136, 0xa }, - { 176, 144, 0x4 }, - { 320, 240, 0x5 } }; - -struct konicawc { - u8 brightness; /* camera uses 0 - 9, x11 for real value */ - u8 contrast; /* as above */ - u8 saturation; /* as above */ - u8 sharpness; /* as above */ - u8 white_bal; /* 0 - 33, x11 for real value */ - u8 speed; /* Stored as 0 - 6, used as index in spd_to_* (above) */ - u8 size; /* Frame Size */ - int height; - int width; - struct urb *sts_urb[USBVIDEO_NUMSBUF]; - u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC]; - struct urb *last_data_urb; - int lastframe; - int cur_frame_size; /* number of bytes in current frame size */ - int maxline; /* number of lines per frame */ - int yplanesz; /* Number of bytes in the Y plane */ - unsigned int buttonsts:1; -#ifdef CONFIG_INPUT - struct input_dev *input; - char input_physname[64]; -#endif -}; - - -#define konicawc_set_misc(uvd, req, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0) -#define konicawc_get_misc(uvd, req, value, index, buf, sz) konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz) -#define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0) - - -static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len) -{ - int retval = usb_control_msg(uvd->dev, - dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0), - request, 0x40 | dir, value, index, buf, len, 1000); - return retval < 0 ? retval : 0; -} - - -static inline void konicawc_camera_on(struct uvd *uvd) -{ - DEBUG(0, "camera on"); - konicawc_set_misc(uvd, 0x2, 1, 0x0b); -} - - -static inline void konicawc_camera_off(struct uvd *uvd) -{ - DEBUG(0, "camera off"); - konicawc_set_misc(uvd, 0x2, 0, 0x0b); -} - - -static void konicawc_set_camera_size(struct uvd *uvd) -{ - struct konicawc *cam = (struct konicawc *)uvd->user_data; - - konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08); - cam->width = camera_sizes[cam->size].width; - cam->height = camera_sizes[cam->size].height; - cam->yplanesz = cam->height * cam->width; - cam->cur_frame_size = (cam->yplanesz * 3) / 2; - cam->maxline = cam->yplanesz / 256; - uvd->videosize = VIDEOSIZE(cam->width, cam->height); -} - - -static int konicawc_setup_on_open(struct uvd *uvd) -{ - struct konicawc *cam = (struct konicawc *)uvd->user_data; - - DEBUG(1, "setting brightness to %d (%d)", cam->brightness, - cam->brightness * 11); - konicawc_set_value(uvd, cam->brightness, SetBrightness); - DEBUG(1, "setting white balance to %d (%d)", cam->white_bal, - cam->white_bal * 11); - konicawc_set_value(uvd, cam->white_bal, SetWhitebal); - DEBUG(1, "setting contrast to %d (%d)", cam->contrast, - cam->contrast * 11); - konicawc_set_value(uvd, cam->contrast, SetContrast); - DEBUG(1, "setting saturation to %d (%d)", cam->saturation, - cam->saturation * 11); - konicawc_set_value(uvd, cam->saturation, SetSaturation); - DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness, - cam->sharpness * 11); - konicawc_set_value(uvd, cam->sharpness, SetSharpness); - konicawc_set_camera_size(uvd); - cam->lastframe = -2; - cam->buttonsts = 0; - return 0; -} - - -static void konicawc_adjust_picture(struct uvd *uvd) -{ - struct konicawc *cam = (struct konicawc *)uvd->user_data; - - konicawc_camera_off(uvd); - DEBUG(1, "new brightness: %d", uvd->vpic.brightness); - uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness; - if(cam->brightness != uvd->vpic.brightness / 11) { - cam->brightness = uvd->vpic.brightness / 11; - DEBUG(1, "setting brightness to %d (%d)", cam->brightness, - cam->brightness * 11); - konicawc_set_value(uvd, cam->brightness, SetBrightness); - } - - DEBUG(1, "new contrast: %d", uvd->vpic.contrast); - uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast; - if(cam->contrast != uvd->vpic.contrast / 11) { - cam->contrast = uvd->vpic.contrast / 11; - DEBUG(1, "setting contrast to %d (%d)", cam->contrast, - cam->contrast * 11); - konicawc_set_value(uvd, cam->contrast, SetContrast); - } - konicawc_camera_on(uvd); -} - -#ifdef CONFIG_INPUT - -static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) -{ - struct input_dev *input_dev; - - usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname)); - strncat(cam->input_physname, "/input0", sizeof(cam->input_physname)); - - cam->input = input_dev = input_allocate_device(); - if (!input_dev) { - warn("Not enough memory for camera's input device\n"); - return; - } - - input_dev->name = "Konicawc snapshot button"; - input_dev->phys = cam->input_physname; - usb_to_input_id(dev, &input_dev->id); - input_dev->cdev.dev = &dev->dev; - - input_dev->evbit[0] = BIT(EV_KEY); - input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); - - input_dev->private = cam; - - input_register_device(cam->input); -} - -static void konicawc_unregister_input(struct konicawc *cam) -{ - if (cam->input) { - input_unregister_device(cam->input); - cam->input = NULL; - } -} - -static void konicawc_report_buttonstat(struct konicawc *cam) -{ - if (cam->input) { - input_report_key(cam->input, BTN_0, cam->buttonsts); - input_sync(cam->input); - } -} - -#else - -static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { } -static inline void konicawc_unregister_input(struct konicawc *cam) { } -static inline void konicawc_report_buttonstat(struct konicawc *cam) { } - -#endif /* CONFIG_INPUT */ - -static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb) -{ - char *cdata; - int i, totlen = 0; - unsigned char *status = stsurb->transfer_buffer; - int keep = 0, discard = 0, bad = 0; - struct konicawc *cam = (struct konicawc *)uvd->user_data; - - for (i = 0; i < dataurb->number_of_packets; i++) { - int button = cam->buttonsts; - unsigned char sts; - int n = dataurb->iso_frame_desc[i].actual_length; - int st = dataurb->iso_frame_desc[i].status; - cdata = dataurb->transfer_buffer + - dataurb->iso_frame_desc[i].offset; - - /* Detect and ignore errored packets */ - if (st < 0) { - DEBUG(1, "Data error: packet=%d. len=%d. status=%d.", - i, n, st); - uvd->stats.iso_err_count++; - continue; - } - - /* Detect and ignore empty packets */ - if (n <= 0) { - uvd->stats.iso_skip_count++; - continue; - } - - /* See what the status data said about the packet */ - sts = *(status+stsurb->iso_frame_desc[i].offset); - - /* sts: 0x80-0xff: frame start with frame number (ie 0-7f) - * otherwise: - * bit 0 0: keep packet - * 1: drop packet (padding data) - * - * bit 4 0 button not clicked - * 1 button clicked - * button is used to `take a picture' (in software) - */ - - if(sts < 0x80) { - button = !!(sts & 0x40); - sts &= ~0x40; - } - - /* work out the button status, but don't do - anything with it for now */ - - if(button != cam->buttonsts) { - DEBUG(2, "button: %sclicked", button ? "" : "un"); - cam->buttonsts = button; - konicawc_report_buttonstat(cam); - } - - if(sts == 0x01) { /* drop frame */ - discard++; - continue; - } - - if((sts > 0x01) && (sts < 0x80)) { - info("unknown status %2.2x", sts); - bad++; - continue; - } - if(!sts && cam->lastframe == -2) { - DEBUG(2, "dropping frame looking for image start"); - continue; - } - - keep++; - if(sts & 0x80) { /* frame start */ - unsigned char marker[] = { 0, 0xff, 0, 0x00 }; - - if(cam->lastframe == -2) { - DEBUG(2, "found initial image"); - cam->lastframe = -1; - } - - marker[3] = sts & 0x7F; - RingQueue_Enqueue(&uvd->dp, marker, 4); - totlen += 4; - } - - totlen += n; /* Little local accounting */ - RingQueue_Enqueue(&uvd->dp, cdata, n); - } - DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes", - keep, discard, bad, totlen); - return totlen; -} - - -static void resubmit_urb(struct uvd *uvd, struct urb *urb) -{ - int i, ret; - for (i = 0; i < FRAMES_PER_DESC; i++) { - urb->iso_frame_desc[i].status = 0; - } - urb->dev = uvd->dev; - urb->status = 0; - ret = usb_submit_urb(urb, GFP_ATOMIC); - DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length); - if(ret) - err("usb_submit_urb error (%d)", ret); - -} - - -static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs) -{ - struct uvd *uvd = urb->context; - struct konicawc *cam = (struct konicawc *)uvd->user_data; - - /* We don't want to do anything if we are about to be removed! */ - if (!CAMERA_IS_OPERATIONAL(uvd)) - return; - - if (!uvd->streaming) { - DEBUG(1, "Not streaming, but interrupt!"); - return; - } - - DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length); - - uvd->stats.urb_count++; - - if (urb->transfer_buffer_length > 32) { - cam->last_data_urb = urb; - return; - } - /* Copy the data received into ring queue */ - if(cam->last_data_urb) { - int len = 0; - if(urb->start_frame != cam->last_data_urb->start_frame) - err("Lost sync on frames"); - else if (!urb->status && !cam->last_data_urb->status) - len = konicawc_compress_iso(uvd, cam->last_data_urb, urb); - - resubmit_urb(uvd, cam->last_data_urb); - resubmit_urb(uvd, urb); - cam->last_data_urb = NULL; - uvd->stats.urb_length = len; - uvd->stats.data_count += len; - if(len) - RingQueue_WakeUpInterruptible(&uvd->dp); - return; - } - return; -} - - -static int konicawc_start_data(struct uvd *uvd) -{ - struct usb_device *dev = uvd->dev; - int i, errFlag; - struct konicawc *cam = (struct konicawc *)uvd->user_data; - int pktsz; - struct usb_interface *intf; - struct usb_host_interface *interface = NULL; - - intf = usb_ifnum_to_if(dev, uvd->iface); - if (intf) - interface = usb_altnum_to_altsetting(intf, - spd_to_iface[cam->speed]); - if (!interface) - return -ENXIO; - pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize); - DEBUG(1, "pktsz = %d", pktsz); - if (!CAMERA_IS_OPERATIONAL(uvd)) { - err("Camera is not operational"); - return -EFAULT; - } - uvd->curframe = -1; - konicawc_camera_on(uvd); - /* Alternate interface 1 is is the biggest frame size */ - i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); - if (i < 0) { - err("usb_set_interface error"); - uvd->last_error = i; - return -EBUSY; - } - - /* We double buffer the Iso lists */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - int j, k; - struct urb *urb = uvd->sbuf[i].urb; - urb->dev = dev; - urb->context = uvd; - urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); - urb->interval = 1; - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = uvd->sbuf[i].data; - urb->complete = konicawc_isoc_irq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC; - for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = pktsz; - } - - urb = cam->sts_urb[i]; - urb->dev = dev; - urb->context = uvd; - urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1); - urb->interval = 1; - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = cam->sts_buf[i]; - urb->complete = konicawc_isoc_irq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = FRAMES_PER_DESC; - for (j=0; j < FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j; - urb->iso_frame_desc[j].length = 1; - } - } - - cam->last_data_urb = NULL; - - /* Submit all URBs */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL); - if (errFlag) - err("usb_submit_isoc(%d) ret %d", i, errFlag); - - errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); - if (errFlag) - err ("usb_submit_isoc(%d) ret %d", i, errFlag); - } - - uvd->streaming = 1; - DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp); - return 0; -} - - -static void konicawc_stop_data(struct uvd *uvd) -{ - int i, j; - struct konicawc *cam; - - if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) - return; - - konicawc_camera_off(uvd); - uvd->streaming = 0; - cam = (struct konicawc *)uvd->user_data; - cam->last_data_urb = NULL; - - /* Unschedule all of the iso td's */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - usb_kill_urb(uvd->sbuf[i].urb); - usb_kill_urb(cam->sts_urb[i]); - } - - if (!uvd->remove_pending) { - /* Set packet size to 0 */ - j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); - if (j < 0) { - err("usb_set_interface() error %d.", j); - uvd->last_error = j; - } - } -} - - -static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame) -{ - struct konicawc *cam = (struct konicawc *)uvd->user_data; - int maxline = cam->maxline; - int yplanesz = cam->yplanesz; - - assert(frame != NULL); - - DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz); - DEBUG(3, "Frame state = %d", frame->scanstate); - - if(frame->scanstate == ScanState_Scanning) { - int drop = 0; - int curframe; - int fdrops = 0; - DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp)); - while(RingQueue_GetLength(&uvd->dp) >= 4) { - if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) && - (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) && - (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) && - (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) { - curframe = RING_QUEUE_PEEK(&uvd->dp, 3); - if(cam->lastframe >= 0) { - fdrops = (0x80 + curframe - cam->lastframe) & 0x7F; - fdrops--; - if(fdrops) { - info("Dropped %d frames (%d -> %d)", fdrops, - cam->lastframe, curframe); - } - } - cam->lastframe = curframe; - frame->curline = 0; - frame->scanstate = ScanState_Lines; - RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4); - break; - } - RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1); - drop++; - } - if(drop) - DEBUG(2, "dropped %d bytes looking for new frame", drop); - } - - if(frame->scanstate == ScanState_Scanning) - return; - - /* Try to move data from queue into frame buffer - * We get data in blocks of 384 bytes made up of: - * 256 Y, 64 U, 64 V. - * This needs to be written out as a Y plane, a U plane and a V plane. - */ - - while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) { - /* Y */ - RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256); - /* U */ - RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64); - /* V */ - RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64); - frame->seqRead_Length += 384; - frame->curline++; - } - /* See if we filled the frame */ - if (frame->curline == maxline) { - DEBUG(5, "got whole frame"); - - frame->frameState = FrameState_Done_Hold; - frame->curline = 0; - uvd->curframe = -1; - uvd->stats.frame_num++; - } -} - - -static int konicawc_find_fps(int size, int fps) -{ - int i; - - fps *= 3; - DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps); - if(fps <= spd_to_fps[size][0]) - return 0; - - if(fps >= spd_to_fps[size][MAX_SPEED]) - return MAX_SPEED; - - for(i = 0; i < MAX_SPEED; i++) { - if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) { - DEBUG(2, "fps %d between %d and %d", fps, i, i+1); - if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps)) - return i; - else - return i+1; - } - } - return MAX_SPEED+1; -} - - -static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw) -{ - struct konicawc *cam = (struct konicawc *)uvd->user_data; - int newspeed = cam->speed; - int newsize; - int x = vw->width; - int y = vw->height; - int fps = vw->flags; - - if(x > 0 && y > 0) { - DEBUG(2, "trying to find size %d,%d", x, y); - for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) { - if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y)) - break; - } - } else { - newsize = cam->size; - } - - if(newsize > MAX_FRAME_SIZE) { - DEBUG(1, "couldn't find size %d,%d", x, y); - return -EINVAL; - } - - if(fps > 0) { - DEBUG(1, "trying to set fps to %d", fps); - newspeed = konicawc_find_fps(newsize, fps); - DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]); - } - - if(newspeed > MAX_SPEED) - return -EINVAL; - - DEBUG(1, "setting size to %d speed to %d", newsize, newspeed); - if((newsize == cam->size) && (newspeed == cam->speed)) { - DEBUG(1, "Nothing to do"); - return 0; - } - DEBUG(0, "setting to %dx%d @ %d fps", camera_sizes[newsize].width, - camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3); - - konicawc_stop_data(uvd); - uvd->ifaceAltActive = spd_to_iface[newspeed]; - DEBUG(1, "new interface = %d", uvd->ifaceAltActive); - cam->speed = newspeed; - - if(cam->size != newsize) { - cam->size = newsize; - konicawc_set_camera_size(uvd); - } - - /* Flush the input queue and clear any current frame in progress */ - - RingQueue_Flush(&uvd->dp); - cam->lastframe = -2; - if(uvd->curframe != -1) { - uvd->frame[uvd->curframe].curline = 0; - uvd->frame[uvd->curframe].seqRead_Length = 0; - uvd->frame[uvd->curframe].seqRead_Index = 0; - } - - konicawc_start_data(uvd); - return 0; -} - - -static int konicawc_calculate_fps(struct uvd *uvd) -{ - struct konicawc *cam = uvd->user_data; - return spd_to_fps[cam->size][cam->speed]/3; -} - - -static void konicawc_configure_video(struct uvd *uvd) -{ - struct konicawc *cam = (struct konicawc *)uvd->user_data; - u8 buf[2]; - - memset(&uvd->vpic, 0, sizeof(uvd->vpic)); - memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); - - RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS); - RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST); - RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION); - RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS); - RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL); - - cam->brightness = brightness / 11; - cam->contrast = contrast / 11; - cam->saturation = saturation / 11; - cam->sharpness = sharpness / 11; - cam->white_bal = whitebal / 11; - - uvd->vpic.colour = 108; - uvd->vpic.hue = 108; - uvd->vpic.brightness = brightness; - uvd->vpic.contrast = contrast; - uvd->vpic.whiteness = whitebal; - uvd->vpic.depth = 6; - uvd->vpic.palette = VIDEO_PALETTE_YUV420P; - - memset(&uvd->vcap, 0, sizeof(uvd->vcap)); - strcpy(uvd->vcap.name, "Konica Webcam"); - uvd->vcap.type = VID_TYPE_CAPTURE; - uvd->vcap.channels = 1; - uvd->vcap.audios = 0; - uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width; - uvd->vcap.minheight = camera_sizes[SIZE_160X120].height; - uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width; - uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height; - - memset(&uvd->vchan, 0, sizeof(uvd->vchan)); - uvd->vchan.flags = 0 ; - uvd->vchan.tuners = 0; - uvd->vchan.channel = 0; - uvd->vchan.type = VIDEO_TYPE_CAMERA; - strcpy(uvd->vchan.name, "Camera"); - - /* Talk to device */ - DEBUG(1, "device init"); - if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2)) - DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]); - if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2)) - DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]); - if(konicawc_set_misc(uvd, 0x2, 0, 0xd)) - DEBUG(2, "2,0,d failed"); - DEBUG(1, "setting initial values"); -} - -static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct uvd *uvd = NULL; - int ix, i, nas; - int actInterface=-1, inactInterface=-1, maxPS=0; - unsigned char video_ep = 0; - - DEBUG(1, "konicawc_probe(%p)", intf); - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice)); - RESTRICT_TO_RANGE(speed, 0, MAX_SPEED); - - /* Validate found interface: must have one ISO endpoint */ - nas = intf->num_altsetting; - if (nas != 8) { - err("Incorrect number of alternate settings (%d) for this camera!", nas); - return -ENODEV; - } - /* Validate all alternate settings */ - for (ix=0; ix < nas; ix++) { - const struct usb_host_interface *interface; - const struct usb_endpoint_descriptor *endpoint; - - interface = &intf->altsetting[ix]; - i = interface->desc.bAlternateSetting; - if (interface->desc.bNumEndpoints != 2) { - err("Interface %d. has %u. endpoints!", - interface->desc.bInterfaceNumber, - (unsigned)(interface->desc.bNumEndpoints)); - return -ENODEV; - } - endpoint = &interface->endpoint[1].desc; - DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x", - endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize)); - if (video_ep == 0) - video_ep = endpoint->bEndpointAddress; - else if (video_ep != endpoint->bEndpointAddress) { - err("Alternate settings have different endpoint addresses!"); - return -ENODEV; - } - if ((endpoint->bmAttributes & 0x03) != 0x01) { - err("Interface %d. has non-ISO endpoint!", - interface->desc.bInterfaceNumber); - return -ENODEV; - } - if ((endpoint->bEndpointAddress & 0x80) == 0) { - err("Interface %d. has ISO OUT endpoint!", - interface->desc.bInterfaceNumber); - return -ENODEV; - } - if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { - if (inactInterface < 0) - inactInterface = i; - else { - err("More than one inactive alt. setting!"); - return -ENODEV; - } - } else { - if (i == spd_to_iface[speed]) { - /* This one is the requested one */ - actInterface = i; - } - } - if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS) - maxPS = le16_to_cpu(endpoint->wMaxPacketSize); - } - if(actInterface == -1) { - err("Cant find required endpoint"); - return -ENODEV; - } - - DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS); - - uvd = usbvideo_AllocateDevice(cams); - if (uvd != NULL) { - struct konicawc *cam = (struct konicawc *)(uvd->user_data); - /* Here uvd is a fully allocated uvd object */ - for(i = 0; i < USBVIDEO_NUMSBUF; i++) { - cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); - if(cam->sts_urb[i] == NULL) { - while(i--) { - usb_free_urb(cam->sts_urb[i]); - } - err("can't allocate urbs"); - return -ENOMEM; - } - } - cam->speed = speed; - RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240); - cam->width = camera_sizes[size].width; - cam->height = camera_sizes[size].height; - cam->size = size; - - uvd->flags = 0; - uvd->debug = debug; - uvd->dev = dev; - uvd->iface = intf->altsetting->desc.bInterfaceNumber; - uvd->ifaceAltInactive = inactInterface; - uvd->ifaceAltActive = actInterface; - uvd->video_endp = video_ep; - uvd->iso_packet_len = maxPS; - uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P; - uvd->defaultPalette = VIDEO_PALETTE_YUV420P; - uvd->canvas = VIDEOSIZE(320, 240); - uvd->videosize = VIDEOSIZE(cam->width, cam->height); - - /* Initialize konicawc specific data */ - konicawc_configure_video(uvd); - - i = usbvideo_RegisterVideoDevice(uvd); - uvd->max_frame_size = (320 * 240 * 3)/2; - if (i != 0) { - err("usbvideo_RegisterVideoDevice() failed."); - uvd = NULL; - } - - konicawc_register_input(cam, dev); - } - - if (uvd) { - usb_set_intfdata (intf, uvd); - return 0; - } - return -EIO; -} - - -static void konicawc_free_uvd(struct uvd *uvd) -{ - int i; - struct konicawc *cam = (struct konicawc *)uvd->user_data; - - konicawc_unregister_input(cam); - - for (i = 0; i < USBVIDEO_NUMSBUF; i++) { - usb_free_urb(cam->sts_urb[i]); - cam->sts_urb[i] = NULL; - } -} - - -static struct usb_device_id id_table[] = { - { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */ - { } /* Terminating entry */ -}; - - -static int __init konicawc_init(void) -{ - struct usbvideo_cb cbTbl; - info(DRIVER_DESC " " DRIVER_VERSION); - memset(&cbTbl, 0, sizeof(cbTbl)); - cbTbl.probe = konicawc_probe; - cbTbl.setupOnOpen = konicawc_setup_on_open; - cbTbl.processData = konicawc_process_isoc; - cbTbl.getFPS = konicawc_calculate_fps; - cbTbl.setVideoMode = konicawc_set_video_mode; - cbTbl.startDataPump = konicawc_start_data; - cbTbl.stopDataPump = konicawc_stop_data; - cbTbl.adjustPicture = konicawc_adjust_picture; - cbTbl.userFree = konicawc_free_uvd; - return usbvideo_register( - &cams, - MAX_CAMERAS, - sizeof(struct konicawc), - "konicawc", - &cbTbl, - THIS_MODULE, - id_table); -} - - -static void __exit konicawc_cleanup(void) -{ - usbvideo_Deregister(&cams); -} - - -MODULE_DEVICE_TABLE(usb, id_table); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Simon Evans "); -MODULE_DESCRIPTION(DRIVER_DESC); -module_param(speed, int, 0); -MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)"); -module_param(size, int, 0); -MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240"); -module_param(brightness, int, 0); -MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108"); -module_param(contrast, int, 0); -MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108"); -module_param(saturation, int, 0); -MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108"); -module_param(sharpness, int, 0); -MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108"); -module_param(whitebal, int, 0); -MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363"); - -#ifdef CONFIG_USB_DEBUG -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -#endif - -module_init(konicawc_init); -module_exit(konicawc_cleanup); diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c deleted file mode 100644 index da44579d6f29..000000000000 --- a/drivers/usb/media/ov511.c +++ /dev/null @@ -1,5932 +0,0 @@ -/* - * OmniVision OV511 Camera-to-USB Bridge Driver - * - * Copyright (c) 1999-2003 Mark W. McClelland - * Original decompression code Copyright 1998-2000 OmniVision Technologies - * Many improvements by Bret Wallach - * Color fixes by by Orion Sky Lawlor (2/26/2000) - * Snapshot code by Kevin Moore - * OV7620 fixes by Charl P. Botha - * Changes by Claudio Matsuoka - * Original SAA7111A code by Dave Perks - * URB error messages from pwc driver by Nemosoft - * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox - * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others - * - * Based on the Linux CPiA driver written by Peter Pregler, - * Scott J. Bertin and Johannes Erdfelt. - * - * Please see the file: Documentation/usb/ov511.txt - * and the website at: http://alpha.dyndns.org/ov511 - * for more info. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined (__i386__) - #include -#endif - -#include "ov511.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.64 for Linux 2.5" -#define EMAIL "mark@alpha.dyndns.org" -#define DRIVER_AUTHOR "Mark McClelland & Bret Wallach \ - & Orion Sky Lawlor & Kevin Moore & Charl P. Botha \ - & Claudio Matsuoka " -#define DRIVER_DESC "ov511 USB Camera Driver" - -#define OV511_I2C_RETRIES 3 -#define ENABLE_Y_QUANTABLE 1 -#define ENABLE_UV_QUANTABLE 1 - -#define OV511_MAX_UNIT_VIDEO 16 - -/* Pixel count * bytes per YUV420 pixel (1.5) */ -#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2) - -#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval)) - -/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */ -#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024) - -#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM) - -/********************************************************************** - * Module Parameters - * (See ov511.txt for detailed descriptions of these) - **********************************************************************/ - -/* These variables (and all static globals) default to zero */ -static int autobright = 1; -static int autogain = 1; -static int autoexp = 1; -static int debug; -static int snapshot; -static int cams = 1; -static int compress; -static int testpat; -static int dumppix; -static int led = 1; -static int dump_bridge; -static int dump_sensor; -static int printph; -static int phy = 0x1f; -static int phuv = 0x05; -static int pvy = 0x06; -static int pvuv = 0x06; -static int qhy = 0x14; -static int qhuv = 0x03; -static int qvy = 0x04; -static int qvuv = 0x04; -static int lightfreq; -static int bandingfilter; -static int clockdiv = -1; -static int packetsize = -1; -static int framedrop = -1; -static int fastset; -static int force_palette; -static int backlight; -static int unit_video[OV511_MAX_UNIT_VIDEO]; -static int remove_zeros; -static int mirror; -static int ov518_color; - -module_param(autobright, int, 0); -MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); -module_param(autogain, int, 0); -MODULE_PARM_DESC(autogain, "Sensor automatically changes gain"); -module_param(autoexp, int, 0); -MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure"); -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, - "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); -module_param(snapshot, int, 0); -MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); -module_param(cams, int, 0); -MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); -module_param(compress, int, 0); -MODULE_PARM_DESC(compress, "Turn on compression"); -module_param(testpat, int, 0); -MODULE_PARM_DESC(testpat, - "Replace image with vertical bar testpattern (only partially working)"); -module_param(dumppix, int, 0); -MODULE_PARM_DESC(dumppix, "Dump raw pixel data"); -module_param(led, int, 0); -MODULE_PARM_DESC(led, - "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)"); -module_param(dump_bridge, int, 0); -MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers"); -module_param(dump_sensor, int, 0); -MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers"); -module_param(printph, int, 0); -MODULE_PARM_DESC(printph, "Print frame start/end headers"); -module_param(phy, int, 0); -MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)"); -module_param(phuv, int, 0); -MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)"); -module_param(pvy, int, 0); -MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)"); -module_param(pvuv, int, 0); -MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)"); -module_param(qhy, int, 0); -MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)"); -module_param(qhuv, int, 0); -MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)"); -module_param(qvy, int, 0); -MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)"); -module_param(qvuv, int, 0); -MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)"); -module_param(lightfreq, int, 0); -MODULE_PARM_DESC(lightfreq, - "Light frequency. Set to 50 or 60 Hz, or zero for default settings"); -module_param(bandingfilter, int, 0); -MODULE_PARM_DESC(bandingfilter, - "Enable banding filter (to reduce effects of fluorescent lighting)"); -module_param(clockdiv, int, 0); -MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value"); -module_param(packetsize, int, 0); -MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size"); -module_param(framedrop, int, 0); -MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting"); -module_param(fastset, int, 0); -MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately"); -module_param(force_palette, int, 0); -MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); -module_param(backlight, int, 0); -MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); -static int num_uv; -module_param_array(unit_video, int, &num_uv, 0); -MODULE_PARM_DESC(unit_video, - "Force use of specific minor number(s). 0 is not allowed."); -module_param(remove_zeros, int, 0); -MODULE_PARM_DESC(remove_zeros, - "Remove zero-padding from uncompressed incoming data"); -module_param(mirror, int, 0); -MODULE_PARM_DESC(mirror, "Reverse image horizontally"); -module_param(ov518_color, int, 0); -MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -/********************************************************************** - * Miscellaneous Globals - **********************************************************************/ - -static struct usb_driver ov511_driver; - -/* Number of times to retry a failed I2C transaction. Increase this if you - * are getting "Failed to read sensor ID..." */ -static const int i2c_detect_tries = 5; - -static struct usb_device_id device_table [] = { - { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, - { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) }, - { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) }, - { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) }, - { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, device_table); - -static unsigned char yQuanTable511[] = OV511_YQUANTABLE; -static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE; -static unsigned char yQuanTable518[] = OV518_YQUANTABLE; -static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; - -/********************************************************************** - * Symbolic Names - **********************************************************************/ - -/* Known OV511-based cameras */ -static struct symbolic_list camlist[] = { - { 0, "Generic Camera (no ID)" }, - { 1, "Mustek WCam 3X" }, - { 3, "D-Link DSB-C300" }, - { 4, "Generic OV511/OV7610" }, - { 5, "Puretek PT-6007" }, - { 6, "Lifeview USB Life TV (NTSC)" }, - { 21, "Creative Labs WebCam 3" }, - { 22, "Lifeview USB Life TV (PAL D/K+B/G)" }, - { 36, "Koala-Cam" }, - { 38, "Lifeview USB Life TV (PAL)" }, - { 41, "Samsung Anycam MPC-M10" }, - { 43, "Mtekvision Zeca MV402" }, - { 46, "Suma eON" }, - { 70, "Lifeview USB Life TV (PAL/SECAM)" }, - { 100, "Lifeview RoboCam" }, - { 102, "AverMedia InterCam Elite" }, - { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ - { 134, "Ezonics EZCam II" }, - { 192, "Webeye 2000B" }, - { 253, "Alpha Vision Tech. AlphaCam SE" }, - { -1, NULL } -}; - -/* Video4Linux1 Palettes */ -static struct symbolic_list v4l1_plist[] = { - { VIDEO_PALETTE_GREY, "GREY" }, - { VIDEO_PALETTE_HI240, "HI240" }, - { VIDEO_PALETTE_RGB565, "RGB565" }, - { VIDEO_PALETTE_RGB24, "RGB24" }, - { VIDEO_PALETTE_RGB32, "RGB32" }, - { VIDEO_PALETTE_RGB555, "RGB555" }, - { VIDEO_PALETTE_YUV422, "YUV422" }, - { VIDEO_PALETTE_YUYV, "YUYV" }, - { VIDEO_PALETTE_UYVY, "UYVY" }, - { VIDEO_PALETTE_YUV420, "YUV420" }, - { VIDEO_PALETTE_YUV411, "YUV411" }, - { VIDEO_PALETTE_RAW, "RAW" }, - { VIDEO_PALETTE_YUV422P,"YUV422P" }, - { VIDEO_PALETTE_YUV411P,"YUV411P" }, - { VIDEO_PALETTE_YUV420P,"YUV420P" }, - { VIDEO_PALETTE_YUV410P,"YUV410P" }, - { -1, NULL } -}; - -static struct symbolic_list brglist[] = { - { BRG_OV511, "OV511" }, - { BRG_OV511PLUS, "OV511+" }, - { BRG_OV518, "OV518" }, - { BRG_OV518PLUS, "OV518+" }, - { -1, NULL } -}; - -static struct symbolic_list senlist[] = { - { SEN_OV76BE, "OV76BE" }, - { SEN_OV7610, "OV7610" }, - { SEN_OV7620, "OV7620" }, - { SEN_OV7620AE, "OV7620AE" }, - { SEN_OV6620, "OV6620" }, - { SEN_OV6630, "OV6630" }, - { SEN_OV6630AE, "OV6630AE" }, - { SEN_OV6630AF, "OV6630AF" }, - { SEN_OV8600, "OV8600" }, - { SEN_KS0127, "KS0127" }, - { SEN_KS0127B, "KS0127B" }, - { SEN_SAA7111A, "SAA7111A" }, - { -1, NULL } -}; - -/* URB error codes: */ -static struct symbolic_list urb_errlist[] = { - { -ENOSR, "Buffer error (overrun)" }, - { -EPIPE, "Stalled (device not responding)" }, - { -EOVERFLOW, "Babble (bad cable?)" }, - { -EPROTO, "Bit-stuff error (bad cable?)" }, - { -EILSEQ, "CRC/Timeout" }, - { -ETIMEDOUT, "NAK (device does not respond)" }, - { -1, NULL } -}; - -/********************************************************************** - * Memory management - **********************************************************************/ -static void * -rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void -rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - -/********************************************************************** - * - * Register I/O - * - **********************************************************************/ - -/* Write an OV51x register */ -static int -reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) -{ - int rc; - - PDEBUG(5, "0x%02X:0x%02X", reg, value); - - mutex_lock(&ov->cbuf_lock); - ov->cbuf[0] = value; - rc = usb_control_msg(ov->dev, - usb_sndctrlpipe(ov->dev, 0), - (ov->bclass == BCL_OV518)?1:2 /* REG_IO */, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, (__u16)reg, &ov->cbuf[0], 1, 1000); - mutex_unlock(&ov->cbuf_lock); - - if (rc < 0) - err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc)); - - return rc; -} - -/* Read from an OV51x register */ -/* returns: negative is error, pos or zero is data */ -static int -reg_r(struct usb_ov511 *ov, unsigned char reg) -{ - int rc; - - mutex_lock(&ov->cbuf_lock); - rc = usb_control_msg(ov->dev, - usb_rcvctrlpipe(ov->dev, 0), - (ov->bclass == BCL_OV518)?1:3 /* REG_IO */, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, (__u16)reg, &ov->cbuf[0], 1, 1000); - - if (rc < 0) { - err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc)); - } else { - rc = ov->cbuf[0]; - PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); - } - - mutex_unlock(&ov->cbuf_lock); - - return rc; -} - -/* - * Writes bits at positions specified by mask to an OV51x reg. Bits that are in - * the same position as 1's in "mask" are cleared and set to "value". Bits - * that are in the same position as 0's in "mask" are preserved, regardless - * of their respective state in "value". - */ -static int -reg_w_mask(struct usb_ov511 *ov, - unsigned char reg, - unsigned char value, - unsigned char mask) -{ - int ret; - unsigned char oldval, newval; - - ret = reg_r(ov, reg); - if (ret < 0) - return ret; - - oldval = (unsigned char) ret; - oldval &= (~mask); /* Clear the masked bits */ - value &= mask; /* Enforce mask on value */ - newval = oldval | value; /* Set the desired bits */ - - return (reg_w(ov, reg, newval)); -} - -/* - * Writes multiple (n) byte value to a single register. Only valid with certain - * registers (0x30 and 0xc4 - 0xce). - */ -static int -ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) -{ - int rc; - - PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n); - - mutex_lock(&ov->cbuf_lock); - - *((__le32 *)ov->cbuf) = __cpu_to_le32(val); - - rc = usb_control_msg(ov->dev, - usb_sndctrlpipe(ov->dev, 0), - 1 /* REG_IO */, - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, (__u16)reg, ov->cbuf, n, 1000); - mutex_unlock(&ov->cbuf_lock); - - if (rc < 0) - err("reg write multiple: error %d: %s", rc, - symbolic(urb_errlist, rc)); - - return rc; -} - -static int -ov511_upload_quan_tables(struct usb_ov511 *ov) -{ - unsigned char *pYTable = yQuanTable511; - unsigned char *pUVTable = uvQuanTable511; - unsigned char val0, val1; - int i, rc, reg = R511_COMP_LUT_BEGIN; - - PDEBUG(4, "Uploading quantization tables"); - - for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) { - if (ENABLE_Y_QUANTABLE) { - val0 = *pYTable++; - val1 = *pYTable++; - val0 &= 0x0f; - val1 &= 0x0f; - val0 |= val1 << 4; - rc = reg_w(ov, reg, val0); - if (rc < 0) - return rc; - } - - if (ENABLE_UV_QUANTABLE) { - val0 = *pUVTable++; - val1 = *pUVTable++; - val0 &= 0x0f; - val1 &= 0x0f; - val0 |= val1 << 4; - rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0); - if (rc < 0) - return rc; - } - - reg++; - } - - return 0; -} - -/* OV518 quantization tables are 8x4 (instead of 8x8) */ -static int -ov518_upload_quan_tables(struct usb_ov511 *ov) -{ - unsigned char *pYTable = yQuanTable518; - unsigned char *pUVTable = uvQuanTable518; - unsigned char val0, val1; - int i, rc, reg = R511_COMP_LUT_BEGIN; - - PDEBUG(4, "Uploading quantization tables"); - - for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) { - if (ENABLE_Y_QUANTABLE) { - val0 = *pYTable++; - val1 = *pYTable++; - val0 &= 0x0f; - val1 &= 0x0f; - val0 |= val1 << 4; - rc = reg_w(ov, reg, val0); - if (rc < 0) - return rc; - } - - if (ENABLE_UV_QUANTABLE) { - val0 = *pUVTable++; - val1 = *pUVTable++; - val0 &= 0x0f; - val1 &= 0x0f; - val0 |= val1 << 4; - rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0); - if (rc < 0) - return rc; - } - - reg++; - } - - return 0; -} - -static int -ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type) -{ - int rc; - - /* Setting bit 0 not allowed on 518/518Plus */ - if (ov->bclass == BCL_OV518) - reset_type &= 0xfe; - - PDEBUG(4, "Reset: type=0x%02X", reset_type); - - rc = reg_w(ov, R51x_SYS_RESET, reset_type); - rc = reg_w(ov, R51x_SYS_RESET, 0); - - if (rc < 0) - err("reset: command failed"); - - return rc; -} - -/********************************************************************** - * - * Low-level I2C I/O functions - * - **********************************************************************/ - -/* NOTE: Do not call this function directly! - * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from i2c_w(). Note that this function - * always succeeds regardless of whether the sensor is present and working. - */ -static int -ov518_i2c_write_internal(struct usb_ov511 *ov, - unsigned char reg, - unsigned char value) -{ - int rc; - - PDEBUG(5, "0x%02X:0x%02X", reg, value); - - /* Select camera register */ - rc = reg_w(ov, R51x_I2C_SADDR_3, reg); - if (rc < 0) - return rc; - - /* Write "value" to I2C data port of OV511 */ - rc = reg_w(ov, R51x_I2C_DATA, value); - if (rc < 0) - return rc; - - /* Initiate 3-byte write cycle */ - rc = reg_w(ov, R518_I2C_CTL, 0x01); - if (rc < 0) - return rc; - - return 0; -} - -/* NOTE: Do not call this function directly! */ -static int -ov511_i2c_write_internal(struct usb_ov511 *ov, - unsigned char reg, - unsigned char value) -{ - int rc, retries; - - PDEBUG(5, "0x%02X:0x%02X", reg, value); - - /* Three byte write cycle */ - for (retries = OV511_I2C_RETRIES; ; ) { - /* Select camera register */ - rc = reg_w(ov, R51x_I2C_SADDR_3, reg); - if (rc < 0) - break; - - /* Write "value" to I2C data port of OV511 */ - rc = reg_w(ov, R51x_I2C_DATA, value); - if (rc < 0) - break; - - /* Initiate 3-byte write cycle */ - rc = reg_w(ov, R511_I2C_CTL, 0x01); - if (rc < 0) - break; - - /* Retry until idle */ - do - rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); - if (rc < 0) - break; - - /* Ack? */ - if ((rc&2) == 0) { - rc = 0; - break; - } -#if 0 - /* I2C abort */ - reg_w(ov, R511_I2C_CTL, 0x10); -#endif - if (--retries < 0) { - err("i2c write retries exhausted"); - rc = -1; - break; - } - } - - return rc; -} - -/* NOTE: Do not call this function directly! - * The OV518 I2C I/O procedure is different, hence, this function. - * This is normally only called from i2c_r(). Note that this function - * always succeeds regardless of whether the sensor is present and working. - */ -static int -ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) -{ - int rc, value; - - /* Select camera register */ - rc = reg_w(ov, R51x_I2C_SADDR_2, reg); - if (rc < 0) - return rc; - - /* Initiate 2-byte write cycle */ - rc = reg_w(ov, R518_I2C_CTL, 0x03); - if (rc < 0) - return rc; - - /* Initiate 2-byte read cycle */ - rc = reg_w(ov, R518_I2C_CTL, 0x05); - if (rc < 0) - return rc; - - value = reg_r(ov, R51x_I2C_DATA); - - PDEBUG(5, "0x%02X:0x%02X", reg, value); - - return value; -} - -/* NOTE: Do not call this function directly! - * returns: negative is error, pos or zero is data */ -static int -ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) -{ - int rc, value, retries; - - /* Two byte write cycle */ - for (retries = OV511_I2C_RETRIES; ; ) { - /* Select camera register */ - rc = reg_w(ov, R51x_I2C_SADDR_2, reg); - if (rc < 0) - return rc; - - /* Initiate 2-byte write cycle */ - rc = reg_w(ov, R511_I2C_CTL, 0x03); - if (rc < 0) - return rc; - - /* Retry until idle */ - do - rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); - if (rc < 0) - return rc; - - if ((rc&2) == 0) /* Ack? */ - break; - - /* I2C abort */ - reg_w(ov, R511_I2C_CTL, 0x10); - - if (--retries < 0) { - err("i2c write retries exhausted"); - return -1; - } - } - - /* Two byte read cycle */ - for (retries = OV511_I2C_RETRIES; ; ) { - /* Initiate 2-byte read cycle */ - rc = reg_w(ov, R511_I2C_CTL, 0x05); - if (rc < 0) - return rc; - - /* Retry until idle */ - do - rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); - if (rc < 0) - return rc; - - if ((rc&2) == 0) /* Ack? */ - break; - - /* I2C abort */ - rc = reg_w(ov, R511_I2C_CTL, 0x10); - if (rc < 0) - return rc; - - if (--retries < 0) { - err("i2c read retries exhausted"); - return -1; - } - } - - value = reg_r(ov, R51x_I2C_DATA); - - PDEBUG(5, "0x%02X:0x%02X", reg, value); - - /* This is needed to make i2c_w() work */ - rc = reg_w(ov, R511_I2C_CTL, 0x05); - if (rc < 0) - return rc; - - return value; -} - -/* returns: negative is error, pos or zero is data */ -static int -i2c_r(struct usb_ov511 *ov, unsigned char reg) -{ - int rc; - - mutex_lock(&ov->i2c_lock); - - if (ov->bclass == BCL_OV518) - rc = ov518_i2c_read_internal(ov, reg); - else - rc = ov511_i2c_read_internal(ov, reg); - - mutex_unlock(&ov->i2c_lock); - - return rc; -} - -static int -i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) -{ - int rc; - - mutex_lock(&ov->i2c_lock); - - if (ov->bclass == BCL_OV518) - rc = ov518_i2c_write_internal(ov, reg, value); - else - rc = ov511_i2c_write_internal(ov, reg, value); - - mutex_unlock(&ov->i2c_lock); - - return rc; -} - -/* Do not call this function directly! */ -static int -ov51x_i2c_write_mask_internal(struct usb_ov511 *ov, - unsigned char reg, - unsigned char value, - unsigned char mask) -{ - int rc; - unsigned char oldval, newval; - - if (mask == 0xff) { - newval = value; - } else { - if (ov->bclass == BCL_OV518) - rc = ov518_i2c_read_internal(ov, reg); - else - rc = ov511_i2c_read_internal(ov, reg); - if (rc < 0) - return rc; - - oldval = (unsigned char) rc; - oldval &= (~mask); /* Clear the masked bits */ - value &= mask; /* Enforce mask on value */ - newval = oldval | value; /* Set the desired bits */ - } - - if (ov->bclass == BCL_OV518) - return (ov518_i2c_write_internal(ov, reg, newval)); - else - return (ov511_i2c_write_internal(ov, reg, newval)); -} - -/* Writes bits at positions specified by mask to an I2C reg. Bits that are in - * the same position as 1's in "mask" are cleared and set to "value". Bits - * that are in the same position as 0's in "mask" are preserved, regardless - * of their respective state in "value". - */ -static int -i2c_w_mask(struct usb_ov511 *ov, - unsigned char reg, - unsigned char value, - unsigned char mask) -{ - int rc; - - mutex_lock(&ov->i2c_lock); - rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); - mutex_unlock(&ov->i2c_lock); - - return rc; -} - -/* Set the read and write slave IDs. The "slave" argument is the write slave, - * and the read slave will be set to (slave + 1). ov->i2c_lock should be held - * when calling this. This should not be called from outside the i2c I/O - * functions. - */ -static int -i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave) -{ - int rc; - - rc = reg_w(ov, R51x_I2C_W_SID, slave); - if (rc < 0) - return rc; - - rc = reg_w(ov, R51x_I2C_R_SID, slave + 1); - if (rc < 0) - return rc; - - return 0; -} - -/* Write to a specific I2C slave ID and register, using the specified mask */ -static int -i2c_w_slave(struct usb_ov511 *ov, - unsigned char slave, - unsigned char reg, - unsigned char value, - unsigned char mask) -{ - int rc = 0; - - mutex_lock(&ov->i2c_lock); - - /* Set new slave IDs */ - rc = i2c_set_slave_internal(ov, slave); - if (rc < 0) - goto out; - - rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); - -out: - /* Restore primary IDs */ - if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) - err("Couldn't restore primary I2C slave"); - - mutex_unlock(&ov->i2c_lock); - return rc; -} - -/* Read from a specific I2C slave ID and register */ -static int -i2c_r_slave(struct usb_ov511 *ov, - unsigned char slave, - unsigned char reg) -{ - int rc; - - mutex_lock(&ov->i2c_lock); - - /* Set new slave IDs */ - rc = i2c_set_slave_internal(ov, slave); - if (rc < 0) - goto out; - - if (ov->bclass == BCL_OV518) - rc = ov518_i2c_read_internal(ov, reg); - else - rc = ov511_i2c_read_internal(ov, reg); - -out: - /* Restore primary IDs */ - if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) - err("Couldn't restore primary I2C slave"); - - mutex_unlock(&ov->i2c_lock); - return rc; -} - -/* Sets I2C read and write slave IDs. Returns <0 for error */ -static int -ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) -{ - int rc; - - mutex_lock(&ov->i2c_lock); - - rc = i2c_set_slave_internal(ov, sid); - if (rc < 0) - goto out; - - // FIXME: Is this actually necessary? - rc = ov51x_reset(ov, OV511_RESET_NOREGS); -out: - mutex_unlock(&ov->i2c_lock); - return rc; -} - -static int -write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) -{ - int rc; - - while (pRegvals->bus != OV511_DONE_BUS) { - if (pRegvals->bus == OV511_REG_BUS) { - if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) - return rc; - } else if (pRegvals->bus == OV511_I2C_BUS) { - if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) - return rc; - } else { - err("Bad regval array"); - return -1; - } - pRegvals++; - } - return 0; -} - -#ifdef OV511_DEBUG -static void -dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) -{ - int i, rc; - - for (i = reg1; i <= regn; i++) { - rc = i2c_r(ov, i); - info("Sensor[0x%02X] = 0x%02X", i, rc); - } -} - -static void -dump_i2c_regs(struct usb_ov511 *ov) -{ - info("I2C REGS"); - dump_i2c_range(ov, 0x00, 0x7C); -} - -static void -dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) -{ - int i, rc; - - for (i = reg1; i <= regn; i++) { - rc = reg_r(ov, i); - info("OV511[0x%02X] = 0x%02X", i, rc); - } -} - -static void -ov511_dump_regs(struct usb_ov511 *ov) -{ - info("CAMERA INTERFACE REGS"); - dump_reg_range(ov, 0x10, 0x1f); - info("DRAM INTERFACE REGS"); - dump_reg_range(ov, 0x20, 0x23); - info("ISO FIFO REGS"); - dump_reg_range(ov, 0x30, 0x31); - info("PIO REGS"); - dump_reg_range(ov, 0x38, 0x39); - dump_reg_range(ov, 0x3e, 0x3e); - info("I2C REGS"); - dump_reg_range(ov, 0x40, 0x49); - info("SYSTEM CONTROL REGS"); - dump_reg_range(ov, 0x50, 0x55); - dump_reg_range(ov, 0x5e, 0x5f); - info("OmniCE REGS"); - dump_reg_range(ov, 0x70, 0x79); - /* NOTE: Quantization tables are not readable. You will get the value - * in reg. 0x79 for every table register */ - dump_reg_range(ov, 0x80, 0x9f); - dump_reg_range(ov, 0xa0, 0xbf); - -} - -static void -ov518_dump_regs(struct usb_ov511 *ov) -{ - info("VIDEO MODE REGS"); - dump_reg_range(ov, 0x20, 0x2f); - info("DATA PUMP AND SNAPSHOT REGS"); - dump_reg_range(ov, 0x30, 0x3f); - info("I2C REGS"); - dump_reg_range(ov, 0x40, 0x4f); - info("SYSTEM CONTROL AND VENDOR REGS"); - dump_reg_range(ov, 0x50, 0x5f); - info("60 - 6F"); - dump_reg_range(ov, 0x60, 0x6f); - info("70 - 7F"); - dump_reg_range(ov, 0x70, 0x7f); - info("Y QUANTIZATION TABLE"); - dump_reg_range(ov, 0x80, 0x8f); - info("UV QUANTIZATION TABLE"); - dump_reg_range(ov, 0x90, 0x9f); - info("A0 - BF"); - dump_reg_range(ov, 0xa0, 0xbf); - info("CBR"); - dump_reg_range(ov, 0xc0, 0xcf); -} -#endif - -/*****************************************************************************/ - -/* Temporarily stops OV511 from functioning. Must do this before changing - * registers while the camera is streaming */ -static inline int -ov51x_stop(struct usb_ov511 *ov) -{ - PDEBUG(4, "stopping"); - ov->stopped = 1; - if (ov->bclass == BCL_OV518) - return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a)); - else - return (reg_w(ov, R51x_SYS_RESET, 0x3d)); -} - -/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not - * actually stopped (for performance). */ -static inline int -ov51x_restart(struct usb_ov511 *ov) -{ - if (ov->stopped) { - PDEBUG(4, "restarting"); - ov->stopped = 0; - - /* Reinitialize the stream */ - if (ov->bclass == BCL_OV518) - reg_w(ov, 0x2f, 0x80); - - return (reg_w(ov, R51x_SYS_RESET, 0x00)); - } - - return 0; -} - -/* Sleeps until no frames are active. Returns !0 if got signal */ -static int -ov51x_wait_frames_inactive(struct usb_ov511 *ov) -{ - return wait_event_interruptible(ov->wq, ov->curframe < 0); -} - -/* Resets the hardware snapshot button */ -static void -ov51x_clear_snapshot(struct usb_ov511 *ov) -{ - if (ov->bclass == BCL_OV511) { - reg_w(ov, R51x_SYS_SNAP, 0x00); - reg_w(ov, R51x_SYS_SNAP, 0x02); - reg_w(ov, R51x_SYS_SNAP, 0x00); - } else if (ov->bclass == BCL_OV518) { - warn("snapshot reset not supported yet on OV518(+)"); - } else { - err("clear snap: invalid bridge type"); - } -} - -#if 0 -/* Checks the status of the snapshot button. Returns 1 if it was pressed since - * it was last cleared, and zero in all other cases (including errors) */ -static int -ov51x_check_snapshot(struct usb_ov511 *ov) -{ - int ret, status = 0; - - if (ov->bclass == BCL_OV511) { - ret = reg_r(ov, R51x_SYS_SNAP); - if (ret < 0) { - err("Error checking snspshot status (%d)", ret); - } else if (ret & 0x08) { - status = 1; - } - } else if (ov->bclass == BCL_OV518) { - warn("snapshot check not supported yet on OV518(+)"); - } else { - err("check snap: invalid bridge type"); - } - - return status; -} -#endif - -/* This does an initial reset of an OmniVision sensor and ensures that I2C - * is synchronized. Returns <0 for failure. - */ -static int -init_ov_sensor(struct usb_ov511 *ov) -{ - int i, success; - - /* Reset the sensor */ - if (i2c_w(ov, 0x12, 0x80) < 0) - return -EIO; - - /* Wait for it to initialize */ - msleep(150); - - for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { - if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && - (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { - success = 1; - continue; - } - - /* Reset the sensor */ - if (i2c_w(ov, 0x12, 0x80) < 0) - return -EIO; - /* Wait for it to initialize */ - msleep(150); - /* Dummy read to sync I2C */ - if (i2c_r(ov, 0x00) < 0) - return -EIO; - } - - if (!success) - return -EIO; - - PDEBUG(1, "I2C synced in %d attempt(s)", i); - - return 0; -} - -static int -ov511_set_packet_size(struct usb_ov511 *ov, int size) -{ - int alt, mult; - - if (ov51x_stop(ov) < 0) - return -EIO; - - mult = size >> 5; - - if (ov->bridge == BRG_OV511) { - if (size == 0) - alt = OV511_ALT_SIZE_0; - else if (size == 257) - alt = OV511_ALT_SIZE_257; - else if (size == 513) - alt = OV511_ALT_SIZE_513; - else if (size == 769) - alt = OV511_ALT_SIZE_769; - else if (size == 993) - alt = OV511_ALT_SIZE_993; - else { - err("Set packet size: invalid size (%d)", size); - return -EINVAL; - } - } else if (ov->bridge == BRG_OV511PLUS) { - if (size == 0) - alt = OV511PLUS_ALT_SIZE_0; - else if (size == 33) - alt = OV511PLUS_ALT_SIZE_33; - else if (size == 129) - alt = OV511PLUS_ALT_SIZE_129; - else if (size == 257) - alt = OV511PLUS_ALT_SIZE_257; - else if (size == 385) - alt = OV511PLUS_ALT_SIZE_385; - else if (size == 513) - alt = OV511PLUS_ALT_SIZE_513; - else if (size == 769) - alt = OV511PLUS_ALT_SIZE_769; - else if (size == 961) - alt = OV511PLUS_ALT_SIZE_961; - else { - err("Set packet size: invalid size (%d)", size); - return -EINVAL; - } - } else { - err("Set packet size: Invalid bridge type"); - return -EINVAL; - } - - PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt); - - if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) - return -EIO; - - if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { - err("Set packet size: set interface error"); - return -EBUSY; - } - - if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) - return -EIO; - - ov->packet_size = size; - - if (ov51x_restart(ov) < 0) - return -EIO; - - return 0; -} - -/* Note: Unlike the OV511/OV511+, the size argument does NOT include the - * optional packet number byte. The actual size *is* stored in ov->packet_size, - * though. */ -static int -ov518_set_packet_size(struct usb_ov511 *ov, int size) -{ - int alt; - - if (ov51x_stop(ov) < 0) - return -EIO; - - if (ov->bclass == BCL_OV518) { - if (size == 0) - alt = OV518_ALT_SIZE_0; - else if (size == 128) - alt = OV518_ALT_SIZE_128; - else if (size == 256) - alt = OV518_ALT_SIZE_256; - else if (size == 384) - alt = OV518_ALT_SIZE_384; - else if (size == 512) - alt = OV518_ALT_SIZE_512; - else if (size == 640) - alt = OV518_ALT_SIZE_640; - else if (size == 768) - alt = OV518_ALT_SIZE_768; - else if (size == 896) - alt = OV518_ALT_SIZE_896; - else { - err("Set packet size: invalid size (%d)", size); - return -EINVAL; - } - } else { - err("Set packet size: Invalid bridge type"); - return -EINVAL; - } - - PDEBUG(3, "%d, alt=%d", size, alt); - - ov->packet_size = size; - if (size > 0) { - /* Program ISO FIFO size reg (packet number isn't included) */ - ov518_reg_w32(ov, 0x30, size, 2); - - if (ov->packet_numbering) - ++ov->packet_size; - } - - if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { - err("Set packet size: set interface error"); - return -EBUSY; - } - - /* Initialize the stream */ - if (reg_w(ov, 0x2f, 0x80) < 0) - return -EIO; - - if (ov51x_restart(ov) < 0) - return -EIO; - - if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) - return -EIO; - - return 0; -} - -/* Upload compression params and quantization tables. Returns 0 for success. */ -static int -ov511_init_compression(struct usb_ov511 *ov) -{ - int rc = 0; - - if (!ov->compress_inited) { - reg_w(ov, 0x70, phy); - reg_w(ov, 0x71, phuv); - reg_w(ov, 0x72, pvy); - reg_w(ov, 0x73, pvuv); - reg_w(ov, 0x74, qhy); - reg_w(ov, 0x75, qhuv); - reg_w(ov, 0x76, qvy); - reg_w(ov, 0x77, qvuv); - - if (ov511_upload_quan_tables(ov) < 0) { - err("Error uploading quantization tables"); - rc = -EIO; - goto out; - } - } - - ov->compress_inited = 1; -out: - return rc; -} - -/* Upload compression params and quantization tables. Returns 0 for success. */ -static int -ov518_init_compression(struct usb_ov511 *ov) -{ - int rc = 0; - - if (!ov->compress_inited) { - if (ov518_upload_quan_tables(ov) < 0) { - err("Error uploading quantization tables"); - rc = -EIO; - goto out; - } - } - - ov->compress_inited = 1; -out: - return rc; -} - -/* -------------------------------------------------------------------------- */ - -/* Sets sensor's contrast setting to "val" */ -static int -sensor_set_contrast(struct usb_ov511 *ov, unsigned short val) -{ - int rc; - - PDEBUG(3, "%d", val); - - if (ov->stop_during_set) - if (ov51x_stop(ov) < 0) - return -EIO; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV6620: - { - rc = i2c_w(ov, OV7610_REG_CNT, val >> 8); - if (rc < 0) - goto out; - break; - } - case SEN_OV6630: - { - rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f); - if (rc < 0) - goto out; - break; - } - case SEN_OV7620: - { - unsigned char ctab[] = { - 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, - 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff - }; - - /* Use Y gamma control instead. Bit 0 enables it. */ - rc = i2c_w(ov, 0x64, ctab[val>>12]); - if (rc < 0) - goto out; - break; - } - case SEN_SAA7111A: - { - rc = i2c_w(ov, 0x0b, val >> 9); - if (rc < 0) - goto out; - break; - } - default: - { - PDEBUG(3, "Unsupported with this sensor"); - rc = -EPERM; - goto out; - } - } - - rc = 0; /* Success */ - ov->contrast = val; -out: - if (ov51x_restart(ov) < 0) - return -EIO; - - return rc; -} - -/* Gets sensor's contrast setting */ -static int -sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val) -{ - int rc; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV6620: - rc = i2c_r(ov, OV7610_REG_CNT); - if (rc < 0) - return rc; - else - *val = rc << 8; - break; - case SEN_OV6630: - rc = i2c_r(ov, OV7610_REG_CNT); - if (rc < 0) - return rc; - else - *val = rc << 12; - break; - case SEN_OV7620: - /* Use Y gamma reg instead. Bit 0 is the enable bit. */ - rc = i2c_r(ov, 0x64); - if (rc < 0) - return rc; - else - *val = (rc & 0xfe) << 8; - break; - case SEN_SAA7111A: - *val = ov->contrast; - break; - default: - PDEBUG(3, "Unsupported with this sensor"); - return -EPERM; - } - - PDEBUG(3, "%d", *val); - ov->contrast = *val; - - return 0; -} - -/* -------------------------------------------------------------------------- */ - -/* Sets sensor's brightness setting to "val" */ -static int -sensor_set_brightness(struct usb_ov511 *ov, unsigned short val) -{ - int rc; - - PDEBUG(4, "%d", val); - - if (ov->stop_during_set) - if (ov51x_stop(ov) < 0) - return -EIO; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV76BE: - case SEN_OV6620: - case SEN_OV6630: - rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); - if (rc < 0) - goto out; - break; - case SEN_OV7620: - /* 7620 doesn't like manual changes when in auto mode */ - if (!ov->auto_brt) { - rc = i2c_w(ov, OV7610_REG_BRT, val >> 8); - if (rc < 0) - goto out; - } - break; - case SEN_SAA7111A: - rc = i2c_w(ov, 0x0a, val >> 8); - if (rc < 0) - goto out; - break; - default: - PDEBUG(3, "Unsupported with this sensor"); - rc = -EPERM; - goto out; - } - - rc = 0; /* Success */ - ov->brightness = val; -out: - if (ov51x_restart(ov) < 0) - return -EIO; - - return rc; -} - -/* Gets sensor's brightness setting */ -static int -sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val) -{ - int rc; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV76BE: - case SEN_OV7620: - case SEN_OV6620: - case SEN_OV6630: - rc = i2c_r(ov, OV7610_REG_BRT); - if (rc < 0) - return rc; - else - *val = rc << 8; - break; - case SEN_SAA7111A: - *val = ov->brightness; - break; - default: - PDEBUG(3, "Unsupported with this sensor"); - return -EPERM; - } - - PDEBUG(3, "%d", *val); - ov->brightness = *val; - - return 0; -} - -/* -------------------------------------------------------------------------- */ - -/* Sets sensor's saturation (color intensity) setting to "val" */ -static int -sensor_set_saturation(struct usb_ov511 *ov, unsigned short val) -{ - int rc; - - PDEBUG(3, "%d", val); - - if (ov->stop_during_set) - if (ov51x_stop(ov) < 0) - return -EIO; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV76BE: - case SEN_OV6620: - case SEN_OV6630: - rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); - if (rc < 0) - goto out; - break; - case SEN_OV7620: -// /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ -// rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e); -// if (rc < 0) -// goto out; - rc = i2c_w(ov, OV7610_REG_SAT, val >> 8); - if (rc < 0) - goto out; - break; - case SEN_SAA7111A: - rc = i2c_w(ov, 0x0c, val >> 9); - if (rc < 0) - goto out; - break; - default: - PDEBUG(3, "Unsupported with this sensor"); - rc = -EPERM; - goto out; - } - - rc = 0; /* Success */ - ov->colour = val; -out: - if (ov51x_restart(ov) < 0) - return -EIO; - - return rc; -} - -/* Gets sensor's saturation (color intensity) setting */ -static int -sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val) -{ - int rc; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV76BE: - case SEN_OV6620: - case SEN_OV6630: - rc = i2c_r(ov, OV7610_REG_SAT); - if (rc < 0) - return rc; - else - *val = rc << 8; - break; - case SEN_OV7620: -// /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */ -// rc = i2c_r(ov, 0x62); -// if (rc < 0) -// return rc; -// else -// *val = (rc & 0x7e) << 9; - rc = i2c_r(ov, OV7610_REG_SAT); - if (rc < 0) - return rc; - else - *val = rc << 8; - break; - case SEN_SAA7111A: - *val = ov->colour; - break; - default: - PDEBUG(3, "Unsupported with this sensor"); - return -EPERM; - } - - PDEBUG(3, "%d", *val); - ov->colour = *val; - - return 0; -} - -/* -------------------------------------------------------------------------- */ - -/* Sets sensor's hue (red/blue balance) setting to "val" */ -static int -sensor_set_hue(struct usb_ov511 *ov, unsigned short val) -{ - int rc; - - PDEBUG(3, "%d", val); - - if (ov->stop_during_set) - if (ov51x_stop(ov) < 0) - return -EIO; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV6620: - case SEN_OV6630: - rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8)); - if (rc < 0) - goto out; - - rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8); - if (rc < 0) - goto out; - break; - case SEN_OV7620: -// Hue control is causing problems. I will enable it once it's fixed. -#if 0 - rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb); - if (rc < 0) - goto out; - - rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb); - if (rc < 0) - goto out; -#endif - break; - case SEN_SAA7111A: - rc = i2c_w(ov, 0x0d, (val + 32768) >> 8); - if (rc < 0) - goto out; - break; - default: - PDEBUG(3, "Unsupported with this sensor"); - rc = -EPERM; - goto out; - } - - rc = 0; /* Success */ - ov->hue = val; -out: - if (ov51x_restart(ov) < 0) - return -EIO; - - return rc; -} - -/* Gets sensor's hue (red/blue balance) setting */ -static int -sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) -{ - int rc; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV6620: - case SEN_OV6630: - rc = i2c_r(ov, OV7610_REG_BLUE); - if (rc < 0) - return rc; - else - *val = rc << 8; - break; - case SEN_OV7620: - rc = i2c_r(ov, 0x7a); - if (rc < 0) - return rc; - else - *val = rc << 8; - break; - case SEN_SAA7111A: - *val = ov->hue; - break; - default: - PDEBUG(3, "Unsupported with this sensor"); - return -EPERM; - } - - PDEBUG(3, "%d", *val); - ov->hue = *val; - - return 0; -} - -/* -------------------------------------------------------------------------- */ - -static int -sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) -{ - int rc; - - PDEBUG(4, "sensor_set_picture"); - - ov->whiteness = p->whiteness; - - /* Don't return error if a setting is unsupported, or rest of settings - * will not be performed */ - - rc = sensor_set_contrast(ov, p->contrast); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_set_brightness(ov, p->brightness); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_set_saturation(ov, p->colour); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_set_hue(ov, p->hue); - if (FATAL_ERROR(rc)) - return rc; - - return 0; -} - -static int -sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) -{ - int rc; - - PDEBUG(4, "sensor_get_picture"); - - /* Don't return error if a setting is unsupported, or rest of settings - * will not be performed */ - - rc = sensor_get_contrast(ov, &(p->contrast)); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_get_brightness(ov, &(p->brightness)); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_get_saturation(ov, &(p->colour)); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_get_hue(ov, &(p->hue)); - if (FATAL_ERROR(rc)) - return rc; - - p->whiteness = 105 << 8; - - return 0; -} - -#if 0 -// FIXME: Exposure range is only 0x00-0x7f in interlace mode -/* Sets current exposure for sensor. This only has an effect if auto-exposure - * is off */ -static inline int -sensor_set_exposure(struct usb_ov511 *ov, unsigned char val) -{ - int rc; - - PDEBUG(3, "%d", val); - - if (ov->stop_during_set) - if (ov51x_stop(ov) < 0) - return -EIO; - - switch (ov->sensor) { - case SEN_OV6620: - case SEN_OV6630: - case SEN_OV7610: - case SEN_OV7620: - case SEN_OV76BE: - case SEN_OV8600: - rc = i2c_w(ov, 0x10, val); - if (rc < 0) - goto out; - - break; - case SEN_KS0127: - case SEN_KS0127B: - case SEN_SAA7111A: - PDEBUG(3, "Unsupported with this sensor"); - return -EPERM; - default: - err("Sensor not supported for set_exposure"); - return -EINVAL; - } - - rc = 0; /* Success */ - ov->exposure = val; -out: - if (ov51x_restart(ov) < 0) - return -EIO; - - return rc; -} -#endif - -/* Gets current exposure level from sensor, regardless of whether it is under - * manual control. */ -static int -sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) -{ - int rc; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV6620: - case SEN_OV6630: - case SEN_OV7620: - case SEN_OV76BE: - case SEN_OV8600: - rc = i2c_r(ov, 0x10); - if (rc < 0) - return rc; - else - *val = rc; - break; - case SEN_KS0127: - case SEN_KS0127B: - case SEN_SAA7111A: - val = NULL; - PDEBUG(3, "Unsupported with this sensor"); - return -EPERM; - default: - err("Sensor not supported for get_exposure"); - return -EINVAL; - } - - PDEBUG(3, "%d", *val); - ov->exposure = *val; - - return 0; -} - -/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ -static void -ov51x_led_control(struct usb_ov511 *ov, int enable) -{ - PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - - if (ov->bridge == BRG_OV511PLUS) - reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0); - else if (ov->bclass == BCL_OV518) - reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02); - - return; -} - -/* Matches the sensor's internal frame rate to the lighting frequency. - * Valid frequencies are: - * 50 - 50Hz, for European and Asian lighting - * 60 - 60Hz, for American lighting - * - * Tested with: OV7610, OV7620, OV76BE, OV6620 - * Unsupported: KS0127, KS0127B, SAA7111A - * Returns: 0 for success - */ -static int -sensor_set_light_freq(struct usb_ov511 *ov, int freq) -{ - int sixty; - - PDEBUG(4, "%d Hz", freq); - - if (freq == 60) - sixty = 1; - else if (freq == 50) - sixty = 0; - else { - err("Invalid light freq (%d Hz)", freq); - return -EINVAL; - } - - switch (ov->sensor) { - case SEN_OV7610: - i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); - i2c_w(ov, 0x2b, sixty?0x00:0xac); - i2c_w_mask(ov, 0x13, 0x10, 0x10); - i2c_w_mask(ov, 0x13, 0x00, 0x10); - break; - case SEN_OV7620: - case SEN_OV76BE: - case SEN_OV8600: - i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); - i2c_w(ov, 0x2b, sixty?0x00:0xac); - i2c_w_mask(ov, 0x76, 0x01, 0x01); - break; - case SEN_OV6620: - case SEN_OV6630: - i2c_w(ov, 0x2b, sixty?0xa8:0x28); - i2c_w(ov, 0x2a, sixty?0x84:0xa4); - break; - case SEN_KS0127: - case SEN_KS0127B: - case SEN_SAA7111A: - PDEBUG(5, "Unsupported with this sensor"); - return -EPERM; - default: - err("Sensor not supported for set_light_freq"); - return -EINVAL; - } - - ov->lightfreq = freq; - - return 0; -} - -/* If enable is true, turn on the sensor's banding filter, otherwise turn it - * off. This filter tries to reduce the pattern of horizontal light/dark bands - * caused by some (usually fluorescent) lighting. The light frequency must be - * set either before or after enabling it with ov51x_set_light_freq(). - * - * Tested with: OV7610, OV7620, OV76BE, OV6620. - * Unsupported: KS0127, KS0127B, SAA7111A - * Returns: 0 for success - */ -static int -sensor_set_banding_filter(struct usb_ov511 *ov, int enable) -{ - int rc; - - PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - - if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B - || ov->sensor == SEN_SAA7111A) { - PDEBUG(5, "Unsupported with this sensor"); - return -EPERM; - } - - rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04); - if (rc < 0) - return rc; - - ov->bandfilt = enable; - - return 0; -} - -/* If enable is true, turn on the sensor's auto brightness control, otherwise - * turn it off. - * - * Unsupported: KS0127, KS0127B, SAA7111A - * Returns: 0 for success - */ -static int -sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) -{ - int rc; - - PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - - if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B - || ov->sensor == SEN_SAA7111A) { - PDEBUG(5, "Unsupported with this sensor"); - return -EPERM; - } - - rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10); - if (rc < 0) - return rc; - - ov->auto_brt = enable; - - return 0; -} - -/* If enable is true, turn on the sensor's auto exposure control, otherwise - * turn it off. - * - * Unsupported: KS0127, KS0127B, SAA7111A - * Returns: 0 for success - */ -static int -sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) -{ - PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - - switch (ov->sensor) { - case SEN_OV7610: - i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80); - break; - case SEN_OV6620: - case SEN_OV7620: - case SEN_OV76BE: - case SEN_OV8600: - i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01); - break; - case SEN_OV6630: - i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10); - break; - case SEN_KS0127: - case SEN_KS0127B: - case SEN_SAA7111A: - PDEBUG(5, "Unsupported with this sensor"); - return -EPERM; - default: - err("Sensor not supported for set_auto_exposure"); - return -EINVAL; - } - - ov->auto_exp = enable; - - return 0; -} - -/* Modifies the sensor's exposure algorithm to allow proper exposure of objects - * that are illuminated from behind. - * - * Tested with: OV6620, OV7620 - * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A - * Returns: 0 for success - */ -static int -sensor_set_backlight(struct usb_ov511 *ov, int enable) -{ - PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - - switch (ov->sensor) { - case SEN_OV7620: - case SEN_OV8600: - i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); - i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); - i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); - break; - case SEN_OV6620: - i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0); - i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); - i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80); - break; - case SEN_OV6630: - i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0); - i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08); - i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02); - break; - case SEN_OV7610: - case SEN_OV76BE: - case SEN_KS0127: - case SEN_KS0127B: - case SEN_SAA7111A: - PDEBUG(5, "Unsupported with this sensor"); - return -EPERM; - default: - err("Sensor not supported for set_backlight"); - return -EINVAL; - } - - ov->backlight = enable; - - return 0; -} - -static int -sensor_set_mirror(struct usb_ov511 *ov, int enable) -{ - PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - - switch (ov->sensor) { - case SEN_OV6620: - case SEN_OV6630: - case SEN_OV7610: - case SEN_OV7620: - case SEN_OV76BE: - case SEN_OV8600: - i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40); - break; - case SEN_KS0127: - case SEN_KS0127B: - case SEN_SAA7111A: - PDEBUG(5, "Unsupported with this sensor"); - return -EPERM; - default: - err("Sensor not supported for set_mirror"); - return -EINVAL; - } - - ov->mirror = enable; - - return 0; -} - -/* Returns number of bits per pixel (regardless of where they are located; - * planar or not), or zero for unsupported format. - */ -static inline int -get_depth(int palette) -{ - switch (palette) { - case VIDEO_PALETTE_GREY: return 8; - case VIDEO_PALETTE_YUV420: return 12; - case VIDEO_PALETTE_YUV420P: return 12; /* Planar */ - default: return 0; /* Invalid format */ - } -} - -/* Bytes per frame. Used by read(). Return of 0 indicates error */ -static inline long int -get_frame_length(struct ov511_frame *frame) -{ - if (!frame) - return 0; - else - return ((frame->width * frame->height - * get_depth(frame->format)) >> 3); -} - -static int -mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, - int mode, int sub_flag, int qvga) -{ - int clock; - - /******** Mode (VGA/QVGA) and sensor specific regs ********/ - - switch (ov->sensor) { - case SEN_OV7610: - i2c_w(ov, 0x14, qvga?0x24:0x04); -// FIXME: Does this improve the image quality or frame rate? -#if 0 - i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); - i2c_w(ov, 0x24, 0x10); - i2c_w(ov, 0x25, qvga?0x40:0x8a); - i2c_w(ov, 0x2f, qvga?0x30:0xb0); - i2c_w(ov, 0x35, qvga?0x1c:0x9c); -#endif - break; - case SEN_OV7620: -// i2c_w(ov, 0x2b, 0x00); - i2c_w(ov, 0x14, qvga?0xa4:0x84); - i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); - i2c_w(ov, 0x24, qvga?0x20:0x3a); - i2c_w(ov, 0x25, qvga?0x30:0x60); - i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); - i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0); - i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); - break; - case SEN_OV76BE: -// i2c_w(ov, 0x2b, 0x00); - i2c_w(ov, 0x14, qvga?0xa4:0x84); -// FIXME: Enable this once 7620AE uses 7620 initial settings -#if 0 - i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20); - i2c_w(ov, 0x24, qvga?0x20:0x3a); - i2c_w(ov, 0x25, qvga?0x30:0x60); - i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40); - i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0); - i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20); -#endif - break; - case SEN_OV6620: - i2c_w(ov, 0x14, qvga?0x24:0x04); - break; - case SEN_OV6630: - i2c_w(ov, 0x14, qvga?0xa0:0x80); - break; - default: - err("Invalid sensor"); - return -EINVAL; - } - - /******** Palette-specific regs ********/ - - if (mode == VIDEO_PALETTE_GREY) { - if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { - /* these aren't valid on the OV6620/OV7620/6630? */ - i2c_w_mask(ov, 0x0e, 0x40, 0x40); - } - - if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 - && ov518_color) { - i2c_w_mask(ov, 0x12, 0x00, 0x10); - i2c_w_mask(ov, 0x13, 0x00, 0x20); - } else { - i2c_w_mask(ov, 0x13, 0x20, 0x20); - } - } else { - if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { - /* not valid on the OV6620/OV7620/6630? */ - i2c_w_mask(ov, 0x0e, 0x00, 0x40); - } - - /* The OV518 needs special treatment. Although both the OV518 - * and the OV6630 support a 16-bit video bus, only the 8 bit Y - * bus is actually used. The UV bus is tied to ground. - * Therefore, the OV6630 needs to be in 8-bit multiplexed - * output mode */ - - if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 - && ov518_color) { - i2c_w_mask(ov, 0x12, 0x10, 0x10); - i2c_w_mask(ov, 0x13, 0x20, 0x20); - } else { - i2c_w_mask(ov, 0x13, 0x00, 0x20); - } - } - - /******** Clock programming ********/ - - /* The OV6620 needs special handling. This prevents the - * severe banding that normally occurs */ - if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) - { - /* Clock down */ - - i2c_w(ov, 0x2a, 0x04); - - if (ov->compress) { -// clock = 0; /* This ensures the highest frame rate */ - clock = 3; - } else if (clockdiv == -1) { /* If user didn't override it */ - clock = 3; /* Gives better exposure time */ - } else { - clock = clockdiv; - } - - PDEBUG(4, "Setting clock divisor to %d", clock); - - i2c_w(ov, 0x11, clock); - - i2c_w(ov, 0x2a, 0x84); - /* This next setting is critical. It seems to improve - * the gain or the contrast. The "reserved" bits seem - * to have some effect in this case. */ - i2c_w(ov, 0x2d, 0x85); - } - else - { - if (ov->compress) { - clock = 1; /* This ensures the highest frame rate */ - } else if (clockdiv == -1) { /* If user didn't override it */ - /* Calculate and set the clock divisor */ - clock = ((sub_flag ? ov->subw * ov->subh - : width * height) - * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2) - / 66000; - } else { - clock = clockdiv; - } - - PDEBUG(4, "Setting clock divisor to %d", clock); - - i2c_w(ov, 0x11, clock); - } - - /******** Special Features ********/ - - if (framedrop >= 0) - i2c_w(ov, 0x16, framedrop); - - /* Test Pattern */ - i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); - - /* Enable auto white balance */ - i2c_w_mask(ov, 0x12, 0x04, 0x04); - - // This will go away as soon as ov51x_mode_init_sensor_regs() - // is fully tested. - /* 7620/6620/6630? don't have register 0x35, so play it safe */ - if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { - if (width == 640 && height == 480) - i2c_w(ov, 0x35, 0x9e); - else - i2c_w(ov, 0x35, 0x1e); - } - - return 0; -} - -static int -set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode, - int sub_flag) -{ - int ret; - int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; - int hoffset, voffset, hwscale = 0, vwscale = 0; - - /* The different sensor ICs handle setting up of window differently. - * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */ - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV76BE: - hwsbase = 0x38; - hwebase = 0x3a; - vwsbase = vwebase = 0x05; - break; - case SEN_OV6620: - case SEN_OV6630: - hwsbase = 0x38; - hwebase = 0x3a; - vwsbase = 0x05; - vwebase = 0x06; - break; - case SEN_OV7620: - hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ - hwebase = 0x2f; - vwsbase = vwebase = 0x05; - break; - default: - err("Invalid sensor"); - return -EINVAL; - } - - if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) { - /* Note: OV518(+) does downsample on its own) */ - if ((width > 176 && height > 144) - || ov->bclass == BCL_OV518) { /* CIF */ - ret = mode_init_ov_sensor_regs(ov, width, height, - mode, sub_flag, 0); - if (ret < 0) - return ret; - hwscale = 1; - vwscale = 1; /* The datasheet says 0; it's wrong */ - hwsize = 352; - vwsize = 288; - } else if (width > 176 || height > 144) { - err("Illegal dimensions"); - return -EINVAL; - } else { /* QCIF */ - ret = mode_init_ov_sensor_regs(ov, width, height, - mode, sub_flag, 1); - if (ret < 0) - return ret; - hwsize = 176; - vwsize = 144; - } - } else { - if (width > 320 && height > 240) { /* VGA */ - ret = mode_init_ov_sensor_regs(ov, width, height, - mode, sub_flag, 0); - if (ret < 0) - return ret; - hwscale = 2; - vwscale = 1; - hwsize = 640; - vwsize = 480; - } else if (width > 320 || height > 240) { - err("Illegal dimensions"); - return -EINVAL; - } else { /* QVGA */ - ret = mode_init_ov_sensor_regs(ov, width, height, - mode, sub_flag, 1); - if (ret < 0) - return ret; - hwscale = 1; - hwsize = 320; - vwsize = 240; - } - } - - /* Center the window */ - hoffset = ((hwsize - width) / 2) >> hwscale; - voffset = ((vwsize - height) / 2) >> vwscale; - - /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ - if (sub_flag) { - i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale)); - i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale)); - i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale)); - i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale)); - } else { - i2c_w(ov, 0x17, hwsbase + hoffset); - i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale)); - i2c_w(ov, 0x19, vwsbase + voffset); - i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale)); - } - -#ifdef OV511_DEBUG - if (dump_sensor) - dump_i2c_regs(ov); -#endif - - return 0; -} - -/* Set up the OV511/OV511+ with the given image parameters. - * - * Do not put any sensor-specific code in here (including I2C I/O functions) - */ -static int -ov511_mode_init_regs(struct usb_ov511 *ov, - int width, int height, int mode, int sub_flag) -{ - int hsegs, vsegs; - - if (sub_flag) { - width = ov->subw; - height = ov->subh; - } - - PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", - width, height, mode, sub_flag); - - // FIXME: This should be moved to a 7111a-specific function once - // subcapture is dealt with properly - if (ov->sensor == SEN_SAA7111A) { - if (width == 320 && height == 240) { - /* No need to do anything special */ - } else if (width == 640 && height == 480) { - /* Set the OV511 up as 320x480, but keep the - * V4L resolution as 640x480 */ - width = 320; - } else { - err("SAA7111A only allows 320x240 or 640x480"); - return -EINVAL; - } - } - - /* Make sure width and height are a multiple of 8 */ - if (width % 8 || height % 8) { - err("Invalid size (%d, %d) (mode = %d)", width, height, mode); - return -EINVAL; - } - - if (width < ov->minwidth || height < ov->minheight) { - err("Requested dimensions are too small"); - return -EINVAL; - } - - if (ov51x_stop(ov) < 0) - return -EIO; - - if (mode == VIDEO_PALETTE_GREY) { - reg_w(ov, R511_CAM_UV_EN, 0x00); - reg_w(ov, R511_SNAP_UV_EN, 0x00); - reg_w(ov, R511_SNAP_OPTS, 0x01); - } else { - reg_w(ov, R511_CAM_UV_EN, 0x01); - reg_w(ov, R511_SNAP_UV_EN, 0x01); - reg_w(ov, R511_SNAP_OPTS, 0x03); - } - - /* Here I'm assuming that snapshot size == image size. - * I hope that's always true. --claudio - */ - hsegs = (width >> 3) - 1; - vsegs = (height >> 3) - 1; - - reg_w(ov, R511_CAM_PXCNT, hsegs); - reg_w(ov, R511_CAM_LNCNT, vsegs); - reg_w(ov, R511_CAM_PXDIV, 0x00); - reg_w(ov, R511_CAM_LNDIV, 0x00); - - /* YUV420, low pass filter on */ - reg_w(ov, R511_CAM_OPTS, 0x03); - - /* Snapshot additions */ - reg_w(ov, R511_SNAP_PXCNT, hsegs); - reg_w(ov, R511_SNAP_LNCNT, vsegs); - reg_w(ov, R511_SNAP_PXDIV, 0x00); - reg_w(ov, R511_SNAP_LNDIV, 0x00); - - if (ov->compress) { - /* Enable Y and UV quantization and compression */ - reg_w(ov, R511_COMP_EN, 0x07); - reg_w(ov, R511_COMP_LUT_EN, 0x03); - ov51x_reset(ov, OV511_RESET_OMNICE); - } - - if (ov51x_restart(ov) < 0) - return -EIO; - - return 0; -} - -/* Sets up the OV518/OV518+ with the given image parameters - * - * OV518 needs a completely different approach, until we can figure out what - * the individual registers do. Also, only 15 FPS is supported now. - * - * Do not put any sensor-specific code in here (including I2C I/O functions) - */ -static int -ov518_mode_init_regs(struct usb_ov511 *ov, - int width, int height, int mode, int sub_flag) -{ - int hsegs, vsegs, hi_res; - - if (sub_flag) { - width = ov->subw; - height = ov->subh; - } - - PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", - width, height, mode, sub_flag); - - if (width % 16 || height % 8) { - err("Invalid size (%d, %d)", width, height); - return -EINVAL; - } - - if (width < ov->minwidth || height < ov->minheight) { - err("Requested dimensions are too small"); - return -EINVAL; - } - - if (width >= 320 && height >= 240) { - hi_res = 1; - } else if (width >= 320 || height >= 240) { - err("Invalid width/height combination (%d, %d)", width, height); - return -EINVAL; - } else { - hi_res = 0; - } - - if (ov51x_stop(ov) < 0) - return -EIO; - - /******** Set the mode ********/ - - reg_w(ov, 0x2b, 0); - reg_w(ov, 0x2c, 0); - reg_w(ov, 0x2d, 0); - reg_w(ov, 0x2e, 0); - reg_w(ov, 0x3b, 0); - reg_w(ov, 0x3c, 0); - reg_w(ov, 0x3d, 0); - reg_w(ov, 0x3e, 0); - - if (ov->bridge == BRG_OV518 && ov518_color) { - /* OV518 needs U and V swapped */ - i2c_w_mask(ov, 0x15, 0x00, 0x01); - - if (mode == VIDEO_PALETTE_GREY) { - /* Set 16-bit input format (UV data are ignored) */ - reg_w_mask(ov, 0x20, 0x00, 0x08); - - /* Set 8-bit (4:0:0) output format */ - reg_w_mask(ov, 0x28, 0x00, 0xf0); - reg_w_mask(ov, 0x38, 0x00, 0xf0); - } else { - /* Set 8-bit (YVYU) input format */ - reg_w_mask(ov, 0x20, 0x08, 0x08); - - /* Set 12-bit (4:2:0) output format */ - reg_w_mask(ov, 0x28, 0x80, 0xf0); - reg_w_mask(ov, 0x38, 0x80, 0xf0); - } - } else { - reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); - reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); - } - - hsegs = width / 16; - vsegs = height / 4; - - reg_w(ov, 0x29, hsegs); - reg_w(ov, 0x2a, vsegs); - - reg_w(ov, 0x39, hsegs); - reg_w(ov, 0x3a, vsegs); - - /* Windows driver does this here; who knows why */ - reg_w(ov, 0x2f, 0x80); - - /******** Set the framerate (to 15 FPS) ********/ - - /* Mode independent, but framerate dependent, regs */ - reg_w(ov, 0x51, 0x02); /* Clock divider; lower==faster */ - reg_w(ov, 0x22, 0x18); - reg_w(ov, 0x23, 0xff); - - if (ov->bridge == BRG_OV518PLUS) - reg_w(ov, 0x21, 0x19); - else - reg_w(ov, 0x71, 0x19); /* Compression-related? */ - - // FIXME: Sensor-specific - /* Bit 5 is what matters here. Of course, it is "reserved" */ - i2c_w(ov, 0x54, 0x23); - - reg_w(ov, 0x2f, 0x80); - - if (ov->bridge == BRG_OV518PLUS) { - reg_w(ov, 0x24, 0x94); - reg_w(ov, 0x25, 0x90); - ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ - ov518_reg_w32(ov, 0xc6, 540, 2); /* 21ch */ - ov518_reg_w32(ov, 0xc7, 540, 2); /* 21ch */ - ov518_reg_w32(ov, 0xc8, 108, 2); /* 6ch */ - ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ - ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ - ov518_reg_w32(ov, 0xcc, 2400, 2); /* 960h */ - ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ - ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ - } else { - reg_w(ov, 0x24, 0x9f); - reg_w(ov, 0x25, 0x90); - ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */ - ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */ - ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */ - ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */ - ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */ - ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */ - ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */ - ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */ - ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */ - } - - reg_w(ov, 0x2f, 0x80); - - if (ov51x_restart(ov) < 0) - return -EIO; - - /* Reset it just for good measure */ - if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) - return -EIO; - - return 0; -} - -/* This is a wrapper around the OV511, OV518, and sensor specific functions */ -static int -mode_init_regs(struct usb_ov511 *ov, - int width, int height, int mode, int sub_flag) -{ - int rc = 0; - - if (!ov || !ov->dev) - return -EFAULT; - - if (ov->bclass == BCL_OV518) { - rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag); - } else { - rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag); - } - - if (FATAL_ERROR(rc)) - return rc; - - switch (ov->sensor) { - case SEN_OV7610: - case SEN_OV7620: - case SEN_OV76BE: - case SEN_OV8600: - case SEN_OV6620: - case SEN_OV6630: - rc = set_ov_sensor_window(ov, width, height, mode, sub_flag); - break; - case SEN_KS0127: - case SEN_KS0127B: - err("KS0127-series decoders not supported yet"); - rc = -EINVAL; - break; - case SEN_SAA7111A: -// rc = mode_init_saa_sensor_regs(ov, width, height, mode, -// sub_flag); - - PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f)); - break; - default: - err("Unknown sensor"); - rc = -EINVAL; - } - - if (FATAL_ERROR(rc)) - return rc; - - /* Sensor-independent settings */ - rc = sensor_set_auto_brightness(ov, ov->auto_brt); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_set_auto_exposure(ov, ov->auto_exp); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_set_banding_filter(ov, bandingfilter); - if (FATAL_ERROR(rc)) - return rc; - - if (ov->lightfreq) { - rc = sensor_set_light_freq(ov, lightfreq); - if (FATAL_ERROR(rc)) - return rc; - } - - rc = sensor_set_backlight(ov, ov->backlight); - if (FATAL_ERROR(rc)) - return rc; - - rc = sensor_set_mirror(ov, ov->mirror); - if (FATAL_ERROR(rc)) - return rc; - - return 0; -} - -/* This sets the default image parameters. This is useful for apps that use - * read() and do not set these. - */ -static int -ov51x_set_default_params(struct usb_ov511 *ov) -{ - int i; - - /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used - * (using read() instead). */ - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov->frame[i].width = ov->maxwidth; - ov->frame[i].height = ov->maxheight; - ov->frame[i].bytes_read = 0; - if (force_palette) - ov->frame[i].format = force_palette; - else - ov->frame[i].format = VIDEO_PALETTE_YUV420; - - ov->frame[i].depth = get_depth(ov->frame[i].format); - } - - PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight, - symbolic(v4l1_plist, ov->frame[0].format)); - - /* Initialize to max width/height, YUV420 or RGB24 (if supported) */ - if (mode_init_regs(ov, ov->maxwidth, ov->maxheight, - ov->frame[0].format, 0) < 0) - return -EINVAL; - - return 0; -} - -/********************************************************************** - * - * Video decoder stuff - * - **********************************************************************/ - -/* Set analog input port of decoder */ -static int -decoder_set_input(struct usb_ov511 *ov, int input) -{ - PDEBUG(4, "port %d", input); - - switch (ov->sensor) { - case SEN_SAA7111A: - { - /* Select mode */ - i2c_w_mask(ov, 0x02, input, 0x07); - /* Bypass chrominance trap for modes 4..7 */ - i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80); - break; - } - default: - return -EINVAL; - } - - return 0; -} - -/* Get ASCII name of video input */ -static int -decoder_get_input_name(struct usb_ov511 *ov, int input, char *name) -{ - switch (ov->sensor) { - case SEN_SAA7111A: - { - if (input < 0 || input > 7) - return -EINVAL; - else if (input < 4) - sprintf(name, "CVBS-%d", input); - else // if (input < 8) - sprintf(name, "S-Video-%d", input - 4); - break; - } - default: - sprintf(name, "%s", "Camera"); - } - - return 0; -} - -/* Set norm (NTSC, PAL, SECAM, AUTO) */ -static int -decoder_set_norm(struct usb_ov511 *ov, int norm) -{ - PDEBUG(4, "%d", norm); - - switch (ov->sensor) { - case SEN_SAA7111A: - { - int reg_8, reg_e; - - if (norm == VIDEO_MODE_NTSC) { - reg_8 = 0x40; /* 60 Hz */ - reg_e = 0x00; /* NTSC M / PAL BGHI */ - } else if (norm == VIDEO_MODE_PAL) { - reg_8 = 0x00; /* 50 Hz */ - reg_e = 0x00; /* NTSC M / PAL BGHI */ - } else if (norm == VIDEO_MODE_AUTO) { - reg_8 = 0x80; /* Auto field detect */ - reg_e = 0x00; /* NTSC M / PAL BGHI */ - } else if (norm == VIDEO_MODE_SECAM) { - reg_8 = 0x00; /* 50 Hz */ - reg_e = 0x50; /* SECAM / PAL 4.43 */ - } else { - return -EINVAL; - } - - i2c_w_mask(ov, 0x08, reg_8, 0xc0); - i2c_w_mask(ov, 0x0e, reg_e, 0x70); - break; - } - default: - return -EINVAL; - } - - return 0; -} - -/********************************************************************** - * - * Raw data parsing - * - **********************************************************************/ - -/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the - * image at pOut is specified by w. - */ -static inline void -make_8x8(unsigned char *pIn, unsigned char *pOut, int w) -{ - unsigned char *pOut1 = pOut; - int x, y; - - for (y = 0; y < 8; y++) { - pOut1 = pOut; - for (x = 0; x < 8; x++) { - *pOut1++ = *pIn++; - } - pOut += w; - } -} - -/* - * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. - * The segments represent 4 squares of 8x8 pixels as follows: - * - * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 - * 8 9 ... 15 72 73 ... 79 200 201 ... 207 - * ... ... ... - * 56 57 ... 63 120 121 ... 127 248 249 ... 255 - * - */ -static void -yuv400raw_to_yuv400p(struct ov511_frame *frame, - unsigned char *pIn0, unsigned char *pOut0) -{ - int x, y; - unsigned char *pIn, *pOut, *pOutLine; - - /* Copy Y */ - pIn = pIn0; - pOutLine = pOut0; - for (y = 0; y < frame->rawheight - 1; y += 8) { - pOut = pOutLine; - for (x = 0; x < frame->rawwidth - 1; x += 8) { - make_8x8(pIn, pOut, frame->rawwidth); - pIn += 64; - pOut += 8; - } - pOutLine += 8 * frame->rawwidth; - } -} - -/* - * For YUV 4:2:0 images, the data show up in 384 byte segments. - * The first 64 bytes of each segment are U, the next 64 are V. The U and - * V are arranged as follows: - * - * 0 1 ... 7 - * 8 9 ... 15 - * ... - * 56 57 ... 63 - * - * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block). - * - * The next 256 bytes are full resolution Y data and represent 4 squares - * of 8x8 pixels as follows: - * - * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 - * 8 9 ... 15 72 73 ... 79 200 201 ... 207 - * ... ... ... - * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 - * - * Note that the U and V data in one segment represent a 16 x 16 pixel - * area, but the Y data represent a 32 x 8 pixel area. If the width is not an - * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the - * next horizontal stripe. - * - * If dumppix module param is set, _parse_data just dumps the incoming segments, - * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 - * this puts the data on the standard output and can be analyzed with the - * parseppm.c utility I wrote. That's a much faster way for figuring out how - * these data are scrambled. - */ - -/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. - * - * FIXME: Currently only handles width and height that are multiples of 16 - */ -static void -yuv420raw_to_yuv420p(struct ov511_frame *frame, - unsigned char *pIn0, unsigned char *pOut0) -{ - int k, x, y; - unsigned char *pIn, *pOut, *pOutLine; - const unsigned int a = frame->rawwidth * frame->rawheight; - const unsigned int w = frame->rawwidth / 2; - - /* Copy U and V */ - pIn = pIn0; - pOutLine = pOut0 + a; - for (y = 0; y < frame->rawheight - 1; y += 16) { - pOut = pOutLine; - for (x = 0; x < frame->rawwidth - 1; x += 16) { - make_8x8(pIn, pOut, w); - make_8x8(pIn + 64, pOut + a/4, w); - pIn += 384; - pOut += 8; - } - pOutLine += 8 * w; - } - - /* Copy Y */ - pIn = pIn0 + 128; - pOutLine = pOut0; - k = 0; - for (y = 0; y < frame->rawheight - 1; y += 8) { - pOut = pOutLine; - for (x = 0; x < frame->rawwidth - 1; x += 8) { - make_8x8(pIn, pOut, frame->rawwidth); - pIn += 64; - pOut += 8; - if ((++k) > 3) { - k = 0; - pIn += 128; - } - } - pOutLine += 8 * frame->rawwidth; - } -} - -/********************************************************************** - * - * Decompression - * - **********************************************************************/ - -static int -request_decompressor(struct usb_ov511 *ov) -{ - if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) { - err("No decompressor available"); - } else { - err("Unknown bridge"); - } - - return -ENOSYS; -} - -static void -decompress(struct usb_ov511 *ov, struct ov511_frame *frame, - unsigned char *pIn0, unsigned char *pOut0) -{ - if (!ov->decomp_ops) - if (request_decompressor(ov)) - return; - -} - -/********************************************************************** - * - * Format conversion - * - **********************************************************************/ - -/* Fuses even and odd fields together, and doubles width. - * INPUT: an odd field followed by an even field at pIn0, in YUV planar format - * OUTPUT: a normal YUV planar image, with correct aspect ratio - */ -static void -deinterlace(struct ov511_frame *frame, int rawformat, - unsigned char *pIn0, unsigned char *pOut0) -{ - const int fieldheight = frame->rawheight / 2; - const int fieldpix = fieldheight * frame->rawwidth; - const int w = frame->width; - int x, y; - unsigned char *pInEven, *pInOdd, *pOut; - - PDEBUG(5, "fieldheight=%d", fieldheight); - - if (frame->rawheight != frame->height) { - err("invalid height"); - return; - } - - if ((frame->rawwidth * 2) != frame->width) { - err("invalid width"); - return; - } - - /* Y */ - pInOdd = pIn0; - pInEven = pInOdd + fieldpix; - pOut = pOut0; - for (y = 0; y < fieldheight; y++) { - for (x = 0; x < frame->rawwidth; x++) { - *pOut = *pInEven; - *(pOut+1) = *pInEven++; - *(pOut+w) = *pInOdd; - *(pOut+w+1) = *pInOdd++; - pOut += 2; - } - pOut += w; - } - - if (rawformat == RAWFMT_YUV420) { - /* U */ - pInOdd = pIn0 + fieldpix * 2; - pInEven = pInOdd + fieldpix / 4; - for (y = 0; y < fieldheight / 2; y++) { - for (x = 0; x < frame->rawwidth / 2; x++) { - *pOut = *pInEven; - *(pOut+1) = *pInEven++; - *(pOut+w/2) = *pInOdd; - *(pOut+w/2+1) = *pInOdd++; - pOut += 2; - } - pOut += w/2; - } - /* V */ - pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2; - pInEven = pInOdd + fieldpix / 4; - for (y = 0; y < fieldheight / 2; y++) { - for (x = 0; x < frame->rawwidth / 2; x++) { - *pOut = *pInEven; - *(pOut+1) = *pInEven++; - *(pOut+w/2) = *pInOdd; - *(pOut+w/2+1) = *pInOdd++; - pOut += 2; - } - pOut += w/2; - } - } -} - -static void -ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame) -{ - /* Deinterlace frame, if necessary */ - if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { - if (frame->compressed) - decompress(ov, frame, frame->rawdata, - frame->tempdata); - else - yuv400raw_to_yuv400p(frame, frame->rawdata, - frame->tempdata); - - deinterlace(frame, RAWFMT_YUV400, frame->tempdata, - frame->data); - } else { - if (frame->compressed) - decompress(ov, frame, frame->rawdata, - frame->data); - else - yuv400raw_to_yuv400p(frame, frame->rawdata, - frame->data); - } -} - -/* Process raw YUV420 data into standard YUV420P */ -static void -ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame) -{ - /* Deinterlace frame, if necessary */ - if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) { - if (frame->compressed) - decompress(ov, frame, frame->rawdata, frame->tempdata); - else - yuv420raw_to_yuv420p(frame, frame->rawdata, - frame->tempdata); - - deinterlace(frame, RAWFMT_YUV420, frame->tempdata, - frame->data); - } else { - if (frame->compressed) - decompress(ov, frame, frame->rawdata, frame->data); - else - yuv420raw_to_yuv420p(frame, frame->rawdata, - frame->data); - } -} - -/* Post-processes the specified frame. This consists of: - * 1. Decompress frame, if necessary - * 2. Deinterlace frame and scale to proper size, if necessary - * 3. Convert from YUV planar to destination format, if necessary - * 4. Fix the RGB offset, if necessary - */ -static void -ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) -{ - if (dumppix) { - memset(frame->data, 0, - MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); - PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); - memcpy(frame->data, frame->rawdata, frame->bytes_recvd); - } else { - switch (frame->format) { - case VIDEO_PALETTE_GREY: - ov51x_postprocess_grey(ov, frame); - break; - case VIDEO_PALETTE_YUV420: - case VIDEO_PALETTE_YUV420P: - ov51x_postprocess_yuv420(ov, frame); - break; - default: - err("Cannot convert data to %s", - symbolic(v4l1_plist, frame->format)); - } - } -} - -/********************************************************************** - * - * OV51x data transfer, IRQ handler - * - **********************************************************************/ - -static inline void -ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) -{ - int num, offset; - int pnum = in[ov->packet_size - 1]; /* Get packet number */ - int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); - struct ov511_frame *frame = &ov->frame[ov->curframe]; - struct timeval *ts; - - /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th - * byte non-zero. The EOF packet has image width/height in the - * 10th and 11th bytes. The 9th byte is given as follows: - * - * bit 7: EOF - * 6: compression enabled - * 5: 422/420/400 modes - * 4: 422/420/400 modes - * 3: 1 - * 2: snapshot button on - * 1: snapshot frame - * 0: even/odd field - */ - - if (printph) { - info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x", - pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6], - in[7], in[8], in[9], in[10], in[11]); - } - - /* Check for SOF/EOF packet */ - if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) || - (~in[8] & 0x08)) - goto check_middle; - - /* Frame end */ - if (in[8] & 0x80) { - ts = (struct timeval *)(frame->data - + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); - do_gettimeofday(ts); - - /* Get the actual frame size from the EOF header */ - frame->rawwidth = ((int)(in[9]) + 1) * 8; - frame->rawheight = ((int)(in[10]) + 1) * 8; - - PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d", - ov->curframe, pnum, frame->rawwidth, frame->rawheight, - frame->bytes_recvd); - - /* Validate the header data */ - RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); - RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, - ov->maxheight); - - /* Don't allow byte count to exceed buffer size */ - RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); - - if (frame->scanstate == STATE_LINES) { - int nextf; - - frame->grabstate = FRAME_DONE; - wake_up_interruptible(&frame->wq); - - /* If next frame is ready or grabbing, - * point to it */ - nextf = (ov->curframe + 1) % OV511_NUMFRAMES; - if (ov->frame[nextf].grabstate == FRAME_READY - || ov->frame[nextf].grabstate == FRAME_GRABBING) { - ov->curframe = nextf; - ov->frame[nextf].scanstate = STATE_SCANNING; - } else { - if (frame->grabstate == FRAME_DONE) { - PDEBUG(4, "** Frame done **"); - } else { - PDEBUG(4, "Frame not ready? state = %d", - ov->frame[nextf].grabstate); - } - - ov->curframe = -1; - } - } else { - PDEBUG(5, "Frame done, but not scanning"); - } - /* Image corruption caused by misplaced frame->segment = 0 - * fixed by carlosf@conectiva.com.br - */ - } else { - /* Frame start */ - PDEBUG(4, "Frame start, framenum = %d", ov->curframe); - - /* Check to see if it's a snapshot frame */ - /* FIXME?? Should the snapshot reset go here? Performance? */ - if (in[8] & 0x02) { - frame->snapshot = 1; - PDEBUG(3, "snapshot detected"); - } - - frame->scanstate = STATE_LINES; - frame->bytes_recvd = 0; - frame->compressed = in[8] & 0x40; - } - -check_middle: - /* Are we in a frame? */ - if (frame->scanstate != STATE_LINES) { - PDEBUG(5, "Not in a frame; packet skipped"); - return; - } - - /* If frame start, skip header */ - if (frame->bytes_recvd == 0) - offset = 9; - else - offset = 0; - - num = n - offset - 1; - - /* Dump all data exactly as received */ - if (dumppix == 2) { - frame->bytes_recvd += n - 1; - if (frame->bytes_recvd <= max_raw) - memcpy(frame->rawdata + frame->bytes_recvd - (n - 1), - in, n - 1); - else - PDEBUG(3, "Raw data buffer overrun!! (%d)", - frame->bytes_recvd - max_raw); - } else if (!frame->compressed && !remove_zeros) { - frame->bytes_recvd += num; - if (frame->bytes_recvd <= max_raw) - memcpy(frame->rawdata + frame->bytes_recvd - num, - in + offset, num); - else - PDEBUG(3, "Raw data buffer overrun!! (%d)", - frame->bytes_recvd - max_raw); - } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */ - int b, read = 0, allzero, copied = 0; - if (offset) { - frame->bytes_recvd += 32 - offset; // Bytes out - memcpy(frame->rawdata, in + offset, 32 - offset); - read += 32; - } - - while (read < n - 1) { - allzero = 1; - for (b = 0; b < 32; b++) { - if (in[read + b]) { - allzero = 0; - break; - } - } - - if (allzero) { - /* Don't copy it */ - } else { - if (frame->bytes_recvd + copied + 32 <= max_raw) - { - memcpy(frame->rawdata - + frame->bytes_recvd + copied, - in + read, 32); - copied += 32; - } else { - PDEBUG(3, "Raw data buffer overrun!!"); - } - } - read += 32; - } - - frame->bytes_recvd += copied; - } -} - -static inline void -ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) -{ - int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight); - struct ov511_frame *frame = &ov->frame[ov->curframe]; - struct timeval *ts; - - /* Don't copy the packet number byte */ - if (ov->packet_numbering) - --n; - - /* A false positive here is likely, until OVT gives me - * the definitive SOF/EOF format */ - if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) { - if (printph) { - info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0], - in[1], in[2], in[3], in[4], in[5], in[6], in[7]); - } - - if (frame->scanstate == STATE_LINES) { - PDEBUG(4, "Detected frame end/start"); - goto eof; - } else { //scanstate == STATE_SCANNING - /* Frame start */ - PDEBUG(4, "Frame start, framenum = %d", ov->curframe); - goto sof; - } - } else { - goto check_middle; - } - -eof: - ts = (struct timeval *)(frame->data - + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); - do_gettimeofday(ts); - - PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", - ov->curframe, - (int)(in[9]), (int)(in[10]), frame->bytes_recvd); - - // FIXME: Since we don't know the header formats yet, - // there is no way to know what the actual image size is - frame->rawwidth = frame->width; - frame->rawheight = frame->height; - - /* Validate the header data */ - RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); - RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); - - /* Don't allow byte count to exceed buffer size */ - RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw); - - if (frame->scanstate == STATE_LINES) { - int nextf; - - frame->grabstate = FRAME_DONE; - wake_up_interruptible(&frame->wq); - - /* If next frame is ready or grabbing, - * point to it */ - nextf = (ov->curframe + 1) % OV511_NUMFRAMES; - if (ov->frame[nextf].grabstate == FRAME_READY - || ov->frame[nextf].grabstate == FRAME_GRABBING) { - ov->curframe = nextf; - ov->frame[nextf].scanstate = STATE_SCANNING; - frame = &ov->frame[nextf]; - } else { - if (frame->grabstate == FRAME_DONE) { - PDEBUG(4, "** Frame done **"); - } else { - PDEBUG(4, "Frame not ready? state = %d", - ov->frame[nextf].grabstate); - } - - ov->curframe = -1; - PDEBUG(4, "SOF dropped (no active frame)"); - return; /* Nowhere to store this frame */ - } - } -sof: - PDEBUG(4, "Starting capture on frame %d", frame->framenum); - -// Snapshot not reverse-engineered yet. -#if 0 - /* Check to see if it's a snapshot frame */ - /* FIXME?? Should the snapshot reset go here? Performance? */ - if (in[8] & 0x02) { - frame->snapshot = 1; - PDEBUG(3, "snapshot detected"); - } -#endif - frame->scanstate = STATE_LINES; - frame->bytes_recvd = 0; - frame->compressed = 1; - -check_middle: - /* Are we in a frame? */ - if (frame->scanstate != STATE_LINES) { - PDEBUG(4, "scanstate: no SOF yet"); - return; - } - - /* Dump all data exactly as received */ - if (dumppix == 2) { - frame->bytes_recvd += n; - if (frame->bytes_recvd <= max_raw) - memcpy(frame->rawdata + frame->bytes_recvd - n, in, n); - else - PDEBUG(3, "Raw data buffer overrun!! (%d)", - frame->bytes_recvd - max_raw); - } else { - /* All incoming data are divided into 8-byte segments. If the - * segment contains all zero bytes, it must be skipped. These - * zero-segments allow the OV518 to mainain a constant data rate - * regardless of the effectiveness of the compression. Segments - * are aligned relative to the beginning of each isochronous - * packet. The first segment in each image is a header (the - * decompressor skips it later). - */ - - int b, read = 0, allzero, copied = 0; - - while (read < n) { - allzero = 1; - for (b = 0; b < 8; b++) { - if (in[read + b]) { - allzero = 0; - break; - } - } - - if (allzero) { - /* Don't copy it */ - } else { - if (frame->bytes_recvd + copied + 8 <= max_raw) - { - memcpy(frame->rawdata - + frame->bytes_recvd + copied, - in + read, 8); - copied += 8; - } else { - PDEBUG(3, "Raw data buffer overrun!!"); - } - } - read += 8; - } - frame->bytes_recvd += copied; - } -} - -static void -ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs) -{ - int i; - struct usb_ov511 *ov; - struct ov511_sbuf *sbuf; - - if (!urb->context) { - PDEBUG(4, "no context"); - return; - } - - sbuf = urb->context; - ov = sbuf->ov; - - if (!ov || !ov->dev || !ov->user) { - PDEBUG(4, "no device, or not open"); - return; - } - - if (!ov->streaming) { - PDEBUG(4, "hmmm... not streaming, but got interrupt"); - return; - } - - if (urb->status == -ENOENT || urb->status == -ECONNRESET) { - PDEBUG(4, "URB unlinked"); - return; - } - - if (urb->status != -EINPROGRESS && urb->status != 0) { - err("ERROR: urb->status=%d: %s", urb->status, - symbolic(urb_errlist, urb->status)); - } - - /* Copy the data received into our frame buffer */ - PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n, - urb->number_of_packets); - for (i = 0; i < urb->number_of_packets; i++) { - /* Warning: Don't call *_move_data() if no frame active! */ - if (ov->curframe >= 0) { - int n = urb->iso_frame_desc[i].actual_length; - int st = urb->iso_frame_desc[i].status; - unsigned char *cdata; - - urb->iso_frame_desc[i].actual_length = 0; - urb->iso_frame_desc[i].status = 0; - - cdata = urb->transfer_buffer - + urb->iso_frame_desc[i].offset; - - if (!n) { - PDEBUG(4, "Zero-length packet"); - continue; - } - - if (st) - PDEBUG(2, "data error: [%d] len=%d, status=%d", - i, n, st); - - if (ov->bclass == BCL_OV511) - ov511_move_data(ov, cdata, n); - else if (ov->bclass == BCL_OV518) - ov518_move_data(ov, cdata, n); - else - err("Unknown bridge device (%d)", ov->bridge); - - } else if (waitqueue_active(&ov->wq)) { - wake_up_interruptible(&ov->wq); - } - } - - /* Resubmit this URB */ - urb->dev = ov->dev; - if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) - err("usb_submit_urb() ret %d", i); - - return; -} - -/**************************************************************************** - * - * Stream initialization and termination - * - ***************************************************************************/ - -static int -ov51x_init_isoc(struct usb_ov511 *ov) -{ - struct urb *urb; - int fx, err, n, size; - - PDEBUG(3, "*** Initializing capture ***"); - - ov->curframe = -1; - - if (ov->bridge == BRG_OV511) { - if (cams == 1) - size = 993; - else if (cams == 2) - size = 513; - else if (cams == 3 || cams == 4) - size = 257; - else { - err("\"cams\" parameter too high!"); - return -1; - } - } else if (ov->bridge == BRG_OV511PLUS) { - if (cams == 1) - size = 961; - else if (cams == 2) - size = 513; - else if (cams == 3 || cams == 4) - size = 257; - else if (cams >= 5 && cams <= 8) - size = 129; - else if (cams >= 9 && cams <= 31) - size = 33; - else { - err("\"cams\" parameter too high!"); - return -1; - } - } else if (ov->bclass == BCL_OV518) { - if (cams == 1) - size = 896; - else if (cams == 2) - size = 512; - else if (cams == 3 || cams == 4) - size = 256; - else if (cams >= 5 && cams <= 8) - size = 128; - else { - err("\"cams\" parameter too high!"); - return -1; - } - } else { - err("invalid bridge type"); - return -1; - } - - // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now - if (ov->bclass == BCL_OV518) { - if (packetsize == -1) { - ov518_set_packet_size(ov, 640); - } else { - info("Forcing packet size to %d", packetsize); - ov518_set_packet_size(ov, packetsize); - } - } else { - if (packetsize == -1) { - ov511_set_packet_size(ov, size); - } else { - info("Forcing packet size to %d", packetsize); - ov511_set_packet_size(ov, packetsize); - } - } - - for (n = 0; n < OV511_NUMSBUF; n++) { - urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); - if (!urb) { - err("init isoc: usb_alloc_urb ret. NULL"); - return -ENOMEM; - } - ov->sbuf[n].urb = urb; - urb->dev = ov->dev; - urb->context = &ov->sbuf[n]; - urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = ov->sbuf[n].data; - urb->complete = ov51x_isoc_irq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; - urb->interval = 1; - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = ov->packet_size * fx; - urb->iso_frame_desc[fx].length = ov->packet_size; - } - } - - ov->streaming = 1; - - for (n = 0; n < OV511_NUMSBUF; n++) { - ov->sbuf[n].urb->dev = ov->dev; - err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL); - if (err) { - err("init isoc: usb_submit_urb(%d) ret %d", n, err); - return err; - } - } - - return 0; -} - -static void -ov51x_unlink_isoc(struct usb_ov511 *ov) -{ - int n; - - /* Unschedule all of the iso td's */ - for (n = OV511_NUMSBUF - 1; n >= 0; n--) { - if (ov->sbuf[n].urb) { - usb_kill_urb(ov->sbuf[n].urb); - usb_free_urb(ov->sbuf[n].urb); - ov->sbuf[n].urb = NULL; - } - } -} - -static void -ov51x_stop_isoc(struct usb_ov511 *ov) -{ - if (!ov->streaming || !ov->dev) - return; - - PDEBUG(3, "*** Stopping capture ***"); - - if (ov->bclass == BCL_OV518) - ov518_set_packet_size(ov, 0); - else - ov511_set_packet_size(ov, 0); - - ov->streaming = 0; - - ov51x_unlink_isoc(ov); -} - -static int -ov51x_new_frame(struct usb_ov511 *ov, int framenum) -{ - struct ov511_frame *frame; - int newnum; - - PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum); - - if (!ov->dev) - return -1; - - /* If we're not grabbing a frame right now and the other frame is */ - /* ready to be grabbed into, then use it instead */ - if (ov->curframe == -1) { - newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES; - if (ov->frame[newnum].grabstate == FRAME_READY) - framenum = newnum; - } else - return 0; - - frame = &ov->frame[framenum]; - - PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum, - frame->width, frame->height); - - frame->grabstate = FRAME_GRABBING; - frame->scanstate = STATE_SCANNING; - frame->snapshot = 0; - - ov->curframe = framenum; - - /* Make sure it's not too big */ - if (frame->width > ov->maxwidth) - frame->width = ov->maxwidth; - - frame->width &= ~7L; /* Multiple of 8 */ - - if (frame->height > ov->maxheight) - frame->height = ov->maxheight; - - frame->height &= ~3L; /* Multiple of 4 */ - - return 0; -} - -/**************************************************************************** - * - * Buffer management - * - ***************************************************************************/ - -/* - * - You must acquire buf_lock before entering this function. - * - Because this code will free any non-null pointer, you must be sure to null - * them if you explicitly free them somewhere else! - */ -static void -ov51x_do_dealloc(struct usb_ov511 *ov) -{ - int i; - PDEBUG(4, "entered"); - - if (ov->fbuf) { - rvfree(ov->fbuf, OV511_NUMFRAMES - * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); - ov->fbuf = NULL; - } - - vfree(ov->rawfbuf); - ov->rawfbuf = NULL; - - vfree(ov->tempfbuf); - ov->tempfbuf = NULL; - - for (i = 0; i < OV511_NUMSBUF; i++) { - kfree(ov->sbuf[i].data); - ov->sbuf[i].data = NULL; - } - - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov->frame[i].data = NULL; - ov->frame[i].rawdata = NULL; - ov->frame[i].tempdata = NULL; - if (ov->frame[i].compbuf) { - free_page((unsigned long) ov->frame[i].compbuf); - ov->frame[i].compbuf = NULL; - } - } - - PDEBUG(4, "buffer memory deallocated"); - ov->buf_state = BUF_NOT_ALLOCATED; - PDEBUG(4, "leaving"); -} - -static int -ov51x_alloc(struct usb_ov511 *ov) -{ - int i; - const int w = ov->maxwidth; - const int h = ov->maxheight; - const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h); - const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h); - - PDEBUG(4, "entered"); - mutex_lock(&ov->buf_lock); - - if (ov->buf_state == BUF_ALLOCATED) - goto out; - - ov->fbuf = rvmalloc(data_bufsize); - if (!ov->fbuf) - goto error; - - ov->rawfbuf = vmalloc(raw_bufsize); - if (!ov->rawfbuf) - goto error; - - memset(ov->rawfbuf, 0, raw_bufsize); - - ov->tempfbuf = vmalloc(raw_bufsize); - if (!ov->tempfbuf) - goto error; - - memset(ov->tempfbuf, 0, raw_bufsize); - - for (i = 0; i < OV511_NUMSBUF; i++) { - ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * - MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); - if (!ov->sbuf[i].data) - goto error; - - PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); - } - - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h); - ov->frame[i].rawdata = ov->rawfbuf - + i * MAX_RAW_DATA_SIZE(w, h); - ov->frame[i].tempdata = ov->tempfbuf - + i * MAX_RAW_DATA_SIZE(w, h); - - ov->frame[i].compbuf = - (unsigned char *) __get_free_page(GFP_KERNEL); - if (!ov->frame[i].compbuf) - goto error; - - PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); - } - - ov->buf_state = BUF_ALLOCATED; -out: - mutex_unlock(&ov->buf_lock); - PDEBUG(4, "leaving"); - return 0; -error: - ov51x_do_dealloc(ov); - mutex_unlock(&ov->buf_lock); - PDEBUG(4, "errored"); - return -ENOMEM; -} - -static void -ov51x_dealloc(struct usb_ov511 *ov) -{ - PDEBUG(4, "entered"); - mutex_lock(&ov->buf_lock); - ov51x_do_dealloc(ov); - mutex_unlock(&ov->buf_lock); - PDEBUG(4, "leaving"); -} - -/**************************************************************************** - * - * V4L 1 API - * - ***************************************************************************/ - -static int -ov51x_v4l1_open(struct inode *inode, struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct usb_ov511 *ov = video_get_drvdata(vdev); - int err, i; - - PDEBUG(4, "opening"); - - mutex_lock(&ov->lock); - - err = -EBUSY; - if (ov->user) - goto out; - - ov->sub_flag = 0; - - /* In case app doesn't set them... */ - err = ov51x_set_default_params(ov); - if (err < 0) - goto out; - - /* Make sure frames are reset */ - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov->frame[i].grabstate = FRAME_UNUSED; - ov->frame[i].bytes_read = 0; - } - - /* If compression is on, make sure now that a - * decompressor can be loaded */ - if (ov->compress && !ov->decomp_ops) { - err = request_decompressor(ov); - if (err && !dumppix) - goto out; - } - - err = ov51x_alloc(ov); - if (err < 0) - goto out; - - err = ov51x_init_isoc(ov); - if (err) { - ov51x_dealloc(ov); - goto out; - } - - ov->user++; - file->private_data = vdev; - - if (ov->led_policy == LED_AUTO) - ov51x_led_control(ov, 1); - -out: - mutex_unlock(&ov->lock); - return err; -} - -static int -ov51x_v4l1_close(struct inode *inode, struct file *file) -{ - struct video_device *vdev = file->private_data; - struct usb_ov511 *ov = video_get_drvdata(vdev); - - PDEBUG(4, "ov511_close"); - - mutex_lock(&ov->lock); - - ov->user--; - ov51x_stop_isoc(ov); - - if (ov->led_policy == LED_AUTO) - ov51x_led_control(ov, 0); - - if (ov->dev) - ov51x_dealloc(ov); - - mutex_unlock(&ov->lock); - - /* Device unplugged while open. Only a minimum of unregistration is done - * here; the disconnect callback already did the rest. */ - if (!ov->dev) { - mutex_lock(&ov->cbuf_lock); - kfree(ov->cbuf); - ov->cbuf = NULL; - mutex_unlock(&ov->cbuf_lock); - - ov51x_dealloc(ov); - kfree(ov); - ov = NULL; - } - - file->private_data = NULL; - return 0; -} - -/* Do not call this function directly! */ -static int -ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *vdev = file->private_data; - struct usb_ov511 *ov = video_get_drvdata(vdev); - PDEBUG(5, "IOCtl: 0x%X", cmd); - - if (!ov->dev) - return -EIO; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - - PDEBUG(4, "VIDIOCGCAP"); - - memset(b, 0, sizeof(struct video_capability)); - sprintf(b->name, "%s USB Camera", - symbolic(brglist, ov->bridge)); - b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; - b->channels = ov->num_inputs; - b->audios = 0; - b->maxwidth = ov->maxwidth; - b->maxheight = ov->maxheight; - b->minwidth = ov->minwidth; - b->minheight = ov->minheight; - - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - - PDEBUG(4, "VIDIOCGCHAN"); - - if ((unsigned)(v->channel) >= ov->num_inputs) { - err("Invalid channel (%d)", v->channel); - return -EINVAL; - } - - v->norm = ov->norm; - v->type = VIDEO_TYPE_CAMERA; - v->flags = 0; -// v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; - v->tuners = 0; - decoder_get_input_name(ov, v->channel, v->name); - - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - int err; - - PDEBUG(4, "VIDIOCSCHAN"); - - /* Make sure it's not a camera */ - if (!ov->has_decoder) { - if (v->channel == 0) - return 0; - else - return -EINVAL; - } - - if (v->norm != VIDEO_MODE_PAL && - v->norm != VIDEO_MODE_NTSC && - v->norm != VIDEO_MODE_SECAM && - v->norm != VIDEO_MODE_AUTO) { - err("Invalid norm (%d)", v->norm); - return -EINVAL; - } - - if ((unsigned)(v->channel) >= ov->num_inputs) { - err("Invalid channel (%d)", v->channel); - return -EINVAL; - } - - err = decoder_set_input(ov, v->channel); - if (err) - return err; - - err = decoder_set_norm(ov, v->norm); - if (err) - return err; - - return 0; - } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - - PDEBUG(4, "VIDIOCGPICT"); - - memset(p, 0, sizeof(struct video_picture)); - if (sensor_get_picture(ov, p)) - return -EIO; - - /* Can we get these from frame[0]? -claudio? */ - p->depth = ov->frame[0].depth; - p->palette = ov->frame[0].format; - - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - int i, rc; - - PDEBUG(4, "VIDIOCSPICT"); - - if (!get_depth(p->palette)) - return -EINVAL; - - if (sensor_set_picture(ov, p)) - return -EIO; - - if (force_palette && p->palette != force_palette) { - info("Palette rejected (%s)", - symbolic(v4l1_plist, p->palette)); - return -EINVAL; - } - - // FIXME: Format should be independent of frames - if (p->palette != ov->frame[0].format) { - PDEBUG(4, "Detected format change"); - - rc = ov51x_wait_frames_inactive(ov); - if (rc) - return rc; - - mode_init_regs(ov, ov->frame[0].width, - ov->frame[0].height, p->palette, ov->sub_flag); - } - - PDEBUG(4, "Setting depth=%d, palette=%s", - p->depth, symbolic(v4l1_plist, p->palette)); - - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov->frame[i].depth = p->depth; - ov->frame[i].format = p->palette; - } - - return 0; - } - case VIDIOCGCAPTURE: - { - int *vf = arg; - - PDEBUG(4, "VIDIOCGCAPTURE"); - - ov->sub_flag = *vf; - return 0; - } - case VIDIOCSCAPTURE: - { - struct video_capture *vc = arg; - - PDEBUG(4, "VIDIOCSCAPTURE"); - - if (vc->flags) - return -EINVAL; - if (vc->decimation) - return -EINVAL; - - vc->x &= ~3L; - vc->y &= ~1L; - vc->y &= ~31L; - - if (vc->width == 0) - vc->width = 32; - - vc->height /= 16; - vc->height *= 16; - if (vc->height == 0) - vc->height = 16; - - ov->subx = vc->x; - ov->suby = vc->y; - ov->subw = vc->width; - ov->subh = vc->height; - - return 0; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - int i, rc; - - PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height); - -#if 0 - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (vw->height != ov->maxheight) - return -EINVAL; - if (vw->width != ov->maxwidth) - return -EINVAL; -#endif - - rc = ov51x_wait_frames_inactive(ov); - if (rc) - return rc; - - rc = mode_init_regs(ov, vw->width, vw->height, - ov->frame[0].format, ov->sub_flag); - if (rc < 0) - return rc; - - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov->frame[i].width = vw->width; - ov->frame[i].height = vw->height; - } - - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - - memset(vw, 0, sizeof(struct video_window)); - vw->x = 0; /* FIXME */ - vw->y = 0; - vw->width = ov->frame[0].width; - vw->height = ov->frame[0].height; - vw->flags = 30; - - PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height); - - return 0; - } - case VIDIOCGMBUF: - { - struct video_mbuf *vm = arg; - int i; - - PDEBUG(4, "VIDIOCGMBUF"); - - memset(vm, 0, sizeof(struct video_mbuf)); - vm->size = OV511_NUMFRAMES - * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); - vm->frames = OV511_NUMFRAMES; - - vm->offsets[0] = 0; - for (i = 1; i < OV511_NUMFRAMES; i++) { - vm->offsets[i] = vm->offsets[i-1] - + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); - } - - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - int rc, depth; - unsigned int f = vm->frame; - - PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width, - vm->height, symbolic(v4l1_plist, vm->format)); - - depth = get_depth(vm->format); - if (!depth) { - PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)", - symbolic(v4l1_plist, vm->format)); - return -EINVAL; - } - - if (f >= OV511_NUMFRAMES) { - err("VIDIOCMCAPTURE: invalid frame (%d)", f); - return -EINVAL; - } - - if (vm->width > ov->maxwidth - || vm->height > ov->maxheight) { - err("VIDIOCMCAPTURE: requested dimensions too big"); - return -EINVAL; - } - - if (ov->frame[f].grabstate == FRAME_GRABBING) { - PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); - return -EBUSY; - } - - if (force_palette && (vm->format != force_palette)) { - PDEBUG(2, "palette rejected (%s)", - symbolic(v4l1_plist, vm->format)); - return -EINVAL; - } - - if ((ov->frame[f].width != vm->width) || - (ov->frame[f].height != vm->height) || - (ov->frame[f].format != vm->format) || - (ov->frame[f].sub_flag != ov->sub_flag) || - (ov->frame[f].depth != depth)) { - PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); - - rc = ov51x_wait_frames_inactive(ov); - if (rc) - return rc; - - rc = mode_init_regs(ov, vm->width, vm->height, - vm->format, ov->sub_flag); -#if 0 - if (rc < 0) { - PDEBUG(1, "Got error while initializing regs "); - return ret; - } -#endif - ov->frame[f].width = vm->width; - ov->frame[f].height = vm->height; - ov->frame[f].format = vm->format; - ov->frame[f].sub_flag = ov->sub_flag; - ov->frame[f].depth = depth; - } - - /* Mark it as ready */ - ov->frame[f].grabstate = FRAME_READY; - - PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f); - - return ov51x_new_frame(ov, f); - } - case VIDIOCSYNC: - { - unsigned int fnum = *((unsigned int *) arg); - struct ov511_frame *frame; - int rc; - - if (fnum >= OV511_NUMFRAMES) { - err("VIDIOCSYNC: invalid frame (%d)", fnum); - return -EINVAL; - } - - frame = &ov->frame[fnum]; - - PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum, - frame->grabstate); - - switch (frame->grabstate) { - case FRAME_UNUSED: - return -EINVAL; - case FRAME_READY: - case FRAME_GRABBING: - case FRAME_ERROR: -redo: - if (!ov->dev) - return -EIO; - - rc = wait_event_interruptible(frame->wq, - (frame->grabstate == FRAME_DONE) - || (frame->grabstate == FRAME_ERROR)); - - if (rc) - return rc; - - if (frame->grabstate == FRAME_ERROR) { - if ((rc = ov51x_new_frame(ov, fnum)) < 0) - return rc; - goto redo; - } - /* Fall through */ - case FRAME_DONE: - if (ov->snap_enabled && !frame->snapshot) { - if ((rc = ov51x_new_frame(ov, fnum)) < 0) - return rc; - goto redo; - } - - frame->grabstate = FRAME_UNUSED; - - /* Reset the hardware snapshot button */ - /* FIXME - Is this the best place for this? */ - if ((ov->snap_enabled) && (frame->snapshot)) { - frame->snapshot = 0; - ov51x_clear_snapshot(ov); - } - - /* Decompression, format conversion, etc... */ - ov51x_postprocess(ov, frame); - - break; - } /* end switch */ - - return 0; - } - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - - PDEBUG(4, "VIDIOCGFBUF"); - - memset(vb, 0, sizeof(struct video_buffer)); - - return 0; - } - case VIDIOCGUNIT: - { - struct video_unit *vu = arg; - - PDEBUG(4, "VIDIOCGUNIT"); - - memset(vu, 0, sizeof(struct video_unit)); - - vu->video = ov->vdev->minor; - vu->vbi = VIDEO_NO_UNIT; - vu->radio = VIDEO_NO_UNIT; - vu->audio = VIDEO_NO_UNIT; - vu->teletext = VIDEO_NO_UNIT; - - return 0; - } - case OV511IOC_WI2C: - { - struct ov511_i2c_struct *w = arg; - - return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask); - } - case OV511IOC_RI2C: - { - struct ov511_i2c_struct *r = arg; - int rc; - - rc = i2c_r_slave(ov, r->slave, r->reg); - if (rc < 0) - return rc; - - r->value = rc; - return 0; - } - default: - PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd); - return -ENOIOCTLCMD; - } /* end switch */ - - return 0; -} - -static int -ov51x_v4l1_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct video_device *vdev = file->private_data; - struct usb_ov511 *ov = video_get_drvdata(vdev); - int rc; - - if (mutex_lock_interruptible(&ov->lock)) - return -EINTR; - - rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal); - - mutex_unlock(&ov->lock); - return rc; -} - -static ssize_t -ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos) -{ - struct video_device *vdev = file->private_data; - int noblock = file->f_flags&O_NONBLOCK; - unsigned long count = cnt; - struct usb_ov511 *ov = video_get_drvdata(vdev); - int i, rc = 0, frmx = -1; - struct ov511_frame *frame; - - if (mutex_lock_interruptible(&ov->lock)) - return -EINTR; - - PDEBUG(4, "%ld bytes, noblock=%d", count, noblock); - - if (!vdev || !buf) { - rc = -EFAULT; - goto error; - } - - if (!ov->dev) { - rc = -EIO; - goto error; - } - -// FIXME: Only supports two frames - /* See if a frame is completed, then use it. */ - if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ - frmx = 0; - else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */ - frmx = 1; - - /* If nonblocking we return immediately */ - if (noblock && (frmx == -1)) { - rc = -EAGAIN; - goto error; - } - - /* If no FRAME_DONE, look for a FRAME_GRABBING state. */ - /* See if a frame is in process (grabbing), then use it. */ - if (frmx == -1) { - if (ov->frame[0].grabstate == FRAME_GRABBING) - frmx = 0; - else if (ov->frame[1].grabstate == FRAME_GRABBING) - frmx = 1; - } - - /* If no frame is active, start one. */ - if (frmx == -1) { - if ((rc = ov51x_new_frame(ov, frmx = 0))) { - err("read: ov51x_new_frame error"); - goto error; - } - } - - frame = &ov->frame[frmx]; - -restart: - if (!ov->dev) { - rc = -EIO; - goto error; - } - - /* Wait while we're grabbing the image */ - PDEBUG(4, "Waiting image grabbing"); - rc = wait_event_interruptible(frame->wq, - (frame->grabstate == FRAME_DONE) - || (frame->grabstate == FRAME_ERROR)); - - if (rc) - goto error; - - PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate); - PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd); - - if (frame->grabstate == FRAME_ERROR) { - frame->bytes_read = 0; - err("** ick! ** Errored frame %d", ov->curframe); - if (ov51x_new_frame(ov, frmx)) { - err("read: ov51x_new_frame error"); - goto error; - } - goto restart; - } - - - /* Repeat until we get a snapshot frame */ - if (ov->snap_enabled) - PDEBUG(4, "Waiting snapshot frame"); - if (ov->snap_enabled && !frame->snapshot) { - frame->bytes_read = 0; - if ((rc = ov51x_new_frame(ov, frmx))) { - err("read: ov51x_new_frame error"); - goto error; - } - goto restart; - } - - /* Clear the snapshot */ - if (ov->snap_enabled && frame->snapshot) { - frame->snapshot = 0; - ov51x_clear_snapshot(ov); - } - - /* Decompression, format conversion, etc... */ - ov51x_postprocess(ov, frame); - - PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx, - frame->bytes_read, - get_frame_length(frame)); - - /* copy bytes to user space; we allow for partials reads */ -// if ((count + frame->bytes_read) -// > get_frame_length((struct ov511_frame *)frame)) -// count = frame->scanlength - frame->bytes_read; - - /* FIXME - count hardwired to be one frame... */ - count = get_frame_length(frame); - - PDEBUG(4, "Copy to user space: %ld bytes", count); - if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) { - PDEBUG(4, "Copy failed! %d bytes not copied", i); - rc = -EFAULT; - goto error; - } - - frame->bytes_read += count; - PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", - count, frame->bytes_read); - - /* If all data have been read... */ - if (frame->bytes_read - >= get_frame_length(frame)) { - frame->bytes_read = 0; - -// FIXME: Only supports two frames - /* Mark it as available to be used again. */ - ov->frame[frmx].grabstate = FRAME_UNUSED; - if ((rc = ov51x_new_frame(ov, !frmx))) { - err("ov51x_new_frame returned error"); - goto error; - } - } - - PDEBUG(4, "read finished, returning %ld (sweet)", count); - - mutex_unlock(&ov->lock); - return count; - -error: - mutex_unlock(&ov->lock); - return rc; -} - -static int -ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = file->private_data; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - struct usb_ov511 *ov = video_get_drvdata(vdev); - unsigned long page, pos; - - if (ov->dev == NULL) - return -EIO; - - PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); - - if (size > (((OV511_NUMFRAMES - * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight) - + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))) - return -EINVAL; - - if (mutex_lock_interruptible(&ov->lock)) - return -EINTR; - - pos = (unsigned long)ov->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&ov->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - mutex_unlock(&ov->lock); - return 0; -} - -static struct file_operations ov511_fops = { - .owner = THIS_MODULE, - .open = ov51x_v4l1_open, - .release = ov51x_v4l1_close, - .read = ov51x_v4l1_read, - .mmap = ov51x_v4l1_mmap, - .ioctl = ov51x_v4l1_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -static struct video_device vdev_template = { - .owner = THIS_MODULE, - .name = "OV511 USB Camera", - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_OV511, - .fops = &ov511_fops, - .release = video_device_release, - .minor = -1, -}; - -/**************************************************************************** - * - * OV511 and sensor configuration - * - ***************************************************************************/ - -/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses - * the same register settings as the OV7610, since they are very similar. - */ -static int -ov7xx0_configure(struct usb_ov511 *ov) -{ - int i, success; - int rc; - - /* Lawrence Glaister reports: - * - * Register 0x0f in the 7610 has the following effects: - * - * 0x85 (AEC method 1): Best overall, good contrast range - * 0x45 (AEC method 2): Very overexposed - * 0xa5 (spec sheet default): Ok, but the black level is - * shifted resulting in loss of contrast - * 0x05 (old driver setting): very overexposed, too much - * contrast - */ - static struct ov511_regvals aRegvalsNorm7610[] = { - { OV511_I2C_BUS, 0x10, 0xff }, - { OV511_I2C_BUS, 0x16, 0x06 }, - { OV511_I2C_BUS, 0x28, 0x24 }, - { OV511_I2C_BUS, 0x2b, 0xac }, - { OV511_I2C_BUS, 0x12, 0x00 }, - { OV511_I2C_BUS, 0x38, 0x81 }, - { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ - { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ - { OV511_I2C_BUS, 0x15, 0x01 }, - { OV511_I2C_BUS, 0x20, 0x1c }, - { OV511_I2C_BUS, 0x23, 0x2a }, - { OV511_I2C_BUS, 0x24, 0x10 }, - { OV511_I2C_BUS, 0x25, 0x8a }, - { OV511_I2C_BUS, 0x26, 0xa2 }, - { OV511_I2C_BUS, 0x27, 0xc2 }, - { OV511_I2C_BUS, 0x2a, 0x04 }, - { OV511_I2C_BUS, 0x2c, 0xfe }, - { OV511_I2C_BUS, 0x2d, 0x93 }, - { OV511_I2C_BUS, 0x30, 0x71 }, - { OV511_I2C_BUS, 0x31, 0x60 }, - { OV511_I2C_BUS, 0x32, 0x26 }, - { OV511_I2C_BUS, 0x33, 0x20 }, - { OV511_I2C_BUS, 0x34, 0x48 }, - { OV511_I2C_BUS, 0x12, 0x24 }, - { OV511_I2C_BUS, 0x11, 0x01 }, - { OV511_I2C_BUS, 0x0c, 0x24 }, - { OV511_I2C_BUS, 0x0d, 0x24 }, - { OV511_DONE_BUS, 0x0, 0x00 }, - }; - - static struct ov511_regvals aRegvalsNorm7620[] = { - { OV511_I2C_BUS, 0x00, 0x00 }, - { OV511_I2C_BUS, 0x01, 0x80 }, - { OV511_I2C_BUS, 0x02, 0x80 }, - { OV511_I2C_BUS, 0x03, 0xc0 }, - { OV511_I2C_BUS, 0x06, 0x60 }, - { OV511_I2C_BUS, 0x07, 0x00 }, - { OV511_I2C_BUS, 0x0c, 0x24 }, - { OV511_I2C_BUS, 0x0c, 0x24 }, - { OV511_I2C_BUS, 0x0d, 0x24 }, - { OV511_I2C_BUS, 0x11, 0x01 }, - { OV511_I2C_BUS, 0x12, 0x24 }, - { OV511_I2C_BUS, 0x13, 0x01 }, - { OV511_I2C_BUS, 0x14, 0x84 }, - { OV511_I2C_BUS, 0x15, 0x01 }, - { OV511_I2C_BUS, 0x16, 0x03 }, - { OV511_I2C_BUS, 0x17, 0x2f }, - { OV511_I2C_BUS, 0x18, 0xcf }, - { OV511_I2C_BUS, 0x19, 0x06 }, - { OV511_I2C_BUS, 0x1a, 0xf5 }, - { OV511_I2C_BUS, 0x1b, 0x00 }, - { OV511_I2C_BUS, 0x20, 0x18 }, - { OV511_I2C_BUS, 0x21, 0x80 }, - { OV511_I2C_BUS, 0x22, 0x80 }, - { OV511_I2C_BUS, 0x23, 0x00 }, - { OV511_I2C_BUS, 0x26, 0xa2 }, - { OV511_I2C_BUS, 0x27, 0xea }, - { OV511_I2C_BUS, 0x28, 0x20 }, - { OV511_I2C_BUS, 0x29, 0x00 }, - { OV511_I2C_BUS, 0x2a, 0x10 }, - { OV511_I2C_BUS, 0x2b, 0x00 }, - { OV511_I2C_BUS, 0x2c, 0x88 }, - { OV511_I2C_BUS, 0x2d, 0x91 }, - { OV511_I2C_BUS, 0x2e, 0x80 }, - { OV511_I2C_BUS, 0x2f, 0x44 }, - { OV511_I2C_BUS, 0x60, 0x27 }, - { OV511_I2C_BUS, 0x61, 0x02 }, - { OV511_I2C_BUS, 0x62, 0x5f }, - { OV511_I2C_BUS, 0x63, 0xd5 }, - { OV511_I2C_BUS, 0x64, 0x57 }, - { OV511_I2C_BUS, 0x65, 0x83 }, - { OV511_I2C_BUS, 0x66, 0x55 }, - { OV511_I2C_BUS, 0x67, 0x92 }, - { OV511_I2C_BUS, 0x68, 0xcf }, - { OV511_I2C_BUS, 0x69, 0x76 }, - { OV511_I2C_BUS, 0x6a, 0x22 }, - { OV511_I2C_BUS, 0x6b, 0x00 }, - { OV511_I2C_BUS, 0x6c, 0x02 }, - { OV511_I2C_BUS, 0x6d, 0x44 }, - { OV511_I2C_BUS, 0x6e, 0x80 }, - { OV511_I2C_BUS, 0x6f, 0x1d }, - { OV511_I2C_BUS, 0x70, 0x8b }, - { OV511_I2C_BUS, 0x71, 0x00 }, - { OV511_I2C_BUS, 0x72, 0x14 }, - { OV511_I2C_BUS, 0x73, 0x54 }, - { OV511_I2C_BUS, 0x74, 0x00 }, - { OV511_I2C_BUS, 0x75, 0x8e }, - { OV511_I2C_BUS, 0x76, 0x00 }, - { OV511_I2C_BUS, 0x77, 0xff }, - { OV511_I2C_BUS, 0x78, 0x80 }, - { OV511_I2C_BUS, 0x79, 0x80 }, - { OV511_I2C_BUS, 0x7a, 0x80 }, - { OV511_I2C_BUS, 0x7b, 0xe2 }, - { OV511_I2C_BUS, 0x7c, 0x00 }, - { OV511_DONE_BUS, 0x0, 0x00 }, - }; - - PDEBUG(4, "starting configuration"); - - /* This looks redundant, but is necessary for WebCam 3 */ - ov->primary_i2c_slave = OV7xx0_SID; - if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) - return -1; - - if (init_ov_sensor(ov) >= 0) { - PDEBUG(1, "OV7xx0 sensor initalized (method 1)"); - } else { - /* Reset the 76xx */ - if (i2c_w(ov, 0x12, 0x80) < 0) - return -1; - - /* Wait for it to initialize */ - msleep(150); - - i = 0; - success = 0; - while (i <= i2c_detect_tries) { - if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && - (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { - success = 1; - break; - } else { - i++; - } - } - -// Was (i == i2c_detect_tries) previously. This obviously used to always report -// success. Whether anyone actually depended on that bug is unknown - if ((i >= i2c_detect_tries) && (success == 0)) { - err("Failed to read sensor ID. You might not have an"); - err("OV7610/20, or it may be not responding. Report"); - err("this to " EMAIL); - err("This is only a warning. You can attempt to use"); - err("your camera anyway"); -// Only issue a warning for now -// return -1; - } else { - PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1); - } - } - - /* Detect sensor (sub)type */ - rc = i2c_r(ov, OV7610_REG_COM_I); - - if (rc < 0) { - err("Error detecting sensor type"); - return -1; - } else if ((rc & 3) == 3) { - info("Sensor is an OV7610"); - ov->sensor = SEN_OV7610; - } else if ((rc & 3) == 1) { - /* I don't know what's different about the 76BE yet. */ - if (i2c_r(ov, 0x15) & 1) - info("Sensor is an OV7620AE"); - else - info("Sensor is an OV76BE"); - - /* OV511+ will return all zero isoc data unless we - * configure the sensor as a 7620. Someone needs to - * find the exact reg. setting that causes this. */ - if (ov->bridge == BRG_OV511PLUS) { - info("Enabling 511+/7620AE workaround"); - ov->sensor = SEN_OV7620; - } else { - ov->sensor = SEN_OV76BE; - } - } else if ((rc & 3) == 0) { - info("Sensor is an OV7620"); - ov->sensor = SEN_OV7620; - } else { - err("Unknown image sensor version: %d", rc & 3); - return -1; - } - - if (ov->sensor == SEN_OV7620) { - PDEBUG(4, "Writing 7620 registers"); - if (write_regvals(ov, aRegvalsNorm7620)) - return -1; - } else { - PDEBUG(4, "Writing 7610 registers"); - if (write_regvals(ov, aRegvalsNorm7610)) - return -1; - } - - /* Set sensor-specific vars */ - ov->maxwidth = 640; - ov->maxheight = 480; - ov->minwidth = 64; - ov->minheight = 48; - - // FIXME: These do not match the actual settings yet - ov->brightness = 0x80 << 8; - ov->contrast = 0x80 << 8; - ov->colour = 0x80 << 8; - ov->hue = 0x80 << 8; - - return 0; -} - -/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ -static int -ov6xx0_configure(struct usb_ov511 *ov) -{ - int rc; - - static struct ov511_regvals aRegvalsNorm6x20[] = { - { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ - { OV511_I2C_BUS, 0x11, 0x01 }, - { OV511_I2C_BUS, 0x03, 0x60 }, - { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ - { OV511_I2C_BUS, 0x07, 0xa8 }, - /* The ratio of 0x0c and 0x0d controls the white point */ - { OV511_I2C_BUS, 0x0c, 0x24 }, - { OV511_I2C_BUS, 0x0d, 0x24 }, - { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */ - { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */ - { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ - { OV511_I2C_BUS, 0x14, 0x04 }, - /* 0x16: 0x06 helps frame stability with moving objects */ - { OV511_I2C_BUS, 0x16, 0x06 }, -// { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ - { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ - /* 0x28: 0x05 Selects RGB format if RGB on */ - { OV511_I2C_BUS, 0x28, 0x05 }, - { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ -// { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ - { OV511_I2C_BUS, 0x2d, 0x99 }, - { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */ - { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */ - { OV511_I2C_BUS, 0x38, 0x8b }, - { OV511_I2C_BUS, 0x39, 0x40 }, - - { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ - { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ - { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ - - { OV511_I2C_BUS, 0x3d, 0x80 }, - /* These next two registers (0x4a, 0x4b) are undocumented. They - * control the color balance */ - { OV511_I2C_BUS, 0x4a, 0x80 }, - { OV511_I2C_BUS, 0x4b, 0x80 }, - { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */ - { OV511_I2C_BUS, 0x4e, 0xc1 }, - { OV511_I2C_BUS, 0x4f, 0x04 }, -// Do 50-53 have any effect? -// Toggle 0x12[2] off and on here? - { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ - }; - - static struct ov511_regvals aRegvalsNorm6x30[] = { - /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ - { OV511_I2C_BUS, 0x11, 0x00 }, - /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 }, - /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ - { OV511_I2C_BUS, 0x07, 0xa8 }, - /* The ratio of 0x0c and 0x0d controls the white point */ - /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 }, - /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 }, - /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 }, -// /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 }, - { OV511_I2C_BUS, 0x16, 0x03 }, -// /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ - // 21 & 22? The suggested values look wrong. Go with default - /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 }, - /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default -// /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ - - /* 0x28: 0x05 Selects RGB format if RGB on */ -// /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 }, -// /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus - - /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ -// /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ - { OV511_I2C_BUS, 0x2d, 0x99 }, -// /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 -// /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ -// /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 }, -// /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 -// { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ -// { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ -// { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ - { OV511_I2C_BUS, 0x3d, 0x80 }, -// /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e }, - - /* These next two registers (0x4a, 0x4b) are undocumented. They - * control the color balance */ -// /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these -// /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 }, - { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ - /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 }, - - /* UV average mode, color killer: strongest */ - { OV511_I2C_BUS, 0x4f, 0x07 }, - - { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */ - { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */ - { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */ - { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */ - { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */ -// { OV511_I2C_BUS, 0x5c, 0x10 }, - { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ - }; - - PDEBUG(4, "starting sensor configuration"); - - if (init_ov_sensor(ov) < 0) { - err("Failed to read sensor ID. You might not have an OV6xx0,"); - err("or it may be not responding. Report this to " EMAIL); - return -1; - } else { - PDEBUG(1, "OV6xx0 sensor detected"); - } - - /* Detect sensor (sub)type */ - rc = i2c_r(ov, OV7610_REG_COM_I); - - if (rc < 0) { - err("Error detecting sensor type"); - return -1; - } - - if ((rc & 3) == 0) { - ov->sensor = SEN_OV6630; - info("Sensor is an OV6630"); - } else if ((rc & 3) == 1) { - ov->sensor = SEN_OV6620; - info("Sensor is an OV6620"); - } else if ((rc & 3) == 2) { - ov->sensor = SEN_OV6630; - info("Sensor is an OV6630AE"); - } else if ((rc & 3) == 3) { - ov->sensor = SEN_OV6630; - info("Sensor is an OV6630AF"); - } - - /* Set sensor-specific vars */ - ov->maxwidth = 352; - ov->maxheight = 288; - ov->minwidth = 64; - ov->minheight = 48; - - // FIXME: These do not match the actual settings yet - ov->brightness = 0x80 << 8; - ov->contrast = 0x80 << 8; - ov->colour = 0x80 << 8; - ov->hue = 0x80 << 8; - - if (ov->sensor == SEN_OV6620) { - PDEBUG(4, "Writing 6x20 registers"); - if (write_regvals(ov, aRegvalsNorm6x20)) - return -1; - } else { - PDEBUG(4, "Writing 6x30 registers"); - if (write_regvals(ov, aRegvalsNorm6x30)) - return -1; - } - - return 0; -} - -/* This initializes the KS0127 and KS0127B video decoders. */ -static int -ks0127_configure(struct usb_ov511 *ov) -{ - int rc; - -// FIXME: I don't know how to sync or reset it yet -#if 0 - if (ov51x_init_ks_sensor(ov) < 0) { - err("Failed to initialize the KS0127"); - return -1; - } else { - PDEBUG(1, "KS012x(B) sensor detected"); - } -#endif - - /* Detect decoder subtype */ - rc = i2c_r(ov, 0x00); - if (rc < 0) { - err("Error detecting sensor type"); - return -1; - } else if (rc & 0x08) { - rc = i2c_r(ov, 0x3d); - if (rc < 0) { - err("Error detecting sensor type"); - return -1; - } else if ((rc & 0x0f) == 0) { - info("Sensor is a KS0127"); - ov->sensor = SEN_KS0127; - } else if ((rc & 0x0f) == 9) { - info("Sensor is a KS0127B Rev. A"); - ov->sensor = SEN_KS0127B; - } - } else { - err("Error: Sensor is an unsupported KS0122"); - return -1; - } - - /* Set sensor-specific vars */ - ov->maxwidth = 640; - ov->maxheight = 480; - ov->minwidth = 64; - ov->minheight = 48; - - // FIXME: These do not match the actual settings yet - ov->brightness = 0x80 << 8; - ov->contrast = 0x80 << 8; - ov->colour = 0x80 << 8; - ov->hue = 0x80 << 8; - - /* This device is not supported yet. Bail out now... */ - err("This sensor is not supported yet."); - return -1; - - return 0; -} - -/* This initializes the SAA7111A video decoder. */ -static int -saa7111a_configure(struct usb_ov511 *ov) -{ - int rc; - - /* Since there is no register reset command, all registers must be - * written, otherwise gives erratic results */ - static struct ov511_regvals aRegvalsNormSAA7111A[] = { - { OV511_I2C_BUS, 0x06, 0xce }, - { OV511_I2C_BUS, 0x07, 0x00 }, - { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */ - { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */ - { OV511_I2C_BUS, 0x00, 0x00 }, - { OV511_I2C_BUS, 0x01, 0x00 }, - { OV511_I2C_BUS, 0x03, 0x23 }, - { OV511_I2C_BUS, 0x04, 0x00 }, - { OV511_I2C_BUS, 0x05, 0x00 }, - { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */ - { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */ - { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */ - { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */ - { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */ - { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */ - { OV511_I2C_BUS, 0x0f, 0x00 }, - { OV511_I2C_BUS, 0x11, 0x0c }, - { OV511_I2C_BUS, 0x12, 0x00 }, - { OV511_I2C_BUS, 0x13, 0x00 }, - { OV511_I2C_BUS, 0x14, 0x00 }, - { OV511_I2C_BUS, 0x15, 0x00 }, - { OV511_I2C_BUS, 0x16, 0x00 }, - { OV511_I2C_BUS, 0x17, 0x00 }, - { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */ - { OV511_DONE_BUS, 0x0, 0x00 }, - }; - -// FIXME: I don't know how to sync or reset it yet -#if 0 - if (ov51x_init_saa_sensor(ov) < 0) { - err("Failed to initialize the SAA7111A"); - return -1; - } else { - PDEBUG(1, "SAA7111A sensor detected"); - } -#endif - - /* 640x480 not supported with PAL */ - if (ov->pal) { - ov->maxwidth = 320; - ov->maxheight = 240; /* Even field only */ - } else { - ov->maxwidth = 640; - ov->maxheight = 480; /* Even/Odd fields */ - } - - ov->minwidth = 320; - ov->minheight = 240; /* Even field only */ - - ov->has_decoder = 1; - ov->num_inputs = 8; - ov->norm = VIDEO_MODE_AUTO; - ov->stop_during_set = 0; /* Decoder guarantees stable image */ - - /* Decoder doesn't change these values, so we use these instead of - * acutally reading the registers (which doesn't work) */ - ov->brightness = 0x80 << 8; - ov->contrast = 0x40 << 9; - ov->colour = 0x40 << 9; - ov->hue = 32768; - - PDEBUG(4, "Writing SAA7111A registers"); - if (write_regvals(ov, aRegvalsNormSAA7111A)) - return -1; - - /* Detect version of decoder. This must be done after writing the - * initial regs or the decoder will lock up. */ - rc = i2c_r(ov, 0x00); - - if (rc < 0) { - err("Error detecting sensor version"); - return -1; - } else { - info("Sensor is an SAA7111A (version 0x%x)", rc); - ov->sensor = SEN_SAA7111A; - } - - // FIXME: Fix this for OV518(+) - /* Latch to negative edge of clock. Otherwise, we get incorrect - * colors and jitter in the digital signal. */ - if (ov->bclass == BCL_OV511) - reg_w(ov, 0x11, 0x00); - else - warn("SAA7111A not yet supported with OV518/OV518+"); - - return 0; -} - -/* This initializes the OV511/OV511+ and the sensor */ -static int -ov511_configure(struct usb_ov511 *ov) -{ - static struct ov511_regvals aRegvalsInit511[] = { - { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, - { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, - { OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, - { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, - { OV511_REG_BUS, R51x_SYS_RESET, 0x3f }, - { OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, - { OV511_REG_BUS, R51x_SYS_RESET, 0x3d }, - { OV511_DONE_BUS, 0x0, 0x00}, - }; - - static struct ov511_regvals aRegvalsNorm511[] = { - { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, - { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, - { OV511_REG_BUS, R511_COMP_EN, 0x00 }, - { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, - { OV511_DONE_BUS, 0x0, 0x00 }, - }; - - static struct ov511_regvals aRegvalsNorm511Plus[] = { - { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, - { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, - { OV511_REG_BUS, R511_COMP_EN, 0x00 }, - { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, - { OV511_DONE_BUS, 0x0, 0x00 }, - }; - - PDEBUG(4, ""); - - ov->customid = reg_r(ov, R511_SYS_CUST_ID); - if (ov->customid < 0) { - err("Unable to read camera bridge registers"); - goto error; - } - - PDEBUG (1, "CustomID = %d", ov->customid); - ov->desc = symbolic(camlist, ov->customid); - info("model: %s", ov->desc); - - if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) { - err("Camera type (%d) not recognized", ov->customid); - err("Please notify " EMAIL " of the name,"); - err("manufacturer, model, and this number of your camera."); - err("Also include the output of the detection process."); - } - - if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */ - ov->pal = 1; - - if (write_regvals(ov, aRegvalsInit511)) - goto error; - - if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) - ov51x_led_control(ov, 0); - - /* The OV511+ has undocumented bits in the flow control register. - * Setting it to 0xff fixes the corruption with moving objects. */ - if (ov->bridge == BRG_OV511) { - if (write_regvals(ov, aRegvalsNorm511)) - goto error; - } else if (ov->bridge == BRG_OV511PLUS) { - if (write_regvals(ov, aRegvalsNorm511Plus)) - goto error; - } else { - err("Invalid bridge"); - } - - if (ov511_init_compression(ov)) - goto error; - - ov->packet_numbering = 1; - ov511_set_packet_size(ov, 0); - - ov->snap_enabled = snapshot; - - /* Test for 7xx0 */ - PDEBUG(3, "Testing for 0V7xx0"); - ov->primary_i2c_slave = OV7xx0_SID; - if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) - goto error; - - if (i2c_w(ov, 0x12, 0x80) < 0) { - /* Test for 6xx0 */ - PDEBUG(3, "Testing for 0V6xx0"); - ov->primary_i2c_slave = OV6xx0_SID; - if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) - goto error; - - if (i2c_w(ov, 0x12, 0x80) < 0) { - /* Test for 8xx0 */ - PDEBUG(3, "Testing for 0V8xx0"); - ov->primary_i2c_slave = OV8xx0_SID; - if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) - goto error; - - if (i2c_w(ov, 0x12, 0x80) < 0) { - /* Test for SAA7111A */ - PDEBUG(3, "Testing for SAA7111A"); - ov->primary_i2c_slave = SAA7111A_SID; - if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0) - goto error; - - if (i2c_w(ov, 0x0d, 0x00) < 0) { - /* Test for KS0127 */ - PDEBUG(3, "Testing for KS0127"); - ov->primary_i2c_slave = KS0127_SID; - if (ov51x_set_slave_ids(ov, KS0127_SID) < 0) - goto error; - - if (i2c_w(ov, 0x10, 0x00) < 0) { - err("Can't determine sensor slave IDs"); - goto error; - } else { - if (ks0127_configure(ov) < 0) { - err("Failed to configure KS0127"); - goto error; - } - } - } else { - if (saa7111a_configure(ov) < 0) { - err("Failed to configure SAA7111A"); - goto error; - } - } - } else { - err("Detected unsupported OV8xx0 sensor"); - goto error; - } - } else { - if (ov6xx0_configure(ov) < 0) { - err("Failed to configure OV6xx0"); - goto error; - } - } - } else { - if (ov7xx0_configure(ov) < 0) { - err("Failed to configure OV7xx0"); - goto error; - } - } - - return 0; - -error: - err("OV511 Config failed"); - - return -EBUSY; -} - -/* This initializes the OV518/OV518+ and the sensor */ -static int -ov518_configure(struct usb_ov511 *ov) -{ - /* For 518 and 518+ */ - static struct ov511_regvals aRegvalsInit518[] = { - { OV511_REG_BUS, R51x_SYS_RESET, 0x40 }, - { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, - { OV511_REG_BUS, R51x_SYS_RESET, 0x3e }, - { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, - { OV511_REG_BUS, R51x_SYS_RESET, 0x00 }, - { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 }, - { OV511_REG_BUS, 0x46, 0x00 }, - { OV511_REG_BUS, 0x5d, 0x03 }, - { OV511_DONE_BUS, 0x0, 0x00}, - }; - - static struct ov511_regvals aRegvalsNorm518[] = { - { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ - { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ - { OV511_REG_BUS, 0x31, 0x0f }, - { OV511_REG_BUS, 0x5d, 0x03 }, - { OV511_REG_BUS, 0x24, 0x9f }, - { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x00 }, - { OV511_REG_BUS, 0x51, 0x04 }, - { OV511_REG_BUS, 0x71, 0x19 }, - { OV511_DONE_BUS, 0x0, 0x00 }, - }; - - static struct ov511_regvals aRegvalsNorm518Plus[] = { - { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */ - { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */ - { OV511_REG_BUS, 0x31, 0x0f }, - { OV511_REG_BUS, 0x5d, 0x03 }, - { OV511_REG_BUS, 0x24, 0x9f }, - { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x60 }, - { OV511_REG_BUS, 0x51, 0x02 }, - { OV511_REG_BUS, 0x71, 0x19 }, - { OV511_REG_BUS, 0x40, 0xff }, - { OV511_REG_BUS, 0x41, 0x42 }, - { OV511_REG_BUS, 0x46, 0x00 }, - { OV511_REG_BUS, 0x33, 0x04 }, - { OV511_REG_BUS, 0x21, 0x19 }, - { OV511_REG_BUS, 0x3f, 0x10 }, - { OV511_DONE_BUS, 0x0, 0x00 }, - }; - - PDEBUG(4, ""); - - /* First 5 bits of custom ID reg are a revision ID on OV518 */ - info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID)); - - /* Give it the default description */ - ov->desc = symbolic(camlist, 0); - - if (write_regvals(ov, aRegvalsInit518)) - goto error; - - /* Set LED GPIO pin to output mode */ - if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) - goto error; - - /* LED is off by default with OV518; have to explicitly turn it on */ - if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO) - ov51x_led_control(ov, 0); - else - ov51x_led_control(ov, 1); - - /* Don't require compression if dumppix is enabled; otherwise it's - * required. OV518 has no uncompressed mode, to save RAM. */ - if (!dumppix && !ov->compress) { - ov->compress = 1; - warn("Compression required with OV518...enabling"); - } - - if (ov->bridge == BRG_OV518) { - if (write_regvals(ov, aRegvalsNorm518)) - goto error; - } else if (ov->bridge == BRG_OV518PLUS) { - if (write_regvals(ov, aRegvalsNorm518Plus)) - goto error; - } else { - err("Invalid bridge"); - } - - if (reg_w(ov, 0x2f, 0x80) < 0) - goto error; - - if (ov518_init_compression(ov)) - goto error; - - if (ov->bridge == BRG_OV518) - { - struct usb_interface *ifp; - struct usb_host_interface *alt; - __u16 mxps = 0; - - ifp = usb_ifnum_to_if(ov->dev, 0); - if (ifp) { - alt = usb_altnum_to_altsetting(ifp, 7); - if (alt) - mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - } - - /* Some OV518s have packet numbering by default, some don't */ - if (mxps == 897) - ov->packet_numbering = 1; - else - ov->packet_numbering = 0; - } else { - /* OV518+ has packet numbering turned on by default */ - ov->packet_numbering = 1; - } - - ov518_set_packet_size(ov, 0); - - ov->snap_enabled = snapshot; - - /* Test for 76xx */ - ov->primary_i2c_slave = OV7xx0_SID; - if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0) - goto error; - - /* The OV518 must be more aggressive about sensor detection since - * I2C write will never fail if the sensor is not present. We have - * to try to initialize the sensor to detect its presence */ - - if (init_ov_sensor(ov) < 0) { - /* Test for 6xx0 */ - ov->primary_i2c_slave = OV6xx0_SID; - if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0) - goto error; - - if (init_ov_sensor(ov) < 0) { - /* Test for 8xx0 */ - ov->primary_i2c_slave = OV8xx0_SID; - if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0) - goto error; - - if (init_ov_sensor(ov) < 0) { - err("Can't determine sensor slave IDs"); - goto error; - } else { - err("Detected unsupported OV8xx0 sensor"); - goto error; - } - } else { - if (ov6xx0_configure(ov) < 0) { - err("Failed to configure OV6xx0"); - goto error; - } - } - } else { - if (ov7xx0_configure(ov) < 0) { - err("Failed to configure OV7xx0"); - goto error; - } - } - - ov->maxwidth = 352; - ov->maxheight = 288; - - // The OV518 cannot go as low as the sensor can - ov->minwidth = 160; - ov->minheight = 120; - - return 0; - -error: - err("OV518 Config failed"); - - return -EBUSY; -} - -/**************************************************************************** - * sysfs - ***************************************************************************/ - -static inline struct usb_ov511 *cd_to_ov(struct class_device *cd) -{ - struct video_device *vdev = to_video_device(cd); - return video_get_drvdata(vdev); -} - -static ssize_t show_custom_id(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - return sprintf(buf, "%d\n", ov->customid); -} -static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL); - -static ssize_t show_model(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - return sprintf(buf, "%s\n", ov->desc); -} -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); - -static ssize_t show_bridge(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge)); -} -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL); - -static ssize_t show_sensor(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor)); -} -static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL); - -static ssize_t show_brightness(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - unsigned short x; - - if (!ov->dev) - return -ENODEV; - sensor_get_brightness(ov, &x); - return sprintf(buf, "%d\n", x >> 8); -} -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); - -static ssize_t show_saturation(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - unsigned short x; - - if (!ov->dev) - return -ENODEV; - sensor_get_saturation(ov, &x); - return sprintf(buf, "%d\n", x >> 8); -} -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); - -static ssize_t show_contrast(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - unsigned short x; - - if (!ov->dev) - return -ENODEV; - sensor_get_contrast(ov, &x); - return sprintf(buf, "%d\n", x >> 8); -} -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); - -static ssize_t show_hue(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - unsigned short x; - - if (!ov->dev) - return -ENODEV; - sensor_get_hue(ov, &x); - return sprintf(buf, "%d\n", x >> 8); -} -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); - -static ssize_t show_exposure(struct class_device *cd, char *buf) -{ - struct usb_ov511 *ov = cd_to_ov(cd); - unsigned char exp = 0; - - if (!ov->dev) - return -ENODEV; - sensor_get_exposure(ov, &exp); - return sprintf(buf, "%d\n", exp >> 8); -} -static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); - -static void ov_create_sysfs(struct video_device *vdev) -{ - video_device_create_file(vdev, &class_device_attr_custom_id); - video_device_create_file(vdev, &class_device_attr_model); - video_device_create_file(vdev, &class_device_attr_bridge); - video_device_create_file(vdev, &class_device_attr_sensor); - video_device_create_file(vdev, &class_device_attr_brightness); - video_device_create_file(vdev, &class_device_attr_saturation); - video_device_create_file(vdev, &class_device_attr_contrast); - video_device_create_file(vdev, &class_device_attr_hue); - video_device_create_file(vdev, &class_device_attr_exposure); -} - -/**************************************************************************** - * USB routines - ***************************************************************************/ - -static int -ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_interface_descriptor *idesc; - struct usb_ov511 *ov; - int i; - - PDEBUG(1, "probing for device..."); - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - idesc = &intf->cur_altsetting->desc; - - if (idesc->bInterfaceClass != 0xFF) - return -ENODEV; - if (idesc->bInterfaceSubClass != 0x00) - return -ENODEV; - - if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { - err("couldn't kmalloc ov struct"); - goto error_out; - } - - ov->dev = dev; - ov->iface = idesc->bInterfaceNumber; - ov->led_policy = led; - ov->compress = compress; - ov->lightfreq = lightfreq; - ov->num_inputs = 1; /* Video decoder init functs. change this */ - ov->stop_during_set = !fastset; - ov->backlight = backlight; - ov->mirror = mirror; - ov->auto_brt = autobright; - ov->auto_gain = autogain; - ov->auto_exp = autoexp; - - switch (le16_to_cpu(dev->descriptor.idProduct)) { - case PROD_OV511: - ov->bridge = BRG_OV511; - ov->bclass = BCL_OV511; - break; - case PROD_OV511PLUS: - ov->bridge = BRG_OV511PLUS; - ov->bclass = BCL_OV511; - break; - case PROD_OV518: - ov->bridge = BRG_OV518; - ov->bclass = BCL_OV518; - break; - case PROD_OV518PLUS: - ov->bridge = BRG_OV518PLUS; - ov->bclass = BCL_OV518; - break; - case PROD_ME2CAM: - if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL) - goto error; - ov->bridge = BRG_OV511PLUS; - ov->bclass = BCL_OV511; - break; - default: - err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct)); - goto error; - } - - info("USB %s video device found", symbolic(brglist, ov->bridge)); - - init_waitqueue_head(&ov->wq); - - mutex_init(&ov->lock); /* to 1 == available */ - mutex_init(&ov->buf_lock); - mutex_init(&ov->i2c_lock); - mutex_init(&ov->cbuf_lock); - - ov->buf_state = BUF_NOT_ALLOCATED; - - if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) { - err("usb_make_path error"); - goto error; - } - - /* Allocate control transfer buffer. */ - /* Must be kmalloc()'ed, for DMA compatibility */ - ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); - if (!ov->cbuf) - goto error; - - if (ov->bclass == BCL_OV518) { - if (ov518_configure(ov) < 0) - goto error; - } else { - if (ov511_configure(ov) < 0) - goto error; - } - - for (i = 0; i < OV511_NUMFRAMES; i++) { - ov->frame[i].framenum = i; - init_waitqueue_head(&ov->frame[i].wq); - } - - for (i = 0; i < OV511_NUMSBUF; i++) { - ov->sbuf[i].ov = ov; - spin_lock_init(&ov->sbuf[i].lock); - ov->sbuf[i].n = i; - } - - /* Unnecessary? (This is done on open(). Need to make sure variables - * are properly initialized without this before removing it, though). */ - if (ov51x_set_default_params(ov) < 0) - goto error; - -#ifdef OV511_DEBUG - if (dump_bridge) { - if (ov->bclass == BCL_OV511) - ov511_dump_regs(ov); - else - ov518_dump_regs(ov); - } -#endif - - ov->vdev = video_device_alloc(); - if (!ov->vdev) - goto error; - - memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev)); - ov->vdev->dev = &dev->dev; - video_set_drvdata(ov->vdev, ov); - - for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) { - /* Minor 0 cannot be specified; assume user wants autodetect */ - if (unit_video[i] == 0) - break; - - if (video_register_device(ov->vdev, VFL_TYPE_GRABBER, - unit_video[i]) >= 0) { - break; - } - } - - /* Use the next available one */ - if ((ov->vdev->minor == -1) && - video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) { - err("video_register_device failed"); - goto error; - } - - info("Device at %s registered to minor %d", ov->usb_path, - ov->vdev->minor); - - usb_set_intfdata(intf, ov); - ov_create_sysfs(ov->vdev); - return 0; - -error: - if (ov->vdev) { - if (-1 == ov->vdev->minor) - video_device_release(ov->vdev); - else - video_unregister_device(ov->vdev); - ov->vdev = NULL; - } - - if (ov->cbuf) { - mutex_lock(&ov->cbuf_lock); - kfree(ov->cbuf); - ov->cbuf = NULL; - mutex_unlock(&ov->cbuf_lock); - } - - kfree(ov); - ov = NULL; - -error_out: - err("Camera initialization failed"); - return -EIO; -} - -static void -ov51x_disconnect(struct usb_interface *intf) -{ - struct usb_ov511 *ov = usb_get_intfdata(intf); - int n; - - PDEBUG(3, ""); - - usb_set_intfdata (intf, NULL); - - if (!ov) - return; - - if (ov->vdev) - video_unregister_device(ov->vdev); - - for (n = 0; n < OV511_NUMFRAMES; n++) - ov->frame[n].grabstate = FRAME_ERROR; - - ov->curframe = -1; - - /* This will cause the process to request another frame */ - for (n = 0; n < OV511_NUMFRAMES; n++) - wake_up_interruptible(&ov->frame[n].wq); - - wake_up_interruptible(&ov->wq); - - ov->streaming = 0; - ov51x_unlink_isoc(ov); - - ov->dev = NULL; - - /* Free the memory */ - if (ov && !ov->user) { - mutex_lock(&ov->cbuf_lock); - kfree(ov->cbuf); - ov->cbuf = NULL; - mutex_unlock(&ov->cbuf_lock); - - ov51x_dealloc(ov); - kfree(ov); - ov = NULL; - } - - PDEBUG(3, "Disconnect complete"); -} - -static struct usb_driver ov511_driver = { - .name = "ov511", - .id_table = device_table, - .probe = ov51x_probe, - .disconnect = ov51x_disconnect -}; - -/**************************************************************************** - * - * Module routines - * - ***************************************************************************/ - -static int __init -usb_ov511_init(void) -{ - int retval; - - retval = usb_register(&ov511_driver); - if (retval) - goto out; - - info(DRIVER_VERSION " : " DRIVER_DESC); - -out: - return retval; -} - -static void __exit -usb_ov511_exit(void) -{ - usb_deregister(&ov511_driver); - info("driver deregistered"); - -} - -module_init(usb_ov511_init); -module_exit(usb_ov511_exit); - diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h deleted file mode 100644 index bce9b3633889..000000000000 --- a/drivers/usb/media/ov511.h +++ /dev/null @@ -1,568 +0,0 @@ -#ifndef __LINUX_OV511_H -#define __LINUX_OV511_H - -#include -#include -#include -#include -#include - -#define OV511_DEBUG /* Turn on debug messages */ - -#ifdef OV511_DEBUG - #define PDEBUG(level, fmt, args...) \ - if (debug >= (level)) info("[%s:%d] " fmt, \ - __FUNCTION__, __LINE__ , ## args) -#else - #define PDEBUG(level, fmt, args...) do {} while(0) -#endif - -/* This macro restricts an int variable to an inclusive range */ -#define RESTRICT_TO_RANGE(v,mi,ma) { \ - if ((v) < (mi)) (v) = (mi); \ - else if ((v) > (ma)) (v) = (ma); \ -} - -/* --------------------------------- */ -/* DEFINES FOR OV511 AND OTHER CHIPS */ -/* --------------------------------- */ - -/* USB IDs */ -#define VEND_OMNIVISION 0x05A9 -#define PROD_OV511 0x0511 -#define PROD_OV511PLUS 0xA511 -#define PROD_OV518 0x0518 -#define PROD_OV518PLUS 0xA518 - -#define VEND_MATTEL 0x0813 -#define PROD_ME2CAM 0x0002 - -/* --------------------------------- */ -/* OV51x REGISTER MNEMONICS */ -/* --------------------------------- */ - -/* Camera interface register numbers */ -#define R511_CAM_DELAY 0x10 -#define R511_CAM_EDGE 0x11 -#define R511_CAM_PXCNT 0x12 -#define R511_CAM_LNCNT 0x13 -#define R511_CAM_PXDIV 0x14 -#define R511_CAM_LNDIV 0x15 -#define R511_CAM_UV_EN 0x16 -#define R511_CAM_LINE_MODE 0x17 -#define R511_CAM_OPTS 0x18 - -/* Snapshot mode camera interface register numbers */ -#define R511_SNAP_FRAME 0x19 -#define R511_SNAP_PXCNT 0x1A -#define R511_SNAP_LNCNT 0x1B -#define R511_SNAP_PXDIV 0x1C -#define R511_SNAP_LNDIV 0x1D -#define R511_SNAP_UV_EN 0x1E -#define R511_SNAP_OPTS 0x1F - -/* DRAM register numbers */ -#define R511_DRAM_FLOW_CTL 0x20 -#define R511_DRAM_ARCP 0x21 -#define R511_DRAM_MRC 0x22 -#define R511_DRAM_RFC 0x23 - -/* ISO FIFO register numbers */ -#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */ -#define R511_FIFO_OPTS 0x31 - -/* Parallel IO register numbers */ -#define R511_PIO_OPTS 0x38 -#define R511_PIO_DATA 0x39 -#define R511_PIO_BIST 0x3E -#define R518_GPIO_IN 0x55 /* OV518(+) only */ -#define R518_GPIO_OUT 0x56 /* OV518(+) only */ -#define R518_GPIO_CTL 0x57 /* OV518(+) only */ -#define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */ -#define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */ -#define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */ -#define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */ -#define R518_GPIO_RESET 0x5c /* OV518(+) only */ - -/* I2C registers */ -#define R511_I2C_CTL 0x40 -#define R518_I2C_CTL 0x47 /* OV518(+) only */ -#define R51x_I2C_W_SID 0x41 -#define R51x_I2C_SADDR_3 0x42 -#define R51x_I2C_SADDR_2 0x43 -#define R51x_I2C_R_SID 0x44 -#define R51x_I2C_DATA 0x45 -#define R51x_I2C_CLOCK 0x46 -#define R51x_I2C_TIMEOUT 0x47 - -/* I2C snapshot registers */ -#define R511_SI2C_SADDR_3 0x48 -#define R511_SI2C_DATA 0x49 - -/* System control registers */ -#define R51x_SYS_RESET 0x50 - /* Reset type definitions */ -#define OV511_RESET_UDC 0x01 -#define OV511_RESET_I2C 0x02 -#define OV511_RESET_FIFO 0x04 -#define OV511_RESET_OMNICE 0x08 -#define OV511_RESET_DRAM 0x10 -#define OV511_RESET_CAM_INT 0x20 -#define OV511_RESET_OV511 0x40 -#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */ -#define OV511_RESET_ALL 0x7F - -#define R511_SYS_CLOCK_DIV 0x51 -#define R51x_SYS_SNAP 0x52 -#define R51x_SYS_INIT 0x53 -#define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */ -#define R511_SYS_LED_CTL 0x55 /* OV511+ only */ -#define R511_SYS_USER 0x5E -#define R511_SYS_CUST_ID 0x5F - -/* OmniCE (compression) registers */ -#define R511_COMP_PHY 0x70 -#define R511_COMP_PHUV 0x71 -#define R511_COMP_PVY 0x72 -#define R511_COMP_PVUV 0x73 -#define R511_COMP_QHY 0x74 -#define R511_COMP_QHUV 0x75 -#define R511_COMP_QVY 0x76 -#define R511_COMP_QVUV 0x77 -#define R511_COMP_EN 0x78 -#define R511_COMP_LUT_EN 0x79 -#define R511_COMP_LUT_BEGIN 0x80 - -/* --------------------------------- */ -/* ALTERNATE NUMBERS */ -/* --------------------------------- */ - -/* Alternate numbers for various max packet sizes (OV511 only) */ -#define OV511_ALT_SIZE_992 0 -#define OV511_ALT_SIZE_993 1 -#define OV511_ALT_SIZE_768 2 -#define OV511_ALT_SIZE_769 3 -#define OV511_ALT_SIZE_512 4 -#define OV511_ALT_SIZE_513 5 -#define OV511_ALT_SIZE_257 6 -#define OV511_ALT_SIZE_0 7 - -/* Alternate numbers for various max packet sizes (OV511+ only) */ -#define OV511PLUS_ALT_SIZE_0 0 -#define OV511PLUS_ALT_SIZE_33 1 -#define OV511PLUS_ALT_SIZE_129 2 -#define OV511PLUS_ALT_SIZE_257 3 -#define OV511PLUS_ALT_SIZE_385 4 -#define OV511PLUS_ALT_SIZE_513 5 -#define OV511PLUS_ALT_SIZE_769 6 -#define OV511PLUS_ALT_SIZE_961 7 - -/* Alternate numbers for various max packet sizes (OV518(+) only) */ -#define OV518_ALT_SIZE_0 0 -#define OV518_ALT_SIZE_128 1 -#define OV518_ALT_SIZE_256 2 -#define OV518_ALT_SIZE_384 3 -#define OV518_ALT_SIZE_512 4 -#define OV518_ALT_SIZE_640 5 -#define OV518_ALT_SIZE_768 6 -#define OV518_ALT_SIZE_896 7 - -/* --------------------------------- */ -/* OV7610 REGISTER MNEMONICS */ -/* --------------------------------- */ - -/* OV7610 registers */ -#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ -#define OV7610_REG_BLUE 0x01 /* blue channel balance */ -#define OV7610_REG_RED 0x02 /* red channel balance */ -#define OV7610_REG_SAT 0x03 /* saturation */ - /* 04 reserved */ -#define OV7610_REG_CNT 0x05 /* Y contrast */ -#define OV7610_REG_BRT 0x06 /* Y brightness */ - /* 08-0b reserved */ -#define OV7610_REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */ -#define OV7610_REG_RED_BIAS 0x0D /* read channel bias (5:0) */ -#define OV7610_REG_GAMMA_COEFF 0x0E /* gamma settings */ -#define OV7610_REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */ -#define OV7610_REG_EXP 0x10 /* manual exposure setting */ -#define OV7610_REG_CLOCK 0x11 /* polarity/clock prescaler */ -#define OV7610_REG_COM_A 0x12 /* misc common regs */ -#define OV7610_REG_COM_B 0x13 /* misc common regs */ -#define OV7610_REG_COM_C 0x14 /* misc common regs */ -#define OV7610_REG_COM_D 0x15 /* misc common regs */ -#define OV7610_REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */ -#define OV7610_REG_HWIN_START 0x17 /* horizontal window start */ -#define OV7610_REG_HWIN_END 0x18 /* horizontal window end */ -#define OV7610_REG_VWIN_START 0x19 /* vertical window start */ -#define OV7610_REG_VWIN_END 0x1A /* vertical window end */ -#define OV7610_REG_PIXEL_SHIFT 0x1B /* pixel shift */ -#define OV7610_REG_ID_HIGH 0x1C /* manufacturer ID MSB */ -#define OV7610_REG_ID_LOW 0x1D /* manufacturer ID LSB */ - /* 0e-0f reserved */ -#define OV7610_REG_COM_E 0x20 /* misc common regs */ -#define OV7610_REG_YOFFSET 0x21 /* Y channel offset */ -#define OV7610_REG_UOFFSET 0x22 /* U channel offset */ - /* 23 reserved */ -#define OV7610_REG_ECW 0x24 /* Exposure white level for AEC */ -#define OV7610_REG_ECB 0x25 /* Exposure black level for AEC */ -#define OV7610_REG_COM_F 0x26 /* misc settings */ -#define OV7610_REG_COM_G 0x27 /* misc settings */ -#define OV7610_REG_COM_H 0x28 /* misc settings */ -#define OV7610_REG_COM_I 0x29 /* misc settings */ -#define OV7610_REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */ -#define OV7610_REG_FRAMERATE_L 0x2B /* frame rate LSB */ -#define OV7610_REG_ALC 0x2C /* Auto Level Control settings */ -#define OV7610_REG_COM_J 0x2D /* misc settings */ -#define OV7610_REG_VOFFSET 0x2E /* V channel offset adjustment */ -#define OV7610_REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */ - /* 30-32 reserved */ -#define OV7610_REG_YGAMMA 0x33 /* misc gamma settings (7:6) */ -#define OV7610_REG_BIAS_ADJUST 0x34 /* misc bias settings */ -#define OV7610_REG_COM_L 0x35 /* misc settings */ - /* 36-37 reserved */ -#define OV7610_REG_COM_K 0x38 /* misc registers */ - -/* --------------------------------- */ -/* I2C ADDRESSES */ -/* --------------------------------- */ - -#define OV7xx0_SID 0x42 -#define OV6xx0_SID 0xC0 -#define OV8xx0_SID 0xA0 -#define KS0127_SID 0xD8 -#define SAA7111A_SID 0x48 - -/* --------------------------------- */ -/* MISCELLANEOUS DEFINES */ -/* --------------------------------- */ - -#define I2C_CLOCK_PRESCALER 0x03 - -#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */ -#define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */ -#define PIXELS_PER_SEG 256 /* Pixels per segment */ - -#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ - -#define OV511_NUMFRAMES 2 -#if OV511_NUMFRAMES > VIDEO_MAX_FRAME - #error "OV511_NUMFRAMES is too high" -#endif - -#define OV511_NUMSBUF 2 - -/* Control transfers use up to 4 bytes */ -#define OV511_CBUF_SIZE 4 - -/* Size of usb_make_path() buffer */ -#define OV511_USB_PATH_LEN 64 - -/* Bridge types */ -enum { - BRG_UNKNOWN, - BRG_OV511, - BRG_OV511PLUS, - BRG_OV518, - BRG_OV518PLUS, -}; - -/* Bridge classes */ -enum { - BCL_UNKNOWN, - BCL_OV511, - BCL_OV518, -}; - -/* Sensor types */ -enum { - SEN_UNKNOWN, - SEN_OV76BE, - SEN_OV7610, - SEN_OV7620, - SEN_OV7620AE, - SEN_OV6620, - SEN_OV6630, - SEN_OV6630AE, - SEN_OV6630AF, - SEN_OV8600, - SEN_KS0127, - SEN_KS0127B, - SEN_SAA7111A, -}; - -enum { - STATE_SCANNING, /* Scanning for start */ - STATE_HEADER, /* Parsing header */ - STATE_LINES, /* Parsing lines */ -}; - -/* Buffer states */ -enum { - BUF_NOT_ALLOCATED, - BUF_ALLOCATED, -}; - -/* --------- Definition of ioctl interface --------- */ - -#define OV511_INTERFACE_VER 101 - -/* LED options */ -enum { - LED_OFF, - LED_ON, - LED_AUTO, -}; - -/* Raw frame formats */ -enum { - RAWFMT_INVALID, - RAWFMT_YUV400, - RAWFMT_YUV420, - RAWFMT_YUV422, - RAWFMT_GBR422, -}; - -struct ov511_i2c_struct { - unsigned char slave; /* Write slave ID (read ID - 1) */ - unsigned char reg; /* Index of register */ - unsigned char value; /* User sets this w/ write, driver does w/ read */ - unsigned char mask; /* Bits to be changed. Not used with read ops */ -}; - -/* ioctls */ -#define OV511IOC_WI2C _IOW('v', BASE_VIDIOCPRIVATE + 5, \ - struct ov511_i2c_struct) -#define OV511IOC_RI2C _IOWR('v', BASE_VIDIOCPRIVATE + 6, \ - struct ov511_i2c_struct) -/* ------------- End IOCTL interface -------------- */ - -struct usb_ov511; /* Forward declaration */ - -struct ov511_sbuf { - struct usb_ov511 *ov; - unsigned char *data; - struct urb *urb; - spinlock_t lock; - int n; -}; - -enum { - FRAME_UNUSED, /* Unused (no MCAPTURE) */ - FRAME_READY, /* Ready to start grabbing */ - FRAME_GRABBING, /* In the process of being grabbed into */ - FRAME_DONE, /* Finished grabbing, but not been synced yet */ - FRAME_ERROR, /* Something bad happened while processing */ -}; - -struct ov511_regvals { - enum { - OV511_DONE_BUS, - OV511_REG_BUS, - OV511_I2C_BUS, - } bus; - unsigned char reg; - unsigned char val; -}; - -struct ov511_frame { - int framenum; /* Index of this frame */ - unsigned char *data; /* Frame buffer */ - unsigned char *tempdata; /* Temp buffer for multi-stage conversions */ - unsigned char *rawdata; /* Raw camera data buffer */ - unsigned char *compbuf; /* Temp buffer for decompressor */ - - int depth; /* Bytes per pixel */ - int width; /* Width application is expecting */ - int height; /* Height application is expecting */ - - int rawwidth; /* Actual width of frame sent from camera */ - int rawheight; /* Actual height of frame sent from camera */ - - int sub_flag; /* Sub-capture mode for this frame? */ - unsigned int format; /* Format for this frame */ - int compressed; /* Is frame compressed? */ - - volatile int grabstate; /* State of grabbing */ - int scanstate; /* State of scanning */ - - int bytes_recvd; /* Number of image bytes received from camera */ - - long bytes_read; /* Amount that has been read() */ - - wait_queue_head_t wq; /* Processes waiting */ - - int snapshot; /* True if frame was a snapshot */ -}; - -#define DECOMP_INTERFACE_VER 4 - -/* Compression module operations */ -struct ov51x_decomp_ops { - int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *, - int, int, int); - int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *, - int, int, int); - int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *, - int, int, int); - struct module *owner; -}; - -struct usb_ov511 { - struct video_device *vdev; - struct usb_device *dev; - - int customid; - char *desc; - unsigned char iface; - char usb_path[OV511_USB_PATH_LEN]; - - /* Determined by sensor type */ - int maxwidth; - int maxheight; - int minwidth; - int minheight; - - int brightness; - int colour; - int contrast; - int hue; - int whiteness; - int exposure; - int auto_brt; /* Auto brightness enabled flag */ - int auto_gain; /* Auto gain control enabled flag */ - int auto_exp; /* Auto exposure enabled flag */ - int backlight; /* Backlight exposure algorithm flag */ - int mirror; /* Image is reversed horizontally */ - - int led_policy; /* LED: off|on|auto; OV511+ only */ - - struct mutex lock; /* Serializes user-accessible operations */ - int user; /* user count for exclusive use */ - - int streaming; /* Are we streaming Isochronous? */ - int grabbing; /* Are we grabbing? */ - - int compress; /* Should the next frame be compressed? */ - int compress_inited; /* Are compression params uploaded? */ - - int lightfreq; /* Power (lighting) frequency */ - int bandfilt; /* Banding filter enabled flag */ - - unsigned char *fbuf; /* Videodev buffer area */ - unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */ - unsigned char *rawfbuf; /* Raw camera data buffer area */ - - int sub_flag; /* Pix Array subcapture on flag */ - int subx; /* Pix Array subcapture x offset */ - int suby; /* Pix Array subcapture y offset */ - int subw; /* Pix Array subcapture width */ - int subh; /* Pix Array subcapture height */ - - int curframe; /* Current receiving sbuf */ - struct ov511_frame frame[OV511_NUMFRAMES]; - - struct ov511_sbuf sbuf[OV511_NUMSBUF]; - - wait_queue_head_t wq; /* Processes waiting */ - - int snap_enabled; /* Snapshot mode enabled */ - - int bridge; /* Type of bridge (BRG_*) */ - int bclass; /* Class of bridge (BCL_*) */ - int sensor; /* Type of image sensor chip (SEN_*) */ - - int packet_size; /* Frame size per isoc desc */ - int packet_numbering; /* Is ISO frame numbering enabled? */ - - /* Framebuffer/sbuf management */ - int buf_state; - struct mutex buf_lock; - - struct ov51x_decomp_ops *decomp_ops; - - /* Stop streaming while changing picture settings */ - int stop_during_set; - - int stopped; /* Streaming is temporarily paused */ - - /* Video decoder stuff */ - int input; /* Composite, S-VIDEO, etc... */ - int num_inputs; /* Number of inputs */ - int norm; /* NTSC / PAL / SECAM */ - int has_decoder; /* Device has a video decoder */ - int pal; /* Device is designed for PAL resolution */ - - /* I2C interface */ - struct mutex i2c_lock; /* Protect I2C controller regs */ - unsigned char primary_i2c_slave; /* I2C write id of sensor */ - - /* Control transaction stuff */ - unsigned char *cbuf; /* Buffer for payload */ - struct mutex cbuf_lock; -}; - -/* Used to represent a list of values and their respective symbolic names */ -struct symbolic_list { - int num; - char *name; -}; - -#define NOT_DEFINED_STR "Unknown" - -/* Returns the name of the matching element in the symbolic_list array. The - * end of the list must be marked with an element that has a NULL name. - */ -static inline char * -symbolic(struct symbolic_list list[], int num) -{ - int i; - - for (i = 0; list[i].name != NULL; i++) - if (list[i].num == num) - return (list[i].name); - - return (NOT_DEFINED_STR); -} - -/* Compression stuff */ - -#define OV511_QUANTABLESIZE 64 -#define OV518_QUANTABLESIZE 32 - -#define OV511_YQUANTABLE { \ - 0, 1, 1, 2, 2, 3, 3, 4, \ - 1, 1, 1, 2, 2, 3, 4, 4, \ - 1, 1, 2, 2, 3, 4, 4, 4, \ - 2, 2, 2, 3, 4, 4, 4, 4, \ - 2, 2, 3, 4, 4, 5, 5, 5, \ - 3, 3, 4, 4, 5, 5, 5, 5, \ - 3, 4, 4, 4, 5, 5, 5, 5, \ - 4, 4, 4, 4, 5, 5, 5, 5 \ -} - -#define OV511_UVQUANTABLE { \ - 0, 2, 2, 3, 4, 4, 4, 4, \ - 2, 2, 2, 4, 4, 4, 4, 4, \ - 2, 2, 3, 4, 4, 4, 4, 4, \ - 3, 4, 4, 4, 4, 4, 4, 4, \ - 4, 4, 4, 4, 4, 4, 4, 4, \ - 4, 4, 4, 4, 4, 4, 4, 4, \ - 4, 4, 4, 4, 4, 4, 4, 4, \ - 4, 4, 4, 4, 4, 4, 4, 4 \ -} - -#define OV518_YQUANTABLE { \ - 5, 4, 5, 6, 6, 7, 7, 7, \ - 5, 5, 5, 5, 6, 7, 7, 7, \ - 6, 6, 6, 6, 7, 7, 7, 8, \ - 7, 7, 6, 7, 7, 7, 8, 8 \ -} - -#define OV518_UVQUANTABLE { \ - 6, 6, 6, 7, 7, 7, 7, 7, \ - 6, 6, 6, 7, 7, 7, 7, 7, \ - 6, 6, 6, 7, 7, 7, 7, 8, \ - 7, 7, 7, 7, 7, 7, 8, 8 \ -} - -#endif diff --git a/drivers/usb/media/pwc/Makefile b/drivers/usb/media/pwc/Makefile deleted file mode 100644 index 2d93a775011a..000000000000 --- a/drivers/usb/media/pwc/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -ifneq ($(KERNELRELEASE),) - -pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o - -obj-$(CONFIG_USB_PWC) += pwc.o - -else - -KDIR := /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) - -default: - $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules - -endif - -clean: - rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c - rm -rf .tmp_versions - diff --git a/drivers/usb/media/pwc/philips.txt b/drivers/usb/media/pwc/philips.txt deleted file mode 100644 index 04a640d723ed..000000000000 --- a/drivers/usb/media/pwc/philips.txt +++ /dev/null @@ -1,236 +0,0 @@ -This file contains some additional information for the Philips and OEM webcams. -E-mail: webcam@smcc.demon.nl Last updated: 2004-01-19 -Site: http://www.smcc.demon.nl/webcam/ - -As of this moment, the following cameras are supported: - * Philips PCA645 - * Philips PCA646 - * Philips PCVC675 - * Philips PCVC680 - * Philips PCVC690 - * Philips PCVC720/40 - * Philips PCVC730 - * Philips PCVC740 - * Philips PCVC750 - * Askey VC010 - * Creative Labs Webcam 5 - * Creative Labs Webcam Pro Ex - * Logitech QuickCam 3000 Pro - * Logitech QuickCam 4000 Pro - * Logitech QuickCam Notebook Pro - * Logitech QuickCam Zoom - * Logitech QuickCam Orbit - * Logitech QuickCam Sphere - * Samsung MPC-C10 - * Samsung MPC-C30 - * Sotec Afina Eye - * AME CU-001 - * Visionite VCS-UM100 - * Visionite VCS-UC300 - -The main webpage for the Philips driver is at the address above. It contains -a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin -contains decompression routines that allow you to use higher image sizes and -framerates; in addition the webcam uses less bandwidth on the USB bus (handy -if you want to run more than 1 camera simultaneously). These routines fall -under a NDA, and may therefor not be distributed as source; however, its use -is completely optional. - -You can build this code either into your kernel, or as a module. I recommend -the latter, since it makes troubleshooting a lot easier. The built-in -microphone is supported through the USB Audio class. - -When you load the module you can set some default settings for the -camera; some programs depend on a particular image-size or -format and -don't know how to set it properly in the driver. The options are: - -size - Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or - 'vga', for an image size of resp. 128x96, 160x120, 176x144, - 320x240, 352x288 and 640x480 (of course, only for those cameras that - support these resolutions). - -fps - Specifies the desired framerate. Is an integer in the range of 4-30. - -fbufs - This paramter specifies the number of internal buffers to use for storing - frames from the cam. This will help if the process that reads images from - the cam is a bit slow or momentarely busy. However, on slow machines it - only introduces lag, so choose carefully. The default is 3, which is - reasonable. You can set it between 2 and 5. - -mbufs - This is an integer between 1 and 10. It will tell the module the number of - buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends. - The default is 2, which is adequate for most applications (double - buffering). - - Should you experience a lot of 'Dumping frame...' messages during - grabbing with a tool that uses mmap(), you might want to increase if. - However, it doesn't really buffer images, it just gives you a bit more - slack when your program is behind. But you need a multi-threaded or - forked program to really take advantage of these buffers. - - The absolute maximum is 10, but don't set it too high! Every buffer takes - up 460 KB of RAM, so unless you have a lot of memory setting this to - something more than 4 is an absolute waste. This memory is only - allocated during open(), so nothing is wasted when the camera is not in - use. - -power_save - When power_save is enabled (set to 1), the module will try to shut down - the cam on close() and re-activate on open(). This will save power and - turn off the LED. Not all cameras support this though (the 645 and 646 - don't have power saving at all), and some models don't work either (they - will shut down, but never wake up). Consider this experimental. By - default this option is disabled. - -compression (only useful with the plugin) - With this option you can control the compression factor that the camera - uses to squeeze the image through the USB bus. You can set the - parameter between 0 and 3: - 0 = prefer uncompressed images; if the requested mode is not available - in an uncompressed format, the driver will silently switch to low - compression. - 1 = low compression. - 2 = medium compression. - 3 = high compression. - - High compression takes less bandwidth of course, but it could also - introduce some unwanted artefacts. The default is 2, medium compression. - See the FAQ on the website for an overview of which modes require - compression. - - The compression parameter does not apply to the 645 and 646 cameras - and OEM models derived from those (only a few). Most cams honour this - parameter. - -leds - This settings takes 2 integers, that define the on/off time for the LED - (in milliseconds). One of the interesting things that you can do with - this is let the LED blink while the camera is in use. This: - - leds=500,500 - - will blink the LED once every second. But with: - - leds=0,0 - - the LED never goes on, making it suitable for silent surveillance. - - By default the camera's LED is on solid while in use, and turned off - when the camera is not used anymore. - - This parameter works only with the ToUCam range of cameras (720, 730, 740, - 750) and OEMs. For other cameras this command is silently ignored, and - the LED cannot be controlled. - - Finally: this parameters does not take effect UNTIL the first time you - open the camera device. Until then, the LED remains on. - -dev_hint - A long standing problem with USB devices is their dynamic nature: you - never know what device a camera gets assigned; it depends on module load - order, the hub configuration, the order in which devices are plugged in, - and the phase of the moon (i.e. it can be random). With this option you - can give the driver a hint as to what video device node (/dev/videoX) it - should use with a specific camera. This is also handy if you have two - cameras of the same model. - - A camera is specified by its type (the number from the camera model, - like PCA645, PCVC750VC, etc) and optionally the serial number (visible - in /proc/bus/usb/devices). A hint consists of a string with the following - format: - - [type[.serialnumber]:]node - - The square brackets mean that both the type and the serialnumber are - optional, but a serialnumber cannot be specified without a type (which - would be rather pointless). The serialnumber is separated from the type - by a '.'; the node number by a ':'. - - This somewhat cryptic syntax is best explained by a few examples: - - dev_hint=3,5 The first detected cam gets assigned - /dev/video3, the second /dev/video5. Any - other cameras will get the first free - available slot (see below). - - dev_hint=645:1,680:2 The PCA645 camera will get /dev/video1, - and a PCVC680 /dev/video2. - - dev_hint=645.0123:3,645.4567:0 The PCA645 camera with serialnumber - 0123 goes to /dev/video3, the same - camera model with the 4567 serial - gets /dev/video0. - - dev_hint=750:1,4,5,6 The PCVC750 camera will get /dev/video1, the - next 3 Philips cams will use /dev/video4 - through /dev/video6. - - Some points worth knowing: - - Serialnumbers are case sensitive and must be written full, including - leading zeroes (it's treated as a string). - - If a device node is already occupied, registration will fail and - the webcam is not available. - - You can have up to 64 video devices; be sure to make enough device - nodes in /dev if you want to spread the numbers (this does not apply - to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA). - - If a camera does not match any dev_hint, it will simply get assigned - the first available device node, just as it used to be. - -trace - In order to better detect problems, it is now possible to turn on a - 'trace' of some of the calls the module makes; it logs all items in your - kernel log at debug level. - - The trace variable is a bitmask; each bit represents a certain feature. - If you want to trace something, look up the bit value(s) in the table - below, add the values together and supply that to the trace variable. - - Value Value Description Default - (dec) (hex) - 1 0x1 Module initialization; this will log messages On - while loading and unloading the module - - 2 0x2 probe() and disconnect() traces On - - 4 0x4 Trace open() and close() calls Off - - 8 0x8 read(), mmap() and associated ioctl() calls Off - - 16 0x10 Memory allocation of buffers, etc. Off - - 32 0x20 Showing underflow, overflow and Dumping frame On - messages - - 64 0x40 Show viewport and image sizes Off - - 128 0x80 PWCX debugging Off - - For example, to trace the open() & read() fuctions, sum 8 + 4 = 12, - so you would supply trace=12 during insmod or modprobe. If - you want to turn the initialization and probing tracing off, set trace=0. - The default value for trace is 35 (0x23). - - - -Example: - - # modprobe pwc size=cif fps=15 power_save=1 - -The fbufs, mbufs and trace parameters are global and apply to all connected -cameras. Each camera has its own set of buffers. - -size and fps only specify defaults when you open() the device; this is to -accommodate some tools that don't set the size. You can change these -settings after open() with the Video4Linux ioctl() calls. The default of -defaults is QCIF size at 10 fps. - -The compression parameter is semiglobal; it sets the initial compression -preference for all camera's, but this parameter can be set per camera with -the VIDIOCPWCSCQUAL ioctl() call. - -All parameters are optional. - diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c deleted file mode 100644 index 0398b812e0ce..000000000000 --- a/drivers/usb/media/pwc/pwc-ctrl.c +++ /dev/null @@ -1,1541 +0,0 @@ -/* Driver for Philips webcam - Functions that send various control messages to the webcam, including - video modes. - (C) 1999-2003 Nemosoft Unv. - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - Changes - 2001/08/03 Alvarado Added methods for changing white balance and - red/green gains - */ - -/* Control functions for the cam; brightness, contrast, video mode, etc. */ - -#ifdef __KERNEL__ -#include -#endif -#include - -#include "pwc.h" -#include "pwc-ioctl.h" -#include "pwc-uncompress.h" -#include "pwc-kiara.h" -#include "pwc-timon.h" - -/* Request types: video */ -#define SET_LUM_CTL 0x01 -#define GET_LUM_CTL 0x02 -#define SET_CHROM_CTL 0x03 -#define GET_CHROM_CTL 0x04 -#define SET_STATUS_CTL 0x05 -#define GET_STATUS_CTL 0x06 -#define SET_EP_STREAM_CTL 0x07 -#define GET_EP_STREAM_CTL 0x08 -#define SET_MPT_CTL 0x0D -#define GET_MPT_CTL 0x0E - -/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ -#define AGC_MODE_FORMATTER 0x2000 -#define PRESET_AGC_FORMATTER 0x2100 -#define SHUTTER_MODE_FORMATTER 0x2200 -#define PRESET_SHUTTER_FORMATTER 0x2300 -#define PRESET_CONTOUR_FORMATTER 0x2400 -#define AUTO_CONTOUR_FORMATTER 0x2500 -#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 -#define CONTRAST_FORMATTER 0x2700 -#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 -#define FLICKERLESS_MODE_FORMATTER 0x2900 -#define AE_CONTROL_SPEED 0x2A00 -#define BRIGHTNESS_FORMATTER 0x2B00 -#define GAMMA_FORMATTER 0x2C00 - -/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ -#define WB_MODE_FORMATTER 0x1000 -#define AWB_CONTROL_SPEED_FORMATTER 0x1100 -#define AWB_CONTROL_DELAY_FORMATTER 0x1200 -#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 -#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 -#define COLOUR_MODE_FORMATTER 0x1500 -#define SATURATION_MODE_FORMATTER1 0x1600 -#define SATURATION_MODE_FORMATTER2 0x1700 - -/* Selectors for the Status controls [GS]ET_STATUS_CTL */ -#define SAVE_USER_DEFAULTS_FORMATTER 0x0200 -#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 -#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 -#define READ_AGC_FORMATTER 0x0500 -#define READ_SHUTTER_FORMATTER 0x0600 -#define READ_RED_GAIN_FORMATTER 0x0700 -#define READ_BLUE_GAIN_FORMATTER 0x0800 -#define SENSOR_TYPE_FORMATTER1 0x0C00 -#define READ_RAW_Y_MEAN_FORMATTER 0x3100 -#define SET_POWER_SAVE_MODE_FORMATTER 0x3200 -#define MIRROR_IMAGE_FORMATTER 0x3300 -#define LED_FORMATTER 0x3400 -#define SENSOR_TYPE_FORMATTER2 0x3700 - -/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ -#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 - -/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ -#define PT_RELATIVE_CONTROL_FORMATTER 0x01 -#define PT_RESET_CONTROL_FORMATTER 0x02 -#define PT_STATUS_FORMATTER 0x03 - -static const char *size2name[PSZ_MAX] = -{ - "subQCIF", - "QSIF", - "QCIF", - "SIF", - "CIF", - "VGA", -}; - -/********/ - -/* Entries for the Nala (645/646) camera; the Nala doesn't have compression - preferences, so you either get compressed or non-compressed streams. - - An alternate value of 0 means this mode is not available at all. - */ - -struct Nala_table_entry { - char alternate; /* USB alternate setting */ - int compressed; /* Compressed yes/no */ - - unsigned char mode[3]; /* precomputed mode table */ -}; - -static struct Nala_table_entry Nala_table[PSZ_MAX][8] = -{ -#include "pwc-nala.h" -}; - - -/****************************************************************************/ - - -#define SendControlMsg(request, value, buflen) \ - usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ - request, \ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ - value, \ - pdev->vcinterface, \ - &buf, buflen, 500) - -#define RecvControlMsg(request, value, buflen) \ - usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ - request, \ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ - value, \ - pdev->vcinterface, \ - &buf, buflen, 500) - - -#if PWC_DEBUG -void pwc_hexdump(void *p, int len) -{ - int i; - unsigned char *s; - char buf[100], *d; - - s = (unsigned char *)p; - d = buf; - *d = '\0'; - Debug("Doing hexdump @ %p, %d bytes.\n", p, len); - for (i = 0; i < len; i++) { - d += sprintf(d, "%02X ", *s++); - if ((i & 0xF) == 0xF) { - Debug("%s\n", buf); - d = buf; - *d = '\0'; - } - } - if ((i & 0xF) != 0) - Debug("%s\n", buf); -} -#endif - -static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) -{ - return usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - SET_EP_STREAM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - VIDEO_OUTPUT_CONTROL_FORMATTER, - index, - buf, buflen, 1000); -} - - - -static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) -{ - unsigned char buf[3]; - int ret, fps; - struct Nala_table_entry *pEntry; - int frames2frames[31] = - { /* closest match of framerate */ - 0, 0, 0, 0, 4, /* 0-4 */ - 5, 5, 7, 7, 10, /* 5-9 */ - 10, 10, 12, 12, 15, /* 10-14 */ - 15, 15, 15, 20, 20, /* 15-19 */ - 20, 20, 20, 24, 24, /* 20-24 */ - 24, 24, 24, 24, 24, /* 25-29 */ - 24 /* 30 */ - }; - int frames2table[31] = - { 0, 0, 0, 0, 0, /* 0-4 */ - 1, 1, 1, 2, 2, /* 5-9 */ - 3, 3, 4, 4, 4, /* 10-14 */ - 5, 5, 5, 5, 5, /* 15-19 */ - 6, 6, 6, 6, 7, /* 20-24 */ - 7, 7, 7, 7, 7, /* 25-29 */ - 7 /* 30 */ - }; - - if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) - return -EINVAL; - frames = frames2frames[frames]; - fps = frames2table[frames]; - pEntry = &Nala_table[size][fps]; - if (pEntry->alternate == 0) - return -EINVAL; - - if (pEntry->compressed) - return -ENOENT; /* Not supported. */ - - memcpy(buf, pEntry->mode, 3); - ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); - if (ret < 0) { - Debug("Failed to send video command... %d\n", ret); - return ret; - } - if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) - { - switch(pdev->type) { - case 645: - case 646: -/* pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ - break; - - case 675: - case 680: - case 690: - case 720: - case 730: - case 740: - case 750: -/* pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ - break; - } - } - - pdev->cmd_len = 3; - memcpy(pdev->cmd_buf, buf, 3); - - /* Set various parameters */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->valternate = pEntry->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; - if (pEntry->compressed) { - if (pdev->release < 5) { /* 4 fold compression */ - pdev->vbandlength = 528; - pdev->frame_size /= 4; - } - else { - pdev->vbandlength = 704; - pdev->frame_size /= 3; - } - } - else - pdev->vbandlength = 0; - return 0; -} - - -static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) -{ - unsigned char buf[13]; - const struct Timon_table_entry *pChoose; - int ret, fps; - - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) - return -EINVAL; - fps = (frames / 5) - 1; - - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - */ - pChoose = NULL; - while (compression <= 3) { - pChoose = &Timon_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; - } - if (pChoose == NULL || pChoose->alternate == 0) - return -ENOENT; /* Not supported. */ - - memcpy(buf, pChoose->mode, 13); - if (snapshot) - buf[0] |= 0x80; - ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); - if (ret < 0) - return ret; - -/* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) - pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ - - pdev->cmd_len = 13; - memcpy(pdev->cmd_buf, buf, 13); - - /* Set various parameters */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; - pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->vbandlength = pChoose->bandlength; - if (pChoose->bandlength > 0) - pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; - else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - return 0; -} - - -static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) -{ - const struct Kiara_table_entry *pChoose = NULL; - int fps, ret; - unsigned char buf[12]; - struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; - - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) - return -EINVAL; - if (size == PSZ_VGA && frames > 15) - return -EINVAL; - fps = (frames / 5) - 1; - - /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ - if (size == PSZ_VGA && frames == 5 && snapshot) - { - /* Only available in case the raw palette is selected or - we have the decompressor available. This mode is - only available in compressed form - */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) - { - Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); - pChoose = &RawEntry; - } - else - { - Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); - } - } - else - { - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - Skip this step when using RAW modes. - */ - while (compression <= 3) { - pChoose = &Kiara_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; - } - } - if (pChoose == NULL || pChoose->alternate == 0) - return -ENOENT; /* Not supported. */ - - Debug("Using alternate setting %d.\n", pChoose->alternate); - - /* usb_control_msg won't take staticly allocated arrays as argument?? */ - memcpy(buf, pChoose->mode, 12); - if (snapshot) - buf[0] |= 0x80; - - /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ - ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); - if (ret < 0) - return ret; - -/* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) - pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */ - - pdev->cmd_len = 12; - memcpy(pdev->cmd_buf, buf, 12); - /* All set and go */ - pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; - pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->vbandlength = pChoose->bandlength; - if (pdev->vbandlength > 0) - pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; - else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - return 0; -} - - - -static void pwc_set_image_buffer_size(struct pwc_device *pdev) -{ - int i, factor = 0, filler = 0; - - /* for PALETTE_YUV420P */ - switch(pdev->vpalette) - { - case VIDEO_PALETTE_YUV420P: - factor = 6; - filler = 128; - break; - case VIDEO_PALETTE_RAW: - factor = 6; /* can be uncompressed YUV420P */ - filler = 0; - break; - } - - /* Set sizes in bytes */ - pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; - pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; - - /* Align offset, or you'll get some very weird results in - YUV420 mode... x must be multiple of 4 (to get the Y's in - place), and y even (or you'll mixup U & V). This is less of a - problem for YUV420P. - */ - pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; - pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; - - /* Fill buffers with gray or black */ - for (i = 0; i < MAX_IMAGES; i++) { - if (pdev->image_ptr[i] != NULL) - memset(pdev->image_ptr[i], filler, pdev->view.size); - } -} - - - -/** - @pdev: device structure - @width: viewport width - @height: viewport height - @frame: framerate, in fps - @compression: preferred compression ratio - @snapshot: snapshot mode or streaming - */ -int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) -{ - int ret, size; - - Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); - size = pwc_decode_size(pdev, width, height); - if (size < 0) { - Debug("Could not find suitable size.\n"); - return -ERANGE; - } - Debug("decode_size = %d.\n", size); - - ret = -EINVAL; - switch(pdev->type) { - case 645: - case 646: - ret = set_video_mode_Nala(pdev, size, frames); - break; - - case 675: - case 680: - case 690: - ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); - break; - - case 720: - case 730: - case 740: - case 750: - ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); - break; - } - if (ret < 0) { - if (ret == -ENOENT) - Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); - else { - Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); - } - return ret; - } - pdev->view.x = width; - pdev->view.y = height; - pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; - pwc_set_image_buffer_size(pdev); - Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); - return 0; -} - - -/* BRIGHTNESS */ - -int pwc_get_brightness(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); - if (ret < 0) - return ret; - return buf << 9; -} - -int pwc_set_brightness(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 9) & 0x7f; - return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); -} - -/* CONTRAST */ - -int pwc_get_contrast(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); - if (ret < 0) - return ret; - return buf << 10; -} - -int pwc_set_contrast(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 10) & 0x3f; - return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); -} - -/* GAMMA */ - -int pwc_get_gamma(struct pwc_device *pdev) -{ - char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); - if (ret < 0) - return ret; - return buf << 11; -} - -int pwc_set_gamma(struct pwc_device *pdev, int value) -{ - char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 11) & 0x1f; - return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); -} - - -/* SATURATION */ - -int pwc_get_saturation(struct pwc_device *pdev) -{ - char buf; - int ret; - - if (pdev->type < 675) - return -1; - ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); - if (ret < 0) - return ret; - return 32768 + buf * 327; -} - -int pwc_set_saturation(struct pwc_device *pdev, int value) -{ - char buf; - - if (pdev->type < 675) - return -EINVAL; - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - /* saturation ranges from -100 to +100 */ - buf = (value - 32768) / 327; - return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); -} - -/* AGC */ - -static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value) -{ - char buf; - int ret; - - if (mode) - buf = 0x0; /* auto */ - else - buf = 0xff; /* fixed */ - - ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); - - if (!mode && ret >= 0) { - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - buf = (value >> 10) & 0x3F; - ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); - } - if (ret < 0) - return ret; - return 0; -} - -static inline int pwc_get_agc(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); - if (ret < 0) - return ret; - - if (buf != 0) { /* fixed */ - ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); - if (ret < 0) - return ret; - if (buf > 0x3F) - buf = 0x3F; - *value = (buf << 10); - } - else { /* auto */ - ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); - if (ret < 0) - return ret; - /* Gah... this value ranges from 0x00 ... 0x9F */ - if (buf > 0x9F) - buf = 0x9F; - *value = -(48 + buf * 409); - } - - return 0; -} - -static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) -{ - char buf[2]; - int speed, ret; - - - if (mode) - buf[0] = 0x0; /* auto */ - else - buf[0] = 0xff; /* fixed */ - - ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); - - if (!mode && ret >= 0) { - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - switch(pdev->type) { - case 675: - case 680: - case 690: - /* speed ranges from 0x0 to 0x290 (656) */ - speed = (value / 100); - buf[1] = speed >> 8; - buf[0] = speed & 0xff; - break; - case 720: - case 730: - case 740: - case 750: - /* speed seems to range from 0x0 to 0xff */ - buf[1] = 0; - buf[0] = value >> 8; - break; - } - - ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); - } - return ret; -} - - -/* POWER */ - -int pwc_camera_power(struct pwc_device *pdev, int power) -{ - char buf; - - if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) - return 0; /* Not supported by Nala or Timon < release 6 */ - - if (power) - buf = 0x00; /* active */ - else - buf = 0xFF; /* power save */ - return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); -} - - - -/* private calls */ - -static inline int pwc_restore_user(struct pwc_device *pdev) -{ - char buf; /* dummy */ - return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); -} - -static inline int pwc_save_user(struct pwc_device *pdev) -{ - char buf; /* dummy */ - return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); -} - -static inline int pwc_restore_factory(struct pwc_device *pdev) -{ - char buf; /* dummy */ - return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); -} - - /* ************************************************* */ - /* Patch by Alvarado: (not in the original version */ - - /* - * the camera recognizes modes from 0 to 4: - * - * 00: indoor (incandescant lighting) - * 01: outdoor (sunlight) - * 02: fluorescent lighting - * 03: manual - * 04: auto - */ -static inline int pwc_set_awb(struct pwc_device *pdev, int mode) -{ - char buf; - int ret; - - if (mode < 0) - mode = 0; - - if (mode > 4) - mode = 4; - - buf = mode & 0x07; /* just the lowest three bits */ - - ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); - - if (ret < 0) - return ret; - return 0; -} - -static inline int pwc_get_awb(struct pwc_device *pdev) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); - - if (ret < 0) - return ret; - return buf; -} - -static inline int pwc_set_red_gain(struct pwc_device *pdev, int value) -{ - unsigned char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - /* only the msb is considered */ - buf = value >> 8; - return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); -} - -static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value) -{ - unsigned char buf; - - if (value < 0) - value = 0; - if (value > 0xffff) - value = 0xffff; - /* only the msb is considered */ - buf = value >> 8; - return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); -} - -static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -/* The following two functions are different, since they only read the - internal red/blue gains, which may be different from the manual - gains set or read above. - */ -static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - -static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 8; - return 0; -} - - -static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) -{ - unsigned char buf; - - /* useful range is 0x01..0x20 */ - buf = speed / 0x7f0; - return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); -} - -static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf * 0x7f0; - return 0; -} - - -static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) -{ - unsigned char buf; - - /* useful range is 0x01..0x3F */ - buf = (delay >> 10); - return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); -} - -static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); - if (ret < 0) - return ret; - *value = buf << 10; - return 0; -} - - -int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) -{ - unsigned char buf[2]; - - if (pdev->type < 730) - return 0; - on_value /= 100; - off_value /= 100; - if (on_value < 0) - on_value = 0; - if (on_value > 0xff) - on_value = 0xff; - if (off_value < 0) - off_value = 0; - if (off_value > 0xff) - off_value = 0xff; - - buf[0] = on_value; - buf[1] = off_value; - - return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); -} - -static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) -{ - unsigned char buf[2]; - int ret; - - if (pdev->type < 730) { - *on_value = -1; - *off_value = -1; - return 0; - } - - ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); - if (ret < 0) - return ret; - *on_value = buf[0] * 100; - *off_value = buf[1] * 100; - return 0; -} - -static inline int pwc_set_contour(struct pwc_device *pdev, int contour) -{ - unsigned char buf; - int ret; - - if (contour < 0) - buf = 0xff; /* auto contour on */ - else - buf = 0x0; /* auto contour off */ - ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); - if (ret < 0) - return ret; - - if (contour < 0) - return 0; - if (contour > 0xffff) - contour = 0xffff; - - buf = (contour >> 10); /* contour preset is [0..3f] */ - ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); - if (ret < 0) - return ret; - return 0; -} - -static inline int pwc_get_contour(struct pwc_device *pdev, int *contour) -{ - unsigned char buf; - int ret; - - ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); - if (ret < 0) - return ret; - - if (buf == 0) { - /* auto mode off, query current preset value */ - ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); - if (ret < 0) - return ret; - *contour = buf << 10; - } - else - *contour = -1; - return 0; -} - - -static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) -{ - unsigned char buf; - - if (backlight) - buf = 0xff; - else - buf = 0x0; - return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); -} - -static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight) -{ - int ret; - unsigned char buf; - - ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); - if (ret < 0) - return ret; - *backlight = buf; - return 0; -} - - -static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) -{ - unsigned char buf; - - if (flicker) - buf = 0xff; - else - buf = 0x0; - return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); -} - -static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker) -{ - int ret; - unsigned char buf; - - ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); - if (ret < 0) - return ret; - *flicker = buf; - return 0; -} - - -static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) -{ - unsigned char buf; - - if (noise < 0) - noise = 0; - if (noise > 3) - noise = 3; - buf = noise; - return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); -} - -static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) -{ - int ret; - unsigned char buf; - - ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); - if (ret < 0) - return ret; - *noise = buf; - return 0; -} - -static int pwc_mpt_reset(struct pwc_device *pdev, int flags) -{ - unsigned char buf; - - buf = flags & 0x03; // only lower two bits are currently used - return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); -} - -static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) -{ - unsigned char buf[4]; - - /* set new relative angle; angles are expressed in degrees * 100, - but cam as .5 degree resolution, hence divide by 200. Also - the angle must be multiplied by 64 before it's send to - the cam (??) - */ - pan = 64 * pan / 100; - tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ - buf[0] = pan & 0xFF; - buf[1] = (pan >> 8) & 0xFF; - buf[2] = tilt & 0xFF; - buf[3] = (tilt >> 8) & 0xFF; - return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4); -} - -static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) -{ - int ret; - unsigned char buf[5]; - - ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); - if (ret < 0) - return ret; - status->status = buf[0] & 0x7; // 3 bits are used for reporting - status->time_pan = (buf[1] << 8) + buf[2]; - status->time_tilt = (buf[3] << 8) + buf[4]; - return 0; -} - - -int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) -{ - unsigned char buf; - int ret = -1, request; - - if (pdev->type < 675) - request = SENSOR_TYPE_FORMATTER1; - else if (pdev->type < 730) - return -1; /* The Vesta series doesn't have this call */ - else - request = SENSOR_TYPE_FORMATTER2; - - ret = RecvControlMsg(GET_STATUS_CTL, request, 1); - if (ret < 0) - return ret; - if (pdev->type < 675) - *sensor = buf | 0x100; - else - *sensor = buf; - return 0; -} - - - /* End of Add-Ons */ - /* ************************************************* */ - - -int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) -{ - int ret = 0; - - switch(cmd) { - case VIDIOCPWCRUSER: - { - if (pwc_restore_user(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSUSER: - { - if (pwc_save_user(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCFACTORY: - { - if (pwc_restore_factory(pdev)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSCQUAL: - { - int *qual = arg; - - if (*qual < 0 || *qual > 3) - ret = -EINVAL; - else - ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot); - if (ret >= 0) - pdev->vcompression = *qual; - break; - } - - case VIDIOCPWCGCQUAL: - { - int *qual = arg; - *qual = pdev->vcompression; - break; - } - - case VIDIOCPWCPROBE: - { - struct pwc_probe *probe = arg; - strcpy(probe->name, pdev->vdev->name); - probe->type = pdev->type; - break; - } - - case VIDIOCPWCGSERIAL: - { - struct pwc_serial *serial = arg; - strcpy(serial->serial, pdev->serial); - break; - } - - case VIDIOCPWCSAGC: - { - int *agc = arg; - if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCGAGC: - { - int *agc = arg; - - if (pwc_get_agc(pdev, agc)) - ret = -EINVAL; - break; - } - - case VIDIOCPWCSSHUTTER: - { - int *shutter_speed = arg; - ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed); - break; - } - - case VIDIOCPWCSAWB: - { - struct pwc_whitebalance *wb = arg; - - ret = pwc_set_awb(pdev, wb->mode); - if (ret >= 0 && wb->mode == PWC_WB_MANUAL) { - pwc_set_red_gain(pdev, wb->manual_red); - pwc_set_blue_gain(pdev, wb->manual_blue); - } - break; - } - - case VIDIOCPWCGAWB: - { - struct pwc_whitebalance *wb = arg; - - memset(wb, 0, sizeof(struct pwc_whitebalance)); - wb->mode = pwc_get_awb(pdev); - if (wb->mode < 0) - ret = -EINVAL; - else { - if (wb->mode == PWC_WB_MANUAL) { - ret = pwc_get_red_gain(pdev, &wb->manual_red); - if (ret < 0) - break; - ret = pwc_get_blue_gain(pdev, &wb->manual_blue); - if (ret < 0) - break; - } - if (wb->mode == PWC_WB_AUTO) { - ret = pwc_read_red_gain(pdev, &wb->read_red); - if (ret < 0) - break; - ret = pwc_read_blue_gain(pdev, &wb->read_blue); - if (ret < 0) - break; - } - } - break; - } - - case VIDIOCPWCSAWBSPEED: - { - struct pwc_wb_speed *wbs = arg; - - if (wbs->control_speed > 0) { - ret = pwc_set_wb_speed(pdev, wbs->control_speed); - } - if (wbs->control_delay > 0) { - ret = pwc_set_wb_delay(pdev, wbs->control_delay); - } - break; - } - - case VIDIOCPWCGAWBSPEED: - { - struct pwc_wb_speed *wbs = arg; - - ret = pwc_get_wb_speed(pdev, &wbs->control_speed); - if (ret < 0) - break; - ret = pwc_get_wb_delay(pdev, &wbs->control_delay); - if (ret < 0) - break; - break; - } - - case VIDIOCPWCSLED: - { - struct pwc_leds *leds = arg; - ret = pwc_set_leds(pdev, leds->led_on, leds->led_off); - break; - } - - - case VIDIOCPWCGLED: - { - struct pwc_leds *leds = arg; - ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off); - break; - } - - case VIDIOCPWCSCONTOUR: - { - int *contour = arg; - ret = pwc_set_contour(pdev, *contour); - break; - } - - case VIDIOCPWCGCONTOUR: - { - int *contour = arg; - ret = pwc_get_contour(pdev, contour); - break; - } - - case VIDIOCPWCSBACKLIGHT: - { - int *backlight = arg; - ret = pwc_set_backlight(pdev, *backlight); - break; - } - - case VIDIOCPWCGBACKLIGHT: - { - int *backlight = arg; - ret = pwc_get_backlight(pdev, backlight); - break; - } - - case VIDIOCPWCSFLICKER: - { - int *flicker = arg; - ret = pwc_set_flicker(pdev, *flicker); - break; - } - - case VIDIOCPWCGFLICKER: - { - int *flicker = arg; - ret = pwc_get_flicker(pdev, flicker); - break; - } - - case VIDIOCPWCSDYNNOISE: - { - int *dynnoise = arg; - ret = pwc_set_dynamic_noise(pdev, *dynnoise); - break; - } - - case VIDIOCPWCGDYNNOISE: - { - int *dynnoise = arg; - ret = pwc_get_dynamic_noise(pdev, dynnoise); - break; - } - - case VIDIOCPWCGREALSIZE: - { - struct pwc_imagesize *size = arg; - size->width = pdev->image.x; - size->height = pdev->image.y; - break; - } - - case VIDIOCPWCMPTRESET: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - int *flags = arg; - - ret = pwc_mpt_reset(pdev, *flags); - if (ret >= 0) - { - pdev->pan_angle = 0; - pdev->tilt_angle = 0; - } - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGRANGE: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - struct pwc_mpt_range *range = arg; - *range = pdev->angle_range; - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSANGLE: - { - int new_pan, new_tilt; - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - struct pwc_mpt_angles *angles = arg; - /* The camera can only set relative angles, so - do some calculations when getting an absolute angle . - */ - if (angles->absolute) - { - new_pan = angles->pan; - new_tilt = angles->tilt; - } - else - { - new_pan = pdev->pan_angle + angles->pan; - new_tilt = pdev->tilt_angle + angles->tilt; - } - /* check absolute ranges */ - if (new_pan < pdev->angle_range.pan_min || - new_pan > pdev->angle_range.pan_max || - new_tilt < pdev->angle_range.tilt_min || - new_tilt > pdev->angle_range.tilt_max) - { - ret = -ERANGE; - } - else - { - /* go to relative range, check again */ - new_pan -= pdev->pan_angle; - new_tilt -= pdev->tilt_angle; - /* angles are specified in degrees * 100, thus the limit = 36000 */ - if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000) - ret = -ERANGE; - } - if (ret == 0) /* no errors so far */ - { - ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); - if (ret >= 0) - { - pdev->pan_angle += new_pan; - pdev->tilt_angle += new_tilt; - } - if (ret == -EPIPE) /* stall -> out of range */ - ret = -ERANGE; - } - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGANGLE: - { - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - struct pwc_mpt_angles *angles = arg; - - angles->absolute = 1; - angles->pan = pdev->pan_angle; - angles->tilt = pdev->tilt_angle; - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSTATUS: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - struct pwc_mpt_status *status = arg; - ret = pwc_mpt_get_status(pdev, status); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCGVIDCMD: - { - struct pwc_video_command *cmd = arg; - - cmd->type = pdev->type; - cmd->release = pdev->release; - cmd->command_len = pdev->cmd_len; - memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len); - cmd->bandlength = pdev->vbandlength; - cmd->frame_size = pdev->frame_size; - break; - } - /* - case VIDIOCPWCGVIDTABLE: - { - struct pwc_table_init_buffer *table = arg; - table->len = pdev->cmd_len; - memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size); - break; - } - */ - - default: - ret = -ENOIOCTLCMD; - break; - } - - if (ret > 0) - return 0; - return ret; -} - - - diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c deleted file mode 100644 index 90eb26042817..000000000000 --- a/drivers/usb/media/pwc/pwc-if.c +++ /dev/null @@ -1,2205 +0,0 @@ -/* Linux driver for Philips webcam - USB and Video4Linux interface part. - (C) 1999-2004 Nemosoft Unv. - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -/* - This code forms the interface between the USB layers and the Philips - specific stuff. Some adanved stuff of the driver falls under an - NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and - is thus not distributed in source form. The binary pwcx.o module - contains the code that falls under the NDA. - - In case you're wondering: 'pwc' stands for "Philips WebCam", but - I really didn't want to type 'philips_web_cam' every time (I'm lazy as - any Linux kernel hacker, but I don't like uncomprehensible abbreviations - without explanation). - - Oh yes, convention: to disctinguish between all the various pointers to - device-structures, I use these names for the pointer variables: - udev: struct usb_device * - vdev: struct video_device * - pdev: struct pwc_devive * -*/ - -/* Contributors: - - Alvarado: adding whitebalance code - - Alistar Moire: QuickCam 3000 Pro device/product ID - - Tony Hoyle: Creative Labs Webcam 5 device/product ID - - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged - - Jk Fang: Sotec Afina Eye ID - - Xavier Roche: QuickCam Pro 4000 ID - - Jens Knudsen: QuickCam Zoom ID - - J. Debert: QuickCam for Notebooks ID -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pwc.h" -#include "pwc-ioctl.h" -#include "pwc-kiara.h" -#include "pwc-timon.h" -#include "pwc-uncompress.h" - -/* Function prototypes and driver templates */ - -/* hotplug device table support */ -static struct usb_device_id pwc_device_table [] = { - { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ - { USB_DEVICE(0x0471, 0x0303) }, - { USB_DEVICE(0x0471, 0x0304) }, - { USB_DEVICE(0x0471, 0x0307) }, - { USB_DEVICE(0x0471, 0x0308) }, - { USB_DEVICE(0x0471, 0x030C) }, - { USB_DEVICE(0x0471, 0x0310) }, - { USB_DEVICE(0x0471, 0x0311) }, - { USB_DEVICE(0x0471, 0x0312) }, - { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ - { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ - { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ - { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ - { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ - { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ - { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ - { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ - { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ - { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ - { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ - { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ - { USB_DEVICE(0x055D, 0x9001) }, - { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ - { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ - { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ - { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ - { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ - { USB_DEVICE(0x0d81, 0x1900) }, - { } -}; -MODULE_DEVICE_TABLE(usb, pwc_device_table); - -static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); -static void usb_pwc_disconnect(struct usb_interface *intf); - -static struct usb_driver pwc_driver = { - .name = "Philips webcam", /* name */ - .id_table = pwc_device_table, - .probe = usb_pwc_probe, /* probe() */ - .disconnect = usb_pwc_disconnect, /* disconnect() */ -}; - -#define MAX_DEV_HINTS 20 -#define MAX_ISOC_ERRORS 20 - -static int default_size = PSZ_QCIF; -static int default_fps = 10; -static int default_fbufs = 3; /* Default number of frame buffers */ -static int default_mbufs = 2; /* Default number of mmap() buffers */ - int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; -static int power_save = 0; -static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ -static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ -static struct { - int type; - char serial_number[30]; - int device_node; - struct pwc_device *pdev; -} device_hint[MAX_DEV_HINTS]; - -/***/ - -static int pwc_video_open(struct inode *inode, struct file *file); -static int pwc_video_close(struct inode *inode, struct file *file); -static ssize_t pwc_video_read(struct file *file, char __user * buf, - size_t count, loff_t *ppos); -static unsigned int pwc_video_poll(struct file *file, poll_table *wait); -static int pwc_video_ioctl(struct inode *inode, struct file *file, - unsigned int ioctlnr, unsigned long arg); -static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); - -static struct file_operations pwc_fops = { - .owner = THIS_MODULE, - .open = pwc_video_open, - .release = pwc_video_close, - .read = pwc_video_read, - .poll = pwc_video_poll, - .mmap = pwc_video_mmap, - .ioctl = pwc_video_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; -static struct video_device pwc_template = { - .owner = THIS_MODULE, - .name = "Philips Webcam", /* Filled in later */ - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_PWC, - .release = video_device_release, - .fops = &pwc_fops, - .minor = -1, -}; - -/***************************************************************************/ - -/* Okay, this is some magic that I worked out and the reasoning behind it... - - The biggest problem with any USB device is of course: "what to do - when the user unplugs the device while it is in use by an application?" - We have several options: - 1) Curse them with the 7 plagues when they do (requires divine intervention) - 2) Tell them not to (won't work: they'll do it anyway) - 3) Oops the kernel (this will have a negative effect on a user's uptime) - 4) Do something sensible. - - Of course, we go for option 4. - - It happens that this device will be linked to two times, once from - usb_device and once from the video_device in their respective 'private' - pointers. This is done when the device is probed() and all initialization - succeeded. The pwc_device struct links back to both structures. - - When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register it as a V4L device, but - unfortunately I can't free the memory since the struct is still in use - by the file descriptor. This free-ing is then deferend until the first - opportunity. Crude, but it works. - - A small 'advantage' is that if a user unplugs the cam and plugs it back - in, it should get assigned the same video device minor, but unfortunately - it's non-trivial to re-link the cam back to the video device... (that - would surely be magic! :)) -*/ - -/***************************************************************************/ -/* Private functions */ - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long kva, ret; - - kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - ret = __pa(kva); - return ret; -} - -static void * rvmalloc(unsigned long size) -{ - void * mem; - unsigned long adr; - - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} - - - - -static int pwc_allocate_buffers(struct pwc_device *pdev) -{ - int i; - void *kbuf; - - Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); - - if (pdev == NULL) - return -ENXIO; - -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("allocate_buffers(): magic failed.\n"); - return -ENXIO; - } -#endif - /* Allocate Isochronous pipe buffers */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (pdev->sbuf[i].data == NULL) { - kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); - if (kbuf == NULL) { - Err("Failed to allocate iso buffer %d.\n", i); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); - pdev->sbuf[i].data = kbuf; - memset(kbuf, 0, ISO_BUFFER_SIZE); - } - } - - /* Allocate frame buffer structure */ - if (pdev->fbuf == NULL) { - kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); - if (kbuf == NULL) { - Err("Failed to allocate frame buffer structure.\n"); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); - pdev->fbuf = kbuf; - memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); - } - /* create frame buffers, and make circular ring */ - for (i = 0; i < default_fbufs; i++) { - if (pdev->fbuf[i].data == NULL) { - kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ - if (kbuf == NULL) { - Err("Failed to allocate frame buffer %d.\n", i); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); - pdev->fbuf[i].data = kbuf; - memset(kbuf, 128, PWC_FRAME_SIZE); - } - } - - /* Allocate decompressor table space */ - kbuf = NULL; - switch (pdev->type) - { - case 675: - case 680: - case 690: - case 720: - case 730: - case 740: - case 750: -#if 0 - Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private)); - kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ - break; - case 645: - case 646: - /* TODO & FIXME */ - kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); - break; -#endif - ; - } - pdev->decompress_data = kbuf; - - /* Allocate image buffer; double buffer for mmap() */ - kbuf = rvmalloc(default_mbufs * pdev->len_per_image); - if (kbuf == NULL) { - Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image); - return -ENOMEM; - } - Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); - pdev->image_data = kbuf; - for (i = 0; i < default_mbufs; i++) - pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; - for (; i < MAX_IMAGES; i++) - pdev->image_ptr[i] = NULL; - - kbuf = NULL; - - Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); - return 0; -} - -static void pwc_free_buffers(struct pwc_device *pdev) -{ - int i; - - Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); - - if (pdev == NULL) - return; -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("free_buffers(): magic failed.\n"); - return; - } -#endif - - /* Release Iso-pipe buffers */ - for (i = 0; i < MAX_ISO_BUFS; i++) - if (pdev->sbuf[i].data != NULL) { - Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); - kfree(pdev->sbuf[i].data); - pdev->sbuf[i].data = NULL; - } - - /* The same for frame buffers */ - if (pdev->fbuf != NULL) { - for (i = 0; i < default_fbufs; i++) { - if (pdev->fbuf[i].data != NULL) { - Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); - vfree(pdev->fbuf[i].data); - pdev->fbuf[i].data = NULL; - } - } - kfree(pdev->fbuf); - pdev->fbuf = NULL; - } - - /* Intermediate decompression buffer & tables */ - if (pdev->decompress_data != NULL) { - Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); - kfree(pdev->decompress_data); - pdev->decompress_data = NULL; - } - pdev->decompressor = NULL; - - /* Release image buffers */ - if (pdev->image_data != NULL) { - Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); - rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); - } - pdev->image_data = NULL; - - Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); -} - -/* The frame & image buffer mess. - - Yes, this is a mess. Well, it used to be simple, but alas... In this - module, 3 buffers schemes are used to get the data from the USB bus to - the user program. The first scheme involves the ISO buffers (called thus - since they transport ISO data from the USB controller), and not really - interesting. Suffices to say the data from this buffer is quickly - gathered in an interrupt handler (pwc_isoc_handler) and placed into the - frame buffer. - - The frame buffer is the second scheme, and is the central element here. - It collects the data from a single frame from the camera (hence, the - name). Frames are delimited by the USB camera with a short USB packet, - so that's easy to detect. The frame buffers form a list that is filled - by the camera+USB controller and drained by the user process through - either read() or mmap(). - - The image buffer is the third scheme, in which frames are decompressed - and converted into planar format. For mmap() there is more than - one image buffer available. - - The frame buffers provide the image buffering. In case the user process - is a bit slow, this introduces lag and some undesired side-effects. - The problem arises when the frame buffer is full. I used to drop the last - frame, which makes the data in the queue stale very quickly. But dropping - the frame at the head of the queue proved to be a litte bit more difficult. - I tried a circular linked scheme, but this introduced more problems than - it solved. - - Because filling and draining are completely asynchronous processes, this - requires some fiddling with pointers and mutexes. - - Eventually, I came up with a system with 2 lists: an 'empty' frame list - and a 'full' frame list: - * Initially, all frame buffers but one are on the 'empty' list; the one - remaining buffer is our initial fill frame. - * If a frame is needed for filling, we try to take it from the 'empty' - list, unless that list is empty, in which case we take the buffer at - the head of the 'full' list. - * When our fill buffer has been filled, it is appended to the 'full' - list. - * If a frame is needed by read() or mmap(), it is taken from the head of - the 'full' list, handled, and then appended to the 'empty' list. If no - buffer is present on the 'full' list, we wait. - The advantage is that the buffer that is currently being decompressed/ - converted, is on neither list, and thus not in our way (any other scheme - I tried had the problem of old data lingering in the queue). - - Whatever strategy you choose, it always remains a tradeoff: with more - frame buffers the chances of a missed frame are reduced. On the other - hand, on slower machines it introduces lag because the queue will - always be full. - */ - -/** - \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. - */ -static inline int pwc_next_fill_frame(struct pwc_device *pdev) -{ - int ret; - unsigned long flags; - - ret = 0; - spin_lock_irqsave(&pdev->ptrlock, flags); - if (pdev->fill_frame != NULL) { - /* append to 'full' list */ - if (pdev->full_frames == NULL) { - pdev->full_frames = pdev->fill_frame; - pdev->full_frames_tail = pdev->full_frames; - } - else { - pdev->full_frames_tail->next = pdev->fill_frame; - pdev->full_frames_tail = pdev->fill_frame; - } - } - if (pdev->empty_frames != NULL) { - /* We have empty frames available. That's easy */ - pdev->fill_frame = pdev->empty_frames; - pdev->empty_frames = pdev->empty_frames->next; - } - else { - /* Hmm. Take it from the full list */ -#if PWC_DEBUG - /* sanity check */ - if (pdev->full_frames == NULL) { - Err("Neither empty or full frames available!\n"); - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return -EINVAL; - } -#endif - pdev->fill_frame = pdev->full_frames; - pdev->full_frames = pdev->full_frames->next; - ret = 1; - } - pdev->fill_frame->next = NULL; -#if PWC_DEBUG - Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); - pdev->fill_frame->sequence = pdev->sequence++; -#endif - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return ret; -} - - -/** - \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. - - If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. - */ -static void pwc_reset_buffers(struct pwc_device *pdev) -{ - int i; - unsigned long flags; - - spin_lock_irqsave(&pdev->ptrlock, flags); - pdev->full_frames = NULL; - pdev->full_frames_tail = NULL; - for (i = 0; i < default_fbufs; i++) { - pdev->fbuf[i].filled = 0; - if (i > 0) - pdev->fbuf[i].next = &pdev->fbuf[i - 1]; - else - pdev->fbuf->next = NULL; - } - pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; - pdev->empty_frames_tail = pdev->fbuf; - pdev->read_frame = NULL; - pdev->fill_frame = pdev->empty_frames; - pdev->empty_frames = pdev->empty_frames->next; - - pdev->image_read_pos = 0; - pdev->fill_image = 0; - spin_unlock_irqrestore(&pdev->ptrlock, flags); -} - - -/** - \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. - */ -static int pwc_handle_frame(struct pwc_device *pdev) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&pdev->ptrlock, flags); - /* First grab our read_frame; this is removed from all lists, so - we can release the lock after this without problems */ - if (pdev->read_frame != NULL) { - /* This can't theoretically happen */ - Err("Huh? Read frame still in use?\n"); - } - else { - if (pdev->full_frames == NULL) { - Err("Woops. No frames ready.\n"); - } - else { - pdev->read_frame = pdev->full_frames; - pdev->full_frames = pdev->full_frames->next; - pdev->read_frame->next = NULL; - } - - if (pdev->read_frame != NULL) { -#if PWC_DEBUG - Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); -#endif - /* Decompression is a lenghty process, so it's outside of the lock. - This gives the isoc_handler the opportunity to fill more frames - in the mean time. - */ - spin_unlock_irqrestore(&pdev->ptrlock, flags); - ret = pwc_decompress(pdev); - spin_lock_irqsave(&pdev->ptrlock, flags); - - /* We're done with read_buffer, tack it to the end of the empty buffer list */ - if (pdev->empty_frames == NULL) { - pdev->empty_frames = pdev->read_frame; - pdev->empty_frames_tail = pdev->empty_frames; - } - else { - pdev->empty_frames_tail->next = pdev->read_frame; - pdev->empty_frames_tail = pdev->read_frame; - } - pdev->read_frame = NULL; - } - } - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return ret; -} - -/** - \brief Advance pointers of image buffer (after each user request) -*/ -static inline void pwc_next_image(struct pwc_device *pdev) -{ - pdev->image_used[pdev->fill_image] = 0; - pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; -} - - -/* This gets called for the Isochronous pipe (video). This is done in - * interrupt time, so it has to be fast, not crash, and not stall. Neat. - */ -static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) -{ - struct pwc_device *pdev; - int i, fst, flen; - int awake; - struct pwc_frame_buf *fbuf; - unsigned char *fillptr = NULL, *iso_buf = NULL; - - awake = 0; - pdev = (struct pwc_device *)urb->context; - if (pdev == NULL) { - Err("isoc_handler() called with NULL device?!\n"); - return; - } -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("isoc_handler() called with bad magic!\n"); - return; - } -#endif - if (urb->status == -ENOENT || urb->status == -ECONNRESET) { - Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); - return; - } - if (urb->status != -EINPROGRESS && urb->status != 0) { - const char *errmsg; - - errmsg = "Unknown"; - switch(urb->status) { - 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 -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; - } - Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); - /* Give up after a number of contiguous errors on the USB bus. - Appearantly something is wrong so we simulate an unplug event. - */ - if (++pdev->visoc_errors > MAX_ISOC_ERRORS) - { - Info("Too many ISOC errors, bailing out.\n"); - pdev->error_status = EIO; - awake = 1; - wake_up_interruptible(&pdev->frameq); - } - goto handler_end; // ugly, but practical - } - - fbuf = pdev->fill_frame; - if (fbuf == NULL) { - Err("pwc_isoc_handler without valid fill frame.\n"); - awake = 1; - goto handler_end; - } - else { - fillptr = fbuf->data + fbuf->filled; - } - - /* Reset ISOC error counter. We did get here, after all. */ - pdev->visoc_errors = 0; - - /* vsync: 0 = don't copy data - 1 = sync-hunt - 2 = synched - */ - /* Compact data */ - for (i = 0; i < urb->number_of_packets; i++) { - fst = urb->iso_frame_desc[i].status; - flen = urb->iso_frame_desc[i].actual_length; - iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - if (fst == 0) { - if (flen > 0) { /* if valid data... */ - if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ - pdev->vsync = 2; - - /* ...copy data to frame buffer, if possible */ - if (flen + fbuf->filled > pdev->frame_total_size) { - Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); - pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ - pdev->vframes_error++; - } - else { - memmove(fillptr, iso_buf, flen); - fillptr += flen; - } - } - fbuf->filled += flen; - } /* ..flen > 0 */ - - if (flen < pdev->vlast_packet_size) { - /* Shorter packet... We probably have the end of an image-frame; - wake up read() process and let select()/poll() do something. - Decompression is done in user time over there. - */ - if (pdev->vsync == 2) { - /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus - frames on the USB wire after an exposure change. This conditition is - however detected in the cam and a bit is set in the header. - */ - if (pdev->type == 730) { - unsigned char *ptr = (unsigned char *)fbuf->data; - - if (ptr[1] == 1 && ptr[0] & 0x10) { -#if PWC_DEBUG - Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); -#endif - pdev->drop_frames += 2; - pdev->vframes_error++; - } - if ((ptr[0] ^ pdev->vmirror) & 0x01) { - if (ptr[0] & 0x01) - Info("Snapshot button pressed.\n"); - else - Info("Snapshot button released.\n"); - } - if ((ptr[0] ^ pdev->vmirror) & 0x02) { - if (ptr[0] & 0x02) - Info("Image is mirrored.\n"); - else - Info("Image is normal.\n"); - } - pdev->vmirror = ptr[0] & 0x03; - /* Sometimes the trailer of the 730 is still sent as a 4 byte packet - after a short frame; this condition is filtered out specifically. A 4 byte - frame doesn't make sense anyway. - So we get either this sequence: - drop_bit set -> 4 byte frame -> short frame -> good frame - Or this one: - drop_bit set -> short frame -> good frame - So we drop either 3 or 2 frames in all! - */ - if (fbuf->filled == 4) - pdev->drop_frames++; - } - - /* In case we were instructed to drop the frame, do so silently. - The buffer pointers are not updated either (but the counters are reset below). - */ - if (pdev->drop_frames > 0) - pdev->drop_frames--; - else { - /* Check for underflow first */ - if (fbuf->filled < pdev->frame_total_size) { - Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); - pdev->vframes_error++; - } - else { - /* Send only once per EOF */ - awake = 1; /* delay wake_ups */ - - /* Find our next frame to fill. This will always succeed, since we - * nick a frame from either empty or full list, but if we had to - * take it from the full list, it means a frame got dropped. - */ - if (pwc_next_fill_frame(pdev)) { - pdev->vframes_dumped++; - if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { - if (pdev->vframes_dumped < 20) - Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count); - if (pdev->vframes_dumped == 20) - Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count); - } - } - fbuf = pdev->fill_frame; - } - } /* !drop_frames */ - pdev->vframe_count++; - } - fbuf->filled = 0; - fillptr = fbuf->data; - pdev->vsync = 1; - } /* .. flen < last_packet_size */ - pdev->vlast_packet_size = flen; - } /* ..status == 0 */ -#if PWC_DEBUG - /* This is normally not interesting to the user, unless you are really debugging something */ - else { - static int iso_error = 0; - iso_error++; - if (iso_error < 20) - Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); - } -#endif - } - -handler_end: - if (awake) - wake_up_interruptible(&pdev->frameq); - - urb->dev = pdev->udev; - i = usb_submit_urb(urb, GFP_ATOMIC); - if (i != 0) - Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); -} - - -static int pwc_isoc_init(struct pwc_device *pdev) -{ - struct usb_device *udev; - struct urb *urb; - int i, j, ret; - - struct usb_interface *intf; - struct usb_host_interface *idesc = NULL; - - if (pdev == NULL) - return -EFAULT; - if (pdev->iso_init) - return 0; - pdev->vsync = 0; - udev = pdev->udev; - - /* Get the current alternate interface, adjust packet size */ - if (!udev->actconfig) - return -EFAULT; - - intf = usb_ifnum_to_if(udev, 0); - if (intf) - idesc = usb_altnum_to_altsetting(intf, pdev->valternate); - - if (!idesc) - return -EFAULT; - - /* Search video endpoint */ - pdev->vmax_packet_size = -1; - for (i = 0; i < idesc->desc.bNumEndpoints; i++) - if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { - pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize); - break; - } - - if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { - Err("Failed to find packet size for video endpoint in current alternate setting.\n"); - return -ENFILE; /* Odd error, that should be noticeable */ - } - - /* Set alternate interface */ - ret = 0; - Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); - ret = usb_set_interface(pdev->udev, 0, pdev->valternate); - if (ret < 0) - return ret; - - for (i = 0; i < MAX_ISO_BUFS; i++) { - urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); - if (urb == NULL) { - Err("Failed to allocate urb %d\n", i); - ret = -ENOMEM; - break; - } - pdev->sbuf[i].urb = urb; - Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); - } - if (ret) { - /* De-allocate in reverse order */ - while (i >= 0) { - if (pdev->sbuf[i].urb != NULL) - usb_free_urb(pdev->sbuf[i].urb); - pdev->sbuf[i].urb = NULL; - i--; - } - return ret; - } - - /* init URB structure */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - urb = pdev->sbuf[i].urb; - - urb->interval = 1; // devik - urb->dev = udev; - urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = pdev->sbuf[i].data; - urb->transfer_buffer_length = ISO_BUFFER_SIZE; - urb->complete = pwc_isoc_handler; - urb->context = pdev; - urb->start_frame = 0; - urb->number_of_packets = ISO_FRAMES_PER_DESC; - for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; - urb->iso_frame_desc[j].length = pdev->vmax_packet_size; - } - } - - /* link */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); - if (ret) - Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); - else - Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); - } - - /* All is done... */ - pdev->iso_init = 1; - Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); - return 0; -} - -static void pwc_isoc_cleanup(struct pwc_device *pdev) -{ - int i; - - Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); - if (pdev == NULL) - return; - - /* Unlinking ISOC buffers one by one */ - for (i = 0; i < MAX_ISO_BUFS; i++) { - struct urb *urb; - - urb = pdev->sbuf[i].urb; - if (urb != 0) { - if (pdev->iso_init) { - Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); - usb_kill_urb(urb); - } - Trace(TRACE_MEMORY, "Freeing URB\n"); - usb_free_urb(urb); - pdev->sbuf[i].urb = NULL; - } - } - - /* Stop camera, but only if we are sure the camera is still there (unplug - is signalled by EPIPE) - */ - if (pdev->error_status && pdev->error_status != EPIPE) { - Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); - usb_set_interface(pdev->udev, 0, 0); - } - - pdev->iso_init = 0; - Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); -} - -int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) -{ - int ret, start; - - /* Stop isoc stuff */ - pwc_isoc_cleanup(pdev); - /* Reset parameters */ - pwc_reset_buffers(pdev); - /* Try to set video mode... */ - start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); - if (ret) { - Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); - /* That failed... restore old mode (we know that worked) */ - start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - if (start) { - Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); - } - } - if (start == 0) - { - if (pwc_isoc_init(pdev) < 0) - { - Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); - ret = -EAGAIN; /* let's try again, who knows if it works a second time */ - } - } - pdev->drop_frames++; /* try to avoid garbage during switch */ - return ret; /* Return original error code */ -} - - -/***************************************************************************/ -/* Video4Linux functions */ - -static int pwc_video_open(struct inode *inode, struct file *file) -{ - int i; - struct video_device *vdev = video_devdata(file); - struct pwc_device *pdev; - - Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); - - pdev = (struct pwc_device *)vdev->priv; - if (pdev == NULL) - BUG(); - if (pdev->vopen) - return -EBUSY; - - down(&pdev->modlock); - if (!pdev->usb_init) { - Trace(TRACE_OPEN, "Doing first time initialization.\n"); - pdev->usb_init = 1; - - if (pwc_trace & TRACE_OPEN) - { - /* Query sensor type */ - const char *sensor_type = NULL; - int ret; - - ret = pwc_get_cmos_sensor(pdev, &i); - if (ret >= 0) - { - switch(i) { - case 0x00: sensor_type = "Hyundai CMOS sensor"; break; - case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; - case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; - case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; - case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; - case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; - case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; - case 0x40: sensor_type = "UPA 1021 sensor"; break; - case 0x100: sensor_type = "VGA sensor"; break; - case 0x101: sensor_type = "PAL MR sensor"; break; - default: sensor_type = "unknown type of sensor"; break; - } - } - if (sensor_type != NULL) - Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); - } - } - - /* Turn on camera */ - if (power_save) { - i = pwc_camera_power(pdev, 1); - if (i < 0) - Info("Failed to restore power to the camera! (%d)\n", i); - } - /* Set LED on/off time */ - if (pwc_set_leds(pdev, led_on, led_off) < 0) - Info("Failed to set LED on/off time.\n"); - - pwc_construct(pdev); /* set min/max sizes correct */ - - /* So far, so good. Allocate memory. */ - i = pwc_allocate_buffers(pdev); - if (i < 0) { - Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n"); - up(&pdev->modlock); - return i; - } - - /* Reset buffers & parameters */ - pwc_reset_buffers(pdev); - for (i = 0; i < default_mbufs; i++) - pdev->image_used[i] = 0; - pdev->vframe_count = 0; - pdev->vframes_dumped = 0; - pdev->vframes_error = 0; - pdev->visoc_errors = 0; - pdev->error_status = 0; -#if PWC_DEBUG - pdev->sequence = 0; -#endif - pwc_construct(pdev); /* set min/max sizes correct */ - - /* Set some defaults */ - pdev->vsnapshot = 0; - - /* Start iso pipe for video; first try the last used video size - (or the default one); if that fails try QCIF/10 or QSIF/10; - it that fails too, give up. - */ - i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); - if (i) { - Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); - if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750) - i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); - else - i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); - } - if (i) { - Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); - up(&pdev->modlock); - return i; - } - - i = pwc_isoc_init(pdev); - if (i) { - Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); - up(&pdev->modlock); - return i; - } - - pdev->vopen++; - file->private_data = vdev; - up(&pdev->modlock); - Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); - return 0; -} - -/* Note that all cleanup is done in the reverse order as in _open */ -static int pwc_video_close(struct inode *inode, struct file *file) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - int i; - - Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); - - pdev = (struct pwc_device *)vdev->priv; - if (pdev->vopen == 0) - Info("video_close() called on closed device?\n"); - - /* Dump statistics, but only if a reasonable amount of frames were - processed (to prevent endless log-entries in case of snap-shot - programs) - */ - if (pdev->vframe_count > 20) - Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); - - switch (pdev->type) - { - case 675: - case 680: - case 690: - case 720: - case 730: - case 740: - case 750: -/* pwc_dec23_exit(); *//* Timon & Kiara */ - break; - case 645: - case 646: -/* pwc_dec1_exit(); */ - break; - } - - pwc_isoc_cleanup(pdev); - pwc_free_buffers(pdev); - - /* Turn off LEDS and power down camera, but only when not unplugged */ - if (pdev->error_status != EPIPE) { - /* Turn LEDs off */ - if (pwc_set_leds(pdev, 0, 0) < 0) - Info("Failed to set LED on/off time.\n"); - if (power_save) { - i = pwc_camera_power(pdev, 0); - if (i < 0) - Err("Failed to power down camera (%d)\n", i); - } - } - pdev->vopen = 0; - Trace(TRACE_OPEN, "<< video_close()\n"); - return 0; -} - -/* - * FIXME: what about two parallel reads ???? - * ANSWER: Not supported. You can't open the device more than once, - despite what the V4L1 interface says. First, I don't see - the need, second there's no mechanism of alerting the - 2nd/3rd/... process of events like changing image size. - And I don't see the point of blocking that for the - 2nd/3rd/... process. - In multi-threaded environments reading parallel from any - device is tricky anyhow. - */ - -static ssize_t pwc_video_read(struct file *file, char __user * buf, - size_t count, loff_t *ppos) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - int noblock = file->f_flags & O_NONBLOCK; - DECLARE_WAITQUEUE(wait, current); - int bytes_to_read; - - Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count); - if (vdev == NULL) - return -EFAULT; - pdev = vdev->priv; - if (pdev == NULL) - return -EFAULT; - if (pdev->error_status) - return -pdev->error_status; /* Something happened, report what. */ - - /* In case we're doing partial reads, we don't have to wait for a frame */ - if (pdev->image_read_pos == 0) { - /* Do wait queueing according to the (doc)book */ - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - /* Check for unplugged/etc. here */ - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -pdev->error_status ; - } - if (noblock) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -EWOULDBLOCK; - } - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - - /* Decompress and release frame */ - if (pwc_handle_frame(pdev)) - return -EFAULT; - } - - Trace(TRACE_READ, "Copying data to user space.\n"); - if (pdev->vpalette == VIDEO_PALETTE_RAW) - bytes_to_read = pdev->frame_size; - else - bytes_to_read = pdev->view.size; - - /* copy bytes to user space; we allow for partial reads */ - if (count + pdev->image_read_pos > bytes_to_read) - count = bytes_to_read - pdev->image_read_pos; - if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) - return -EFAULT; - pdev->image_read_pos += count; - if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ - pdev->image_read_pos = 0; - pwc_next_image(pdev); - } - return count; -} - -static unsigned int pwc_video_poll(struct file *file, poll_table *wait) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - - if (vdev == NULL) - return -EFAULT; - pdev = vdev->priv; - if (pdev == NULL) - return -EFAULT; - - poll_wait(file, &pdev->frameq, wait); - if (pdev->error_status) - return POLLERR; - if (pdev->full_frames != NULL) /* we have frames waiting */ - return (POLLIN | POLLRDNORM); - - return 0; -} - -static int pwc_video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - DECLARE_WAITQUEUE(wait, current); - - if (vdev == NULL) - return -EFAULT; - pdev = vdev->priv; - if (pdev == NULL) - return -EFAULT; - - switch (cmd) { - /* Query cabapilities */ - case VIDIOCGCAP: - { - struct video_capability *caps = arg; - - strcpy(caps->name, vdev->name); - caps->type = VID_TYPE_CAPTURE; - caps->channels = 1; - caps->audios = 1; - caps->minwidth = pdev->view_min.x; - caps->minheight = pdev->view_min.y; - caps->maxwidth = pdev->view_max.x; - caps->maxheight = pdev->view_max.y; - break; - } - - /* Channel functions (simulate 1 channel) */ - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Webcam"); - return 0; - } - - case VIDIOCSCHAN: - { - /* The spec says the argument is an integer, but - the bttv driver uses a video_channel arg, which - makes sense becasue it also has the norm flag. - */ - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } - - - /* Picture functions; contrast etc. */ - case VIDIOCGPICT: - { - struct video_picture *p = arg; - int val; - - val = pwc_get_brightness(pdev); - if (val >= 0) - p->brightness = val; - else - p->brightness = 0xffff; - val = pwc_get_contrast(pdev); - if (val >= 0) - p->contrast = val; - else - p->contrast = 0xffff; - /* Gamma, Whiteness, what's the difference? :) */ - val = pwc_get_gamma(pdev); - if (val >= 0) - p->whiteness = val; - else - p->whiteness = 0xffff; - val = pwc_get_saturation(pdev); - if (val >= 0) - p->colour = val; - else - p->colour = 0xffff; - p->depth = 24; - p->palette = pdev->vpalette; - p->hue = 0xFFFF; /* N/A */ - break; - } - - case VIDIOCSPICT: - { - struct video_picture *p = arg; - /* - * FIXME: Suppose we are mid read - ANSWER: No problem: the firmware of the camera - can handle brightness/contrast/etc - changes at _any_ time, and the palette - is used exactly once in the uncompress - routine. - */ - pwc_set_brightness(pdev, p->brightness); - pwc_set_contrast(pdev, p->contrast); - pwc_set_gamma(pdev, p->whiteness); - pwc_set_saturation(pdev, p->colour); - if (p->palette && p->palette != pdev->vpalette) { - switch (p->palette) { - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_RAW: - pdev->vpalette = p->palette; - return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - break; - default: - return -EINVAL; - break; - } - } - break; - } - - /* Window/size parameters */ - case VIDIOCGWIN: - { - struct video_window *vw = arg; - - vw->x = 0; - vw->y = 0; - vw->width = pdev->view.x; - vw->height = pdev->view.y; - vw->chromakey = 0; - vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | - (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); - break; - } - - case VIDIOCSWIN: - { - struct video_window *vw = arg; - int fps, snapshot, ret; - - fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; - snapshot = vw->flags & PWC_FPS_SNAPSHOT; - if (fps == 0) - fps = pdev->vframes; - if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) - return 0; - ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); - if (ret) - return ret; - break; - } - - /* We don't have overlay support (yet) */ - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - - memset(vb,0,sizeof(*vb)); - break; - } - - /* mmap() functions */ - case VIDIOCGMBUF: - { - /* Tell the user program how much memory is needed for a mmap() */ - struct video_mbuf *vm = arg; - int i; - - memset(vm, 0, sizeof(*vm)); - vm->size = default_mbufs * pdev->len_per_image; - vm->frames = default_mbufs; /* double buffering should be enough for most applications */ - for (i = 0; i < default_mbufs; i++) - vm->offsets[i] = i * pdev->len_per_image; - break; - } - - case VIDIOCMCAPTURE: - { - /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ - struct video_mmap *vm = arg; - - Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); - if (vm->frame < 0 || vm->frame >= default_mbufs) - return -EINVAL; - - /* xawtv is nasty. It probes the available palettes - by setting a very small image size and trying - various palettes... The driver doesn't support - such small images, so I'm working around it. - */ - if (vm->format) - { - switch (vm->format) - { - case VIDEO_PALETTE_YUV420P: - case VIDEO_PALETTE_RAW: - break; - default: - return -EINVAL; - break; - } - } - - if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && - (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { - int ret; - - Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); - ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - if (ret) - return ret; - } /* ... size mismatch */ - - /* FIXME: should we lock here? */ - if (pdev->image_used[vm->frame]) - return -EBUSY; /* buffer wasn't available. Bummer */ - pdev->image_used[vm->frame] = 1; - - /* Okay, we're done here. In the SYNC call we wait until a - frame comes available, then expand image into the given - buffer. - In contrast to the CPiA cam the Philips cams deliver a - constant stream, almost like a grabber card. Also, - we have separate buffers for the rawdata and the image, - meaning we can nearly always expand into the requested buffer. - */ - Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); - break; - } - - case VIDIOCSYNC: - { - /* The doc says: "Whenever a buffer is used it should - call VIDIOCSYNC to free this frame up and continue." - - The only odd thing about this whole procedure is - that MCAPTURE flags the buffer as "in use", and - SYNC immediately unmarks it, while it isn't - after SYNC that you know that the buffer actually - got filled! So you better not start a CAPTURE in - the same frame immediately (use double buffering). - This is not a problem for this cam, since it has - extra intermediate buffers, but a hardware - grabber card will then overwrite the buffer - you're working on. - */ - int *mbuf = arg; - int ret; - - Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); - - /* bounds check */ - if (*mbuf < 0 || *mbuf >= default_mbufs) - return -EINVAL; - /* check if this buffer was requested anyway */ - if (pdev->image_used[*mbuf] == 0) - return -EINVAL; - - /* Add ourselves to the frame wait-queue. - - FIXME: needs auditing for safety. - QUESTION: In what respect? I think that using the - frameq is safe now. - */ - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -pdev->error_status; - } - - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - - /* The frame is ready. Expand in the image buffer - requested by the user. I don't care if you - mmap() 5 buffers and request data in this order: - buffer 4 2 3 0 1 2 3 0 4 3 1 . . . - Grabber hardware may not be so forgiving. - */ - Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); - pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ - /* Decompress, etc */ - ret = pwc_handle_frame(pdev); - pdev->image_used[*mbuf] = 0; - if (ret) - return -EFAULT; - break; - } - - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; - - strcpy(v->name, "Microphone"); - v->audio = -1; /* unknown audio minor */ - v->flags = 0; - v->mode = VIDEO_SOUND_MONO; - v->volume = 0; - v->bass = 0; - v->treble = 0; - v->balance = 0x8000; - v->step = 1; - break; - } - - case VIDIOCSAUDIO: - { - /* Dummy: nothing can be set */ - break; - } - - case VIDIOCGUNIT: - { - struct video_unit *vu = arg; - - vu->video = pdev->vdev->minor & 0x3F; - vu->audio = -1; /* not known yet */ - vu->vbi = -1; - vu->radio = -1; - vu->teletext = -1; - break; - } - default: - return pwc_ioctl(pdev, cmd, arg); - } /* ..switch */ - return 0; -} - -static int pwc_video_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); -} - - -static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; - - Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); - pdev = vdev->priv; - - vma->vm_flags |= VM_IO; - - pos = (unsigned long)pdev->image_data; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return 0; -} - -/***************************************************************************/ -/* USB functions */ - -/* This function gets called when a new device is plugged in or the usb core - * is loaded. - */ - -static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct pwc_device *pdev = NULL; - int vendor_id, product_id, type_id; - int i, hint; - int features = 0; - int video_nr = -1; /* default: use next available device */ - char serial_number[30], *name; - - /* Check if we can handle this device */ - Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - intf->altsetting->desc.bInterfaceNumber); - - /* the interfaces are probed one by one. We are only interested in the - video interface (0) now. - Interface 1 is the Audio Control, and interface 2 Audio itself. - */ - if (intf->altsetting->desc.bInterfaceNumber > 0) - return -ENODEV; - - vendor_id = le16_to_cpu(udev->descriptor.idVendor); - product_id = le16_to_cpu(udev->descriptor.idProduct); - - if (vendor_id == 0x0471) { - switch (product_id) { - case 0x0302: - Info("Philips PCA645VC USB webcam detected.\n"); - name = "Philips 645 webcam"; - type_id = 645; - break; - case 0x0303: - Info("Philips PCA646VC USB webcam detected.\n"); - name = "Philips 646 webcam"; - type_id = 646; - break; - case 0x0304: - Info("Askey VC010 type 2 USB webcam detected.\n"); - name = "Askey VC010 webcam"; - type_id = 646; - break; - case 0x0307: - Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); - name = "Philips 675 webcam"; - type_id = 675; - break; - case 0x0308: - Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); - name = "Philips 680 webcam"; - type_id = 680; - break; - case 0x030C: - Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); - name = "Philips 690 webcam"; - type_id = 690; - break; - case 0x0310: - Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); - name = "Philips 730 webcam"; - type_id = 730; - break; - case 0x0311: - Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); - name = "Philips 740 webcam"; - type_id = 740; - break; - case 0x0312: - Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); - name = "Philips 750 webcam"; - type_id = 750; - break; - case 0x0313: - Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); - name = "Philips 720K/40 webcam"; - type_id = 720; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x069A) { - switch(product_id) { - case 0x0001: - Info("Askey VC010 type 1 USB webcam detected.\n"); - name = "Askey VC010 webcam"; - type_id = 645; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x046d) { - switch(product_id) { - case 0x08b0: - Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); - name = "Logitech QuickCam Pro 3000"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b1: - Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); - name = "Logitech QuickCam Notebook Pro"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b2: - Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); - name = "Logitech QuickCam Pro 4000"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b3: - Info("Logitech QuickCam Zoom USB webcam detected.\n"); - name = "Logitech QuickCam Zoom"; - type_id = 740; /* CCD sensor */ - break; - case 0x08B4: - Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); - name = "Logitech QuickCam Zoom"; - type_id = 740; /* CCD sensor */ - break; - case 0x08b5: - Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); - name = "Logitech QuickCam Orbit"; - type_id = 740; /* CCD sensor */ - features |= FEATURE_MOTOR_PANTILT; - break; - case 0x08b6: - case 0x08b7: - case 0x08b8: - Info("Logitech QuickCam detected (reserved ID).\n"); - name = "Logitech QuickCam (res.)"; - type_id = 730; /* Assuming CMOS */ - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x055d) { - /* I don't know the difference between the C10 and the C30; - I suppose the difference is the sensor, but both cameras - work equally well with a type_id of 675 - */ - switch(product_id) { - case 0x9000: - Info("Samsung MPC-C10 USB webcam detected.\n"); - name = "Samsung MPC-C10"; - type_id = 675; - break; - case 0x9001: - Info("Samsung MPC-C30 USB webcam detected.\n"); - name = "Samsung MPC-C30"; - type_id = 675; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x041e) { - switch(product_id) { - case 0x400c: - Info("Creative Labs Webcam 5 detected.\n"); - name = "Creative Labs Webcam 5"; - type_id = 730; - break; - case 0x4011: - Info("Creative Labs Webcam Pro Ex detected.\n"); - name = "Creative Labs Webcam Pro Ex"; - type_id = 740; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x04cc) { - switch(product_id) { - case 0x8116: - Info("Sotec Afina Eye USB webcam detected.\n"); - name = "Sotec Afina Eye"; - type_id = 730; - break; - default: - return -ENODEV; - break; - } - } - else if (vendor_id == 0x06be) { - switch(product_id) { - case 0x8116: - /* This is essentially the same cam as the Sotec Afina Eye */ - Info("AME Co. Afina Eye USB webcam detected.\n"); - name = "AME Co. Afina Eye"; - type_id = 750; - break; - default: - return -ENODEV; - break; - } - - } - else if (vendor_id == 0x0d81) { - switch(product_id) { - case 0x1900: - Info("Visionite VCS-UC300 USB webcam detected.\n"); - name = "Visionite VCS-UC300"; - type_id = 740; /* CCD sensor */ - break; - case 0x1910: - Info("Visionite VCS-UM100 USB webcam detected.\n"); - name = "Visionite VCS-UM100"; - type_id = 730; /* CMOS sensor */ - break; - default: - return -ENODEV; - break; - } - } - else - return -ENODEV; /* Not any of the know types; but the list keeps growing. */ - - memset(serial_number, 0, 30); - usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); - Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); - - if (udev->descriptor.bNumConfigurations > 1) - Info("Warning: more than 1 configuration available.\n"); - - /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ - pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL); - if (pdev == NULL) { - Err("Oops, could not allocate memory for pwc_device.\n"); - return -ENOMEM; - } - pdev->type = type_id; - pdev->vsize = default_size; - pdev->vframes = default_fps; - strcpy(pdev->serial, serial_number); - pdev->features = features; - if (vendor_id == 0x046D && product_id == 0x08B5) - { - /* Logitech QuickCam Orbit - The ranges have been determined experimentally; they may differ from cam to cam. - Also, the exact ranges left-right and up-down are different for my cam - */ - pdev->angle_range.pan_min = -7000; - pdev->angle_range.pan_max = 7000; - pdev->angle_range.tilt_min = -3000; - pdev->angle_range.tilt_max = 2500; - } - - init_MUTEX(&pdev->modlock); - spin_lock_init(&pdev->ptrlock); - - pdev->udev = udev; - init_waitqueue_head(&pdev->frameq); - pdev->vcompression = pwc_preferred_compression; - - /* Allocate video_device structure */ - pdev->vdev = video_device_alloc(); - if (pdev->vdev == 0) - { - Err("Err, cannot allocate video_device struture. Failing probe."); - kfree(pdev); - return -ENOMEM; - } - memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - strcpy(pdev->vdev->name, name); - pdev->vdev->owner = THIS_MODULE; - video_set_drvdata(pdev->vdev, pdev); - - pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); - Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); - - /* Now search device_hint[] table for a match, so we can hint a node number. */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) { - if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && - (device_hint[hint].pdev == NULL)) { - /* so far, so good... try serial number */ - if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { - /* match! */ - video_nr = device_hint[hint].device_node; - Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr); - break; - } - } - } - - pdev->vdev->release = video_device_release; - i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); - if (i < 0) { - Err("Failed to register as video device (%d).\n", i); - video_device_release(pdev->vdev); /* Drip... drip... drip... */ - kfree(pdev); /* Oops, no memory leaks please */ - return -EIO; - } - else { - Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); - } - - /* occupy slot */ - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = pdev; - - Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); - usb_set_intfdata (intf, pdev); - return 0; -} - -/* The user janked out the cable... */ -static void usb_pwc_disconnect(struct usb_interface *intf) -{ - struct pwc_device *pdev; - int hint; - - lock_kernel(); - pdev = usb_get_intfdata (intf); - usb_set_intfdata (intf, NULL); - if (pdev == NULL) { - Err("pwc_disconnect() Called without private pointer.\n"); - goto disconnect_out; - } - if (pdev->udev == NULL) { - Err("pwc_disconnect() already called for %p\n", pdev); - goto disconnect_out; - } - if (pdev->udev != interface_to_usbdev(intf)) { - Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); - goto disconnect_out; - } -#ifdef PWC_MAGIC - if (pdev->magic != PWC_MAGIC) { - Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); - goto disconnect_out; - } -#endif - - /* We got unplugged; this is signalled by an EPIPE error code */ - if (pdev->vopen) { - Info("Disconnected while webcam is in use!\n"); - pdev->error_status = EPIPE; - } - - /* Alert waiting processes */ - wake_up_interruptible(&pdev->frameq); - /* Wait until device is closed */ - while (pdev->vopen) - schedule(); - /* Device is now closed, so we can safely unregister it */ - Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); - video_unregister_device(pdev->vdev); - - /* Free memory (don't set pdev to 0 just yet) */ - kfree(pdev); - -disconnect_out: - /* search device_hint[] table if we occupy a slot, by any chance */ - for (hint = 0; hint < MAX_DEV_HINTS; hint++) - if (device_hint[hint].pdev == pdev) - device_hint[hint].pdev = NULL; - - unlock_kernel(); -} - - -/* *grunt* We have to do atoi ourselves :-( */ -static int pwc_atoi(const char *s) -{ - int k = 0; - - k = 0; - while (*s != '\0' && *s >= '0' && *s <= '9') { - k = 10 * k + (*s - '0'); - s++; - } - return k; -} - - -/* - * Initialization code & module stuff - */ - -static char size[10]; -static int fps = 0; -static int fbufs = 0; -static int mbufs = 0; -static int trace = -1; -static int compression = -1; -static int leds[2] = { -1, -1 }; -static char *dev_hint[MAX_DEV_HINTS] = { }; - -module_param_string(size, size, sizeof(size), 0); -MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); -module_param(fps, int, 0000); -MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); -module_param(fbufs, int, 0000); -MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); -module_param(mbufs, int, 0000); -MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); -module_param(trace, int, 0000); -MODULE_PARM_DESC(trace, "For debugging purposes"); -module_param(power_save, bool, 0000); -MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); -module_param(compression, int, 0000); -MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); -module_param_array(leds, int, NULL, 0000); -MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); -module_param_array(dev_hint, charp, NULL, 0000); -MODULE_PARM_DESC(dev_hint, "Device node hints"); - -MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); -MODULE_AUTHOR("Luc Saillard "); -MODULE_LICENSE("GPL"); - -static int __init usb_pwc_init(void) -{ - int i, sz; - char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; - - Info("Philips webcam module version " PWC_VERSION " loaded.\n"); - Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); - Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); - Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); - - if (fps) { - if (fps < 4 || fps > 30) { - Err("Framerate out of bounds (4-30).\n"); - return -EINVAL; - } - default_fps = fps; - Info("Default framerate set to %d.\n", default_fps); - } - - if (size[0]) { - /* string; try matching with array */ - for (sz = 0; sz < PSZ_MAX; sz++) { - if (!strcmp(sizenames[sz], size)) { /* Found! */ - default_size = sz; - break; - } - } - if (sz == PSZ_MAX) { - Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); - return -EINVAL; - } - Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); - } - if (mbufs) { - if (mbufs < 1 || mbufs > MAX_IMAGES) { - Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); - return -EINVAL; - } - default_mbufs = mbufs; - Info("Number of image buffers set to %d.\n", default_mbufs); - } - if (fbufs) { - if (fbufs < 2 || fbufs > MAX_FRAMES) { - Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); - return -EINVAL; - } - default_fbufs = fbufs; - Info("Number of frame buffers set to %d.\n", default_fbufs); - } - if (trace >= 0) { - Info("Trace options: 0x%04x\n", trace); - pwc_trace = trace; - } - if (compression >= 0) { - if (compression > 3) { - Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); - return -EINVAL; - } - pwc_preferred_compression = compression; - Info("Preferred compression set to %d.\n", pwc_preferred_compression); - } - if (power_save) - Info("Enabling power save on open/close.\n"); - if (leds[0] >= 0) - led_on = leds[0]; - if (leds[1] >= 0) - led_off = leds[1]; - - /* Big device node whoopla. Basically, it allows you to assign a - device node (/dev/videoX) to a camera, based on its type - & serial number. The format is [type[.serialnumber]:]node. - - Any camera that isn't matched by these rules gets the next - available free device node. - */ - for (i = 0; i < MAX_DEV_HINTS; i++) { - char *s, *colon, *dot; - - /* This loop also initializes the array */ - device_hint[i].pdev = NULL; - s = dev_hint[i]; - if (s != NULL && *s != '\0') { - device_hint[i].type = -1; /* wildcard */ - strcpy(device_hint[i].serial_number, "*"); - - /* parse string: chop at ':' & '/' */ - colon = dot = s; - while (*colon != '\0' && *colon != ':') - colon++; - while (*dot != '\0' && *dot != '.') - dot++; - /* Few sanity checks */ - if (*dot != '\0' && dot > colon) { - Err("Malformed camera hint: the colon must be after the dot.\n"); - return -EINVAL; - } - - if (*colon == '\0') { - /* No colon */ - if (*dot != '\0') { - Err("Malformed camera hint: no colon + device node given.\n"); - return -EINVAL; - } - else { - /* No type or serial number specified, just a number. */ - device_hint[i].device_node = pwc_atoi(s); - } - } - else { - /* There's a colon, so we have at least a type and a device node */ - device_hint[i].type = pwc_atoi(s); - device_hint[i].device_node = pwc_atoi(colon + 1); - if (*dot != '\0') { - /* There's a serial number as well */ - int k; - - dot++; - k = 0; - while (*dot != ':' && k < 29) { - device_hint[i].serial_number[k++] = *dot; - dot++; - } - device_hint[i].serial_number[k] = '\0'; - } - } -#if PWC_DEBUG - Debug("device_hint[%d]:\n", i); - Debug(" type : %d\n", device_hint[i].type); - Debug(" serial# : %s\n", device_hint[i].serial_number); - Debug(" node : %d\n", device_hint[i].device_node); -#endif - } - else - device_hint[i].type = 0; /* not filled */ - } /* ..for MAX_DEV_HINTS */ - - Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); - return usb_register(&pwc_driver); -} - -static void __exit usb_pwc_exit(void) -{ - Trace(TRACE_MODULE, "Deregistering driver.\n"); - usb_deregister(&pwc_driver); - Info("Philips webcam module removed.\n"); -} - -module_init(usb_pwc_init); -module_exit(usb_pwc_exit); - diff --git a/drivers/usb/media/pwc/pwc-ioctl.h b/drivers/usb/media/pwc/pwc-ioctl.h deleted file mode 100644 index 5f9cb08bc02e..000000000000 --- a/drivers/usb/media/pwc/pwc-ioctl.h +++ /dev/null @@ -1,292 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2004 Nemosoft Unv. - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This is pwc-ioctl.h belonging to PWC 8.12.1 - It contains structures and defines to communicate from user space - directly to the driver. - */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - 2003/12/13 Nemosft Unv. Some modifications to make interfacing to - PWCX easier - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - - - /* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 - - -/* structure for transferring x & y coordinates */ -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - - -/* Used with VIDIOCPWCPROBE */ -struct pwc_probe -{ - char name[32]; - int type; -}; - -struct pwc_serial -{ - char serial[30]; /* String with serial number. Contains terminating 0 */ -}; - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute != 0, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - -/* This is used for out-of-kernel decompression. With it, you can get - all the necessary information to initialize and use the decompressor - routines in standalone applications. - */ -struct pwc_video_command -{ - int type; /* camera type (645, 675, 730, etc.) */ - int release; /* release number */ - - int size; /* one of PSZ_* */ - int alternate; - int command_len; /* length of USB video command */ - unsigned char command_buf[13]; /* Actual USB video command */ - int bandlength; /* >0 = compressed */ - int frame_size; /* Size of one (un)compressed frame */ -}; - -/* Flags for PWCX subroutines. Not all modules honour all flags. */ -#define PWCX_FLAG_PLANAR 0x0001 -#define PWCX_FLAG_BAYER 0x0008 - - -/* IOCTL definitions */ - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - -/* Retrieve serial number of camera */ -#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - - /* Get the USB set-video command; needed for initializing libpwcx */ -#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) -struct pwc_table_init_buffer { - int len; - char *buffer; - -}; -#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) - -#endif diff --git a/drivers/usb/media/pwc/pwc-kiara.c b/drivers/usb/media/pwc/pwc-kiara.c deleted file mode 100644 index c498c68bace1..000000000000 --- a/drivers/usb/media/pwc/pwc-kiara.c +++ /dev/null @@ -1,318 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -/* This tables contains entries for the 730/740/750 (Kiara) camera, with - 4 different qualities (no compression, low, medium, high). - It lists the bandwidth requirements for said mode by its alternate interface - number. An alternate of 0 means that the mode is unavailable. - - There are 6 * 4 * 4 entries: - 6 different resolutions subqcif, qsif, qcif, sif, cif, vga - 6 framerates: 5, 10, 15, 20, 25, 30 - 4 compression modi: none, low, medium, high - - When an uncompressed mode is not available, the next available compressed mode - will be chosen (unless the decompressor is absent). Sometimes there are only - 1 or 2 compressed modes available; in that case entries are duplicated. -*/ - - -#include "pwc-kiara.h" -#include "pwc-uncompress.h" - -const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = -{ - /* SQCIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* QSIF */ - { - /* 5 fps */ - { - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, - }, - /* 10 fps */ - { - {2, 291, 0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, - }, - /* 15 fps */ - { - {3, 437, 0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, - {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, - {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, - {1, 192, 420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, - }, - /* 20 fps */ - { - {4, 589, 0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, - {3, 448, 730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, - {2, 292, 476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, - {1, 192, 312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, - }, - /* 25 fps */ - { - {5, 703, 0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, - {3, 447, 610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, - {2, 292, 398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, - {1, 193, 262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, - }, - /* 30 fps */ - { - {8, 874, 0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, - {5, 704, 730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, - {3, 448, 492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, - {2, 292, 320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, - }, - }, - /* QCIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* SIF */ - { - /* 5 fps */ - { - {4, 582, 0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, - {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, - {2, 291, 960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, - {1, 191, 630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, - }, - /* 10 fps */ - { - {0, }, - {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, - {3, 447, 736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, - {2, 292, 480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, - }, - /* 15 fps */ - { - {0, }, - {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, - {4, 592, 650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, - {3, 448, 492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, - }, - /* 20 fps */ - { - {0, }, - {9, 958, 782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, - {5, 703, 574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, - {3, 446, 364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, - }, - /* 25 fps */ - { - {0, }, - {9, 958, 654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, - {6, 776, 530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, - {4, 592, 404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, - }, - /* 30 fps */ - { - {0, }, - {9, 957, 526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, - {6, 775, 426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, - {4, 590, 324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, - }, - }, - /* CIF */ - { - /* 5 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 10 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 15 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, - /* VGA */ - { - /* 5 fps */ - { - {0, }, - {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, - {4, 592, 976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, - {3, 448, 738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, - }, - /* 10 fps */ - { - {0, }, - {9, 956, 788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, - {6, 776, 640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, - {4, 592, 488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, - }, - /* 15 fps */ - { - {0, }, - {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, - {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, - {8, 895, 492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, -}; - diff --git a/drivers/usb/media/pwc/pwc-kiara.h b/drivers/usb/media/pwc/pwc-kiara.h deleted file mode 100644 index 12929abbb1f0..000000000000 --- a/drivers/usb/media/pwc/pwc-kiara.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* Entries for the Kiara (730/740/750) camera */ - -#ifndef PWC_KIARA_H -#define PWC_KIARA_H - -#include "pwc-ioctl.h" - -struct Kiara_table_entry -{ - char alternate; /* USB alternate interface */ - unsigned short packetsize; /* Normal packet size */ - unsigned short bandlength; /* Bandlength when decompressing */ - unsigned char mode[12]; /* precomputed mode settings for cam */ -}; - -const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4]; -const extern unsigned int KiaraRomTable[8][2][16][8]; - -#endif - - diff --git a/drivers/usb/media/pwc/pwc-misc.c b/drivers/usb/media/pwc/pwc-misc.c deleted file mode 100644 index b7a4bd3524c7..000000000000 --- a/drivers/usb/media/pwc/pwc-misc.c +++ /dev/null @@ -1,140 +0,0 @@ -/* Linux driver for Philips webcam - Various miscellaneous functions and tables. - (C) 1999-2003 Nemosoft Unv. - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include - -#include "pwc.h" - -struct pwc_coord pwc_image_sizes[PSZ_MAX] = -{ - { 128, 96, 0 }, - { 160, 120, 0 }, - { 176, 144, 0 }, - { 320, 240, 0 }, - { 352, 288, 0 }, - { 640, 480, 0 }, -}; - -/* x,y -> PSZ_ */ -int pwc_decode_size(struct pwc_device *pdev, int width, int height) -{ - int i, find; - - /* Make sure we don't go beyond our max size. - NB: we have different limits for RAW and normal modes. In case - you don't have the decompressor loaded or use RAW mode, - the maximum viewable size is smaller. - */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) - { - if (width > pdev->abs_max.x || height > pdev->abs_max.y) - { - Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); - return -1; - } - } - else - { - if (width > pdev->view_max.x || height > pdev->view_max.y) - { - Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n"); - return -1; - } - } - - /* Find the largest size supported by the camera that fits into the - requested size. - */ - find = -1; - for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1 << i)) { - if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) - find = i; - } - } - return find; -} - -/* initialize variables depending on type and decompressor*/ -void pwc_construct(struct pwc_device *pdev) -{ - switch(pdev->type) { - case 645: - case 646: - pdev->view_min.x = 128; - pdev->view_min.y = 96; - pdev->view_max.x = 352; - pdev->view_max.y = 288; - pdev->abs_max.x = 352; - pdev->abs_max.y = 288; - pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; - pdev->vcinterface = 2; - pdev->vendpoint = 4; - pdev->frame_header_size = 0; - pdev->frame_trailer_size = 0; - break; - case 675: - case 680: - case 690: - pdev->view_min.x = 128; - pdev->view_min.y = 96; - /* Anthill bug #38: PWC always reports max size, even without PWCX */ - pdev->view_max.x = 640; - pdev->view_max.y = 480; - pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; - pdev->vcinterface = 3; - pdev->vendpoint = 4; - pdev->frame_header_size = 0; - pdev->frame_trailer_size = 0; - break; - case 720: - case 730: - case 740: - case 750: - pdev->view_min.x = 160; - pdev->view_min.y = 120; - pdev->view_max.x = 640; - pdev->view_max.y = 480; - pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; - pdev->vcinterface = 3; - pdev->vendpoint = 5; - pdev->frame_header_size = TOUCAM_HEADER_SIZE; - pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; - break; - } - Debug("type = %d\n",pdev->type); - pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ - pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; - pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; - /* length of image, in YUV format; always allocate enough memory. */ - pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2; -} - - diff --git a/drivers/usb/media/pwc/pwc-nala.h b/drivers/usb/media/pwc/pwc-nala.h deleted file mode 100644 index e6c5cb69d03b..000000000000 --- a/drivers/usb/media/pwc/pwc-nala.h +++ /dev/null @@ -1,66 +0,0 @@ - /* SQCIF */ - { - {0, 0, {0x04, 0x01, 0x03}}, - {8, 0, {0x05, 0x01, 0x03}}, - {7, 0, {0x08, 0x01, 0x03}}, - {7, 0, {0x0A, 0x01, 0x03}}, - {6, 0, {0x0C, 0x01, 0x03}}, - {5, 0, {0x0F, 0x01, 0x03}}, - {4, 0, {0x14, 0x01, 0x03}}, - {3, 0, {0x18, 0x01, 0x03}}, - }, - /* QSIF */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, - /* QCIF */ - { - {0, 0, {0x04, 0x01, 0x02}}, - {8, 0, {0x05, 0x01, 0x02}}, - {7, 0, {0x08, 0x01, 0x02}}, - {6, 0, {0x0A, 0x01, 0x02}}, - {5, 0, {0x0C, 0x01, 0x02}}, - {4, 0, {0x0F, 0x01, 0x02}}, - {1, 0, {0x14, 0x01, 0x02}}, - {1, 0, {0x18, 0x01, 0x02}}, - }, - /* SIF */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, - /* CIF */ - { - {4, 0, {0x04, 0x01, 0x01}}, - {7, 1, {0x05, 0x03, 0x01}}, - {6, 1, {0x08, 0x03, 0x01}}, - {4, 1, {0x0A, 0x03, 0x01}}, - {3, 1, {0x0C, 0x03, 0x01}}, - {2, 1, {0x0F, 0x03, 0x01}}, - {0}, - {0}, - }, - /* VGA */ - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - }, diff --git a/drivers/usb/media/pwc/pwc-timon.c b/drivers/usb/media/pwc/pwc-timon.c deleted file mode 100644 index dee967173d6c..000000000000 --- a/drivers/usb/media/pwc/pwc-timon.c +++ /dev/null @@ -1,316 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -/* This tables contains entries for the 675/680/690 (Timon) camera, with - 4 different qualities (no compression, low, medium, high). - It lists the bandwidth requirements for said mode by its alternate interface - number. An alternate of 0 means that the mode is unavailable. - - There are 6 * 4 * 4 entries: - 6 different resolutions subqcif, qsif, qcif, sif, cif, vga - 6 framerates: 5, 10, 15, 20, 25, 30 - 4 compression modi: none, low, medium, high - - When an uncompressed mode is not available, the next available compressed mode - will be chosen (unless the decompressor is absent). Sometimes there are only - 1 or 2 compressed modes available; in that case entries are duplicated. -*/ - -#include "pwc-timon.h" - -const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = -{ - /* SQCIF */ - { - /* 5 fps */ - { - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, - }, - /* 10 fps */ - { - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, - }, - /* 15 fps */ - { - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, - }, - /* 20 fps */ - { - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, - }, - /* 25 fps */ - { - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, - }, - /* 30 fps */ - { - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, - }, - }, - /* QSIF */ - { - /* 5 fps */ - { - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, - }, - /* 10 fps */ - { - {2, 291, 0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - }, - /* 15 fps */ - { - {3, 437, 0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, - {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 191, 420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, - }, - /* 20 fps */ - { - {4, 588, 0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, - {3, 447, 730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 192, 312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, - }, - /* 25 fps */ - { - {5, 703, 0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, - {3, 447, 610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 192, 262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {8, 873, 0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, - {5, 704, 774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, - {3, 448, 492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, - {2, 291, 320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, - }, - }, - /* QCIF */ - { - /* 5 fps */ - { - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, - }, - /* 10 fps */ - { - {3, 385, 0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, - {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, - {1, 194, 532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, - }, - /* 15 fps */ - { - {4, 577, 0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, - {3, 447, 818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, - {1, 195, 356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, - }, - /* 20 fps */ - { - {6, 776, 0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, - {4, 591, 804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, - {3, 447, 608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 291, 396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, - }, - /* 25 fps */ - { - {9, 928, 0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, - {5, 703, 800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, - {3, 447, 508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, - {2, 292, 332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 956, 876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, - {4, 592, 542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, - {2, 291, 266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, - }, - }, - /* SIF */ - { - /* 5 fps */ - { - {4, 582, 0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, - {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, - {2, 291, 960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, - {1, 191, 630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, - {3, 447, 736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, - {2, 291, 480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, - {4, 591, 650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, - {3, 448, 492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {9, 958, 782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, - {5, 703, 574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, - {3, 446, 364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, - }, - /* 25 fps */ - { - {0, }, - {9, 958, 654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, - {6, 776, 530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, - {4, 592, 404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 957, 526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, - {6, 775, 426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, - {4, 590, 324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, - }, - }, - /* CIF */ - { - /* 5 fps */ - { - {6, 771, 0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, - {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, - {2, 291, 800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, - {1, 193, 528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, - {4, 591, 812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, - {2, 291, 400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 956, 876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, - {5, 703, 644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, - {3, 448, 410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {9, 956, 650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, - {6, 776, 528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, - {4, 591, 402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, - }, - /* 25 fps */ - { - {0, }, - {9, 956, 544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, - {7, 840, 478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, - {5, 703, 400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, - }, - /* 30 fps */ - { - {0, }, - {9, 956, 438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, - {7, 838, 384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, - {6, 773, 354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, - }, - }, - /* VGA */ - { - /* 5 fps */ - { - {0, }, - {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, - {4, 592, 976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, - {3, 448, 738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, - }, - /* 10 fps */ - { - {0, }, - {9, 956, 788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, - {6, 776, 640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, - {4, 592, 488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, - }, - /* 15 fps */ - { - {0, }, - {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, - {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, - {8, 895, 492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, - }, - /* 20 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 25 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - /* 30 fps */ - { - {0, }, - {0, }, - {0, }, - {0, }, - }, - }, -}; - diff --git a/drivers/usb/media/pwc/pwc-timon.h b/drivers/usb/media/pwc/pwc-timon.h deleted file mode 100644 index a86b3782a081..000000000000 --- a/drivers/usb/media/pwc/pwc-timon.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Linux driver for Philips webcam - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - - -/* This tables contains entries for the 675/680/690 (Timon) camera, with - 4 different qualities (no compression, low, medium, high). - It lists the bandwidth requirements for said mode by its alternate interface - number. An alternate of 0 means that the mode is unavailable. - - There are 6 * 4 * 4 entries: - 6 different resolutions subqcif, qsif, qcif, sif, cif, vga - 6 framerates: 5, 10, 15, 20, 25, 30 - 4 compression modi: none, low, medium, high - - When an uncompressed mode is not available, the next available compressed mode - will be chosen (unless the decompressor is absent). Sometimes there are only - 1 or 2 compressed modes available; in that case entries are duplicated. -*/ - -#ifndef PWC_TIMON_H -#define PWC_TIMON_H - -#include "pwc-ioctl.h" - -struct Timon_table_entry -{ - char alternate; /* USB alternate interface */ - unsigned short packetsize; /* Normal packet size */ - unsigned short bandlength; /* Bandlength when decompressing */ - unsigned char mode[13]; /* precomputed mode settings for cam */ -}; - -const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4]; -const extern unsigned int TimonRomTable [16][2][16][8]; - - -#endif - - diff --git a/drivers/usb/media/pwc/pwc-uncompress.c b/drivers/usb/media/pwc/pwc-uncompress.c deleted file mode 100644 index ef4204eab6c4..000000000000 --- a/drivers/usb/media/pwc/pwc-uncompress.c +++ /dev/null @@ -1,146 +0,0 @@ -/* Linux driver for Philips webcam - Decompression frontend. - (C) 1999-2003 Nemosoft Unv. - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include - -#include "pwc.h" -#include "pwc-uncompress.h" - -int pwc_decompress(struct pwc_device *pdev) -{ - struct pwc_frame_buf *fbuf; - int n, line, col, stride; - void *yuv, *image; - u16 *src; - u16 *dsty, *dstu, *dstv; - - if (pdev == NULL) - return -EFAULT; -#if defined(__KERNEL__) && defined(PWC_MAGIC) - if (pdev->magic != PWC_MAGIC) { - Err("pwc_decompress(): magic failed.\n"); - return -EFAULT; - } -#endif - - fbuf = pdev->read_frame; - if (fbuf == NULL) - return -EFAULT; - image = pdev->image_ptr[pdev->fill_image]; - if (!image) - return -EFAULT; - - yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ - - /* Raw format; that's easy... */ - if (pdev->vpalette == VIDEO_PALETTE_RAW) - { - memcpy(image, yuv, pdev->frame_size); - return 0; - } - - if (pdev->vbandlength == 0) { - /* Uncompressed mode. We copy the data into the output buffer, - using the viewport size (which may be larger than the image - size). Unfortunately we have to do a bit of byte stuffing - to get the desired output format/size. - */ - /* - * We do some byte shuffling here to go from the - * native format to YUV420P. - */ - src = (u16 *)yuv; - n = pdev->view.x * pdev->view.y; - - /* offset in Y plane */ - stride = pdev->view.x * pdev->offset.y + pdev->offset.x; - dsty = (u16 *)(image + stride); - - /* offsets in U/V planes */ - stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; - dstu = (u16 *)(image + n + stride); - dstv = (u16 *)(image + n + n / 4 + stride); - - /* increment after each line */ - stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ - - for (line = 0; line < pdev->image.y; line++) { - for (col = 0; col < pdev->image.x; col += 4) { - *dsty++ = *src++; - *dsty++ = *src++; - if (line & 1) - *dstv++ = *src++; - else - *dstu++ = *src++; - } - dsty += stride; - if (line & 1) - dstv += (stride >> 1); - else - dstu += (stride >> 1); - } - } - else { - /* Compressed; the decompressor routines will write the data - in planar format immediately. - */ - int flags; - - flags = PWCX_FLAG_PLANAR; - if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) - { - printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n"); - flags |= PWCX_FLAG_BAYER; - return -ENXIO; /* No such device or address: missing decompressor */ - } - -#if 0 - switch (pdev->type) - { - case 675: - case 680: - case 690: - case 720: - case 730: - case 740: - case 750: - pwc_dec23_decompress(&pdev->image, &pdev->view, - &pdev->offset, yuv, image, flags, - pdev->decompress_data, pdev->vbandlength); - break; - case 645: - case 646: - /* TODO & FIXME */ - return -ENXIO; /* Missing decompressor */ - break; - } -#endif - } - return 0; -} - - diff --git a/drivers/usb/media/pwc/pwc-uncompress.h b/drivers/usb/media/pwc/pwc-uncompress.h deleted file mode 100644 index d3b9250e4ed3..000000000000 --- a/drivers/usb/media/pwc/pwc-uncompress.h +++ /dev/null @@ -1,41 +0,0 @@ -/* (C) 1999-2003 Nemosoft Unv. - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This file is the bridge between the kernel module and the plugin; it - describes the structures and datatypes used in both modules. Any - significant change should be reflected by increasing the - pwc_decompressor_version major number. - */ -#ifndef PWC_UNCOMPRESS_H -#define PWC_UNCOMPRESS_H - -#include - -#include "pwc-ioctl.h" - -/* from pwc-dec.h */ -#define PWCX_FLAG_PLANAR 0x0001 -/* */ - -#endif diff --git a/drivers/usb/media/pwc/pwc.h b/drivers/usb/media/pwc/pwc.h deleted file mode 100644 index 6dd76bb3dff1..000000000000 --- a/drivers/usb/media/pwc/pwc.h +++ /dev/null @@ -1,272 +0,0 @@ -/* (C) 1999-2003 Nemosoft Unv. - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef PWC_H -#define PWC_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pwc-uncompress.h" -#include "pwc-ioctl.h" - -/* Defines and structures for the Philips webcam */ -/* Used for checking memory corruption/pointer validation */ -#define PWC_MAGIC 0x89DC10ABUL -#undef PWC_MAGIC - -/* Turn some debugging options on/off */ -#define PWC_DEBUG 0 - -/* Trace certain actions in the driver */ -#define TRACE_MODULE 0x0001 -#define TRACE_PROBE 0x0002 -#define TRACE_OPEN 0x0004 -#define TRACE_READ 0x0008 -#define TRACE_MEMORY 0x0010 -#define TRACE_FLOW 0x0020 -#define TRACE_SIZE 0x0040 -#define TRACE_PWCX 0x0080 -#define TRACE_SEQUENCE 0x1000 - -#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) -#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) -#define Info(A...) printk(KERN_INFO PWC_NAME " " A) -#define Err(A...) printk(KERN_ERR PWC_NAME " " A) - - -/* Defines for ToUCam cameras */ -#define TOUCAM_HEADER_SIZE 8 -#define TOUCAM_TRAILER_SIZE 4 - -#define FEATURE_MOTOR_PANTILT 0x0001 - -/* Version block */ -#define PWC_MAJOR 9 -#define PWC_MINOR 0 -#define PWC_VERSION "9.0.2-unofficial" -#define PWC_NAME "pwc" - -/* Turn certain features on/off */ -#define PWC_INT_PIPE 0 - -/* Ignore errors in the first N frames, to allow for startup delays */ -#define FRAME_LOWMARK 5 - -/* Size and number of buffers for the ISO pipe. */ -#define MAX_ISO_BUFS 2 -#define ISO_FRAMES_PER_DESC 10 -#define ISO_MAX_FRAME_SIZE 960 -#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) - -/* Frame buffers: contains compressed or uncompressed video data. */ -#define MAX_FRAMES 5 -/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ -#define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) - -/* Absolute maximum number of buffers available for mmap() */ -#define MAX_IMAGES 10 - -/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ -struct pwc_iso_buf -{ - void *data; - int length; - int read; - struct urb *urb; -}; - -/* intermediate buffers with raw data from the USB cam */ -struct pwc_frame_buf -{ - void *data; - volatile int filled; /* number of bytes filled */ - struct pwc_frame_buf *next; /* list */ -#if PWC_DEBUG - int sequence; /* Sequence number */ -#endif -}; - -struct pwc_device -{ - struct video_device *vdev; -#ifdef PWC_MAGIC - int magic; -#endif - /* Pointer to our usb_device */ - struct usb_device *udev; - - int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ - int release; /* release number */ - int features; /* feature bits */ - char serial[30]; /* serial number (string) */ - int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ - int usb_init; /* set when the cam has been initialized over USB */ - - /*** Video data ***/ - int vopen; /* flag */ - int vendpoint; /* video isoc endpoint */ - int vcinterface; /* video control interface */ - int valternate; /* alternate interface needed */ - int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ - int vpalette; /* palette: 420P, RAW or RGBBAYER */ - int vframe_count; /* received frames */ - int vframes_dumped; /* counter for dumped frames */ - int vframes_error; /* frames received in error */ - int vmax_packet_size; /* USB maxpacket size */ - int vlast_packet_size; /* for frame synchronisation */ - int visoc_errors; /* number of contiguous ISOC errors */ - int vcompression; /* desired compression factor */ - int vbandlength; /* compressed band length; 0 is uncompressed */ - char vsnapshot; /* snapshot mode */ - char vsync; /* used by isoc handler */ - char vmirror; /* for ToUCaM series */ - - int cmd_len; - unsigned char cmd_buf[13]; - - /* The image acquisition requires 3 to 4 steps: - 1. data is gathered in short packets from the USB controller - 2. data is synchronized and packed into a frame buffer - 3a. in case data is compressed, decompress it directly into image buffer - 3b. in case data is uncompressed, copy into image buffer with viewport - 4. data is transferred to the user process - - Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... - We have in effect a back-to-back-double-buffer system. - */ - /* 1: isoc */ - struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; - char iso_init; - - /* 2: frame */ - struct pwc_frame_buf *fbuf; /* all frames */ - struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ - struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ - struct pwc_frame_buf *fill_frame; /* frame currently being filled */ - struct pwc_frame_buf *read_frame; /* frame currently read by user process */ - int frame_header_size, frame_trailer_size; - int frame_size; - int frame_total_size; /* including header & trailer */ - int drop_frames; -#if PWC_DEBUG - int sequence; /* Debugging aid */ -#endif - - /* 3: decompression */ - struct pwc_decompressor *decompressor; /* function block with decompression routines */ - void *decompress_data; /* private data for decompression engine */ - - /* 4: image */ - /* We have an 'image' and a 'view', where 'image' is the fixed-size image - as delivered by the camera, and 'view' is the size requested by the - program. The camera image is centered in this viewport, laced with - a gray or black border. view_min <= image <= view <= view_max; - */ - int image_mask; /* bitmask of supported sizes */ - struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ - struct pwc_coord abs_max; /* maximum supported size with compression */ - struct pwc_coord image, view; /* image and viewport size */ - struct pwc_coord offset; /* offset within the viewport */ - - void *image_data; /* total buffer, which is subdivided into ... */ - void *image_ptr[MAX_IMAGES]; /* ...several images... */ - int fill_image; /* ...which are rotated. */ - int len_per_image; /* length per image */ - int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ - int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ - - struct semaphore modlock; /* to prevent races in video_open(), etc */ - spinlock_t ptrlock; /* for manipulating the buffer pointers */ - - /*** motorized pan/tilt feature */ - struct pwc_mpt_range angle_range; - int pan_angle; /* in degrees * 100 */ - int tilt_angle; /* absolute angle; 0,0 is home position */ - - /*** Misc. data ***/ - wait_queue_head_t frameq; /* When waiting for a frame to finish... */ -#if PWC_INT_PIPE - void *usb_int_handler; /* for the interrupt endpoint */ -#endif -}; - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Global variable */ -extern int pwc_trace; - -/** functions in pwc-if.c */ -int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); - -/** Functions in pwc-misc.c */ -/* sizes in pixels */ -extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; - -int pwc_decode_size(struct pwc_device *pdev, int width, int height); -void pwc_construct(struct pwc_device *pdev); - -/** Functions in pwc-ctrl.c */ -/* Request a certain video mode. Returns < 0 if not possible */ -extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); - -/* Various controls; should be obvious. Value 0..65535, or < 0 on error */ -extern int pwc_get_brightness(struct pwc_device *pdev); -extern int pwc_set_brightness(struct pwc_device *pdev, int value); -extern int pwc_get_contrast(struct pwc_device *pdev); -extern int pwc_set_contrast(struct pwc_device *pdev, int value); -extern int pwc_get_gamma(struct pwc_device *pdev); -extern int pwc_set_gamma(struct pwc_device *pdev, int value); -extern int pwc_get_saturation(struct pwc_device *pdev); -extern int pwc_set_saturation(struct pwc_device *pdev, int value); -extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); -extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); - -/* Power down or up the camera; not supported by all models */ -extern int pwc_camera_power(struct pwc_device *pdev, int power); - -/* Private ioctl()s; see pwc-ioctl.h */ -extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); - - -/** pwc-uncompress.c */ -/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ -extern int pwc_decompress(struct pwc_device *pdev); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c deleted file mode 100644 index f03ea7f89596..000000000000 --- a/drivers/usb/media/se401.c +++ /dev/null @@ -1,1435 +0,0 @@ -/* - * Endpoints (formerly known as AOX) se401 USB Camera Driver - * - * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) - * - * Still somewhat based on the Linux ov511 driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on - * their chipset available and supporting me while writing this driver. - * - Jeroen Vreeken - */ - -static const char version[] = "0.24"; - -#include -#include -#include -#include -#include -#include -#include -#include "se401.h" - -static int flickerless=0; -static int video_nr = -1; - -static struct usb_device_id device_table [] = { - { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */ - { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */ - { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */ - { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */ - { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */ - { } -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -MODULE_AUTHOR("Jeroen Vreeken "); -MODULE_DESCRIPTION("SE401 USB Camera Driver"); -MODULE_LICENSE("GPL"); -module_param(flickerless, int, 0); -MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)"); -module_param(video_nr, int, 0); - -static struct usb_driver se401_driver; - - -/********************************************************************** - * - * Memory management - * - **********************************************************************/ -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - - - -/**************************************************************************** - * - * se401 register read/write functions - * - ***************************************************************************/ - -static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req, - unsigned short value, unsigned char *cp, int size) -{ - return usb_control_msg ( - se401->dev, - set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0), - req, - (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - 0, - cp, - size, - 1000 - ); -} - -static int se401_set_feature(struct usb_se401 *se401, unsigned short selector, - unsigned short param) -{ - /* specs say that the selector (address) should go in the value field - and the param in index, but in the logs of the windows driver they do - this the other way around... - */ - return usb_control_msg ( - se401->dev, - usb_sndctrlpipe(se401->dev, 0), - SE401_REQ_SET_EXT_FEATURE, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - param, - selector, - NULL, - 0, - 1000 - ); -} - -static unsigned short se401_get_feature(struct usb_se401 *se401, - unsigned short selector) -{ - /* For 'set' the selecetor should be in index, not sure if the spec is - wrong here to.... - */ - unsigned char cp[2]; - usb_control_msg ( - se401->dev, - usb_rcvctrlpipe(se401->dev, 0), - SE401_REQ_GET_EXT_FEATURE, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, - selector, - cp, - 2, - 1000 - ); - return cp[0]+cp[1]*256; -} - -/**************************************************************************** - * - * Camera control - * - ***************************************************************************/ - - -static int se401_send_pict(struct usb_se401 *se401) -{ - se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */ - se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */ - se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */ - se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */ - se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */ - se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */ - se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */ - - return 0; -} - -static void se401_set_exposure(struct usb_se401 *se401, int brightness) -{ - int integration=brightness<<5; - - if (flickerless==50) { - integration=integration-integration%106667; - } - if (flickerless==60) { - integration=integration-integration%88889; - } - se401->brightness=integration>>5; - se401->expose_h=(integration>>16)&0xff; - se401->expose_m=(integration>>8)&0xff; - se401->expose_l=integration&0xff; -} - -static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p) -{ - p->brightness=se401->brightness; - if (se401->enhance) { - p->whiteness=32768; - } else { - p->whiteness=0; - } - p->colour=65535; - p->contrast=65535; - p->hue=se401->rgain<<10; - p->palette=se401->palette; - p->depth=3; /* rgb24 */ - return 0; -} - - -static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p) -{ - if (p->palette != VIDEO_PALETTE_RGB24) - return 1; - se401->palette=p->palette; - if (p->hue!=se401->hue) { - se401->rgain= p->hue>>10; - se401->bgain= 0x40-(p->hue>>10); - se401->hue=p->hue; - } - if (p->brightness!=se401->brightness) { - se401_set_exposure(se401, p->brightness); - } - if (p->whiteness>=32768) { - se401->enhance=1; - } else { - se401->enhance=0; - } - se401_send_pict(se401); - se401_send_pict(se401); - return 0; -} - -/* - Hyundai have some really nice docs about this and other sensor related - stuff on their homepage: www.hei.co.kr -*/ -static void se401_auto_resetlevel(struct usb_se401 *se401) -{ - unsigned int ahrc, alrc; - int oldreset=se401->resetlevel; - - /* For some reason this normally read-only register doesn't get reset - to zero after reading them just once... - */ - se401_get_feature(se401, HV7131_REG_HIREFNOH); - se401_get_feature(se401, HV7131_REG_HIREFNOL); - se401_get_feature(se401, HV7131_REG_LOREFNOH); - se401_get_feature(se401, HV7131_REG_LOREFNOL); - ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + - se401_get_feature(se401, HV7131_REG_HIREFNOL); - alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) + - se401_get_feature(se401, HV7131_REG_LOREFNOL); - - /* Not an exact science, but it seems to work pretty well... */ - if (alrc > 10) { - while (alrc>=10 && se401->resetlevel < 63) { - se401->resetlevel++; - alrc /=2; - } - } else if (ahrc > 20) { - while (ahrc>=20 && se401->resetlevel > 0) { - se401->resetlevel--; - ahrc /=2; - } - } - if (se401->resetlevel!=oldreset) - se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel); - - return; -} - -/* irq handler for snapshot button */ -static void se401_button_irq(struct urb *urb, struct pt_regs *regs) -{ - struct usb_se401 *se401 = urb->context; - int status; - - if (!se401->dev) { - info("ohoh: device vapourished"); - return; - } - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); - goto exit; - } - - if (urb->actual_length >=2) { - if (se401->button) - se401->buttonpressed=1; - } -exit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) - err ("%s - usb_submit_urb failed with result %d", - __FUNCTION__, status); -} - -static void se401_video_irq(struct urb *urb, struct pt_regs *regs) -{ - struct usb_se401 *se401 = urb->context; - int length = urb->actual_length; - - /* ohoh... */ - if (!se401->streaming) - return; - - if (!se401->dev) { - info ("ohoh: device vapourished"); - return; - } - - /* 0 sized packets happen if we are to fast, but sometimes the camera - keeps sending them forever... - */ - if (length && !urb->status) { - se401->nullpackets=0; - switch(se401->scratch[se401->scratch_next].state) { - case BUFFER_READY: - case BUFFER_BUSY: { - se401->dropped++; - break; - } - case BUFFER_UNUSED: { - memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length); - se401->scratch[se401->scratch_next].state=BUFFER_READY; - se401->scratch[se401->scratch_next].offset=se401->bayeroffset; - se401->scratch[se401->scratch_next].length=length; - if (waitqueue_active(&se401->wq)) { - wake_up_interruptible(&se401->wq); - } - se401->scratch_overflow=0; - se401->scratch_next++; - if (se401->scratch_next>=SE401_NUMSCRATCH) - se401->scratch_next=0; - break; - } - } - se401->bayeroffset+=length; - if (se401->bayeroffset>=se401->cheight*se401->cwidth) { - se401->bayeroffset=0; - } - } else { - se401->nullpackets++; - if (se401->nullpackets > SE401_MAX_NULLPACKETS) { - if (waitqueue_active(&se401->wq)) { - wake_up_interruptible(&se401->wq); - } - } - } - - /* Resubmit urb for new data */ - urb->status=0; - urb->dev=se401->dev; - if(usb_submit_urb(urb, GFP_KERNEL)) - info("urb burned down"); - return; -} - -static void se401_send_size(struct usb_se401 *se401, int width, int height) -{ - int i=0; - int mode=0x03; /* No compression */ - int sendheight=height; - int sendwidth=width; - - /* JangGu compression can only be used with the camera supported sizes, - but bayer seems to work with any size that fits on the sensor. - We check if we can use compression with the current size with either - 4 or 16 times subcapturing, if not we use uncompressed bayer data - but this will result in cutouts of the maximum size.... - */ - while (isizes && !(se401->width[i]==width && se401->height[i]==height)) - i++; - while (isizes) { - if (se401->width[i]==width*2 && se401->height[i]==height*2) { - sendheight=se401->height[i]; - sendwidth=se401->width[i]; - mode=0x40; - } - if (se401->width[i]==width*4 && se401->height[i]==height*4) { - sendheight=se401->height[i]; - sendwidth=se401->width[i]; - mode=0x42; - } - i++; - } - - se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0); - se401_set_feature(se401, SE401_OPERATINGMODE, mode); - - if (mode==0x03) { - se401->format=FMT_BAYER; - } else { - se401->format=FMT_JANGGU; - } - - return; -} - -/* - In this function se401_send_pict is called several times, - for some reason (depending on the state of the sensor and the phase of - the moon :) doing this only in either place doesn't always work... -*/ -static int se401_start_stream(struct usb_se401 *se401) -{ - struct urb *urb; - int err=0, i; - se401->streaming=1; - - se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); - - /* Set picture settings */ - se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */ - se401_send_pict(se401); - - se401_send_size(se401, se401->cwidth, se401->cheight); - - se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0); - - /* Do some memory allocation */ - for (i=0; iframe[i].data=se401->fbuf + i * se401->maxframesize; - se401->frame[i].curpix=0; - } - for (i=0; isbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); - } - - se401->bayeroffset=0; - se401->scratch_next=0; - se401->scratch_use=0; - se401->scratch_overflow=0; - for (i=0; iscratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); - se401->scratch[i].state=BUFFER_UNUSED; - } - - for (i=0; idev, - usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), - se401->sbuf[i].data, SE401_PACKETSIZE, - se401_video_irq, - se401); - - se401->urb[i]=urb; - - err=usb_submit_urb(se401->urb[i], GFP_KERNEL); - if(err) - err("urb burned down"); - } - - se401->framecount=0; - - return 0; -} - -static int se401_stop_stream(struct usb_se401 *se401) -{ - int i; - - if (!se401->streaming || !se401->dev) - return 1; - - se401->streaming=0; - - se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0); - - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); - - for (i=0; iurb[i]) { - usb_kill_urb(se401->urb[i]); - usb_free_urb(se401->urb[i]); - se401->urb[i]=NULL; - kfree(se401->sbuf[i].data); - } - for (i=0; iscratch[i].data); - se401->scratch[i].data=NULL; - } - - return 0; -} - -static int se401_set_size(struct usb_se401 *se401, int width, int height) -{ - int wasstreaming=se401->streaming; - /* Check to see if we need to change */ - if (se401->cwidth==width && se401->cheight==height) - return 0; - - /* Check for a valid mode */ - if (!width || !height) - return 1; - if ((width & 1) || (height & 1)) - return 1; - if (width>se401->width[se401->sizes-1]) - return 1; - if (height>se401->height[se401->sizes-1]) - return 1; - - /* Stop a current stream and start it again at the new size */ - if (wasstreaming) - se401_stop_stream(se401); - se401->cwidth=width; - se401->cheight=height; - if (wasstreaming) - se401_start_stream(se401); - return 0; -} - - -/**************************************************************************** - * - * Video Decoding - * - ***************************************************************************/ - -/* - This shouldn't really be done in a v4l driver.... - But it does make the image look a lot more usable. - Basically it lifts the dark pixels more than the light pixels. -*/ -static inline void enhance_picture(unsigned char *frame, int len) -{ - while (len--) { - *frame=(((*frame^255)*(*frame^255))/255)^255; - frame++; - } -} - -static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data) -{ - struct se401_frame *frame=&se401->frame[se401->curframe]; - int linelength=se401->cwidth*3; - - if (frame->curlinepix >= linelength) { - frame->curlinepix=0; - frame->curline+=linelength; - } - - /* First three are absolute, all others relative. - * Format is rgb from right to left (mirrorred image), - * we flip it to get bgr from left to right. */ - if (frame->curlinepix < 3) { - *(frame->curline-frame->curlinepix)=1+data*4; - } else { - *(frame->curline-frame->curlinepix)= - *(frame->curline-frame->curlinepix+3)+data*4; - } - frame->curlinepix++; -} - -static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength) -{ - int pos=0; - int vlc_cod=0; - int vlc_size=0; - int vlc_data=0; - int bit_cur; - int bit; - data+=4; - while (pos < packetlength) { - bit_cur=8; - while (bit_cur && bit_exp) { - bit=((*data)>>(bit_cur-1))&1; - if (!vlc_cod) { - if (bit) { - vlc_size++; - } else { - if (!vlc_size) { - decode_JangGu_integrate(se401, 0); - } else { - vlc_cod=2; - vlc_data=0; - } - } - } else { - if (vlc_cod==2) { - if (!bit) - vlc_data = -(1<data; - int len=buffer->length; - int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size; - int datapos=0; - - /* New image? */ - if (!se401->frame[se401->curframe].curpix) { - se401->frame[se401->curframe].curlinepix=0; - se401->frame[se401->curframe].curline= - se401->frame[se401->curframe].data+ - se401->cwidth*3-1; - if (se401->frame[se401->curframe].grabstate==FRAME_READY) - se401->frame[se401->curframe].grabstate=FRAME_GRABBING; - se401->vlcdatapos=0; - } - while (datapos < len) { - size=1024-se401->vlcdatapos; - if (size+datapos > len) - size=len-datapos; - memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size); - se401->vlcdatapos+=size; - packetlength=0; - if (se401->vlcdatapos >= 4) { - bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8); - pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8); - frameinfo=se401->vlcdata[0]&0xc0; - packetlength=((bit_exp+47)>>4)<<1; - if (packetlength > 1024) { - se401->vlcdatapos=0; - datapos=len; - packetlength=0; - se401->error++; - se401->frame[se401->curframe].curpix=0; - } - } - if (packetlength && se401->vlcdatapos >= packetlength) { - decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength); - se401->frame[se401->curframe].curpix+=pix_exp*3; - datapos+=size-(se401->vlcdatapos-packetlength); - se401->vlcdatapos=0; - if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) { - if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) { - if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) { - se401->frame[se401->curframe].grabstate=FRAME_DONE; - se401->framecount++; - se401->readcount++; - } - if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) { - se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1); - } - } else { - se401->error++; - } - se401->frame[se401->curframe].curpix=0; - datapos=len; - } - } else { - datapos+=size; - } - } -} - -static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer) -{ - unsigned char *data=buffer->data; - int len=buffer->length; - int offset=buffer->offset; - int datasize=se401->cwidth*se401->cheight; - struct se401_frame *frame=&se401->frame[se401->curframe]; - - unsigned char *framedata=frame->data, *curline, *nextline; - int width=se401->cwidth; - int blineoffset=0, bline; - int linelength=width*3, i; - - - if (frame->curpix==0) { - if (frame->grabstate==FRAME_READY) { - frame->grabstate=FRAME_GRABBING; - } - frame->curline=framedata+linelength; - frame->curlinepix=0; - } - - if (offset!=frame->curpix) { - /* Regard frame as lost :( */ - frame->curpix=0; - se401->error++; - return; - } - - /* Check if we have to much data */ - if (frame->curpix+len > datasize) { - len=datasize-frame->curpix; - } - if (se401->cheight%4) - blineoffset=1; - bline=frame->curpix/se401->cwidth+blineoffset; - - curline=frame->curline; - nextline=curline+linelength; - if (nextline >= framedata+datasize*3) - nextline=curline; - while (len) { - if (frame->curlinepix>=width) { - frame->curlinepix-=width; - bline=frame->curpix/width+blineoffset; - curline+=linelength*2; - nextline+=linelength*2; - if (curline >= framedata+datasize*3) { - frame->curlinepix++; - curline-=3; - nextline-=3; - len--; - data++; - frame->curpix++; - } - if (nextline >= framedata+datasize*3) - nextline=curline; - } - if ((bline&1)) { - if ((frame->curlinepix&1)) { - *(curline+2)=*data; - *(curline-1)=*data; - *(nextline+2)=*data; - *(nextline-1)=*data; - } else { - *(curline+1)= - (*(curline+1)+*data)/2; - *(curline-2)= - (*(curline-2)+*data)/2; - *(nextline+1)=*data; - *(nextline-2)=*data; - } - } else { - if ((frame->curlinepix&1)) { - *(curline+1)= - (*(curline+1)+*data)/2; - *(curline-2)= - (*(curline-2)+*data)/2; - *(nextline+1)=*data; - *(nextline-2)=*data; - } else { - *curline=*data; - *(curline-3)=*data; - *nextline=*data; - *(nextline-3)=*data; - } - } - frame->curlinepix++; - curline-=3; - nextline-=3; - len--; - data++; - frame->curpix++; - } - frame->curline=curline; - - if (frame->curpix>=datasize) { - /* Fix the top line */ - framedata+=linelength; - for (i=0; icheight; i++) { - *framedata=*(framedata+3); - *(framedata+1)=*(framedata+4); - *(framedata+2)=*(framedata+5); - framedata+=linelength; - } - frame->curpix=0; - frame->grabstate=FRAME_DONE; - se401->framecount++; - se401->readcount++; - if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) { - se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1); - } - } -} - -static int se401_newframe(struct usb_se401 *se401, int framenr) -{ - DECLARE_WAITQUEUE(wait, current); - int errors=0; - - while (se401->streaming && - (se401->frame[framenr].grabstate==FRAME_READY || - se401->frame[framenr].grabstate==FRAME_GRABBING) ) { - if(!se401->frame[framenr].curpix) { - errors++; - } - wait_interruptible( - se401->scratch[se401->scratch_use].state!=BUFFER_READY, - &se401->wq, - &wait - ); - if (se401->nullpackets > SE401_MAX_NULLPACKETS) { - se401->nullpackets=0; - info("to many null length packets, restarting capture"); - se401_stop_stream(se401); - se401_start_stream(se401); - } else { - if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) { - se401->frame[framenr].grabstate=FRAME_ERROR; - return -EIO; - } - se401->scratch[se401->scratch_use].state=BUFFER_BUSY; - if (se401->format==FMT_JANGGU) { - decode_JangGu(se401, &se401->scratch[se401->scratch_use]); - } else { - decode_bayer(se401, &se401->scratch[se401->scratch_use]); - } - se401->scratch[se401->scratch_use].state=BUFFER_UNUSED; - se401->scratch_use++; - if (se401->scratch_use>=SE401_NUMSCRATCH) - se401->scratch_use=0; - if (errors > SE401_MAX_ERRORS) { - errors=0; - info("to much errors, restarting capture"); - se401_stop_stream(se401); - se401_start_stream(se401); - } - } - } - - if (se401->frame[framenr].grabstate==FRAME_DONE) - if (se401->enhance) - enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3); - return 0; -} - -static void usb_se401_remove_disconnected (struct usb_se401 *se401) -{ - int i; - - se401->dev = NULL; - - for (i=0; iurb[i]) { - usb_kill_urb(se401->urb[i]); - usb_free_urb(se401->urb[i]); - se401->urb[i] = NULL; - kfree(se401->sbuf[i].data); - } - for (i=0; iscratch[i].data); - } - if (se401->inturb) { - usb_kill_urb(se401->inturb); - usb_free_urb(se401->inturb); - } - info("%s disconnected", se401->camera_name); - - /* Free the memory */ - kfree(se401->width); - kfree(se401->height); - kfree(se401); -} - - - -/**************************************************************************** - * - * Video4Linux - * - ***************************************************************************/ - - -static int se401_open(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_se401 *se401 = (struct usb_se401 *)dev; - int err = 0; - - if (se401->user) - return -EBUSY; - se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES); - if (se401->fbuf) - file->private_data = dev; - else - err = -ENOMEM; - se401->user = !err; - - return err; -} - -static int se401_close(struct inode *inode, struct file *file) -{ - struct video_device *dev = file->private_data; - struct usb_se401 *se401 = (struct usb_se401 *)dev; - int i; - - rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES); - if (se401->removed) { - usb_se401_remove_disconnected(se401); - info("device unregistered"); - } else { - for (i=0; iframe[i].grabstate=FRAME_UNUSED; - if (se401->streaming) - se401_stop_stream(se401); - se401->user=0; - } - file->private_data = NULL; - return 0; -} - -static int se401_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *vdev = file->private_data; - struct usb_se401 *se401 = (struct usb_se401 *)vdev; - - if (!se401->dev) - return -EIO; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - strcpy(b->name, se401->camera_name); - b->type = VID_TYPE_CAPTURE; - b->channels = 1; - b->audios = 0; - b->maxwidth = se401->width[se401->sizes-1]; - b->maxheight = se401->height[se401->sizes-1]; - b->minwidth = se401->width[0]; - b->minheight = se401->height[0]; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - - se401_get_pict(se401, p); - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - - if (se401_set_pict(se401, p)) - return -EINVAL; - return 0; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (se401_set_size(se401, vw->width, vw->height)) - return -EINVAL; - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - - vw->x = 0; /* FIXME */ - vw->y = 0; - vw->chromakey = 0; - vw->flags = 0; - vw->clipcount = 0; - vw->width = se401->cwidth; - vw->height = se401->cheight; - return 0; - } - case VIDIOCGMBUF: - { - struct video_mbuf *vm = arg; - int i; - - memset(vm, 0, sizeof(*vm)); - vm->size = SE401_NUMFRAMES * se401->maxframesize; - vm->frames = SE401_NUMFRAMES; - for (i=0; ioffsets[i] = se401->maxframesize * i; - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - - if (vm->format != VIDEO_PALETTE_RGB24) - return -EINVAL; - if (vm->frame >= SE401_NUMFRAMES) - return -EINVAL; - if (se401->frame[vm->frame].grabstate != FRAME_UNUSED) - return -EBUSY; - - /* Is this according to the v4l spec??? */ - if (se401_set_size(se401, vm->width, vm->height)) - return -EINVAL; - se401->frame[vm->frame].grabstate=FRAME_READY; - - if (!se401->streaming) - se401_start_stream(se401); - - /* Set the picture properties */ - if (se401->framecount==0) - se401_send_pict(se401); - /* Calibrate the reset level after a few frames. */ - if (se401->framecount%20==1) - se401_auto_resetlevel(se401); - - return 0; - } - case VIDIOCSYNC: - { - int *frame = arg; - int ret=0; - - if(*frame <0 || *frame >= SE401_NUMFRAMES) - return -EINVAL; - - ret=se401_newframe(se401, *frame); - se401->frame[*frame].grabstate=FRAME_UNUSED; - return ret; - } - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - - memset(vb, 0, sizeof(*vb)); - return 0; - } - case VIDIOCKEY: - return 0; - case VIDIOCCAPTURE: - return -EINVAL; - case VIDIOCSFBUF: - return -EINVAL; - case VIDIOCGTUNER: - case VIDIOCSTUNER: - return -EINVAL; - case VIDIOCGFREQ: - case VIDIOCSFREQ: - return -EINVAL; - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - default: - return -ENOIOCTLCMD; - } /* end switch */ - - return 0; -} - -static int se401_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, se401_do_ioctl); -} - -static ssize_t se401_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - int realcount=count, ret=0; - struct video_device *dev = file->private_data; - struct usb_se401 *se401 = (struct usb_se401 *)dev; - - - if (se401->dev == NULL) - return -EIO; - if (realcount > se401->cwidth*se401->cheight*3) - realcount=se401->cwidth*se401->cheight*3; - - /* Shouldn't happen: */ - if (se401->frame[0].grabstate==FRAME_GRABBING) - return -EBUSY; - se401->frame[0].grabstate=FRAME_READY; - se401->frame[1].grabstate=FRAME_UNUSED; - se401->curframe=0; - - if (!se401->streaming) - se401_start_stream(se401); - - /* Set the picture properties */ - if (se401->framecount==0) - se401_send_pict(se401); - /* Calibrate the reset level after a few frames. */ - if (se401->framecount%20==1) - se401_auto_resetlevel(se401); - - ret=se401_newframe(se401, 0); - - se401->frame[0].grabstate=FRAME_UNUSED; - if (ret) - return ret; - if (copy_to_user(buf, se401->frame[0].data, realcount)) - return -EFAULT; - - return realcount; -} - -static int se401_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *dev = file->private_data; - struct usb_se401 *se401 = (struct usb_se401 *)dev; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; - - mutex_lock(&se401->lock); - - if (se401->dev == NULL) { - mutex_unlock(&se401->lock); - return -EIO; - } - if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { - mutex_unlock(&se401->lock); - return -EINVAL; - } - pos = (unsigned long)se401->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&se401->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - mutex_unlock(&se401->lock); - - return 0; -} - -static struct file_operations se401_fops = { - .owner = THIS_MODULE, - .open = se401_open, - .release = se401_close, - .read = se401_read, - .mmap = se401_mmap, - .ioctl = se401_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; -static struct video_device se401_template = { - .owner = THIS_MODULE, - .name = "se401 USB camera", - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_SE401, - .fops = &se401_fops, -}; - - - -/***************************/ -static int se401_init(struct usb_se401 *se401, int button) -{ - int i=0, rc; - unsigned char cp[0x40]; - char temp[200]; - - /* led on */ - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); - - /* get camera descriptor */ - rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp)); - if (cp[1]!=0x41) { - err("Wrong descriptor type"); - return 1; - } - sprintf (temp, "ExtraFeatures: %d", cp[3]); - - se401->sizes=cp[4]+cp[5]*256; - se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); - if (!se401->width) - return 1; - se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); - if (!se401->height) { - kfree(se401->width); - return 1; - } - for (i=0; isizes; i++) { - se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256; - se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256; - } - sprintf (temp, "%s Sizes:", temp); - for (i=0; isizes; i++) { - sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]); - } - info("%s", temp); - se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3; - - rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); - se401->cwidth=cp[0]+cp[1]*256; - rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp)); - se401->cheight=cp[0]+cp[1]*256; - - if (!cp[2] && SE401_FORMAT_BAYER) { - err("Bayer format not supported!"); - return 1; - } - /* set output mode (BAYER) */ - se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0); - - rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp)); - se401->brightness=cp[0]+cp[1]*256; - /* some default values */ - se401->resetlevel=0x2d; - se401->rgain=0x20; - se401->ggain=0x20; - se401->bgain=0x20; - se401_set_exposure(se401, 20000); - se401->palette=VIDEO_PALETTE_RGB24; - se401->enhance=1; - se401->dropped=0; - se401->error=0; - se401->framecount=0; - se401->readcount=0; - - /* Start interrupt transfers for snapshot button */ - if (button) { - se401->inturb=usb_alloc_urb(0, GFP_KERNEL); - if (!se401->inturb) { - info("Allocation of inturb failed"); - return 1; - } - usb_fill_int_urb(se401->inturb, se401->dev, - usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT), - &se401->button, sizeof(se401->button), - se401_button_irq, - se401, - 8 - ); - if (usb_submit_urb(se401->inturb, GFP_KERNEL)) { - info("int urb burned down"); - return 1; - } - } else - se401->inturb=NULL; - - /* Flash the led */ - se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); - - return 0; -} - -static int se401_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_interface_descriptor *interface; - struct usb_se401 *se401; - char *camera_name=NULL; - int button=1; - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - interface = &intf->cur_altsetting->desc; - - /* Is it an se401? */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 && - le16_to_cpu(dev->descriptor.idProduct) == 0x0004) { - camera_name="Endpoints/Aox SE401"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 && - le16_to_cpu(dev->descriptor.idProduct) == 0x030b) { - camera_name="Philips PCVC665K"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5001) { - camera_name="Kensington VideoCAM 67014"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5002) { - camera_name="Kensington VideoCAM 6701(5/7)"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5003) { - camera_name="Kensington VideoCAM 67016"; - button=0; - } else - return -ENODEV; - - /* Checking vendor/product should be enough, but what the hell */ - if (interface->bInterfaceClass != 0x00) - return -ENODEV; - if (interface->bInterfaceSubClass != 0x00) - return -ENODEV; - - /* We found one */ - info("SE401 camera found: %s", camera_name); - - if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) { - err("couldn't kmalloc se401 struct"); - return -ENOMEM; - } - - se401->dev = dev; - se401->iface = interface->bInterfaceNumber; - se401->camera_name = camera_name; - - info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255); - - if (se401_init(se401, button)) { - kfree(se401); - return -EIO; - } - - memcpy(&se401->vdev, &se401_template, sizeof(se401_template)); - memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name)); - init_waitqueue_head(&se401->wq); - mutex_init(&se401->lock); - wmb(); - - if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { - kfree(se401); - err("video_register_device failed"); - return -EIO; - } - info("registered new video device: video%d", se401->vdev.minor); - - usb_set_intfdata (intf, se401); - return 0; -} - -static void se401_disconnect(struct usb_interface *intf) -{ - struct usb_se401 *se401 = usb_get_intfdata (intf); - - usb_set_intfdata (intf, NULL); - if (se401) { - video_unregister_device(&se401->vdev); - if (!se401->user){ - usb_se401_remove_disconnected(se401); - } else { - se401->frame[0].grabstate = FRAME_ERROR; - se401->frame[0].grabstate = FRAME_ERROR; - - se401->streaming = 0; - - wake_up_interruptible(&se401->wq); - se401->removed = 1; - } - } -} - -static struct usb_driver se401_driver = { - .name = "se401", - .id_table = device_table, - .probe = se401_probe, - .disconnect = se401_disconnect, -}; - - - -/**************************************************************************** - * - * Module routines - * - ***************************************************************************/ - -static int __init usb_se401_init(void) -{ - info("SE401 usb camera driver version %s registering", version); - if (flickerless) - if (flickerless!=50 && flickerless!=60) { - info("Invallid flickerless value, use 0, 50 or 60."); - return -1; - } - return usb_register(&se401_driver); -} - -static void __exit usb_se401_exit(void) -{ - usb_deregister(&se401_driver); - info("SE401 driver deregistered"); -} - -module_init(usb_se401_init); -module_exit(usb_se401_exit); diff --git a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h deleted file mode 100644 index e88a40d4c86a..000000000000 --- a/drivers/usb/media/se401.h +++ /dev/null @@ -1,234 +0,0 @@ - -#ifndef __LINUX_se401_H -#define __LINUX_se401_H - -#include -#include -#include -#include - -#define se401_DEBUG /* Turn on debug messages */ - -#ifdef se401_DEBUG -# define PDEBUG(level, fmt, args...) \ -if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args) -#else -# define PDEBUG(level, fmt, args...) do {} while(0) -#endif - -/* An almost drop-in replacement for sleep_on_interruptible */ -#define wait_interruptible(test, queue, wait) \ -{ \ - add_wait_queue(queue, wait); \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (test) \ - schedule(); \ - remove_wait_queue(queue, wait); \ - set_current_state(TASK_RUNNING); \ - if (signal_pending(current)) \ - break; \ -} - -#define SE401_REQ_GET_CAMERA_DESCRIPTOR 0x06 -#define SE401_REQ_START_CONTINUOUS_CAPTURE 0x41 -#define SE401_REQ_STOP_CONTINUOUS_CAPTURE 0x42 -#define SE401_REQ_CAPTURE_FRAME 0x43 -#define SE401_REQ_GET_BRT 0x44 -#define SE401_REQ_SET_BRT 0x45 -#define SE401_REQ_GET_WIDTH 0x4c -#define SE401_REQ_SET_WIDTH 0x4d -#define SE401_REQ_GET_HEIGHT 0x4e -#define SE401_REQ_SET_HEIGHT 0x4f -#define SE401_REQ_GET_OUTPUT_MODE 0x50 -#define SE401_REQ_SET_OUTPUT_MODE 0x51 -#define SE401_REQ_GET_EXT_FEATURE 0x52 -#define SE401_REQ_SET_EXT_FEATURE 0x53 -#define SE401_REQ_CAMERA_POWER 0x56 -#define SE401_REQ_LED_CONTROL 0x57 -#define SE401_REQ_BIOS 0xff - -#define SE401_BIOS_READ 0x07 - -#define SE401_FORMAT_BAYER 0x40 - -/* Hyundai hv7131b registers - 7121 and 7141 should be the same (haven't really checked...) */ -/* Mode registers: */ -#define HV7131_REG_MODE_A 0x00 -#define HV7131_REG_MODE_B 0x01 -#define HV7131_REG_MODE_C 0x02 -/* Frame registers: */ -#define HV7131_REG_FRSU 0x10 -#define HV7131_REG_FRSL 0x11 -#define HV7131_REG_FCSU 0x12 -#define HV7131_REG_FCSL 0x13 -#define HV7131_REG_FWHU 0x14 -#define HV7131_REG_FWHL 0x15 -#define HV7131_REG_FWWU 0x16 -#define HV7131_REG_FWWL 0x17 -/* Timing registers: */ -#define HV7131_REG_THBU 0x20 -#define HV7131_REG_THBL 0x21 -#define HV7131_REG_TVBU 0x22 -#define HV7131_REG_TVBL 0x23 -#define HV7131_REG_TITU 0x25 -#define HV7131_REG_TITM 0x26 -#define HV7131_REG_TITL 0x27 -#define HV7131_REG_TMCD 0x28 -/* Adjust Registers: */ -#define HV7131_REG_ARLV 0x30 -#define HV7131_REG_ARCG 0x31 -#define HV7131_REG_AGCG 0x32 -#define HV7131_REG_ABCG 0x33 -#define HV7131_REG_APBV 0x34 -#define HV7131_REG_ASLP 0x54 -/* Offset Registers: */ -#define HV7131_REG_OFSR 0x50 -#define HV7131_REG_OFSG 0x51 -#define HV7131_REG_OFSB 0x52 -/* REset level statistics registers: */ -#define HV7131_REG_LOREFNOH 0x57 -#define HV7131_REG_LOREFNOL 0x58 -#define HV7131_REG_HIREFNOH 0x59 -#define HV7131_REG_HIREFNOL 0x5a - -/* se401 registers */ -#define SE401_OPERATINGMODE 0x2000 - - -/* size of usb transfers */ -#define SE401_PACKETSIZE 4096 -/* number of queued bulk transfers to use, should be about 8 */ -#define SE401_NUMSBUF 1 -/* read the usb specs for this one :) */ -#define SE401_VIDEO_ENDPOINT 1 -#define SE401_BUTTON_ENDPOINT 2 -/* number of frames supported by the v4l part */ -#define SE401_NUMFRAMES 2 -/* scratch buffers for passing data to the decoders */ -#define SE401_NUMSCRATCH 32 -/* maximum amount of data in a JangGu packet */ -#define SE401_VLCDATALEN 1024 -/* number of nul sized packets to receive before kicking the camera */ -#define SE401_MAX_NULLPACKETS 4000 -/* number of decoding errors before kicking the camera */ -#define SE401_MAX_ERRORS 200 - -struct usb_device; - -struct se401_sbuf { - unsigned char *data; -}; - -enum { - FRAME_UNUSED, /* Unused (no MCAPTURE) */ - FRAME_READY, /* Ready to start grabbing */ - FRAME_GRABBING, /* In the process of being grabbed into */ - FRAME_DONE, /* Finished grabbing, but not been synced yet */ - FRAME_ERROR, /* Something bad happened while processing */ -}; - -enum { - FMT_BAYER, - FMT_JANGGU, -}; - -enum { - BUFFER_UNUSED, - BUFFER_READY, - BUFFER_BUSY, - BUFFER_DONE, -}; - -struct se401_scratch { - unsigned char *data; - volatile int state; - int offset; - int length; -}; - -struct se401_frame { - unsigned char *data; /* Frame buffer */ - - volatile int grabstate; /* State of grabbing */ - - unsigned char *curline; - int curlinepix; - int curpix; -}; - -struct usb_se401 { - struct video_device vdev; - - /* Device structure */ - struct usb_device *dev; - - unsigned char iface; - - char *camera_name; - - int change; - int brightness; - int hue; - int rgain; - int ggain; - int bgain; - int expose_h; - int expose_m; - int expose_l; - int resetlevel; - - int enhance; - - int format; - int sizes; - int *width; - int *height; - int cwidth; /* current width */ - int cheight; /* current height */ - int palette; - int maxframesize; - int cframesize; /* current framesize */ - - struct mutex lock; - int user; /* user count for exclusive use */ - int removed; /* device disconnected */ - - int streaming; /* Are we streaming video? */ - - char *fbuf; /* Videodev buffer area */ - - struct urb *urb[SE401_NUMSBUF]; - struct urb *inturb; - - int button; - int buttonpressed; - - int curframe; /* Current receiving frame */ - struct se401_frame frame[SE401_NUMFRAMES]; - int readcount; - int framecount; - int error; - int dropped; - - int scratch_next; - int scratch_use; - int scratch_overflow; - struct se401_scratch scratch[SE401_NUMSCRATCH]; - - /* Decoder specific data: */ - unsigned char vlcdata[SE401_VLCDATALEN]; - int vlcdatapos; - int bayeroffset; - - struct se401_sbuf sbuf[SE401_NUMSBUF]; - - wait_queue_head_t wq; /* Processes waiting */ - - int nullpackets; -}; - - - -#endif - diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h deleted file mode 100644 index 1d70a62b9f23..000000000000 --- a/drivers/usb/media/sn9c102.h +++ /dev/null @@ -1,218 +0,0 @@ -/*************************************************************************** - * V4L2 driver for SN9C10x PC Camera Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_H_ -#define _SN9C102_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sn9c102_sensor.h" - -/*****************************************************************************/ - -#define SN9C102_DEBUG -#define SN9C102_DEBUG_LEVEL 2 -#define SN9C102_MAX_DEVICES 64 -#define SN9C102_PRESERVE_IMGSCALE 0 -#define SN9C102_FORCE_MUNMAP 0 -#define SN9C102_MAX_FRAMES 32 -#define SN9C102_URBS 2 -#define SN9C102_ISO_PACKETS 7 -#define SN9C102_ALTERNATE_SETTING 8 -#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS) -#define SN9C102_CTRL_TIMEOUT 300 -#define SN9C102_FRAME_TIMEOUT 2 - -/*****************************************************************************/ - -enum sn9c102_bridge { - BRIDGE_SN9C101 = 0x01, - BRIDGE_SN9C102 = 0x02, - BRIDGE_SN9C103 = 0x04, -}; - -SN9C102_ID_TABLE -SN9C102_SENSOR_TABLE - -enum sn9c102_frame_state { - F_UNUSED, - F_QUEUED, - F_GRABBING, - F_DONE, - F_ERROR, -}; - -struct sn9c102_frame_t { - void* bufmem; - struct v4l2_buffer buf; - enum sn9c102_frame_state state; - struct list_head frame; - unsigned long vma_use_count; -}; - -enum sn9c102_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -enum sn9c102_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum sn9c102_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON, -}; - -typedef char sn9c103_sof_header_t[18]; -typedef char sn9c102_sof_header_t[12]; -typedef char sn9c102_eof_header_t[4]; - -struct sn9c102_sysfs_attr { - u8 reg, i2c_reg; - sn9c103_sof_header_t frame_header; -}; - -struct sn9c102_module_param { - u8 force_munmap; - u16 frame_timeout; -}; - -static DEFINE_MUTEX(sn9c102_sysfs_lock); -static DECLARE_RWSEM(sn9c102_disconnect); - -struct sn9c102_device { - struct video_device* v4ldev; - - enum sn9c102_bridge bridge; - struct sn9c102_sensor sensor; - - struct usb_device* usbdev; - struct urb* urb[SN9C102_URBS]; - void* transfer_buffer[SN9C102_URBS]; - u8* control_buffer; - - struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES]; - struct list_head inqueue, outqueue; - u32 frame_count, nbuffers, nreadbuffers; - - enum sn9c102_io_method io; - enum sn9c102_stream_state stream; - - struct v4l2_jpegcompression compression; - - struct sn9c102_sysfs_attr sysfs; - sn9c103_sof_header_t sof_header; - u16 reg[63]; - - struct sn9c102_module_param module_param; - - enum sn9c102_dev_state state; - u8 users; - - struct mutex dev_mutex, fileop_mutex; - spinlock_t queue_lock; - wait_queue_head_t open, wait_frame, wait_stream; -}; - -/*****************************************************************************/ - -struct sn9c102_device* -sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id) -{ - if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id)) - return cam; - - return NULL; -} - - -void -sn9c102_attach_sensor(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor) -{ - memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor)); -} - -/*****************************************************************************/ - -#undef DBG -#undef KDBG -#ifdef SN9C102_DEBUG -# define DBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1) \ - dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) == 2) \ - dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args); \ - } \ -} while (0) -# define V4LDBG(level, name, cmd) \ -do { \ - if (debug >= (level)) \ - v4l_print_ioctl(name, cmd); \ -} while (0) -# define KDBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1 || (level) == 2) \ - pr_info("sn9c102: " fmt "\n", ## args); \ - else if ((level) == 3) \ - pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ - __LINE__ , ## args); \ - } \ -} while (0) -#else -# define DBG(level, fmt, args...) do {;} while(0) -# define V4LDBG(level, name, cmd) do {;} while(0) -# define KDBG(level, fmt, args...) do {;} while(0) -#endif - -#undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args) - -#undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ - -#endif /* _SN9C102_H_ */ diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c deleted file mode 100644 index 4c6cc6395723..000000000000 --- a/drivers/usb/media/sn9c102_core.c +++ /dev/null @@ -1,2919 +0,0 @@ -/*************************************************************************** - * V4L2 driver for SN9C10x PC Camera Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sn9c102.h" - -/*****************************************************************************/ - -#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers" -#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" -#define SN9C102_AUTHOR_EMAIL "" -#define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.27" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 27) - -/*****************************************************************************/ - -MODULE_DEVICE_TABLE(usb, sn9c102_id_table); - -MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); -MODULE_DESCRIPTION(SN9C102_MODULE_NAME); -MODULE_VERSION(SN9C102_MODULE_VERSION); -MODULE_LICENSE(SN9C102_MODULE_LICENSE); - -static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1}; -module_param_array(video_nr, short, NULL, 0444); -MODULE_PARM_DESC(video_nr, - "\n<-1|n[,...]> Specify V4L2 minor mode number." - "\n -1 = use next available (default)" - "\n n = use minor number n (integer >= 0)" - "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES) - " cameras this way." - "\nFor example:" - "\nvideo_nr=-1,2,-1 would assign minor number 2 to" - "\nthe second camera and use auto for the first" - "\none and for every other camera." - "\n"); - -static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = - SN9C102_FORCE_MUNMAP}; -module_param_array(force_munmap, bool, NULL, 0444); -MODULE_PARM_DESC(force_munmap, - "\n<0|1[,...]> Force the application to unmap previously" - "\nmapped buffer memory before calling any VIDIOC_S_CROP or" - "\nVIDIOC_S_FMT ioctl's. Not all the applications support" - "\nthis feature. This parameter is specific for each" - "\ndetected camera." - "\n 0 = do not force memory unmapping" - "\n 1 = force memory unmapping (save memory)" - "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." - "\n"); - -static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] = - SN9C102_FRAME_TIMEOUT}; -module_param_array(frame_timeout, uint, NULL, 0644); -MODULE_PARM_DESC(frame_timeout, - "\n Timeout for a video frame in seconds." - "\nThis parameter is specific for each detected camera." - "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"." - "\n"); - -#ifdef SN9C102_DEBUG -static unsigned short debug = SN9C102_DEBUG_LEVEL; -module_param(debug, ushort, 0644); -MODULE_PARM_DESC(debug, - "\n Debugging information level, from 0 to 3:" - "\n0 = none (use carefully)" - "\n1 = critical errors" - "\n2 = significant informations" - "\n3 = more verbose messages" - "\nLevel 3 is useful for testing only, when only " - "one device is used." - "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." - "\n"); -#endif - -/*****************************************************************************/ - -static sn9c102_sof_header_t sn9c102_sof_header[] = { - {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00}, - {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01}, -}; - -static sn9c103_sof_header_t sn9c103_sof_header[] = { - {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20}, -}; - -static sn9c102_eof_header_t sn9c102_eof_header[] = { - {0x00, 0x00, 0x00, 0x00}, - {0x40, 0x00, 0x00, 0x00}, - {0x80, 0x00, 0x00, 0x00}, - {0xc0, 0x00, 0x00, 0x00}, -}; - -/*****************************************************************************/ - -static u32 -sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, - enum sn9c102_io_method io) -{ - struct v4l2_pix_format* p = &(cam->sensor.pix_format); - struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); - const size_t imagesize = cam->module_param.force_munmap || - io == IO_READ ? - (p->width * p->height * p->priv) / 8 : - (r->width * r->height * p->priv) / 8; - void* buff = NULL; - u32 i; - - if (count > SN9C102_MAX_FRAMES) - count = SN9C102_MAX_FRAMES; - - cam->nbuffers = count; - while (cam->nbuffers > 0) { - if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) - break; - cam->nbuffers--; - } - - for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.index = i; - cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.length = imagesize; - cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cam->frame[i].buf.sequence = 0; - cam->frame[i].buf.field = V4L2_FIELD_NONE; - cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; - cam->frame[i].buf.flags = 0; - } - - return cam->nbuffers; -} - - -static void sn9c102_release_buffers(struct sn9c102_device* cam) -{ - if (cam->nbuffers) { - vfree(cam->frame[0].bufmem); - cam->nbuffers = 0; - } - cam->frame_current = NULL; -} - - -static void sn9c102_empty_framequeues(struct sn9c102_device* cam) -{ - u32 i; - - INIT_LIST_HEAD(&cam->inqueue); - INIT_LIST_HEAD(&cam->outqueue); - - for (i = 0; i < SN9C102_MAX_FRAMES; i++) { - cam->frame[i].state = F_UNUSED; - cam->frame[i].buf.bytesused = 0; - } -} - - -static void sn9c102_requeue_outqueue(struct sn9c102_device* cam) -{ - struct sn9c102_frame_t *i; - - list_for_each_entry(i, &cam->outqueue, frame) { - i->state = F_QUEUED; - list_add(&i->frame, &cam->inqueue); - } - - INIT_LIST_HEAD(&cam->outqueue); -} - - -static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) -{ - unsigned long lock_flags; - u32 i; - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].state == F_UNUSED) { - cam->frame[i].state = F_QUEUED; - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[i].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - } -} - -/*****************************************************************************/ - -int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index) -{ - struct usb_device* udev = cam->usbdev; - int i, res; - - if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg)) - return -1; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - index, 0, buff, sizeof(buff), - SN9C102_CTRL_TIMEOUT*sizeof(buff)); - if (res < 0) { - DBG(3, "Failed to write registers (index 0x%02X, error %d)", - index, res); - return -1; - } - - for (i = 0; i < sizeof(buff); i++) - cam->reg[index+i] = buff[i]; - - return 0; -} - - -int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - if (index >= ARRAY_SIZE(cam->reg)) - return -1; - - *buff = value; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); - if (res < 0) { - DBG(3, "Failed to write a register (value 0x%02X, index " - "0x%02X, error %d)", value, index, res); - return -1; - } - - cam->reg[index] = value; - - return 0; -} - - -/* NOTE: reading some registers always returns 0 */ -static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - index, 0, buff, 1, SN9C102_CTRL_TIMEOUT); - if (res < 0) - DBG(3, "Failed to read a register (index 0x%02X, error %d)", - index, res); - - return (res >= 0) ? (int)(*buff) : -1; -} - - -int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index) -{ - if (index >= ARRAY_SIZE(cam->reg)) - return -1; - - return cam->reg[index]; -} - - -static int -sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor) -{ - int i, r; - - for (i = 1; i <= 5; i++) { - r = sn9c102_read_reg(cam, 0x08); - if (r < 0) - return -EIO; - if (r & 0x04) - return 0; - if (sensor->frequency & SN9C102_I2C_400KHZ) - udelay(5*16); - else - udelay(16*16); - } - return -EBUSY; -} - - -static int -sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor) -{ - int r; - r = sn9c102_read_reg(cam, 0x08); - return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0; -} - - -static int -sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor) -{ - int r; - r = sn9c102_read_reg(cam, 0x08); - return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0; -} - - -int -sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor, u8 data0, u8 data1, - u8 n, u8 buffer[]) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - /* Write cycle */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10; - data[1] = data0; /* I2C slave id */ - data[2] = data1; /* address */ - data[7] = 0x10; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - - /* Read cycle - n bytes */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | - (n << 4) | 0x02; - data[1] = data0; - data[7] = 0x10; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - - /* The first read byte will be placed in data[4] */ - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_detect_read_error(cam, sensor); - - PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1, - data[4]); - - if (err) { - DBG(3, "I2C read failed for %s image sensor", sensor->name); - return -1; - } - - if (buffer) - memcpy(buffer, data, sizeof(buffer)); - - return (int)data[4]; -} - - -int -sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor, u8 n, u8 data0, - u8 data1, u8 data2, u8 data3, u8 data4, u8 data5) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - /* Write cycle. It usually is address + value */ - data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) | - ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) - | ((n - 1) << 4); - data[1] = data0; - data[2] = data1; - data[3] = data2; - data[4] = data3; - data[5] = data4; - data[6] = data5; - data[7] = 0x14; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, - 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += sn9c102_i2c_wait(cam, sensor); - err += sn9c102_i2c_detect_write_error(cam, sensor); - - if (err) - DBG(3, "I2C write failed for %s image sensor", sensor->name); - - PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " - "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", - n, data0, data1, data2, data3, data4, data5); - - return err ? -1 : 0; -} - - -int -sn9c102_i2c_try_read(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor, u8 address) -{ - return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id, - address, 1, NULL); -} - - -int -sn9c102_i2c_try_write(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor, u8 address, u8 value) -{ - return sn9c102_i2c_try_raw_write(cam, sensor, 3, - sensor->i2c_slave_id, address, - value, 0, 0, 0); -} - - -int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address) -{ - return sn9c102_i2c_try_read(cam, &cam->sensor, address); -} - - -int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value) -{ - return sn9c102_i2c_try_write(cam, &cam->sensor, address, value); -} - -/*****************************************************************************/ - -static void* -sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) -{ - size_t soflen = 0, i; - u8 j, n = 0; - - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - soflen = sizeof(sn9c102_sof_header_t); - n = sizeof(sn9c102_sof_header) / soflen; - break; - case BRIDGE_SN9C103: - soflen = sizeof(sn9c103_sof_header_t); - n = sizeof(sn9c103_sof_header) / soflen; - } - - for (i = 0; (len >= soflen) && (i <= len - soflen); i++) - for (j = 0; j < n; j++) - /* The invariable part of the header is 6 bytes long */ - if ((cam->bridge != BRIDGE_SN9C103 && - !memcmp(mem + i, sn9c102_sof_header[j], 6)) || - (cam->bridge == BRIDGE_SN9C103 && - !memcmp(mem + i, sn9c103_sof_header[j], 6))) { - memcpy(cam->sof_header, mem + i, soflen); - /* Skip the header */ - return mem + i + soflen; - } - - return NULL; -} - - -static void* -sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) -{ - size_t eoflen = sizeof(sn9c102_eof_header_t), i; - unsigned j, n = sizeof(sn9c102_eof_header) / eoflen; - - if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) - return NULL; /* EOF header does not exist in compressed data */ - - for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++) - for (j = 0; j < n; j++) - if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen)) - return mem + i; - - return NULL; -} - - -static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs) -{ - struct sn9c102_device* cam = urb->context; - struct sn9c102_frame_t** f; - size_t imagesize, soflen; - u8 i; - int err = 0; - - if (urb->status == -ENOENT) - return; - - f = &cam->frame_current; - - if (cam->stream == STREAM_INTERRUPT) { - cam->stream = STREAM_OFF; - if ((*f)) - (*f)->state = F_QUEUED; - DBG(3, "Stream interrupted"); - wake_up(&cam->wait_stream); - } - - if (cam->state & DEV_DISCONNECTED) - return; - - if (cam->state & DEV_MISCONFIGURED) { - wake_up_interruptible(&cam->wait_frame); - return; - } - - if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) - goto resubmit_urb; - - if (!(*f)) - (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t, - frame); - - imagesize = (cam->sensor.pix_format.width * - cam->sensor.pix_format.height * - cam->sensor.pix_format.priv) / 8; - - soflen = (cam->bridge) == BRIDGE_SN9C103 ? - sizeof(sn9c103_sof_header_t) : - sizeof(sn9c102_sof_header_t); - - for (i = 0; i < urb->number_of_packets; i++) { - unsigned int img, len, status; - void *pos, *sof, *eof; - - len = urb->iso_frame_desc[i].actual_length; - status = urb->iso_frame_desc[i].status; - pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; - - if (status) { - DBG(3, "Error in isochronous frame"); - (*f)->state = F_ERROR; - continue; - } - - PDBGG("Isochrnous frame: length %u, #%u i", len, i); - -redo: - sof = sn9c102_find_sof_header(cam, pos, len); - if (likely(!sof)) { - eof = sn9c102_find_eof_header(cam, pos, len); - if ((*f)->state == F_GRABBING) { -end_of_frame: - img = len; - - if (eof) - img = (eof > pos) ? eof - pos - 1 : 0; - - if ((*f)->buf.bytesused+img > imagesize) { - u32 b; - b = (*f)->buf.bytesused + img - - imagesize; - img = imagesize - (*f)->buf.bytesused; - DBG(3, "Expected EOF not found: " - "video frame cut"); - if (eof) - DBG(3, "Exceeded limit: +%u " - "bytes", (unsigned)(b)); - } - - memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, - img); - - if ((*f)->buf.bytesused == 0) - do_gettimeofday(&(*f)->buf.timestamp); - - (*f)->buf.bytesused += img; - - if ((*f)->buf.bytesused == imagesize || - (cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_SN9C10X && eof)) { - u32 b; - b = (*f)->buf.bytesused; - (*f)->state = F_DONE; - (*f)->buf.sequence= ++cam->frame_count; - spin_lock(&cam->queue_lock); - list_move_tail(&(*f)->frame, - &cam->outqueue); - if (!list_empty(&cam->inqueue)) - (*f) = list_entry( - cam->inqueue.next, - struct sn9c102_frame_t, - frame ); - else - (*f) = NULL; - spin_unlock(&cam->queue_lock); - memcpy(cam->sysfs.frame_header, - cam->sof_header, soflen); - DBG(3, "Video frame captured: %lu " - "bytes", (unsigned long)(b)); - - if (!(*f)) - goto resubmit_urb; - - } else if (eof) { - (*f)->state = F_ERROR; - DBG(3, "Not expected EOF after %lu " - "bytes of image data", - (unsigned long) - ((*f)->buf.bytesused)); - } - - if (sof) /* (1) */ - goto start_of_frame; - - } else if (eof) { - DBG(3, "EOF without SOF"); - continue; - - } else { - PDBGG("Ignoring pointless isochronous frame"); - continue; - } - - } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) { -start_of_frame: - (*f)->state = F_GRABBING; - (*f)->buf.bytesused = 0; - len -= (sof - pos); - pos = sof; - DBG(3, "SOF detected: new video frame"); - if (len) - goto redo; - - } else if ((*f)->state == F_GRABBING) { - eof = sn9c102_find_eof_header(cam, pos, len); - if (eof && eof < sof) - goto end_of_frame; /* (1) */ - else { - if (cam->sensor.pix_format.pixelformat == - V4L2_PIX_FMT_SN9C10X) { - eof = sof - soflen; - goto end_of_frame; - } else { - DBG(3, "SOF before expected EOF after " - "%lu bytes of image data", - (unsigned long) - ((*f)->buf.bytesused)); - goto start_of_frame; - } - } - } - } - -resubmit_urb: - urb->dev = cam->usbdev; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0 && err != -EPERM) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "usb_submit_urb() failed"); - } - - wake_up_interruptible(&cam->wait_frame); -} - - -static int sn9c102_start_transfer(struct sn9c102_device* cam) -{ - struct usb_device *udev = cam->usbdev; - struct urb* urb; - const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512, - 680, 800, 900, 1023}; - const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512, - 680, 800, 900, 1003}; - const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ? - sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] : - sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING]; - s8 i, j; - int err = 0; - - for (i = 0; i < SN9C102_URBS; i++) { - cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz, - GFP_KERNEL); - if (!cam->transfer_buffer[i]) { - err = -ENOMEM; - DBG(1, "Not enough memory"); - goto free_buffers; - } - } - - for (i = 0; i < SN9C102_URBS; i++) { - urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL); - cam->urb[i] = urb; - if (!urb) { - err = -ENOMEM; - DBG(1, "usb_alloc_urb() failed"); - goto free_urbs; - } - urb->dev = udev; - urb->context = cam; - urb->pipe = usb_rcvisocpipe(udev, 1); - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = SN9C102_ISO_PACKETS; - urb->complete = sn9c102_urb_complete; - urb->transfer_buffer = cam->transfer_buffer[i]; - urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS; - urb->interval = 1; - for (j = 0; j < SN9C102_ISO_PACKETS; j++) { - urb->iso_frame_desc[j].offset = psz * j; - urb->iso_frame_desc[j].length = psz; - } - } - - /* Enable video */ - if (!(cam->reg[0x01] & 0x04)) { - err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01); - if (err) { - err = -EIO; - DBG(1, "I/O hardware error"); - goto free_urbs; - } - } - - err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING); - if (err) { - DBG(1, "usb_set_interface() failed"); - goto free_urbs; - } - - cam->frame_current = NULL; - - for (i = 0; i < SN9C102_URBS; i++) { - err = usb_submit_urb(cam->urb[i], GFP_KERNEL); - if (err) { - for (j = i-1; j >= 0; j--) - usb_kill_urb(cam->urb[j]); - DBG(1, "usb_submit_urb() failed, error %d", err); - goto free_urbs; - } - } - - return 0; - -free_urbs: - for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) - usb_free_urb(cam->urb[i]); - -free_buffers: - for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++) - kfree(cam->transfer_buffer[i]); - - return err; -} - - -static int sn9c102_stop_transfer(struct sn9c102_device* cam) -{ - struct usb_device *udev = cam->usbdev; - s8 i; - int err = 0; - - if (cam->state & DEV_DISCONNECTED) - return 0; - - for (i = SN9C102_URBS-1; i >= 0; i--) { - usb_kill_urb(cam->urb[i]); - usb_free_urb(cam->urb[i]); - kfree(cam->transfer_buffer[i]); - } - - err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ - if (err) - DBG(3, "usb_set_interface() failed"); - - return err; -} - - -static int sn9c102_stream_interrupt(struct sn9c102_device* cam) -{ - long timeout; - - cam->stream = STREAM_INTERRUPT; - timeout = wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - SN9C102_URB_TIMEOUT); - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - else if (cam->stream != STREAM_OFF) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "URB timeout reached. The camera is misconfigured. " - "To use it, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - return 0; -} - -/*****************************************************************************/ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count) -{ - char str[5]; - char* endp; - unsigned long val; - - if (len < 4) { - strncpy(str, buff, len); - str[len+1] = '\0'; - } else { - strncpy(str, buff, 4); - str[4] = '\0'; - } - - val = simple_strtoul(str, &endp, 0); - - *count = 0; - if (val <= 0xff) - *count = (ssize_t)(endp - str); - if ((*count) && (len == *count+1) && (buff[*count] == '\n')) - *count += 1; - - return (u8)val; -} - -/* - NOTE 1: being inside one of the following methods implies that the v4l - device exists for sure (see kobjects and reference counters) - NOTE 2: buffers are PAGE_SIZE long -*/ - -static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.reg); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u8 index; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - index = sn9c102_strtou8(buf, len, &count); - if (index > 0x1f || !count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.reg = index; - - DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_val(struct class_device* cd, const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u8 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - value = sn9c102_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - err = sn9c102_write_reg(cam, value, cam->sysfs.reg); - if (err) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X", - cam->sysfs.reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u8 index; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - index = sn9c102_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - cam->sysfs.i2c_reg = index; - - DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - int val; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENOSYS; - } - - if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - count = sprintf(buf, "%d\n", val); - - DBG(3, "Read bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len) -{ - struct sn9c102_device* cam; - u8 value; - ssize_t count; - int err; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENOSYS; - } - - value = sn9c102_strtou8(buf, len, &count); - if (!count) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EINVAL; - } - - err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value); - if (err) { - mutex_unlock(&sn9c102_sysfs_lock); - return -EIO; - } - - DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X", - cam->sysfs.i2c_reg, value); - DBG(3, "Written bytes: %zd", count); - - mutex_unlock(&sn9c102_sysfs_lock); - - return count; -} - - -static ssize_t -sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) -{ - struct sn9c102_device* cam; - enum sn9c102_bridge bridge; - ssize_t res = 0; - u8 value; - ssize_t count; - - if (mutex_lock_interruptible(&sn9c102_sysfs_lock)) - return -ERESTARTSYS; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) { - mutex_unlock(&sn9c102_sysfs_lock); - return -ENODEV; - } - - bridge = cam->bridge; - - mutex_unlock(&sn9c102_sysfs_lock); - - value = sn9c102_strtou8(buf, len, &count); - if (!count) - return -EINVAL; - - switch (bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - if (value > 0x0f) - return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); - break; - case BRIDGE_SN9C103: - if (value > 0x7f) - return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); - break; - } - - return res; -} - - -static ssize_t -sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) -{ - ssize_t res = 0; - u8 value; - ssize_t count; - - value = sn9c102_strtou8(buf, len, &count); - if (!count || value > 0x7f) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); - - return res; -} - - -static ssize_t -sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) -{ - ssize_t res = 0; - u8 value; - ssize_t count; - - value = sn9c102_strtou8(buf, len, &count); - if (!count || value > 0x7f) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); - - return res; -} - - -static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf) -{ - struct sn9c102_device* cam; - ssize_t count; - - cam = video_get_drvdata(to_video_device(cd)); - if (!cam) - return -ENODEV; - - count = sizeof(cam->sysfs.frame_header); - memcpy(buf, cam->sysfs.frame_header, count); - - DBG(3, "Frame header, read bytes: %zd", count); - - return count; -} - - -static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, - sn9c102_show_reg, sn9c102_store_reg); -static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR, - sn9c102_show_val, sn9c102_store_val); -static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); -static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, - sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); -static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); -static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); -static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, - sn9c102_show_frame_header, NULL); - - -static void sn9c102_create_sysfs(struct sn9c102_device* cam) -{ - struct video_device *v4ldev = cam->v4ldev; - - video_device_create_file(v4ldev, &class_device_attr_reg); - video_device_create_file(v4ldev, &class_device_attr_val); - video_device_create_file(v4ldev, &class_device_attr_frame_header); - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - video_device_create_file(v4ldev, &class_device_attr_green); - else if (cam->bridge == BRIDGE_SN9C103) { - video_device_create_file(v4ldev, &class_device_attr_blue); - video_device_create_file(v4ldev, &class_device_attr_red); - } - if (cam->sensor.sysfs_ops) { - video_device_create_file(v4ldev, &class_device_attr_i2c_reg); - video_device_create_file(v4ldev, &class_device_attr_i2c_val); - } -} -#endif /* CONFIG_VIDEO_ADV_DEBUG */ - -/*****************************************************************************/ - -static int -sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18); - else - err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18); - - return err ? -EIO : 0; -} - - -static int -sn9c102_set_compression(struct sn9c102_device* cam, - struct v4l2_jpegcompression* compression) -{ - int err = 0; - - if (compression->quality == 0) - err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17); - else if (compression->quality == 1) - err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17); - - return err ? -EIO : 0; -} - - -static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale) -{ - u8 r = 0; - int err = 0; - - if (scale == 1) - r = cam->reg[0x18] & 0xcf; - else if (scale == 2) { - r = cam->reg[0x18] & 0xcf; - r |= 0x10; - } else if (scale == 4) - r = cam->reg[0x18] | 0x20; - - err += sn9c102_write_reg(cam, r, 0x18); - if (err) - return -EIO; - - PDBGG("Scaling factor: %u", scale); - - return 0; -} - - -static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &cam->sensor; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), - v_start = (u8)(rect->top - s->cropcap.bounds.top), - h_size = (u8)(rect->width / 16), - v_size = (u8)(rect->height / 16); - int err = 0; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - err += sn9c102_write_reg(cam, h_size, 0x15); - err += sn9c102_write_reg(cam, v_size, 0x16); - if (err) - return -EIO; - - PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " - "%u %u %u %u", h_start, v_start, h_size, v_size); - - return 0; -} - - -static int sn9c102_init(struct sn9c102_device* cam) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - struct v4l2_queryctrl *qctrl; - struct v4l2_rect* rect; - u8 i = 0; - int err = 0; - - if (!(cam->state & DEV_INITIALIZED)) { - init_waitqueue_head(&cam->open); - qctrl = s->qctrl; - rect = &(s->cropcap.defrect); - } else { /* use current values */ - qctrl = s->_qctrl; - rect = &(s->_rect); - } - - err += sn9c102_set_scale(cam, rect->width / s->pix_format.width); - err += sn9c102_set_crop(cam, rect); - if (err) - return err; - - if (s->init) { - err = s->init(cam); - if (err) { - DBG(3, "Sensor initialization failed"); - return err; - } - } - - if (!(cam->state & DEV_INITIALIZED)) - cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1; - else - err += sn9c102_set_compression(cam, &cam->compression); - err += sn9c102_set_pix_format(cam, &s->pix_format); - if (s->set_pix_format) - err += s->set_pix_format(cam, &s->pix_format); - if (err) - return err; - - if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) - DBG(3, "Compressed video format is active, quality %d", - cam->compression.quality); - else - DBG(3, "Uncompressed video format is active"); - - if (s->set_crop) - if ((err = s->set_crop(cam, rect))) { - DBG(3, "set_crop() failed"); - return err; - } - - if (s->set_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (s->qctrl[i].id != 0 && - !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl.id = s->qctrl[i].id; - ctrl.value = qctrl[i].default_value; - err = s->set_ctrl(cam, &ctrl); - if (err) { - DBG(3, "Set %s control failed", - s->qctrl[i].name); - return err; - } - DBG(3, "Image sensor supports '%s' control", - s->qctrl[i].name); - } - } - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->fileop_mutex); - spin_lock_init(&cam->queue_lock); - init_waitqueue_head(&cam->wait_frame); - init_waitqueue_head(&cam->wait_stream); - cam->nreadbuffers = 2; - memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); - memcpy(&(s->_rect), &(s->cropcap.defrect), - sizeof(struct v4l2_rect)); - cam->state |= DEV_INITIALIZED; - } - - DBG(2, "Initialization succeeded"); - return 0; -} - - -static void sn9c102_release_resources(struct sn9c102_device* cam) -{ - mutex_lock(&sn9c102_sysfs_lock); - - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); - video_set_drvdata(cam->v4ldev, NULL); - video_unregister_device(cam->v4ldev); - - usb_put_dev(cam->usbdev); - - mutex_unlock(&sn9c102_sysfs_lock); - - kfree(cam->control_buffer); -} - -/*****************************************************************************/ - -static int sn9c102_open(struct inode* inode, struct file* filp) -{ - struct sn9c102_device* cam; - int err = 0; - - /* - This is the only safe way to prevent race conditions with - disconnect - */ - if (!down_read_trylock(&sn9c102_disconnect)) - return -ERESTARTSYS; - - cam = video_get_drvdata(video_devdata(filp)); - - if (mutex_lock_interruptible(&cam->dev_mutex)) { - up_read(&sn9c102_disconnect); - return -ERESTARTSYS; - } - - if (cam->users) { - DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); - if ((filp->f_flags & O_NONBLOCK) || - (filp->f_flags & O_NDELAY)) { - err = -EWOULDBLOCK; - goto out; - } - mutex_unlock(&cam->dev_mutex); - err = wait_event_interruptible_exclusive(cam->open, - cam->state & DEV_DISCONNECTED - || !cam->users); - if (err) { - up_read(&sn9c102_disconnect); - return err; - } - if (cam->state & DEV_DISCONNECTED) { - up_read(&sn9c102_disconnect); - return -ENODEV; - } - mutex_lock(&cam->dev_mutex); - } - - - if (cam->state & DEV_MISCONFIGURED) { - err = sn9c102_init(cam); - if (err) { - DBG(1, "Initialization failed again. " - "I will retry on next open()."); - goto out; - } - cam->state &= ~DEV_MISCONFIGURED; - } - - if ((err = sn9c102_start_transfer(cam))) - goto out; - - filp->private_data = cam; - cam->users++; - cam->io = IO_NONE; - cam->stream = STREAM_OFF; - cam->nbuffers = 0; - cam->frame_count = 0; - sn9c102_empty_framequeues(cam); - - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); - -out: - mutex_unlock(&cam->dev_mutex); - up_read(&sn9c102_disconnect); - return err; -} - - -static int sn9c102_release(struct inode* inode, struct file* filp) -{ - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); - - mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ - - sn9c102_stop_transfer(cam); - - sn9c102_release_buffers(cam); - - if (cam->state & DEV_DISCONNECTED) { - sn9c102_release_resources(cam); - mutex_unlock(&cam->dev_mutex); - kfree(cam); - return 0; - } - - cam->users--; - wake_up_interruptible_nr(&cam->open, 1); - - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - - mutex_unlock(&cam->dev_mutex); - - return 0; -} - - -static ssize_t -sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) -{ - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); - struct sn9c102_frame_t* f, * i; - unsigned long lock_flags; - long timeout; - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io == IO_MMAP) { - DBG(3, "Close and open the device again to choose " - "the read method"); - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - if (cam->io == IO_NONE) { - if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { - DBG(1, "read() failed, not enough memory"); - mutex_unlock(&cam->fileop_mutex); - return -ENOMEM; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (list_empty(&cam->inqueue)) { - if (!list_empty(&cam->outqueue)) - sn9c102_empty_framequeues(cam); - sn9c102_queue_unusedframes(cam); - } - - if (!count) { - mutex_unlock(&cam->fileop_mutex); - return 0; - } - - if (list_empty(&cam->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) { - mutex_unlock(&cam->fileop_mutex); - return timeout; - } - if (cam->state & DEV_DISCONNECTED) { - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - if (!timeout || (cam->state & DEV_MISCONFIGURED)) { - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - } - - f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame); - - if (count > f->buf.bytesused) - count = f->buf.bytesused; - - if (copy_to_user(buf, f->bufmem, count)) { - err = -EFAULT; - goto exit; - } - *f_pos += count; - -exit: - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(i, &cam->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - sn9c102_queue_unusedframes(cam); - - PDBGG("Frame #%lu, bytes read: %zu", - (unsigned long)f->buf.index, count); - - mutex_unlock(&cam->fileop_mutex); - - return count; -} - - -static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) -{ - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); - struct sn9c102_frame_t* f; - unsigned long lock_flags; - unsigned int mask = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return POLLERR; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - goto error; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - goto error; - } - - if (cam->io == IO_NONE) { - if (!sn9c102_request_buffers(cam, cam->nreadbuffers, - IO_READ)) { - DBG(1, "poll() failed, not enough memory"); - goto error; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (cam->io == IO_READ) { - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(f, &cam->outqueue, frame) - f->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - sn9c102_queue_unusedframes(cam); - } - - poll_wait(filp, &cam->wait_frame, wait); - - if (!list_empty(&cam->outqueue)) - mask |= POLLIN | POLLRDNORM; - - mutex_unlock(&cam->fileop_mutex); - - return mask; - -error: - mutex_unlock(&cam->fileop_mutex); - return POLLERR; -} - - -static void sn9c102_vm_open(struct vm_area_struct* vma) -{ - struct sn9c102_frame_t* f = vma->vm_private_data; - f->vma_use_count++; -} - - -static void sn9c102_vm_close(struct vm_area_struct* vma) -{ - /* NOTE: buffers are not freed here */ - struct sn9c102_frame_t* f = vma->vm_private_data; - f->vma_use_count--; -} - - -static struct vm_operations_struct sn9c102_vm_ops = { - .open = sn9c102_vm_open, - .close = sn9c102_vm_close, -}; - - -static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) -{ - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(cam->frame[0].buf.length)) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) { - if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == cam->nbuffers) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; - - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &sn9c102_vm_ops; - vma->vm_private_data = &cam->frame[i]; - - sn9c102_vm_open(vma); - - mutex_unlock(&cam->fileop_mutex); - - return 0; -} - -/*****************************************************************************/ - -static int -sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_capability cap = { - .driver = "sn9c102", - .version = SN9C102_MODULE_VERSION_CODE, - .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING, - }; - - strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); - if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, - sizeof(cap.bus_info)); - - if (copy_to_user(arg, &cap, sizeof(cap))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_input i; - - if (copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - if (i.index) - return -EINVAL; - - memset(&i, 0, sizeof(i)); - strcpy(i.name, "Camera"); - i.type = V4L2_INPUT_TYPE_CAMERA; - - if (copy_to_user(arg, &i, sizeof(i))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg) -{ - int index = 0; - - if (copy_to_user(arg, &index, sizeof(index))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg) -{ - int index; - - if (copy_from_user(&index, arg, sizeof(index))) - return -EFAULT; - - if (index != 0) - return -EINVAL; - - return 0; -} - - -static int -sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_queryctrl qc; - u8 i; - - if (copy_from_user(&qc, arg, sizeof(qc))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (qc.id && qc.id == s->qctrl[i].id) { - memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); - if (copy_to_user(arg, &qc, sizeof(qc))) - return -EFAULT; - return 0; - } - - return -EINVAL; -} - - -static int -sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - int err = 0; - u8 i; - - if (!s->get_ctrl && !s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - if (!s->get_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id && ctrl.id == s->qctrl[i].id) { - ctrl.value = s->_qctrl[i].default_value; - goto exit; - } - return -EINVAL; - } else - err = s->get_ctrl(cam, &ctrl); - -exit: - if (copy_to_user(arg, &ctrl, sizeof(ctrl))) - return -EFAULT; - - return err; -} - - -static int -sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - u8 i; - int err = 0; - - if (!s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id == s->qctrl[i].id) { - if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) - return -EINVAL; - if (ctrl.value < s->qctrl[i].minimum || - ctrl.value > s->qctrl[i].maximum) - return -ERANGE; - ctrl.value -= ctrl.value % s->qctrl[i].step; - break; - } - - if ((err = s->set_ctrl(cam, &ctrl))) - return err; - - s->_qctrl[i].default_value = ctrl.value; - - PDBGG("VIDIOC_S_CTRL: id %lu, value %lu", - (unsigned long)ctrl.id, (unsigned long)ctrl.value); - - return 0; -} - - -static int -sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_cropcap* cc = &(cam->sensor.cropcap); - - cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cc->pixelaspect.numerator = 1; - cc->pixelaspect.denominator = 1; - - if (copy_to_user(arg, cc, sizeof(*cc))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_crop crop = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - }; - - memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); - - if (copy_to_user(arg, &crop, sizeof(crop))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_crop crop; - struct v4l2_rect* rect; - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_pix_format* pix_format = &(s->pix_format); - u8 scale; - const enum sn9c102_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&crop, arg, sizeof(crop))) - return -EFAULT; - - rect = &(crop.c); - - if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_CROP failed. " - "Unmap the buffers first."); - return -EINVAL; - } - - /* Preserve R,G or B origin */ - rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L; - rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L; - - if (rect->width < 16) - rect->width = 16; - if (rect->height < 16) - rect->height = 16; - if (rect->width > bounds->width) - rect->width = bounds->width; - if (rect->height > bounds->height) - rect->height = bounds->height; - if (rect->left < bounds->left) - rect->left = bounds->left; - if (rect->top < bounds->top) - rect->top = bounds->top; - if (rect->left + rect->width > bounds->left + bounds->width) - rect->left = bounds->left+bounds->width - rect->width; - if (rect->top + rect->height > bounds->top + bounds->height) - rect->top = bounds->top+bounds->height - rect->height; - - rect->width &= ~15L; - rect->height &= ~15L; - - if (SN9C102_PRESERVE_IMGSCALE) { - /* Calculate the actual scaling factor */ - u32 a, b; - a = rect->width * rect->height; - b = pix_format->width * pix_format->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } else - scale = 1; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &crop, sizeof(crop))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - sn9c102_release_buffers(cam); - - err = sn9c102_set_crop(cam, rect); - if (s->set_crop) - err += s->set_crop(cam, rect); - err += sn9c102_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - s->pix_format.width = rect->width/scale; - s->pix_format.height = rect->height/scale; - memcpy(&(s->_rect), rect, sizeof(*rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -ENOMEM; - } - - if (cam->io == IO_READ) - sn9c102_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - sn9c102_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_fmtdesc fmtd; - - if (copy_from_user(&fmtd, arg, sizeof(fmtd))) - return -EFAULT; - - if (fmtd.index == 0) { - strcpy(fmtd.description, "bayer rgb"); - fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8; - } else if (fmtd.index == 1) { - strcpy(fmtd.description, "compressed"); - fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; - fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; - } else - return -EINVAL; - - fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); - - if (copy_to_user(arg, &fmtd, sizeof(fmtd))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X) - ? 0 : (pfmt->width * pfmt->priv) / 8; - pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); - pfmt->field = V4L2_FIELD_NONE; - memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); - - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, - void __user * arg) -{ - struct sn9c102_sensor* s = &cam->sensor; - struct v4l2_format format; - struct v4l2_pix_format* pix; - struct v4l2_pix_format* pfmt = &(s->pix_format); - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_rect rect; - u8 scale; - const enum sn9c102_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - pix = &(format.fmt.pix); - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memcpy(&rect, &(s->_rect), sizeof(rect)); - - { /* calculate the actual scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } - - rect.width = scale * pix->width; - rect.height = scale * pix->height; - - if (rect.width < 16) - rect.width = 16; - if (rect.height < 16) - rect.height = 16; - if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left + bounds->width - rect.left; - if (rect.height > bounds->top + bounds->height - rect.top) - rect.height = bounds->top + bounds->height - rect.top; - - rect.width &= ~15L; - rect.height &= ~15L; - - { /* adjust the scaling factor */ - u32 a, b; - a = rect.width * rect.height; - b = pix->width * pix->height; - scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1; - } - - pix->width = rect.width / scale; - pix->height = rect.height / scale; - - if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && - pix->pixelformat != V4L2_PIX_FMT_SBGGR8) - pix->pixelformat = pfmt->pixelformat; - pix->priv = pfmt->priv; /* bpp */ - pix->colorspace = pfmt->colorspace; - pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - ? 0 : (pix->width * pix->priv) / 8; - pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); - pix->field = V4L2_FIELD_NONE; - - if (cmd == VIDIOC_TRY_FMT) { - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - return 0; - } - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_FMT failed. Unmap the " - "buffers first."); - return -EINVAL; - } - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &format, sizeof(format))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - sn9c102_release_buffers(cam); - - err += sn9c102_set_pix_format(cam, pix); - err += sn9c102_set_crop(cam, &rect); - if (s->set_pix_format) - err += s->set_pix_format(cam, pix); - if (s->set_crop) - err += s->set_crop(cam, &rect); - err += sn9c102_set_scale(cam, scale); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - memcpy(pfmt, pix, sizeof(*pix)); - memcpy(&(s->_rect), &rect, sizeof(rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -ENOMEM; - } - - if (cam->io == IO_READ) - sn9c102_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - sn9c102_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg) -{ - if (copy_to_user(arg, &cam->compression, - sizeof(cam->compression))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_jpegcompression jc; - const enum sn9c102_stream_state stream = cam->stream; - int err = 0; - - if (copy_from_user(&jc, arg, sizeof(jc))) - return -EFAULT; - - if (jc.quality != 0 && jc.quality != 1) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - err += sn9c102_set_compression(cam, &jc); - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " - "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->minor); - return -EIO; - } - - cam->compression.quality = jc.quality; - - cam->stream = stream; - - return 0; -} - - -static int -sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_requestbuffers rb; - u32 i; - int err; - - if (copy_from_user(&rb, arg, sizeof(rb))) - return -EFAULT; - - if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb.memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (cam->io == IO_READ) { - DBG(3, "Close and open the device again to choose the mmap " - "I/O method"); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " - "still mapped."); - return -EINVAL; - } - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - sn9c102_empty_framequeues(cam); - - sn9c102_release_buffers(cam); - if (rb.count) - rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP); - - if (copy_to_user(arg, &rb, sizeof(rb))) { - sn9c102_release_buffers(cam); - cam->io = IO_NONE; - return -EFAULT; - } - - cam->io = rb.count ? IO_MMAP : IO_NONE; - - return 0; -} - - -static int -sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); - - if (cam->frame[b.index].vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (cam->frame[b.index].state == F_DONE) - b.flags |= V4L2_BUF_FLAG_DONE; - else if (cam->frame[b.index].state != F_UNUSED) - b.flags |= V4L2_BUF_FLAG_QUEUED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - unsigned long lock_flags; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->frame[b.index].state != F_UNUSED) - return -EINVAL; - - cam->frame[b.index].state = F_QUEUED; - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - PDBGG("Frame #%lu queued", (unsigned long)b.index); - - return 0; -} - - -static int -sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, - void __user * arg) -{ - struct v4l2_buffer b; - struct sn9c102_frame_t *f; - unsigned long lock_flags; - long timeout; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->outqueue)) { - if (cam->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) - return timeout; - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - if (!timeout || (cam->state & DEV_MISCONFIGURED)) - return -EIO; - } - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame); - list_del(cam->outqueue.next); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - f->state = F_UNUSED; - - memcpy(&b, &f->buf, sizeof(b)); - if (f->vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); - - return 0; -} - - -static int -sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) -{ - int type; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->inqueue)) - return -EINVAL; - - cam->stream = STREAM_ON; - - DBG(3, "Stream on"); - - return 0; -} - - -static int -sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg) -{ - int type, err; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = sn9c102_stream_interrupt(cam))) - return err; - - sn9c102_empty_framequeues(cam); - - DBG(3, "Stream off"); - - return 0; -} - - -static int -sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - return 0; -} - - -static int -sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - - if (sp.parm.capture.readbuffers == 0) - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES) - sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - cam->nreadbuffers = sp.parm.capture.readbuffers; - - return 0; -} - - -static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, - unsigned int cmd, void __user * arg) -{ - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); - - switch (cmd) { - - case VIDIOC_QUERYCAP: - return sn9c102_vidioc_querycap(cam, arg); - - case VIDIOC_ENUMINPUT: - return sn9c102_vidioc_enuminput(cam, arg); - - case VIDIOC_G_INPUT: - return sn9c102_vidioc_g_input(cam, arg); - - case VIDIOC_S_INPUT: - return sn9c102_vidioc_s_input(cam, arg); - - case VIDIOC_QUERYCTRL: - return sn9c102_vidioc_query_ctrl(cam, arg); - - case VIDIOC_G_CTRL: - return sn9c102_vidioc_g_ctrl(cam, arg); - - case VIDIOC_S_CTRL_OLD: - case VIDIOC_S_CTRL: - return sn9c102_vidioc_s_ctrl(cam, arg); - - case VIDIOC_CROPCAP_OLD: - case VIDIOC_CROPCAP: - return sn9c102_vidioc_cropcap(cam, arg); - - case VIDIOC_G_CROP: - return sn9c102_vidioc_g_crop(cam, arg); - - case VIDIOC_S_CROP: - return sn9c102_vidioc_s_crop(cam, arg); - - case VIDIOC_ENUM_FMT: - return sn9c102_vidioc_enum_fmt(cam, arg); - - case VIDIOC_G_FMT: - return sn9c102_vidioc_g_fmt(cam, arg); - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - return sn9c102_vidioc_try_s_fmt(cam, cmd, arg); - - case VIDIOC_G_JPEGCOMP: - return sn9c102_vidioc_g_jpegcomp(cam, arg); - - case VIDIOC_S_JPEGCOMP: - return sn9c102_vidioc_s_jpegcomp(cam, arg); - - case VIDIOC_REQBUFS: - return sn9c102_vidioc_reqbufs(cam, arg); - - case VIDIOC_QUERYBUF: - return sn9c102_vidioc_querybuf(cam, arg); - - case VIDIOC_QBUF: - return sn9c102_vidioc_qbuf(cam, arg); - - case VIDIOC_DQBUF: - return sn9c102_vidioc_dqbuf(cam, filp, arg); - - case VIDIOC_STREAMON: - return sn9c102_vidioc_streamon(cam, arg); - - case VIDIOC_STREAMOFF: - return sn9c102_vidioc_streamoff(cam, arg); - - case VIDIOC_G_PARM: - return sn9c102_vidioc_g_parm(cam, arg); - - case VIDIOC_S_PARM_OLD: - case VIDIOC_S_PARM: - return sn9c102_vidioc_s_parm(cam, arg); - - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_QUERYSTD: - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYMENU: - return -EINVAL; - - default: - return -EINVAL; - - } -} - - -static int sn9c102_ioctl(struct inode* inode, struct file* filp, - unsigned int cmd, unsigned long arg) -{ - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - V4LDBG(3, "sn9c102", cmd); - - err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); - - mutex_unlock(&cam->fileop_mutex); - - return err; -} - -/*****************************************************************************/ - -static struct file_operations sn9c102_fops = { - .owner = THIS_MODULE, - .open = sn9c102_open, - .release = sn9c102_release, - .ioctl = sn9c102_ioctl, - .read = sn9c102_read, - .poll = sn9c102_poll, - .mmap = sn9c102_mmap, - .llseek = no_llseek, -}; - -/*****************************************************************************/ - -/* It exists a single interface only. We do not need to validate anything. */ -static int -sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct sn9c102_device* cam; - static unsigned int dev_nr = 0; - unsigned int i; - int err = 0, r; - - if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL))) - return -ENOMEM; - - cam->usbdev = udev; - - if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) { - DBG(1, "kmalloc() failed"); - err = -ENOMEM; - goto fail; - } - - if (!(cam->v4ldev = video_device_alloc())) { - DBG(1, "video_device_alloc() failed"); - err = -ENOMEM; - goto fail; - } - - mutex_init(&cam->dev_mutex); - - r = sn9c102_read_reg(cam, 0x00); - if (r < 0 || r != 0x10) { - DBG(1, "Sorry, this is not a SN9C10x based camera " - "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); - err = -ENODEV; - goto fail; - } - - cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ? - BRIDGE_SN9C103 : BRIDGE_SN9C102; - switch (cam->bridge) { - case BRIDGE_SN9C101: - case BRIDGE_SN9C102: - DBG(2, "SN9C10[12] PC Camera Controller detected " - "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); - break; - case BRIDGE_SN9C103: - DBG(2, "SN9C103 PC Camera Controller detected " - "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct); - break; - } - - for (i = 0; sn9c102_sensor_table[i]; i++) { - err = sn9c102_sensor_table[i](cam); - if (!err) - break; - } - - if (!err) { - DBG(2, "%s image sensor detected", cam->sensor.name); - DBG(3, "Support for %s maintained by %s", - cam->sensor.name, cam->sensor.maintainer); - } else { - DBG(1, "No supported image sensor detected"); - err = -ENODEV; - goto fail; - } - - if (sn9c102_init(cam)) { - DBG(1, "Initialization failed. I will retry on open()."); - cam->state |= DEV_MISCONFIGURED; - } - - strcpy(cam->v4ldev->name, "SN9C10x PC Camera"); - cam->v4ldev->owner = THIS_MODULE; - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; - cam->v4ldev->hardware = 0; - cam->v4ldev->fops = &sn9c102_fops; - cam->v4ldev->minor = video_nr[dev_nr]; - cam->v4ldev->release = video_device_release; - video_set_drvdata(cam->v4ldev, cam); - - mutex_lock(&cam->dev_mutex); - - err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, - video_nr[dev_nr]); - if (err) { - DBG(1, "V4L2 device registration failed"); - if (err == -ENFILE && video_nr[dev_nr] == -1) - DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); - goto fail; - } - - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); - - cam->module_param.force_munmap = force_munmap[dev_nr]; - cam->module_param.frame_timeout = frame_timeout[dev_nr]; - - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - -#ifdef CONFIG_VIDEO_ADV_DEBUG - sn9c102_create_sysfs(cam); - DBG(2, "Optional device control through 'sysfs' interface ready"); -#endif - - usb_set_intfdata(intf, cam); - - mutex_unlock(&cam->dev_mutex); - - return 0; - -fail: - if (cam) { - kfree(cam->control_buffer); - if (cam->v4ldev) - video_device_release(cam->v4ldev); - kfree(cam); - } - return err; -} - - -static void sn9c102_usb_disconnect(struct usb_interface* intf) -{ - struct sn9c102_device* cam = usb_get_intfdata(intf); - - if (!cam) - return; - - down_write(&sn9c102_disconnect); - - mutex_lock(&cam->dev_mutex); - - DBG(2, "Disconnecting %s...", cam->v4ldev->name); - - wake_up_interruptible_all(&cam->open); - - if (cam->users) { - DBG(2, "Device /dev/video%d is open! Deregistration and " - "memory deallocation are deferred on close.", - cam->v4ldev->minor); - cam->state |= DEV_MISCONFIGURED; - sn9c102_stop_transfer(cam); - cam->state |= DEV_DISCONNECTED; - wake_up_interruptible(&cam->wait_frame); - wake_up(&cam->wait_stream); - usb_get_dev(cam->usbdev); - } else { - cam->state |= DEV_DISCONNECTED; - sn9c102_release_resources(cam); - } - - mutex_unlock(&cam->dev_mutex); - - if (!cam->users) - kfree(cam); - - up_write(&sn9c102_disconnect); -} - - -static struct usb_driver sn9c102_usb_driver = { - .name = "sn9c102", - .id_table = sn9c102_id_table, - .probe = sn9c102_usb_probe, - .disconnect = sn9c102_usb_disconnect, -}; - -/*****************************************************************************/ - -static int __init sn9c102_module_init(void) -{ - int err = 0; - - KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION); - KDBG(3, SN9C102_MODULE_AUTHOR); - - if ((err = usb_register(&sn9c102_usb_driver))) - KDBG(1, "usb_register() failed"); - - return err; -} - - -static void __exit sn9c102_module_exit(void) -{ - usb_deregister(&sn9c102_usb_driver); -} - - -module_init(sn9c102_module_init); -module_exit(sn9c102_module_exit); diff --git a/drivers/usb/media/sn9c102_hv7131d.c b/drivers/usb/media/sn9c102_hv7131d.c deleted file mode 100644 index 46c12ec3ca62..000000000000 --- a/drivers/usb/media/sn9c102_hv7131d.c +++ /dev/null @@ -1,271 +0,0 @@ -/*************************************************************************** - * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" - - -static struct sn9c102_sensor hv7131d; - - -static int hv7131d_init(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x00, 0x10); - err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); - err += sn9c102_write_reg(cam, 0x60, 0x17); - err += sn9c102_write_reg(cam, 0x0e, 0x18); - err += sn9c102_write_reg(cam, 0xf2, 0x19); - - err += sn9c102_i2c_write(cam, 0x01, 0x04); - err += sn9c102_i2c_write(cam, 0x02, 0x00); - err += sn9c102_i2c_write(cam, 0x28, 0x00); - - return err; -} - - -static int hv7131d_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x26), - r2 = sn9c102_i2c_read(cam, 0x27); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 8) | (r2 & 0xff); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) - return -EIO; - ctrl->value = 0x3f - (ctrl->value & 0x3f); - return 0; - case SN9C102_V4L2_CID_RESET_LEVEL: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) - return -EIO; - ctrl->value &= 0x3f; - return 0; - case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0) - return -EIO; - ctrl->value &= 0x07; - return 0; - default: - return -EINVAL; - } -} - - -static int hv7131d_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8); - err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value); - break; - case SN9C102_V4L2_CID_RESET_LEVEL: - err += sn9c102_i2c_write(cam, 0x30, ctrl->value); - break; - case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE: - err += sn9c102_i2c_write(cam, 0x34, ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int hv7131d_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &hv7131d; - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int hv7131d_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x42, 0x19); - else - err += sn9c102_write_reg(cam, 0xf2, 0x19); - - return err; -} - - -static struct sn9c102_sensor hv7131d = { - .name = "HV7131D", - .maintainer = "Luca Risolia ", - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x11, - .init = &hv7131d_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x0250, - .maximum = 0xffff, - .step = 0x0001, - .default_value = 0x0250, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x1e, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_RESET_LEVEL, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "reset level", - .minimum = 0x19, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x30, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "pixel bias voltage", - .minimum = 0x00, - .maximum = 0x07, - .step = 0x01, - .default_value = 0x02, - .flags = 0, - }, - }, - .get_ctrl = &hv7131d_get_ctrl, - .set_ctrl = &hv7131d_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &hv7131d_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &hv7131d_set_pix_format -}; - - -int sn9c102_probe_hv7131d(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0, err = 0; - - err += sn9c102_write_reg(cam, 0x01, 0x01); - err += sn9c102_write_reg(cam, 0x00, 0x01); - err += sn9c102_write_reg(cam, 0x28, 0x17); - if (err) - return -EIO; - - r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00); - r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01); - if (r0 < 0 || r1 < 0) - return -EIO; - - if (r0 != 0x00 && r1 != 0x04) - return -ENODEV; - - sn9c102_attach_sensor(cam, &hv7131d); - - return 0; -} diff --git a/drivers/usb/media/sn9c102_mi0343.c b/drivers/usb/media/sn9c102_mi0343.c deleted file mode 100644 index d9aa7a61095d..000000000000 --- a/drivers/usb/media/sn9c102_mi0343.c +++ /dev/null @@ -1,363 +0,0 @@ -/*************************************************************************** - * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" - - -static struct sn9c102_sensor mi0343; -static u8 mi0343_i2c_data[5+1]; - - -static int mi0343_init(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x00, 0x10); - err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x0a, 0x14); - err += sn9c102_write_reg(cam, 0x40, 0x01); - err += sn9c102_write_reg(cam, 0x20, 0x17); - err += sn9c102_write_reg(cam, 0x07, 0x18); - err += sn9c102_write_reg(cam, 0xa0, 0x19); - - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x0d, 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x0d, 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x03, 0x01, 0xe1, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x04, 0x02, 0x81, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x05, 0x00, 0x17, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x06, 0x00, 0x11, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, - 0x62, 0x04, 0x9a, 0, 0); - - return err; -} - - -static int mi0343_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x09, 2+1, mi0343_i2c_data) < 0) - return -EIO; - ctrl->value = mi0343_i2c_data[2]; - return 0; - case V4L2_CID_GAIN: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x35, 2+1, mi0343_i2c_data) < 0) - return -EIO; - break; - case V4L2_CID_HFLIP: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x20, 2+1, mi0343_i2c_data) < 0) - return -EIO; - ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0; - return 0; - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x20, 2+1, mi0343_i2c_data) < 0) - return -EIO; - ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0; - return 0; - case V4L2_CID_RED_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x2d, 2+1, mi0343_i2c_data) < 0) - return -EIO; - break; - case V4L2_CID_BLUE_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x2c, 2+1, mi0343_i2c_data) < 0) - return -EIO; - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, - 0x2e, 2+1, mi0343_i2c_data) < 0) - return -EIO; - break; - default: - return -EINVAL; - } - - switch (ctrl->id) { - case V4L2_CID_GAIN: - case V4L2_CID_RED_BALANCE: - case V4L2_CID_BLUE_BALANCE: - case SN9C102_V4L2_CID_GREEN_BALANCE: - ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8); - if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) - ctrl->value -= 0x10; - else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) - ctrl->value -= 0x60; - else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff) - ctrl->value -= 0xe0; - } - - return 0; -} - - -static int mi0343_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - u16 reg = 0; - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - case V4L2_CID_RED_BALANCE: - case V4L2_CID_BLUE_BALANCE: - case SN9C102_V4L2_CID_GREEN_BALANCE: - if (ctrl->value <= (0x3f-0x10)) - reg = 0x10 + ctrl->value; - else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60))) - reg = 0x60 + (ctrl->value - (0x3f-0x10)); - else - reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60)); - break; - } - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x09, ctrl->value, 0x00, - 0, 0); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x35, reg >> 8, reg & 0xff, - 0, 0); - break; - case V4L2_CID_HFLIP: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x20, ctrl->value ? 0x40:0x00, - ctrl->value ? 0x20:0x00, - 0, 0); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x20, ctrl->value ? 0x80:0x00, - ctrl->value ? 0x80:0x00, - 0, 0); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x2d, reg >> 8, reg & 0xff, - 0, 0); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x2c, reg >> 8, reg & 0xff, - 0, 0); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x2b, reg >> 8, reg & 0xff, - 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x2e, reg >> 8, reg & 0xff, - 0, 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int mi0343_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &mi0343; - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int mi0343_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x0a, 0x00, 0x03, 0, 0); - err += sn9c102_write_reg(cam, 0x20, 0x19); - } else { - err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, - mi0343.i2c_slave_id, - 0x0a, 0x00, 0x05, 0, 0); - err += sn9c102_write_reg(cam, 0xa0, 0x19); - } - - return err; -} - - -static struct sn9c102_sensor mi0343 = { - .name = "MI-0343", - .maintainer = "Luca Risolia ", - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5d, - .init = &mi0343_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x06, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/ - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)), - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .get_ctrl = &mi0343_get_ctrl, - .set_ctrl = &mi0343_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mi0343_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mi0343_set_pix_format -}; - - -int sn9c102_probe_mi0343(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x01, 0x01); - err += sn9c102_write_reg(cam, 0x00, 0x01); - err += sn9c102_write_reg(cam, 0x28, 0x17); - if (err) - return -EIO; - - if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, - 2, mi0343_i2c_data) < 0) - return -EIO; - - if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mi0343); - - return 0; -} diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c deleted file mode 100644 index 42852b7cb042..000000000000 --- a/drivers/usb/media/sn9c102_ov7630.c +++ /dev/null @@ -1,401 +0,0 @@ -/*************************************************************************** - * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera * - * Controllers * - * * - * Copyright (C) 2005-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" - - -static struct sn9c102_sensor ov7630; - - -static int ov7630_init(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x00, 0x14); - err += sn9c102_write_reg(cam, 0x60, 0x17); - err += sn9c102_write_reg(cam, 0x0f, 0x18); - err += sn9c102_write_reg(cam, 0x50, 0x19); - - err += sn9c102_i2c_write(cam, 0x12, 0x80); - err += sn9c102_i2c_write(cam, 0x11, 0x01); - err += sn9c102_i2c_write(cam, 0x15, 0x34); - err += sn9c102_i2c_write(cam, 0x16, 0x03); - err += sn9c102_i2c_write(cam, 0x17, 0x1c); - err += sn9c102_i2c_write(cam, 0x18, 0xbd); - err += sn9c102_i2c_write(cam, 0x19, 0x06); - err += sn9c102_i2c_write(cam, 0x1a, 0xf6); - err += sn9c102_i2c_write(cam, 0x1b, 0x04); - err += sn9c102_i2c_write(cam, 0x20, 0xf6); - err += sn9c102_i2c_write(cam, 0x23, 0xee); - err += sn9c102_i2c_write(cam, 0x26, 0xa0); - err += sn9c102_i2c_write(cam, 0x27, 0x9a); - err += sn9c102_i2c_write(cam, 0x28, 0xa0); - err += sn9c102_i2c_write(cam, 0x29, 0x30); - err += sn9c102_i2c_write(cam, 0x2a, 0xa0); - err += sn9c102_i2c_write(cam, 0x2b, 0x1f); - err += sn9c102_i2c_write(cam, 0x2f, 0x3d); - err += sn9c102_i2c_write(cam, 0x30, 0x24); - err += sn9c102_i2c_write(cam, 0x32, 0x86); - err += sn9c102_i2c_write(cam, 0x60, 0xa9); - err += sn9c102_i2c_write(cam, 0x61, 0x42); - err += sn9c102_i2c_write(cam, 0x65, 0x00); - err += sn9c102_i2c_write(cam, 0x69, 0x38); - err += sn9c102_i2c_write(cam, 0x6f, 0x88); - err += sn9c102_i2c_write(cam, 0x70, 0x0b); - err += sn9c102_i2c_write(cam, 0x71, 0x00); - err += sn9c102_i2c_write(cam, 0x74, 0x21); - err += sn9c102_i2c_write(cam, 0x7d, 0xf7); - - return err; -} - - -static int ov7630_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2); - err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x02, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x01, ctrl->value); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x00, ctrl->value); - break; - case V4L2_CID_CONTRAST: - err += ctrl->value ? sn9c102_i2c_write(cam, 0x05, - (ctrl->value-1) | 0x20) - : sn9c102_i2c_write(cam, 0x05, 0x00); - break; - case V4L2_CID_BRIGHTNESS: - err += sn9c102_i2c_write(cam, 0x06, ctrl->value); - break; - case V4L2_CID_SATURATION: - err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4); - break; - case V4L2_CID_HUE: - err += ctrl->value ? sn9c102_i2c_write(cam, 0x04, - (ctrl->value-1) | 0x20) - : sn9c102_i2c_write(cam, 0x04, 0x00); - break; - case V4L2_CID_DO_WHITE_BALANCE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - case V4L2_CID_WHITENESS: - err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78); - break; - case V4L2_CID_AUTOGAIN: - err += sn9c102_i2c_write(cam, 0x13, ctrl->value); - break; - case V4L2_CID_VFLIP: - err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); - break; - case V4L2_CID_BLACK_LEVEL: - err += sn9c102_i2c_write(cam, 0x25, ctrl->value); - break; - case SN9C102_V4L2_CID_BRIGHT_LEVEL: - err += sn9c102_i2c_write(cam, 0x24, ctrl->value); - break; - case SN9C102_V4L2_CID_GAMMA: - err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80); - break; - case SN9C102_V4L2_CID_BAND_FILTER: - err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int ov7630_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &ov7630; - int err = 0; - u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; - - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int ov7630_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x20, 0x19); - else - err += sn9c102_write_reg(cam, 0x50, 0x19); - - return err; -} - - -static struct sn9c102_sensor ov7630 = { - .name = "OV7630", - .maintainer = "Luca Risolia ", - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x21, - .init = &ov7630_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x14, - .flags = 0, - }, - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "hue", - .minimum = 0x00, - .maximum = 0x1f+1, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "saturation", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x08, - .flags = 0, - }, - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "contrast", - .minimum = 0x00, - .maximum = 0x1f+1, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x000, - .maximum = 0x3ff, - .step = 0x001, - .default_value = 0x83<<2, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x3a, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x77, - .flags = 0, - }, - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0xa0, - .flags = 0, - }, - { - .id = V4L2_CID_DO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "white balance background: blue", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_WHITENESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "white balance background: red", - .minimum = 0x00, - .maximum = 0x3f, - .step = 0x01, - .default_value = 0x20, - .flags = 0, - }, - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain & exposure mode", - .minimum = 0x00, - .maximum = 0x03, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - { - .id = V4L2_CID_BLACK_LEVEL, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "black pixel ratio", - .minimum = 0x01, - .maximum = 0x9a, - .step = 0x01, - .default_value = 0x8a, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_BRIGHT_LEVEL, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "bright pixel ratio", - .minimum = 0x01, - .maximum = 0x9a, - .step = 0x01, - .default_value = 0x10, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_BAND_FILTER, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "band filter", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "rgb gamma", - .minimum = 0x00, - .maximum = 0x01, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .set_ctrl = &ov7630_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &ov7630_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &ov7630_set_pix_format -}; - - -int sn9c102_probe_ov7630(struct sn9c102_device* cam) -{ - const struct usb_device_id ov7630_id_table[] = { - { USB_DEVICE(0x0c45, 0x602c), }, - { USB_DEVICE(0x0c45, 0x602d), }, - { USB_DEVICE(0x0c45, 0x608f), }, - { USB_DEVICE(0x0c45, 0x60b0), }, - { } - }; - int err = 0; - - if (!sn9c102_match_id(cam, ov7630_id_table)) - return -ENODEV; - - err += sn9c102_write_reg(cam, 0x01, 0x01); - err += sn9c102_write_reg(cam, 0x00, 0x01); - err += sn9c102_write_reg(cam, 0x28, 0x17); - if (err) - return -EIO; - - err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0); - if (err) - return -ENODEV; - - sn9c102_attach_sensor(cam, &ov7630); - - return 0; -} diff --git a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c deleted file mode 100644 index b1dee78abe04..000000000000 --- a/drivers/usb/media/sn9c102_pas106b.c +++ /dev/null @@ -1,307 +0,0 @@ -/*************************************************************************** - * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include "sn9c102_sensor.h" - - -static struct sn9c102_sensor pas106b; - - -static int pas106b_init(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x00, 0x10); - err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); - err += sn9c102_write_reg(cam, 0x20, 0x17); - err += sn9c102_write_reg(cam, 0x20, 0x19); - err += sn9c102_write_reg(cam, 0x09, 0x18); - - err += sn9c102_i2c_write(cam, 0x02, 0x0c); - err += sn9c102_i2c_write(cam, 0x05, 0x5a); - err += sn9c102_i2c_write(cam, 0x06, 0x88); - err += sn9c102_i2c_write(cam, 0x07, 0x80); - err += sn9c102_i2c_write(cam, 0x10, 0x06); - err += sn9c102_i2c_write(cam, 0x11, 0x06); - err += sn9c102_i2c_write(cam, 0x12, 0x00); - err += sn9c102_i2c_write(cam, 0x14, 0x02); - err += sn9c102_i2c_write(cam, 0x13, 0x01); - - msleep(400); - - return err; -} - - -static int pas106b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x03), - r2 = sn9c102_i2c_read(cam, 0x04); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 4) | (r2 & 0x0f); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case V4L2_CID_CONTRAST: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) - return -EIO; - ctrl->value &= 0x07; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0) - return -EIO; - ctrl->value = (ctrl->value & 0x1f) << 1; - return 0; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) - return -EIO; - ctrl->value &= 0xf8; - return 0; - default: - return -EINVAL; - } -} - - -static int pas106b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4); - err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x0e, ctrl->value); - break; - case V4L2_CID_CONTRAST: - err += sn9c102_i2c_write(cam, 0x0f, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1); - err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1); - break; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3); - break; - default: - return -EINVAL; - } - err += sn9c102_i2c_write(cam, 0x13, 0x01); - - return err ? -EIO : 0; -} - - -static int pas106b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &pas106b; - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static int pas106b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x2c, 0x17); - else - err += sn9c102_write_reg(cam, 0x20, 0x17); - - return err; -} - - -static struct sn9c102_sensor pas106b = { - .name = "PAS106B", - .maintainer = "Luca Risolia ", - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x40, - .init = &pas106b_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x125, - .maximum = 0xfff, - .step = 0x001, - .default_value = 0x140, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x0d, - .flags = 0, - }, - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "contrast", - .minimum = 0x00, - .maximum = 0x07, - .step = 0x01, - .default_value = 0x00, /* 0x00~0x03 have same effect */ - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x04, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x06, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x3e, - .step = 0x02, - .default_value = 0x02, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - }, - .get_ctrl = &pas106b_get_ctrl, - .set_ctrl = &pas106b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &pas106b_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, /* we use this field as 'bits per pixel' */ - }, - .set_pix_format = &pas106b_set_pix_format -}; - - -int sn9c102_probe_pas106b(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0, err = 0; - unsigned int pid = 0; - - /* - Minimal initialization to enable the I2C communication - NOTE: do NOT change the values! - */ - err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ - err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ - err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ - if (err) - return -EIO; - - r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00); - r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01); - - if (r0 < 0 || r1 < 0) - return -EIO; - - pid = (r0 << 11) | ((r1 & 0xf0) >> 4); - if (pid != 0x007) - return -ENODEV; - - sn9c102_attach_sensor(cam, &pas106b); - - return 0; -} diff --git a/drivers/usb/media/sn9c102_pas202bca.c b/drivers/usb/media/sn9c102_pas202bca.c deleted file mode 100644 index 3453237055bb..000000000000 --- a/drivers/usb/media/sn9c102_pas202bca.c +++ /dev/null @@ -1,238 +0,0 @@ -/*************************************************************************** - * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera * - * Controllers * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include "sn9c102_sensor.h" - - -static struct sn9c102_sensor pas202bca; - - -static int pas202bca_init(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x00, 0x10); - err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); - err += sn9c102_write_reg(cam, 0x20, 0x17); - err += sn9c102_write_reg(cam, 0x30, 0x19); - err += sn9c102_write_reg(cam, 0x09, 0x18); - - err += sn9c102_i2c_write(cam, 0x02, 0x14); - err += sn9c102_i2c_write(cam, 0x03, 0x40); - err += sn9c102_i2c_write(cam, 0x0d, 0x2c); - err += sn9c102_i2c_write(cam, 0x0e, 0x01); - err += sn9c102_i2c_write(cam, 0x0f, 0xa9); - err += sn9c102_i2c_write(cam, 0x10, 0x08); - err += sn9c102_i2c_write(cam, 0x13, 0x63); - err += sn9c102_i2c_write(cam, 0x15, 0x70); - err += sn9c102_i2c_write(cam, 0x11, 0x01); - - msleep(400); - - return err; -} - - -static int pas202bca_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x24, 0x17); - else - err += sn9c102_write_reg(cam, 0x20, 0x17); - - return err; -} - - -static int pas202bca_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); - err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x07, ctrl->value); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x08, ctrl->value); - break; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - default: - return -EINVAL; - } - err += sn9c102_i2c_write(cam, 0x11, 0x01); - - return err ? -EIO : 0; -} - - -static int pas202bca_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &pas202bca; - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static struct sn9c102_sensor pas202bca = { - .name = "PAS202BCA", - .maintainer = "Luca Risolia ", - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x40, - .init = &pas202bca_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x01e5, - .maximum = 0x3fff, - .step = 0x0001, - .default_value = 0x01e5, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x0c, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x05, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x04, - .flags = 0, - }, - }, - .set_ctrl = &pas202bca_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &pas202bca_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &pas202bca_set_pix_format -}; - - -int sn9c102_probe_pas202bca(struct sn9c102_device* cam) -{ - const struct usb_device_id pas202bca_id_table[] = { - { USB_DEVICE(0x0c45, 0x60af), }, - { } - }; - int err = 0; - - if (!sn9c102_match_id(cam,pas202bca_id_table)) - return -ENODEV; - - err += sn9c102_write_reg(cam, 0x01, 0x01); - err += sn9c102_write_reg(cam, 0x40, 0x01); - err += sn9c102_write_reg(cam, 0x28, 0x17); - if (err) - return -EIO; - - if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */ - return -ENODEV; - - sn9c102_attach_sensor(cam, &pas202bca); - - return 0; -} diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c deleted file mode 100644 index d068616ab337..000000000000 --- a/drivers/usb/media/sn9c102_pas202bcb.c +++ /dev/null @@ -1,293 +0,0 @@ -/*************************************************************************** - * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera * - * Controllers * - * * - * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * - * * - * http://cadu.homelinux.com:8080/ * - * * - * DAC Magnitude, exposure and green gain controls added by * - * Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include "sn9c102_sensor.h" - - -static struct sn9c102_sensor pas202bcb; - - -static int pas202bcb_init(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x00, 0x10); - err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); - err += sn9c102_write_reg(cam, 0x20, 0x17); - err += sn9c102_write_reg(cam, 0x30, 0x19); - err += sn9c102_write_reg(cam, 0x09, 0x18); - - err += sn9c102_i2c_write(cam, 0x02, 0x14); - err += sn9c102_i2c_write(cam, 0x03, 0x40); - err += sn9c102_i2c_write(cam, 0x0d, 0x2c); - err += sn9c102_i2c_write(cam, 0x0e, 0x01); - err += sn9c102_i2c_write(cam, 0x0f, 0xa9); - err += sn9c102_i2c_write(cam, 0x10, 0x08); - err += sn9c102_i2c_write(cam, 0x13, 0x63); - err += sn9c102_i2c_write(cam, 0x15, 0x70); - err += sn9c102_i2c_write(cam, 0x11, 0x01); - - msleep(400); - - return err; -} - - -static int pas202bcb_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = sn9c102_i2c_read(cam, 0x04), - r2 = sn9c102_i2c_read(cam, 0x05); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 6) | (r2 & 0x3f); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case V4L2_CID_GAIN: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case SN9C102_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) - return -EIO; - return 0; - default: - return -EINVAL; - } -} - - -static int pas202bcb_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x24, 0x17); - else - err += sn9c102_write_reg(cam, 0x20, 0x17); - - return err; -} - - -static int pas202bcb_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6); - err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f); - break; - case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x07, ctrl->value); - break; - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value); - break; - case SN9C102_V4L2_CID_GREEN_BALANCE: - err += sn9c102_i2c_write(cam, 0x08, ctrl->value); - break; - case SN9C102_V4L2_CID_DAC_MAGNITUDE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); - break; - default: - return -EINVAL; - } - err += sn9c102_i2c_write(cam, 0x11, 0x01); - - return err ? -EIO : 0; -} - - -static int pas202bcb_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &pas202bcb; - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - - -static struct sn9c102_sensor pas202bcb = { - .name = "PAS202BCB", - .maintainer = "Carlos Eduardo Medaglia Dyonisio " - "", - .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x40, - .init = &pas202bcb_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x01e5, - .maximum = 0x3fff, - .step = 0x0001, - .default_value = 0x01e5, - .flags = 0, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x0c, - .flags = 0, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x01, - .flags = 0, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x05, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - { - .id = SN9C102_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x04, - .flags = 0, - }, - }, - .get_ctrl = &pas202bcb_get_ctrl, - .set_ctrl = &pas202bcb_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &pas202bcb_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &pas202bcb_set_pix_format -}; - - -int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) -{ - int r0 = 0, r1 = 0, err = 0; - unsigned int pid = 0; - - /* - * Minimal initialization to enable the I2C communication - * NOTE: do NOT change the values! - */ - err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ - err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */ - err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ - if (err) - return -EIO; - - r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); - r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); - - if (r0 < 0 || r1 < 0) - return -EIO; - - pid = (r0 << 4) | ((r1 & 0xf0) >> 4); - if (pid != 0x017) - return -ENODEV; - - sn9c102_attach_sensor(cam, &pas202bcb); - - return 0; -} diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h deleted file mode 100644 index 2afd9e9d09bb..000000000000 --- a/drivers/usb/media/sn9c102_sensor.h +++ /dev/null @@ -1,389 +0,0 @@ -/*************************************************************************** - * API for image sensors connected to the SN9C10x PC Camera Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _SN9C102_SENSOR_H_ -#define _SN9C102_SENSOR_H_ - -#include -#include -#include -#include -#include -#include - -struct sn9c102_device; -struct sn9c102_sensor; - -/*****************************************************************************/ - -/* - OVERVIEW. - This is a small interface that allows you to add support for any CCD/CMOS - image sensors connected to the SN9C10X bridges. The entire API is documented - below. In the most general case, to support a sensor there are three steps - you have to follow: - 1) define the main "sn9c102_sensor" structure by setting the basic fields; - 2) write a probing function to be called by the core module when the USB - camera is recognized, then add both the USB ids and the name of that - function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see - below); - 3) implement the methods that you want/need (and fill the rest of the main - structure accordingly). - "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do - NOT need to touch the source code of the core module for the things to work - properly, unless you find bugs or flaws in it. Finally, do not forget to - read the V4L2 API for completeness. -*/ - -/*****************************************************************************/ - -/* - Probing functions: on success, you must attach the sensor to the camera - by calling sn9c102_attach_sensor() provided below. - To enable the I2C communication, you might need to perform a really basic - initialization of the SN9C10X chip by using the write function declared - ahead. - Functions must return 0 on success, the appropriate error otherwise. -*/ -extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); -extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); -extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); -extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); -extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam); -extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); -extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); - -/* - Add the above entries to this table. Be sure to add the entry in the right - place, since, on failure, the next probing routine is called according to - the order of the list below, from top to bottom. -*/ -#define SN9C102_SENSOR_TABLE \ -static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ - &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ \ - &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ - &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ - &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \ - &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \ - &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \ - &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ - &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ - NULL, \ -}; - -/* Device identification */ -extern struct sn9c102_device* -sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id); - -/* Attach a probed sensor to the camera. */ -extern void -sn9c102_attach_sensor(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor); - -/* - Each SN9C10x camera has proper PID/VID identifiers. - SN9C103 supports multiple interfaces, but we only handle the video class - interface. -*/ -#define SN9C102_USB_DEVICE(vend, prod, intclass) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_INT_CLASS, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bInterfaceClass = (intclass) - -#define SN9C102_ID_TABLE \ -static const struct usb_device_id sn9c102_id_table[] = { \ - { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \ - { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \ - { USB_DEVICE(0x0c45, 0x6007), }, \ - { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \ - { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \ - { USB_DEVICE(0x0c45, 0x6024), }, \ - { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ - { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \ - { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ - { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \ - { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \ - { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \ - { USB_DEVICE(0x0c45, 0x602d), }, \ - { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */ \ - { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */ \ - { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), }, \ - { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), }, \ - { } \ -}; - -/*****************************************************************************/ - -/* - Read/write routines: they always return -1 on error, 0 or the read value - otherwise. NOTE that a real read operation is not supported by the SN9C10X - chip for some of its registers. To work around this problem, a pseudo-read - call is provided instead: it returns the last successfully written value - on the register (0 if it has never been written), the usual -1 on error. -*/ - -/* The "try" I2C I/O versions are used when probing the sensor */ -extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, - u8 address, u8 value); -extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, - u8 address); - -/* - These must be used if and only if the sensor doesn't implement the standard - I2C protocol. There are a number of good reasons why you must use the - single-byte versions of these functions: do not abuse. The first function - writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X - chip. The second one programs the registers 0x09 and 0x10 with data0 and - data1, and places the n bytes read from the sensor register table in the - buffer pointed by 'buffer'. Both the functions return -1 on error; the write - version returns 0 on success, while the read version returns the first read - byte. -*/ -extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor, u8 n, - u8 data0, u8 data1, u8 data2, u8 data3, - u8 data4, u8 data5); -extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam, - struct sn9c102_sensor* sensor, u8 data0, - u8 data1, u8 n, u8 buffer[]); - -/* To be used after the sensor struct has been attached to the camera struct */ -extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); -extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); - -/* I/O on registers in the bridge. Could be used by the sensor methods too */ -extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index); -extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); -extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); - -/* - NOTE: there are no exported debugging functions. To uniform the output you - must use the dev_info()/dev_warn()/dev_err() macros defined in device.h, - already included here, the argument being the struct device '&usbdev->dev' - of the sensor structure. Do NOT use these macros before the sensor is - attached or the kernel will crash! However, you should not need to notify - the user about common errors or other messages, since this is done by the - master module. -*/ - -/*****************************************************************************/ - -enum sn9c102_i2c_sysfs_ops { - SN9C102_I2C_READ = 0x01, - SN9C102_I2C_WRITE = 0x02, -}; - -enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */ - SN9C102_I2C_100KHZ = 0x01, - SN9C102_I2C_400KHZ = 0x02, -}; - -enum sn9c102_i2c_interface { - SN9C102_I2C_2WIRES, - SN9C102_I2C_3WIRES, -}; - -#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 - -struct sn9c102_sensor { - char name[32], /* sensor name */ - maintainer[64]; /* name of the mantainer */ - - /* Supported operations through the 'sysfs' interface */ - enum sn9c102_i2c_sysfs_ops sysfs_ops; - - /* - These sensor capabilities must be provided if the SN9C10X controller - needs to communicate through the sensor serial interface by using - at least one of the i2c functions available. - */ - enum sn9c102_i2c_frequency frequency; - enum sn9c102_i2c_interface interface; - - /* - This identifier must be provided if the image sensor implements - the standard I2C protocol. - */ - u8 i2c_slave_id; /* reg. 0x09 */ - - /* - NOTE: Where not noted,most of the functions below are not mandatory. - Set to null if you do not implement them. If implemented, - they must return 0 on success, the proper error otherwise. - */ - - int (*init)(struct sn9c102_device* cam); - /* - This function will be called after the sensor has been attached. - It should be used to initialize the sensor only, but may also - configure part of the SN9C10X chip if necessary. You don't need to - setup picture settings like brightness, contrast, etc.. here, if - the corrisponding controls are implemented (see below), since - they are adjusted in the core driver by calling the set_ctrl() - method after init(), where the arguments are the default values - specified in the v4l2_queryctrl list of supported controls; - Same suggestions apply for other settings, _if_ the corresponding - methods are present; if not, the initialization must configure the - sensor according to the default configuration structures below. - */ - - struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; - /* - Optional list of default controls, defined as indicated in the - V4L2 API. Menu type controls are not handled by this interface. - */ - - int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); - int (*set_ctrl)(struct sn9c102_device* cam, - const struct v4l2_control* ctrl); - /* - You must implement at least the set_ctrl method if you have defined - the list above. The returned value must follow the V4L2 - specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER - are not supported by this driver, so do not implement them. Also, - you don't have to check whether the passed values are out of bounds, - given that this is done by the core module. - */ - - struct v4l2_cropcap cropcap; - /* - Think the image sensor as a grid of R,G,B monochromatic pixels - disposed according to a particular Bayer pattern, which describes - the complete array of pixels, from (0,0) to (xmax, ymax). We will - use this coordinate system from now on. It is assumed the sensor - chip can be programmed to capture/transmit a subsection of that - array of pixels: we will call this subsection "active window". - It is not always true that the largest achievable active window can - cover the whole array of pixels. The V4L2 API defines another - area called "source rectangle", which, in turn, is a subrectangle of - the active window. The SN9C10X chip is always programmed to read the - source rectangle. - The bounds of both the active window and the source rectangle are - specified in the cropcap substructures 'bounds' and 'defrect'. - By default, the source rectangle should cover the largest possible - area. Again, it is not always true that the largest source rectangle - can cover the entire active window, although it is a rare case for - the hardware we have. The bounds of the source rectangle _must_ be - multiple of 16 and must use the same coordinate system as indicated - before; their centers shall align initially. - If necessary, the sensor chip must be initialized during init() to - set the bounds of the active sensor window; however, by default, it - usually covers the largest achievable area (maxwidth x maxheight) - of pixels, so no particular initialization is needed, if you have - defined the correct default bounds in the structures. - See the V4L2 API for further details. - NOTE: once you have defined the bounds of the active window - (struct cropcap.bounds) you must not change them.anymore. - Only 'bounds' and 'defrect' fields are mandatory, other fields - will be ignored. - */ - - int (*set_crop)(struct sn9c102_device* cam, - const struct v4l2_rect* rect); - /* - To be called on VIDIOC_C_SETCROP. The core module always calls a - default routine which configures the appropriate SN9C10X regs (also - scaling), but you may need to override/adjust specific stuff. - 'rect' contains width and height values that are multiple of 16: in - case you override the default function, you always have to program - the chip to match those values; on error return the corresponding - error code without rolling back. - NOTE: in case, you must program the SN9C10X chip to get rid of - blank pixels or blank lines at the _start_ of each line or - frame after each HSYNC or VSYNC, so that the image starts with - real RGB data (see regs 0x12, 0x13) (having set H_SIZE and, - V_SIZE you don't have to care about blank pixels or blank - lines at the end of each line or frame). - */ - - struct v4l2_pix_format pix_format; - /* - What you have to define here are: 1) initial 'width' and 'height' of - the target rectangle 2) the initial 'pixelformat', which can be - either V4L2_PIX_FMT_SN9C10X (for compressed video) or - V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the - number of bits per pixel for uncompressed video, 8 or 9 (despite the - current value of 'pixelformat'). - NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4 - of cropcap.defrect.width and cropcap.defrect.height. I - suggest 1/1. - NOTE 2: The initial compression quality is defined by the first bit - of reg 0x17 during the initialization of the image sensor. - NOTE 3: as said above, you have to program the SN9C10X chip to get - rid of any blank pixels, so that the output of the sensor - matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). - */ - - int (*set_pix_format)(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix); - /* - To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to - SN9C10X pixel format or viceversa. On error return the corresponding - error code without rolling back. - */ - - /* - Do NOT write to the data below, it's READ ONLY. It is used by the - core module to store successfully updated values of the above - settings, for rollbacks..etc..in case of errors during atomic I/O - */ - struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; - struct v4l2_rect _rect; -}; - -/*****************************************************************************/ - -/* Private ioctl's for control settings supported by some image sensors */ -#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE -#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 -#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2 -#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3 -#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4 -#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5 -#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6 - -#endif /* _SN9C102_SENSOR_H_ */ diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c deleted file mode 100644 index 2e08c552f40a..000000000000 --- a/drivers/usb/media/sn9c102_tas5110c1b.c +++ /dev/null @@ -1,159 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" - - -static struct sn9c102_sensor tas5110c1b; - - -static int tas5110c1b_init(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x01, 0x01); - err += sn9c102_write_reg(cam, 0x44, 0x01); - err += sn9c102_write_reg(cam, 0x00, 0x10); - err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x0a, 0x14); - err += sn9c102_write_reg(cam, 0x60, 0x17); - err += sn9c102_write_reg(cam, 0x06, 0x18); - err += sn9c102_write_reg(cam, 0xfb, 0x19); - - err += sn9c102_i2c_write(cam, 0xc0, 0x80); - - return err; -} - - -static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int tas5110c1b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &tas5110c1b; - int err = 0; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - /* Don't change ! */ - err += sn9c102_write_reg(cam, 0x14, 0x1a); - err += sn9c102_write_reg(cam, 0x0a, 0x1b); - err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); - - return err; -} - - -static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x2b, 0x19); - else - err += sn9c102_write_reg(cam, 0xfb, 0x19); - - return err; -} - - -static struct sn9c102_sensor tas5110c1b = { - .name = "TAS5110C1B", - .maintainer = "Luca Risolia ", - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_3WIRES, - .init = &tas5110c1b_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xf6, - .step = 0x01, - .default_value = 0x40, - .flags = 0, - }, - }, - .set_ctrl = &tas5110c1b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 352, - .height = 288, - }, - }, - .set_crop = &tas5110c1b_set_crop, - .pix_format = { - .width = 352, - .height = 288, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5110c1b_set_pix_format -}; - - -int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5110c1b_id_table[] = { - { USB_DEVICE(0x0c45, 0x6001), }, - { USB_DEVICE(0x0c45, 0x6005), }, - { USB_DEVICE(0x0c45, 0x60ab), }, - { } - }; - - /* Sensor detection is based on USB pid/vid */ - if (!sn9c102_match_id(cam, tas5110c1b_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5110c1b); - - return 0; -} diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c deleted file mode 100644 index c7b339740bbf..000000000000 --- a/drivers/usb/media/sn9c102_tas5130d1b.c +++ /dev/null @@ -1,169 +0,0 @@ -/*************************************************************************** - * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera * - * Controllers * - * * - * Copyright (C) 2004-2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include "sn9c102_sensor.h" - - -static struct sn9c102_sensor tas5130d1b; - - -static int tas5130d1b_init(struct sn9c102_device* cam) -{ - int err = 0; - - err += sn9c102_write_reg(cam, 0x01, 0x01); - err += sn9c102_write_reg(cam, 0x20, 0x17); - err += sn9c102_write_reg(cam, 0x04, 0x01); - err += sn9c102_write_reg(cam, 0x01, 0x10); - err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); - err += sn9c102_write_reg(cam, 0x60, 0x17); - err += sn9c102_write_reg(cam, 0x07, 0x18); - - return err; -} - - -static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); - break; - case V4L2_CID_EXPOSURE: - err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - - -static int tas5130d1b_set_crop(struct sn9c102_device* cam, - const struct v4l2_rect* rect) -{ - struct sn9c102_sensor* s = &tas5130d1b; - u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, - v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; - int err = 0; - - err += sn9c102_write_reg(cam, h_start, 0x12); - err += sn9c102_write_reg(cam, v_start, 0x13); - - /* Do NOT change! */ - err += sn9c102_write_reg(cam, 0x1f, 0x1a); - err += sn9c102_write_reg(cam, 0x1a, 0x1b); - err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19); - - return err; -} - - -static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, - const struct v4l2_pix_format* pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) - err += sn9c102_write_reg(cam, 0x63, 0x19); - else - err += sn9c102_write_reg(cam, 0xf3, 0x19); - - return err; -} - - -static struct sn9c102_sensor tas5130d1b = { - .name = "TAS5130D1B", - .maintainer = "Luca Risolia ", - .sysfs_ops = SN9C102_I2C_WRITE, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_3WIRES, - .init = &tas5130d1b_init, - .qctrl = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0xf6, - .step = 0x02, - .default_value = 0x00, - .flags = 0, - }, - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x47, - .step = 0x01, - .default_value = 0x00, - .flags = 0, - }, - }, - .set_ctrl = &tas5130d1b_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &tas5130d1b_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &tas5130d1b_set_pix_format -}; - - -int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam) -{ - const struct usb_device_id tas5130d1b_id_table[] = { - { USB_DEVICE(0x0c45, 0x6025), }, - { USB_DEVICE(0x0c45, 0x60aa), }, - { } - }; - - /* Sensor detection is based on USB pid/vid */ - if (!sn9c102_match_id(cam, tas5130d1b_id_table)) - return -ENODEV; - - sn9c102_attach_sensor(cam, &tas5130d1b); - - return 0; -} diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c deleted file mode 100644 index 9636da20748d..000000000000 --- a/drivers/usb/media/stv680.c +++ /dev/null @@ -1,1508 +0,0 @@ -/* - * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net) - * - * Thanks to STMicroelectronics for information on the usb commands, and - * to Steve Miller at STM for his help and encouragement while I was - * writing this driver. - * - * This driver is based heavily on the - * Endpoints (formerly known as AOX) se401 USB Camera Driver - * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) - * - * Still somewhat based on the Linux ov511 driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: - * ver 0.1 October, 2001. Initial attempt. - * - * ver 0.2 November, 2001. Fixed asbility to resize, added brightness - * function, made more stable (?) - * - * ver 0.21 Nov, 2001. Added gamma correction and white balance, - * due to Alexander Schwartz. Still trying to - * improve stablility. Moved stuff into stv680.h - * - * ver 0.22 Nov, 2001. Added sharpen function (by Michael Sweet, - * mike@easysw.com) from GIMP, also used in pencam. - * Simple, fast, good integer math routine. - * - * ver 0.23 Dec, 2001 (gkh) - * Took out sharpen function, ran code through - * Lindent, and did other minor tweaks to get - * things to work properly with 2.5.1 - * - * ver 0.24 Jan, 2002 (kjs) - * Fixed the problem with webcam crashing after - * two pictures. Changed the way pic is halved to - * improve quality. Got rid of green line around - * frame. Fix brightness reset when changing size - * bug. Adjusted gamma filters slightly. - * - * ver 0.25 Jan, 2002 (kjs) - * Fixed a bug in which the driver sometimes attempted - * to set to a non-supported size. This allowed - * gnomemeeting to work. - * Fixed proc entry removal bug. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stv680.h" - -static int video_nr = -1; -static int swapRGB = 0; /* default for auto sleect */ -static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */ - -static unsigned int debug = 0; - -#define PDEBUG(level, fmt, args...) \ - do { \ - if (debug >= level) \ - info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \ - } while (0) - - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.25" -#define DRIVER_AUTHOR "Kevin Sisson " -#define DRIVER_DESC "STV0680 USB Camera Driver" - -MODULE_AUTHOR (DRIVER_AUTHOR); -MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_LICENSE ("GPL"); -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC (debug, "Debug enabled or not"); -module_param(swapRGB_on, int, 0); -MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); -module_param(video_nr, int, 0); - -/******************************************************************** - * - * Memory management - * - * This is a shameless copy from the USB-cpia driver (linux kernel - * version 2.3.29 or so, I have no idea what this code actually does ;). - * Actually it seems to be a copy of a shameless copy of the bttv-driver. - * Or that is a copy of a shameless copy of ... (To the powers: is there - * no generic kernel-function to do this sort of stuff?) - * - * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says - * there will be one, but apparentely not yet -jerdfelt - * - * So I copied it again for the ov511 driver -claudio - * - * Same for the se401 driver -Jeroen - * - * And the STV0680 driver - Kevin - ********************************************************************/ -static void *rvmalloc (unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32 (size); - if (!mem) - return NULL; - - memset (mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - return mem; -} - -static void rvfree (void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree (mem); -} - - -/********************************************************************* - * pencam read/write functions - ********************************************************************/ - -static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size) -{ - int ret = -1; - - switch (set) { - case 0: /* 0xc1 */ - ret = usb_control_msg (stv680->udev, - usb_rcvctrlpipe (stv680->udev, 0), - req, - (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), - value, 0, buffer, size, PENCAM_TIMEOUT); - break; - - case 1: /* 0x41 */ - ret = usb_control_msg (stv680->udev, - usb_sndctrlpipe (stv680->udev, 0), - req, - (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT), - value, 0, buffer, size, PENCAM_TIMEOUT); - break; - - case 2: /* 0x80 */ - ret = usb_control_msg (stv680->udev, - usb_rcvctrlpipe (stv680->udev, 0), - req, - (USB_DIR_IN | USB_RECIP_DEVICE), - value, 0, buffer, size, PENCAM_TIMEOUT); - break; - - case 3: /* 0x40 */ - ret = usb_control_msg (stv680->udev, - usb_sndctrlpipe (stv680->udev, 0), - req, - (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), - value, 0, buffer, size, PENCAM_TIMEOUT); - break; - - } - if ((ret < 0) && (req != 0x0a)) { - PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret); - } - return ret; -} - -static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate) -{ - - if (configuration != dev->udev->actconfig->desc.bConfigurationValue - || usb_reset_configuration (dev->udev) < 0) { - PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration); - return -1; - } - if (usb_set_interface (dev->udev, interface, alternate) < 0) { - PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate); - return -1; - } - return 0; -} - -static int stv_stop_video (struct usb_stv *dev) -{ - int i; - unsigned char *buf; - - buf = kmalloc (40, GFP_KERNEL); - if (buf == NULL) { - PDEBUG (0, "STV(e): Out of (small buf) memory"); - return -1; - } - - /* this is a high priority command; it stops all lower order commands */ - if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) { - i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */ - PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]); - } else { - PDEBUG (1, "STV(i): Camera reset to idle mode."); - } - - if ((i = stv_set_config (dev, 1, 0, 0)) < 0) - PDEBUG (1, "STV(e): Reset config during exit failed"); - - /* get current mode */ - buf[0] = 0xf0; - if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */ - PDEBUG (0, "STV(e): Stop_video: problem setting original mode"); - if (dev->origMode != buf[0]) { - memset (buf, 0, 8); - buf[0] = (unsigned char) dev->origMode; - if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) { - PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed"); - i = -1; - } - buf[0] = 0xf0; - i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08); - if ((i != 0x08) || (buf[0] != dev->origMode)) { - PDEBUG (0, "STV(e): camera NOT set to original resolution."); - i = -1; - } else - PDEBUG (0, "STV(i): Camera set to original resolution"); - } - /* origMode */ - kfree(buf); - return i; -} - -static int stv_set_video_mode (struct usb_stv *dev) -{ - int i, stop_video = 1; - unsigned char *buf; - - buf = kmalloc (40, GFP_KERNEL); - if (buf == NULL) { - PDEBUG (0, "STV(e): Out of (small buf) memory"); - return -1; - } - - if ((i = stv_set_config (dev, 1, 0, 0)) < 0) { - kfree(buf); - return i; - } - - i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12); - if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) { - PDEBUG (1, "STV(e): Could not get descriptor 0100."); - goto error; - } - - /* set alternate interface 1 */ - if ((i = stv_set_config (dev, 1, 0, 1)) < 0) - goto error; - - if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10) - goto error; - PDEBUG (1, "STV(i): Setting video mode."); - /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */ - if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) { - stop_video = 0; - goto error; - } - goto exit; - -error: - kfree(buf); - if (stop_video == 1) - stv_stop_video (dev); - return -1; - -exit: - kfree(buf); - return 0; -} - -static int stv_init (struct usb_stv *stv680) -{ - int i = 0; - unsigned char *buffer; - unsigned long int bufsize; - - buffer = kzalloc (40, GFP_KERNEL); - if (buffer == NULL) { - PDEBUG (0, "STV(e): Out of (small buf) memory"); - return -1; - } - udelay (100); - - /* set config 1, interface 0, alternate 0 */ - if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) { - kfree(buffer); - PDEBUG (0, "STV(e): set config 1,0,0 failed"); - return -1; - } - /* ping camera to be sure STV0680 is present */ - if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02) - goto error; - if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) { - PDEBUG (1, "STV(e): camera ping failed!!"); - goto error; - } - - /* get camera descriptor */ - if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09) - goto error; - i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22); - if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) { - PDEBUG (1, "STV(e): Could not get descriptor 0200."); - goto error; - } - if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02) - goto error; - if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24) - goto error; - if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) - goto error; - - stv680->SupportedModes = buffer[7]; - i = stv680->SupportedModes; - stv680->CIF = 0; - stv680->VGA = 0; - stv680->QVGA = 0; - if (i & 1) - stv680->CIF = 1; - if (i & 2) - stv680->VGA = 1; - if (i & 8) - stv680->QVGA = 1; - if (stv680->SupportedModes == 0) { - PDEBUG (0, "STV(e): There are NO supported STV680 modes!!"); - i = -1; - goto error; - } else { - if (stv680->CIF) - PDEBUG (0, "STV(i): CIF is supported"); - if (stv680->QVGA) - PDEBUG (0, "STV(i): QVGA is supported"); - } - /* FW rev, ASIC rev, sensor ID */ - PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]); - PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]); - PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4)); - - /* set alternate interface 1 */ - if ((i = stv_set_config (stv680, 1, 0, 1)) < 0) - goto error; - - if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10) - goto error; - if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08) - goto error; - i = buffer[3]; - PDEBUG (0, "STV(i): Camera has %i pictures.", i); - - /* get current mode */ - if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08) - goto error; - stv680->origMode = buffer[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */ - - /* This will attemp CIF mode, if supported. If not, set to QVGA */ - memset (buffer, 0, 8); - if (stv680->CIF) - buffer[0] = 0x00; - else if (stv680->QVGA) - buffer[0] = 0x03; - if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) { - PDEBUG (0, "STV(i): Set_Camera_Mode failed"); - i = -1; - goto error; - } - buffer[0] = 0xf0; - stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08); - if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) { - PDEBUG (0, "STV(e): Error setting camera video mode!"); - i = -1; - goto error; - } else { - if (buffer[0] == 0) { - stv680->VideoMode = 0x0000; - PDEBUG (0, "STV(i): Video Mode set to CIF"); - } - if (buffer[0] == 0x03) { - stv680->VideoMode = 0x0300; - PDEBUG (0, "STV(i): Video Mode set to QVGA"); - } - } - if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10) - goto error; - bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]); - stv680->cwidth = (buffer[4] << 8) | (buffer[5]); /* ->camera = 322, 356, 644 */ - stv680->cheight = (buffer[6] << 8) | (buffer[7]); /* ->camera = 242, 292, 484 */ - stv680->origGain = buffer[12]; - - goto exit; - -error: - i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */ - PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]); - kfree(buffer); - return -1; - -exit: - kfree(buffer); - - /* video = 320x240, 352x288 */ - if (stv680->CIF == 1) { - stv680->maxwidth = 352; - stv680->maxheight = 288; - stv680->vwidth = 352; - stv680->vheight = 288; - } - if (stv680->QVGA == 1) { - stv680->maxwidth = 320; - stv680->maxheight = 240; - stv680->vwidth = 320; - stv680->vheight = 240; - } - - stv680->rawbufsize = bufsize; /* must be ./. by 8 */ - stv680->maxframesize = bufsize * 3; /* RGB size */ - PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight); - PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize); - - /* some default values */ - stv680->bulk_in_endpointAddr = 0x82; - stv680->dropped = 0; - stv680->error = 0; - stv680->framecount = 0; - stv680->readcount = 0; - stv680->streaming = 0; - /* bright, white, colour, hue, contrast are set by software, not in stv0680 */ - stv680->brightness = 32767; - stv680->chgbright = 0; - stv680->whiteness = 0; /* only for greyscale */ - stv680->colour = 32767; - stv680->contrast = 32767; - stv680->hue = 32767; - stv680->palette = STV_VIDEO_PALETTE; - stv680->depth = 24; /* rgb24 bits */ - if ((swapRGB_on == 0) && (swapRGB == 0)) - PDEBUG (1, "STV(i): swapRGB is (auto) OFF"); - else if ((swapRGB_on == 0) && (swapRGB == 1)) - PDEBUG (1, "STV(i): swapRGB is (auto) ON"); - else if (swapRGB_on == 1) - PDEBUG (1, "STV(i): swapRGB is (forced) ON"); - else if (swapRGB_on == -1) - PDEBUG (1, "STV(i): swapRGB is (forced) OFF"); - - if (stv_set_video_mode (stv680) < 0) { - PDEBUG (0, "STV(e): Could not set video mode in stv_init"); - return -1; - } - - return 0; -} - -/***************** last of pencam routines *******************/ - -/**************************************************************************** - * sysfs - ***************************************************************************/ -#define stv680_file(name, variable, field) \ -static ssize_t show_##name(struct class_device *class_dev, char *buf) \ -{ \ - struct video_device *vdev = to_video_device(class_dev); \ - struct usb_stv *stv = video_get_drvdata(vdev); \ - return sprintf(buf, field, stv->variable); \ -} \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); - -stv680_file(model, camera_name, "%s\n"); -stv680_file(in_use, user, "%d\n"); -stv680_file(streaming, streaming, "%d\n"); -stv680_file(palette, palette, "%i\n"); -stv680_file(frames_total, readcount, "%d\n"); -stv680_file(frames_read, framecount, "%d\n"); -stv680_file(packets_dropped, dropped, "%d\n"); -stv680_file(decoding_errors, error, "%d\n"); - -static void stv680_create_sysfs_files(struct video_device *vdev) -{ - video_device_create_file(vdev, &class_device_attr_model); - video_device_create_file(vdev, &class_device_attr_in_use); - video_device_create_file(vdev, &class_device_attr_streaming); - video_device_create_file(vdev, &class_device_attr_palette); - video_device_create_file(vdev, &class_device_attr_frames_total); - video_device_create_file(vdev, &class_device_attr_frames_read); - video_device_create_file(vdev, &class_device_attr_packets_dropped); - video_device_create_file(vdev, &class_device_attr_decoding_errors); -} - -static void stv680_remove_sysfs_files(struct video_device *vdev) -{ - video_device_remove_file(vdev, &class_device_attr_model); - video_device_remove_file(vdev, &class_device_attr_in_use); - video_device_remove_file(vdev, &class_device_attr_streaming); - video_device_remove_file(vdev, &class_device_attr_palette); - video_device_remove_file(vdev, &class_device_attr_frames_total); - video_device_remove_file(vdev, &class_device_attr_frames_read); - video_device_remove_file(vdev, &class_device_attr_packets_dropped); - video_device_remove_file(vdev, &class_device_attr_decoding_errors); -} - -/******************************************************************** - * Camera control - *******************************************************************/ - -static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p) -{ - /* This sets values for v4l interface. max/min = 65535/0 */ - - p->brightness = stv680->brightness; - p->whiteness = stv680->whiteness; /* greyscale */ - p->colour = stv680->colour; - p->contrast = stv680->contrast; - p->hue = stv680->hue; - p->palette = stv680->palette; - p->depth = stv680->depth; - return 0; -} - -static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p) -{ - /* See above stv680_get_pict */ - - if (p->palette != STV_VIDEO_PALETTE) { - PDEBUG (2, "STV(e): Palette set error in _set_pic"); - return 1; - } - - if (stv680->brightness != p->brightness) { - stv680->chgbright = 1; - stv680->brightness = p->brightness; - } - - stv680->whiteness = p->whiteness; /* greyscale */ - stv680->colour = p->colour; - stv680->contrast = p->contrast; - stv680->hue = p->hue; - stv680->palette = p->palette; - stv680->depth = p->depth; - - return 0; -} - -static void stv680_video_irq (struct urb *urb, struct pt_regs *regs) -{ - struct usb_stv *stv680 = urb->context; - int length = urb->actual_length; - - if (length < stv680->rawbufsize) - PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length); - - /* ohoh... */ - if (!stv680->streaming) - return; - - if (!stv680->udev) { - PDEBUG (0, "STV(e): device vapourished in video_irq"); - return; - } - - /* 0 sized packets happen if we are to fast, but sometimes the camera - keeps sending them forever... - */ - if (length && !urb->status) { - stv680->nullpackets = 0; - switch (stv680->scratch[stv680->scratch_next].state) { - case BUFFER_READY: - case BUFFER_BUSY: - stv680->dropped++; - break; - - case BUFFER_UNUSED: - memcpy (stv680->scratch[stv680->scratch_next].data, - (unsigned char *) urb->transfer_buffer, length); - stv680->scratch[stv680->scratch_next].state = BUFFER_READY; - stv680->scratch[stv680->scratch_next].length = length; - if (waitqueue_active (&stv680->wq)) { - wake_up_interruptible (&stv680->wq); - } - stv680->scratch_overflow = 0; - stv680->scratch_next++; - if (stv680->scratch_next >= STV680_NUMSCRATCH) - stv680->scratch_next = 0; - break; - } /* switch */ - } else { - stv680->nullpackets++; - if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { - if (waitqueue_active (&stv680->wq)) { - wake_up_interruptible (&stv680->wq); - } - } - } /* if - else */ - - /* Resubmit urb for new data */ - urb->status = 0; - urb->dev = stv680->udev; - if (usb_submit_urb (urb, GFP_ATOMIC)) - PDEBUG (0, "STV(e): urb burned down in video irq"); - return; -} /* _video_irq */ - -static int stv680_start_stream (struct usb_stv *stv680) -{ - struct urb *urb; - int err = 0, i; - - stv680->streaming = 1; - - /* Do some memory allocation */ - for (i = 0; i < STV680_NUMFRAMES; i++) { - stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize; - stv680->frame[i].curpix = 0; - } - /* packet size = 4096 */ - for (i = 0; i < STV680_NUMSBUF; i++) { - stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); - if (stv680->sbuf[i].data == NULL) { - PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i); - return -1; - } - } - - stv680->scratch_next = 0; - stv680->scratch_use = 0; - stv680->scratch_overflow = 0; - for (i = 0; i < STV680_NUMSCRATCH; i++) { - stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); - if (stv680->scratch[i].data == NULL) { - PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i); - return -1; - } - stv680->scratch[i].state = BUFFER_UNUSED; - } - - for (i = 0; i < STV680_NUMSBUF; i++) { - urb = usb_alloc_urb (0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */ - usb_fill_bulk_urb (urb, stv680->udev, - usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr), - stv680->sbuf[i].data, stv680->rawbufsize, - stv680_video_irq, stv680); - stv680->urb[i] = urb; - err = usb_submit_urb (stv680->urb[i], GFP_KERNEL); - if (err) - PDEBUG (0, "STV(e): urb burned down in start stream"); - } /* i STV680_NUMSBUF */ - - stv680->framecount = 0; - return 0; -} - -static int stv680_stop_stream (struct usb_stv *stv680) -{ - int i; - - if (!stv680->streaming || !stv680->udev) - return 1; - - stv680->streaming = 0; - - for (i = 0; i < STV680_NUMSBUF; i++) - if (stv680->urb[i]) { - usb_kill_urb (stv680->urb[i]); - usb_free_urb (stv680->urb[i]); - stv680->urb[i] = NULL; - kfree(stv680->sbuf[i].data); - } - for (i = 0; i < STV680_NUMSCRATCH; i++) { - kfree(stv680->scratch[i].data); - stv680->scratch[i].data = NULL; - } - - return 0; -} - -static int stv680_set_size (struct usb_stv *stv680, int width, int height) -{ - int wasstreaming = stv680->streaming; - - /* Check to see if we need to change */ - if ((stv680->vwidth == width) && (stv680->vheight == height)) - return 0; - - PDEBUG (1, "STV(i): size request for %i x %i", width, height); - /* Check for a valid mode */ - if ((!width || !height) || ((width & 1) || (height & 1))) { - PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); - return 1; - } - - if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) { - width = stv680->maxwidth / 2; - height = stv680->maxheight / 2; - } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) { - width = 160; - height = 120; - } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) { - width = 176; - height = 144; - } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) { - width = 320; - height = 240; - } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) { - width = 352; - height = 288; - } else { - PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight); - return 1; - } - - /* Stop a current stream and start it again at the new size */ - if (wasstreaming) - stv680_stop_stream (stv680); - stv680->vwidth = width; - stv680->vheight = height; - PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight); - if (wasstreaming) - stv680_start_stream (stv680); - - return 0; -} - -/********************************************************************** - * Video Decoding - **********************************************************************/ - -/******* routines from the pencam program; hey, they work! ********/ - -/* - * STV0680 Vision Camera Chipset Driver - * Copyright (C) 2000 Adam Harrison -*/ - -#define RED 0 -#define GREEN 1 -#define BLUE 2 -#define AD(x, y, w) (((y)*(w)+(x))*3) - -static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer) -{ - int x, y, i; - int w = stv680->cwidth; - int vw = stv680->cwidth, vh = stv680->cheight; - unsigned int p = 0; - int colour = 0, bayer = 0; - unsigned char *raw = buffer->data; - struct stv680_frame *frame = &stv680->frame[stv680->curframe]; - unsigned char *output = frame->data; - unsigned char *temp = frame->data; - int offset = buffer->offset; - - if (frame->curpix == 0) { - if (frame->grabstate == FRAME_READY) { - frame->grabstate = FRAME_GRABBING; - } - } - if (offset != frame->curpix) { /* Regard frame as lost :( */ - frame->curpix = 0; - stv680->error++; - return; - } - - if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) { - vw = 320; - vh = 240; - } - if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) { - vw = 352; - vh = 288; - } - - memset (output, 0, 3 * vw * vh); /* clear output matrix. */ - - for (y = 0; y < vh; y++) { - for (x = 0; x < vw; x++) { - if (x & 1) - p = *(raw + y * w + (x >> 1)); - else - p = *(raw + y * w + (x >> 1) + (w >> 1)); - - if (y & 1) - bayer = 2; - else - bayer = 0; - if (x & 1) - bayer++; - - switch (bayer) { - case 0: - case 3: - colour = 1; - break; - case 1: - colour = 0; - break; - case 2: - colour = 2; - break; - } - i = (y * vw + x) * 3; - *(output + i + colour) = (unsigned char) p; - } /* for x */ - - } /* for y */ - - /****** gamma correction plus hardcoded white balance */ - /* Thanks to Alexander Schwartx for this code. - Correction values red[], green[], blue[], are generated by - (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1> 1; - *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1; - break; - - case 1: /* blue. green lrtb, red diagonals */ - *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; - *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2; - break; - - case 2: /* red. green lrtb, blue diagonals */ - *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2; - *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2; - break; - - case 3: /* green. red lr, blue tb */ - *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1; - *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1; - break; - } /* switch */ - } /* for x */ - } /* for y - end demosaic */ - - /* fix top and bottom row, left and right side */ - i = vw * 3; - memcpy (output, (output + i), i); - memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i); - for (y = 0; y < vh; y++) { - i = y * vw * 3; - memcpy ((output + i), (output + i + 3), 3); - memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3); - } - - /* process all raw data, then trim to size if necessary */ - if ((stv680->vwidth == 160) || (stv680->vwidth == 176)) { - i = 0; - for (y = 0; y < vh; y++) { - if (!(y & 1)) { - for (x = 0; x < vw; x++) { - p = (y * vw + x) * 3; - if (!(x & 1)) { - *(output + i) = *(output + p); - *(output + i + 1) = *(output + p + 1); - *(output + i + 2) = *(output + p + 2); - i += 3; - } - } /* for x */ - } - } /* for y */ - } - /* reset to proper width */ - if ((stv680->vwidth == 160)) { - vw = 160; - vh = 120; - } - if ((stv680->vwidth == 176)) { - vw = 176; - vh = 144; - } - - /* output is RGB; some programs want BGR */ - /* swapRGB_on=0 -> program decides; swapRGB_on=1, always swap */ - /* swapRGB_on=-1, never swap */ - if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) { - for (y = 0; y < vh; y++) { - for (x = 0; x < vw; x++) { - i = (y * vw + x) * 3; - *(temp) = *(output + i); - *(output + i) = *(output + i + 2); - *(output + i + 2) = *(temp); - } - } - } - /* brightness */ - if (stv680->chgbright == 1) { - if (stv680->brightness >= 32767) { - p = (stv680->brightness - 32767) / 256; - for (x = 0; x < (vw * vh * 3); x++) { - if ((*(output + x) + (unsigned char) p) > 255) - *(output + x) = 255; - else - *(output + x) += (unsigned char) p; - } /* for */ - } else { - p = (32767 - stv680->brightness) / 256; - for (x = 0; x < (vw * vh * 3); x++) { - if ((unsigned char) p > *(output + x)) - *(output + x) = 0; - else - *(output + x) -= (unsigned char) p; - } /* for */ - } /* else */ - } - /* if */ - frame->curpix = 0; - frame->curlinepix = 0; - frame->grabstate = FRAME_DONE; - stv680->framecount++; - stv680->readcount++; - if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) { - stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1); - } - -} /* bayer_unshuffle */ - -/******* end routines from the pencam program *********/ - -static int stv680_newframe (struct usb_stv *stv680, int framenr) -{ - int errors = 0; - - while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) { - if (!stv680->frame[framenr].curpix) { - errors++; - } - wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY)); - - if (stv680->nullpackets > STV680_MAX_NULLPACKETS) { - stv680->nullpackets = 0; - PDEBUG (2, "STV(i): too many null length packets, restarting capture"); - stv680_stop_stream (stv680); - stv680_start_stream (stv680); - } else { - if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) { - stv680->frame[framenr].grabstate = FRAME_ERROR; - PDEBUG (2, "STV(e): FRAME_ERROR in _newframe"); - return -EIO; - } - stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY; - - bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]); - - stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED; - stv680->scratch_use++; - if (stv680->scratch_use >= STV680_NUMSCRATCH) - stv680->scratch_use = 0; - if (errors > STV680_MAX_ERRORS) { - errors = 0; - PDEBUG (2, "STV(i): too many errors, restarting capture"); - stv680_stop_stream (stv680); - stv680_start_stream (stv680); - } - } /* else */ - } /* while */ - return 0; -} - -/********************************************************************* - * Video4Linux - *********************************************************************/ - -static int stv_open (struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_stv *stv680 = video_get_drvdata(dev); - int err = 0; - - /* we are called with the BKL held */ - stv680->user = 1; - err = stv_init (stv680); /* main initialization routine for camera */ - - if (err >= 0) { - stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES); - if (!stv680->fbuf) { - PDEBUG (0, "STV(e): Could not rvmalloc frame bufer"); - err = -ENOMEM; - } - file->private_data = dev; - } - if (err) - stv680->user = 0; - - return err; -} - -static int stv_close (struct inode *inode, struct file *file) -{ - struct video_device *dev = file->private_data; - struct usb_stv *stv680 = video_get_drvdata(dev); - int i; - - for (i = 0; i < STV680_NUMFRAMES; i++) - stv680->frame[i].grabstate = FRAME_UNUSED; - if (stv680->streaming) - stv680_stop_stream (stv680); - - if ((i = stv_stop_video (stv680)) < 0) - PDEBUG (1, "STV(e): stop_video failed in stv_close"); - - rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES); - stv680->user = 0; - - if (stv680->removed) { - kfree(stv680); - stv680 = NULL; - PDEBUG (0, "STV(i): device unregistered"); - } - file->private_data = NULL; - return 0; -} - -static int stv680_do_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *vdev = file->private_data; - struct usb_stv *stv680 = video_get_drvdata(vdev); - - if (!stv680->udev) - return -EIO; - - switch (cmd) { - case VIDIOCGCAP:{ - struct video_capability *b = arg; - - strcpy (b->name, stv680->camera_name); - b->type = VID_TYPE_CAPTURE; - b->channels = 1; - b->audios = 0; - b->maxwidth = stv680->maxwidth; - b->maxheight = stv680->maxheight; - b->minwidth = stv680->maxwidth / 2; - b->minheight = stv680->maxheight / 2; - return 0; - } - case VIDIOCGCHAN:{ - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy (v->name, "STV Camera"); - return 0; - } - case VIDIOCSCHAN:{ - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGPICT:{ - struct video_picture *p = arg; - - stv680_get_pict (stv680, p); - return 0; - } - case VIDIOCSPICT:{ - struct video_picture *p = arg; - - if (stv680_set_pict (stv680, p)) - return -EINVAL; - return 0; - } - case VIDIOCSWIN:{ - struct video_window *vw = arg; - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (vw->width != stv680->vwidth) { - if (stv680_set_size (stv680, vw->width, vw->height)) { - PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN"); - return -EINVAL; - } - } - return 0; - } - case VIDIOCGWIN:{ - struct video_window *vw = arg; - - vw->x = 0; /* FIXME */ - vw->y = 0; - vw->chromakey = 0; - vw->flags = 0; - vw->clipcount = 0; - vw->width = stv680->vwidth; - vw->height = stv680->vheight; - return 0; - } - case VIDIOCGMBUF:{ - struct video_mbuf *vm = arg; - int i; - - memset (vm, 0, sizeof (*vm)); - vm->size = STV680_NUMFRAMES * stv680->maxframesize; - vm->frames = STV680_NUMFRAMES; - for (i = 0; i < STV680_NUMFRAMES; i++) - vm->offsets[i] = stv680->maxframesize * i; - return 0; - } - case VIDIOCMCAPTURE:{ - struct video_mmap *vm = arg; - - if (vm->format != STV_VIDEO_PALETTE) { - PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)", - vm->format, STV_VIDEO_PALETTE); - if ((vm->format == 3) && (swapRGB_on == 0)) { - PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON"); - /* this may fix those apps (e.g., xawtv) that want BGR */ - swapRGB = 1; - } - return -EINVAL; - } - if (vm->frame >= STV680_NUMFRAMES) { - PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES"); - return -EINVAL; - } - if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR) - || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) { - PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error", - stv680->frame[vm->frame].grabstate); - return -EBUSY; - } - /* Is this according to the v4l spec??? */ - if (stv680->vwidth != vm->width) { - if (stv680_set_size (stv680, vm->width, vm->height)) { - PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed"); - return -EINVAL; - } - } - stv680->frame[vm->frame].grabstate = FRAME_READY; - - if (!stv680->streaming) - stv680_start_stream (stv680); - - return 0; - } - case VIDIOCSYNC:{ - int *frame = arg; - int ret = 0; - - if (*frame < 0 || *frame >= STV680_NUMFRAMES) { - PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC"); - return -EINVAL; - } - ret = stv680_newframe (stv680, *frame); - stv680->frame[*frame].grabstate = FRAME_UNUSED; - return ret; - } - case VIDIOCGFBUF:{ - struct video_buffer *vb = arg; - - memset (vb, 0, sizeof (*vb)); - return 0; - } - case VIDIOCKEY: - return 0; - case VIDIOCCAPTURE: - { - PDEBUG (2, "STV(e): VIDIOCCAPTURE failed"); - return -EINVAL; - } - case VIDIOCSFBUF: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - default: - return -ENOIOCTLCMD; - } /* end switch */ - - return 0; -} - -static int stv680_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl); -} - -static int stv680_mmap (struct file *file, struct vm_area_struct *vma) -{ - struct video_device *dev = file->private_data; - struct usb_stv *stv680 = video_get_drvdata(dev); - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; - - mutex_lock(&stv680->lock); - - if (stv680->udev == NULL) { - mutex_unlock(&stv680->lock); - return -EIO; - } - if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1) - & ~(PAGE_SIZE - 1))) { - mutex_unlock(&stv680->lock); - return -EINVAL; - } - pos = (unsigned long) stv680->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&stv680->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - mutex_unlock(&stv680->lock); - - return 0; -} - -static ssize_t stv680_read (struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct video_device *dev = file->private_data; - unsigned long int realcount = count; - int ret = 0; - struct usb_stv *stv680 = video_get_drvdata(dev); - unsigned long int i; - - if (STV680_NUMFRAMES != 2) { - PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!"); - return -1; - } - if (stv680->udev == NULL) - return -EIO; - if (realcount > (stv680->vwidth * stv680->vheight * 3)) - realcount = stv680->vwidth * stv680->vheight * 3; - - /* Shouldn't happen: */ - if (stv680->frame[0].grabstate == FRAME_GRABBING) { - PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read"); - return -EBUSY; - } - stv680->frame[0].grabstate = FRAME_READY; - stv680->frame[1].grabstate = FRAME_UNUSED; - stv680->curframe = 0; - - if (!stv680->streaming) - stv680_start_stream (stv680); - - if (!stv680->streaming) { - ret = stv680_newframe (stv680, 0); /* ret should = 0 */ - } - - ret = stv680_newframe (stv680, 0); - - if (!ret) { - if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) { - PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i); - return -EFAULT; - } - } else { - realcount = ret; - } - stv680->frame[0].grabstate = FRAME_UNUSED; - return realcount; -} /* stv680_read */ - -static struct file_operations stv680_fops = { - .owner = THIS_MODULE, - .open = stv_open, - .release = stv_close, - .read = stv680_read, - .mmap = stv680_mmap, - .ioctl = stv680_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; -static struct video_device stv680_template = { - .owner = THIS_MODULE, - .name = "STV0680 USB camera", - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_SE401, - .fops = &stv680_fops, - .release = video_device_release, - .minor = -1, -}; - -static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_host_interface *interface; - struct usb_stv *stv680 = NULL; - char *camera_name = NULL; - int retval = 0; - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) { - PDEBUG (0, "STV(e): Number of Configurations != 1"); - return -ENODEV; - } - - interface = &intf->altsetting[0]; - /* Is it a STV680? */ - if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) { - camera_name = "STV0680"; - PDEBUG (0, "STV(i): STV0680 camera found."); - } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) { - camera_name = "Creative WebCam Go Mini"; - PDEBUG (0, "STV(i): Creative WebCam Go Mini found."); - } else { - PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values."); - PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer."); - retval = -ENODEV; - goto error; - } - /* We found one */ - if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) { - PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct."); - retval = -ENOMEM; - goto error; - } - - stv680->udev = dev; - stv680->camera_name = camera_name; - - stv680->vdev = video_device_alloc(); - if (!stv680->vdev) { - retval = -ENOMEM; - goto error; - } - memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template)); - stv680->vdev->dev = &intf->dev; - video_set_drvdata(stv680->vdev, stv680); - - memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name)); - init_waitqueue_head (&stv680->wq); - mutex_init (&stv680->lock); - wmb (); - - if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { - PDEBUG (0, "STV(e): video_register_device failed"); - retval = -EIO; - goto error_vdev; - } - PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor); - - usb_set_intfdata (intf, stv680); - stv680_create_sysfs_files(stv680->vdev); - return 0; - -error_vdev: - video_device_release(stv680->vdev); -error: - kfree(stv680); - return retval; -} - -static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680) -{ - int i; - - stv680->udev = NULL; - stv680->frame[0].grabstate = FRAME_ERROR; - stv680->frame[1].grabstate = FRAME_ERROR; - stv680->streaming = 0; - - wake_up_interruptible (&stv680->wq); - - for (i = 0; i < STV680_NUMSBUF; i++) - if (stv680->urb[i]) { - usb_kill_urb (stv680->urb[i]); - usb_free_urb (stv680->urb[i]); - stv680->urb[i] = NULL; - kfree(stv680->sbuf[i].data); - } - for (i = 0; i < STV680_NUMSCRATCH; i++) - kfree(stv680->scratch[i].data); - PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name); - - /* Free the memory */ - kfree(stv680); -} - -static void stv680_disconnect (struct usb_interface *intf) -{ - struct usb_stv *stv680 = usb_get_intfdata (intf); - - usb_set_intfdata (intf, NULL); - - if (stv680) { - /* We don't want people trying to open up the device */ - if (stv680->vdev) { - stv680_remove_sysfs_files(stv680->vdev); - video_unregister_device(stv680->vdev); - stv680->vdev = NULL; - } - if (!stv680->user) { - usb_stv680_remove_disconnected (stv680); - } else { - stv680->removed = 1; - } - } -} - -static struct usb_driver stv680_driver = { - .name = "stv680", - .probe = stv680_probe, - .disconnect = stv680_disconnect, - .id_table = device_table -}; - -/******************************************************************** - * Module routines - ********************************************************************/ - -static int __init usb_stv680_init (void) -{ - if (usb_register (&stv680_driver) < 0) { - PDEBUG (0, "STV(e): Could not setup STV0680 driver"); - return -1; - } - PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION); - - info(DRIVER_DESC " " DRIVER_VERSION); - return 0; -} - -static void __exit usb_stv680_exit (void) -{ - usb_deregister (&stv680_driver); - PDEBUG (0, "STV(i): driver deregistered"); -} - -module_init (usb_stv680_init); -module_exit (usb_stv680_exit); diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h deleted file mode 100644 index ea46e0001e6d..000000000000 --- a/drivers/usb/media/stv680.h +++ /dev/null @@ -1,227 +0,0 @@ -/**************************************************************************** - * - * Filename: stv680.h - * - * Description: - * This is a USB driver for STV0680 based usb video cameras. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ****************************************************************************/ - -/* size of usb transfers */ -#define STV680_PACKETSIZE 4096 - -/* number of queued bulk transfers to use, may have problems if > 1 */ -#define STV680_NUMSBUF 1 - -/* number of frames supported by the v4l part */ -#define STV680_NUMFRAMES 2 - -/* scratch buffers for passing data to the decoders: 2 or 4 are good */ -#define STV680_NUMSCRATCH 2 - -/* number of nul sized packets to receive before kicking the camera */ -#define STV680_MAX_NULLPACKETS 200 - -/* number of decoding errors before kicking the camera */ -#define STV680_MAX_ERRORS 100 - -#define USB_PENCAM_VENDOR_ID 0x0553 -#define USB_PENCAM_PRODUCT_ID 0x0202 - -#define USB_CREATIVEGOMINI_VENDOR_ID 0x041e -#define USB_CREATIVEGOMINI_PRODUCT_ID 0x4007 - -#define PENCAM_TIMEOUT 1000 -/* fmt 4 */ -#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24 - -static struct usb_device_id device_table[] = { - {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)}, - {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)}, - {} -}; -MODULE_DEVICE_TABLE (usb, device_table); - -struct stv680_sbuf { - unsigned char *data; -}; - -enum { - FRAME_UNUSED, /* Unused (no MCAPTURE) */ - FRAME_READY, /* Ready to start grabbing */ - FRAME_GRABBING, /* In the process of being grabbed into */ - FRAME_DONE, /* Finished grabbing, but not been synced yet */ - FRAME_ERROR, /* Something bad happened while processing */ -}; - -enum { - BUFFER_UNUSED, - BUFFER_READY, - BUFFER_BUSY, - BUFFER_DONE, -}; - -/* raw camera data <- sbuf (urb transfer buf) */ -struct stv680_scratch { - unsigned char *data; - volatile int state; - int offset; - int length; -}; - -/* processed data for display ends up here, after bayer */ -struct stv680_frame { - unsigned char *data; /* Frame buffer */ - volatile int grabstate; /* State of grabbing */ - unsigned char *curline; - int curlinepix; - int curpix; -}; - -/* this is almost the video structure uvd_t, with extra parameters for stv */ -struct usb_stv { - struct video_device *vdev; - - struct usb_device *udev; - - unsigned char bulk_in_endpointAddr; /* __u8 the address of the bulk in endpoint */ - char *camera_name; - - unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */ - int SupportedModes; - int CIF; - int VGA; - int QVGA; - int cwidth; /* camera width */ - int cheight; /* camera height */ - int maxwidth; /* max video width */ - int maxheight; /* max video height */ - int vwidth; /* current width for video window */ - int vheight; /* current height for video window */ - unsigned long int rawbufsize; - unsigned long int maxframesize; /* rawbufsize * 3 for RGB */ - - int origGain; - int origMode; /* original camera mode */ - - struct mutex lock; /* to lock the structure */ - int user; /* user count for exclusive use */ - int removed; /* device disconnected */ - int streaming; /* Are we streaming video? */ - char *fbuf; /* Videodev buffer area */ - struct urb *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */ - int curframe; /* Current receiving frame */ - struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */ - int readcount; - int framecount; - int error; - int dropped; - int scratch_next; - int scratch_use; - int scratch_overflow; - struct stv680_scratch scratch[STV680_NUMSCRATCH]; /* for decoders */ - struct stv680_sbuf sbuf[STV680_NUMSBUF]; - - unsigned int brightness; - unsigned int chgbright; - unsigned int whiteness; - unsigned int colour; - unsigned int contrast; - unsigned int hue; - unsigned int palette; - unsigned int depth; /* rgb24 in bits */ - - wait_queue_head_t wq; /* Processes waiting */ - - int nullpackets; -}; - - -static const unsigned char red[256] = { - 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, - 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, - 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, - 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, - 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, - 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, - 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, - 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, - 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, - 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, - 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, - 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, - 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, - 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, - 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, - 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, - 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, - 220, 220, 221, 221 -}; - -static const unsigned char green[256] = { - 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, - 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, - 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, - 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, - 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, - 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, - 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, - 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, - 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, - 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, - 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, - 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, - 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, - 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, - 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, - 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, - 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, - 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, - 245, 245, 246, 246 -}; - -static const unsigned char blue[256] = { - 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, - 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, - 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, - 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, - 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, - 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, - 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, - 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, - 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, - 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, - 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, - 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, - 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, - 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, - 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, - 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255 -}; diff --git a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c deleted file mode 100644 index 75ff755224df..000000000000 --- a/drivers/usb/media/ultracam.c +++ /dev/null @@ -1,679 +0,0 @@ -/* - * USB NB Camera driver - * - * HISTORY: - * 25-Dec-2002 Dmitri Removed lighting, sharpness parameters, methods. - */ - -#include -#include -#include -#include - -#include "usbvideo.h" - -#define ULTRACAM_VENDOR_ID 0x0461 -#define ULTRACAM_PRODUCT_ID 0x0813 - -#define MAX_CAMERAS 4 /* How many devices we allow to connect */ - -/* - * This structure lives in uvd_t->user field. - */ -typedef struct { - int initialized; /* Had we already sent init sequence? */ - int camera_model; /* What type of IBM camera we got? */ - int has_hdr; -} ultracam_t; -#define ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data)) - -static struct usbvideo *cams = NULL; - -static int debug = 0; - -static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */ - -static const int min_canvasWidth = 8; -static const int min_canvasHeight = 4; - -#define FRAMERATE_MIN 0 -#define FRAMERATE_MAX 6 -static int framerate = -1; - -/* - * Here we define several initialization variables. They may - * be used to automatically set color, hue, brightness and - * contrast to desired values. This is particularly useful in - * case of webcams (which have no controls and no on-screen - * output) and also when a client V4L software is used that - * does not have some of those controls. In any case it's - * good to have startup values as options. - * - * These values are all in [0..255] range. This simplifies - * operation. Note that actual values of V4L variables may - * be scaled up (as much as << 8). User can see that only - * on overlay output, however, or through a V4L client. - */ -static int init_brightness = 128; -static int init_contrast = 192; -static int init_color = 128; -static int init_hue = 128; -static int hue_correction = 128; - -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -module_param(flags, int, 0); -MODULE_PARM_DESC(flags, - "Bitfield: 0=VIDIOCSYNC, " - "1=B/W, " - "2=show hints, " - "3=show stats, " - "4=test pattern, " - "5=separate frames, " - "6=clean frames"); -module_param(framerate, int, 0); -MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); - -module_param(init_brightness, int, 0); -MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); -module_param(init_contrast, int, 0); -MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); -module_param(init_color, int, 0); -MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); -module_param(init_hue, int, 0); -MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); -module_param(hue_correction, int, 0); -MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); - -/* - * ultracam_ProcessIsocData() - * - * Generic routine to parse the ring queue data. It employs either - * ultracam_find_header() or ultracam_parse_lines() to do most - * of work. - * - * 02-Nov-2000 First (mostly dummy) version. - * 06-Nov-2000 Rewrote to dump all data into frame. - */ -static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame) -{ - int n; - - assert(uvd != NULL); - assert(frame != NULL); - - /* Try to move data from queue into frame buffer */ - n = RingQueue_GetLength(&uvd->dp); - if (n > 0) { - int m; - /* See how much spare we have left */ - m = uvd->max_frame_size - frame->seqRead_Length; - if (n > m) - n = m; - /* Now move that much data into frame buffer */ - RingQueue_Dequeue( - &uvd->dp, - frame->data + frame->seqRead_Length, - m); - frame->seqRead_Length += m; - } - /* See if we filled the frame */ - if (frame->seqRead_Length >= uvd->max_frame_size) { - frame->frameState = FrameState_Done; - uvd->curframe = -1; - uvd->stats.frame_num++; - } -} - -/* - * ultracam_veio() - * - * History: - * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. - */ -static int ultracam_veio( - struct uvd *uvd, - unsigned char req, - unsigned short value, - unsigned short index, - int is_out) -{ - static const char proc[] = "ultracam_veio"; - unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; - int i; - - if (!CAMERA_IS_OPERATIONAL(uvd)) - return 0; - - if (!is_out) { - i = usb_control_msg( - uvd->dev, - usb_rcvctrlpipe(uvd->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - cp, - sizeof(cp), - 1000); -#if 1 - info("USB => %02x%02x%02x%02x%02x%02x%02x%02x " - "(req=$%02x val=$%04x ind=$%04x)", - cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], - req, value, index); -#endif - } else { - i = usb_control_msg( - uvd->dev, - usb_sndctrlpipe(uvd->dev, 0), - req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - NULL, - 0, - 1000); - } - if (i < 0) { - err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.", - proc, i); - uvd->last_error = i; - } - return i; -} - -/* - * ultracam_calculate_fps() - */ -static int ultracam_calculate_fps(struct uvd *uvd) -{ - return 3 + framerate*4 + framerate/2; -} - -/* - * ultracam_adjust_contrast() - */ -static void ultracam_adjust_contrast(struct uvd *uvd) -{ -} - -/* - * ultracam_set_brightness() - * - * This procedure changes brightness of the picture. - */ -static void ultracam_set_brightness(struct uvd *uvd) -{ -} - -static void ultracam_set_hue(struct uvd *uvd) -{ -} - -/* - * ultracam_adjust_picture() - * - * This procedure gets called from V4L interface to update picture settings. - * Here we change brightness and contrast. - */ -static void ultracam_adjust_picture(struct uvd *uvd) -{ - ultracam_adjust_contrast(uvd); - ultracam_set_brightness(uvd); - ultracam_set_hue(uvd); -} - -/* - * ultracam_video_stop() - * - * This code tells camera to stop streaming. The interface remains - * configured and bandwidth - claimed. - */ -static void ultracam_video_stop(struct uvd *uvd) -{ -} - -/* - * ultracam_reinit_iso() - * - * This procedure sends couple of commands to the camera and then - * resets the video pipe. This sequence was observed to reinit the - * camera or, at least, to initiate ISO data stream. - */ -static void ultracam_reinit_iso(struct uvd *uvd, int do_stop) -{ -} - -static void ultracam_video_start(struct uvd *uvd) -{ - ultracam_reinit_iso(uvd, 0); -} - -static int ultracam_resetPipe(struct uvd *uvd) -{ - usb_clear_halt(uvd->dev, uvd->video_endp); - return 0; -} - -static int ultracam_alternateSetting(struct uvd *uvd, int setting) -{ - static const char proc[] = "ultracam_alternateSetting"; - int i; - i = usb_set_interface(uvd->dev, uvd->iface, setting); - if (i < 0) { - err("%s: usb_set_interface error", proc); - uvd->last_error = i; - return -EBUSY; - } - return 0; -} - -/* - * Return negative code on failure, 0 on success. - */ -static int ultracam_setup_on_open(struct uvd *uvd) -{ - int setup_ok = 0; /* Success by default */ - /* Send init sequence only once, it's large! */ - if (!ULTRACAM_T(uvd)->initialized) { - ultracam_alternateSetting(uvd, 0x04); - ultracam_alternateSetting(uvd, 0x00); - ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1); - ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1); - ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); - ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1); - ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1); - ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1); - ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1); - ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1); - ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1); - ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1); - ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1); - ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1); - ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1); - ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1); - ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1); - ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); - ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); - ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); - ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); - ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); - ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); - ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); - ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); - ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1); - ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1); - ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1); - ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1); - ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1); - ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1); - ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1); - ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1); - ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1); - ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1); - ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1); - ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1); - ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1); - ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1); - ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1); - ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1); - ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1); - ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1); - ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1); - ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1); - ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1); - ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1); - ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1); - ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0); - ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0); - ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1); - ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1); - ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1); - ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1); - ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1); - ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1); - ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1); - ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1); - ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0); - ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1); - ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1); - ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1); - ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1); - ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1); - ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1); - ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1); - ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1); - ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1); - ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1); - ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1); - ultracam_alternateSetting(uvd, 0x04); - ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); - ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1); - ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1); - ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1); - ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1); - ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0); - ultracam_resetPipe(uvd); - ULTRACAM_T(uvd)->initialized = (setup_ok != 0); - } - return setup_ok; -} - -static void ultracam_configure_video(struct uvd *uvd) -{ - if (uvd == NULL) - return; - - RESTRICT_TO_RANGE(init_brightness, 0, 255); - RESTRICT_TO_RANGE(init_contrast, 0, 255); - RESTRICT_TO_RANGE(init_color, 0, 255); - RESTRICT_TO_RANGE(init_hue, 0, 255); - RESTRICT_TO_RANGE(hue_correction, 0, 255); - - memset(&uvd->vpic, 0, sizeof(uvd->vpic)); - memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old)); - - uvd->vpic.colour = init_color << 8; - uvd->vpic.hue = init_hue << 8; - uvd->vpic.brightness = init_brightness << 8; - uvd->vpic.contrast = init_contrast << 8; - uvd->vpic.whiteness = 105 << 8; /* This one isn't used */ - uvd->vpic.depth = 24; - uvd->vpic.palette = VIDEO_PALETTE_RGB24; - - memset(&uvd->vcap, 0, sizeof(uvd->vcap)); - strcpy(uvd->vcap.name, "IBM Ultra Camera"); - uvd->vcap.type = VID_TYPE_CAPTURE; - uvd->vcap.channels = 1; - uvd->vcap.audios = 0; - uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas); - uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas); - uvd->vcap.minwidth = min_canvasWidth; - uvd->vcap.minheight = min_canvasHeight; - - memset(&uvd->vchan, 0, sizeof(uvd->vchan)); - uvd->vchan.flags = 0; - uvd->vchan.tuners = 0; - uvd->vchan.channel = 0; - uvd->vchan.type = VIDEO_TYPE_CAMERA; - strcpy(uvd->vchan.name, "Camera"); -} - -/* - * ultracam_probe() - * - * This procedure queries device descriptor and accepts the interface - * if it looks like our camera. - * - * History: - * 12-Nov-2000 Reworked to comply with new probe() signature. - * 23-Jan-2001 Added compatibility with 2.2.x kernels. - */ -static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct uvd *uvd = NULL; - int ix, i, nas; - int actInterface=-1, inactInterface=-1, maxPS=0; - unsigned char video_ep = 0; - - if (debug >= 1) - info("ultracam_probe(%p)", intf); - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - info("IBM Ultra camera found (rev. 0x%04x)", - le16_to_cpu(dev->descriptor.bcdDevice)); - - /* Validate found interface: must have one ISO endpoint */ - nas = intf->num_altsetting; - if (debug > 0) - info("Number of alternate settings=%d.", nas); - if (nas < 8) { - err("Too few alternate settings for this camera!"); - return -ENODEV; - } - /* Validate all alternate settings */ - for (ix=0; ix < nas; ix++) { - const struct usb_host_interface *interface; - const struct usb_endpoint_descriptor *endpoint; - - interface = &intf->altsetting[ix]; - i = interface->desc.bAlternateSetting; - if (interface->desc.bNumEndpoints != 1) { - err("Interface %d. has %u. endpoints!", - interface->desc.bInterfaceNumber, - (unsigned)(interface->desc.bNumEndpoints)); - return -ENODEV; - } - endpoint = &interface->endpoint[0].desc; - if (video_ep == 0) - video_ep = endpoint->bEndpointAddress; - else if (video_ep != endpoint->bEndpointAddress) { - err("Alternate settings have different endpoint addresses!"); - return -ENODEV; - } - if ((endpoint->bmAttributes & 0x03) != 0x01) { - err("Interface %d. has non-ISO endpoint!", - interface->desc.bInterfaceNumber); - return -ENODEV; - } - if ((endpoint->bEndpointAddress & 0x80) == 0) { - err("Interface %d. has ISO OUT endpoint!", - interface->desc.bInterfaceNumber); - return -ENODEV; - } - if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) { - if (inactInterface < 0) - inactInterface = i; - else { - err("More than one inactive alt. setting!"); - return -ENODEV; - } - } else { - if (actInterface < 0) { - actInterface = i; - maxPS = le16_to_cpu(endpoint->wMaxPacketSize); - if (debug > 0) - info("Active setting=%d. maxPS=%d.", i, maxPS); - } else { - /* Got another active alt. setting */ - if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) { - /* This one is better! */ - actInterface = i; - maxPS = le16_to_cpu(endpoint->wMaxPacketSize); - if (debug > 0) { - info("Even better ctive setting=%d. maxPS=%d.", - i, maxPS); - } - } - } - } - } - if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) { - err("Failed to recognize the camera!"); - return -ENODEV; - } - - uvd = usbvideo_AllocateDevice(cams); - if (uvd != NULL) { - /* Here uvd is a fully allocated uvd object */ - uvd->flags = flags; - uvd->debug = debug; - uvd->dev = dev; - uvd->iface = intf->altsetting->desc.bInterfaceNumber; - uvd->ifaceAltInactive = inactInterface; - uvd->ifaceAltActive = actInterface; - uvd->video_endp = video_ep; - uvd->iso_packet_len = maxPS; - uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24; - uvd->defaultPalette = VIDEO_PALETTE_RGB24; - uvd->canvas = VIDEOSIZE(640, 480); /* FIXME */ - uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/ - - /* Initialize ibmcam-specific data */ - assert(ULTRACAM_T(uvd) != NULL); - ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */ - ULTRACAM_T(uvd)->initialized = 0; - - ultracam_configure_video(uvd); - - i = usbvideo_RegisterVideoDevice(uvd); - if (i != 0) { - err("usbvideo_RegisterVideoDevice() failed."); - uvd = NULL; - } - } - - if (uvd) { - usb_set_intfdata (intf, uvd); - return 0; - } - return -EIO; -} - - -static struct usb_device_id id_table[] = { - { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -/* - * ultracam_init() - * - * This code is run to initialize the driver. - */ -static int __init ultracam_init(void) -{ - struct usbvideo_cb cbTbl; - memset(&cbTbl, 0, sizeof(cbTbl)); - cbTbl.probe = ultracam_probe; - cbTbl.setupOnOpen = ultracam_setup_on_open; - cbTbl.videoStart = ultracam_video_start; - cbTbl.videoStop = ultracam_video_stop; - cbTbl.processData = ultracam_ProcessIsocData; - cbTbl.postProcess = usbvideo_DeinterlaceFrame; - cbTbl.adjustPicture = ultracam_adjust_picture; - cbTbl.getFPS = ultracam_calculate_fps; - return usbvideo_register( - &cams, - MAX_CAMERAS, - sizeof(ultracam_t), - "ultracam", - &cbTbl, - THIS_MODULE, - id_table); -} - -static void __exit ultracam_cleanup(void) -{ - usbvideo_Deregister(&cams); -} - -MODULE_DEVICE_TABLE(usb, id_table); -MODULE_LICENSE("GPL"); - -module_init(ultracam_init); -module_exit(ultracam_cleanup); diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c deleted file mode 100644 index 0b51fae720a9..000000000000 --- a/drivers/usb/media/usbvideo.c +++ /dev/null @@ -1,2190 +0,0 @@ -/* - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "usbvideo.h" - -#if defined(MAP_NR) -#define virt_to_page(v) MAP_NR(v) /* Kernels 2.2.x */ -#endif - -static int video_nr = -1; -module_param(video_nr, int, 0); - -/* - * Local prototypes. - */ -static void usbvideo_Disconnect(struct usb_interface *intf); -static void usbvideo_CameraRelease(struct uvd *uvd); - -static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma); -static int usbvideo_v4l_open(struct inode *inode, struct file *file); -static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); -static int usbvideo_v4l_close(struct inode *inode, struct file *file); - -static int usbvideo_StartDataPump(struct uvd *uvd); -static void usbvideo_StopDataPump(struct uvd *uvd); -static int usbvideo_GetFrame(struct uvd *uvd, int frameNum); -static int usbvideo_NewFrame(struct uvd *uvd, int framenum); -static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, - struct usbvideo_frame *frame); - -/*******************************/ -/* Memory management functions */ -/*******************************/ -static void *usbvideo_rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void usbvideo_rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - -static void RingQueue_Initialize(struct RingQueue *rq) -{ - assert(rq != NULL); - init_waitqueue_head(&rq->wqh); -} - -static void RingQueue_Allocate(struct RingQueue *rq, int rqLen) -{ - /* Make sure the requested size is a power of 2 and - round up if necessary. This allows index wrapping - using masks rather than modulo */ - - int i = 1; - assert(rq != NULL); - assert(rqLen > 0); - - while(rqLen >> i) - i++; - if(rqLen != 1 << (i-1)) - rqLen = 1 << i; - - rq->length = rqLen; - rq->ri = rq->wi = 0; - rq->queue = usbvideo_rvmalloc(rq->length); - assert(rq->queue != NULL); -} - -static int RingQueue_IsAllocated(const struct RingQueue *rq) -{ - if (rq == NULL) - return 0; - return (rq->queue != NULL) && (rq->length > 0); -} - -static void RingQueue_Free(struct RingQueue *rq) -{ - assert(rq != NULL); - if (RingQueue_IsAllocated(rq)) { - usbvideo_rvfree(rq->queue, rq->length); - rq->queue = NULL; - rq->length = 0; - } -} - -int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len) -{ - int rql, toread; - - assert(rq != NULL); - assert(dst != NULL); - - rql = RingQueue_GetLength(rq); - if(!rql) - return 0; - - /* Clip requested length to available data */ - if(len > rql) - len = rql; - - toread = len; - if(rq->ri > rq->wi) { - /* Read data from tail */ - int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri; - memcpy(dst, rq->queue + rq->ri, read); - toread -= read; - dst += read; - rq->ri = (rq->ri + read) & (rq->length-1); - } - if(toread) { - /* Read data from head */ - memcpy(dst, rq->queue + rq->ri, toread); - rq->ri = (rq->ri + toread) & (rq->length-1); - } - return len; -} - -EXPORT_SYMBOL(RingQueue_Dequeue); - -int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n) -{ - int enqueued = 0; - - assert(rq != NULL); - assert(cdata != NULL); - assert(rq->length > 0); - while (n > 0) { - int m, q_avail; - - /* Calculate the largest chunk that fits the tail of the ring */ - q_avail = rq->length - rq->wi; - if (q_avail <= 0) { - rq->wi = 0; - q_avail = rq->length; - } - m = n; - assert(q_avail > 0); - if (m > q_avail) - m = q_avail; - - memcpy(rq->queue + rq->wi, cdata, m); - RING_QUEUE_ADVANCE_INDEX(rq, wi, m); - cdata += m; - enqueued += m; - n -= m; - } - return enqueued; -} - -EXPORT_SYMBOL(RingQueue_Enqueue); - -static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq) -{ - assert(rq != NULL); - interruptible_sleep_on(&rq->wqh); -} - -void RingQueue_WakeUpInterruptible(struct RingQueue *rq) -{ - assert(rq != NULL); - if (waitqueue_active(&rq->wqh)) - wake_up_interruptible(&rq->wqh); -} - -EXPORT_SYMBOL(RingQueue_WakeUpInterruptible); - -void RingQueue_Flush(struct RingQueue *rq) -{ - assert(rq != NULL); - rq->ri = 0; - rq->wi = 0; -} - -EXPORT_SYMBOL(RingQueue_Flush); - - -/* - * usbvideo_VideosizeToString() - * - * This procedure converts given videosize value to readable string. - * - * History: - * 07-Aug-2000 Created. - * 19-Oct-2000 Reworked for usbvideo module. - */ -static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs) -{ - char tmp[40]; - int n; - - n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs)); - assert(n < sizeof(tmp)); - if ((buf == NULL) || (bufLen < n)) - err("usbvideo_VideosizeToString: buffer is too small."); - else - memmove(buf, tmp, n); -} - -/* - * usbvideo_OverlayChar() - * - * History: - * 01-Feb-2000 Created. - */ -static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame, - int x, int y, int ch) -{ - static const unsigned short digits[16] = { - 0xF6DE, /* 0 */ - 0x2492, /* 1 */ - 0xE7CE, /* 2 */ - 0xE79E, /* 3 */ - 0xB792, /* 4 */ - 0xF39E, /* 5 */ - 0xF3DE, /* 6 */ - 0xF492, /* 7 */ - 0xF7DE, /* 8 */ - 0xF79E, /* 9 */ - 0x77DA, /* a */ - 0xD75C, /* b */ - 0xF24E, /* c */ - 0xD6DC, /* d */ - 0xF34E, /* e */ - 0xF348 /* f */ - }; - unsigned short digit; - int ix, iy; - - if ((uvd == NULL) || (frame == NULL)) - return; - - if (ch >= '0' && ch <= '9') - ch -= '0'; - else if (ch >= 'A' && ch <= 'F') - ch = 10 + (ch - 'A'); - else if (ch >= 'a' && ch <= 'f') - ch = 10 + (ch - 'a'); - else - return; - digit = digits[ch]; - - for (iy=0; iy < 5; iy++) { - for (ix=0; ix < 3; ix++) { - if (digit & 0x8000) { - if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) { -/* TODO */ RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF); - } - } - digit = digit << 1; - } - } -} - -/* - * usbvideo_OverlayString() - * - * History: - * 01-Feb-2000 Created. - */ -static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame, - int x, int y, const char *str) -{ - while (*str) { - usbvideo_OverlayChar(uvd, frame, x, y, *str); - str++; - x += 4; /* 3 pixels character + 1 space */ - } -} - -/* - * usbvideo_OverlayStats() - * - * Overlays important debugging information. - * - * History: - * 01-Feb-2000 Created. - */ -static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame) -{ - const int y_diff = 8; - char tmp[16]; - int x = 10, y=10; - long i, j, barLength; - const int qi_x1 = 60, qi_y1 = 10; - const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10; - - /* Call the user callback, see if we may proceed after that */ - if (VALID_CALLBACK(uvd, overlayHook)) { - if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0) - return; - } - - /* - * We draw a (mostly) hollow rectangle with qi_xxx coordinates. - * Left edge symbolizes the queue index 0; right edge symbolizes - * the full capacity of the queue. - */ - barLength = qi_x2 - qi_x1 - 2; - if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) { -/* TODO */ long u_lo, u_hi, q_used; - long m_ri, m_wi, m_lo, m_hi; - - /* - * Determine fill zones (used areas of the queue): - * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length - * - * if u_lo < 0 then there is no first filler. - */ - - q_used = RingQueue_GetLength(&uvd->dp); - if ((uvd->dp.ri + q_used) >= uvd->dp.length) { - u_hi = uvd->dp.length; - u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1); - } else { - u_hi = (q_used + uvd->dp.ri); - u_lo = -1; - } - - /* Convert byte indices into screen units */ - m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length); - m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length); - m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1; - m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length); - - for (j=qi_y1; j < (qi_y1 + qi_h); j++) { - for (i=qi_x1; i < qi_x2; i++) { - /* Draw border lines */ - if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) || - (i == qi_x1) || (i == (qi_x2 - 1))) { - RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF); - continue; - } - /* For all other points the Y coordinate does not matter */ - if ((i >= m_ri) && (i <= (m_ri + 3))) { - RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00); - } else if ((i >= m_wi) && (i <= (m_wi + 3))) { - RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00); - } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi))) - RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF); - } - } - } - - sprintf(tmp, "%8lx", uvd->stats.frame_num); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.urb_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.urb_length); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.data_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.header_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.iso_skip_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.iso_err_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", uvd->vpic.colour); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", uvd->vpic.hue); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", uvd->vpic.brightness >> 8); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", uvd->vpic.contrast >> 12); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; -} - -/* - * usbvideo_ReportStatistics() - * - * This procedure prints packet and transfer statistics. - * - * History: - * 14-Jan-2000 Corrected default multiplier. - */ -static void usbvideo_ReportStatistics(const struct uvd *uvd) -{ - if ((uvd != NULL) && (uvd->stats.urb_count > 0)) { - unsigned long allPackets, badPackets, goodPackets, percent; - allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES; - badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count; - goodPackets = allPackets - badPackets; - /* Calculate percentage wisely, remember integer limits */ - assert(allPackets != 0); - if (goodPackets < (((unsigned long)-1)/100)) - percent = (100 * goodPackets) / allPackets; - else - percent = goodPackets / (allPackets / 100); - info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%", - allPackets, badPackets, percent); - if (uvd->iso_packet_len > 0) { - unsigned long allBytes, xferBytes; - char multiplier = ' '; - allBytes = allPackets * uvd->iso_packet_len; - xferBytes = uvd->stats.data_count; - assert(allBytes != 0); - if (xferBytes < (((unsigned long)-1)/100)) - percent = (100 * xferBytes) / allBytes; - else - percent = xferBytes / (allBytes / 100); - /* Scale xferBytes for easy reading */ - if (xferBytes > 10*1024) { - xferBytes /= 1024; - multiplier = 'K'; - if (xferBytes > 10*1024) { - xferBytes /= 1024; - multiplier = 'M'; - if (xferBytes > 10*1024) { - xferBytes /= 1024; - multiplier = 'G'; - if (xferBytes > 10*1024) { - xferBytes /= 1024; - multiplier = 'T'; - } - } - } - } - info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%", - xferBytes, multiplier, percent); - } - } -} - -/* - * usbvideo_TestPattern() - * - * Procedure forms a test pattern (yellow grid on blue background). - * - * Parameters: - * fullframe: if TRUE then entire frame is filled, otherwise the procedure - * continues from the current scanline. - * pmode 0: fill the frame with solid blue color (like on VCR or TV) - * 1: Draw a colored grid - * - * History: - * 01-Feb-2000 Created. - */ -void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode) -{ - struct usbvideo_frame *frame; - int num_cell = 0; - int scan_length = 0; - static int num_pass = 0; - - if (uvd == NULL) { - err("%s: uvd == NULL", __FUNCTION__); - return; - } - if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { - err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe); - return; - } - - /* Grab the current frame */ - frame = &uvd->frame[uvd->curframe]; - - /* Optionally start at the beginning */ - if (fullframe) { - frame->curline = 0; - frame->seqRead_Length = 0; - } -#if 0 - { /* For debugging purposes only */ - char tmp[20]; - usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request); - info("testpattern: frame=%s", tmp); - } -#endif - /* Form every scan line */ - for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) { - int i; - unsigned char *f = frame->data + - (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline); - for (i=0; i < VIDEOSIZE_X(frame->request); i++) { - unsigned char cb=0x80; - unsigned char cg = 0; - unsigned char cr = 0; - - if (pmode == 1) { - if (frame->curline % 32 == 0) - cb = 0, cg = cr = 0xFF; - else if (i % 32 == 0) { - if (frame->curline % 32 == 1) - num_cell++; - cb = 0, cg = cr = 0xFF; - } else { - cb = ((num_cell*7) + num_pass) & 0xFF; - cg = ((num_cell*5) + num_pass*2) & 0xFF; - cr = ((num_cell*3) + num_pass*3) & 0xFF; - } - } else { - /* Just the blue screen */ - } - - *f++ = cb; - *f++ = cg; - *f++ = cr; - scan_length += 3; - } - } - - frame->frameState = FrameState_Done; - frame->seqRead_Length += scan_length; - ++num_pass; - - /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */ - usbvideo_OverlayStats(uvd, frame); -} - -EXPORT_SYMBOL(usbvideo_TestPattern); - - -#ifdef DEBUG -/* - * usbvideo_HexDump() - * - * A debugging tool. Prints hex dumps. - * - * History: - * 29-Jul-2000 Added printing of offsets. - */ -void usbvideo_HexDump(const unsigned char *data, int len) -{ - const int bytes_per_line = 32; - char tmp[128]; /* 32*3 + 5 */ - int i, k; - - for (i=k=0; len > 0; i++, len--) { - if (i > 0 && ((i % bytes_per_line) == 0)) { - printk("%s\n", tmp); - k=0; - } - if ((i % bytes_per_line) == 0) - k += sprintf(&tmp[k], "%04x: ", i); - k += sprintf(&tmp[k], "%02x ", data[i]); - } - if (k > 0) - printk("%s\n", tmp); -} - -EXPORT_SYMBOL(usbvideo_HexDump); - -#endif - -/* ******************************************************************** */ - -/* XXX: this piece of crap really wants some error handling.. */ -static void usbvideo_ClientIncModCount(struct uvd *uvd) -{ - if (uvd == NULL) { - err("%s: uvd == NULL", __FUNCTION__); - return; - } - if (uvd->handle == NULL) { - err("%s: uvd->handle == NULL", __FUNCTION__); - return; - } - if (uvd->handle->md_module == NULL) { - err("%s: uvd->handle->md_module == NULL", __FUNCTION__); - return; - } - if (!try_module_get(uvd->handle->md_module)) { - err("%s: try_module_get() == 0", __FUNCTION__); - return; - } -} - -static void usbvideo_ClientDecModCount(struct uvd *uvd) -{ - if (uvd == NULL) { - err("%s: uvd == NULL", __FUNCTION__); - return; - } - if (uvd->handle == NULL) { - err("%s: uvd->handle == NULL", __FUNCTION__); - return; - } - if (uvd->handle->md_module == NULL) { - err("%s: uvd->handle->md_module == NULL", __FUNCTION__); - return; - } - module_put(uvd->handle->md_module); -} - -int usbvideo_register( - struct usbvideo **pCams, - const int num_cams, - const int num_extra, - const char *driverName, - const struct usbvideo_cb *cbTbl, - struct module *md, - const struct usb_device_id *id_table) -{ - struct usbvideo *cams; - int i, base_size, result; - - /* Check parameters for sanity */ - if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) { - err("%s: Illegal call", __FUNCTION__); - return -EINVAL; - } - - /* Check registration callback - must be set! */ - if (cbTbl->probe == NULL) { - err("%s: probe() is required!", __FUNCTION__); - return -EINVAL; - } - - base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo); - cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL); - if (cams == NULL) { - err("Failed to allocate %d. bytes for usbvideo struct", base_size); - return -ENOMEM; - } - dbg("%s: Allocated $%p (%d. bytes) for %d. cameras", - __FUNCTION__, cams, base_size, num_cams); - - /* Copy callbacks, apply defaults for those that are not set */ - memmove(&cams->cb, cbTbl, sizeof(cams->cb)); - if (cams->cb.getFrame == NULL) - cams->cb.getFrame = usbvideo_GetFrame; - if (cams->cb.disconnect == NULL) - cams->cb.disconnect = usbvideo_Disconnect; - if (cams->cb.startDataPump == NULL) - cams->cb.startDataPump = usbvideo_StartDataPump; - if (cams->cb.stopDataPump == NULL) - cams->cb.stopDataPump = usbvideo_StopDataPump; - - cams->num_cameras = num_cams; - cams->cam = (struct uvd *) &cams[1]; - cams->md_module = md; - if (cams->md_module == NULL) - warn("%s: module == NULL!", __FUNCTION__); - mutex_init(&cams->lock); /* to 1 == available */ - - for (i = 0; i < num_cams; i++) { - struct uvd *up = &cams->cam[i]; - - up->handle = cams; - - /* Allocate user_data separately because of kmalloc's limits */ - if (num_extra > 0) { - up->user_size = num_cams * num_extra; - up->user_data = kmalloc(up->user_size, GFP_KERNEL); - if (up->user_data == NULL) { - err("%s: Failed to allocate user_data (%d. bytes)", - __FUNCTION__, up->user_size); - while (i) { - up = &cams->cam[--i]; - kfree(up->user_data); - } - kfree(cams); - return -ENOMEM; - } - dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)", - __FUNCTION__, i, up->user_data, up->user_size); - } - } - - /* - * Register ourselves with USB stack. - */ - strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown"); - cams->usbdrv.name = cams->drvName; - cams->usbdrv.probe = cams->cb.probe; - cams->usbdrv.disconnect = cams->cb.disconnect; - cams->usbdrv.id_table = id_table; - - /* - * Update global handle to usbvideo. This is very important - * because probe() can be called before usb_register() returns. - * If the handle is not yet updated then the probe() will fail. - */ - *pCams = cams; - result = usb_register(&cams->usbdrv); - if (result) { - for (i = 0; i < num_cams; i++) { - struct uvd *up = &cams->cam[i]; - kfree(up->user_data); - } - kfree(cams); - } - - return result; -} - -EXPORT_SYMBOL(usbvideo_register); - -/* - * usbvideo_Deregister() - * - * Procedure frees all usbvideo and user data structures. Be warned that - * if you had some dynamically allocated components in ->user field then - * you should free them before calling here. - */ -void usbvideo_Deregister(struct usbvideo **pCams) -{ - struct usbvideo *cams; - int i; - - if (pCams == NULL) { - err("%s: pCams == NULL", __FUNCTION__); - return; - } - cams = *pCams; - if (cams == NULL) { - err("%s: cams == NULL", __FUNCTION__); - return; - } - - dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName); - usb_deregister(&cams->usbdrv); - - dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras); - for (i=0; i < cams->num_cameras; i++) { - struct uvd *up = &cams->cam[i]; - int warning = 0; - - if (up->user_data != NULL) { - if (up->user_size <= 0) - ++warning; - } else { - if (up->user_size > 0) - ++warning; - } - if (warning) { - err("%s: Warning: user_data=$%p user_size=%d.", - __FUNCTION__, up->user_data, up->user_size); - } else { - dbg("%s: Freeing %d. $%p->user_data=$%p", - __FUNCTION__, i, up, up->user_data); - kfree(up->user_data); - } - } - /* Whole array was allocated in one chunk */ - dbg("%s: Freed %d uvd structures", - __FUNCTION__, cams->num_cameras); - kfree(cams); - *pCams = NULL; -} - -EXPORT_SYMBOL(usbvideo_Deregister); - -/* - * usbvideo_Disconnect() - * - * This procedure stops all driver activity. Deallocation of - * the interface-private structure (pointed by 'ptr') is done now - * (if we don't have any open files) or later, when those files - * are closed. After that driver should be removable. - * - * This code handles surprise removal. The uvd->user is a counter which - * increments on open() and decrements on close(). If we see here that - * this counter is not 0 then we have a client who still has us opened. - * We set uvd->remove_pending flag as early as possible, and after that - * all access to the camera will gracefully fail. These failures should - * prompt client to (eventually) close the video device, and then - in - * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter. - * - * History: - * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone. - * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close() - * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). - * 19-Oct-2000 Moved to usbvideo module. - */ -static void usbvideo_Disconnect(struct usb_interface *intf) -{ - struct uvd *uvd = usb_get_intfdata (intf); - int i; - - if (uvd == NULL) { - err("%s($%p): Illegal call.", __FUNCTION__, intf); - return; - } - - usb_set_intfdata (intf, NULL); - - usbvideo_ClientIncModCount(uvd); - if (uvd->debug > 0) - info("%s(%p.)", __FUNCTION__, intf); - - mutex_lock(&uvd->lock); - uvd->remove_pending = 1; /* Now all ISO data will be ignored */ - - /* At this time we ask to cancel outstanding URBs */ - GET_CALLBACK(uvd, stopDataPump)(uvd); - - for (i=0; i < USBVIDEO_NUMSBUF; i++) - usb_free_urb(uvd->sbuf[i].urb); - - usb_put_dev(uvd->dev); - uvd->dev = NULL; /* USB device is no more */ - - video_unregister_device(&uvd->vdev); - if (uvd->debug > 0) - info("%s: Video unregistered.", __FUNCTION__); - - if (uvd->user) - info("%s: In use, disconnect pending.", __FUNCTION__); - else - usbvideo_CameraRelease(uvd); - mutex_unlock(&uvd->lock); - info("USB camera disconnected."); - - usbvideo_ClientDecModCount(uvd); -} - -/* - * usbvideo_CameraRelease() - * - * This code does final release of uvd. This happens - * after the device is disconnected -and- all clients - * closed their files. - * - * History: - * 27-Jan-2000 Created. - */ -static void usbvideo_CameraRelease(struct uvd *uvd) -{ - if (uvd == NULL) { - err("%s: Illegal call", __FUNCTION__); - return; - } - - RingQueue_Free(&uvd->dp); - if (VALID_CALLBACK(uvd, userFree)) - GET_CALLBACK(uvd, userFree)(uvd); - uvd->uvd_used = 0; /* This is atomic, no need to take mutex */ -} - -/* - * usbvideo_find_struct() - * - * This code searches the array of preallocated (static) structures - * and returns index of the first one that isn't in use. Returns -1 - * if there are no free structures. - * - * History: - * 27-Jan-2000 Created. - */ -static int usbvideo_find_struct(struct usbvideo *cams) -{ - int u, rv = -1; - - if (cams == NULL) { - err("No usbvideo handle?"); - return -1; - } - mutex_lock(&cams->lock); - for (u = 0; u < cams->num_cameras; u++) { - struct uvd *uvd = &cams->cam[u]; - if (!uvd->uvd_used) /* This one is free */ - { - uvd->uvd_used = 1; /* In use now */ - mutex_init(&uvd->lock); /* to 1 == available */ - uvd->dev = NULL; - rv = u; - break; - } - } - mutex_unlock(&cams->lock); - return rv; -} - -static struct file_operations usbvideo_fops = { - .owner = THIS_MODULE, - .open = usbvideo_v4l_open, - .release =usbvideo_v4l_close, - .read = usbvideo_v4l_read, - .mmap = usbvideo_v4l_mmap, - .ioctl = usbvideo_v4l_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; -static const struct video_device usbvideo_template = { - .owner = THIS_MODULE, - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_CPIA, - .fops = &usbvideo_fops, -}; - -struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams) -{ - int i, devnum; - struct uvd *uvd = NULL; - - if (cams == NULL) { - err("No usbvideo handle?"); - return NULL; - } - - devnum = usbvideo_find_struct(cams); - if (devnum == -1) { - err("IBM USB camera driver: Too many devices!"); - return NULL; - } - uvd = &cams->cam[devnum]; - dbg("Device entry #%d. at $%p", devnum, uvd); - - /* Not relying upon caller we increase module counter ourselves */ - usbvideo_ClientIncModCount(uvd); - - mutex_lock(&uvd->lock); - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); - if (uvd->sbuf[i].urb == NULL) { - err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC); - uvd->uvd_used = 0; - uvd = NULL; - goto allocate_done; - } - } - uvd->user=0; - uvd->remove_pending = 0; - uvd->last_error = 0; - RingQueue_Initialize(&uvd->dp); - - /* Initialize video device structure */ - uvd->vdev = usbvideo_template; - sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName); - /* - * The client is free to overwrite those because we - * return control to the client's probe function right now. - */ -allocate_done: - mutex_unlock(&uvd->lock); - usbvideo_ClientDecModCount(uvd); - return uvd; -} - -EXPORT_SYMBOL(usbvideo_AllocateDevice); - -int usbvideo_RegisterVideoDevice(struct uvd *uvd) -{ - char tmp1[20], tmp2[20]; /* Buffers for printing */ - - if (uvd == NULL) { - err("%s: Illegal call.", __FUNCTION__); - return -EINVAL; - } - if (uvd->video_endp == 0) { - info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__); - } - if (uvd->paletteBits == 0) { - err("%s: No palettes specified!", __FUNCTION__); - return -EINVAL; - } - if (uvd->defaultPalette == 0) { - info("%s: No default palette!", __FUNCTION__); - } - - uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) * - VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL; - usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize); - usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas); - - if (uvd->debug > 0) { - info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx", - __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits); - } - if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { - err("%s: video_register_device failed", __FUNCTION__); - return -EPIPE; - } - if (uvd->debug > 1) { - info("%s: video_register_device() successful", __FUNCTION__); - } - if (uvd->dev == NULL) { - err("%s: uvd->dev == NULL", __FUNCTION__); - return -EINVAL; - } - - info("%s on /dev/video%d: canvas=%s videosize=%s", - (uvd->handle != NULL) ? uvd->handle->drvName : "???", - uvd->vdev.minor, tmp2, tmp1); - - usb_get_dev(uvd->dev); - return 0; -} - -EXPORT_SYMBOL(usbvideo_RegisterVideoDevice); - -/* ******************************************************************** */ - -static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct uvd *uvd = file->private_data; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; - - if (!CAMERA_IS_OPERATIONAL(uvd)) - return -EFAULT; - - if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) - return -EINVAL; - - pos = (unsigned long) uvd->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return 0; -} - -/* - * usbvideo_v4l_open() - * - * This is part of Video 4 Linux API. The driver can be opened by one - * client only (checks internal counter 'uvdser'). The procedure - * then allocates buffers needed for video processing. - * - * History: - * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the - * camera is also initialized here (once per connect), at - * expense of V4L client (it waits on open() call). - * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. - * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). - */ -static int usbvideo_v4l_open(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct uvd *uvd = (struct uvd *) dev; - const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len; - int i, errCode = 0; - - if (uvd->debug > 1) - info("%s($%p)", __FUNCTION__, dev); - - usbvideo_ClientIncModCount(uvd); - mutex_lock(&uvd->lock); - - if (uvd->user) { - err("%s: Someone tried to open an already opened device!", __FUNCTION__); - errCode = -EBUSY; - } else { - /* Clear statistics */ - memset(&uvd->stats, 0, sizeof(uvd->stats)); - - /* Clean pointers so we know if we allocated something */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) - uvd->sbuf[i].data = NULL; - - /* Allocate memory for the frame buffers */ - uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size; - uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size); - RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE); - if ((uvd->fbuf == NULL) || - (!RingQueue_IsAllocated(&uvd->dp))) { - err("%s: Failed to allocate fbuf or dp", __FUNCTION__); - errCode = -ENOMEM; - } else { - /* Allocate all buffers */ - for (i=0; i < USBVIDEO_NUMFRAMES; i++) { - uvd->frame[i].frameState = FrameState_Unused; - uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size); - /* - * Set default sizes in case IOCTL (VIDIOCMCAPTURE) - * is not used (using read() instead). - */ - uvd->frame[i].canvas = uvd->canvas; - uvd->frame[i].seqRead_Index = 0; - } - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); - if (uvd->sbuf[i].data == NULL) { - errCode = -ENOMEM; - break; - } - } - } - if (errCode != 0) { - /* Have to free all that memory */ - if (uvd->fbuf != NULL) { - usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); - uvd->fbuf = NULL; - } - RingQueue_Free(&uvd->dp); - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - kfree(uvd->sbuf[i].data); - uvd->sbuf[i].data = NULL; - } - } - } - - /* If so far no errors then we shall start the camera */ - if (errCode == 0) { - /* Start data pump if we have valid endpoint */ - if (uvd->video_endp != 0) - errCode = GET_CALLBACK(uvd, startDataPump)(uvd); - if (errCode == 0) { - if (VALID_CALLBACK(uvd, setupOnOpen)) { - if (uvd->debug > 1) - info("%s: setupOnOpen callback", __FUNCTION__); - errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd); - if (errCode < 0) { - err("%s: setupOnOpen callback failed (%d.).", - __FUNCTION__, errCode); - } else if (uvd->debug > 1) { - info("%s: setupOnOpen callback successful", __FUNCTION__); - } - } - if (errCode == 0) { - uvd->settingsAdjusted = 0; - if (uvd->debug > 1) - info("%s: Open succeeded.", __FUNCTION__); - uvd->user++; - file->private_data = uvd; - } - } - } - mutex_unlock(&uvd->lock); - if (errCode != 0) - usbvideo_ClientDecModCount(uvd); - if (uvd->debug > 0) - info("%s: Returning %d.", __FUNCTION__, errCode); - return errCode; -} - -/* - * usbvideo_v4l_close() - * - * This is part of Video 4 Linux API. The procedure - * stops streaming and deallocates all buffers that were earlier - * allocated in usbvideo_v4l_open(). - * - * History: - * 22-Jan-2000 Moved scratch buffer deallocation here. - * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. - * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. - */ -static int usbvideo_v4l_close(struct inode *inode, struct file *file) -{ - struct video_device *dev = file->private_data; - struct uvd *uvd = (struct uvd *) dev; - int i; - - if (uvd->debug > 1) - info("%s($%p)", __FUNCTION__, dev); - - mutex_lock(&uvd->lock); - GET_CALLBACK(uvd, stopDataPump)(uvd); - usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); - uvd->fbuf = NULL; - RingQueue_Free(&uvd->dp); - - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - kfree(uvd->sbuf[i].data); - uvd->sbuf[i].data = NULL; - } - -#if USBVIDEO_REPORT_STATS - usbvideo_ReportStatistics(uvd); -#endif - - uvd->user--; - if (uvd->remove_pending) { - if (uvd->debug > 0) - info("usbvideo_v4l_close: Final disconnect."); - usbvideo_CameraRelease(uvd); - } - mutex_unlock(&uvd->lock); - usbvideo_ClientDecModCount(uvd); - - if (uvd->debug > 1) - info("%s: Completed.", __FUNCTION__); - file->private_data = NULL; - return 0; -} - -/* - * usbvideo_v4l_ioctl() - * - * This is part of Video 4 Linux API. The procedure handles ioctl() calls. - * - * History: - * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. - */ -static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct uvd *uvd = file->private_data; - - if (!CAMERA_IS_OPERATIONAL(uvd)) - return -EIO; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - *b = uvd->vcap; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - *v = uvd->vchan; - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGPICT: - { - struct video_picture *pic = arg; - *pic = uvd->vpic; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *pic = arg; - /* - * Use temporary 'video_picture' structure to preserve our - * own settings (such as color depth, palette) that we - * aren't allowing everyone (V4L client) to change. - */ - uvd->vpic.brightness = pic->brightness; - uvd->vpic.hue = pic->hue; - uvd->vpic.colour = pic->colour; - uvd->vpic.contrast = pic->contrast; - uvd->settingsAdjusted = 0; /* Will force new settings */ - return 0; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - - if(VALID_CALLBACK(uvd, setVideoMode)) { - return GET_CALLBACK(uvd, setVideoMode)(uvd, vw); - } - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (vw->width != VIDEOSIZE_X(uvd->canvas)) - return -EINVAL; - if (vw->height != VIDEOSIZE_Y(uvd->canvas)) - return -EINVAL; - - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - - vw->x = 0; - vw->y = 0; - vw->width = VIDEOSIZE_X(uvd->videosize); - vw->height = VIDEOSIZE_Y(uvd->videosize); - vw->chromakey = 0; - if (VALID_CALLBACK(uvd, getFPS)) - vw->flags = GET_CALLBACK(uvd, getFPS)(uvd); - else - vw->flags = 10; /* FIXME: do better! */ - return 0; - } - case VIDIOCGMBUF: - { - struct video_mbuf *vm = arg; - int i; - - memset(vm, 0, sizeof(*vm)); - vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES; - vm->frames = USBVIDEO_NUMFRAMES; - for(i = 0; i < USBVIDEO_NUMFRAMES; i++) - vm->offsets[i] = i * uvd->max_frame_size; - - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - - if (uvd->debug >= 1) { - info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.", - vm->frame, vm->width, vm->height, vm->format); - } - /* - * Check if the requested size is supported. If the requestor - * requests too big a frame then we may be tricked into accessing - * outside of own preallocated frame buffer (in uvd->frame). - * This will cause oops or a security hole. Theoretically, we - * could only clamp the size down to acceptable bounds, but then - * we'd need to figure out how to insert our smaller buffer into - * larger caller's buffer... this is not an easy question. So we - * here just flatly reject too large requests, assuming that the - * caller will resubmit with smaller size. Callers should know - * what size we support (returned by VIDIOCGCAP). However vidcat, - * for one, does not care and allows to ask for any size. - */ - if ((vm->width > VIDEOSIZE_X(uvd->canvas)) || - (vm->height > VIDEOSIZE_Y(uvd->canvas))) { - if (uvd->debug > 0) { - info("VIDIOCMCAPTURE: Size=%dx%d too large; " - "allowed only up to %ldx%ld", vm->width, vm->height, - VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas)); - } - return -EINVAL; - } - /* Check if the palette is supported */ - if (((1L << vm->format) & uvd->paletteBits) == 0) { - if (uvd->debug > 0) { - info("VIDIOCMCAPTURE: format=%d. not supported" - " (paletteBits=$%08lx)", - vm->format, uvd->paletteBits); - } - return -EINVAL; - } - if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) { - err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1); - return -EINVAL; - } - if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) { - /* Not an error - can happen */ - } - uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height); - uvd->frame[vm->frame].palette = vm->format; - - /* Mark it as ready */ - uvd->frame[vm->frame].frameState = FrameState_Ready; - - return usbvideo_NewFrame(uvd, vm->frame); - } - case VIDIOCSYNC: - { - int *frameNum = arg; - int ret; - - if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES) - return -EINVAL; - - if (uvd->debug >= 1) - info("VIDIOCSYNC: syncing to frame %d.", *frameNum); - if (uvd->flags & FLAGS_NO_DECODING) - ret = usbvideo_GetFrame(uvd, *frameNum); - else if (VALID_CALLBACK(uvd, getFrame)) { - ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum); - if ((ret < 0) && (uvd->debug >= 1)) { - err("VIDIOCSYNC: getFrame() returned %d.", ret); - } - } else { - err("VIDIOCSYNC: getFrame is not set"); - ret = -EFAULT; - } - - /* - * The frame is in FrameState_Done_Hold state. Release it - * right now because its data is already mapped into - * the user space and it's up to the application to - * make use of it until it asks for another frame. - */ - uvd->frame[*frameNum].frameState = FrameState_Unused; - return ret; - } - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - - memset(vb, 0, sizeof(*vb)); - return 0; - } - case VIDIOCKEY: - return 0; - - case VIDIOCCAPTURE: - return -EINVAL; - - case VIDIOCSFBUF: - - case VIDIOCGTUNER: - case VIDIOCSTUNER: - - case VIDIOCGFREQ: - case VIDIOCSFREQ: - - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl); -} - -/* - * usbvideo_v4l_read() - * - * This is mostly boring stuff. We simply ask for a frame and when it - * arrives copy all the video data from it into user space. There is - * no obvious need to override this method. - * - * History: - * 20-Oct-2000 Created. - * 01-Nov-2000 Added mutex (uvd->lock). - */ -static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct uvd *uvd = file->private_data; - int noblock = file->f_flags & O_NONBLOCK; - int frmx = -1, i; - struct usbvideo_frame *frame; - - if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL)) - return -EFAULT; - - if (uvd->debug >= 1) - info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock); - - mutex_lock(&uvd->lock); - - /* See if a frame is completed, then use it. */ - for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { - if ((uvd->frame[i].frameState == FrameState_Done) || - (uvd->frame[i].frameState == FrameState_Done_Hold) || - (uvd->frame[i].frameState == FrameState_Error)) { - frmx = i; - break; - } - } - - /* FIXME: If we don't start a frame here then who ever does? */ - if (noblock && (frmx == -1)) { - count = -EAGAIN; - goto read_done; - } - - /* - * If no FrameState_Done, look for a FrameState_Grabbing state. - * See if a frame is in process (grabbing), then use it. - * We will need to wait until it becomes cooked, of course. - */ - if (frmx == -1) { - for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { - if (uvd->frame[i].frameState == FrameState_Grabbing) { - frmx = i; - break; - } - } - } - - /* - * If no frame is active, start one. We don't care which one - * it will be, so #0 is as good as any. - * In read access mode we don't have convenience of VIDIOCMCAPTURE - * to specify the requested palette (video format) on per-frame - * basis. This means that we have to return data in -some- format - * and just hope that the client knows what to do with it. - * The default format is configured in uvd->defaultPalette field - * as one of VIDEO_PALETTE_xxx values. We stuff it into the new - * frame and initiate the frame filling process. - */ - if (frmx == -1) { - if (uvd->defaultPalette == 0) { - err("%s: No default palette; don't know what to do!", __FUNCTION__); - count = -EFAULT; - goto read_done; - } - frmx = 0; - /* - * We have no per-frame control over video size. - * Therefore we only can use whatever size was - * specified as default. - */ - uvd->frame[frmx].request = uvd->videosize; - uvd->frame[frmx].palette = uvd->defaultPalette; - uvd->frame[frmx].frameState = FrameState_Ready; - usbvideo_NewFrame(uvd, frmx); - /* Now frame 0 is supposed to start filling... */ - } - - /* - * Get a pointer to the active frame. It is either previously - * completed frame or frame in progress but not completed yet. - */ - frame = &uvd->frame[frmx]; - - /* - * Sit back & wait until the frame gets filled and postprocessed. - * If we fail to get the picture [in time] then return the error. - * In this call we specify that we want the frame to be waited for, - * postprocessed and switched into FrameState_Done_Hold state. This - * state is used to hold the frame as "fully completed" between - * subsequent partial reads of the same frame. - */ - if (frame->frameState != FrameState_Done_Hold) { - long rv = -EFAULT; - if (uvd->flags & FLAGS_NO_DECODING) - rv = usbvideo_GetFrame(uvd, frmx); - else if (VALID_CALLBACK(uvd, getFrame)) - rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx); - else - err("getFrame is not set"); - if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) { - count = rv; - goto read_done; - } - } - - /* - * Copy bytes to user space. We allow for partial reads, which - * means that the user application can request read less than - * the full frame size. It is up to the application to issue - * subsequent calls until entire frame is read. - * - * First things first, make sure we don't copy more than we - * have - even if the application wants more. That would be - * a big security embarassment! - */ - if ((count + frame->seqRead_Index) > frame->seqRead_Length) - count = frame->seqRead_Length - frame->seqRead_Index; - - /* - * Copy requested amount of data to user space. We start - * copying from the position where we last left it, which - * will be zero for a new frame (not read before). - */ - if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) { - count = -EFAULT; - goto read_done; - } - - /* Update last read position */ - frame->seqRead_Index += count; - if (uvd->debug >= 1) { - err("%s: {copy} count used=%Zd, new seqRead_Index=%ld", - __FUNCTION__, count, frame->seqRead_Index); - } - - /* Finally check if the frame is done with and "release" it */ - if (frame->seqRead_Index >= frame->seqRead_Length) { - /* All data has been read */ - frame->seqRead_Index = 0; - - /* Mark it as available to be used again. */ - uvd->frame[frmx].frameState = FrameState_Unused; - if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) { - err("%s: usbvideo_NewFrame failed.", __FUNCTION__); - } - } -read_done: - mutex_unlock(&uvd->lock); - return count; -} - -/* - * Make all of the blocks of data contiguous - */ -static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb) -{ - char *cdata; - int i, totlen = 0; - - for (i = 0; i < urb->number_of_packets; i++) { - int n = urb->iso_frame_desc[i].actual_length; - int st = urb->iso_frame_desc[i].status; - - cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - /* Detect and ignore errored packets */ - if (st < 0) { - if (uvd->debug >= 1) - err("Data error: packet=%d. len=%d. status=%d.", i, n, st); - uvd->stats.iso_err_count++; - continue; - } - - /* Detect and ignore empty packets */ - if (n <= 0) { - uvd->stats.iso_skip_count++; - continue; - } - totlen += n; /* Little local accounting */ - RingQueue_Enqueue(&uvd->dp, cdata, n); - } - return totlen; -} - -static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs) -{ - int i, ret, len; - struct uvd *uvd = urb->context; - - /* We don't want to do anything if we are about to be removed! */ - if (!CAMERA_IS_OPERATIONAL(uvd)) - return; -#if 0 - if (urb->actual_length > 0) { - info("urb=$%p status=%d. errcount=%d. length=%d.", - urb, urb->status, urb->error_count, urb->actual_length); - } else { - static int c = 0; - if (c++ % 100 == 0) - info("No Isoc data"); - } -#endif - - if (!uvd->streaming) { - if (uvd->debug >= 1) - info("Not streaming, but interrupt!"); - return; - } - - uvd->stats.urb_count++; - if (urb->actual_length <= 0) - goto urb_done_with; - - /* Copy the data received into ring queue */ - len = usbvideo_CompressIsochronous(uvd, urb); - uvd->stats.urb_length = len; - if (len <= 0) - goto urb_done_with; - - /* Here we got some data */ - uvd->stats.data_count += len; - RingQueue_WakeUpInterruptible(&uvd->dp); - -urb_done_with: - for (i = 0; i < FRAMES_PER_DESC; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - urb->dev = uvd->dev; - ret = usb_submit_urb (urb, GFP_KERNEL); - if(ret) - err("usb_submit_urb error (%d)", ret); - return; -} - -/* - * usbvideo_StartDataPump() - * - * History: - * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead - * of hardcoded values. Simplified by using for loop, - * allowed any number of URBs. - */ -static int usbvideo_StartDataPump(struct uvd *uvd) -{ - struct usb_device *dev = uvd->dev; - int i, errFlag; - - if (uvd->debug > 1) - info("%s($%p)", __FUNCTION__, uvd); - - if (!CAMERA_IS_OPERATIONAL(uvd)) { - err("%s: Camera is not operational", __FUNCTION__); - return -EFAULT; - } - uvd->curframe = -1; - - /* Alternate interface 1 is is the biggest frame size */ - i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); - if (i < 0) { - err("%s: usb_set_interface error", __FUNCTION__); - uvd->last_error = i; - return -EBUSY; - } - if (VALID_CALLBACK(uvd, videoStart)) - GET_CALLBACK(uvd, videoStart)(uvd); - else - err("%s: videoStart not set", __FUNCTION__); - - /* We double buffer the Iso lists */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - int j, k; - struct urb *urb = uvd->sbuf[i].urb; - urb->dev = dev; - urb->context = uvd; - urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); - urb->interval = 1; - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = uvd->sbuf[i].data; - urb->complete = usbvideo_IsocIrq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC; - for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = uvd->iso_packet_len; - } - } - - /* Submit all URBs */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); - if (errFlag) - err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag); - } - - uvd->streaming = 1; - if (uvd->debug > 1) - info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp); - return 0; -} - -/* - * usbvideo_StopDataPump() - * - * This procedure stops streaming and deallocates URBs. Then it - * activates zero-bandwidth alt. setting of the video interface. - * - * History: - * 22-Jan-2000 Corrected order of actions to work after surprise removal. - * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values. - */ -static void usbvideo_StopDataPump(struct uvd *uvd) -{ - int i, j; - - if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) - return; - - if (uvd->debug > 1) - info("%s($%p)", __FUNCTION__, uvd); - - /* Unschedule all of the iso td's */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - usb_kill_urb(uvd->sbuf[i].urb); - } - if (uvd->debug > 1) - info("%s: streaming=0", __FUNCTION__); - uvd->streaming = 0; - - if (!uvd->remove_pending) { - /* Invoke minidriver's magic to stop the camera */ - if (VALID_CALLBACK(uvd, videoStop)) - GET_CALLBACK(uvd, videoStop)(uvd); - else - err("%s: videoStop not set", __FUNCTION__); - - /* Set packet size to 0 */ - j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); - if (j < 0) { - err("%s: usb_set_interface() error %d.", __FUNCTION__, j); - uvd->last_error = j; - } - } -} - -/* - * usbvideo_NewFrame() - * - * History: - * 29-Mar-00 Added copying of previous frame into the current one. - * 6-Aug-00 Added model 3 video sizes, removed redundant width, height. - */ -static int usbvideo_NewFrame(struct uvd *uvd, int framenum) -{ - struct usbvideo_frame *frame; - int n; - - if (uvd->debug > 1) - info("usbvideo_NewFrame($%p,%d.)", uvd, framenum); - - /* If we're not grabbing a frame right now and the other frame is */ - /* ready to be grabbed into, then use it instead */ - if (uvd->curframe != -1) - return 0; - - /* If necessary we adjust picture settings between frames */ - if (!uvd->settingsAdjusted) { - if (VALID_CALLBACK(uvd, adjustPicture)) - GET_CALLBACK(uvd, adjustPicture)(uvd); - uvd->settingsAdjusted = 1; - } - - n = (framenum + 1) % USBVIDEO_NUMFRAMES; - if (uvd->frame[n].frameState == FrameState_Ready) - framenum = n; - - frame = &uvd->frame[framenum]; - - frame->frameState = FrameState_Grabbing; - frame->scanstate = ScanState_Scanning; - frame->seqRead_Length = 0; /* Accumulated in xxx_parse_data() */ - frame->deinterlace = Deinterlace_None; - frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */ - uvd->curframe = framenum; - - /* - * Normally we would want to copy previous frame into the current one - * before we even start filling it with data; this allows us to stop - * filling at any moment; top portion of the frame will be new and - * bottom portion will stay as it was in previous frame. If we don't - * do that then missing chunks of video stream will result in flickering - * portions of old data whatever it was before. - * - * If we choose not to copy previous frame (to, for example, save few - * bus cycles - the frame can be pretty large!) then we have an option - * to clear the frame before using. If we experience losses in this - * mode then missing picture will be black (no flickering). - * - * Finally, if user chooses not to clean the current frame before - * filling it with data then the old data will be visible if we fail - * to refill entire frame with new data. - */ - if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) { - /* This copies previous frame into this one to mask losses */ - int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES; - memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size); - } else { - if (uvd->flags & FLAGS_CLEAN_FRAMES) { - /* This provides a "clean" frame but slows things down */ - memset(frame->data, 0, uvd->max_frame_size); - } - } - return 0; -} - -/* - * usbvideo_CollectRawData() - * - * This procedure can be used instead of 'processData' callback if you - * only want to dump the raw data from the camera into the output - * device (frame buffer). You can look at it with V4L client, but the - * image will be unwatchable. The main purpose of this code and of the - * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from - * new, unknown cameras. This procedure will be automatically invoked - * instead of the specified callback handler when uvd->flags has bit - * FLAGS_NO_DECODING set. Therefore, any regular build of any driver - * based on usbvideo can use this feature at any time. - */ -static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame) -{ - int n; - - assert(uvd != NULL); - assert(frame != NULL); - - /* Try to move data from queue into frame buffer */ - n = RingQueue_GetLength(&uvd->dp); - if (n > 0) { - int m; - /* See how much space we have left */ - m = uvd->max_frame_size - frame->seqRead_Length; - if (n > m) - n = m; - /* Now move that much data into frame buffer */ - RingQueue_Dequeue( - &uvd->dp, - frame->data + frame->seqRead_Length, - m); - frame->seqRead_Length += m; - } - /* See if we filled the frame */ - if (frame->seqRead_Length >= uvd->max_frame_size) { - frame->frameState = FrameState_Done; - uvd->curframe = -1; - uvd->stats.frame_num++; - } -} - -static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) -{ - struct usbvideo_frame *frame = &uvd->frame[frameNum]; - - if (uvd->debug >= 2) - info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum); - - switch (frame->frameState) { - case FrameState_Unused: - if (uvd->debug >= 2) - info("%s: FrameState_Unused", __FUNCTION__); - return -EINVAL; - case FrameState_Ready: - case FrameState_Grabbing: - case FrameState_Error: - { - int ntries, signalPending; - redo: - if (!CAMERA_IS_OPERATIONAL(uvd)) { - if (uvd->debug >= 2) - info("%s: Camera is not operational (1)", __FUNCTION__); - return -EIO; - } - ntries = 0; - do { - RingQueue_InterruptibleSleepOn(&uvd->dp); - signalPending = signal_pending(current); - if (!CAMERA_IS_OPERATIONAL(uvd)) { - if (uvd->debug >= 2) - info("%s: Camera is not operational (2)", __FUNCTION__); - return -EIO; - } - assert(uvd->fbuf != NULL); - if (signalPending) { - if (uvd->debug >= 2) - info("%s: Signal=$%08x", __FUNCTION__, signalPending); - if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) { - usbvideo_TestPattern(uvd, 1, 0); - uvd->curframe = -1; - uvd->stats.frame_num++; - if (uvd->debug >= 2) - info("%s: Forced test pattern screen", __FUNCTION__); - return 0; - } else { - /* Standard answer: Interrupted! */ - if (uvd->debug >= 2) - info("%s: Interrupted!", __FUNCTION__); - return -EINTR; - } - } else { - /* No signals - we just got new data in dp queue */ - if (uvd->flags & FLAGS_NO_DECODING) - usbvideo_CollectRawData(uvd, frame); - else if (VALID_CALLBACK(uvd, processData)) - GET_CALLBACK(uvd, processData)(uvd, frame); - else - err("%s: processData not set", __FUNCTION__); - } - } while (frame->frameState == FrameState_Grabbing); - if (uvd->debug >= 2) { - info("%s: Grabbing done; state=%d. (%lu. bytes)", - __FUNCTION__, frame->frameState, frame->seqRead_Length); - } - if (frame->frameState == FrameState_Error) { - int ret = usbvideo_NewFrame(uvd, frameNum); - if (ret < 0) { - err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret); - return ret; - } - goto redo; - } - /* Note that we fall through to meet our destiny below */ - } - case FrameState_Done: - /* - * Do all necessary postprocessing of data prepared in - * "interrupt" code and the collecting code above. The - * frame gets marked as FrameState_Done by queue parsing code. - * This status means that we collected enough data and - * most likely processed it as we went through. However - * the data may need postprocessing, such as deinterlacing - * or picture adjustments implemented in software (horror!) - * - * As soon as the frame becomes "final" it gets promoted to - * FrameState_Done_Hold status where it will remain until the - * caller consumed all the video data from the frame. Then - * the empty shell of ex-frame is thrown out for dogs to eat. - * But we, worried about pets, will recycle the frame! - */ - uvd->stats.frame_num++; - if ((uvd->flags & FLAGS_NO_DECODING) == 0) { - if (VALID_CALLBACK(uvd, postProcess)) - GET_CALLBACK(uvd, postProcess)(uvd, frame); - if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST) - usbvideo_SoftwareContrastAdjustment(uvd, frame); - } - frame->frameState = FrameState_Done_Hold; - if (uvd->debug >= 2) - info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__); - return 0; - - case FrameState_Done_Hold: - /* - * We stay in this state indefinitely until someone external, - * like ioctl() or read() call finishes digesting the frame - * data. Then it will mark the frame as FrameState_Unused and - * it will be released back into the wild to roam freely. - */ - if (uvd->debug >= 2) - info("%s: FrameState_Done_Hold state.", __FUNCTION__); - return 0; - } - - /* Catch-all for other cases. We shall not be here. */ - err("%s: Invalid state %d.", __FUNCTION__, frame->frameState); - frame->frameState = FrameState_Unused; - return 0; -} - -/* - * usbvideo_DeinterlaceFrame() - * - * This procedure deinterlaces the given frame. Some cameras produce - * only half of scanlines - sometimes only even lines, sometimes only - * odd lines. The deinterlacing method is stored in frame->deinterlace - * variable. - * - * Here we scan the frame vertically and replace missing scanlines with - * average between surrounding ones - before and after. If we have no - * line above then we just copy next line. Similarly, if we need to - * create a last line then preceding line is used. - */ -void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame) -{ - if ((uvd == NULL) || (frame == NULL)) - return; - - if ((frame->deinterlace == Deinterlace_FillEvenLines) || - (frame->deinterlace == Deinterlace_FillOddLines)) - { - const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1; - - for (; i < VIDEOSIZE_Y(frame->request); i += 2) { - const unsigned char *fs1, *fs2; - unsigned char *fd; - int ip, in, j; /* Previous and next lines */ - - /* - * Need to average lines before and after 'i'. - * If we go out of bounds seeking those lines then - * we point back to existing line. - */ - ip = i - 1; /* First, get rough numbers */ - in = i + 1; - - /* Now validate */ - if (ip < 0) - ip = in; - if (in >= VIDEOSIZE_Y(frame->request)) - in = ip; - - /* Sanity check */ - if ((ip < 0) || (in < 0) || - (ip >= VIDEOSIZE_Y(frame->request)) || - (in >= VIDEOSIZE_Y(frame->request))) - { - err("Error: ip=%d. in=%d. req.height=%ld.", - ip, in, VIDEOSIZE_Y(frame->request)); - break; - } - - /* Now we need to average lines 'ip' and 'in' to produce line 'i' */ - fs1 = frame->data + (v4l_linesize * ip); - fs2 = frame->data + (v4l_linesize * in); - fd = frame->data + (v4l_linesize * i); - - /* Average lines around destination */ - for (j=0; j < v4l_linesize; j++) { - fd[j] = (unsigned char)((((unsigned) fs1[j]) + - ((unsigned)fs2[j])) >> 1); - } - } - } - - /* Optionally display statistics on the screen */ - if (uvd->flags & FLAGS_OVERLAY_STATS) - usbvideo_OverlayStats(uvd, frame); -} - -EXPORT_SYMBOL(usbvideo_DeinterlaceFrame); - -/* - * usbvideo_SoftwareContrastAdjustment() - * - * This code adjusts the contrast of the frame, assuming RGB24 format. - * As most software image processing, this job is CPU-intensive. - * Get a camera that supports hardware adjustment! - * - * History: - * 09-Feb-2001 Created. - */ -static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, - struct usbvideo_frame *frame) -{ - int i, j, v4l_linesize; - signed long adj; - const int ccm = 128; /* Color correction median - see below */ - - if ((uvd == NULL) || (frame == NULL)) { - err("%s: Illegal call.", __FUNCTION__); - return; - } - adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ - RESTRICT_TO_RANGE(adj, -ccm, ccm+1); - if (adj == 0) { - /* In rare case of no adjustment */ - return; - } - v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - for (i=0; i < VIDEOSIZE_Y(frame->request); i++) { - unsigned char *fd = frame->data + (v4l_linesize * i); - for (j=0; j < v4l_linesize; j++) { - signed long v = (signed long) fd[j]; - /* Magnify up to 2 times, reduce down to zero */ - v = 128 + ((ccm + adj) * (v - 128)) / ccm; - RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */ - fd[j] = (unsigned char) v; - } - } -} - -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h deleted file mode 100644 index 135433c2680a..000000000000 --- a/drivers/usb/media/usbvideo.h +++ /dev/null @@ -1,394 +0,0 @@ -/* - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef usbvideo_h -#define usbvideo_h - -#include -#include -#include -#include - -/* Most helpful debugging aid */ -#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) - -#define USBVIDEO_REPORT_STATS 1 /* Set to 0 to block statistics on close */ - -/* Bit flags (options) */ -#define FLAGS_RETRY_VIDIOCSYNC (1 << 0) -#define FLAGS_MONOCHROME (1 << 1) -#define FLAGS_DISPLAY_HINTS (1 << 2) -#define FLAGS_OVERLAY_STATS (1 << 3) -#define FLAGS_FORCE_TESTPATTERN (1 << 4) -#define FLAGS_SEPARATE_FRAMES (1 << 5) -#define FLAGS_CLEAN_FRAMES (1 << 6) -#define FLAGS_NO_DECODING (1 << 7) - -/* Bit flags for frames (apply to the frame where they are specified) */ -#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST (1 << 0) - -/* Camera capabilities (maximum) */ -#define CAMERA_URB_FRAMES 32 -#define CAMERA_MAX_ISO_PACKET 1023 /* 1022 actually sent by camera */ -#define FRAMES_PER_DESC (CAMERA_URB_FRAMES) -#define FRAME_SIZE_PER_DESC (CAMERA_MAX_ISO_PACKET) - -/* This macro restricts an int variable to an inclusive range */ -#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } - -#define V4L_BYTES_PER_PIXEL 3 /* Because we produce RGB24 */ - -/* - * Use this macro to construct constants for different video sizes. - * We have to deal with different video sizes that have to be - * configured in the device or compared against when we receive - * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y - * #defines and that's the end of story. However this solution - * does not allow to convert between real pixel sizes and the - * constant (integer) value that may be used to tag a frame or - * whatever. The set of macros below constructs videosize constants - * from the pixel size and allows to reconstruct the pixel size - * from the combined value later. - */ -#define VIDEOSIZE(x,y) (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16)) -#define VIDEOSIZE_X(vs) ((vs) & 0xFFFFL) -#define VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL) -typedef unsigned long videosize_t; - -/* - * This macro checks if the camera is still operational. The 'uvd' - * pointer must be valid, uvd->dev must be valid, we are not - * removing the device and the device has not erred on us. - */ -#define CAMERA_IS_OPERATIONAL(uvd) (\ - (uvd != NULL) && \ - ((uvd)->dev != NULL) && \ - ((uvd)->last_error == 0) && \ - (!(uvd)->remove_pending)) - -/* - * We use macros to do YUV -> RGB conversion because this is - * very important for speed and totally unimportant for size. - * - * YUV -> RGB Conversion - * --------------------- - * - * B = 1.164*(Y-16) + 2.018*(V-128) - * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) - * R = 1.164*(Y-16) + 1.596*(U-128) - * - * If you fancy integer arithmetics (as you should), hear this: - * - * 65536*B = 76284*(Y-16) + 132252*(V-128) - * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) - * 65536*R = 76284*(Y-16) + 104595*(U-128) - * - * Make sure the output values are within [0..255] range. - */ -#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) -#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \ - int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ - mm_y = (my) - 16; \ - mm_u = (mu) - 128; \ - mm_v = (mv) - 128; \ - mm_yc= mm_y * 76284; \ - mm_b = (mm_yc + 132252*mm_v ) >> 16; \ - mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \ - mm_r = (mm_yc + 104595*mm_u ) >> 16; \ - mb = LIMIT_RGB(mm_b); \ - mg = LIMIT_RGB(mm_g); \ - mr = LIMIT_RGB(mm_r); \ -} - -#define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */ -#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1) -#define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n) -#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)]) - -struct RingQueue { - unsigned char *queue; /* Data from the Isoc data pump */ - int length; /* How many bytes allocated for the queue */ - int wi; /* That's where we write */ - int ri; /* Read from here until you hit write index */ - wait_queue_head_t wqh; /* Processes waiting */ -}; - -enum ScanState { - ScanState_Scanning, /* Scanning for header */ - ScanState_Lines /* Parsing lines */ -}; - -/* Completion states of the data parser */ -enum ParseState { - scan_Continue, /* Just parse next item */ - scan_NextFrame, /* Frame done, send it to V4L */ - scan_Out, /* Not enough data for frame */ - scan_EndParse /* End parsing */ -}; - -enum FrameState { - FrameState_Unused, /* Unused (no MCAPTURE) */ - FrameState_Ready, /* Ready to start grabbing */ - FrameState_Grabbing, /* In the process of being grabbed into */ - FrameState_Done, /* Finished grabbing, but not been synced yet */ - FrameState_Done_Hold, /* Are syncing or reading */ - FrameState_Error, /* Something bad happened while processing */ -}; - -/* - * Some frames may contain only even or odd lines. This type - * specifies what type of deinterlacing is required. - */ -enum Deinterlace { - Deinterlace_None=0, - Deinterlace_FillOddLines, - Deinterlace_FillEvenLines -}; - -#define USBVIDEO_NUMFRAMES 2 /* How many frames we work with */ -#define USBVIDEO_NUMSBUF 2 /* How many URBs linked in a ring */ - -/* This structure represents one Isoc request - URB and buffer */ -struct usbvideo_sbuf { - char *data; - struct urb *urb; -}; - -struct usbvideo_frame { - char *data; /* Frame buffer */ - unsigned long header; /* Significant bits from the header */ - - videosize_t canvas; /* The canvas (max. image) allocated */ - videosize_t request; /* That's what the application asked for */ - unsigned short palette; /* The desired format */ - - enum FrameState frameState;/* State of grabbing */ - enum ScanState scanstate; /* State of scanning */ - enum Deinterlace deinterlace; - int flags; /* USBVIDEO_FRAME_FLAG_xxx bit flags */ - - int curline; /* Line of frame we're working on */ - - long seqRead_Length; /* Raw data length of frame */ - long seqRead_Index; /* Amount of data that has been already read */ - - void *user; /* Additional data that user may need */ -}; - -/* Statistics that can be overlaid on screen */ -struct usbvideo_statistics { - unsigned long frame_num; /* Sequential number of the frame */ - unsigned long urb_count; /* How many URBs we received so far */ - unsigned long urb_length; /* Length of last URB */ - unsigned long data_count; /* How many bytes we received */ - unsigned long header_count; /* How many frame headers we found */ - unsigned long iso_skip_count; /* How many empty ISO packets received */ - unsigned long iso_err_count; /* How many bad ISO packets received */ -}; - -struct usbvideo; - -struct uvd { - struct video_device vdev; /* Must be the first field! */ - struct usb_device *dev; - struct usbvideo *handle; /* Points back to the struct usbvideo */ - void *user_data; /* Camera-dependent data */ - int user_size; /* Size of that camera-dependent data */ - int debug; /* Debug level for usbvideo */ - unsigned char iface; /* Video interface number */ - unsigned char video_endp; - unsigned char ifaceAltActive; - unsigned char ifaceAltInactive; /* Alt settings */ - unsigned long flags; /* FLAGS_USBVIDEO_xxx */ - unsigned long paletteBits; /* Which palettes we accept? */ - unsigned short defaultPalette; /* What palette to use for read() */ - struct mutex lock; - int user; /* user count for exclusive use */ - - videosize_t videosize; /* Current setting */ - videosize_t canvas; /* This is the width,height of the V4L canvas */ - int max_frame_size; /* Bytes in one video frame */ - - int uvd_used; /* Is this structure in use? */ - int streaming; /* Are we streaming Isochronous? */ - int grabbing; /* Are we grabbing? */ - int settingsAdjusted; /* Have we adjusted contrast etc.? */ - int last_error; /* What calamity struck us? */ - - char *fbuf; /* Videodev buffer area */ - int fbuf_size; /* Videodev buffer size */ - - int curframe; - int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */ - - struct RingQueue dp; /* Isoc data pump */ - struct usbvideo_frame frame[USBVIDEO_NUMFRAMES]; - struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF]; - - volatile int remove_pending; /* If set then about to exit */ - - struct video_picture vpic, vpic_old; /* Picture settings */ - struct video_capability vcap; /* Video capabilities */ - struct video_channel vchan; /* May be used for tuner support */ - struct usbvideo_statistics stats; - char videoName[32]; /* Holds name like "video7" */ -}; - -/* - * usbvideo callbacks (virtual methods). They are set when usbvideo - * services are registered. All of these default to NULL, except those - * that default to usbvideo-provided methods. - */ -struct usbvideo_cb { - int (*probe)(struct usb_interface *, const struct usb_device_id *); - void (*userFree)(struct uvd *); - void (*disconnect)(struct usb_interface *); - int (*setupOnOpen)(struct uvd *); - void (*videoStart)(struct uvd *); - void (*videoStop)(struct uvd *); - void (*processData)(struct uvd *, struct usbvideo_frame *); - void (*postProcess)(struct uvd *, struct usbvideo_frame *); - void (*adjustPicture)(struct uvd *); - int (*getFPS)(struct uvd *); - int (*overlayHook)(struct uvd *, struct usbvideo_frame *); - int (*getFrame)(struct uvd *, int); - int (*startDataPump)(struct uvd *uvd); - void (*stopDataPump)(struct uvd *uvd); - int (*setVideoMode)(struct uvd *uvd, struct video_window *vw); -}; - -struct usbvideo { - int num_cameras; /* As allocated */ - struct usb_driver usbdrv; /* Interface to the USB stack */ - char drvName[80]; /* Driver name */ - struct mutex lock; /* Mutex protecting camera structures */ - struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */ - struct video_device vdt; /* Video device template */ - struct uvd *cam; /* Array of camera structures */ - struct module *md_module; /* Minidriver module */ -}; - - -/* - * This macro retrieves callback address from the struct uvd object. - * No validity checks are done here, so be sure to check the - * callback beforehand with VALID_CALLBACK. - */ -#define GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName) - -/* - * This macro returns either callback pointer or NULL. This is safe - * macro, meaning that most of components of data structures involved - * may be NULL - this only results in NULL being returned. You may - * wish to use this macro to make sure that the callback is callable. - * However keep in mind that those checks take time. - */ -#define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \ - ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL) - -int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len); -int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n); -void RingQueue_WakeUpInterruptible(struct RingQueue *rq); -void RingQueue_Flush(struct RingQueue *rq); - -static inline int RingQueue_GetLength(const struct RingQueue *rq) -{ - return (rq->wi - rq->ri + rq->length) & (rq->length-1); -} - -static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq) -{ - return rq->length - RingQueue_GetLength(rq); -} - -void usbvideo_DrawLine( - struct usbvideo_frame *frame, - int x1, int y1, - int x2, int y2, - unsigned char cr, unsigned char cg, unsigned char cb); -void usbvideo_HexDump(const unsigned char *data, int len); -void usbvideo_SayAndWait(const char *what); -void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode); - -/* Memory allocation routines */ -unsigned long usbvideo_kvirt_to_pa(unsigned long adr); - -int usbvideo_register( - struct usbvideo **pCams, - const int num_cams, - const int num_extra, - const char *driverName, - const struct usbvideo_cb *cbTable, - struct module *md, - const struct usb_device_id *id_table); -struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams); -int usbvideo_RegisterVideoDevice(struct uvd *uvd); -void usbvideo_Deregister(struct usbvideo **uvt); - -int usbvideo_v4l_initialize(struct video_device *dev); - -void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame); - -/* - * This code performs bounds checking - use it when working with - * new formats, or else you may get oopses all over the place. - * If pixel falls out of bounds then it gets shoved back (as close - * to place of offence as possible) and is painted bright red. - * - * There are two important concepts: frame width, height and - * V4L canvas width, height. The former is the area requested by - * the application -for this very frame-. The latter is the largest - * possible frame that we can serve (we advertise that via V4L ioctl). - * The frame data is expected to be formatted as lines of length - * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines. - */ -static inline void RGB24_PUTPIXEL( - struct usbvideo_frame *fr, - int ix, int iy, - unsigned char vr, - unsigned char vg, - unsigned char vb) -{ - register unsigned char *pf; - int limiter = 0, mx, my; - mx = ix; - my = iy; - if (mx < 0) { - mx=0; - limiter++; - } else if (mx >= VIDEOSIZE_X((fr)->request)) { - mx= VIDEOSIZE_X((fr)->request) - 1; - limiter++; - } - if (my < 0) { - my = 0; - limiter++; - } else if (my >= VIDEOSIZE_Y((fr)->request)) { - my = VIDEOSIZE_Y((fr)->request) - 1; - limiter++; - } - pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix)); - if (limiter) { - *pf++ = 0; - *pf++ = 0; - *pf++ = 0xFF; - } else { - *pf++ = (vb); - *pf++ = (vg); - *pf++ = (vr); - } -} - -#endif /* usbvideo_h */ diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c deleted file mode 100644 index 1d06e53ec7c5..000000000000 --- a/drivers/usb/media/vicam.c +++ /dev/null @@ -1,1411 +0,0 @@ -/* - * USB ViCam WebCam driver - * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), - * Christopher L Cheney (ccheney@cheney.cx), - * Pavel Machek (pavel@suse.cz), - * John Tyner (jtyner@cs.ucr.edu), - * Monroe Williams (monroe@pobox.com) - * - * Supports 3COM HomeConnect PC Digital WebCam - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This source code is based heavily on the CPiA webcam driver which was - * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt - * - * Portions of this code were also copied from usbvideo.c - * - * Special thanks to the the whole team at Sourceforge for help making - * this driver become a reality. Notably: - * Andy Armstrong who reverse engineered the color encoding and - * Pavel Machek and Chris Cheney who worked on reverse engineering the - * camera controls and wrote the first generation driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usbvideo.h" - -// #define VICAM_DEBUG - -#ifdef VICAM_DEBUG -#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args) -#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) -#else -#define DBG(fmn,args...) do {} while(0) -#endif - -#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" -#define DRIVER_DESC "ViCam WebCam Driver" - -/* Define these values to match your device */ -#define USB_VICAM_VENDOR_ID 0x04c1 -#define USB_VICAM_PRODUCT_ID 0x009d - -#define VICAM_BYTES_PER_PIXEL 3 -#define VICAM_MAX_READ_SIZE (512*242+128) -#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) -#define VICAM_FRAMES 2 - -#define VICAM_HEADER_SIZE 64 - -#define clamp( x, l, h ) max_t( __typeof__( x ), \ - ( l ), \ - min_t( __typeof__( x ), \ - ( h ), \ - ( x ) ) ) - -/* Not sure what all the bytes in these char - * arrays do, but they're necessary to make - * the camera work. - */ - -static unsigned char setup1[] = { - 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67, - 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00, - 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17, - 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00, - 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 -}; - -static unsigned char setup2[] = { - 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00, - 0x00, 0x00 -}; - -static unsigned char setup3[] = { - 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00 -}; - -static unsigned char setup4[] = { - 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07, - 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00, - 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00, - 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07, - 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00, - 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00, - 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07, - 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, - 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0, - 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07, - 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00, - 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0, - 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1, - 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09, - 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, - 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF, - 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02, - 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, - 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF, - 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00, - 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00, - 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05, - 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA, - 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06, - 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF, - 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05, - 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01, - 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09, - 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06, - 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05, - 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA, - 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05, - 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, - 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00, - 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF, - 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00, - 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0, - 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06, - 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00, - 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07, - 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF, - 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00, - 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, - 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57, - 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57, - 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00, - 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0, - 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B, - 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06, - 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, - 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E, - 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, - 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, - 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00, - 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, - 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF, - 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0, - 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, - 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05, - 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF, - 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0, - 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07, - 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07, - 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF, - 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF, - 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, - 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, - 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1, - 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67, - 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00, - 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07, - 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07, - 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07, - 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00, - 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06, - 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67, - 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8, - 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, - 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF, - 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02, - 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, - 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06, - 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05, - 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, - 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00, - 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06, - 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, - 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05, - 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05, - 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, - 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04, - 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF, - 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06, - 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00, - 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05, - 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07, - 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07, - 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07, - 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF, - 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07, - 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06, - 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05, - 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07, - 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00, - 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00, - 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77, - 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04, - 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0, - 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1, - 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07, - 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, - 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, - 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, - 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77, - 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1, - 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07, - 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06, - 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, - 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, - 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07, - 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00, - 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00, - 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F, - 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00, - 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00, - 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA, - 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, - 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06, - 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B, - 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09, - 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05, - 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07, - 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00, - 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF, - 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05, - 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00, - 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00, - 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00, - 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09, - 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00, - 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00, - 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0, - 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67, - 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87, - 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9, - 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1, - 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF, - 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00, - 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0, - 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87, - 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, - 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67, - 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, - 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, - 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67, - 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, - 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, - 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00, - 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF, - 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, - 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67, - 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09, - 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, - 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA, - 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87, - 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07, - 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, - 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07, - 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, - 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02, - 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, - 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static unsigned char setup5[] = { - 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00, - 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, - 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00, - 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00, - 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, - 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00, - 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00, - 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01, - 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01, - 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01, - 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01, - 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01, - 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01, - 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01, - 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01, - 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02, - 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02, - 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, - 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02, - 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, - 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02, - 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02, - 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02, - 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03, - 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03, - 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03, - 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03, - 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03, - 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03, - 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03, - 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04, - 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04, - 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04, - 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04, - 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04, - 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04, - 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04, - 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05, - 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 -}; - -/* rvmalloc / rvfree copied from usbvideo.c - * - * Not sure why these are not yet non-statics which I can reference through - * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime - * in the future. - * -*/ -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - -struct vicam_camera { - u16 shutter_speed; // capture shutter speed - u16 gain; // capture gain - - u8 *raw_image; // raw data captured from the camera - u8 *framebuf; // processed data in RGB24 format - u8 *cntrlbuf; // area used to send control msgs - - struct video_device vdev; // v4l video device - struct usb_device *udev; // usb device - - /* guard against simultaneous accesses to the camera */ - struct mutex cam_lock; - - int is_initialized; - u8 open_count; - u8 bulkEndpoint; - int needsDummyRead; - -#if defined(CONFIG_VIDEO_PROC_FS) - struct proc_dir_entry *proc_dir; -#endif - -}; - -static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); -static void vicam_disconnect(struct usb_interface *intf); -static void read_frame(struct vicam_camera *cam, int framenum); -static void vicam_decode_color(const u8 *, u8 *); - -static int __send_control_msg(struct vicam_camera *cam, - u8 request, - u16 value, - u16 index, - unsigned char *cp, - u16 size) -{ - int status; - - /* cp must be memory that has been allocated by kmalloc */ - - status = usb_control_msg(cam->udev, - usb_sndctrlpipe(cam->udev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, value, index, - cp, size, 1000); - - status = min(status, 0); - - if (status < 0) { - printk(KERN_INFO "Failed sending control message, error %d.\n", - status); - } - - return status; -} - -static int send_control_msg(struct vicam_camera *cam, - u8 request, - u16 value, - u16 index, - unsigned char *cp, - u16 size) -{ - int status = -ENODEV; - mutex_lock(&cam->cam_lock); - if (cam->udev) { - status = __send_control_msg(cam, request, value, - index, cp, size); - } - mutex_unlock(&cam->cam_lock); - return status; -} -static int -initialize_camera(struct vicam_camera *cam) -{ - const struct { - u8 *data; - u32 size; - } firmware[] = { - { .data = setup1, .size = sizeof(setup1) }, - { .data = setup2, .size = sizeof(setup2) }, - { .data = setup3, .size = sizeof(setup3) }, - { .data = setup4, .size = sizeof(setup4) }, - { .data = setup5, .size = sizeof(setup5) }, - { .data = setup3, .size = sizeof(setup3) }, - { .data = NULL, .size = 0 } - }; - - int err, i; - - for (i = 0, err = 0; firmware[i].data && !err; i++) { - memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size); - - err = send_control_msg(cam, 0xff, 0, 0, - cam->cntrlbuf, firmware[i].size); - } - - return err; -} - -static int -set_camera_power(struct vicam_camera *cam, int state) -{ - int status; - - if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0) - return status; - - if (state) { - send_control_msg(cam, 0x55, 1, 0, NULL, 0); - } - - return 0; -} - -static int -vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg) -{ - void __user *user_arg = (void __user *)arg; - struct vicam_camera *cam = file->private_data; - int retval = 0; - - if (!cam) - return -ENODEV; - - switch (ioctlnr) { - /* query capabilities */ - case VIDIOCGCAP: - { - struct video_capability b; - - DBG("VIDIOCGCAP\n"); - memset(&b, 0, sizeof(b)); - strcpy(b.name, "ViCam-based Camera"); - b.type = VID_TYPE_CAPTURE; - b.channels = 1; - b.audios = 0; - b.maxwidth = 320; /* VIDEOSIZE_CIF */ - b.maxheight = 240; - b.minwidth = 320; /* VIDEOSIZE_48_48 */ - b.minheight = 240; - - if (copy_to_user(user_arg, &b, sizeof(b))) - retval = -EFAULT; - - break; - } - /* get/set video source - we are a camera and nothing else */ - case VIDIOCGCHAN: - { - struct video_channel v; - - DBG("VIDIOCGCHAN\n"); - if (copy_from_user(&v, user_arg, sizeof(v))) { - retval = -EFAULT; - break; - } - if (v.channel != 0) { - retval = -EINVAL; - break; - } - - v.channel = 0; - strcpy(v.name, "Camera"); - v.tuners = 0; - v.flags = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = 0; - - if (copy_to_user(user_arg, &v, sizeof(v))) - retval = -EFAULT; - break; - } - - case VIDIOCSCHAN: - { - int v; - - if (copy_from_user(&v, user_arg, sizeof(v))) - retval = -EFAULT; - DBG("VIDIOCSCHAN %d\n", v); - - if (retval == 0 && v != 0) - retval = -EINVAL; - - break; - } - - /* image properties */ - case VIDIOCGPICT: - { - struct video_picture vp; - DBG("VIDIOCGPICT\n"); - memset(&vp, 0, sizeof (struct video_picture)); - vp.brightness = cam->gain << 8; - vp.depth = 24; - vp.palette = VIDEO_PALETTE_RGB24; - if (copy_to_user(user_arg, &vp, sizeof (struct video_picture))) - retval = -EFAULT; - break; - } - - case VIDIOCSPICT: - { - struct video_picture vp; - - if (copy_from_user(&vp, user_arg, sizeof(vp))) { - retval = -EFAULT; - break; - } - - DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth, - vp.palette); - - cam->gain = vp.brightness >> 8; - - if (vp.depth != 24 - || vp.palette != VIDEO_PALETTE_RGB24) - retval = -EINVAL; - - break; - } - - /* get/set capture window */ - case VIDIOCGWIN: - { - struct video_window vw; - vw.x = 0; - vw.y = 0; - vw.width = 320; - vw.height = 240; - vw.chromakey = 0; - vw.flags = 0; - vw.clips = NULL; - vw.clipcount = 0; - - DBG("VIDIOCGWIN\n"); - - if (copy_to_user(user_arg, (void *)&vw, sizeof(vw))) - retval = -EFAULT; - - // I'm not sure what the deal with a capture window is, it is very poorly described - // in the doc. So I won't support it now. - break; - } - - case VIDIOCSWIN: - { - - struct video_window vw; - - if (copy_from_user(&vw, user_arg, sizeof(vw))) { - retval = -EFAULT; - break; - } - - DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height); - - if ( vw.width != 320 || vw.height != 240 ) - retval = -EFAULT; - - break; - } - - /* mmap interface */ - case VIDIOCGMBUF: - { - struct video_mbuf vm; - int i; - - DBG("VIDIOCGMBUF\n"); - memset(&vm, 0, sizeof (vm)); - vm.size = - VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; - vm.frames = VICAM_FRAMES; - for (i = 0; i < VICAM_FRAMES; i++) - vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; - - if (copy_to_user(user_arg, (void *)&vm, sizeof(vm))) - retval = -EFAULT; - - break; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - // int video_size; - - if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) { - retval = -EFAULT; - break; - } - - DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); - - if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) - retval = -EINVAL; - - // in theory right here we'd start the image capturing - // (fill in a bulk urb and submit it asynchronously) - // - // Instead we're going to do a total hack job for now and - // retrieve the frame in VIDIOCSYNC - - break; - } - - case VIDIOCSYNC: - { - int frame; - - if (copy_from_user((void *)&frame, user_arg, sizeof(int))) { - retval = -EFAULT; - break; - } - DBG("VIDIOCSYNC: %d\n", frame); - - read_frame(cam, frame); - vicam_decode_color(cam->raw_image, - cam->framebuf + - frame * VICAM_MAX_FRAME_SIZE ); - - break; - } - - /* pointless to implement overlay with this camera */ - case VIDIOCCAPTURE: - case VIDIOCGFBUF: - case VIDIOCSFBUF: - case VIDIOCKEY: - retval = -EINVAL; - break; - - /* tuner interface - we have none */ - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - retval = -EINVAL; - break; - - /* audio interface - we have none */ - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - retval = -EINVAL; - break; - default: - retval = -ENOIOCTLCMD; - break; - } - - return retval; -} - -static int -vicam_open(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct vicam_camera *cam = - (struct vicam_camera *) dev->priv; - DBG("open\n"); - - if (!cam) { - printk(KERN_ERR - "vicam video_device improperly initialized"); - return -EINVAL; - } - - /* the videodev_lock held above us protects us from - * simultaneous opens...for now. we probably shouldn't - * rely on this fact forever. - */ - - if (cam->open_count > 0) { - printk(KERN_INFO - "vicam_open called on already opened camera"); - return -EBUSY; - } - - cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); - if (!cam->raw_image) { - return -ENOMEM; - } - - cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - if (!cam->framebuf) { - kfree(cam->raw_image); - return -ENOMEM; - } - - cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!cam->cntrlbuf) { - kfree(cam->raw_image); - rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - return -ENOMEM; - } - - // First upload firmware, then turn the camera on - - if (!cam->is_initialized) { - initialize_camera(cam); - - cam->is_initialized = 1; - } - - set_camera_power(cam, 1); - - cam->needsDummyRead = 1; - cam->open_count++; - - file->private_data = cam; - - return 0; -} - -static int -vicam_close(struct inode *inode, struct file *file) -{ - struct vicam_camera *cam = file->private_data; - int open_count; - struct usb_device *udev; - - DBG("close\n"); - - /* it's not the end of the world if - * we fail to turn the camera off. - */ - - set_camera_power(cam, 0); - - kfree(cam->raw_image); - rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - kfree(cam->cntrlbuf); - - mutex_lock(&cam->cam_lock); - - cam->open_count--; - open_count = cam->open_count; - udev = cam->udev; - - mutex_unlock(&cam->cam_lock); - - if (!open_count && !udev) { - kfree(cam); - } - - return 0; -} - -static void vicam_decode_color(const u8 *data, u8 *rgb) -{ - /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB - * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) - */ - - int i, prevY, nextY; - - prevY = 512; - nextY = 512; - - data += VICAM_HEADER_SIZE; - - for( i = 0; i < 240; i++, data += 512 ) { - const int y = ( i * 242 ) / 240; - - int j, prevX, nextX; - int Y, Cr, Cb; - - if ( y == 242 - 1 ) { - nextY = -512; - } - - prevX = 1; - nextX = 1; - - for ( j = 0; j < 320; j++, rgb += 3 ) { - const int x = ( j * 512 ) / 320; - const u8 * const src = &data[x]; - - if ( x == 512 - 1 ) { - nextX = -1; - } - - Cr = ( src[prevX] - src[0] ) + - ( src[nextX] - src[0] ); - Cr /= 2; - - Cb = ( src[prevY] - src[prevX + prevY] ) + - ( src[prevY] - src[nextX + prevY] ) + - ( src[nextY] - src[prevX + nextY] ) + - ( src[nextY] - src[nextX + nextY] ); - Cb /= 4; - - Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); - - if ( i & 1 ) { - int Ct = Cr; - Cr = Cb; - Cb = Ct; - } - - if ( ( x ^ i ) & 1 ) { - Cr = -Cr; - Cb = -Cb; - } - - rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + - 500 ) / 900, 0, 255 ); - rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - - ( 813 * Cr ) ) + - 500 ) / 1000, 0, 255 ); - rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + - 500 ) / 1300, 0, 255 ); - - prevX = -1; - } - - prevY = -512; - } -} - -static void -read_frame(struct vicam_camera *cam, int framenum) -{ - unsigned char *request = cam->cntrlbuf; - int realShutter; - int n; - int actual_length; - - if (cam->needsDummyRead) { - cam->needsDummyRead = 0; - read_frame(cam, framenum); - } - - memset(request, 0, 16); - request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain - - request[1] = 0; // 512x242 capture - - request[2] = 0x90; // the function of these two bytes - request[3] = 0x07; // is not yet understood - - if (cam->shutter_speed > 60) { - // Short exposure - realShutter = - ((-15631900 / cam->shutter_speed) + 260533) / 1000; - request[4] = realShutter & 0xFF; - request[5] = (realShutter >> 8) & 0xFF; - request[6] = 0x03; - request[7] = 0x01; - } else { - // Long exposure - realShutter = 15600 / cam->shutter_speed - 1; - request[4] = 0; - request[5] = 0; - request[6] = realShutter & 0xFF; - request[7] = realShutter >> 8; - } - - // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 - request[8] = 0; - // bytes 9-15 do not seem to affect exposure or image quality - - mutex_lock(&cam->cam_lock); - - if (!cam->udev) { - goto done; - } - - n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16); - - if (n < 0) { - printk(KERN_ERR - " Problem sending frame capture control message"); - goto done; - } - - n = usb_bulk_msg(cam->udev, - usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), - cam->raw_image, - 512 * 242 + 128, &actual_length, 10000); - - if (n < 0) { - printk(KERN_ERR "Problem during bulk read of frame data: %d\n", - n); - } - - done: - mutex_unlock(&cam->cam_lock); -} - -static ssize_t -vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos ) -{ - struct vicam_camera *cam = file->private_data; - - DBG("read %d bytes.\n", (int) count); - - if (*ppos >= VICAM_MAX_FRAME_SIZE) { - *ppos = 0; - return 0; - } - - if (*ppos == 0) { - read_frame(cam, 0); - vicam_decode_color(cam->raw_image, - cam->framebuf + - 0 * VICAM_MAX_FRAME_SIZE); - } - - count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos); - - if (copy_to_user(buf, &cam->framebuf[*ppos], count)) { - count = -EFAULT; - } else { - *ppos += count; - } - - if (count == VICAM_MAX_FRAME_SIZE) { - *ppos = 0; - } - - return count; -} - - -static int -vicam_mmap(struct file *file, struct vm_area_struct *vma) -{ - // TODO: allocate the raw frame buffer if necessary - unsigned long page, pos; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - struct vicam_camera *cam = file->private_data; - - if (!cam) - return -ENODEV; - - DBG("vicam_mmap: %ld\n", size); - - /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes - * to the size the application requested for mmap and it was screwing apps up. - if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) - return -EINVAL; - */ - - pos = (unsigned long)cam->framebuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return 0; -} - -#if defined(CONFIG_VIDEO_PROC_FS) - -static struct proc_dir_entry *vicam_proc_root = NULL; - -static int vicam_read_helper(char *page, char **start, off_t off, - int count, int *eof, int value) -{ - char *out = page; - int len; - - out += sprintf(out, "%d",value); - - len = out - page; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) - return 0; - } else - len = count; - - *start = page + off; - return len; -} - -static int vicam_read_proc_shutter(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return vicam_read_helper(page,start,off,count,eof, - ((struct vicam_camera *)data)->shutter_speed); -} - -static int vicam_read_proc_gain(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return vicam_read_helper(page,start,off,count,eof, - ((struct vicam_camera *)data)->gain); -} - -static int -vicam_write_proc_shutter(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - u16 stmp; - char kbuf[8]; - struct vicam_camera *cam = (struct vicam_camera *) data; - - if (count > 6) - return -EINVAL; - - if (copy_from_user(kbuf, buffer, count)) - return -EFAULT; - - stmp = (u16) simple_strtoul(kbuf, NULL, 10); - if (stmp < 4 || stmp > 32000) - return -EINVAL; - - cam->shutter_speed = stmp; - - return count; -} - -static int -vicam_write_proc_gain(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - u16 gtmp; - char kbuf[8]; - - struct vicam_camera *cam = (struct vicam_camera *) data; - - if (count > 4) - return -EINVAL; - - if (copy_from_user(kbuf, buffer, count)) - return -EFAULT; - - gtmp = (u16) simple_strtoul(kbuf, NULL, 10); - if (gtmp > 255) - return -EINVAL; - cam->gain = gtmp; - - return count; -} - -static void -vicam_create_proc_root(void) -{ - vicam_proc_root = proc_mkdir("video/vicam", NULL); - - if (vicam_proc_root) - vicam_proc_root->owner = THIS_MODULE; - else - printk(KERN_ERR - "could not create /proc entry for vicam!"); -} - -static void -vicam_destroy_proc_root(void) -{ - if (vicam_proc_root) - remove_proc_entry("video/vicam", 0); -} - -static void -vicam_create_proc_entry(struct vicam_camera *cam) -{ - char name[64]; - struct proc_dir_entry *ent; - - DBG(KERN_INFO "vicam: creating proc entry\n"); - - if (!vicam_proc_root || !cam) { - printk(KERN_INFO - "vicam: could not create proc entry, %s pointer is null.\n", - (!cam ? "camera" : "root")); - return; - } - - sprintf(name, "video%d", cam->vdev.minor); - - cam->proc_dir = proc_mkdir(name, vicam_proc_root); - - if ( !cam->proc_dir ) - return; // FIXME: We should probably return an error here - - ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR, - cam->proc_dir); - if (ent) { - ent->data = cam; - ent->read_proc = vicam_read_proc_shutter; - ent->write_proc = vicam_write_proc_shutter; - ent->size = 64; - } - - ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR, - cam->proc_dir); - if (ent) { - ent->data = cam; - ent->read_proc = vicam_read_proc_gain; - ent->write_proc = vicam_write_proc_gain; - ent->size = 64; - } -} - -static void -vicam_destroy_proc_entry(void *ptr) -{ - struct vicam_camera *cam = (struct vicam_camera *) ptr; - char name[16]; - - if ( !cam->proc_dir ) - return; - - sprintf(name, "video%d", cam->vdev.minor); - remove_proc_entry("shutter", cam->proc_dir); - remove_proc_entry("gain", cam->proc_dir); - remove_proc_entry(name,vicam_proc_root); - cam->proc_dir = NULL; - -} - -#else -static inline void vicam_create_proc_root(void) { } -static inline void vicam_destroy_proc_root(void) { } -static inline void vicam_create_proc_entry(struct vicam_camera *cam) { } -static inline void vicam_destroy_proc_entry(void *ptr) { } -#endif - -static struct file_operations vicam_fops = { - .owner = THIS_MODULE, - .open = vicam_open, - .release = vicam_close, - .read = vicam_read, - .mmap = vicam_mmap, - .ioctl = vicam_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -static struct video_device vicam_template = { - .owner = THIS_MODULE, - .name = "ViCam-based USB Camera", - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_VICAM, - .fops = &vicam_fops, - .minor = -1, -}; - -/* table of devices that work with this driver */ -static struct usb_device_id vicam_table[] = { - {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, vicam_table); - -static struct usb_driver vicam_driver = { - .name = "vicam", - .probe = vicam_probe, - .disconnect = vicam_disconnect, - .id_table = vicam_table -}; - -/** - * vicam_probe - * @intf: the interface - * @id: the device id - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ -static int -vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - int bulkEndpoint = 0; - const struct usb_host_interface *interface; - const struct usb_endpoint_descriptor *endpoint; - struct vicam_camera *cam; - - printk(KERN_INFO "ViCam based webcam connected\n"); - - interface = intf->cur_altsetting; - - DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", - interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints)); - endpoint = &interface->endpoint[0].desc; - - if ((endpoint->bEndpointAddress & 0x80) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found a bulk in endpoint */ - bulkEndpoint = endpoint->bEndpointAddress; - } else { - printk(KERN_ERR - "No bulk in endpoint was found ?! (this is bad)\n"); - } - - if ((cam = - kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { - printk(KERN_WARNING - "could not allocate kernel memory for vicam_camera struct\n"); - return -ENOMEM; - } - - memset(cam, 0, sizeof (struct vicam_camera)); - - cam->shutter_speed = 15; - - mutex_init(&cam->cam_lock); - - memcpy(&cam->vdev, &vicam_template, - sizeof (vicam_template)); - cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only - - cam->udev = dev; - cam->bulkEndpoint = bulkEndpoint; - - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { - kfree(cam); - printk(KERN_WARNING "video_register_device failed\n"); - return -EIO; - } - - vicam_create_proc_entry(cam); - - printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); - - usb_set_intfdata (intf, cam); - - return 0; -} - -static void -vicam_disconnect(struct usb_interface *intf) -{ - int open_count; - struct vicam_camera *cam = usb_get_intfdata (intf); - usb_set_intfdata (intf, NULL); - - /* we must unregister the device before taking its - * cam_lock. This is because the video open call - * holds the same lock as video unregister. if we - * unregister inside of the cam_lock and open also - * uses the cam_lock, we get deadlock. - */ - - video_unregister_device(&cam->vdev); - - /* stop the camera from being used */ - - mutex_lock(&cam->cam_lock); - - /* mark the camera as gone */ - - cam->udev = NULL; - - vicam_destroy_proc_entry(cam); - - /* the only thing left to do is synchronize with - * our close/release function on who should release - * the camera memory. if there are any users using the - * camera, it's their job. if there are no users, - * it's ours. - */ - - open_count = cam->open_count; - - mutex_unlock(&cam->cam_lock); - - if (!open_count) { - kfree(cam); - } - - printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); -} - -/* - */ -static int __init -usb_vicam_init(void) -{ - int retval; - DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); - vicam_create_proc_root(); - retval = usb_register(&vicam_driver); - if (retval) - printk(KERN_WARNING "usb_register failed!\n"); - return retval; -} - -static void __exit -usb_vicam_exit(void) -{ - DBG(KERN_INFO - "ViCam-based WebCam driver shutdown\n"); - - usb_deregister(&vicam_driver); - vicam_destroy_proc_root(); -} - -module_init(usb_vicam_init); -module_exit(usb_vicam_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c deleted file mode 100644 index b57dec3782e0..000000000000 --- a/drivers/usb/media/w9968cf.c +++ /dev/null @@ -1,3691 +0,0 @@ -/*************************************************************************** - * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * - * * - * Copyright (C) 2002-2004 by Luca Risolia * - * * - * - Memory management code from bttv driver by Ralph Metzler, * - * Marcus Metzler and Gerd Knorr. * - * - I2C interface to kernel, high-level image sensor control routines and * - * some symbolic names from OV511 driver by Mark W. McClelland. * - * - Low-level I2C fast write function by Piotr Czerczak. * - * - Low-level I2C read function by Frederic Jouault. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "w9968cf.h" -#include "w9968cf_decoder.h" - -static struct w9968cf_vpp_t* w9968cf_vpp; -static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); - -static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ -static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */ - -static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ - - -/**************************************************************************** - * Module macros and parameters * - ****************************************************************************/ - -MODULE_DEVICE_TABLE(usb, winbond_id_table); - -MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL); -MODULE_DESCRIPTION(W9968CF_MODULE_NAME); -MODULE_VERSION(W9968CF_MODULE_VERSION); -MODULE_LICENSE(W9968CF_MODULE_LICENSE); -MODULE_SUPPORTED_DEVICE("Video"); - -static int ovmod_load = W9968CF_OVMOD_LOAD; -static unsigned short simcams = W9968CF_SIMCAMS; -static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/ -static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_PACKET_SIZE}; -static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_BUFFERS}; -static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_DOUBLE_BUFFER}; -static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING}; -static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_FILTER_TYPE}; -static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW}; -static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_DECOMPRESSION}; -static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING}; -static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0}; -static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB}; -static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT}; -static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP}; -static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_LIGHTFREQ}; -static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]= - W9968CF_BANDINGFILTER}; -static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; -static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT}; -static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR}; -static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME}; -static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_BRIGHTNESS}; -static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE}; -static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR}; -static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_CONTRAST}; -static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = - W9968CF_WHITENESS}; -#ifdef W9968CF_DEBUG -static unsigned short debug = W9968CF_DEBUG_LEVEL; -static int specific_debug = W9968CF_SPECIFIC_DEBUG; -#endif - -static unsigned int param_nv[24]; /* number of values per parameter */ - -#ifdef CONFIG_KMOD -module_param(ovmod_load, bool, 0644); -#endif -module_param(simcams, ushort, 0644); -module_param_array(video_nr, short, ¶m_nv[0], 0444); -module_param_array(packet_size, uint, ¶m_nv[1], 0444); -module_param_array(max_buffers, ushort, ¶m_nv[2], 0444); -module_param_array(double_buffer, bool, ¶m_nv[3], 0444); -module_param_array(clamping, bool, ¶m_nv[4], 0444); -module_param_array(filter_type, ushort, ¶m_nv[5], 0444); -module_param_array(largeview, bool, ¶m_nv[6], 0444); -module_param_array(decompression, ushort, ¶m_nv[7], 0444); -module_param_array(upscaling, bool, ¶m_nv[8], 0444); -module_param_array(force_palette, ushort, ¶m_nv[9], 0444); -module_param_array(force_rgb, ushort, ¶m_nv[10], 0444); -module_param_array(autobright, bool, ¶m_nv[11], 0444); -module_param_array(autoexp, bool, ¶m_nv[12], 0444); -module_param_array(lightfreq, ushort, ¶m_nv[13], 0444); -module_param_array(bandingfilter, bool, ¶m_nv[14], 0444); -module_param_array(clockdiv, short, ¶m_nv[15], 0444); -module_param_array(backlight, bool, ¶m_nv[16], 0444); -module_param_array(mirror, bool, ¶m_nv[17], 0444); -module_param_array(monochrome, bool, ¶m_nv[18], 0444); -module_param_array(brightness, uint, ¶m_nv[19], 0444); -module_param_array(hue, uint, ¶m_nv[20], 0444); -module_param_array(colour, uint, ¶m_nv[21], 0444); -module_param_array(contrast, uint, ¶m_nv[22], 0444); -module_param_array(whiteness, uint, ¶m_nv[23], 0444); -#ifdef W9968CF_DEBUG -module_param(debug, ushort, 0644); -module_param(specific_debug, bool, 0644); -#endif - -#ifdef CONFIG_KMOD -MODULE_PARM_DESC(ovmod_load, - "\n<0|1> Automatic 'ovcamchip' module loading." - "\n0 disabled, 1 enabled." - "\nIf enabled,'insmod' searches for the required 'ovcamchip'" - "\nmodule in the system, according to its configuration, and" - "\nattempts to load that module automatically. This action is" - "\nperformed once as soon as the 'w9968cf' module is loaded" - "\ninto memory." - "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"." - "\n"); -#endif -MODULE_PARM_DESC(simcams, - "\n Number of cameras allowed to stream simultaneously." - "\nn may vary from 0 to " - __MODULE_STRING(W9968CF_MAX_DEVICES)"." - "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"." - "\n"); -MODULE_PARM_DESC(video_nr, - "\n<-1|n[,...]> Specify V4L minor mode number." - "\n -1 = use next available (default)" - "\n n = use minor number n (integer >= 0)" - "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES) - " cameras this way." - "\nFor example:" - "\nvideo_nr=-1,2,-1 would assign minor number 2 to" - "\nthe second camera and use auto for the first" - "\none and for every other camera." - "\n"); -MODULE_PARM_DESC(packet_size, - "\n Specify the maximum data payload" - "\nsize in bytes for alternate settings, for each device." - "\nn is scaled between 63 and 1023 " - "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")." - "\n"); -MODULE_PARM_DESC(max_buffers, - "\n For advanced users." - "\nSpecify the maximum number of video frame buffers" - "\nto allocate for each device, from 2 to " - __MODULE_STRING(W9968CF_MAX_BUFFERS) - ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")." - "\n"); -MODULE_PARM_DESC(double_buffer, - "\n<0|1[,...]> " - "Hardware double buffering: 0 disabled, 1 enabled." - "\nIt should be enabled if you want smooth video output: if" - "\nyou obtain out of sync. video, disable it, or try to" - "\ndecrease the 'clockdiv' module parameter value." - "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER) - " for every device." - "\n"); -MODULE_PARM_DESC(clamping, - "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled." - "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING) - " for every device." - "\n"); -MODULE_PARM_DESC(filter_type, - "\n<0|1|2[,...]> Video filter type." - "\n0 none, 1 (1-2-1) 3-tap filter, " - "2 (2-3-6-3-2) 5-tap filter." - "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE) - " for every device." - "\nThe filter is used to reduce noise and aliasing artifacts" - "\nproduced by the CCD or CMOS image sensor, and the scaling" - " process." - "\n"); -MODULE_PARM_DESC(largeview, - "\n<0|1[,...]> Large view: 0 disabled, 1 enabled." - "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW) - " for every device." - "\n"); -MODULE_PARM_DESC(upscaling, - "\n<0|1[,...]> Software scaling (for non-compressed video):" - "\n0 disabled, 1 enabled." - "\nDisable it if you have a slow CPU or you don't have" - " enough memory." - "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) - " for every device." - "\nIf 'w9968cf-vpp' is not present, this parameter is" - " set to 0." - "\n"); -MODULE_PARM_DESC(decompression, - "\n<0|1|2[,...]> Software video decompression:" - "\n- 0 disables decompression (doesn't allow formats needing" - " decompression)" - "\n- 1 forces decompression (allows formats needing" - " decompression only);" - "\n- 2 allows any permitted formats." - "\nFormats supporting compressed video are YUV422P and" - " YUV420P/YUV420 " - "\nin any resolutions where both width and height are " - "a multiple of 16." - "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) - " for every device." - "\nIf 'w9968cf-vpp' is not present, forcing decompression is " - "\nnot allowed; in this case this parameter is set to 2." - "\n"); -MODULE_PARM_DESC(force_palette, - "\n<0" - "|" __MODULE_STRING(VIDEO_PALETTE_UYVY) - "|" __MODULE_STRING(VIDEO_PALETTE_YUV420) - "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P) - "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P) - "|" __MODULE_STRING(VIDEO_PALETTE_YUYV) - "|" __MODULE_STRING(VIDEO_PALETTE_YUV422) - "|" __MODULE_STRING(VIDEO_PALETTE_GREY) - "|" __MODULE_STRING(VIDEO_PALETTE_RGB555) - "|" __MODULE_STRING(VIDEO_PALETTE_RGB565) - "|" __MODULE_STRING(VIDEO_PALETTE_RGB24) - "|" __MODULE_STRING(VIDEO_PALETTE_RGB32) - "[,...]>" - " Force picture palette." - "\nIn order:" - "\n- 0 allows any of the following formats:" - "\n- UYVY 16 bpp - Original video, compression disabled" - "\n- YUV420 12 bpp - Original video, compression enabled" - "\n- YUV422P 16 bpp - Original video, compression enabled" - "\n- YUV420P 12 bpp - Original video, compression enabled" - "\n- YUVY 16 bpp - Software conversion from UYVY" - "\n- YUV422 16 bpp - Software conversion from UYVY" - "\n- GREY 8 bpp - Software conversion from UYVY" - "\n- RGB555 16 bpp - Software conversion from UYVY" - "\n- RGB565 16 bpp - Software conversion from UYVY" - "\n- RGB24 24 bpp - Software conversion from UYVY" - "\n- RGB32 32 bpp - Software conversion from UYVY" - "\nWhen not 0, this parameter will override 'decompression'." - "\nDefault value is 0 for every device." - "\nInitial palette is " - __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." - "\nIf 'w9968cf-vpp' is not present, this parameter is" - " set to 9 (UYVY)." - "\n"); -MODULE_PARM_DESC(force_rgb, - "\n<0|1[,...]> Read RGB video data instead of BGR:" - "\n 1 = use RGB component ordering." - "\n 0 = use BGR component ordering." - "\nThis parameter has effect when using RGBX palettes only." - "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB) - " for every device." - "\n"); -MODULE_PARM_DESC(autobright, - "\n<0|1[,...]> Image sensor automatically changes brightness:" - "\n 0 = no, 1 = yes" - "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT) - " for every device." - "\n"); -MODULE_PARM_DESC(autoexp, - "\n<0|1[,...]> Image sensor automatically changes exposure:" - "\n 0 = no, 1 = yes" - "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP) - " for every device." - "\n"); -MODULE_PARM_DESC(lightfreq, - "\n<50|60[,...]> Light frequency in Hz:" - "\n 50 for European and Asian lighting," - " 60 for American lighting." - "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ) - " for every device." - "\n"); -MODULE_PARM_DESC(bandingfilter, - "\n<0|1[,...]> Banding filter to reduce effects of" - " fluorescent lighting:" - "\n 0 disabled, 1 enabled." - "\nThis filter tries to reduce the pattern of horizontal" - "\nlight/dark bands caused by some (usually fluorescent)" - " lighting." - "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER) - " for every device." - "\n"); -MODULE_PARM_DESC(clockdiv, - "\n<-1|n[,...]> " - "Force pixel clock divisor to a specific value (for experts):" - "\n n may vary from 0 to 127." - "\n -1 for automatic value." - "\nSee also the 'double_buffer' module parameter." - "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV) - " for every device." - "\n"); -MODULE_PARM_DESC(backlight, - "\n<0|1[,...]> Objects are lit from behind:" - "\n 0 = no, 1 = yes" - "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT) - " for every device." - "\n"); -MODULE_PARM_DESC(mirror, - "\n<0|1[,...]> Reverse image horizontally:" - "\n 0 = no, 1 = yes" - "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR) - " for every device." - "\n"); -MODULE_PARM_DESC(monochrome, - "\n<0|1[,...]> Use image sensor as monochrome sensor:" - "\n 0 = no, 1 = yes" - "\nNot all the sensors support monochrome color." - "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME) - " for every device." - "\n"); -MODULE_PARM_DESC(brightness, - "\n Set picture brightness (0-65535)." - "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS) - " for every device." - "\nThis parameter has no effect if 'autobright' is enabled." - "\n"); -MODULE_PARM_DESC(hue, - "\n Set picture hue (0-65535)." - "\nDefault value is "__MODULE_STRING(W9968CF_HUE) - " for every device." - "\n"); -MODULE_PARM_DESC(colour, - "\n Set picture saturation (0-65535)." - "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR) - " for every device." - "\n"); -MODULE_PARM_DESC(contrast, - "\n Set picture contrast (0-65535)." - "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST) - " for every device." - "\n"); -MODULE_PARM_DESC(whiteness, - "\n Set picture whiteness (0-65535)." - "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS) - " for every device." - "\n"); -#ifdef W9968CF_DEBUG -MODULE_PARM_DESC(debug, - "\n Debugging information level, from 0 to 6:" - "\n0 = none (use carefully)" - "\n1 = critical errors" - "\n2 = significant informations" - "\n3 = configuration or general messages" - "\n4 = warnings" - "\n5 = called functions" - "\n6 = function internals" - "\nLevel 5 and 6 are useful for testing only, when only " - "one device is used." - "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"." - "\n"); -MODULE_PARM_DESC(specific_debug, - "\n<0|1> Enable or disable specific debugging messages:" - "\n0 = print messages concerning every level" - " <= 'debug' level." - "\n1 = print messages concerning the level" - " indicated by 'debug'." - "\nDefault value is " - __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"." - "\n"); -#endif /* W9968CF_DEBUG */ - - - -/**************************************************************************** - * Some prototypes * - ****************************************************************************/ - -/* Video4linux interface */ -static struct file_operations w9968cf_fops; -static int w9968cf_open(struct inode*, struct file*); -static int w9968cf_release(struct inode*, struct file*); -static int w9968cf_mmap(struct file*, struct vm_area_struct*); -static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long); -static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*); -static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, - void __user *); - -/* USB-specific */ -static int w9968cf_start_transfer(struct w9968cf_device*); -static int w9968cf_stop_transfer(struct w9968cf_device*); -static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index); -static int w9968cf_read_reg(struct w9968cf_device*, u16 index); -static int w9968cf_write_fsb(struct w9968cf_device*, u16* data); -static int w9968cf_write_sb(struct w9968cf_device*, u16 value); -static int w9968cf_read_sb(struct w9968cf_device*); -static int w9968cf_upload_quantizationtables(struct w9968cf_device*); -static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs); - -/* Low-level I2C (SMBus) I/O */ -static int w9968cf_smbus_start(struct w9968cf_device*); -static int w9968cf_smbus_stop(struct w9968cf_device*); -static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v); -static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v); -static int w9968cf_smbus_write_ack(struct w9968cf_device*); -static int w9968cf_smbus_read_ack(struct w9968cf_device*); -static int w9968cf_smbus_refresh_bus(struct w9968cf_device*); -static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, - u16 address, u8* value); -static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, - u8 subaddress, u8* value); -static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*, - u16 address, u8 subaddress); -static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*, - u16 address, u8 subaddress, - u8 value); - -/* I2C interface to kernel */ -static int w9968cf_i2c_init(struct w9968cf_device*); -static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data*); -static u32 w9968cf_i2c_func(struct i2c_adapter*); -static int w9968cf_i2c_attach_inform(struct i2c_client*); -static int w9968cf_i2c_detach_inform(struct i2c_client*); -static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd, - unsigned long arg); - -/* Memory management */ -static void* rvmalloc(unsigned long size); -static void rvfree(void *mem, unsigned long size); -static void w9968cf_deallocate_memory(struct w9968cf_device*); -static int w9968cf_allocate_memory(struct w9968cf_device*); - -/* High-level image sensor control functions */ -static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); -static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); -static int w9968cf_sensor_cmd(struct w9968cf_device*, - unsigned int cmd, void *arg); -static int w9968cf_sensor_init(struct w9968cf_device*); -static int w9968cf_sensor_update_settings(struct w9968cf_device*); -static int w9968cf_sensor_get_picture(struct w9968cf_device*); -static int w9968cf_sensor_update_picture(struct w9968cf_device*, - struct video_picture pict); - -/* Other helper functions */ -static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, - enum w9968cf_model_id, - const unsigned short dev_nr); -static void w9968cf_adjust_configuration(struct w9968cf_device*); -static int w9968cf_turn_on_led(struct w9968cf_device*); -static int w9968cf_init_chip(struct w9968cf_device*); -static inline u16 w9968cf_valid_palette(u16 palette); -static inline u16 w9968cf_valid_depth(u16 palette); -static inline u8 w9968cf_need_decompression(u16 palette); -static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture); -static int w9968cf_set_window(struct w9968cf_device*, struct video_window); -static int w9968cf_postprocess_frame(struct w9968cf_device*, - struct w9968cf_frame_t*); -static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h); -static void w9968cf_init_framelist(struct w9968cf_device*); -static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num); -static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**); -static void w9968cf_release_resources(struct w9968cf_device*); - - - -/**************************************************************************** - * Symbolic names * - ****************************************************************************/ - -/* Used to represent a list of values and their respective symbolic names */ -struct w9968cf_symbolic_list { - const int num; - const char *name; -}; - -/*-------------------------------------------------------------------------- - Returns the name of the matching element in the symbolic_list array. The - end of the list must be marked with an element that has a NULL name. - --------------------------------------------------------------------------*/ -static inline const char * -symbolic(struct w9968cf_symbolic_list list[], const int num) -{ - int i; - - for (i = 0; list[i].name != NULL; i++) - if (list[i].num == num) - return (list[i].name); - - return "Unknown"; -} - -static struct w9968cf_symbolic_list camlist[] = { - { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" }, - { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" }, - - /* Other cameras (having the same descriptors as Generic W996[87]CF) */ - { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" }, - { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" }, - { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" }, - { W9968CF_MOD_LL, "Lebon LDC-035A" }, - { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" }, - { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" }, - { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" }, - { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" }, - { W9968CF_MOD_PDP480, "Pretec DigiPen-480" }, - - { -1, NULL } -}; - -static struct w9968cf_symbolic_list senlist[] = { - { CC_OV76BE, "OV76BE" }, - { CC_OV7610, "OV7610" }, - { CC_OV7620, "OV7620" }, - { CC_OV7620AE, "OV7620AE" }, - { CC_OV6620, "OV6620" }, - { CC_OV6630, "OV6630" }, - { CC_OV6630AE, "OV6630AE" }, - { CC_OV6630AF, "OV6630AF" }, - { -1, NULL } -}; - -/* Video4Linux1 palettes */ -static struct w9968cf_symbolic_list v4l1_plist[] = { - { VIDEO_PALETTE_GREY, "GREY" }, - { VIDEO_PALETTE_HI240, "HI240" }, - { VIDEO_PALETTE_RGB565, "RGB565" }, - { VIDEO_PALETTE_RGB24, "RGB24" }, - { VIDEO_PALETTE_RGB32, "RGB32" }, - { VIDEO_PALETTE_RGB555, "RGB555" }, - { VIDEO_PALETTE_YUV422, "YUV422" }, - { VIDEO_PALETTE_YUYV, "YUYV" }, - { VIDEO_PALETTE_UYVY, "UYVY" }, - { VIDEO_PALETTE_YUV420, "YUV420" }, - { VIDEO_PALETTE_YUV411, "YUV411" }, - { VIDEO_PALETTE_RAW, "RAW" }, - { VIDEO_PALETTE_YUV422P, "YUV422P" }, - { VIDEO_PALETTE_YUV411P, "YUV411P" }, - { VIDEO_PALETTE_YUV420P, "YUV420P" }, - { VIDEO_PALETTE_YUV410P, "YUV410P" }, - { -1, NULL } -}; - -/* Decoder error codes: */ -static struct w9968cf_symbolic_list decoder_errlist[] = { - { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" }, - { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" }, - { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" }, - { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" }, - { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" }, - { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" }, - { -1, NULL } -}; - -/* URB error codes: */ -static struct w9968cf_symbolic_list urb_errlist[] = { - { -ENOMEM, "No memory for allocation of internal structures" }, - { -ENOSPC, "The host controller's bandwidth is already consumed" }, - { -ENOENT, "URB was canceled by unlink_urb" }, - { -EXDEV, "ISO transfer only partially completed" }, - { -EAGAIN, "Too match scheduled for the future" }, - { -ENXIO, "URB already queued" }, - { -EFBIG, "Too much ISO frames requested" }, - { -ENOSR, "Buffer error (overrun)" }, - { -EPIPE, "Specified endpoint is stalled (device not responding)"}, - { -EOVERFLOW, "Babble (bad cable?)" }, - { -EPROTO, "Bit-stuff error (bad cable?)" }, - { -EILSEQ, "CRC/Timeout" }, - { -ETIMEDOUT, "NAK (device does not respond)" }, - { -1, NULL } -}; - - - -/**************************************************************************** - * Memory management functions * - ****************************************************************************/ -static void* rvmalloc(unsigned long size) -{ - void* mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - - -static void rvfree(void* mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - - -/*-------------------------------------------------------------------------- - Deallocate previously allocated memory. - --------------------------------------------------------------------------*/ -static void w9968cf_deallocate_memory(struct w9968cf_device* cam) -{ - u8 i; - - /* Free the isochronous transfer buffers */ - for (i = 0; i < W9968CF_URBS; i++) { - kfree(cam->transfer_buffer[i]); - cam->transfer_buffer[i] = NULL; - } - - /* Free temporary frame buffer */ - if (cam->frame_tmp.buffer) { - rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size); - cam->frame_tmp.buffer = NULL; - } - - /* Free helper buffer */ - if (cam->frame_vpp.buffer) { - rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size); - cam->frame_vpp.buffer = NULL; - } - - /* Free video frame buffers */ - if (cam->frame[0].buffer) { - rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size); - cam->frame[0].buffer = NULL; - } - - cam->nbuffers = 0; - - DBG(5, "Memory successfully deallocated") -} - - -/*-------------------------------------------------------------------------- - Allocate memory buffers for USB transfers and video frames. - This function is called by open() only. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_allocate_memory(struct w9968cf_device* cam) -{ - const u16 p_size = wMaxPacketSize[cam->altsetting-1]; - void* buff = NULL; - unsigned long hw_bufsize, vpp_bufsize; - u8 i, bpp; - - /* NOTE: Deallocation is done elsewhere in case of error */ - - /* Calculate the max amount of raw data per frame from the device */ - hw_bufsize = cam->maxwidth*cam->maxheight*2; - - /* Calculate the max buf. size needed for post-processing routines */ - bpp = (w9968cf_vpp) ? 4 : 2; - if (cam->upscaling) - vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp, - cam->maxwidth*cam->maxheight*bpp); - else - vpp_bufsize = cam->maxwidth*cam->maxheight*bpp; - - /* Allocate memory for the isochronous transfer buffers */ - for (i = 0; i < W9968CF_URBS; i++) { - if (!(cam->transfer_buffer[i] = - kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { - DBG(1, "Couldn't allocate memory for the isochronous " - "transfer buffers (%u bytes)", - p_size * W9968CF_ISO_PACKETS) - return -ENOMEM; - } - } - - /* Allocate memory for the temporary frame buffer */ - if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) { - DBG(1, "Couldn't allocate memory for the temporary " - "video frame buffer (%lu bytes)", hw_bufsize) - return -ENOMEM; - } - cam->frame_tmp.size = hw_bufsize; - cam->frame_tmp.number = -1; - - /* Allocate memory for the helper buffer */ - if (w9968cf_vpp) { - if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) { - DBG(1, "Couldn't allocate memory for the helper buffer" - " (%lu bytes)", vpp_bufsize) - return -ENOMEM; - } - cam->frame_vpp.size = vpp_bufsize; - } else - cam->frame_vpp.buffer = NULL; - - /* Allocate memory for video frame buffers */ - cam->nbuffers = cam->max_buffers; - while (cam->nbuffers >= 2) { - if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize))) - break; - else - cam->nbuffers--; - } - - if (!buff) { - DBG(1, "Couldn't allocate memory for the video frame buffers") - cam->nbuffers = 0; - return -ENOMEM; - } - - if (cam->nbuffers != cam->max_buffers) - DBG(2, "Couldn't allocate memory for %u video frame buffers. " - "Only memory for %u buffers has been allocated", - cam->max_buffers, cam->nbuffers) - - for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].buffer = buff + i*vpp_bufsize; - cam->frame[i].size = vpp_bufsize; - cam->frame[i].number = i; - /* Circular list */ - if (i != cam->nbuffers-1) - cam->frame[i].next = &cam->frame[i+1]; - else - cam->frame[i].next = &cam->frame[0]; - cam->frame[i].status = F_UNUSED; - } - - DBG(5, "Memory successfully allocated") - return 0; -} - - - -/**************************************************************************** - * USB-specific functions * - ****************************************************************************/ - -/*-------------------------------------------------------------------------- - This is an handler function which is called after the URBs are completed. - It collects multiple data packets coming from the camera by putting them - into frame buffers: one or more zero data length data packets are used to - mark the end of a video frame; the first non-zero data packet is the start - of the next video frame; if an error is encountered in a packet, the entire - video frame is discarded and grabbed again. - If there are no requested frames in the FIFO list, packets are collected into - a temporary buffer. - --------------------------------------------------------------------------*/ -static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs) -{ - struct w9968cf_device* cam = (struct w9968cf_device*)urb->context; - struct w9968cf_frame_t** f; - unsigned int len, status; - void* pos; - u8 i; - int err = 0; - - if ((!cam->streaming) || cam->disconnected) { - DBG(4, "Got interrupt, but not streaming") - return; - } - - /* "(*f)" will be used instead of "cam->frame_current" */ - f = &cam->frame_current; - - /* If a frame has been requested and we are grabbing into - the temporary frame, we'll switch to that requested frame */ - if ((*f) == &cam->frame_tmp && *cam->requested_frame) { - if (cam->frame_tmp.status == F_GRABBING) { - w9968cf_pop_frame(cam, &cam->frame_current); - (*f)->status = F_GRABBING; - (*f)->length = cam->frame_tmp.length; - memcpy((*f)->buffer, cam->frame_tmp.buffer, - (*f)->length); - DBG(6, "Switched from temp. frame to frame #%d", - (*f)->number) - } - } - - for (i = 0; i < urb->number_of_packets; i++) { - len = urb->iso_frame_desc[i].actual_length; - status = urb->iso_frame_desc[i].status; - pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; - - if (status && len != 0) { - DBG(4, "URB failed, error in data packet " - "(error #%u, %s)", - status, symbolic(urb_errlist, status)) - (*f)->status = F_ERROR; - continue; - } - - if (len) { /* start of frame */ - - if ((*f)->status == F_UNUSED) { - (*f)->status = F_GRABBING; - (*f)->length = 0; - } - - /* Buffer overflows shouldn't happen, however...*/ - if ((*f)->length + len > (*f)->size) { - DBG(4, "Buffer overflow: bad data packets") - (*f)->status = F_ERROR; - } - - if ((*f)->status == F_GRABBING) { - memcpy((*f)->buffer + (*f)->length, pos, len); - (*f)->length += len; - } - - } else if ((*f)->status == F_GRABBING) { /* end of frame */ - - DBG(6, "Frame #%d successfully grabbed", (*f)->number) - - if (cam->vpp_flag & VPP_DECOMPRESSION) { - err = w9968cf_vpp->check_headers((*f)->buffer, - (*f)->length); - if (err) { - DBG(4, "Skip corrupted frame: %s", - symbolic(decoder_errlist, err)) - (*f)->status = F_UNUSED; - continue; /* grab this frame again */ - } - } - - (*f)->status = F_READY; - (*f)->queued = 0; - - /* Take a pointer to the new frame from the FIFO list. - If the list is empty,we'll use the temporary frame*/ - if (*cam->requested_frame) - w9968cf_pop_frame(cam, &cam->frame_current); - else { - cam->frame_current = &cam->frame_tmp; - (*f)->status = F_UNUSED; - } - - } else if ((*f)->status == F_ERROR) - (*f)->status = F_UNUSED; /* grab it again */ - - PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d", - (unsigned long)(*f)->length, i, len, (*f)->status) - - } /* end for */ - - /* Resubmit this URB */ - urb->dev = cam->usbdev; - urb->status = 0; - spin_lock(&cam->urb_lock); - if (cam->streaming) - if ((err = usb_submit_urb(urb, GFP_ATOMIC))) { - cam->misconfigured = 1; - DBG(1, "Couldn't resubmit the URB: error %d, %s", - err, symbolic(urb_errlist, err)) - } - spin_unlock(&cam->urb_lock); - - /* Wake up the user process */ - wake_up_interruptible(&cam->wait_queue); -} - - -/*--------------------------------------------------------------------------- - Setup the URB structures for the isochronous transfer. - Submit the URBs so that the data transfer begins. - Return 0 on success, a negative number otherwise. - ---------------------------------------------------------------------------*/ -static int w9968cf_start_transfer(struct w9968cf_device* cam) -{ - struct usb_device *udev = cam->usbdev; - struct urb* urb; - const u16 p_size = wMaxPacketSize[cam->altsetting-1]; - u16 w, h, d; - int vidcapt; - u32 t_size; - int err = 0; - s8 i, j; - - for (i = 0; i < W9968CF_URBS; i++) { - urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); - cam->urb[i] = urb; - if (!urb) { - for (j = 0; j < i; j++) - usb_free_urb(cam->urb[j]); - DBG(1, "Couldn't allocate the URB structures") - return -ENOMEM; - } - - urb->dev = udev; - urb->context = (void*)cam; - urb->pipe = usb_rcvisocpipe(udev, 1); - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = W9968CF_ISO_PACKETS; - urb->complete = w9968cf_urb_complete; - urb->transfer_buffer = cam->transfer_buffer[i]; - urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS; - urb->interval = 1; - for (j = 0; j < W9968CF_ISO_PACKETS; j++) { - urb->iso_frame_desc[j].offset = p_size*j; - urb->iso_frame_desc[j].length = p_size; - } - } - - /* Transfer size per frame, in WORD ! */ - d = cam->hw_depth; - w = cam->hw_width; - h = cam->hw_height; - - t_size = (w*h*d)/16; - - err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ - err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ - - /* Transfer size */ - err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */ - err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */ - - if (cam->vpp_flag & VPP_DECOMPRESSION) - err += w9968cf_upload_quantizationtables(cam); - - vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */ - err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */ - - err += usb_set_interface(udev, 0, cam->altsetting); - err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */ - - if (err || (vidcapt < 0)) { - for (i = 0; i < W9968CF_URBS; i++) - usb_free_urb(cam->urb[i]); - DBG(1, "Couldn't tell the camera to start the data transfer") - return err; - } - - w9968cf_init_framelist(cam); - - /* Begin to grab into the temporary buffer */ - cam->frame_tmp.status = F_UNUSED; - cam->frame_tmp.queued = 0; - cam->frame_current = &cam->frame_tmp; - - if (!(cam->vpp_flag & VPP_DECOMPRESSION)) - DBG(5, "Isochronous transfer size: %lu bytes/frame", - (unsigned long)t_size*2) - - DBG(5, "Starting the isochronous transfer...") - - cam->streaming = 1; - - /* Submit the URBs */ - for (i = 0; i < W9968CF_URBS; i++) { - err = usb_submit_urb(cam->urb[i], GFP_KERNEL); - if (err) { - cam->streaming = 0; - for (j = i-1; j >= 0; j--) { - usb_kill_urb(cam->urb[j]); - usb_free_urb(cam->urb[j]); - } - DBG(1, "Couldn't send a transfer request to the " - "USB core (error #%d, %s)", err, - symbolic(urb_errlist, err)) - return err; - } - } - - return 0; -} - - -/*-------------------------------------------------------------------------- - Stop the isochronous transfer and set alternate setting to 0 (0Mb/s). - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_stop_transfer(struct w9968cf_device* cam) -{ - struct usb_device *udev = cam->usbdev; - unsigned long lock_flags; - int err = 0; - s8 i; - - if (!cam->streaming) - return 0; - - /* This avoids race conditions with usb_submit_urb() - in the URB completition handler */ - spin_lock_irqsave(&cam->urb_lock, lock_flags); - cam->streaming = 0; - spin_unlock_irqrestore(&cam->urb_lock, lock_flags); - - for (i = W9968CF_URBS-1; i >= 0; i--) - if (cam->urb[i]) { - usb_kill_urb(cam->urb[i]); - usb_free_urb(cam->urb[i]); - cam->urb[i] = NULL; - } - - if (cam->disconnected) - goto exit; - - err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */ - err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */ - err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */ - err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */ - - if (err) { - DBG(2, "Failed to tell the camera to stop the isochronous " - "transfer. However this is not a critical error.") - return -EIO; - } - -exit: - DBG(5, "Isochronous transfer stopped") - return 0; -} - - -/*-------------------------------------------------------------------------- - Write a W9968CF register. - Return 0 on success, -1 otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index) -{ - struct usb_device* udev = cam->usbdev; - int res; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT); - - if (res < 0) - DBG(4, "Failed to write a register " - "(value 0x%04X, index 0x%02X, error #%d, %s)", - value, index, res, symbolic(urb_errlist, res)) - - return (res >= 0) ? 0 : -1; -} - - -/*-------------------------------------------------------------------------- - Read a W9968CF register. - Return the register value on success, -1 otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u16* buff = cam->control_buffer; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT); - - if (res < 0) - DBG(4, "Failed to read a register " - "(index 0x%02X, error #%d, %s)", - index, res, symbolic(urb_errlist, res)) - - return (res >= 0) ? (int)(*buff) : -1; -} - - -/*-------------------------------------------------------------------------- - Write 64-bit data to the fast serial bus registers. - Return 0 on success, -1 otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data) -{ - struct usb_device* udev = cam->usbdev; - u16 value; - int res; - - value = *data++; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT); - - if (res < 0) - DBG(4, "Failed to write the FSB registers " - "(error #%d, %s)", res, symbolic(urb_errlist, res)) - - return (res >= 0) ? 0 : -1; -} - - -/*-------------------------------------------------------------------------- - Write data to the serial bus control register. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value) -{ - int err = 0; - - err = w9968cf_write_reg(cam, value, 0x01); - udelay(W9968CF_I2C_BUS_DELAY); - - return err; -} - - -/*-------------------------------------------------------------------------- - Read data from the serial bus control register. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_read_sb(struct w9968cf_device* cam) -{ - int v = 0; - - v = w9968cf_read_reg(cam, 0x01); - udelay(W9968CF_I2C_BUS_DELAY); - - return v; -} - - -/*-------------------------------------------------------------------------- - Upload quantization tables for the JPEG compression. - This function is called by w9968cf_start_transfer(). - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam) -{ - u16 a, b; - int err = 0, i, j; - - err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */ - - for (i = 0, j = 0; i < 32; i++, j += 2) { - a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8); - b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8); - err += w9968cf_write_reg(cam, a, 0x40+i); - err += w9968cf_write_reg(cam, b, 0x60+i); - } - err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */ - - return err; -} - - - -/**************************************************************************** - * Low-level I2C I/O functions. * - * The adapter supports the following I2C transfer functions: * - * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) * - * i2c_adap_read_byte_data() * - * i2c_adap_read_byte() * - ****************************************************************************/ - -static int w9968cf_smbus_start(struct w9968cf_device* cam) -{ - int err = 0; - - err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ - err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ - - return err; -} - - -static int w9968cf_smbus_stop(struct w9968cf_device* cam) -{ - int err = 0; - - err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ - err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ - - return err; -} - - -static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v) -{ - u8 bit; - int err = 0, sda; - - for (bit = 0 ; bit < 8 ; bit++) { - sda = (v & 0x80) ? 2 : 0; - v <<= 1; - /* SDE=1, SDA=sda, SCL=0 */ - err += w9968cf_write_sb(cam, 0x10 | sda); - /* SDE=1, SDA=sda, SCL=1 */ - err += w9968cf_write_sb(cam, 0x11 | sda); - /* SDE=1, SDA=sda, SCL=0 */ - err += w9968cf_write_sb(cam, 0x10 | sda); - } - - return err; -} - - -static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v) -{ - u8 bit; - int err = 0; - - *v = 0; - for (bit = 0 ; bit < 8 ; bit++) { - *v <<= 1; - err += w9968cf_write_sb(cam, 0x0013); - *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0; - err += w9968cf_write_sb(cam, 0x0012); - } - - return err; -} - - -static int w9968cf_smbus_write_ack(struct w9968cf_device* cam) -{ - int err = 0; - - err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ - err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */ - err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */ - - return err; -} - - -static int w9968cf_smbus_read_ack(struct w9968cf_device* cam) -{ - int err = 0, sda; - - err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */ - sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */ - err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */ - if (sda < 0) - err += sda; - if (sda == 1) { - DBG(6, "Couldn't receive the ACK") - err += -1; - } - - return err; -} - - -/* This seems to refresh the communication through the serial bus */ -static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam) -{ - int err = 0, j; - - for (j = 1; j <= 10; j++) { - err = w9968cf_write_reg(cam, 0x0020, 0x01); - err += w9968cf_write_reg(cam, 0x0000, 0x01); - if (err) - break; - } - - return err; -} - - -/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ -static int -w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, - u16 address, u8 subaddress,u8 value) -{ - u16* data = cam->data_buffer; - int err = 0; - - err += w9968cf_smbus_refresh_bus(cam); - - /* Enable SBUS outputs */ - err += w9968cf_write_sb(cam, 0x0020); - - data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); - data[0] |= (address & 0x40) ? 0x4000 : 0x0; - data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0); - data[1] |= (address & 0x20) ? 0x0150 : 0x0; - data[1] |= (address & 0x10) ? 0x5400 : 0x0; - data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0); - data[2] |= (address & 0x04) ? 0x0540 : 0x0; - data[2] |= (address & 0x02) ? 0x5000 : 0x0; - data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0); - data[3] |= (address & 0x01) ? 0x0054 : 0x0; - - err += w9968cf_write_fsb(cam, data); - - data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0); - data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0; - data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0; - data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0); - data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0; - data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0; - data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0; - data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0); - data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0; - data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0; - data[3] = 0x001d; - - err += w9968cf_write_fsb(cam, data); - - data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0); - data[0] |= (value & 0x40) ? 0x0540 : 0x0; - data[0] |= (value & 0x20) ? 0x5000 : 0x0; - data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0); - data[1] |= (value & 0x10) ? 0x0054 : 0x0; - data[1] |= (value & 0x08) ? 0x1500 : 0x0; - data[1] |= (value & 0x04) ? 0x4000 : 0x0; - data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0); - data[2] |= (value & 0x02) ? 0x0150 : 0x0; - data[2] |= (value & 0x01) ? 0x5400 : 0x0; - data[3] = 0xfe1d; - - err += w9968cf_write_fsb(cam, data); - - /* Disable SBUS outputs */ - err += w9968cf_write_sb(cam, 0x0000); - - if (!err) - DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " - "value 0x%02X", address, subaddress, value) - else - DBG(5, "I2C write byte data failed, addr.0x%04X, " - "subaddr.0x%02X, value 0x%02X", - address, subaddress, value) - - return err; -} - - -/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ -static int -w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, - u16 address, u8 subaddress, - u8* value) -{ - int err = 0; - - /* Serial data enable */ - err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */ - - err += w9968cf_smbus_start(cam); - err += w9968cf_smbus_write_byte(cam, address); - err += w9968cf_smbus_read_ack(cam); - err += w9968cf_smbus_write_byte(cam, subaddress); - err += w9968cf_smbus_read_ack(cam); - err += w9968cf_smbus_stop(cam); - err += w9968cf_smbus_start(cam); - err += w9968cf_smbus_write_byte(cam, address + 1); - err += w9968cf_smbus_read_ack(cam); - err += w9968cf_smbus_read_byte(cam, value); - err += w9968cf_smbus_write_ack(cam); - err += w9968cf_smbus_stop(cam); - - /* Serial data disable */ - err += w9968cf_write_sb(cam, 0x0000); - - if (!err) - DBG(5, "I2C read byte data done, addr.0x%04X, " - "subaddr.0x%02X, value 0x%02X", - address, subaddress, *value) - else - DBG(5, "I2C read byte data failed, addr.0x%04X, " - "subaddr.0x%02X, wrong value 0x%02X", - address, subaddress, *value) - - return err; -} - - -/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */ -static int -w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, - u16 address, u8* value) -{ - int err = 0; - - /* Serial data enable */ - err += w9968cf_write_sb(cam, 0x0013); - - err += w9968cf_smbus_start(cam); - err += w9968cf_smbus_write_byte(cam, address + 1); - err += w9968cf_smbus_read_ack(cam); - err += w9968cf_smbus_read_byte(cam, value); - err += w9968cf_smbus_write_ack(cam); - err += w9968cf_smbus_stop(cam); - - /* Serial data disable */ - err += w9968cf_write_sb(cam, 0x0000); - - if (!err) - DBG(5, "I2C read byte done, addr.0x%04X, " - "value 0x%02X", address, *value) - else - DBG(5, "I2C read byte failed, addr.0x%04X, " - "wrong value 0x%02X", address, *value) - - return err; -} - - -/* SMBus protocol: S Addr Wr [A] Value [A] P */ -static int -w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam, - u16 address, u8 value) -{ - DBG(4, "i2c_write_byte() is an unsupported transfer mode") - return -EINVAL; -} - - - -/**************************************************************************** - * I2C interface to kernel * - ****************************************************************************/ - -static int -w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - unsigned short flags, char read_write, u8 command, - int size, union i2c_smbus_data *data) -{ - struct w9968cf_device* cam = i2c_get_adapdata(adapter); - u8 i; - int err = 0; - - switch (addr) { - case OV6xx0_SID: - case OV7xx0_SID: - break; - default: - DBG(4, "Rejected slave ID 0x%04X", addr) - return -EINVAL; - } - - if (size == I2C_SMBUS_BYTE) { - /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */ - addr <<= 1; - - if (read_write == I2C_SMBUS_WRITE) - err = w9968cf_i2c_adap_write_byte(cam, addr, command); - else if (read_write == I2C_SMBUS_READ) - err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte); - - } else if (size == I2C_SMBUS_BYTE_DATA) { - addr <<= 1; - - if (read_write == I2C_SMBUS_WRITE) - err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, - command, data->byte); - else if (read_write == I2C_SMBUS_READ) { - for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { - err = w9968cf_i2c_adap_read_byte_data(cam,addr, - command, &data->byte); - if (err) { - if (w9968cf_smbus_refresh_bus(cam)) { - err = -EIO; - break; - } - } else - break; - } - - } else - return -EINVAL; - - } else { - DBG(4, "Unsupported I2C transfer mode (%d)", size) - return -EINVAL; - } - - return err; -} - - -static u32 w9968cf_i2c_func(struct i2c_adapter* adap) -{ - return I2C_FUNC_SMBUS_READ_BYTE | - I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA; -} - - -static int w9968cf_i2c_attach_inform(struct i2c_client* client) -{ - struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); - int id = client->driver->id, err = 0; - - if (id == I2C_DRIVERID_OVCAMCHIP) { - cam->sensor_client = client; - err = w9968cf_sensor_init(cam); - if (err) { - cam->sensor_client = NULL; - return err; - } - } else { - DBG(4, "Rejected client [%s] with driver [%s]", - client->name, client->driver->driver.name) - return -EINVAL; - } - - DBG(5, "I2C attach client [%s] with driver [%s]", - client->name, client->driver->driver.name) - - return 0; -} - - -static int w9968cf_i2c_detach_inform(struct i2c_client* client) -{ - struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); - - if (cam->sensor_client == client) - cam->sensor_client = NULL; - - DBG(5, "I2C detach client [%s]", client->name) - - return 0; -} - - -static int -w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - - -static int w9968cf_i2c_init(struct w9968cf_device* cam) -{ - int err = 0; - - static struct i2c_algorithm algo = { - .smbus_xfer = w9968cf_i2c_smbus_xfer, - .algo_control = w9968cf_i2c_control, - .functionality = w9968cf_i2c_func, - }; - - static struct i2c_adapter adap = { - .id = I2C_HW_SMBUS_W9968CF, - .class = I2C_CLASS_CAM_DIGITAL, - .owner = THIS_MODULE, - .client_register = w9968cf_i2c_attach_inform, - .client_unregister = w9968cf_i2c_detach_inform, - .algo = &algo, - }; - - memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); - strcpy(cam->i2c_adapter.name, "w9968cf"); - i2c_set_adapdata(&cam->i2c_adapter, cam); - - DBG(6, "Registering I2C adapter with kernel...") - - err = i2c_add_adapter(&cam->i2c_adapter); - if (err) - DBG(1, "Failed to register the I2C adapter") - else - DBG(5, "I2C adapter registered") - - return err; -} - - - -/**************************************************************************** - * Helper functions * - ****************************************************************************/ - -/*-------------------------------------------------------------------------- - Turn on the LED on some webcams. A beep should be heard too. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_turn_on_led(struct w9968cf_device* cam) -{ - int err = 0; - - err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */ - err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ - err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ - err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */ - err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */ - err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */ - - if (err) - DBG(2, "Couldn't turn on the LED") - - DBG(5, "LED turned on") - - return err; -} - - -/*-------------------------------------------------------------------------- - Write some registers for the device initialization. - This function is called once on open(). - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_init_chip(struct w9968cf_device* cam) -{ - unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2, - y0 = 0x0000, - u0 = y0 + hw_bufsize/2, - v0 = u0 + hw_bufsize/4, - y1 = v0 + hw_bufsize/4, - u1 = y1 + hw_bufsize/2, - v1 = u1 + hw_bufsize/4; - int err = 0; - - err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ - err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ - - err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */ - err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */ - - err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */ - err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */ - err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */ - err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */ - err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */ - err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */ - - err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */ - err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */ - err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */ - err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */ - err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */ - err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */ - - err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */ - err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */ - - err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */ - err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */ - - err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */ - err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/ - err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */ - err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */ - - err += w9968cf_set_picture(cam, cam->picture); /* this before */ - err += w9968cf_set_window(cam, cam->window); - - if (err) - DBG(1, "Chip initialization failed") - else - DBG(5, "Chip successfully initialized") - - return err; -} - - -/*-------------------------------------------------------------------------- - Return non-zero if the palette is supported, 0 otherwise. - --------------------------------------------------------------------------*/ -static inline u16 w9968cf_valid_palette(u16 palette) -{ - u8 i = 0; - while (w9968cf_formatlist[i].palette != 0) { - if (palette == w9968cf_formatlist[i].palette) - return palette; - i++; - } - return 0; -} - - -/*-------------------------------------------------------------------------- - Return the depth corresponding to the given palette. - Palette _must_ be supported ! - --------------------------------------------------------------------------*/ -static inline u16 w9968cf_valid_depth(u16 palette) -{ - u8 i=0; - while (w9968cf_formatlist[i].palette != palette) - i++; - - return w9968cf_formatlist[i].depth; -} - - -/*-------------------------------------------------------------------------- - Return non-zero if the format requires decompression, 0 otherwise. - --------------------------------------------------------------------------*/ -static inline u8 w9968cf_need_decompression(u16 palette) -{ - u8 i = 0; - while (w9968cf_formatlist[i].palette != 0) { - if (palette == w9968cf_formatlist[i].palette) - return w9968cf_formatlist[i].compression; - i++; - } - return 0; -} - - -/*-------------------------------------------------------------------------- - Change the picture settings of the camera. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int -w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) -{ - u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; - int err = 0; - - /* Make sure we are using a valid depth */ - pict.depth = w9968cf_valid_depth(pict.palette); - - fmt = pict.palette; - - hw_depth = pict.depth; /* depth used by the winbond chip */ - hw_palette = pict.palette; /* palette used by the winbond chip */ - - /* VS & HS polarities */ - reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11); - - switch (fmt) - { - case VIDEO_PALETTE_UYVY: - reg_v |= 0x0000; - cam->vpp_flag = VPP_NONE; - break; - case VIDEO_PALETTE_YUV422P: - reg_v |= 0x0002; - cam->vpp_flag = VPP_DECOMPRESSION; - break; - case VIDEO_PALETTE_YUV420: - case VIDEO_PALETTE_YUV420P: - reg_v |= 0x0003; - cam->vpp_flag = VPP_DECOMPRESSION; - break; - case VIDEO_PALETTE_YUYV: - case VIDEO_PALETTE_YUV422: - reg_v |= 0x0000; - cam->vpp_flag = VPP_SWAP_YUV_BYTES; - hw_palette = VIDEO_PALETTE_UYVY; - break; - /* Original video is used instead of RGBX palettes. - Software conversion later. */ - case VIDEO_PALETTE_GREY: - case VIDEO_PALETTE_RGB555: - case VIDEO_PALETTE_RGB565: - case VIDEO_PALETTE_RGB24: - case VIDEO_PALETTE_RGB32: - reg_v |= 0x0000; /* UYVY 16 bit is used */ - hw_depth = 16; - hw_palette = VIDEO_PALETTE_UYVY; - cam->vpp_flag = VPP_UYVY_TO_RGBX; - break; - } - - /* NOTE: due to memory issues, it is better to disable the hardware - double buffering during compression */ - if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION)) - reg_v |= 0x0080; - - if (cam->clamping) - reg_v |= 0x0020; - - if (cam->filter_type == 1) - reg_v |= 0x0008; - else if (cam->filter_type == 2) - reg_v |= 0x000c; - - if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) - goto error; - - if ((err = w9968cf_sensor_update_picture(cam, pict))) - goto error; - - /* If all went well, update the device data structure */ - memcpy(&cam->picture, &pict, sizeof(pict)); - cam->hw_depth = hw_depth; - cam->hw_palette = hw_palette; - - /* Settings changed, so we clear the frame buffers */ - memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); - - DBG(4, "Palette is %s, depth is %u bpp", - symbolic(v4l1_plist, pict.palette), pict.depth) - - return 0; - -error: - DBG(1, "Failed to change picture settings") - return err; -} - - -/*-------------------------------------------------------------------------- - Change the capture area size of the camera. - This function _must_ be called _after_ w9968cf_set_picture(). - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int -w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) -{ - u16 x, y, w, h, scx, scy, cw, ch, ax, ay; - unsigned long fw, fh; - struct ovcamchip_window s_win; - int err = 0; - - /* Work around to avoid FP arithmetics */ - #define __SC(x) ((x) << 10) - #define __UNSC(x) ((x) >> 10) - - /* Make sure we are using a supported resolution */ - if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, - (u16*)&win.height))) - goto error; - - /* Scaling factors */ - fw = __SC(win.width) / cam->maxwidth; - fh = __SC(win.height) / cam->maxheight; - - /* Set up the width and height values used by the chip */ - if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) { - cam->vpp_flag |= VPP_UPSCALE; - /* Calculate largest w,h mantaining the same w/h ratio */ - w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; - h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; - if (w < cam->minwidth) /* just in case */ - w = cam->minwidth; - if (h < cam->minheight) /* just in case */ - h = cam->minheight; - } else { - cam->vpp_flag &= ~VPP_UPSCALE; - w = win.width; - h = win.height; - } - - /* x,y offsets of the cropped area */ - scx = cam->start_cropx; - scy = cam->start_cropy; - - /* Calculate cropped area manteining the right w/h ratio */ - if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) { - cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh; - ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight; - } else { - cw = w; - ch = h; - } - - /* Setup the window of the sensor */ - s_win.format = VIDEO_PALETTE_UYVY; - s_win.width = cam->maxwidth; - s_win.height = cam->maxheight; - s_win.quarter = 0; /* full progressive video */ - - /* Center it */ - s_win.x = (s_win.width - cw) / 2; - s_win.y = (s_win.height - ch) / 2; - - /* Clock divisor */ - if (cam->clockdiv >= 0) - s_win.clockdiv = cam->clockdiv; /* manual override */ - else - switch (cam->sensor) { - case CC_OV6620: - s_win.clockdiv = 0; - break; - case CC_OV6630: - s_win.clockdiv = 0; - break; - case CC_OV76BE: - case CC_OV7610: - case CC_OV7620: - s_win.clockdiv = 0; - break; - default: - s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR; - } - - /* We have to scale win.x and win.y offsets */ - if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) - || (cam->vpp_flag & VPP_UPSCALE) ) { - ax = __SC(win.x)/fw; - ay = __SC(win.y)/fh; - } else { - ax = win.x; - ay = win.y; - } - - if ((ax + cw) > cam->maxwidth) - ax = cam->maxwidth - cw; - - if ((ay + ch) > cam->maxheight) - ay = cam->maxheight - ch; - - /* Adjust win.x, win.y */ - if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) - || (cam->vpp_flag & VPP_UPSCALE) ) { - win.x = __UNSC(ax*fw); - win.y = __UNSC(ay*fh); - } else { - win.x = ax; - win.y = ay; - } - - /* Offsets used by the chip */ - x = ax + s_win.x; - y = ay + s_win.y; - - /* Go ! */ - if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) - goto error; - - err += w9968cf_write_reg(cam, scx + x, 0x10); - err += w9968cf_write_reg(cam, scy + y, 0x11); - err += w9968cf_write_reg(cam, scx + x + cw, 0x12); - err += w9968cf_write_reg(cam, scy + y + ch, 0x13); - err += w9968cf_write_reg(cam, w, 0x14); - err += w9968cf_write_reg(cam, h, 0x15); - - /* JPEG width & height */ - err += w9968cf_write_reg(cam, w, 0x30); - err += w9968cf_write_reg(cam, h, 0x31); - - /* Y & UV frame buffer strides (in WORD) */ - if (cam->vpp_flag & VPP_DECOMPRESSION) { - err += w9968cf_write_reg(cam, w/2, 0x2c); - err += w9968cf_write_reg(cam, w/4, 0x2d); - } else - err += w9968cf_write_reg(cam, w, 0x2c); - - if (err) - goto error; - - /* If all went well, update the device data structure */ - memcpy(&cam->window, &win, sizeof(win)); - cam->hw_width = w; - cam->hw_height = h; - - /* Settings changed, so we clear the frame buffers */ - memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size); - - DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", - win.width, win.height, win.x, win.y) - - PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, " - "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u", - x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y, - win.width, win.height) - - return 0; - -error: - DBG(1, "Failed to change the capture area size") - return err; -} - - -/*-------------------------------------------------------------------------- - Adjust the asked values for window width and height. - Return 0 on success, -1 otherwise. - --------------------------------------------------------------------------*/ -static int -w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height) -{ - u16 maxw, maxh; - - if ((*width < cam->minwidth) || (*height < cam->minheight)) - return -ERANGE; - - maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && - w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) - : cam->maxwidth; - maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) && - w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) - : cam->maxheight; - - if (*width > maxw) - *width = maxw; - if (*height > maxh) - *height = maxh; - - if (cam->vpp_flag & VPP_DECOMPRESSION) { - *width &= ~15L; /* multiple of 16 */ - *height &= ~15L; - } - - PDBGG("Window size adjusted w=%u, h=%u ", *width, *height) - - return 0; -} - - -/*-------------------------------------------------------------------------- - Initialize the FIFO list of requested frames. - --------------------------------------------------------------------------*/ -static void w9968cf_init_framelist(struct w9968cf_device* cam) -{ - u8 i; - - for (i = 0; i < cam->nbuffers; i++) { - cam->requested_frame[i] = NULL; - cam->frame[i].queued = 0; - cam->frame[i].status = F_UNUSED; - } -} - - -/*-------------------------------------------------------------------------- - Add a frame in the FIFO list of requested frames. - This function is called in process context. - --------------------------------------------------------------------------*/ -static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num) -{ - u8 f; - unsigned long lock_flags; - - spin_lock_irqsave(&cam->flist_lock, lock_flags); - - for (f=0; cam->requested_frame[f] != NULL; f++); - cam->requested_frame[f] = &cam->frame[f_num]; - cam->frame[f_num].queued = 1; - cam->frame[f_num].status = F_UNUSED; /* clear the status */ - - spin_unlock_irqrestore(&cam->flist_lock, lock_flags); - - DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f) -} - - -/*-------------------------------------------------------------------------- - Read, store and remove the first pointer in the FIFO list of requested - frames. This function is called in interrupt context. - --------------------------------------------------------------------------*/ -static void -w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep) -{ - u8 i; - - spin_lock(&cam->flist_lock); - - *framep = cam->requested_frame[0]; - - /* Shift the list of pointers */ - for (i = 0; i < cam->nbuffers-1; i++) - cam->requested_frame[i] = cam->requested_frame[i+1]; - cam->requested_frame[i] = NULL; - - spin_unlock(&cam->flist_lock); - - DBG(6,"Popped frame #%d from the list", (*framep)->number) -} - - -/*-------------------------------------------------------------------------- - High-level video post-processing routine on grabbed frames. - Return 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int -w9968cf_postprocess_frame(struct w9968cf_device* cam, - struct w9968cf_frame_t* fr) -{ - void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp; - u16 w = cam->window.width, - h = cam->window.height, - d = cam->picture.depth, - fmt = cam->picture.palette, - rgb = cam->force_rgb, - hw_w = cam->hw_width, - hw_h = cam->hw_height, - hw_d = cam->hw_depth; - int err = 0; - - #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;} - - if (cam->vpp_flag & VPP_DECOMPRESSION) { - memcpy(pOut, pIn, fr->length); - _PSWAP(pIn, pOut) - err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut); - PDBGG("Compressed frame length: %lu",(unsigned long)fr->length) - fr->length = (hw_w*hw_h*hw_d)/8; - _PSWAP(pIn, pOut) - if (err) { - DBG(4, "An error occurred while decoding the frame: " - "%s", symbolic(decoder_errlist, err)) - return err; - } else - DBG(6, "Frame decoded") - } - - if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) { - w9968cf_vpp->swap_yuvbytes(pIn, fr->length); - DBG(6, "Original UYVY component ordering changed") - } - - if (cam->vpp_flag & VPP_UPSCALE) { - w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h); - fr->length = (w*h*hw_d)/8; - _PSWAP(pIn, pOut) - DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u", - hw_w, hw_h, hw_d, w, h) - } - - if (cam->vpp_flag & VPP_UYVY_TO_RGBX) { - w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb); - fr->length = (w*h*d)/8; - _PSWAP(pIn, pOut) - DBG(6, "UYVY-16bit to %s conversion done", - symbolic(v4l1_plist, fmt)) - } - - if (pOut == fr->buffer) - memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length); - - return 0; -} - - - -/**************************************************************************** - * Image sensor control routines * - ****************************************************************************/ - -static int -w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val) -{ - struct ovcamchip_control ctl; - int err; - - ctl.id = cid; - ctl.value = val; - - err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl); - - return err; -} - - -static int -w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val) -{ - struct ovcamchip_control ctl; - int err; - - ctl.id = cid; - - err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); - if (!err) - *val = ctl.value; - - return err; -} - - -static int -w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) -{ - struct i2c_client* c = cam->sensor_client; - int rc = 0; - - if (!c || !c->driver || !c->driver->command) - return -EINVAL; - - rc = c->driver->command(c, cmd, arg); - /* The I2C driver returns -EPERM on non-supported controls */ - return (rc < 0 && rc != -EPERM) ? rc : 0; -} - - -/*-------------------------------------------------------------------------- - Update some settings of the image sensor. - Returns: 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_sensor_update_settings(struct w9968cf_device* cam) -{ - int err = 0; - - /* Auto brightness */ - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, - cam->auto_brt); - if (err) - return err; - - /* Auto exposure */ - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, - cam->auto_exp); - if (err) - return err; - - /* Banding filter */ - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, - cam->bandfilt); - if (err) - return err; - - /* Light frequency */ - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, - cam->lightfreq); - if (err) - return err; - - /* Back light */ - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, - cam->backlight); - if (err) - return err; - - /* Mirror */ - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, - cam->mirror); - if (err) - return err; - - return 0; -} - - -/*-------------------------------------------------------------------------- - Get some current picture settings from the image sensor and update the - internal 'picture' structure of the camera. - Returns: 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_sensor_get_picture(struct w9968cf_device* cam) -{ - int err, v; - - err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v); - if (err) - return err; - cam->picture.contrast = v; - - err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v); - if (err) - return err; - cam->picture.brightness = v; - - err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v); - if (err) - return err; - cam->picture.colour = v; - - err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); - if (err) - return err; - cam->picture.hue = v; - - DBG(5, "Got picture settings from the image sensor") - - PDBGG("Brightness, contrast, hue, colour, whiteness are " - "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast, - cam->picture.hue, cam->picture.colour, cam->picture.whiteness) - - return 0; -} - - -/*-------------------------------------------------------------------------- - Update picture settings of the image sensor. - Returns: 0 on success, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int -w9968cf_sensor_update_picture(struct w9968cf_device* cam, - struct video_picture pict) -{ - int err = 0; - - if ((!cam->sensor_initialized) - || pict.contrast != cam->picture.contrast) { - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT, - pict.contrast); - if (err) - goto fail; - DBG(4, "Contrast changed from %u to %u", - cam->picture.contrast, pict.contrast) - cam->picture.contrast = pict.contrast; - } - - if (((!cam->sensor_initialized) || - pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) { - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, - pict.brightness); - if (err) - goto fail; - DBG(4, "Brightness changed from %u to %u", - cam->picture.brightness, pict.brightness) - cam->picture.brightness = pict.brightness; - } - - if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) { - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, - pict.colour); - if (err) - goto fail; - DBG(4, "Colour changed from %u to %u", - cam->picture.colour, pict.colour) - cam->picture.colour = pict.colour; - } - - if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) { - err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, - pict.hue); - if (err) - goto fail; - DBG(4, "Hue changed from %u to %u", - cam->picture.hue, pict.hue) - cam->picture.hue = pict.hue; - } - - return 0; - -fail: - DBG(4, "Failed to change sensor picture setting") - return err; -} - - - -/**************************************************************************** - * Camera configuration * - ****************************************************************************/ - -/*-------------------------------------------------------------------------- - This function is called when a supported image sensor is detected. - Return 0 if the initialization succeeds, a negative number otherwise. - --------------------------------------------------------------------------*/ -static int w9968cf_sensor_init(struct w9968cf_device* cam) -{ - int err = 0; - - if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, - &cam->monochrome))) - goto error; - - if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, - &cam->sensor))) - goto error; - - /* NOTE: Make sure width and height are a multiple of 16 */ - switch (cam->sensor_client->addr) { - case OV6xx0_SID: - cam->maxwidth = 352; - cam->maxheight = 288; - cam->minwidth = 64; - cam->minheight = 48; - break; - case OV7xx0_SID: - cam->maxwidth = 640; - cam->maxheight = 480; - cam->minwidth = 64; - cam->minheight = 48; - break; - default: - DBG(1, "Not supported image sensor detected for %s", - symbolic(camlist, cam->id)) - return -EINVAL; - } - - /* These values depend on the ones in the ovxxx0.c sources */ - switch (cam->sensor) { - case CC_OV7620: - cam->start_cropx = 287; - cam->start_cropy = 35; - /* Seems to work around a bug in the image sensor */ - cam->vs_polarity = 1; - cam->hs_polarity = 1; - break; - default: - cam->start_cropx = 320; - cam->start_cropy = 35; - cam->vs_polarity = 1; - cam->hs_polarity = 0; - } - - if ((err = w9968cf_sensor_update_settings(cam))) - goto error; - - if ((err = w9968cf_sensor_update_picture(cam, cam->picture))) - goto error; - - cam->sensor_initialized = 1; - - DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor)) - return 0; - -error: - cam->sensor_initialized = 0; - cam->sensor = CC_UNKNOWN; - DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " - "Try to detach and attach this device again", - symbolic(camlist, cam->id), cam->v4ldev->minor) - return err; -} - - -/*-------------------------------------------------------------------------- - Fill some basic fields in the main device data structure. - This function is called once on w9968cf_usb_probe() for each recognized - camera. - --------------------------------------------------------------------------*/ -static void -w9968cf_configure_camera(struct w9968cf_device* cam, - struct usb_device* udev, - enum w9968cf_model_id mod_id, - const unsigned short dev_nr) -{ - mutex_init(&cam->fileop_mutex); - init_waitqueue_head(&cam->open); - spin_lock_init(&cam->urb_lock); - spin_lock_init(&cam->flist_lock); - - cam->users = 0; - cam->disconnected = 0; - cam->id = mod_id; - cam->sensor = CC_UNKNOWN; - cam->sensor_initialized = 0; - - /* Calculate the alternate setting number (from 1 to 16) - according to the 'packet_size' module parameter */ - if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE) - packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE; - for (cam->altsetting = 1; - packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1]; - cam->altsetting++); - - cam->max_buffers = (max_buffers[dev_nr] < 2 || - max_buffers[dev_nr] > W9968CF_MAX_BUFFERS) - ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr]; - - cam->double_buffer = (double_buffer[dev_nr] == 0 || - double_buffer[dev_nr] == 1) - ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER; - - cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1) - ? (u8)clamping[dev_nr] : W9968CF_CLAMPING; - - cam->filter_type = (filter_type[dev_nr] == 0 || - filter_type[dev_nr] == 1 || - filter_type[dev_nr] == 2) - ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE; - - cam->capture = 1; - - cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1) - ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW; - - cam->decompression = (decompression[dev_nr] == 0 || - decompression[dev_nr] == 1 || - decompression[dev_nr] == 2) - ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION; - - cam->upscaling = (upscaling[dev_nr] == 0 || - upscaling[dev_nr] == 1) - ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING; - - cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1) - ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT; - - cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1) - ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP; - - cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60) - ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ; - - cam->bandfilt = (bandingfilter[dev_nr] == 0 || - bandingfilter[dev_nr] == 1) - ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER; - - cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1) - ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT; - - cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0) - ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV; - - cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1) - ? (u8)mirror[dev_nr] : W9968CF_MIRROR; - - cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1) - ? monochrome[dev_nr] : W9968CF_MONOCHROME; - - cam->picture.brightness = (u16)brightness[dev_nr]; - cam->picture.hue = (u16)hue[dev_nr]; - cam->picture.colour = (u16)colour[dev_nr]; - cam->picture.contrast = (u16)contrast[dev_nr]; - cam->picture.whiteness = (u16)whiteness[dev_nr]; - if (w9968cf_valid_palette((u16)force_palette[dev_nr])) { - cam->picture.palette = (u16)force_palette[dev_nr]; - cam->force_palette = 1; - } else { - cam->force_palette = 0; - if (cam->decompression == 0) - cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF; - else if (cam->decompression == 1) - cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE; - else - cam->picture.palette = W9968CF_PALETTE_DECOMP_ON; - } - cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); - - cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) - ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB; - - cam->window.x = 0; - cam->window.y = 0; - cam->window.width = W9968CF_WIDTH; - cam->window.height = W9968CF_HEIGHT; - cam->window.chromakey = 0; - cam->window.clipcount = 0; - cam->window.flags = 0; - - DBG(3, "%s configured with settings #%u:", - symbolic(camlist, cam->id), dev_nr) - - DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes", - wMaxPacketSize[cam->altsetting-1]) - - DBG(3, "- Number of requested video frame buffers: %u", - cam->max_buffers) - - if (cam->double_buffer) - DBG(3, "- Hardware double buffering enabled") - else - DBG(3, "- Hardware double buffering disabled") - - if (cam->filter_type == 0) - DBG(3, "- Video filtering disabled") - else if (cam->filter_type == 1) - DBG(3, "- Video filtering enabled: type 1-2-1") - else if (cam->filter_type == 2) - DBG(3, "- Video filtering enabled: type 2-3-6-3-2") - - if (cam->clamping) - DBG(3, "- Video data clamping (CCIR-601 format) enabled") - else - DBG(3, "- Video data clamping (CCIR-601 format) disabled") - - if (cam->largeview) - DBG(3, "- Large view enabled") - else - DBG(3, "- Large view disabled") - - if ((cam->decompression) == 0 && (!cam->force_palette)) - DBG(3, "- Decompression disabled") - else if ((cam->decompression) == 1 && (!cam->force_palette)) - DBG(3, "- Decompression forced") - else if ((cam->decompression) == 2 && (!cam->force_palette)) - DBG(3, "- Decompression allowed") - - if (cam->upscaling) - DBG(3, "- Software image scaling enabled") - else - DBG(3, "- Software image scaling disabled") - - if (cam->force_palette) - DBG(3, "- Image palette forced to %s", - symbolic(v4l1_plist, cam->picture.palette)) - - if (cam->force_rgb) - DBG(3, "- RGB component ordering will be used instead of BGR") - - if (cam->auto_brt) - DBG(3, "- Auto brightness enabled") - else - DBG(3, "- Auto brightness disabled") - - if (cam->auto_exp) - DBG(3, "- Auto exposure enabled") - else - DBG(3, "- Auto exposure disabled") - - if (cam->backlight) - DBG(3, "- Backlight exposure algorithm enabled") - else - DBG(3, "- Backlight exposure algorithm disabled") - - if (cam->mirror) - DBG(3, "- Mirror enabled") - else - DBG(3, "- Mirror disabled") - - if (cam->bandfilt) - DBG(3, "- Banding filter enabled") - else - DBG(3, "- Banding filter disabled") - - DBG(3, "- Power lighting frequency: %u", cam->lightfreq) - - if (cam->clockdiv == -1) - DBG(3, "- Automatic clock divisor enabled") - else - DBG(3, "- Clock divisor: %d", cam->clockdiv) - - if (cam->monochrome) - DBG(3, "- Image sensor used as monochrome") - else - DBG(3, "- Image sensor not used as monochrome") -} - - -/*-------------------------------------------------------------------------- - If the video post-processing module is not loaded, some parameters - must be overridden. - --------------------------------------------------------------------------*/ -static void w9968cf_adjust_configuration(struct w9968cf_device* cam) -{ - if (!w9968cf_vpp) { - if (cam->decompression == 1) { - cam->decompression = 2; - DBG(2, "Video post-processing module not found: " - "'decompression' parameter forced to 2") - } - if (cam->upscaling) { - cam->upscaling = 0; - DBG(2, "Video post-processing module not found: " - "'upscaling' parameter forced to 0") - } - if (cam->picture.palette != VIDEO_PALETTE_UYVY) { - cam->force_palette = 0; - DBG(2, "Video post-processing module not found: " - "'force_palette' parameter forced to 0") - } - cam->picture.palette = VIDEO_PALETTE_UYVY; - cam->picture.depth = w9968cf_valid_depth(cam->picture.palette); - } -} - - -/*-------------------------------------------------------------------------- - Release the resources used by the driver. - This function is called on disconnect - (or on close if deallocation has been deferred) - --------------------------------------------------------------------------*/ -static void w9968cf_release_resources(struct w9968cf_device* cam) -{ - mutex_lock(&w9968cf_devlist_mutex); - - DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) - - video_unregister_device(cam->v4ldev); - list_del(&cam->v4llist); - i2c_del_adapter(&cam->i2c_adapter); - w9968cf_deallocate_memory(cam); - kfree(cam->control_buffer); - kfree(cam->data_buffer); - - mutex_unlock(&w9968cf_devlist_mutex); -} - - - -/**************************************************************************** - * Video4Linux interface * - ****************************************************************************/ - -static int w9968cf_open(struct inode* inode, struct file* filp) -{ - struct w9968cf_device* cam; - int err; - - /* This the only safe way to prevent race conditions with disconnect */ - if (!down_read_trylock(&w9968cf_disconnect)) - return -ERESTARTSYS; - - cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); - - mutex_lock(&cam->dev_mutex); - - if (cam->sensor == CC_UNKNOWN) { - DBG(2, "No supported image sensor has been detected by the " - "'ovcamchip' module for the %s (/dev/video%d). Make " - "sure it is loaded *before* (re)connecting the camera.", - symbolic(camlist, cam->id), cam->v4ldev->minor) - mutex_unlock(&cam->dev_mutex); - up_read(&w9968cf_disconnect); - return -ENODEV; - } - - if (cam->users) { - DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", - symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) - if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { - mutex_unlock(&cam->dev_mutex); - up_read(&w9968cf_disconnect); - return -EWOULDBLOCK; - } - mutex_unlock(&cam->dev_mutex); - err = wait_event_interruptible_exclusive(cam->open, - cam->disconnected || - !cam->users); - if (err) { - up_read(&w9968cf_disconnect); - return err; - } - if (cam->disconnected) { - up_read(&w9968cf_disconnect); - return -ENODEV; - } - mutex_lock(&cam->dev_mutex); - } - - DBG(5, "Opening '%s', /dev/video%d ...", - symbolic(camlist, cam->id), cam->v4ldev->minor) - - cam->streaming = 0; - cam->misconfigured = 0; - - w9968cf_adjust_configuration(cam); - - if ((err = w9968cf_allocate_memory(cam))) - goto deallocate_memory; - - if ((err = w9968cf_init_chip(cam))) - goto deallocate_memory; - - if ((err = w9968cf_start_transfer(cam))) - goto deallocate_memory; - - filp->private_data = cam; - - cam->users++; - strcpy(cam->command, current->comm); - - init_waitqueue_head(&cam->wait_queue); - - DBG(5, "Video device is open") - - mutex_unlock(&cam->dev_mutex); - up_read(&w9968cf_disconnect); - - return 0; - -deallocate_memory: - w9968cf_deallocate_memory(cam); - DBG(2, "Failed to open the video device") - mutex_unlock(&cam->dev_mutex); - up_read(&w9968cf_disconnect); - return err; -} - - -static int w9968cf_release(struct inode* inode, struct file* filp) -{ - struct w9968cf_device* cam; - - cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); - - mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ - - w9968cf_stop_transfer(cam); - - if (cam->disconnected) { - w9968cf_release_resources(cam); - mutex_unlock(&cam->dev_mutex); - kfree(cam); - return 0; - } - - cam->users--; - w9968cf_deallocate_memory(cam); - wake_up_interruptible_nr(&cam->open, 1); - - DBG(5, "Video device closed") - mutex_unlock(&cam->dev_mutex); - return 0; -} - - -static ssize_t -w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) -{ - struct w9968cf_device* cam; - struct w9968cf_frame_t* fr; - int err = 0; - - cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); - - if (filp->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->disconnected) { - DBG(2, "Device not present") - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->misconfigured) { - DBG(2, "The camera is misconfigured. Close and open it again.") - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (!cam->frame[0].queued) - w9968cf_push_frame(cam, 0); - - if (!cam->frame[1].queued) - w9968cf_push_frame(cam, 1); - - err = wait_event_interruptible(cam->wait_queue, - cam->frame[0].status == F_READY || - cam->frame[1].status == F_READY || - cam->disconnected); - if (err) { - mutex_unlock(&cam->fileop_mutex); - return err; - } - if (cam->disconnected) { - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1]; - - if (w9968cf_vpp) - w9968cf_postprocess_frame(cam, fr); - - if (count > fr->length) - count = fr->length; - - if (copy_to_user(buf, fr->buffer, count)) { - fr->status = F_UNUSED; - mutex_unlock(&cam->fileop_mutex); - return -EFAULT; - } - *f_pos += count; - - fr->status = F_UNUSED; - - DBG(5, "%zu bytes read", count) - - mutex_unlock(&cam->fileop_mutex); - return count; -} - - -static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma) -{ - struct w9968cf_device* cam = (struct w9968cf_device*) - video_get_drvdata(video_devdata(filp)); - unsigned long vsize = vma->vm_end - vma->vm_start, - psize = cam->nbuffers * cam->frame[0].size, - start = vma->vm_start, - pos = (unsigned long)cam->frame[0].buffer, - page; - - if (cam->disconnected) { - DBG(2, "Device not present") - return -ENODEV; - } - - if (cam->misconfigured) { - DBG(2, "The camera is misconfigured. Close and open it again") - return -EIO; - } - - PDBGG("mmapping %lu bytes...", vsize) - - if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) - return -EINVAL; - - while (vsize > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page + vma->vm_pgoff, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - vsize -= PAGE_SIZE; - } - - DBG(5, "mmap method successfully called") - return 0; -} - - -static int -w9968cf_ioctl(struct inode* inode, struct file* filp, - unsigned int cmd, unsigned long arg) -{ - struct w9968cf_device* cam; - int err; - - cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->disconnected) { - DBG(2, "Device not present") - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->misconfigured) { - DBG(2, "The camera is misconfigured. Close and open it again.") - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); - - mutex_unlock(&cam->fileop_mutex); - return err; -} - - -static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, - unsigned int cmd, void __user * arg) -{ - struct w9968cf_device* cam; - const char* v4l1_ioctls[] = { - "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", - "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", - "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", - "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", - "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", - "GVBIFMT", "SVBIFMT" - }; - - #define V4L1_IOCTL(cmd) \ - ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \ - v4l1_ioctls[_IOC_NR((cmd))] : "?") - - cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); - - switch (cmd) { - - case VIDIOCGCAP: /* get video capability */ - { - struct video_capability cap = { - .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, - .channels = 1, - .audios = 0, - .minwidth = cam->minwidth, - .minheight = cam->minheight, - }; - sprintf(cap.name, "W996[87]CF USB Camera #%d", - cam->v4ldev->minor); - cap.maxwidth = (cam->upscaling && w9968cf_vpp) - ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) - : cam->maxwidth; - cap.maxheight = (cam->upscaling && w9968cf_vpp) - ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight) - : cam->maxheight; - - if (copy_to_user(arg, &cap, sizeof(cap))) - return -EFAULT; - - DBG(5, "VIDIOCGCAP successfully called") - return 0; - } - - case VIDIOCGCHAN: /* get video channel informations */ - { - struct video_channel chan; - if (copy_from_user(&chan, arg, sizeof(chan))) - return -EFAULT; - - if (chan.channel != 0) - return -EINVAL; - - strcpy(chan.name, "Camera"); - chan.tuners = 0; - chan.flags = 0; - chan.type = VIDEO_TYPE_CAMERA; - chan.norm = VIDEO_MODE_AUTO; - - if (copy_to_user(arg, &chan, sizeof(chan))) - return -EFAULT; - - DBG(5, "VIDIOCGCHAN successfully called") - return 0; - } - - case VIDIOCSCHAN: /* set active channel */ - { - struct video_channel chan; - - if (copy_from_user(&chan, arg, sizeof(chan))) - return -EFAULT; - - if (chan.channel != 0) - return -EINVAL; - - DBG(5, "VIDIOCSCHAN successfully called") - return 0; - } - - case VIDIOCGPICT: /* get image properties of the picture */ - { - if (w9968cf_sensor_get_picture(cam)) - return -EIO; - - if (copy_to_user(arg, &cam->picture, sizeof(cam->picture))) - return -EFAULT; - - DBG(5, "VIDIOCGPICT successfully called") - return 0; - } - - case VIDIOCSPICT: /* change picture settings */ - { - struct video_picture pict; - int err = 0; - - if (copy_from_user(&pict, arg, sizeof(pict))) - return -EFAULT; - - if ( (cam->force_palette || !w9968cf_vpp) - && pict.palette != cam->picture.palette ) { - DBG(4, "Palette %s rejected: only %s is allowed", - symbolic(v4l1_plist, pict.palette), - symbolic(v4l1_plist, cam->picture.palette)) - return -EINVAL; - } - - if (!w9968cf_valid_palette(pict.palette)) { - DBG(4, "Palette %s not supported. VIDIOCSPICT failed", - symbolic(v4l1_plist, pict.palette)) - return -EINVAL; - } - - if (!cam->force_palette) { - if (cam->decompression == 0) { - if (w9968cf_need_decompression(pict.palette)) { - DBG(4, "Decompression disabled: palette %s is not " - "allowed. VIDIOCSPICT failed", - symbolic(v4l1_plist, pict.palette)) - return -EINVAL; - } - } else if (cam->decompression == 1) { - if (!w9968cf_need_decompression(pict.palette)) { - DBG(4, "Decompression forced: palette %s is not " - "allowed. VIDIOCSPICT failed", - symbolic(v4l1_plist, pict.palette)) - return -EINVAL; - } - } - } - - if (pict.depth != w9968cf_valid_depth(pict.palette)) { - DBG(4, "Requested depth %u bpp is not valid for %s " - "palette: ignored and changed to %u bpp", - pict.depth, symbolic(v4l1_plist, pict.palette), - w9968cf_valid_depth(pict.palette)) - pict.depth = w9968cf_valid_depth(pict.palette); - } - - if (pict.palette != cam->picture.palette) { - if(*cam->requested_frame - || cam->frame_current->queued) { - err = wait_event_interruptible - ( cam->wait_queue, - cam->disconnected || - (!*cam->requested_frame && - !cam->frame_current->queued) ); - if (err) - return err; - if (cam->disconnected) - return -ENODEV; - } - - if (w9968cf_stop_transfer(cam)) - goto ioctl_fail; - - if (w9968cf_set_picture(cam, pict)) - goto ioctl_fail; - - if (w9968cf_start_transfer(cam)) - goto ioctl_fail; - - } else if (w9968cf_sensor_update_picture(cam, pict)) - return -EIO; - - - DBG(5, "VIDIOCSPICT successfully called") - return 0; - } - - case VIDIOCSWIN: /* set capture area */ - { - struct video_window win; - int err = 0; - - if (copy_from_user(&win, arg, sizeof(win))) - return -EFAULT; - - DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, " - "x=%u, y=%u, %ux%u", win.clipcount, win.flags, - win.x, win.y, win.width, win.height) - - if (win.clipcount != 0 || win.flags != 0) - return -EINVAL; - - if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, - (u16*)&win.height))) { - DBG(4, "Resolution not supported (%ux%u). " - "VIDIOCSWIN failed", win.width, win.height) - return err; - } - - if (win.x != cam->window.x || - win.y != cam->window.y || - win.width != cam->window.width || - win.height != cam->window.height) { - if(*cam->requested_frame - || cam->frame_current->queued) { - err = wait_event_interruptible - ( cam->wait_queue, - cam->disconnected || - (!*cam->requested_frame && - !cam->frame_current->queued) ); - if (err) - return err; - if (cam->disconnected) - return -ENODEV; - } - - if (w9968cf_stop_transfer(cam)) - goto ioctl_fail; - - /* This _must_ be called before set_window() */ - if (w9968cf_set_picture(cam, cam->picture)) - goto ioctl_fail; - - if (w9968cf_set_window(cam, win)) - goto ioctl_fail; - - if (w9968cf_start_transfer(cam)) - goto ioctl_fail; - } - - DBG(5, "VIDIOCSWIN successfully called. ") - return 0; - } - - case VIDIOCGWIN: /* get current window properties */ - { - if (copy_to_user(arg,&cam->window,sizeof(struct video_window))) - return -EFAULT; - - DBG(5, "VIDIOCGWIN successfully called") - return 0; - } - - case VIDIOCGMBUF: /* request for memory (mapped) buffer */ - { - struct video_mbuf mbuf; - u8 i; - - mbuf.size = cam->nbuffers * cam->frame[0].size; - mbuf.frames = cam->nbuffers; - for (i = 0; i < cam->nbuffers; i++) - mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer - - (unsigned long)cam->frame[0].buffer; - - if (copy_to_user(arg, &mbuf, sizeof(mbuf))) - return -EFAULT; - - DBG(5, "VIDIOCGMBUF successfully called") - return 0; - } - - case VIDIOCMCAPTURE: /* start the capture to a frame */ - { - struct video_mmap mmap; - struct w9968cf_frame_t* fr; - int err = 0; - - if (copy_from_user(&mmap, arg, sizeof(mmap))) - return -EFAULT; - - DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d", - mmap.frame, symbolic(v4l1_plist, mmap.format), - mmap.width, mmap.height) - - if (mmap.frame >= cam->nbuffers) { - DBG(4, "Invalid frame number (%u). " - "VIDIOCMCAPTURE failed", mmap.frame) - return -EINVAL; - } - - if (mmap.format!=cam->picture.palette && - (cam->force_palette || !w9968cf_vpp)) { - DBG(4, "Palette %s rejected: only %s is allowed", - symbolic(v4l1_plist, mmap.format), - symbolic(v4l1_plist, cam->picture.palette)) - return -EINVAL; - } - - if (!w9968cf_valid_palette(mmap.format)) { - DBG(4, "Palette %s not supported. " - "VIDIOCMCAPTURE failed", - symbolic(v4l1_plist, mmap.format)) - return -EINVAL; - } - - if (!cam->force_palette) { - if (cam->decompression == 0) { - if (w9968cf_need_decompression(mmap.format)) { - DBG(4, "Decompression disabled: palette %s is not " - "allowed. VIDIOCSPICT failed", - symbolic(v4l1_plist, mmap.format)) - return -EINVAL; - } - } else if (cam->decompression == 1) { - if (!w9968cf_need_decompression(mmap.format)) { - DBG(4, "Decompression forced: palette %s is not " - "allowed. VIDIOCSPICT failed", - symbolic(v4l1_plist, mmap.format)) - return -EINVAL; - } - } - } - - if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, - (u16*)&mmap.height))) { - DBG(4, "Resolution not supported (%dx%d). " - "VIDIOCMCAPTURE failed", - mmap.width, mmap.height) - return err; - } - - fr = &cam->frame[mmap.frame]; - - if (mmap.width != cam->window.width || - mmap.height != cam->window.height || - mmap.format != cam->picture.palette) { - - struct video_window win; - struct video_picture pict; - - if(*cam->requested_frame - || cam->frame_current->queued) { - DBG(6, "VIDIOCMCAPTURE. Change settings for " - "frame #%u: %dx%d, format %s. Wait...", - mmap.frame, mmap.width, mmap.height, - symbolic(v4l1_plist, mmap.format)) - err = wait_event_interruptible - ( cam->wait_queue, - cam->disconnected || - (!*cam->requested_frame && - !cam->frame_current->queued) ); - if (err) - return err; - if (cam->disconnected) - return -ENODEV; - } - - memcpy(&win, &cam->window, sizeof(win)); - memcpy(&pict, &cam->picture, sizeof(pict)); - win.width = mmap.width; - win.height = mmap.height; - pict.palette = mmap.format; - - if (w9968cf_stop_transfer(cam)) - goto ioctl_fail; - - /* This before set_window */ - if (w9968cf_set_picture(cam, pict)) - goto ioctl_fail; - - if (w9968cf_set_window(cam, win)) - goto ioctl_fail; - - if (w9968cf_start_transfer(cam)) - goto ioctl_fail; - - } else if (fr->queued) { - - DBG(6, "Wait until frame #%u is free", mmap.frame) - - err = wait_event_interruptible(cam->wait_queue, - cam->disconnected || - (!fr->queued)); - if (err) - return err; - if (cam->disconnected) - return -ENODEV; - } - - w9968cf_push_frame(cam, mmap.frame); - DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame) - return 0; - } - - case VIDIOCSYNC: /* wait until the capture of a frame is finished */ - { - unsigned int f_num; - struct w9968cf_frame_t* fr; - int err = 0; - - if (copy_from_user(&f_num, arg, sizeof(f_num))) - return -EFAULT; - - if (f_num >= cam->nbuffers) { - DBG(4, "Invalid frame number (%u). " - "VIDIOCMCAPTURE failed", f_num) - return -EINVAL; - } - - DBG(6, "VIDIOCSYNC called for frame #%u", f_num) - - fr = &cam->frame[f_num]; - - switch (fr->status) { - case F_UNUSED: - if (!fr->queued) { - DBG(4, "VIDIOSYNC: Frame #%u not requested!", - f_num) - return -EFAULT; - } - case F_ERROR: - case F_GRABBING: - err = wait_event_interruptible(cam->wait_queue, - (fr->status == F_READY) - || cam->disconnected); - if (err) - return err; - if (cam->disconnected) - return -ENODEV; - break; - case F_READY: - break; - } - - if (w9968cf_vpp) - w9968cf_postprocess_frame(cam, fr); - - fr->status = F_UNUSED; - - DBG(5, "VIDIOCSYNC(%u) successfully called", f_num) - return 0; - } - - case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/ - { - struct video_unit unit = { - .video = cam->v4ldev->minor, - .vbi = VIDEO_NO_UNIT, - .radio = VIDEO_NO_UNIT, - .audio = VIDEO_NO_UNIT, - .teletext = VIDEO_NO_UNIT, - }; - - if (copy_to_user(arg, &unit, sizeof(unit))) - return -EFAULT; - - DBG(5, "VIDIOCGUNIT successfully called") - return 0; - } - - case VIDIOCKEY: - return 0; - - case VIDIOCGFBUF: - { - if (clear_user(arg, sizeof(struct video_buffer))) - return -EFAULT; - - DBG(5, "VIDIOCGFBUF successfully called") - return 0; - } - - case VIDIOCGTUNER: - { - struct video_tuner tuner; - if (copy_from_user(&tuner, arg, sizeof(tuner))) - return -EFAULT; - - if (tuner.tuner != 0) - return -EINVAL; - - strcpy(tuner.name, "no_tuner"); - tuner.rangelow = 0; - tuner.rangehigh = 0; - tuner.flags = VIDEO_TUNER_NORM; - tuner.mode = VIDEO_MODE_AUTO; - tuner.signal = 0xffff; - - if (copy_to_user(arg, &tuner, sizeof(tuner))) - return -EFAULT; - - DBG(5, "VIDIOCGTUNER successfully called") - return 0; - } - - case VIDIOCSTUNER: - { - struct video_tuner tuner; - if (copy_from_user(&tuner, arg, sizeof(tuner))) - return -EFAULT; - - if (tuner.tuner != 0) - return -EINVAL; - - if (tuner.mode != VIDEO_MODE_AUTO) - return -EINVAL; - - DBG(5, "VIDIOCSTUNER successfully called") - return 0; - } - - case VIDIOCSFBUF: - case VIDIOCCAPTURE: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - case VIDIOCSPLAYMODE: - case VIDIOCSWRITEMODE: - case VIDIOCGPLAYINFO: - case VIDIOCSMICROCODE: - case VIDIOCGVBIFMT: - case VIDIOCSVBIFMT: - DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s " - "(type 0x%01X, " - "n. 0x%01X, " - "dir. 0x%01X, " - "size 0x%02X)", - V4L1_IOCTL(cmd), - _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) - - return -EINVAL; - - default: - DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s " - "type 0x%01X, " - "n. 0x%01X, " - "dir. 0x%01X, " - "size 0x%02X", - V4L1_IOCTL(cmd), - _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd)) - - return -ENOIOCTLCMD; - - } /* end of switch */ - -ioctl_fail: - cam->misconfigured = 1; - DBG(1, "VIDIOC%s failed because of hardware problems. " - "To use the camera, close and open it again.", V4L1_IOCTL(cmd)) - return -EFAULT; -} - - -static struct file_operations w9968cf_fops = { - .owner = THIS_MODULE, - .open = w9968cf_open, - .release = w9968cf_release, - .read = w9968cf_read, - .ioctl = w9968cf_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .mmap = w9968cf_mmap, - .llseek = no_llseek, -}; - - - -/**************************************************************************** - * USB probe and V4L registration, disconnect and id_table[] definition * - ****************************************************************************/ - -static int -w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct w9968cf_device* cam; - int err = 0; - enum w9968cf_model_id mod_id; - struct list_head* ptr; - u8 sc = 0; /* number of simultaneous cameras */ - static unsigned short dev_nr = 0; /* we are handling device number n */ - - if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor && - le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct) - mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */ - else if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[1].idVendor && - le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct) - mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */ - else - return -ENODEV; - - cam = (struct w9968cf_device*) - kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL); - if (!cam) - return -ENOMEM; - - mutex_init(&cam->dev_mutex); - mutex_lock(&cam->dev_mutex); - - cam->usbdev = udev; - /* NOTE: a local copy is used to avoid possible race conditions */ - memcpy(&cam->dev, &udev->dev, sizeof(struct device)); - - DBG(2, "%s detected", symbolic(camlist, mod_id)) - - if (simcams > W9968CF_MAX_DEVICES) - simcams = W9968CF_SIMCAMS; - - /* How many cameras are connected ? */ - mutex_lock(&w9968cf_devlist_mutex); - list_for_each(ptr, &w9968cf_dev_list) - sc++; - mutex_unlock(&w9968cf_devlist_mutex); - - if (sc >= simcams) { - DBG(2, "Device rejected: too many connected cameras " - "(max. %u)", simcams) - err = -EPERM; - goto fail; - } - - - /* Allocate 2 bytes of memory for camera control USB transfers */ - if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) { - DBG(1,"Couldn't allocate memory for camera control transfers") - err = -ENOMEM; - goto fail; - } - - /* Allocate 8 bytes of memory for USB data transfers to the FSB */ - if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) { - DBG(1, "Couldn't allocate memory for data " - "transfers to the FSB") - err = -ENOMEM; - goto fail; - } - - /* Register the V4L device */ - cam->v4ldev = video_device_alloc(); - if (!cam->v4ldev) { - DBG(1, "Could not allocate memory for a V4L structure") - err = -ENOMEM; - goto fail; - } - - strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); - cam->v4ldev->owner = THIS_MODULE; - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; - cam->v4ldev->hardware = VID_HARDWARE_W9968CF; - cam->v4ldev->fops = &w9968cf_fops; - cam->v4ldev->minor = video_nr[dev_nr]; - cam->v4ldev->release = video_device_release; - video_set_drvdata(cam->v4ldev, cam); - cam->v4ldev->dev = &cam->dev; - - err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, - video_nr[dev_nr]); - if (err) { - DBG(1, "V4L device registration failed") - if (err == -ENFILE && video_nr[dev_nr] == -1) - DBG(2, "Couldn't find a free /dev/videoX node") - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; - goto fail; - } - - DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor) - - /* Set some basic constants */ - w9968cf_configure_camera(cam, udev, mod_id, dev_nr); - - /* Add a new entry into the list of V4L registered devices */ - mutex_lock(&w9968cf_devlist_mutex); - list_add(&cam->v4llist, &w9968cf_dev_list); - mutex_unlock(&w9968cf_devlist_mutex); - dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; - - w9968cf_turn_on_led(cam); - - w9968cf_i2c_init(cam); - - usb_set_intfdata(intf, cam); - mutex_unlock(&cam->dev_mutex); - return 0; - -fail: /* Free unused memory */ - kfree(cam->control_buffer); - kfree(cam->data_buffer); - if (cam->v4ldev) - video_device_release(cam->v4ldev); - mutex_unlock(&cam->dev_mutex); - kfree(cam); - return err; -} - - -static void w9968cf_usb_disconnect(struct usb_interface* intf) -{ - struct w9968cf_device* cam = - (struct w9968cf_device*)usb_get_intfdata(intf); - - down_write(&w9968cf_disconnect); - - if (cam) { - /* Prevent concurrent accesses to data */ - mutex_lock(&cam->dev_mutex); - - cam->disconnected = 1; - - DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id)) - - wake_up_interruptible_all(&cam->open); - - if (cam->users) { - DBG(2, "The device is open (/dev/video%d)! " - "Process name: %s. Deregistration and memory " - "deallocation are deferred on close.", - cam->v4ldev->minor, cam->command) - cam->misconfigured = 1; - w9968cf_stop_transfer(cam); - wake_up_interruptible(&cam->wait_queue); - } else - w9968cf_release_resources(cam); - - mutex_unlock(&cam->dev_mutex); - - if (!cam->users) - kfree(cam); - } - - up_write(&w9968cf_disconnect); -} - - -static struct usb_driver w9968cf_usb_driver = { - .name = "w9968cf", - .id_table = winbond_id_table, - .probe = w9968cf_usb_probe, - .disconnect = w9968cf_usb_disconnect, -}; - - - -/**************************************************************************** - * Module init, exit and intermodule communication * - ****************************************************************************/ - -static int __init w9968cf_module_init(void) -{ - int err; - - KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION) - KDBG(3, W9968CF_MODULE_AUTHOR) - - if (ovmod_load) - request_module("ovcamchip"); - - if ((err = usb_register(&w9968cf_usb_driver))) - return err; - - return 0; -} - - -static void __exit w9968cf_module_exit(void) -{ - /* w9968cf_usb_disconnect() will be called */ - usb_deregister(&w9968cf_usb_driver); - - KDBG(2, W9968CF_MODULE_NAME" deregistered") -} - - -module_init(w9968cf_module_init); -module_exit(w9968cf_module_exit); - diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h deleted file mode 100644 index a87be719a281..000000000000 --- a/drivers/usb/media/w9968cf.h +++ /dev/null @@ -1,330 +0,0 @@ -/*************************************************************************** - * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * - * * - * Copyright (C) 2002-2004 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _W9968CF_H_ -#define _W9968CF_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "w9968cf_vpp.h" - - -/**************************************************************************** - * Default values * - ****************************************************************************/ - -#define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */ -#define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */ - -/* Comment/uncomment the following line to enable/disable debugging messages */ -#define W9968CF_DEBUG - -/* These have effect only if W9968CF_DEBUG is defined */ -#define W9968CF_DEBUG_LEVEL 2 /* from 0 to 6. 0 for no debug informations */ -#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */ - -#define W9968CF_MAX_DEVICES 32 -#define W9968CF_SIMCAMS W9968CF_MAX_DEVICES /* simultaneous cameras */ - -#define W9968CF_MAX_BUFFERS 32 -#define W9968CF_BUFFERS 2 /* n. of frame buffers from 2 to MAX_BUFFERS */ - -/* Maximum data payload sizes in bytes for alternate settings */ -static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575, - 511, 447, 383, 319, 255, 191, 127, 63}; -#define W9968CF_PACKET_SIZE 1023 /* according to wMaxPacketSizes[] */ -#define W9968CF_MIN_PACKET_SIZE 63 /* minimum value */ -#define W9968CF_ISO_PACKETS 5 /* n.of packets for isochronous transfers */ -#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */ -#define W9968CF_URBS 2 /* n. of scheduled URBs for ISO transfer */ - -#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */ -#define W9968CF_I2C_RW_RETRIES 15 /* number of max I2C r/w retries */ - -/* Available video formats */ -struct w9968cf_format { - const u16 palette; - const u16 depth; - const u8 compression; -}; - -static const struct w9968cf_format w9968cf_formatlist[] = { - { VIDEO_PALETTE_UYVY, 16, 0 }, /* original video */ - { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */ - { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */ - { VIDEO_PALETTE_YUV420, 12, 1 }, /* same as YUV420P */ - { VIDEO_PALETTE_YUYV, 16, 0 }, /* software conversion */ - { VIDEO_PALETTE_YUV422, 16, 0 }, /* software conversion */ - { VIDEO_PALETTE_GREY, 8, 0 }, /* software conversion */ - { VIDEO_PALETTE_RGB555, 16, 0 }, /* software conversion */ - { VIDEO_PALETTE_RGB565, 16, 0 }, /* software conversion */ - { VIDEO_PALETTE_RGB24, 24, 0 }, /* software conversion */ - { VIDEO_PALETTE_RGB32, 32, 0 }, /* software conversion */ - { 0, 0, 0 } /* 0 is a terminating entry */ -}; - -#define W9968CF_DECOMPRESSION 2 /* decomp:0=disable,1=force,2=any formats */ -#define W9968CF_PALETTE_DECOMP_OFF VIDEO_PALETTE_UYVY /* when decomp=0 */ -#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */ -#define W9968CF_PALETTE_DECOMP_ON VIDEO_PALETTE_UYVY /* when decomp=2 */ - -#define W9968CF_FORCE_RGB 0 /* read RGB instead of BGR, yes=1/no=0 */ - -#define W9968CF_MAX_WIDTH 800 /* Has effect if up-scaling is on */ -#define W9968CF_MAX_HEIGHT 600 /* Has effect if up-scaling is on */ -#define W9968CF_WIDTH 320 /* from 128 to 352, multiple of 16 */ -#define W9968CF_HEIGHT 240 /* from 96 to 288, multiple of 16 */ - -#define W9968CF_CLAMPING 0 /* 0 disable, 1 enable video data clamping */ -#define W9968CF_FILTER_TYPE 0 /* 0 disable 1 (1-2-1), 2 (2-3-6-3-2) */ -#define W9968CF_DOUBLE_BUFFER 1 /* 0 disable, 1 enable double buffer */ -#define W9968CF_LARGEVIEW 1 /* 0 disable, 1 enable */ -#define W9968CF_UPSCALING 0 /* 0 disable, 1 enable */ - -#define W9968CF_MONOCHROME 0 /* 0 not monochrome, 1 monochrome sensor */ -#define W9968CF_BRIGHTNESS 31000 /* from 0 to 65535 */ -#define W9968CF_HUE 32768 /* from 0 to 65535 */ -#define W9968CF_COLOUR 32768 /* from 0 to 65535 */ -#define W9968CF_CONTRAST 50000 /* from 0 to 65535 */ -#define W9968CF_WHITENESS 32768 /* from 0 to 65535 */ - -#define W9968CF_AUTOBRIGHT 0 /* 0 disable, 1 enable automatic brightness */ -#define W9968CF_AUTOEXP 1 /* 0 disable, 1 enable automatic exposure */ -#define W9968CF_LIGHTFREQ 50 /* light frequency. 50Hz (Europe) or 60Hz */ -#define W9968CF_BANDINGFILTER 0 /* 0 disable, 1 enable banding filter */ -#define W9968CF_BACKLIGHT 0 /* 0 or 1, 1=object is lit from behind */ -#define W9968CF_MIRROR 0 /* 0 or 1 [don't] reverse image horizontally*/ - -#define W9968CF_CLOCKDIV -1 /* -1 = automatic clock divisor */ -#define W9968CF_DEF_CLOCKDIVISOR 0 /* default sensor clock divisor value */ - - -/**************************************************************************** - * Globals * - ****************************************************************************/ - -#define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \ - "Dual Mode Camera Chip" -#define W9968CF_MODULE_VERSION "1:1.33-basic" -#define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia" -#define W9968CF_AUTHOR_EMAIL "" -#define W9968CF_MODULE_LICENSE "GPL" - -static const struct usb_device_id winbond_id_table[] = { - { - /* Creative Labs Video Blaster WebCam Go Plus */ - USB_DEVICE(0x041e, 0x4003), - .driver_info = (unsigned long)"w9968cf", - }, - { - /* Generic W996[87]CF JPEG USB Dual Mode Camera */ - USB_DEVICE(0x1046, 0x9967), - .driver_info = (unsigned long)"w9968cf", - }, - { } /* terminating entry */ -}; - -/* W996[87]CF camera models, internal ids: */ -enum w9968cf_model_id { - W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */ - W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/ - W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */ - W9986CF_MOD_AAU = 31, /* AVerMedia AVerTV USB */ - W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */ - W9968CF_MOD_LL = 37, /* Lebon LDC-035A */ - W9968CF_MOD_EEEMC = 40, /* Ezonics EZ-802 EZMega Cam */ - W9968CF_MOD_OOE = 42, /* OmniVision OV8610-EDE */ - W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */ - W9968CF_MOD_PDPII = 46, /* Pretec Digi Pen-II */ - W9968CF_MOD_PDP480 = 49, /* Pretec DigiPen-480 */ -}; - -enum w9968cf_frame_status { - F_READY, /* finished grabbing & ready to be read/synced */ - F_GRABBING, /* in the process of being grabbed into */ - F_ERROR, /* something bad happened while processing */ - F_UNUSED /* unused (no VIDIOCMCAPTURE) */ -}; - -struct w9968cf_frame_t { - void* buffer; - unsigned long size; - u32 length; - int number; - enum w9968cf_frame_status status; - struct w9968cf_frame_t* next; - u8 queued; -}; - -enum w9968cf_vpp_flag { - VPP_NONE = 0x00, - VPP_UPSCALE = 0x01, - VPP_SWAP_YUV_BYTES = 0x02, - VPP_DECOMPRESSION = 0x04, - VPP_UYVY_TO_RGBX = 0x08, -}; - -/* Main device driver structure */ -struct w9968cf_device { - struct device dev; /* device structure */ - - enum w9968cf_model_id id; /* private device identifier */ - - struct video_device* v4ldev; /* -> V4L structure */ - struct list_head v4llist; /* entry of the list of V4L cameras */ - - struct usb_device* usbdev; /* -> main USB structure */ - struct urb* urb[W9968CF_URBS]; /* -> USB request block structs */ - void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */ - u16* control_buffer; /* -> buffer for control req.*/ - u16* data_buffer; /* -> data to send to the FSB */ - - struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS]; - struct w9968cf_frame_t frame_tmp; /* temporary frame */ - struct w9968cf_frame_t frame_vpp; /* helper frame.*/ - struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */ - struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS]; - - u8 max_buffers, /* number of requested buffers */ - force_palette, /* yes=1/no=0 */ - force_rgb, /* read RGB instead of BGR, yes=1, no=0 */ - double_buffer, /* hardware double buffering yes=1/no=0 */ - clamping, /* video data clamping yes=1/no=0 */ - filter_type, /* 0=disabled, 1=3 tap, 2=5 tap filter */ - capture, /* 0=disabled, 1=enabled */ - largeview, /* 0=disabled, 1=enabled */ - decompression, /* 0=disabled, 1=forced, 2=allowed */ - upscaling; /* software image scaling, 0=enabled, 1=disabled */ - - struct video_picture picture; /* current picture settings */ - struct video_window window; /* current window settings */ - - u16 hw_depth, /* depth (used by the chip) */ - hw_palette, /* palette (used by the chip) */ - hw_width, /* width (used by the chip) */ - hw_height, /* height (used by the chip) */ - hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ - vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ - start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/ - start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/ - - enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */ - - u8 nbuffers, /* number of allocated frame buffers */ - altsetting, /* camera alternate setting */ - disconnected, /* flag: yes=1, no=0 */ - misconfigured, /* flag: yes=1, no=0 */ - users, /* flag: number of users holding the device */ - streaming; /* flag: yes=1, no=0 */ - - u8 sensor_initialized; /* flag: yes=1, no=0 */ - - /* Determined by the image sensor type: */ - int sensor, /* type of image sensor chip (CC_*) */ - monochrome; /* image sensor is (probably) monochrome */ - u16 maxwidth, /* maximum width supported by the image sensor */ - maxheight, /* maximum height supported by the image sensor */ - minwidth, /* minimum width supported by the image sensor */ - minheight; /* minimum height supported by the image sensor */ - u8 auto_brt, /* auto brightness enabled flag */ - auto_exp, /* auto exposure enabled flag */ - backlight, /* backlight exposure algorithm flag */ - mirror, /* image is reversed horizontally */ - lightfreq, /* power (lighting) frequency */ - bandfilt; /* banding filter enabled flag */ - s8 clockdiv; /* clock divisor */ - - /* I2C interface to kernel */ - struct i2c_adapter i2c_adapter; - struct i2c_client* sensor_client; - - /* Locks */ - struct mutex dev_mutex, /* for probe, disconnect,open and close */ - fileop_mutex; /* for read and ioctl */ - spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */ - flist_lock; /* for requested frame list accesses */ - wait_queue_head_t open, wait_queue; - - char command[16]; /* name of the program holding the device */ -}; - - -/**************************************************************************** - * Macros for debugging * - ****************************************************************************/ - -#undef DBG -#undef KDBG -#ifdef W9968CF_DEBUG -/* For device specific debugging messages */ -# define DBG(level, fmt, args...) \ -{ \ - if ( ((specific_debug) && (debug == (level))) || \ - ((!specific_debug) && (debug >= (level))) ) { \ - if ((level) == 1) \ - dev_err(&cam->dev, fmt "\n", ## args); \ - else if ((level) == 2 || (level) == 3) \ - dev_info(&cam->dev, fmt "\n", ## args); \ - else if ((level) == 4) \ - dev_warn(&cam->dev, fmt "\n", ## args); \ - else if ((level) >= 5) \ - dev_info(&cam->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args); \ - } \ -} -/* For generic kernel (not device specific) messages */ -# define KDBG(level, fmt, args...) \ -{ \ - if ( ((specific_debug) && (debug == (level))) || \ - ((!specific_debug) && (debug >= (level))) ) { \ - if ((level) >= 1 && (level) <= 4) \ - pr_info("w9968cf: " fmt "\n", ## args); \ - else if ((level) >= 5) \ - pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__, \ - __LINE__ , ## args); \ - } \ -} -#else - /* Not debugging: nothing */ -# define DBG(level, fmt, args...) do {;} while(0); -# define KDBG(level, fmt, args...) do {;} while(0); -#endif - -#undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args); - -#undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */ - -#endif /* _W9968CF_H_ */ diff --git a/drivers/usb/media/w9968cf_decoder.h b/drivers/usb/media/w9968cf_decoder.h deleted file mode 100644 index 31faccbe8f03..000000000000 --- a/drivers/usb/media/w9968cf_decoder.h +++ /dev/null @@ -1,86 +0,0 @@ -/*************************************************************************** - * Video decoder for the W996[87]CF driver for Linux. * - * * - * Copyright (C) 2003 2004 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _W9968CF_DECODER_H_ -#define _W9968CF_DECODER_H_ - -/* Comment/uncomment this for high/low quality of compressed video */ -#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO - -#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO -static const unsigned char Y_QUANTABLE[64] = { - 16, 11, 10, 16, 24, 40, 51, 61, - 12, 12, 14, 19, 26, 58, 60, 55, - 14, 13, 16, 24, 40, 57, 69, 56, - 14, 17, 22, 29, 51, 87, 80, 62, - 18, 22, 37, 56, 68, 109, 103, 77, - 24, 35, 55, 64, 81, 104, 113, 92, - 49, 64, 78, 87, 103, 121, 120, 101, - 72, 92, 95, 98, 112, 100, 103, 99 -}; - -static const unsigned char UV_QUANTABLE[64] = { - 17, 18, 24, 47, 99, 99, 99, 99, - 18, 21, 26, 66, 99, 99, 99, 99, - 24, 26, 56, 99, 99, 99, 99, 99, - 47, 66, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 -}; -#else -static const unsigned char Y_QUANTABLE[64] = { - 8, 5, 5, 8, 12, 20, 25, 30, - 6, 6, 7, 9, 13, 29, 30, 27, - 7, 6, 8, 12, 20, 28, 34, 28, - 7, 8, 11, 14, 25, 43, 40, 31, - 9, 11, 18, 28, 34, 54, 51, 38, - 12, 17, 27, 32, 40, 52, 56, 46, - 24, 32, 39, 43, 51, 60, 60, 50, - 36, 46, 47, 49, 56, 50, 51, 49 -}; - -static const unsigned char UV_QUANTABLE[64] = { - 8, 9, 12, 23, 49, 49, 49, 49, - 9, 10, 13, 33, 49, 49, 49, 49, - 12, 13, 28, 49, 49, 49, 49, 49, - 23, 33, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49 -}; -#endif - -#define W9968CF_DEC_ERR_CORRUPTED_DATA -1 -#define W9968CF_DEC_ERR_BUF_OVERFLOW -2 -#define W9968CF_DEC_ERR_NO_SOI -3 -#define W9968CF_DEC_ERR_NO_SOF0 -4 -#define W9968CF_DEC_ERR_NO_SOS -5 -#define W9968CF_DEC_ERR_NO_EOI -6 - -extern void w9968cf_init_decoder(void); -extern int w9968cf_check_headers(const unsigned char* Pin, - const unsigned long BUF_SIZE); -extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE, - const unsigned W, const unsigned H, char* Pout); - -#endif /* _W9968CF_DECODER_H_ */ diff --git a/drivers/usb/media/w9968cf_vpp.h b/drivers/usb/media/w9968cf_vpp.h deleted file mode 100644 index f3b91b782671..000000000000 --- a/drivers/usb/media/w9968cf_vpp.h +++ /dev/null @@ -1,40 +0,0 @@ -/*************************************************************************** - * Interface for video post-processing functions for the W996[87]CF driver * - * for Linux. * - * * - * Copyright (C) 2002-2004 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _W9968CF_VPP_H_ -#define _W9968CF_VPP_H_ - -#include -#include - -struct w9968cf_vpp_t { - struct module* owner; - int (*check_headers)(const unsigned char*, const unsigned long); - int (*decode)(const char*, const unsigned long, const unsigned, - const unsigned, char*); - void (*swap_yuvbytes)(void*, unsigned long); - void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8); - void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16); - - u8 busy; /* read-only flag: module is/is not in use */ -}; - -#endif /* _W9968CF_VPP_H_ */ diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h deleted file mode 100644 index 8e0655140e60..000000000000 --- a/drivers/usb/media/zc0301.h +++ /dev/null @@ -1,192 +0,0 @@ -/*************************************************************************** - * V4L2 driver for ZC0301 Image Processor and Control Chip * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _ZC0301_H_ -#define _ZC0301_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "zc0301_sensor.h" - -/*****************************************************************************/ - -#define ZC0301_DEBUG -#define ZC0301_DEBUG_LEVEL 2 -#define ZC0301_MAX_DEVICES 64 -#define ZC0301_FORCE_MUNMAP 0 -#define ZC0301_MAX_FRAMES 32 -#define ZC0301_COMPRESSION_QUALITY 0 -#define ZC0301_URBS 2 -#define ZC0301_ISO_PACKETS 7 -#define ZC0301_ALTERNATE_SETTING 7 -#define ZC0301_URB_TIMEOUT msecs_to_jiffies(2 * ZC0301_ISO_PACKETS) -#define ZC0301_CTRL_TIMEOUT 100 -#define ZC0301_FRAME_TIMEOUT 2 - -/*****************************************************************************/ - -ZC0301_ID_TABLE -ZC0301_SENSOR_TABLE - -enum zc0301_frame_state { - F_UNUSED, - F_QUEUED, - F_GRABBING, - F_DONE, - F_ERROR, -}; - -struct zc0301_frame_t { - void* bufmem; - struct v4l2_buffer buf; - enum zc0301_frame_state state; - struct list_head frame; - unsigned long vma_use_count; -}; - -enum zc0301_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -enum zc0301_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -enum zc0301_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON, -}; - -struct zc0301_module_param { - u8 force_munmap; - u16 frame_timeout; -}; - -static DECLARE_RWSEM(zc0301_disconnect); - -struct zc0301_device { - struct video_device* v4ldev; - - struct zc0301_sensor sensor; - - struct usb_device* usbdev; - struct urb* urb[ZC0301_URBS]; - void* transfer_buffer[ZC0301_URBS]; - u8* control_buffer; - - struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES]; - struct list_head inqueue, outqueue; - u32 frame_count, nbuffers, nreadbuffers; - - enum zc0301_io_method io; - enum zc0301_stream_state stream; - - struct v4l2_jpegcompression compression; - - struct zc0301_module_param module_param; - - enum zc0301_dev_state state; - u8 users; - - struct mutex dev_mutex, fileop_mutex; - spinlock_t queue_lock; - wait_queue_head_t open, wait_frame, wait_stream; -}; - -/*****************************************************************************/ - -struct zc0301_device* -zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id) -{ - return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL; -} - -void -zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor) -{ - memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor)); -} - -/*****************************************************************************/ - -#undef DBG -#undef KDBG -#ifdef ZC0301_DEBUG -# define DBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1) \ - dev_err(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) == 2) \ - dev_info(&cam->usbdev->dev, fmt "\n", ## args); \ - else if ((level) >= 3) \ - dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args); \ - } \ -} while (0) -# define KDBG(level, fmt, args...) \ -do { \ - if (debug >= (level)) { \ - if ((level) == 1 || (level) == 2) \ - pr_info("zc0301: " fmt "\n", ## args); \ - else if ((level) == 3) \ - pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__, \ - __LINE__ , ## args); \ - } \ -} while (0) -# define V4LDBG(level, name, cmd) \ -do { \ - if (debug >= (level)) \ - v4l_print_ioctl(name, cmd); \ -} while (0) -#else -# define DBG(level, fmt, args...) do {;} while(0) -# define KDBG(level, fmt, args...) do {;} while(0) -# define V4LDBG(level, name, cmd) do {;} while(0) -#endif - -#undef PDBG -#define PDBG(fmt, args...) \ -dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ - __FUNCTION__, __LINE__ , ## args) - -#undef PDBGG -#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ - -#endif /* _ZC0301_H_ */ diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c deleted file mode 100644 index 4036c6268bff..000000000000 --- a/drivers/usb/media/zc0301_core.c +++ /dev/null @@ -1,2055 +0,0 @@ -/*************************************************************************** - * Video4Linux2 driver for ZC0301 Image Processor and Control Chip * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * Informations about the chip internals needed to enable the I2C protocol * - * have been taken from the documentation of the ZC030x Video4Linux1 * - * driver written by Andrew Birkett * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "zc0301.h" - -/*****************************************************************************/ - -#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301 " \ - "Image Processor and Control Chip" -#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia" -#define ZC0301_AUTHOR_EMAIL "" -#define ZC0301_MODULE_LICENSE "GPL" -#define ZC0301_MODULE_VERSION "1:1.03" -#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 3) - -/*****************************************************************************/ - -MODULE_DEVICE_TABLE(usb, zc0301_id_table); - -MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL); -MODULE_DESCRIPTION(ZC0301_MODULE_NAME); -MODULE_VERSION(ZC0301_MODULE_VERSION); -MODULE_LICENSE(ZC0301_MODULE_LICENSE); - -static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1}; -module_param_array(video_nr, short, NULL, 0444); -MODULE_PARM_DESC(video_nr, - "\n<-1|n[,...]> Specify V4L2 minor mode number." - "\n -1 = use next available (default)" - "\n n = use minor number n (integer >= 0)" - "\nYou can specify up to " - __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way." - "\nFor example:" - "\nvideo_nr=-1,2,-1 would assign minor number 2 to" - "\nthe second registered camera and use auto for the first" - "\none and for every other camera." - "\n"); - -static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] = - ZC0301_FORCE_MUNMAP}; -module_param_array(force_munmap, bool, NULL, 0444); -MODULE_PARM_DESC(force_munmap, - "\n<0|1[,...]> Force the application to unmap previously" - "\nmapped buffer memory before calling any VIDIOC_S_CROP or" - "\nVIDIOC_S_FMT ioctl's. Not all the applications support" - "\nthis feature. This parameter is specific for each" - "\ndetected camera." - "\n 0 = do not force memory unmapping" - "\n 1 = force memory unmapping (save memory)" - "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." - "\n"); - -static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] = - ZC0301_FRAME_TIMEOUT}; -module_param_array(frame_timeout, uint, NULL, 0644); -MODULE_PARM_DESC(frame_timeout, - "\n Timeout for a video frame in seconds." - "\nThis parameter is specific for each detected camera." - "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"." - "\n"); - -#ifdef ZC0301_DEBUG -static unsigned short debug = ZC0301_DEBUG_LEVEL; -module_param(debug, ushort, 0644); -MODULE_PARM_DESC(debug, - "\n Debugging information level, from 0 to 3:" - "\n0 = none (use carefully)" - "\n1 = critical errors" - "\n2 = significant informations" - "\n3 = more verbose messages" - "\nLevel 3 is useful for testing only, when only " - "one device is used." - "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"." - "\n"); -#endif - -/*****************************************************************************/ - -static u32 -zc0301_request_buffers(struct zc0301_device* cam, u32 count, - enum zc0301_io_method io) -{ - struct v4l2_pix_format* p = &(cam->sensor.pix_format); - struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); - const size_t imagesize = cam->module_param.force_munmap || - io == IO_READ ? - (p->width * p->height * p->priv) / 8 : - (r->width * r->height * p->priv) / 8; - void* buff = NULL; - u32 i; - - if (count > ZC0301_MAX_FRAMES) - count = ZC0301_MAX_FRAMES; - - cam->nbuffers = count; - while (cam->nbuffers > 0) { - if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize)))) - break; - cam->nbuffers--; - } - - for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.index = i; - cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); - cam->frame[i].buf.length = imagesize; - cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cam->frame[i].buf.sequence = 0; - cam->frame[i].buf.field = V4L2_FIELD_NONE; - cam->frame[i].buf.memory = V4L2_MEMORY_MMAP; - cam->frame[i].buf.flags = 0; - } - - return cam->nbuffers; -} - - -static void zc0301_release_buffers(struct zc0301_device* cam) -{ - if (cam->nbuffers) { - vfree(cam->frame[0].bufmem); - cam->nbuffers = 0; - } - cam->frame_current = NULL; -} - - -static void zc0301_empty_framequeues(struct zc0301_device* cam) -{ - u32 i; - - INIT_LIST_HEAD(&cam->inqueue); - INIT_LIST_HEAD(&cam->outqueue); - - for (i = 0; i < ZC0301_MAX_FRAMES; i++) { - cam->frame[i].state = F_UNUSED; - cam->frame[i].buf.bytesused = 0; - } -} - - -static void zc0301_requeue_outqueue(struct zc0301_device* cam) -{ - struct zc0301_frame_t *i; - - list_for_each_entry(i, &cam->outqueue, frame) { - i->state = F_QUEUED; - list_add(&i->frame, &cam->inqueue); - } - - INIT_LIST_HEAD(&cam->outqueue); -} - - -static void zc0301_queue_unusedframes(struct zc0301_device* cam) -{ - unsigned long lock_flags; - u32 i; - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].state == F_UNUSED) { - cam->frame[i].state = F_QUEUED; - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[i].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - } -} - -/*****************************************************************************/ - -int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value) -{ - struct usb_device* udev = cam->usbdev; - int res; - - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40, - value, index, NULL, 0, ZC0301_CTRL_TIMEOUT); - if (res < 0) { - DBG(3, "Failed to write a register (index 0x%04X, " - "value 0x%02X, error %d)",index, value, res); - return -1; - } - - return 0; -} - - -int zc0301_read_reg(struct zc0301_device* cam, u16 index) -{ - struct usb_device* udev = cam->usbdev; - u8* buff = cam->control_buffer; - int res; - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0, - 0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT); - if (res < 0) - DBG(3, "Failed to read a register (index 0x%04X, error %d)", - index, res); - - PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff)); - - return (res >= 0) ? (int)(*buff) : -1; -} - - -int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length) -{ - int err = 0, res, r0, r1; - - err += zc0301_write_reg(cam, 0x0092, address); - err += zc0301_write_reg(cam, 0x0090, 0x02); - - msleep(1); - - res = zc0301_read_reg(cam, 0x0091); - if (res < 0) - err += res; - r0 = zc0301_read_reg(cam, 0x0095); - if (r0 < 0) - err += r0; - r1 = zc0301_read_reg(cam, 0x0096); - if (r1 < 0) - err += r1; - - res = (length <= 1) ? r0 : r0 | (r1 << 8); - - if (err) - DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X", - address, res); - - - PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res); - - return err ? -1 : res; -} - - -int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value) -{ - int err = 0, res; - - err += zc0301_write_reg(cam, 0x0092, address); - err += zc0301_write_reg(cam, 0x0093, value & 0xff); - err += zc0301_write_reg(cam, 0x0094, value >> 8); - err += zc0301_write_reg(cam, 0x0090, 0x01); - - msleep(1); - - res = zc0301_read_reg(cam, 0x0091); - if (res < 0) - err += res; - - if (err) - DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X", - address, value); - - PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value); - - return err ? -1 : 0; -} - -/*****************************************************************************/ - -static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs) -{ - struct zc0301_device* cam = urb->context; - struct zc0301_frame_t** f; - size_t imagesize; - u8 i; - int err = 0; - - if (urb->status == -ENOENT) - return; - - f = &cam->frame_current; - - if (cam->stream == STREAM_INTERRUPT) { - cam->stream = STREAM_OFF; - if ((*f)) - (*f)->state = F_QUEUED; - DBG(3, "Stream interrupted"); - wake_up(&cam->wait_stream); - } - - if (cam->state & DEV_DISCONNECTED) - return; - - if (cam->state & DEV_MISCONFIGURED) { - wake_up_interruptible(&cam->wait_frame); - return; - } - - if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) - goto resubmit_urb; - - if (!(*f)) - (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t, - frame); - - imagesize = (cam->sensor.pix_format.width * - cam->sensor.pix_format.height * - cam->sensor.pix_format.priv) / 8; - - for (i = 0; i < urb->number_of_packets; i++) { - unsigned int len, status; - void *pos; - u16* soi; - u8 sof; - - len = urb->iso_frame_desc[i].actual_length; - status = urb->iso_frame_desc[i].status; - pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; - - if (status) { - DBG(3, "Error in isochronous frame"); - (*f)->state = F_ERROR; - continue; - } - - sof = (*(soi = pos) == 0xd8ff); - - PDBGG("Isochrnous frame: length %u, #%u i,", len, i); - - if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) -start_of_frame: - if (sof) { - (*f)->state = F_GRABBING; - (*f)->buf.bytesused = 0; - do_gettimeofday(&(*f)->buf.timestamp); - DBG(3, "SOF detected: new video frame"); - } - - if ((*f)->state == F_GRABBING) { - if (sof && (*f)->buf.bytesused) - goto end_of_frame; - - if ((*f)->buf.bytesused + len > imagesize) { - DBG(3, "Video frame size exceeded"); - (*f)->state = F_ERROR; - continue; - } - - memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len); - (*f)->buf.bytesused += len; - - if ((*f)->buf.bytesused == imagesize) { - u32 b; -end_of_frame: - b = (*f)->buf.bytesused; - (*f)->state = F_DONE; - (*f)->buf.sequence= ++cam->frame_count; - spin_lock(&cam->queue_lock); - list_move_tail(&(*f)->frame, &cam->outqueue); - if (!list_empty(&cam->inqueue)) - (*f) = list_entry(cam->inqueue.next, - struct zc0301_frame_t, - frame); - else - (*f) = NULL; - spin_unlock(&cam->queue_lock); - DBG(3, "Video frame captured: : %lu bytes", - (unsigned long)(b)); - - if (!(*f)) - goto resubmit_urb; - - if (sof) - goto start_of_frame; - } - } - } - -resubmit_urb: - urb->dev = cam->usbdev; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0 && err != -EPERM) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "usb_submit_urb() failed"); - } - - wake_up_interruptible(&cam->wait_frame); -} - - -static int zc0301_start_transfer(struct zc0301_device* cam) -{ - struct usb_device *udev = cam->usbdev; - struct urb* urb; - const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384, - 512, 768, 1023}; - const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING]; - s8 i, j; - int err = 0; - - for (i = 0; i < ZC0301_URBS; i++) { - cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz, - GFP_KERNEL); - if (!cam->transfer_buffer[i]) { - err = -ENOMEM; - DBG(1, "Not enough memory"); - goto free_buffers; - } - } - - for (i = 0; i < ZC0301_URBS; i++) { - urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL); - cam->urb[i] = urb; - if (!urb) { - err = -ENOMEM; - DBG(1, "usb_alloc_urb() failed"); - goto free_urbs; - } - urb->dev = udev; - urb->context = cam; - urb->pipe = usb_rcvisocpipe(udev, 1); - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = ZC0301_ISO_PACKETS; - urb->complete = zc0301_urb_complete; - urb->transfer_buffer = cam->transfer_buffer[i]; - urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS; - urb->interval = 1; - for (j = 0; j < ZC0301_ISO_PACKETS; j++) { - urb->iso_frame_desc[j].offset = psz * j; - urb->iso_frame_desc[j].length = psz; - } - } - - err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING); - if (err) { - DBG(1, "usb_set_interface() failed"); - goto free_urbs; - } - - cam->frame_current = NULL; - - for (i = 0; i < ZC0301_URBS; i++) { - err = usb_submit_urb(cam->urb[i], GFP_KERNEL); - if (err) { - for (j = i-1; j >= 0; j--) - usb_kill_urb(cam->urb[j]); - DBG(1, "usb_submit_urb() failed, error %d", err); - goto free_urbs; - } - } - - return 0; - -free_urbs: - for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++) - usb_free_urb(cam->urb[i]); - -free_buffers: - for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++) - kfree(cam->transfer_buffer[i]); - - return err; -} - - -static int zc0301_stop_transfer(struct zc0301_device* cam) -{ - struct usb_device *udev = cam->usbdev; - s8 i; - int err = 0; - - if (cam->state & DEV_DISCONNECTED) - return 0; - - for (i = ZC0301_URBS-1; i >= 0; i--) { - usb_kill_urb(cam->urb[i]); - usb_free_urb(cam->urb[i]); - kfree(cam->transfer_buffer[i]); - } - - err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */ - if (err) - DBG(3, "usb_set_interface() failed"); - - return err; -} - - -static int zc0301_stream_interrupt(struct zc0301_device* cam) -{ - long timeout; - - cam->stream = STREAM_INTERRUPT; - timeout = wait_event_timeout(cam->wait_stream, - (cam->stream == STREAM_OFF) || - (cam->state & DEV_DISCONNECTED), - ZC0301_URB_TIMEOUT); - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - else if (cam->stream != STREAM_OFF) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "URB timeout reached. The camera is misconfigured. To " - "use it, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - return 0; -} - -/*****************************************************************************/ - -static int -zc0301_set_compression(struct zc0301_device* cam, - struct v4l2_jpegcompression* compression) -{ - int r, err = 0; - - if ((r = zc0301_read_reg(cam, 0x0008)) < 0) - err += r; - err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality); - - return err ? -EIO : 0; -} - - -static int zc0301_init(struct zc0301_device* cam) -{ - struct zc0301_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - struct v4l2_queryctrl *qctrl; - struct v4l2_rect* rect; - u8 i = 0; - int err = 0; - - if (!(cam->state & DEV_INITIALIZED)) { - init_waitqueue_head(&cam->open); - qctrl = s->qctrl; - rect = &(s->cropcap.defrect); - cam->compression.quality = ZC0301_COMPRESSION_QUALITY; - } else { /* use current values */ - qctrl = s->_qctrl; - rect = &(s->_rect); - } - - if (s->init) { - err = s->init(cam); - if (err) { - DBG(3, "Sensor initialization failed"); - return err; - } - } - - if ((err = zc0301_set_compression(cam, &cam->compression))) { - DBG(3, "set_compression() failed"); - return err; - } - - if (s->set_crop) - if ((err = s->set_crop(cam, rect))) { - DBG(3, "set_crop() failed"); - return err; - } - - if (s->set_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (s->qctrl[i].id != 0 && - !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) { - ctrl.id = s->qctrl[i].id; - ctrl.value = qctrl[i].default_value; - err = s->set_ctrl(cam, &ctrl); - if (err) { - DBG(3, "Set %s control failed", - s->qctrl[i].name); - return err; - } - DBG(3, "Image sensor supports '%s' control", - s->qctrl[i].name); - } - } - - if (!(cam->state & DEV_INITIALIZED)) { - mutex_init(&cam->fileop_mutex); - spin_lock_init(&cam->queue_lock); - init_waitqueue_head(&cam->wait_frame); - init_waitqueue_head(&cam->wait_stream); - cam->nreadbuffers = 2; - memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl)); - memcpy(&(s->_rect), &(s->cropcap.defrect), - sizeof(struct v4l2_rect)); - cam->state |= DEV_INITIALIZED; - } - - DBG(2, "Initialization succeeded"); - return 0; -} - - -static void zc0301_release_resources(struct zc0301_device* cam) -{ - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor); - video_set_drvdata(cam->v4ldev, NULL); - video_unregister_device(cam->v4ldev); - kfree(cam->control_buffer); -} - -/*****************************************************************************/ - -static int zc0301_open(struct inode* inode, struct file* filp) -{ - struct zc0301_device* cam; - int err = 0; - - /* - This is the only safe way to prevent race conditions with - disconnect - */ - if (!down_read_trylock(&zc0301_disconnect)) - return -ERESTARTSYS; - - cam = video_get_drvdata(video_devdata(filp)); - - if (mutex_lock_interruptible(&cam->dev_mutex)) { - up_read(&zc0301_disconnect); - return -ERESTARTSYS; - } - - if (cam->users) { - DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor); - if ((filp->f_flags & O_NONBLOCK) || - (filp->f_flags & O_NDELAY)) { - err = -EWOULDBLOCK; - goto out; - } - mutex_unlock(&cam->dev_mutex); - err = wait_event_interruptible_exclusive(cam->open, - cam->state & DEV_DISCONNECTED - || !cam->users); - if (err) { - up_read(&zc0301_disconnect); - return err; - } - if (cam->state & DEV_DISCONNECTED) { - up_read(&zc0301_disconnect); - return -ENODEV; - } - mutex_lock(&cam->dev_mutex); - } - - - if (cam->state & DEV_MISCONFIGURED) { - err = zc0301_init(cam); - if (err) { - DBG(1, "Initialization failed again. " - "I will retry on next open()."); - goto out; - } - cam->state &= ~DEV_MISCONFIGURED; - } - - if ((err = zc0301_start_transfer(cam))) - goto out; - - filp->private_data = cam; - cam->users++; - cam->io = IO_NONE; - cam->stream = STREAM_OFF; - cam->nbuffers = 0; - cam->frame_count = 0; - zc0301_empty_framequeues(cam); - - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor); - -out: - mutex_unlock(&cam->dev_mutex); - up_read(&zc0301_disconnect); - return err; -} - - -static int zc0301_release(struct inode* inode, struct file* filp) -{ - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); - - mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ - - zc0301_stop_transfer(cam); - - zc0301_release_buffers(cam); - - if (cam->state & DEV_DISCONNECTED) { - zc0301_release_resources(cam); - usb_put_dev(cam->usbdev); - mutex_unlock(&cam->dev_mutex); - kfree(cam); - return 0; - } - - cam->users--; - wake_up_interruptible_nr(&cam->open, 1); - - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor); - - mutex_unlock(&cam->dev_mutex); - - return 0; -} - - -static ssize_t -zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) -{ - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); - struct zc0301_frame_t* f, * i; - unsigned long lock_flags; - long timeout; - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io == IO_MMAP) { - DBG(3, "Close and open the device again to choose the read " - "method"); - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - if (cam->io == IO_NONE) { - if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) { - DBG(1, "read() failed, not enough memory"); - mutex_unlock(&cam->fileop_mutex); - return -ENOMEM; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (list_empty(&cam->inqueue)) { - if (!list_empty(&cam->outqueue)) - zc0301_empty_framequeues(cam); - zc0301_queue_unusedframes(cam); - } - - if (!count) { - mutex_unlock(&cam->fileop_mutex); - return 0; - } - - if (list_empty(&cam->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) { - mutex_unlock(&cam->fileop_mutex); - return timeout; - } - if (cam->state & DEV_DISCONNECTED) { - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - if (!timeout || (cam->state & DEV_MISCONFIGURED)) { - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - } - - f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame); - - if (count > f->buf.bytesused) - count = f->buf.bytesused; - - if (copy_to_user(buf, f->bufmem, count)) { - err = -EFAULT; - goto exit; - } - *f_pos += count; - -exit: - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(i, &cam->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - zc0301_queue_unusedframes(cam); - - PDBGG("Frame #%lu, bytes read: %zu", - (unsigned long)f->buf.index, count); - - mutex_unlock(&cam->fileop_mutex); - - return err ? err : count; -} - - -static unsigned int zc0301_poll(struct file *filp, poll_table *wait) -{ - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); - struct zc0301_frame_t* f; - unsigned long lock_flags; - unsigned int mask = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return POLLERR; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - goto error; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - goto error; - } - - if (cam->io == IO_NONE) { - if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) { - DBG(1, "poll() failed, not enough memory"); - goto error; - } - cam->io = IO_READ; - cam->stream = STREAM_ON; - } - - if (cam->io == IO_READ) { - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_for_each_entry(f, &cam->outqueue, frame) - f->state = F_UNUSED; - INIT_LIST_HEAD(&cam->outqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - zc0301_queue_unusedframes(cam); - } - - poll_wait(filp, &cam->wait_frame, wait); - - if (!list_empty(&cam->outqueue)) - mask |= POLLIN | POLLRDNORM; - - mutex_unlock(&cam->fileop_mutex); - - return mask; - -error: - mutex_unlock(&cam->fileop_mutex); - return POLLERR; -} - - -static void zc0301_vm_open(struct vm_area_struct* vma) -{ - struct zc0301_frame_t* f = vma->vm_private_data; - f->vma_use_count++; -} - - -static void zc0301_vm_close(struct vm_area_struct* vma) -{ - /* NOTE: buffers are not freed here */ - struct zc0301_frame_t* f = vma->vm_private_data; - f->vma_use_count--; -} - - -static struct vm_operations_struct zc0301_vm_ops = { - .open = zc0301_vm_open, - .close = zc0301_vm_close, -}; - - -static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma) -{ - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(cam->frame[0].buf.length)) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) { - if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == cam->nbuffers) { - mutex_unlock(&cam->fileop_mutex); - return -EINVAL; - } - - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; - - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &zc0301_vm_ops; - vma->vm_private_data = &cam->frame[i]; - - zc0301_vm_open(vma); - - mutex_unlock(&cam->fileop_mutex); - - return 0; -} - -/*****************************************************************************/ - -static int -zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_capability cap = { - .driver = "zc0301", - .version = ZC0301_MODULE_VERSION_CODE, - .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING, - }; - - strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card)); - if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0) - strlcpy(cap.bus_info, cam->usbdev->dev.bus_id, - sizeof(cap.bus_info)); - - if (copy_to_user(arg, &cap, sizeof(cap))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_input i; - - if (copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - if (i.index) - return -EINVAL; - - memset(&i, 0, sizeof(i)); - strcpy(i.name, "Camera"); - i.type = V4L2_INPUT_TYPE_CAMERA; - - if (copy_to_user(arg, &i, sizeof(i))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg) -{ - int index = 0; - - if (copy_to_user(arg, &index, sizeof(index))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg) -{ - int index; - - if (copy_from_user(&index, arg, sizeof(index))) - return -EFAULT; - - if (index != 0) - return -EINVAL; - - return 0; -} - - -static int -zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg) -{ - struct zc0301_sensor* s = &cam->sensor; - struct v4l2_queryctrl qc; - u8 i; - - if (copy_from_user(&qc, arg, sizeof(qc))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (qc.id && qc.id == s->qctrl[i].id) { - memcpy(&qc, &(s->qctrl[i]), sizeof(qc)); - if (copy_to_user(arg, &qc, sizeof(qc))) - return -EFAULT; - return 0; - } - - return -EINVAL; -} - - -static int -zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg) -{ - struct zc0301_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - int err = 0; - u8 i; - - if (!s->get_ctrl && !s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - if (!s->get_ctrl) { - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id == s->qctrl[i].id) { - ctrl.value = s->_qctrl[i].default_value; - goto exit; - } - return -EINVAL; - } else - err = s->get_ctrl(cam, &ctrl); - -exit: - if (copy_to_user(arg, &ctrl, sizeof(ctrl))) - return -EFAULT; - - return err; -} - - -static int -zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg) -{ - struct zc0301_sensor* s = &cam->sensor; - struct v4l2_control ctrl; - u8 i; - int err = 0; - - if (!s->set_ctrl) - return -EINVAL; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - - for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) - if (ctrl.id == s->qctrl[i].id) { - if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED) - return -EINVAL; - if (ctrl.value < s->qctrl[i].minimum || - ctrl.value > s->qctrl[i].maximum) - return -ERANGE; - ctrl.value -= ctrl.value % s->qctrl[i].step; - break; - } - - if ((err = s->set_ctrl(cam, &ctrl))) - return err; - - s->_qctrl[i].default_value = ctrl.value; - - return 0; -} - - -static int -zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_cropcap* cc = &(cam->sensor.cropcap); - - cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cc->pixelaspect.numerator = 1; - cc->pixelaspect.denominator = 1; - - if (copy_to_user(arg, cc, sizeof(*cc))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg) -{ - struct zc0301_sensor* s = &cam->sensor; - struct v4l2_crop crop = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - }; - - memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect)); - - if (copy_to_user(arg, &crop, sizeof(crop))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) -{ - struct zc0301_sensor* s = &cam->sensor; - struct v4l2_crop crop; - struct v4l2_rect* rect; - struct v4l2_rect* bounds = &(s->cropcap.bounds); - const enum zc0301_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&crop, arg, sizeof(crop))) - return -EFAULT; - - rect = &(crop.c); - - if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_CROP failed. " - "Unmap the buffers first."); - return -EINVAL; - } - - if (!s->set_crop) { - memcpy(rect, &(s->_rect), sizeof(*rect)); - if (copy_to_user(arg, &crop, sizeof(crop))) - return -EFAULT; - return 0; - } - - rect->left &= ~7L; - rect->top &= ~7L; - if (rect->width < 8) - rect->width = 8; - if (rect->height < 8) - rect->height = 8; - if (rect->width > bounds->width) - rect->width = bounds->width; - if (rect->height > bounds->height) - rect->height = bounds->height; - if (rect->left < bounds->left) - rect->left = bounds->left; - if (rect->top < bounds->top) - rect->top = bounds->top; - if (rect->left + rect->width > bounds->left + bounds->width) - rect->left = bounds->left+bounds->width - rect->width; - if (rect->top + rect->height > bounds->top + bounds->height) - rect->top = bounds->top+bounds->height - rect->height; - rect->width &= ~7L; - rect->height &= ~7L; - - if (cam->stream == STREAM_ON) - if ((err = zc0301_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &crop, sizeof(crop))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - zc0301_release_buffers(cam); - - if (s->set_crop) - err += s->set_crop(cam, rect); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - s->pix_format.width = rect->width; - s->pix_format.height = rect->height; - memcpy(&(s->_rect), rect, sizeof(*rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -ENOMEM; - } - - if (cam->io == IO_READ) - zc0301_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - zc0301_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_fmtdesc fmtd; - - if (copy_from_user(&fmtd, arg, sizeof(fmtd))) - return -EFAULT; - - if (fmtd.index == 0) { - strcpy(fmtd.description, "JPEG"); - fmtd.pixelformat = V4L2_PIX_FMT_JPEG; - fmtd.flags = V4L2_FMT_FLAG_COMPRESSED; - } else - return -EINVAL; - - fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - memset(&fmtd.reserved, 0, sizeof(fmtd.reserved)); - - if (copy_to_user(arg, &fmtd, sizeof(fmtd))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_format format; - struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format); - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - pfmt->bytesperline = 0; - pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); - pfmt->field = V4L2_FIELD_NONE; - memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt)); - - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, - void __user * arg) -{ - struct zc0301_sensor* s = &cam->sensor; - struct v4l2_format format; - struct v4l2_pix_format* pix; - struct v4l2_pix_format* pfmt = &(s->pix_format); - struct v4l2_rect* bounds = &(s->cropcap.bounds); - struct v4l2_rect rect; - const enum zc0301_stream_state stream = cam->stream; - const u32 nbuffers = cam->nbuffers; - u32 i; - int err = 0; - - if (copy_from_user(&format, arg, sizeof(format))) - return -EFAULT; - - pix = &(format.fmt.pix); - - if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - memcpy(&rect, &(s->_rect), sizeof(rect)); - - if (!s->set_crop) { - pix->width = rect.width; - pix->height = rect.height; - } else { - rect.width = pix->width; - rect.height = pix->height; - } - - if (rect.width < 8) - rect.width = 8; - if (rect.height < 8) - rect.height = 8; - if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left + bounds->width - rect.left; - if (rect.height > bounds->top + bounds->height - rect.top) - rect.height = bounds->top + bounds->height - rect.top; - rect.width &= ~7L; - rect.height &= ~7L; - - pix->width = rect.width; - pix->height = rect.height; - pix->pixelformat = pfmt->pixelformat; - pix->priv = pfmt->priv; - pix->colorspace = pfmt->colorspace; - pix->bytesperline = 0; - pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8); - pix->field = V4L2_FIELD_NONE; - - if (cmd == VIDIOC_TRY_FMT) { - if (copy_to_user(arg, &format, sizeof(format))) - return -EFAULT; - return 0; - } - - if (cam->module_param.force_munmap) - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_FMT failed. " - "Unmap the buffers first."); - return -EINVAL; - } - - if (cam->stream == STREAM_ON) - if ((err = zc0301_stream_interrupt(cam))) - return err; - - if (copy_to_user(arg, &format, sizeof(format))) { - cam->stream = stream; - return -EFAULT; - } - - if (cam->module_param.force_munmap || cam->io == IO_READ) - zc0301_release_buffers(cam); - - if (s->set_crop) - err += s->set_crop(cam, &rect); - - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -EIO; - } - - memcpy(pfmt, pix, sizeof(*pix)); - memcpy(&(s->_rect), &rect, sizeof(rect)); - - if ((cam->module_param.force_munmap || cam->io == IO_READ) && - nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->minor); - return -ENOMEM; - } - - if (cam->io == IO_READ) - zc0301_empty_framequeues(cam); - else if (cam->module_param.force_munmap) - zc0301_requeue_outqueue(cam); - - cam->stream = stream; - - return 0; -} - - -static int -zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg) -{ - if (copy_to_user(arg, &cam->compression, sizeof(cam->compression))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_jpegcompression jc; - const enum zc0301_stream_state stream = cam->stream; - int err = 0; - - if (copy_from_user(&jc, arg, sizeof(jc))) - return -EFAULT; - - if (jc.quality != 0) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = zc0301_stream_interrupt(cam))) - return err; - - err += zc0301_set_compression(cam, &jc); - if (err) { /* atomic, no rollback in ioctl() */ - cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " - "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->minor); - return -EIO; - } - - cam->compression.quality = jc.quality; - - cam->stream = stream; - - return 0; -} - - -static int -zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_requestbuffers rb; - u32 i; - int err; - - if (copy_from_user(&rb, arg, sizeof(rb))) - return -EFAULT; - - if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb.memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (cam->io == IO_READ) { - DBG(3, "Close and open the device again to choose the mmap " - "I/O method"); - return -EINVAL; - } - - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_REQBUFS failed. " - "Previous buffers are still mapped."); - return -EINVAL; - } - - if (cam->stream == STREAM_ON) - if ((err = zc0301_stream_interrupt(cam))) - return err; - - zc0301_empty_framequeues(cam); - - zc0301_release_buffers(cam); - if (rb.count) - rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP); - - if (copy_to_user(arg, &rb, sizeof(rb))) { - zc0301_release_buffers(cam); - cam->io = IO_NONE; - return -EFAULT; - } - - cam->io = rb.count ? IO_MMAP : IO_NONE; - - return 0; -} - - -static int -zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - memcpy(&b, &cam->frame[b.index].buf, sizeof(b)); - - if (cam->frame[b.index].vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (cam->frame[b.index].state == F_DONE) - b.flags |= V4L2_BUF_FLAG_DONE; - else if (cam->frame[b.index].state != F_UNUSED) - b.flags |= V4L2_BUF_FLAG_QUEUED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_buffer b; - unsigned long lock_flags; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b.index >= cam->nbuffers || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->frame[b.index].state != F_UNUSED) - return -EINVAL; - - cam->frame[b.index].state = F_QUEUED; - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - list_add_tail(&cam->frame[b.index].frame, &cam->inqueue); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - PDBGG("Frame #%lu queued", (unsigned long)b.index); - - return 0; -} - - -static int -zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp, - void __user * arg) -{ - struct v4l2_buffer b; - struct zc0301_frame_t *f; - unsigned long lock_flags; - long timeout; - - if (copy_from_user(&b, arg, sizeof(b))) - return -EFAULT; - - if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->outqueue)) { - if (cam->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - timeout = wait_event_interruptible_timeout - ( cam->wait_frame, - (!list_empty(&cam->outqueue)) || - (cam->state & DEV_DISCONNECTED) || - (cam->state & DEV_MISCONFIGURED), - cam->module_param.frame_timeout * - 1000 * msecs_to_jiffies(1) ); - if (timeout < 0) - return timeout; - if (cam->state & DEV_DISCONNECTED) - return -ENODEV; - if (!timeout || (cam->state & DEV_MISCONFIGURED)) - return -EIO; - } - - spin_lock_irqsave(&cam->queue_lock, lock_flags); - f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame); - list_del(cam->outqueue.next); - spin_unlock_irqrestore(&cam->queue_lock, lock_flags); - - f->state = F_UNUSED; - - memcpy(&b, &f->buf, sizeof(b)); - if (f->vma_use_count) - b.flags |= V4L2_BUF_FLAG_MAPPED; - - if (copy_to_user(arg, &b, sizeof(b))) - return -EFAULT; - - PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index); - - return 0; -} - - -static int -zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg) -{ - int type; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&cam->inqueue)) - return -EINVAL; - - cam->stream = STREAM_ON; - - DBG(3, "Stream on"); - - return 0; -} - - -static int -zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg) -{ - int type, err; - - if (copy_from_user(&type, arg, sizeof(type))) - return -EFAULT; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) - return -EINVAL; - - if (cam->stream == STREAM_ON) - if ((err = zc0301_stream_interrupt(cam))) - return err; - - zc0301_empty_framequeues(cam); - - DBG(3, "Stream off"); - - return 0; -} - - -static int -zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - return 0; -} - - -static int -zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg) -{ - struct v4l2_streamparm sp; - - if (copy_from_user(&sp, arg, sizeof(sp))) - return -EFAULT; - - if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp.parm.capture.extendedmode = 0; - - if (sp.parm.capture.readbuffers == 0) - sp.parm.capture.readbuffers = cam->nreadbuffers; - - if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES) - sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES; - - if (copy_to_user(arg, &sp, sizeof(sp))) - return -EFAULT; - - cam->nreadbuffers = sp.parm.capture.readbuffers; - - return 0; -} - - -static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp, - unsigned int cmd, void __user * arg) -{ - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); - - switch (cmd) { - - case VIDIOC_QUERYCAP: - return zc0301_vidioc_querycap(cam, arg); - - case VIDIOC_ENUMINPUT: - return zc0301_vidioc_enuminput(cam, arg); - - case VIDIOC_G_INPUT: - return zc0301_vidioc_g_input(cam, arg); - - case VIDIOC_S_INPUT: - return zc0301_vidioc_s_input(cam, arg); - - case VIDIOC_QUERYCTRL: - return zc0301_vidioc_query_ctrl(cam, arg); - - case VIDIOC_G_CTRL: - return zc0301_vidioc_g_ctrl(cam, arg); - - case VIDIOC_S_CTRL_OLD: - case VIDIOC_S_CTRL: - return zc0301_vidioc_s_ctrl(cam, arg); - - case VIDIOC_CROPCAP_OLD: - case VIDIOC_CROPCAP: - return zc0301_vidioc_cropcap(cam, arg); - - case VIDIOC_G_CROP: - return zc0301_vidioc_g_crop(cam, arg); - - case VIDIOC_S_CROP: - return zc0301_vidioc_s_crop(cam, arg); - - case VIDIOC_ENUM_FMT: - return zc0301_vidioc_enum_fmt(cam, arg); - - case VIDIOC_G_FMT: - return zc0301_vidioc_g_fmt(cam, arg); - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - return zc0301_vidioc_try_s_fmt(cam, cmd, arg); - - case VIDIOC_G_JPEGCOMP: - return zc0301_vidioc_g_jpegcomp(cam, arg); - - case VIDIOC_S_JPEGCOMP: - return zc0301_vidioc_s_jpegcomp(cam, arg); - - case VIDIOC_REQBUFS: - return zc0301_vidioc_reqbufs(cam, arg); - - case VIDIOC_QUERYBUF: - return zc0301_vidioc_querybuf(cam, arg); - - case VIDIOC_QBUF: - return zc0301_vidioc_qbuf(cam, arg); - - case VIDIOC_DQBUF: - return zc0301_vidioc_dqbuf(cam, filp, arg); - - case VIDIOC_STREAMON: - return zc0301_vidioc_streamon(cam, arg); - - case VIDIOC_STREAMOFF: - return zc0301_vidioc_streamoff(cam, arg); - - case VIDIOC_G_PARM: - return zc0301_vidioc_g_parm(cam, arg); - - case VIDIOC_S_PARM_OLD: - case VIDIOC_S_PARM: - return zc0301_vidioc_s_parm(cam, arg); - - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_QUERYSTD: - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYMENU: - return -EINVAL; - - default: - return -EINVAL; - - } -} - - -static int zc0301_ioctl(struct inode* inode, struct file* filp, - unsigned int cmd, unsigned long arg) -{ - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); - int err = 0; - - if (mutex_lock_interruptible(&cam->fileop_mutex)) - return -ERESTARTSYS; - - if (cam->state & DEV_DISCONNECTED) { - DBG(1, "Device not present"); - mutex_unlock(&cam->fileop_mutex); - return -ENODEV; - } - - if (cam->state & DEV_MISCONFIGURED) { - DBG(1, "The camera is misconfigured. Close and open it " - "again."); - mutex_unlock(&cam->fileop_mutex); - return -EIO; - } - - V4LDBG(3, "zc0301", cmd); - - err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg); - - mutex_unlock(&cam->fileop_mutex); - - return err; -} - - -static struct file_operations zc0301_fops = { - .owner = THIS_MODULE, - .open = zc0301_open, - .release = zc0301_release, - .ioctl = zc0301_ioctl, - .read = zc0301_read, - .poll = zc0301_poll, - .mmap = zc0301_mmap, - .llseek = no_llseek, -}; - -/*****************************************************************************/ - -static int -zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct zc0301_device* cam; - static unsigned int dev_nr = 0; - unsigned int i; - int err = 0; - - if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL))) - return -ENOMEM; - - cam->usbdev = udev; - - if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) { - DBG(1, "kmalloc() failed"); - err = -ENOMEM; - goto fail; - } - - if (!(cam->v4ldev = video_device_alloc())) { - DBG(1, "video_device_alloc() failed"); - err = -ENOMEM; - goto fail; - } - - mutex_init(&cam->dev_mutex); - - DBG(2, "ZC0301 Image Processor and Control Chip detected " - "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct); - - for (i = 0; zc0301_sensor_table[i]; i++) { - err = zc0301_sensor_table[i](cam); - if (!err) - break; - } - - if (!err) - DBG(2, "%s image sensor detected", cam->sensor.name); - else { - DBG(1, "No supported image sensor detected"); - err = -ENODEV; - goto fail; - } - - if (zc0301_init(cam)) { - DBG(1, "Initialization failed. I will retry on open()."); - cam->state |= DEV_MISCONFIGURED; - } - - strcpy(cam->v4ldev->name, "ZC0301 PC Camera"); - cam->v4ldev->owner = THIS_MODULE; - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; - cam->v4ldev->hardware = 0; - cam->v4ldev->fops = &zc0301_fops; - cam->v4ldev->minor = video_nr[dev_nr]; - cam->v4ldev->release = video_device_release; - video_set_drvdata(cam->v4ldev, cam); - - mutex_lock(&cam->dev_mutex); - - err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER, - video_nr[dev_nr]); - if (err) { - DBG(1, "V4L2 device registration failed"); - if (err == -ENFILE && video_nr[dev_nr] == -1) - DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); - goto fail; - } - - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); - - cam->module_param.force_munmap = force_munmap[dev_nr]; - cam->module_param.frame_timeout = frame_timeout[dev_nr]; - - dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0; - - usb_set_intfdata(intf, cam); - - mutex_unlock(&cam->dev_mutex); - - return 0; - -fail: - if (cam) { - kfree(cam->control_buffer); - if (cam->v4ldev) - video_device_release(cam->v4ldev); - kfree(cam); - } - return err; -} - - -static void zc0301_usb_disconnect(struct usb_interface* intf) -{ - struct zc0301_device* cam = usb_get_intfdata(intf); - - if (!cam) - return; - - down_write(&zc0301_disconnect); - - mutex_lock(&cam->dev_mutex); - - DBG(2, "Disconnecting %s...", cam->v4ldev->name); - - wake_up_interruptible_all(&cam->open); - - if (cam->users) { - DBG(2, "Device /dev/video%d is open! Deregistration and " - "memory deallocation are deferred on close.", - cam->v4ldev->minor); - cam->state |= DEV_MISCONFIGURED; - zc0301_stop_transfer(cam); - cam->state |= DEV_DISCONNECTED; - wake_up_interruptible(&cam->wait_frame); - wake_up(&cam->wait_stream); - usb_get_dev(cam->usbdev); - } else { - cam->state |= DEV_DISCONNECTED; - zc0301_release_resources(cam); - } - - mutex_unlock(&cam->dev_mutex); - - if (!cam->users) - kfree(cam); - - up_write(&zc0301_disconnect); -} - - -static struct usb_driver zc0301_usb_driver = { - .name = "zc0301", - .id_table = zc0301_id_table, - .probe = zc0301_usb_probe, - .disconnect = zc0301_usb_disconnect, -}; - -/*****************************************************************************/ - -static int __init zc0301_module_init(void) -{ - int err = 0; - - KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION); - KDBG(3, ZC0301_MODULE_AUTHOR); - - if ((err = usb_register(&zc0301_usb_driver))) - KDBG(1, "usb_register() failed"); - - return err; -} - - -static void __exit zc0301_module_exit(void) -{ - usb_deregister(&zc0301_usb_driver); -} - - -module_init(zc0301_module_init); -module_exit(zc0301_module_exit); diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c deleted file mode 100644 index 9d282a22c15f..000000000000 --- a/drivers/usb/media/zc0301_pas202bcb.c +++ /dev/null @@ -1,361 +0,0 @@ -/*************************************************************************** - * Plug-in for PAS202BCB image sensor connected to the ZC030! Image * - * Processor and Control Chip * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * Initialization values of the ZC0301 have been taken from the SPCA5XX * - * driver maintained by Michel Xhaard * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -/* - NOTE: Sensor controls are disabled for now, becouse changing them while - streaming sometimes results in out-of-sync video frames. We'll use - the default initialization, until we know how to stop and start video - in the chip. However, the image quality still looks good under various - light conditions. -*/ - -#include -#include "zc0301_sensor.h" - - -static struct zc0301_sensor pas202bcb; - - -static int pas202bcb_init(struct zc0301_device* cam) -{ - int err = 0; - - err += zc0301_write_reg(cam, 0x0002, 0x00); - err += zc0301_write_reg(cam, 0x0003, 0x02); - err += zc0301_write_reg(cam, 0x0004, 0x80); - err += zc0301_write_reg(cam, 0x0005, 0x01); - err += zc0301_write_reg(cam, 0x0006, 0xE0); - err += zc0301_write_reg(cam, 0x0098, 0x00); - err += zc0301_write_reg(cam, 0x009A, 0x03); - err += zc0301_write_reg(cam, 0x011A, 0x00); - err += zc0301_write_reg(cam, 0x011C, 0x03); - err += zc0301_write_reg(cam, 0x009B, 0x01); - err += zc0301_write_reg(cam, 0x009C, 0xE6); - err += zc0301_write_reg(cam, 0x009D, 0x02); - err += zc0301_write_reg(cam, 0x009E, 0x86); - - err += zc0301_i2c_write(cam, 0x02, 0x02); - err += zc0301_i2c_write(cam, 0x0A, 0x01); - err += zc0301_i2c_write(cam, 0x0B, 0x01); - err += zc0301_i2c_write(cam, 0x0D, 0x00); - err += zc0301_i2c_write(cam, 0x12, 0x05); - err += zc0301_i2c_write(cam, 0x13, 0x63); - err += zc0301_i2c_write(cam, 0x15, 0x70); - - err += zc0301_write_reg(cam, 0x0101, 0xB7); - err += zc0301_write_reg(cam, 0x0100, 0x0D); - err += zc0301_write_reg(cam, 0x0189, 0x06); - err += zc0301_write_reg(cam, 0x01AD, 0x00); - err += zc0301_write_reg(cam, 0x01C5, 0x03); - err += zc0301_write_reg(cam, 0x01CB, 0x13); - err += zc0301_write_reg(cam, 0x0250, 0x08); - err += zc0301_write_reg(cam, 0x0301, 0x08); - err += zc0301_write_reg(cam, 0x018D, 0x70); - err += zc0301_write_reg(cam, 0x0008, 0x03); - err += zc0301_write_reg(cam, 0x01C6, 0x04); - err += zc0301_write_reg(cam, 0x01CB, 0x07); - err += zc0301_write_reg(cam, 0x0120, 0x11); - err += zc0301_write_reg(cam, 0x0121, 0x37); - err += zc0301_write_reg(cam, 0x0122, 0x58); - err += zc0301_write_reg(cam, 0x0123, 0x79); - err += zc0301_write_reg(cam, 0x0124, 0x91); - err += zc0301_write_reg(cam, 0x0125, 0xA6); - err += zc0301_write_reg(cam, 0x0126, 0xB8); - err += zc0301_write_reg(cam, 0x0127, 0xC7); - err += zc0301_write_reg(cam, 0x0128, 0xD3); - err += zc0301_write_reg(cam, 0x0129, 0xDE); - err += zc0301_write_reg(cam, 0x012A, 0xE6); - err += zc0301_write_reg(cam, 0x012B, 0xED); - err += zc0301_write_reg(cam, 0x012C, 0xF3); - err += zc0301_write_reg(cam, 0x012D, 0xF8); - err += zc0301_write_reg(cam, 0x012E, 0xFB); - err += zc0301_write_reg(cam, 0x012F, 0xFF); - err += zc0301_write_reg(cam, 0x0130, 0x26); - err += zc0301_write_reg(cam, 0x0131, 0x23); - err += zc0301_write_reg(cam, 0x0132, 0x20); - err += zc0301_write_reg(cam, 0x0133, 0x1C); - err += zc0301_write_reg(cam, 0x0134, 0x16); - err += zc0301_write_reg(cam, 0x0135, 0x13); - err += zc0301_write_reg(cam, 0x0136, 0x10); - err += zc0301_write_reg(cam, 0x0137, 0x0D); - err += zc0301_write_reg(cam, 0x0138, 0x0B); - err += zc0301_write_reg(cam, 0x0139, 0x09); - err += zc0301_write_reg(cam, 0x013A, 0x07); - err += zc0301_write_reg(cam, 0x013B, 0x06); - err += zc0301_write_reg(cam, 0x013C, 0x05); - err += zc0301_write_reg(cam, 0x013D, 0x04); - err += zc0301_write_reg(cam, 0x013E, 0x03); - err += zc0301_write_reg(cam, 0x013F, 0x02); - err += zc0301_write_reg(cam, 0x010A, 0x4C); - err += zc0301_write_reg(cam, 0x010B, 0xF5); - err += zc0301_write_reg(cam, 0x010C, 0xFF); - err += zc0301_write_reg(cam, 0x010D, 0xF9); - err += zc0301_write_reg(cam, 0x010E, 0x51); - err += zc0301_write_reg(cam, 0x010F, 0xF5); - err += zc0301_write_reg(cam, 0x0110, 0xFB); - err += zc0301_write_reg(cam, 0x0111, 0xED); - err += zc0301_write_reg(cam, 0x0112, 0x5F); - err += zc0301_write_reg(cam, 0x0180, 0x00); - err += zc0301_write_reg(cam, 0x0019, 0x00); - err += zc0301_write_reg(cam, 0x0087, 0x20); - err += zc0301_write_reg(cam, 0x0088, 0x21); - - err += zc0301_i2c_write(cam, 0x20, 0x02); - err += zc0301_i2c_write(cam, 0x21, 0x1B); - err += zc0301_i2c_write(cam, 0x03, 0x44); - err += zc0301_i2c_write(cam, 0x0E, 0x01); - err += zc0301_i2c_write(cam, 0x0F, 0x00); - - err += zc0301_write_reg(cam, 0x01A9, 0x14); - err += zc0301_write_reg(cam, 0x01AA, 0x24); - err += zc0301_write_reg(cam, 0x0190, 0x00); - err += zc0301_write_reg(cam, 0x0191, 0x02); - err += zc0301_write_reg(cam, 0x0192, 0x1B); - err += zc0301_write_reg(cam, 0x0195, 0x00); - err += zc0301_write_reg(cam, 0x0196, 0x00); - err += zc0301_write_reg(cam, 0x0197, 0x4D); - err += zc0301_write_reg(cam, 0x018C, 0x10); - err += zc0301_write_reg(cam, 0x018F, 0x20); - err += zc0301_write_reg(cam, 0x001D, 0x44); - err += zc0301_write_reg(cam, 0x001E, 0x6F); - err += zc0301_write_reg(cam, 0x001F, 0xAD); - err += zc0301_write_reg(cam, 0x0020, 0xEB); - err += zc0301_write_reg(cam, 0x0087, 0x0F); - err += zc0301_write_reg(cam, 0x0088, 0x0E); - err += zc0301_write_reg(cam, 0x0180, 0x40); - err += zc0301_write_reg(cam, 0x0192, 0x1B); - err += zc0301_write_reg(cam, 0x0191, 0x02); - err += zc0301_write_reg(cam, 0x0190, 0x00); - err += zc0301_write_reg(cam, 0x0116, 0x1D); - err += zc0301_write_reg(cam, 0x0117, 0x40); - err += zc0301_write_reg(cam, 0x0118, 0x99); - err += zc0301_write_reg(cam, 0x0180, 0x42); - err += zc0301_write_reg(cam, 0x0116, 0x1D); - err += zc0301_write_reg(cam, 0x0117, 0x40); - err += zc0301_write_reg(cam, 0x0118, 0x99); - err += zc0301_write_reg(cam, 0x0007, 0x00); - - err += zc0301_i2c_write(cam, 0x11, 0x01); - - msleep(100); - - return err; -} - - -static int pas202bcb_get_ctrl(struct zc0301_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - { - int r1 = zc0301_i2c_read(cam, 0x04, 1), - r2 = zc0301_i2c_read(cam, 0x05, 1); - if (r1 < 0 || r2 < 0) - return -EIO; - ctrl->value = (r1 << 6) | (r2 & 0x3f); - } - return 0; - case V4L2_CID_RED_BALANCE: - if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case V4L2_CID_GAIN: - if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0) - return -EIO; - ctrl->value &= 0x1f; - return 0; - case ZC0301_V4L2_CID_GREEN_BALANCE: - if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0) - return -EIO; - ctrl->value &= 0x0f; - return 0; - case ZC0301_V4L2_CID_DAC_MAGNITUDE: - if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0) - return -EIO; - return 0; - default: - return -EINVAL; - } -} - - -static int pas202bcb_set_ctrl(struct zc0301_device* cam, - const struct v4l2_control* ctrl) -{ - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE: - err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6); - err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f); - break; - case V4L2_CID_RED_BALANCE: - err += zc0301_i2c_write(cam, 0x09, ctrl->value); - break; - case V4L2_CID_BLUE_BALANCE: - err += zc0301_i2c_write(cam, 0x07, ctrl->value); - break; - case V4L2_CID_GAIN: - err += zc0301_i2c_write(cam, 0x10, ctrl->value); - break; - case ZC0301_V4L2_CID_GREEN_BALANCE: - err += zc0301_i2c_write(cam, 0x08, ctrl->value); - break; - case ZC0301_V4L2_CID_DAC_MAGNITUDE: - err += zc0301_i2c_write(cam, 0x0c, ctrl->value); - break; - default: - return -EINVAL; - } - err += zc0301_i2c_write(cam, 0x11, 0x01); - - return err ? -EIO : 0; -} - - -static struct zc0301_sensor pas202bcb = { - .name = "PAS202BCB", - .init = &pas202bcb_init, - .qctrl = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x01e5, - .maximum = 0x3fff, - .step = 0x0001, - .default_value = 0x01e5, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "global gain", - .minimum = 0x00, - .maximum = 0x1f, - .step = 0x01, - .default_value = 0x0c, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = ZC0301_V4L2_CID_DAC_MAGNITUDE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "DAC magnitude", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = 0x00, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x01, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x05, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = ZC0301_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x0f, - .step = 0x01, - .default_value = 0x00, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - }, - .get_ctrl = &pas202bcb_get_ctrl, - .set_ctrl = &pas202bcb_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_JPEG, - .priv = 8, - }, -}; - - -int zc0301_probe_pas202bcb(struct zc0301_device* cam) -{ - int r0 = 0, r1 = 0, err = 0; - unsigned int pid = 0; - - err += zc0301_write_reg(cam, 0x0000, 0x01); - err += zc0301_write_reg(cam, 0x0010, 0x0e); - err += zc0301_write_reg(cam, 0x0001, 0x01); - err += zc0301_write_reg(cam, 0x0012, 0x03); - err += zc0301_write_reg(cam, 0x0012, 0x01); - err += zc0301_write_reg(cam, 0x008d, 0x08); - - msleep(10); - - r0 = zc0301_i2c_read(cam, 0x00, 1); - r1 = zc0301_i2c_read(cam, 0x01, 1); - - if (r0 < 0 || r1 < 0 || err) - return -EIO; - - pid = (r0 << 4) | ((r1 & 0xf0) >> 4); - if (pid != 0x017) - return -ENODEV; - - zc0301_attach_sensor(cam, &pas202bcb); - - return 0; -} diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h deleted file mode 100644 index cf0965a81d01..000000000000 --- a/drivers/usb/media/zc0301_sensor.h +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************** - * API for image sensors connected to the ZC030! Image Processor and * - * Control Chip * - * * - * Copyright (C) 2006 by Luca Risolia * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - ***************************************************************************/ - -#ifndef _ZC0301_SENSOR_H_ -#define _ZC0301_SENSOR_H_ - -#include -#include -#include -#include -#include -#include - -struct zc0301_device; -struct zc0301_sensor; - -/*****************************************************************************/ - -extern int zc0301_probe_pas202bcb(struct zc0301_device* cam); - -#define ZC0301_SENSOR_TABLE \ -/* Weak detections must go at the end of the list */ \ -static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \ - &zc0301_probe_pas202bcb, \ - NULL, \ -}; - -extern struct zc0301_device* -zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id); - -extern void -zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor); - -#define ZC0301_USB_DEVICE(vend, prod, intclass) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_INT_CLASS, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bInterfaceClass = (intclass) - -#define ZC0301_ID_TABLE \ -static const struct usb_device_id zc0301_id_table[] = { \ - { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, \ - { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */ \ - { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \ - { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ - { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \ - { } \ -}; - -/*****************************************************************************/ - -extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value); -extern int zc0301_read_reg(struct zc0301_device*, u16 index); -extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value); -extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length); - -/*****************************************************************************/ - -#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 -#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE -#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 - -struct zc0301_sensor { - char name[32]; - - struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS]; - struct v4l2_cropcap cropcap; - struct v4l2_pix_format pix_format; - - int (*init)(struct zc0301_device*); - int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl); - int (*set_ctrl)(struct zc0301_device*, - const struct v4l2_control* ctrl); - int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect); - - /* Private */ - struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS]; - struct v4l2_rect _rect; -}; - -#endif /* _ZC0301_SENSOR_H_ */ -- cgit v1.2.2 From 0073602544954002e35699477dc59cdd5e9112e3 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 24 Mar 2006 16:45:24 -0800 Subject: [PATCH] zd1201 wireless stat update The "dev->get_wireless_stats" field is deprecated and slowly be surely going away. Most drivers have been updated months ago. Actually, there is an annoying message for driver still using it, but it seems that user of zd1201 were not annoyed enough ;-) Signed-off-by: Jean Tourrilhes Signed-off-by: John W. Linville --- drivers/usb/net/zd1201.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index fe9b60cd8d95..9b1e4ed1d07e 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -1736,6 +1736,7 @@ static const struct iw_handler_def zd1201_iw_handlers = { .standard = (iw_handler *)zd1201_iw_handler, .private = (iw_handler *)zd1201_private_handler, .private_args = (struct iw_priv_args *) zd1201_private_args, + .get_wireless_stats = zd1201_get_wireless_stats, }; static int zd1201_probe(struct usb_interface *interface, @@ -1796,7 +1797,6 @@ static int zd1201_probe(struct usb_interface *interface, zd->dev->open = zd1201_net_open; zd->dev->stop = zd1201_net_stop; zd->dev->get_stats = zd1201_get_stats; - zd->dev->get_wireless_stats = zd1201_get_wireless_stats; zd->dev->wireless_handlers = (struct iw_handler_def *)&zd1201_iw_handlers; zd->dev->hard_start_xmit = zd1201_hard_start_xmit; -- cgit v1.2.2 From e041c683412d5bf44dc2b109053e3b837b71742d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 27 Mar 2006 01:16:30 -0800 Subject: [PATCH] Notifier chain update: API changes The kernel's implementation of notifier chains is unsafe. There is no protection against entries being added to or removed from a chain while the chain is in use. The issues were discussed in this thread: http://marc.theaimsgroup.com/?l=linux-kernel&m=113018709002036&w=2 We noticed that notifier chains in the kernel fall into two basic usage classes: "Blocking" chains are always called from a process context and the callout routines are allowed to sleep; "Atomic" chains can be called from an atomic context and the callout routines are not allowed to sleep. We decided to codify this distinction and make it part of the API. Therefore this set of patches introduces three new, parallel APIs: one for blocking notifiers, one for atomic notifiers, and one for "raw" notifiers (which is really just the old API under a new name). New kinds of data structures are used for the heads of the chains, and new routines are defined for registration, unregistration, and calling a chain. The three APIs are explained in include/linux/notifier.h and their implementation is in kernel/sys.c. With atomic and blocking chains, the implementation guarantees that the chain links will not be corrupted and that chain callers will not get messed up by entries being added or removed. For raw chains the implementation provides no guarantees at all; users of this API must provide their own protections. (The idea was that situations may come up where the assumptions of the atomic and blocking APIs are not appropriate, so it should be possible for users to handle these things in their own way.) There are some limitations, which should not be too hard to live with. For atomic/blocking chains, registration and unregistration must always be done in a process context since the chain is protected by a mutex/rwsem. Also, a callout routine for a non-raw chain must not try to register or unregister entries on its own chain. (This did happen in a couple of places and the code had to be changed to avoid it.) Since atomic chains may be called from within an NMI handler, they cannot use spinlocks for synchronization. Instead we use RCU. The overhead falls almost entirely in the unregister routine, which is okay since unregistration is much less frequent that calling a chain. Here is the list of chains that we adjusted and their classifications. None of them use the raw API, so for the moment it is only a placeholder. ATOMIC CHAINS ------------- arch/i386/kernel/traps.c: i386die_chain arch/ia64/kernel/traps.c: ia64die_chain arch/powerpc/kernel/traps.c: powerpc_die_chain arch/sparc64/kernel/traps.c: sparc64die_chain arch/x86_64/kernel/traps.c: die_chain drivers/char/ipmi/ipmi_si_intf.c: xaction_notifier_list kernel/panic.c: panic_notifier_list kernel/profile.c: task_free_notifier net/bluetooth/hci_core.c: hci_notifier net/ipv4/netfilter/ip_conntrack_core.c: ip_conntrack_chain net/ipv4/netfilter/ip_conntrack_core.c: ip_conntrack_expect_chain net/ipv6/addrconf.c: inet6addr_chain net/netfilter/nf_conntrack_core.c: nf_conntrack_chain net/netfilter/nf_conntrack_core.c: nf_conntrack_expect_chain net/netlink/af_netlink.c: netlink_chain BLOCKING CHAINS --------------- arch/powerpc/platforms/pseries/reconfig.c: pSeries_reconfig_chain arch/s390/kernel/process.c: idle_chain arch/x86_64/kernel/process.c idle_notifier drivers/base/memory.c: memory_chain drivers/cpufreq/cpufreq.c cpufreq_policy_notifier_list drivers/cpufreq/cpufreq.c cpufreq_transition_notifier_list drivers/macintosh/adb.c: adb_client_list drivers/macintosh/via-pmu.c sleep_notifier_list drivers/macintosh/via-pmu68k.c sleep_notifier_list drivers/macintosh/windfarm_core.c wf_client_list drivers/usb/core/notify.c usb_notifier_list drivers/video/fbmem.c fb_notifier_list kernel/cpu.c cpu_chain kernel/module.c module_notify_list kernel/profile.c munmap_notifier kernel/profile.c task_exit_notifier kernel/sys.c reboot_notifier_list net/core/dev.c netdev_chain net/decnet/dn_dev.c: dnaddr_chain net/ipv4/devinet.c: inetaddr_chain It's possible that some of these classifications are wrong. If they are, please let us know or submit a patch to fix them. Note that any chain that gets called very frequently should be atomic, because the rwsem read-locking used for blocking chains is very likely to incur cache misses on SMP systems. (However, if the chain's callout routines may sleep then the chain cannot be atomic.) The patch set was written by Alan Stern and Chandra Seetharaman, incorporating material written by Keith Owens and suggestions from Paul McKenney and Andrew Morton. [jes@sgi.com: restructure the notifier chain initialization macros] Signed-off-by: Alan Stern Signed-off-by: Chandra Seetharaman Signed-off-by: Jes Sorensen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/core/notify.c | 65 ++++++----------------------------------------- 1 file changed, 8 insertions(+), 57 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c index 4b55285de9a0..fe0ed54fa0ae 100644 --- a/drivers/usb/core/notify.c +++ b/drivers/usb/core/notify.c @@ -16,57 +16,7 @@ #include #include "usb.h" - -static struct notifier_block *usb_notifier_list; -static DEFINE_MUTEX(usb_notifier_lock); - -static void usb_notifier_chain_register(struct notifier_block **list, - struct notifier_block *n) -{ - mutex_lock(&usb_notifier_lock); - while (*list) { - if (n->priority > (*list)->priority) - break; - list = &((*list)->next); - } - n->next = *list; - *list = n; - mutex_unlock(&usb_notifier_lock); -} - -static void usb_notifier_chain_unregister(struct notifier_block **nl, - struct notifier_block *n) -{ - mutex_lock(&usb_notifier_lock); - while ((*nl)!=NULL) { - if ((*nl)==n) { - *nl = n->next; - goto exit; - } - nl=&((*nl)->next); - } -exit: - mutex_unlock(&usb_notifier_lock); -} - -static int usb_notifier_call_chain(struct notifier_block **n, - unsigned long val, void *v) -{ - int ret=NOTIFY_DONE; - struct notifier_block *nb = *n; - - mutex_lock(&usb_notifier_lock); - while (nb) { - ret = nb->notifier_call(nb,val,v); - if (ret&NOTIFY_STOP_MASK) { - goto exit; - } - nb = nb->next; - } -exit: - mutex_unlock(&usb_notifier_lock); - return ret; -} +static BLOCKING_NOTIFIER_HEAD(usb_notifier_list); /** * usb_register_notify - register a notifier callback whenever a usb change happens @@ -76,7 +26,7 @@ exit: */ void usb_register_notify(struct notifier_block *nb) { - usb_notifier_chain_register(&usb_notifier_list, nb); + blocking_notifier_chain_register(&usb_notifier_list, nb); } EXPORT_SYMBOL_GPL(usb_register_notify); @@ -89,27 +39,28 @@ EXPORT_SYMBOL_GPL(usb_register_notify); */ void usb_unregister_notify(struct notifier_block *nb) { - usb_notifier_chain_unregister(&usb_notifier_list, nb); + blocking_notifier_chain_unregister(&usb_notifier_list, nb); } EXPORT_SYMBOL_GPL(usb_unregister_notify); void usb_notify_add_device(struct usb_device *udev) { - usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); + blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); } void usb_notify_remove_device(struct usb_device *udev) { - usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev); + blocking_notifier_call_chain(&usb_notifier_list, + USB_DEVICE_REMOVE, udev); } void usb_notify_add_bus(struct usb_bus *ubus) { - usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); + blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); } void usb_notify_remove_bus(struct usb_bus *ubus) { - usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); + blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); } -- cgit v1.2.2 From e8222502ee6157e2713da9e0792c21f4ad458d50 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 28 Mar 2006 23:15:54 +1100 Subject: [PATCH] powerpc: Kill _machine and hard-coded platform numbers This removes statically assigned platform numbers and reworks the powerpc platform probe code to use a better mechanism. With this, board support files can simply declare a new machine type with a macro, and implement a probe() function that uses the flattened device-tree to detect if they apply for a given machine. We now have a machine_is() macro that replaces the comparisons of _machine with the various PLATFORM_* constants. This commit also changes various drivers to use the new macro instead of looking at _machine. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/usb/core/hcd-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index e0afb5ad29e5..0d2193b69235 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -296,7 +296,7 @@ done: #ifdef CONFIG_PPC_PMAC /* Disable ASIC clocks for USB */ - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { struct device_node *of_node; of_node = pci_device_to_OF_node (dev); @@ -331,7 +331,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) #ifdef CONFIG_PPC_PMAC /* Reenable ASIC clocks for USB */ - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { struct device_node *of_node; of_node = pci_device_to_OF_node (dev); -- cgit v1.2.2 From 99ac48f54a91d02140c497edc31dc57d4bc5c85d Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Tue, 28 Mar 2006 01:56:41 -0800 Subject: [PATCH] mark f_ops const in the inode Mark the f_ops members of inodes as const, as well as fix the ripple-through this causes by places that copy this f_ops and then "do stuff" with it. Signed-off-by: Arjan van de Ven Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/core/file.c | 6 +++--- drivers/usb/gadget/inode.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 37b13368c814..b263a54a13c0 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -24,15 +24,15 @@ #include "usb.h" #define MAX_USB_MINORS 256 -static struct file_operations *usb_minors[MAX_USB_MINORS]; +static const struct file_operations *usb_minors[MAX_USB_MINORS]; static DEFINE_SPINLOCK(minor_lock); static int usb_open(struct inode * inode, struct file * file) { int minor = iminor(inode); - struct file_operations *c; + const struct file_operations *c; int err = -ENODEV; - struct file_operations *old_fops, *new_fops = NULL; + const struct file_operations *old_fops, *new_fops = NULL; spin_lock (&minor_lock); c = usb_minors[minor]; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index b44cfda76b61..3f618ce6998d 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1581,7 +1581,7 @@ restart: static struct inode * gadgetfs_create_file (struct super_block *sb, char const *name, - void *data, struct file_operations *fops, + void *data, const struct file_operations *fops, struct dentry **dentry_p); static int activate_ep_files (struct dev_data *dev) @@ -1955,7 +1955,7 @@ module_param (default_perm, uint, 0644); static struct inode * gadgetfs_make_inode (struct super_block *sb, - void *data, struct file_operations *fops, + void *data, const struct file_operations *fops, int mode) { struct inode *inode = new_inode (sb); @@ -1979,7 +1979,7 @@ gadgetfs_make_inode (struct super_block *sb, */ static struct inode * gadgetfs_create_file (struct super_block *sb, char const *name, - void *data, struct file_operations *fops, + void *data, const struct file_operations *fops, struct dentry **dentry_p) { struct dentry *dentry; -- cgit v1.2.2 From 7f927fcc2fd1575d01efb4b76665975007945690 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 28 Mar 2006 01:56:53 -0800 Subject: [PATCH] Typo fixes Fix a lot of typos. Eyeballed by jmc@ in OpenBSD. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/host/ohci-s3c2410.c | 2 +- drivers/usb/net/zaurus.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 372527a83593..682bf2215660 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -158,7 +158,7 @@ static int ohci_s3c2410_hub_control ( "s3c2410_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", hcd, typeReq, wValue, wIndex, buf, wLength); - /* if we are only an humble host without any special capabilites + /* if we are only an humble host without any special capabilities * process the request straight away and exit */ if (info == NULL) { diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c index 9c5ab251370c..f7ac9d6b9856 100644 --- a/drivers/usb/net/zaurus.c +++ b/drivers/usb/net/zaurus.c @@ -217,7 +217,7 @@ static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf) * with devices that use it and those that don't. */ if ((detail->bDetailData[1] & ~0x02) != 0x01) { - /* bmDataCapabilites == 0 would be fine too, + /* bmDataCapabilities == 0 would be fine too, * but framing is minidriver-coupled for now. */ bad_detail: -- cgit v1.2.2