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 <[email protected]>
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
This commit is contained in:
Mauro Carvalho Chehab 2006-03-25 09:05:39 -03:00
commit 9f6933be66
64 changed files with 281 additions and 283 deletions

View file

@ -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"

View file

@ -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/

View file

@ -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
<http://wwwbode.cs.tum.edu/Par/arch/dab/>. This driver can be taken
as an example for URB-based bulk, control, and isochronous
transactions. URB's are explained in
<file:Documentation/usb/URB.txt>.
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 <file:Documentation/video4linux/API.html>.
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
<file:Documentation/video4linux/API.html>.
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 <file:Documentation/usb/et61x251.txt> 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 <file:Documentation/usb/ibmcam.txt>.
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
<file:Documentation/video4linux/API.html>.
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
<file:Documentation/usb/ibmcam.txt> 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
<file:Documentation/video4linux/API.html>.
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 <file:Documentation/usb/ov511.txt> 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 <file:Documentation/video4linux/API.html>.
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 <file:Documentation/usb/se401.txt> 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 <file:Documentation/video4linux/API.html>.
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 <file:Documentation/usb/sn9c102.txt> 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 <file:Documentation/usb/stv680.txt> 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 <file:Documentation/video4linux/API.html>.
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 <file:Documentation/usb/w9968cf.txt> 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 <file:Documentation/usb/zc0301.txt> 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 <file:Documentation/usb/philips.txt> 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 <file:Documentation/video4linux/API.html>.
To compile this driver as a module, choose M here: the
module will be called pwc.

View file

@ -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/

File diff suppressed because it is too large Load diff

View file

@ -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 <linux/module.h>
#include <linux/socket.h>
#include <linux/list.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include "dabusb.h"
#include "dabfirmware.h"
/*
* Version Information
*/
#define DRIVER_VERSION "v1.54"
#define DRIVER_AUTHOR "Deti Fliegl, [email protected]"
#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);
/* --------------------------------------------------------------------- */

View file

@ -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

View file

@ -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 <msdemlei@cl.uni-heidelberg.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., 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 <bradh@dynamite.com.au>: Fixes to make it work as non-module
Markus: Copyright clarification
Version 0.01: Markus: initial release
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/videodev.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v0.40"
#define DRIVER_AUTHOR "Markus Demleitner <[email protected]>"
#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");

View file

@ -1,234 +0,0 @@
/***************************************************************************
* V4L2 driver for ET61X[12]51 PC Camera Controllers *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _ET61X251_H_
#define _ET61X251_H_
#include <linux/version.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/param.h>
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <linux/stddef.h>
#include <linux/string.h>
#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_ */

File diff suppressed because it is too large Load diff

View file

@ -1,116 +0,0 @@
/***************************************************************************
* API for image sensors connected to ET61X[12]51 PC Camera Controllers *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _ET61X251_SENSOR_H_
#define _ET61X251_SENSOR_H_
#include <linux/usb.h>
#include <linux/videodev.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
#include <asm/types.h>
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_ */

View file

@ -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 <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include "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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,978 +0,0 @@
/*
* konicawc.c - konica webcam driver
*
* Author: Simon Evans <spse@secret.org.uk>
*
* Copyright (C) 2002 Simon Evans
*
* Licence: GPL
*
* Driver for USB webcams based on Konica chipset. This
* chipset is used in Intel YC76 camera.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/usb_input.h>
#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 <[email protected]>");
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);

File diff suppressed because it is too large Load diff

View file

@ -1,568 +0,0 @@
#ifndef __LINUX_OV511_H
#define __LINUX_OV511_H
#include <asm/uaccess.h>
#include <linux/videodev.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#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

View file

@ -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

View file

@ -1,236 +0,0 @@
This file contains some additional information for the Philips and OEM webcams.
E-mail: [email protected] 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.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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 <luc@saillard.org>.
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

View file

@ -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 <luc@saillard.org>.
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, },
},
},
};

View file

@ -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 <luc@saillard.org>.
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

View file

@ -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 <luc@saillard.org>.
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 <linux/slab.h>
#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;
}

View file

@ -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},
},

View file

@ -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 <luc@saillard.org>.
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, },
},
},
};

View file

@ -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 <luc@saillard.org>.
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

View file

@ -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 <luc@saillard.org>.
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 <asm/current.h>
#include <asm/types.h>
#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;
}

View file

@ -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 <luc@saillard.org>.
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 <linux/config.h>
#include "pwc-ioctl.h"
/* from pwc-dec.h */
#define PWCX_FLAG_PLANAR 0x0001
/* */
#endif

View file

@ -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 <luc@saillard.org>.
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 <linux/config.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/spinlock.h>
#include <linux/videodev.h>
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <asm/semaphore.h>
#include <asm/errno.h>
#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

File diff suppressed because it is too large Load diff

View file

@ -1,234 +0,0 @@
#ifndef __LINUX_se401_H
#define __LINUX_se401_H
#include <asm/uaccess.h>
#include <linux/videodev.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#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

View file

@ -1,218 +0,0 @@
/***************************************************************************
* V4L2 driver for SN9C10x PC Camera Controllers *
* *
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _SN9C102_H_
#define _SN9C102_H_
#include <linux/version.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/param.h>
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/stddef.h>
#include "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_ */

File diff suppressed because it is too large Load diff

View file

@ -1,271 +0,0 @@
/***************************************************************************
* Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#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 <[email protected]>",
.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;
}

View file

@ -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 <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include "sn9c102_sensor.h"
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 <[email protected]>",
.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;
}

View file

@ -1,401 +0,0 @@
/***************************************************************************
* Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#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 <[email protected]>",
.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;
}

View file

@ -1,307 +0,0 @@
/***************************************************************************
* Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include <linux/delay.h>
#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 <[email protected]>",
.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;
}

View file

@ -1,238 +0,0 @@
/***************************************************************************
* Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include <linux/delay.h>
#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 <[email protected]>",
.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;
}

View file

@ -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 *
* <medaglia@undl.org.br> *
* http://cadu.homelinux.com:8080/ *
* *
* DAC Magnitude, exposure and green gain controls added by *
* Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include <linux/delay.h>
#include "sn9c102_sensor.h"
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 "
"<[email protected]>",
.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;
}

View file

@ -1,389 +0,0 @@
/***************************************************************************
* API for image sensors connected to the SN9C10x PC Camera Controllers *
* *
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _SN9C102_SENSOR_H_
#define _SN9C102_SENSOR_H_
#include <linux/usb.h>
#include <linux/videodev.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
#include <asm/types.h>
struct sn9c102_device;
struct sn9c102_sensor;
/*****************************************************************************/
/*
OVERVIEW.
This is a small interface that allows you to add support for any CCD/CMOS
image sensors connected to the 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 <email> */
/* 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_ */

View file

@ -1,159 +0,0 @@
/***************************************************************************
* Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#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 <[email protected]>",
.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;
}

View file

@ -1,169 +0,0 @@
/***************************************************************************
* Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#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 <[email protected]>",
.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;
}

File diff suppressed because it is too large Load diff

View file

@ -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
};

View file

@ -1,679 +0,0 @@
/*
* USB NB Camera driver
*
* HISTORY:
* 25-Dec-2002 Dmitri Removed lighting, sharpness parameters, methods.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/init.h>
#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);

File diff suppressed because it is too large Load diff

View file

@ -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 <linux/config.h>
#include <linux/videodev.h>
#include <linux/usb.h>
#include <linux/mutex.h>
/* 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 */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,330 +0,0 @@
/***************************************************************************
* Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. *
* *
* Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _W9968CF_H_
#define _W9968CF_H_
#include <linux/videodev.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/config.h>
#include <linux/param.h>
#include <linux/types.h>
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <media/ovcamchip.h>
#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 "<[email protected]>"
#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_ */

View file

@ -1,86 +0,0 @@
/***************************************************************************
* Video decoder for the W996[87]CF driver for Linux. *
* *
* Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _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_ */

View file

@ -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 <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _W9968CF_VPP_H_
#define _W9968CF_VPP_H_
#include <linux/module.h>
#include <asm/types.h>
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_ */

View file

@ -1,192 +0,0 @@
/***************************************************************************
* V4L2 driver for ZC0301 Image Processor and Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _ZC0301_H_
#define _ZC0301_H_
#include <linux/version.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/param.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/stddef.h>
#include <linux/string.h>
#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_ */

File diff suppressed because it is too large Load diff

View file

@ -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 <luca.risolia@studio.unibo.it> *
* *
* Initialization values of the ZC0301 have been taken from the SPCA5XX *
* driver maintained by Michel Xhaard <mxhaard@magic.fr> *
* *
* 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 <linux/delay.h>
#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;
}

View file

@ -1,103 +0,0 @@
/***************************************************************************
* API for image sensors connected to the ZC030! Image Processor and *
* Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _ZC0301_SENSOR_H_
#define _ZC0301_SENSOR_H_
#include <linux/usb.h>
#include <linux/videodev.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
#include <asm/types.h>
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_ */