mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
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:
parent
7fa033b103
commit
9f6933be66
64 changed files with 281 additions and 283 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
|
@ -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
|
||||
|
|
@ -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");
|
||||
|
|
@ -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
|
|
@ -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_ */
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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, },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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},
|
||||
},
|
||||
|
|
@ -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, },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
||||
};
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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_ */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
Loading…
Reference in a new issue