Commit 7cf654b1 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

patch by Simon Evans <spse@secret.org.uk> that adds a Konica USB webcam driver

parent 1a3cb06f
...@@ -505,6 +505,21 @@ CONFIG_USB_DABUSB ...@@ -505,6 +505,21 @@ CONFIG_USB_DABUSB
The module will be called dabusb.o. If you want to compile it as a The module will be called dabusb.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>. module, say M here and read <file:Documentation/modules.txt>.
CONFIG_USB_KONICAWC
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 on the WWW at
<http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called konicawc.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
CONFIG_USB_USBNET CONFIG_USB_USBNET
This driver supports network links over USB with USB "Network" This driver supports network links over USB with USB "Network"
or "data transfer" cables, often used to network laptops to PCs. or "data transfer" cables, often used to network laptops to PCs.
......
...@@ -80,6 +80,7 @@ else ...@@ -80,6 +80,7 @@ else
dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
dep_tristate ' USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
fi fi
comment 'USB Network adaptors' comment 'USB Network adaptors'
......
...@@ -64,6 +64,7 @@ obj-$(CONFIG_USB_ACM) += acm.o ...@@ -64,6 +64,7 @@ obj-$(CONFIG_USB_ACM) += acm.o
obj-$(CONFIG_USB_PRINTER) += printer.o obj-$(CONFIG_USB_PRINTER) += printer.o
obj-$(CONFIG_USB_AUDIO) += audio.o obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o
obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o
obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_PWC) += pwc.o
obj-$(CONFIG_USB_DC2XX) += dc2xx.o obj-$(CONFIG_USB_DC2XX) += dc2xx.o
obj-$(CONFIG_USB_MDC800) += mdc800.o obj-$(CONFIG_USB_MDC800) += mdc800.o
......
/*
* $Id: konicawc.c,v 1.12 2002/02/07 23:18:53 spse Exp $
*
* 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>
#define DEBUG
#include "usbvideo.h"
#define MAX_BRIGHTNESS 108
#define MAX_CONTRAST 108
#define MAX_SATURATION 108
#define MAX_SHARPNESS 108
#define MAX_WHITEBAL 363
#define MAX_CAMERAS 1
enum ctrl_req {
SetWhitebal = 0x01,
SetBrightness = 0x02,
SetSharpness = 0x03,
SetContrast = 0x04,
SetSaturation = 0x05,
};
enum frame_sizes {
SIZE_160X130 = 0,
SIZE_176X144 = 1,
SIZE_320X240 = 2,
};
static usbvideo_t *cams;
/* Some default values for inital camera settings,
can be set by modprobe */
static int debug;
static enum frame_sizes size;
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);
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 fps; /* Stored as fps * 3 */
u8 size; /* Frame Size */
int height;
int width;
struct urb *sts_urb[USBVIDEO_NUMFRAMES];
u8 sts_buf[USBVIDEO_NUMFRAMES][FRAMES_PER_DESC];
struct urb *last_data_urb;
int lastframe;
};
#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(uvd_t *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, HZ);
return retval < 0 ? retval : 0;
}
static int konicawc_setup_on_open(uvd_t *uvd)
{
struct konicawc *cam = (struct konicawc *)uvd->user_data;
konicawc_set_misc(uvd, 0x2, 0, 0x0b);
dbg("setting brightness to %d (%d)", cam->brightness,
cam->brightness*11);
konicawc_set_value(uvd, cam->brightness, SetBrightness);
dbg("setting white balance to %d (%d)", cam->white_bal,
cam->white_bal*11);
konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
dbg("setting contrast to %d (%d)", cam->contrast,
cam->contrast*11);
konicawc_set_value(uvd, cam->brightness, SetBrightness);
dbg("setting saturation to %d (%d)", cam->saturation,
cam->saturation*11);
konicawc_set_value(uvd, cam->saturation, SetSaturation);
dbg("setting sharpness to %d (%d)", cam->sharpness,
cam->sharpness*11);
konicawc_set_value(uvd, cam->sharpness, SetSharpness);
dbg("setting size %d", cam->size);
switch(cam->size) {
case 0:
konicawc_set_misc(uvd, 0x2, 0xa, 0x08);
break;
case 1:
konicawc_set_misc(uvd, 0x2, 4, 0x08);
break;
case 2:
konicawc_set_misc(uvd, 0x2, 5, 0x08);
break;
}
konicawc_set_misc(uvd, 0x2, 1, 0x0b);
cam->lastframe = -1;
return 0;
}
static int konicawc_compress_iso(uvd_t *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;
static int buttonsts = 0;
for (i = 0; i < dataurb->number_of_packets; i++) {
int button = 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) {
if (debug >= 1)
err("Data error: packet=%d. len=%d. status=%d.",
i, n, st);
uvd->stats.iso_err_count++;
continue;
}
/* Detect and ignore empty packets */
if (n <= 0) {
uvd->stats.iso_skip_count++;
continue;
}
/* 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:drop packet (padding data)
* 1 keep packet
*
* 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 dont do
anything with it for now */
if(button != buttonsts) {
dbg("button: %sclicked", button ? "" : "un");
buttonsts = button;
}
if(sts == 0x01) { /* drop frame */
discard++;
continue;
}
if((sts > 0x01) && (sts < 0x80)) {
info("unknown status %2.2x", sts);
bad++;
continue;
}
keep++;
if(*(status+i) & 0x80) { /* frame start */
unsigned char marker[] = { 0, 0xff, 0, 0x00 };
if(debug > 1)
dbg("Adding Marker packet = %d, frame = %2.2x",
i, *(status+i));
marker[3] = *(status+i) - 0x80;
RingQueue_Enqueue(&uvd->dp, marker, 4);
totlen += 4;
}
totlen += n; /* Little local accounting */
if(debug > 5)
dbg("Adding packet %d, bytes = %d", i, n);
RingQueue_Enqueue(&uvd->dp, cdata, n);
}
if(debug > 8) {
dbg("finished: keep = %d discard = %d bad = %d added %d bytes",
keep, discard, bad, totlen);
}
return totlen;
}
static void konicawc_isoc_irq(struct urb *urb)
{
int i, len = 0;
uvd_t *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 (urb->actual_length > 32) {
cam->last_data_urb = urb;
return;
}
if (!uvd->streaming) {
if (debug >= 1)
info("Not streaming, but interrupt!");
return;
}
uvd->stats.urb_count++;
if (urb->actual_length <= 0)
goto urb_done_with;
/* Copy the data received into ring queue */
if(cam->last_data_urb) {
len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
for (i = 0; i < FRAMES_PER_DESC; i++) {
cam->last_data_urb->iso_frame_desc[i].status = 0;
cam->last_data_urb->iso_frame_desc[i].actual_length = 0;
}
cam->last_data_urb = NULL;
}
uvd->stats.urb_length = len;
if (len <= 0) {
goto urb_done_with;
}
/* Here we got some data */
uvd->stats.data_count += len;
RingQueue_WakeUpInterruptible(&uvd->dp);
urb_done_with:
for (i = 0; i < FRAMES_PER_DESC; i++) {
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
return;
}
static int konicawc_start_data(uvd_t *uvd)
{
struct usb_device *dev = uvd->dev;
int i, errFlag;
struct konicawc *cam = (struct konicawc *)uvd->user_data;
if (!CAMERA_IS_OPERATIONAL(uvd)) {
err("Camera is not operational");
return -EFAULT;
}
uvd->curframe = -1;
/* Alternate interface 1 is is the biggest frame size */
i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
if (i < 0) {
err("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->transfer_flags = USB_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 = uvd->iso_packet_len * FRAMES_PER_DESC;
for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {
urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length = uvd->iso_packet_len;
}
urb = cam->sts_urb[i];
urb->dev = dev;
urb->context = uvd;
urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
urb->transfer_flags = USB_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;
}
}
/* Link URBs into a ring so that they invoke each other infinitely */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
if ((i+1) < USBVIDEO_NUMSBUF) {
cam->sts_urb[i]->next = uvd->sbuf[i].urb;
uvd->sbuf[i].urb->next = cam->sts_urb[i+1];
} else {
cam->sts_urb[i]->next = uvd->sbuf[i].urb;
uvd->sbuf[i].urb->next = cam->sts_urb[0];
}
}
/* Submit all URBs */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
if (errFlag)
err ("usb_submit_isoc(%d) ret %d", i, errFlag);
errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL);
if (errFlag)
err("usb_submit_isoc(%d) ret %d", i, errFlag);
}
uvd->streaming = 1;
if (debug > 1)
dbg("streaming=1 video_endp=$%02x", uvd->video_endp);
return 0;
}
static void konicawc_stop_data(uvd_t *uvd)
{
int i, j;
struct konicawc *cam = (struct konicawc *)uvd->user_data;
if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
return;
/* Unschedule all of the iso td's */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
j = usb_unlink_urb(uvd->sbuf[i].urb);
if (j < 0)
err("usb_unlink_urb() error %d.", j);
j = usb_unlink_urb(cam->sts_urb[i]);
if (j < 0)
err("usb_unlink_urb() error %d.", j);
}
uvd->streaming = 0;
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(uvd_t *uvd, usbvideo_frame_t *frame)
{
int n;
int maxline, yplanesz;
struct konicawc *cam = (struct konicawc *)uvd->user_data;
assert(uvd != NULL);
assert(frame != NULL);
maxline = (cam->height * cam->width * 3) / (2 * 384);
yplanesz = cam->height * cam->width;
if(debug > 5)
dbg("maxline = %d yplanesz = %d", maxline, yplanesz);
if(debug > 3)
dbg("Frame state = %d", frame->scanstate);
if(frame->scanstate == ScanState_Scanning) {
int drop = 0;
int curframe;
int fdrops = 0;
if(debug > 3)
dbg("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 != -1) {
if(curframe < cam->lastframe) {
fdrops = (curframe + 0x80) - cam->lastframe;
} else {
fdrops = curframe - cam->lastframe;
}
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(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 && (n = 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) {
if(debug > 5)
dbg("got whole frame");
frame->frameState = FrameState_Done_Hold;
frame->curline = 0;
uvd->curframe = -1;
uvd->stats.frame_num++;
}
}
static int konicawc_calculate_fps(uvd_t *uvd)
{
struct konicawc *t = uvd->user_data;
dbg("");
return (t->fps)/3;
}
static void konicawc_configure_video(uvd_t *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.maxwidth = cam->width;
uvd->vcap.maxheight = cam->height;
uvd->vcap.minwidth = cam->width;
uvd->vcap.minheight = cam->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 */
dbg("device init");
if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
dbg("3,10 -> %2.2x %2.2x", buf[0], buf[1]);
if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
dbg("3,10 -> %2.2x %2.2x", buf[0], buf[1]);
if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
dbg("2,0,d failed");
dbg("setting initial values");
}
static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum ,const struct usb_device_id *devid)
{
uvd_t *uvd = NULL;
int i, nas;
int actInterface=-1, inactInterface=-1, maxPS=0;
unsigned char video_ep = 0;
if (debug >= 1)
dbg("konicawc_probe(%p,%u.)", dev, ifnum);
/* We don't handle multi-config cameras */
if (dev->descriptor.bNumConfigurations != 1)
return NULL;
info("Konica Webcam (rev. 0x%04x)", dev->descriptor.bcdDevice);
/* Validate found interface: must have one ISO endpoint */
nas = dev->actconfig->interface[ifnum].num_altsetting;
if (debug > 0)
info("Number of alternate settings=%d.", nas);
if (nas < 8) {
err("Too few alternate settings for this camera!");
return NULL;
}
/* Validate all alternate settings */
for (i=0; i < nas; i++) {
const struct usb_interface_descriptor *interface;
const struct usb_endpoint_descriptor *endpoint;
interface = &dev->actconfig->interface[ifnum].altsetting[i];
if (interface->bNumEndpoints != 2) {
err("Interface %d. has %u. endpoints!",
ifnum, (unsigned)(interface->bNumEndpoints));
return NULL;
}
endpoint = &interface->endpoint[1];
dbg("found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
if (video_ep == 0)
video_ep = endpoint->bEndpointAddress;
else if (video_ep != endpoint->bEndpointAddress) {
err("Alternate settings have different endpoint addresses!");
return NULL;
}
if ((endpoint->bmAttributes & 0x03) != 0x01) {
err("Interface %d. has non-ISO endpoint!", ifnum);
return NULL;
}
if ((endpoint->bEndpointAddress & 0x80) == 0) {
err("Interface %d. has ISO OUT endpoint!", ifnum);
return NULL;
}
if (endpoint->wMaxPacketSize == 0) {
if (inactInterface < 0)
inactInterface = i;
else {
err("More than one inactive alt. setting!");
return NULL;
}
} else {
if (actInterface < 0) {
actInterface = i;
maxPS = endpoint->wMaxPacketSize;
if (debug > 0)
info("Active setting=%d. maxPS=%d.",
i, maxPS);
} else {
/* Got another active alt. setting */
if (maxPS < endpoint->wMaxPacketSize) {
/* This one is better! */
actInterface = i;
maxPS = endpoint->wMaxPacketSize;
if (debug > 0) {
info("Even better active setting=%d. maxPS=%d.",
i, maxPS);
}
}
}
}
}
/* Code below may sleep, need to lock module while we are here */
MOD_INC_USE_COUNT;
uvd = usbvideo_AllocateDevice(cams);
if (uvd != NULL) {
struct konicawc *konicawc_data = (struct konicawc *)(uvd->user_data);
/* Here uvd is a fully allocated uvd_t object */
for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
konicawc_data->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC);
}
switch(size) {
case SIZE_160X130:
default:
konicawc_data->height = 136;
konicawc_data->width = 160;
konicawc_data->size = SIZE_160X130;
break;
case SIZE_176X144:
konicawc_data->height = 144;
konicawc_data->width = 176;
konicawc_data->size = SIZE_176X144;
break;
case SIZE_320X240:
konicawc_data->height = 240;
konicawc_data->width = 320;
konicawc_data->size = SIZE_320X240;
break;
}
uvd->flags = 0;
uvd->debug = debug;
uvd->dev = dev;
uvd->iface = ifnum;
uvd->ifaceAltInactive = inactInterface;
uvd->ifaceAltActive = actInterface;
uvd->video_endp = video_ep;
uvd->iso_packet_len = maxPS;
uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
uvd->canvas = VIDEOSIZE(konicawc_data->width, konicawc_data->height);
uvd->videosize = uvd->canvas;
/* Initialize konicawc specific data */
konicawc_configure_video(uvd);
i = usbvideo_RegisterVideoDevice(uvd);
uvd->max_frame_size = (konicawc_data->width * konicawc_data->height * 3)/2;
if (i != 0) {
err("usbvideo_RegisterVideoDevice() failed.");
uvd = NULL;
}
}
MOD_DEC_USE_COUNT;
return uvd;
}
static int __init konicawc_init(void)
{
usbvideo_cb_t cbTbl;
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.startDataPump = konicawc_start_data;
cbTbl.stopDataPump = konicawc_stop_data;
return usbvideo_register(
&cams,
MAX_CAMERAS,
sizeof(struct konicawc),
"konicawc",
&cbTbl,
THIS_MODULE);
}
static void __exit konicawc_cleanup(void)
{
usbvideo_Deregister(&cams);
}
#if defined(usb_device_id_ver)
static __devinitdata struct usb_device_id id_table[] = {
{ USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
#endif /* defined(usb_device_id_ver) */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
MODULE_DESCRIPTION("Konica Webcam driver");
MODULE_PARM(size, "i");
MODULE_PARM_DESC(size, "Frame Size 0: 160x136 1: 176x144 2: 320x240");
MODULE_PARM(brightness, "i");
MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
MODULE_PARM(contrast, "i");
MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
MODULE_PARM(saturation, "i");
MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
MODULE_PARM(sharpness, "i");
MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
MODULE_PARM(whitebal, "i");
MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
module_init(konicawc_init);
module_exit(konicawc_cleanup);
...@@ -791,6 +791,10 @@ int usbvideo_register( ...@@ -791,6 +791,10 @@ int usbvideo_register(
cams->cb.getFrame = usbvideo_GetFrame; cams->cb.getFrame = usbvideo_GetFrame;
if (cams->cb.disconnect == NULL) if (cams->cb.disconnect == NULL)
cams->cb.disconnect = usbvideo_Disconnect; cams->cb.disconnect = usbvideo_Disconnect;
if (cams->cb.startDataPump == NULL)
cams->cb.startDataPump = usbvideo_StartDataPump;
if (cams->cb.stopDataPump == NULL)
cams->cb.stopDataPump = usbvideo_StopDataPump;
#if USES_PROC_FS #if USES_PROC_FS
/* /*
* If both /proc fs callbacks are NULL then we assume that the driver * If both /proc fs callbacks are NULL then we assume that the driver
...@@ -963,7 +967,7 @@ void usbvideo_Disconnect(struct usb_device *dev, void *ptr) ...@@ -963,7 +967,7 @@ void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
uvd->remove_pending = 1; /* Now all ISO data will be ignored */ uvd->remove_pending = 1; /* Now all ISO data will be ignored */
/* At this time we ask to cancel outstanding URBs */ /* At this time we ask to cancel outstanding URBs */
usbvideo_StopDataPump(uvd); GET_CALLBACK(uvd, stopDataPump)(uvd);
for (i=0; i < USBVIDEO_NUMSBUF; i++) for (i=0; i < USBVIDEO_NUMSBUF; i++)
usb_free_urb(uvd->sbuf[i].urb); usb_free_urb(uvd->sbuf[i].urb);
...@@ -1299,7 +1303,7 @@ int usbvideo_v4l_open(struct video_device *dev, int flags) ...@@ -1299,7 +1303,7 @@ int usbvideo_v4l_open(struct video_device *dev, int flags)
if (errCode == 0) { if (errCode == 0) {
/* Start data pump if we have valid endpoint */ /* Start data pump if we have valid endpoint */
if (uvd->video_endp != 0) if (uvd->video_endp != 0)
errCode = usbvideo_StartDataPump(uvd); errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
if (errCode == 0) { if (errCode == 0) {
if (VALID_CALLBACK(uvd, setupOnOpen)) { if (VALID_CALLBACK(uvd, setupOnOpen)) {
if (uvd->debug > 1) if (uvd->debug > 1)
...@@ -1350,7 +1354,7 @@ void usbvideo_v4l_close(struct video_device *dev) ...@@ -1350,7 +1354,7 @@ void usbvideo_v4l_close(struct video_device *dev)
info("%s($%p)", proc, dev); info("%s($%p)", proc, dev);
down(&uvd->lock); down(&uvd->lock);
usbvideo_StopDataPump(uvd); GET_CALLBACK(uvd, stopDataPump)(uvd);
usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
uvd->fbuf = NULL; uvd->fbuf = NULL;
RingQueue_Free(&uvd->dp); RingQueue_Free(&uvd->dp);
......
...@@ -269,6 +269,8 @@ typedef struct { ...@@ -269,6 +269,8 @@ typedef struct {
int (*getFrame)(uvd_t *, int); int (*getFrame)(uvd_t *, int);
int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data); int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data);
int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data); int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data);
int (*startDataPump)(uvd_t *uvd);
void (*stopDataPump)(uvd_t *uvd);
} usbvideo_cb_t; } usbvideo_cb_t;
struct s_usbvideo_t { struct s_usbvideo_t {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment