diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-23 21:12:49 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-23 21:12:49 -0700 |
commit | df462b3dbeeaae7141f1b63cbfcc1e1bae6a85fc (patch) | |
tree | bca52fce066159f136d75c69e79016422212cb1d /drivers/media/video/gspca | |
parent | 343800e7d20944aead238c2c6e3f7789f8b6587c (diff) | |
parent | cf25220677b3f10468a74278130fe224f73632a6 (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (247 commits)
[media] gspca - sunplus: Fix some warnings and simplify code
[media] gspca: Fix some warnings tied to 'no debug'
[media] gspca: Unset debug by default
[media] gspca - cpia1: Remove a bad conditional compilation instruction
[media] gspca - main: Remove USB traces
[media] gspca - main: Version change to 2.13
[media] gspca - stk014 / t613: Accept the index 0 in querymenu
[media] gspca - kinect: Remove __devinitdata
[media] gspca - cpia1: Fix some warnings
[media] video/Kconfig: Fix mis-classified devices
[media] support for medion dvb stick 1660:1921
[media] tm6000: fix uninitialized field, change prink to dprintk
[media] cx231xx: Add support for Iconbit U100
[media] saa7134 add new TV cards
[media] Use a more consistent value for RC repeat period
[media] cx18: Move spinlock and vb_type initialisation into stream_init
[media] tm6000: remove tm6010 sif audio start and stop
[media] tm6000: remove unused exports
[media] tm6000: add pts logging
[media] tm6000: change from ioctl to unlocked_ioctl
...
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r-- | drivers/media/video/gspca/Kconfig | 9 | ||||
-rw-r--r-- | drivers/media/video/gspca/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/gspca/cpia1.c | 6 | ||||
-rw-r--r-- | drivers/media/video/gspca/gl860/gl860.c | 15 | ||||
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 4 | ||||
-rw-r--r-- | drivers/media/video/gspca/gspca.h | 6 | ||||
-rw-r--r-- | drivers/media/video/gspca/jeilinj.c | 581 | ||||
-rw-r--r-- | drivers/media/video/gspca/kinect.c | 429 | ||||
-rw-r--r-- | drivers/media/video/gspca/spca508.c | 5 | ||||
-rw-r--r-- | drivers/media/video/gspca/stk014.c | 15 | ||||
-rw-r--r-- | drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c | 2 | ||||
-rw-r--r-- | drivers/media/video/gspca/sunplus.c | 99 | ||||
-rw-r--r-- | drivers/media/video/gspca/t613.c | 17 | ||||
-rw-r--r-- | drivers/media/video/gspca/zc3xx.c | 47 |
14 files changed, 917 insertions, 320 deletions
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index eb04e8b5998..34ae2c29979 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -77,6 +77,15 @@ config USB_GSPCA_JEILINJ To compile this driver as a module, choose M here: the module will be called gspca_jeilinj. +config USB_GSPCA_KINECT + tristate "Kinect sensor device USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for the Microsoft Kinect sensor device. + + To compile this driver as a module, choose M here: the + module will be called gspca_kinect. + config USB_GSPCA_KONICA tristate "Konica USB Camera V4L2 driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 855fbc8c9c4..802fbe1bff4 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o +obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o @@ -46,6 +47,7 @@ gspca_cpia1-objs := cpia1.o gspca_etoms-objs := etoms.o gspca_finepix-objs := finepix.o gspca_jeilinj-objs := jeilinj.o +gspca_kinect-objs := kinect.o gspca_konica-objs := konica.o gspca_mars-objs := mars.o gspca_mr97310a-objs := mr97310a.o diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index 9ddbac68066..f2a9451eea1 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c @@ -1262,7 +1262,7 @@ static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply) static void monitor_exposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - u8 exp_acc, bcomp, gain, coarseL, cmd[8]; + u8 exp_acc, bcomp, cmd[8]; int ret, light_exp, dark_exp, very_dark_exp; int old_exposure, new_exposure, framerate; int setfps = 0, setexp = 0, setflicker = 0; @@ -1284,8 +1284,6 @@ static void monitor_exposure(struct gspca_dev *gspca_dev) } exp_acc = gspca_dev->usb_buf[0]; bcomp = gspca_dev->usb_buf[1]; - gain = gspca_dev->usb_buf[2]; - coarseL = gspca_dev->usb_buf[3]; light_exp = sd->params.colourParams.brightness + TC - 50 + EXP_ACC_LIGHT; @@ -1772,9 +1770,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { -#ifdef GSPCA_DEBUG struct sd *sd = (struct sd *) gspca_dev; -#endif int ret; /* Start / Stop the camera to make sure we are talking to diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index 99083038cec..e8e071aa212 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -499,21 +499,8 @@ MODULE_DEVICE_TABLE(usb, device_table); static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct gspca_dev *gspca_dev; - s32 ret; - - ret = gspca_dev_probe(intf, id, + return gspca_dev_probe(intf, id, &sd_desc_mi1320, sizeof(struct sd), THIS_MODULE); - - if (ret >= 0) { - gspca_dev = usb_get_intfdata(intf); - - PDEBUG(D_PROBE, - "Camera is now controlling video device %s", - video_device_node_name(&gspca_dev->vdev)); - } - - return ret; } static void sd_disconnect(struct usb_interface *intf) diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index e526aa3deda..08ce9948d99 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 12, 0) +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 13, 0) #ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; @@ -2495,6 +2495,6 @@ module_exit(gspca_exit); module_param_named(debug, gspca_debug, int, 0644); MODULE_PARM_DESC(debug, "Debug (bit) 0x01:error 0x02:probe 0x04:config" - " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout" + " 0x08:stream 0x10:frame 0x20:packet" " 0x0100: v4l2"); #endif diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 41755226d38..49e2fcbe81f 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -9,7 +9,7 @@ #include <linux/mutex.h> /* compilation option */ -#define GSPCA_DEBUG 1 +/*#define GSPCA_DEBUG 1*/ #ifdef GSPCA_DEBUG /* GSPCA our debug messages */ @@ -25,8 +25,8 @@ extern int gspca_debug; #define D_STREAM 0x08 #define D_FRAM 0x10 #define D_PACK 0x20 -#define D_USBI 0x40 -#define D_USBO 0x80 +#define D_USBI 0x00 +#define D_USBO 0x00 #define D_V4L2 0x0100 #else #define PDEBUG(level, fmt, args...) diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 36dae38b1e3..1bd9c4b542d 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c @@ -6,6 +6,9 @@ * * Copyright (C) 2009 Theodore Kilgore * + * Sportscam DV15 support and control settings are + * Copyright (C) 2011 Patrice Chotard + * * 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 @@ -23,7 +26,6 @@ #define MODULE_NAME "jeilinj" -#include <linux/workqueue.h> #include <linux/slab.h> #include "gspca.h" #include "jpeg.h" @@ -34,29 +36,51 @@ MODULE_LICENSE("GPL"); /* Default timeouts, in ms */ #define JEILINJ_CMD_TIMEOUT 500 +#define JEILINJ_CMD_DELAY 160 #define JEILINJ_DATA_TIMEOUT 1000 /* Maximum transfer size to use. */ #define JEILINJ_MAX_TRANSFER 0x200 - #define FRAME_HEADER_LEN 0x10 +#define FRAME_START 0xFFFFFFFF + +enum { + SAKAR_57379, + SPORTSCAM_DV15, +}; + +#define CAMQUALITY_MIN 0 /* highest cam quality */ +#define CAMQUALITY_MAX 97 /* lowest cam quality */ + +enum e_ctrl { + LIGHTFREQ, + AUTOGAIN, + RED, + GREEN, + BLUE, + NCTRLS /* number of controls */ +}; /* Structure to hold all of our device specific stuff */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + struct gspca_ctrl ctrls[NCTRLS]; + int blocks_left; const struct v4l2_pix_format *cap_mode; /* Driver stuff */ - struct work_struct work_struct; - struct workqueue_struct *work_thread; + u8 type; u8 quality; /* image quality */ - u8 jpegqual; /* webcam quality */ +#define QUALITY_MIN 35 +#define QUALITY_MAX 85 +#define QUALITY_DEF 85 u8 jpeg_hdr[JPEG_HDR_SZ]; }; - struct jlj_command { - unsigned char instruction[2]; - unsigned char ack_wanted; - }; +struct jlj_command { + unsigned char instruction[2]; + unsigned char ack_wanted; + unsigned char delay; +}; /* AFAICT these cameras will only do 320x240. */ static struct v4l2_pix_format jlj_mode[] = { @@ -64,6 +88,11 @@ static struct v4l2_pix_format jlj_mode[] = { .bytesperline = 320, .sizeimage = 320 * 240, .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, + { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0} }; @@ -73,178 +102,295 @@ static struct v4l2_pix_format jlj_mode[] = { */ /* All commands are two bytes only */ -static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) +static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) { int retval; + if (gspca_dev->usb_err < 0) + return; memcpy(gspca_dev->usb_buf, command, 2); retval = usb_bulk_msg(gspca_dev->dev, usb_sndbulkpipe(gspca_dev->dev, 3), gspca_dev->usb_buf, 2, NULL, 500); - if (retval < 0) + if (retval < 0) { err("command write [%02x] error %d", gspca_dev->usb_buf[0], retval); - return retval; + gspca_dev->usb_err = retval; + } } /* Responses are one byte only */ -static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) +static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) { int retval; + if (gspca_dev->usb_err < 0) + return; retval = usb_bulk_msg(gspca_dev->dev, usb_rcvbulkpipe(gspca_dev->dev, 0x84), gspca_dev->usb_buf, 1, NULL, 500); response = gspca_dev->usb_buf[0]; - if (retval < 0) + if (retval < 0) { err("read command [%02x] error %d", gspca_dev->usb_buf[0], retval); - return retval; + gspca_dev->usb_err = retval; + } } -static int jlj_start(struct gspca_dev *gspca_dev) +static void setfreq(struct gspca_dev *gspca_dev) { - int i; - int retval = -1; - u8 response = 0xff; - struct jlj_command start_commands[] = { - {{0x71, 0x81}, 0}, - {{0x70, 0x05}, 0}, - {{0x95, 0x70}, 1}, - {{0x71, 0x81}, 0}, - {{0x70, 0x04}, 0}, - {{0x95, 0x70}, 1}, - {{0x71, 0x00}, 0}, - {{0x70, 0x08}, 0}, - {{0x95, 0x70}, 1}, - {{0x94, 0x02}, 0}, - {{0xde, 0x24}, 0}, - {{0x94, 0x02}, 0}, - {{0xdd, 0xf0}, 0}, - {{0x94, 0x02}, 0}, - {{0xe3, 0x2c}, 0}, - {{0x94, 0x02}, 0}, - {{0xe4, 0x00}, 0}, - {{0x94, 0x02}, 0}, - {{0xe5, 0x00}, 0}, - {{0x94, 0x02}, 0}, - {{0xe6, 0x2c}, 0}, - {{0x94, 0x03}, 0}, - {{0xaa, 0x00}, 0}, - {{0x71, 0x1e}, 0}, - {{0x70, 0x06}, 0}, - {{0x71, 0x80}, 0}, - {{0x70, 0x07}, 0} + struct sd *sd = (struct sd *) gspca_dev; + u8 freq_commands[][2] = { + {0x71, 0x80}, + {0x70, 0x07} }; - for (i = 0; i < ARRAY_SIZE(start_commands); i++) { - retval = jlj_write2(gspca_dev, start_commands[i].instruction); - if (retval < 0) - return retval; - if (start_commands[i].ack_wanted) - retval = jlj_read1(gspca_dev, response); - if (retval < 0) - return retval; - } - PDEBUG(D_ERR, "jlj_start retval is %d", retval); - return retval; + + freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1); + + jlj_write2(gspca_dev, freq_commands[0]); + jlj_write2(gspca_dev, freq_commands[1]); } -static int jlj_stop(struct gspca_dev *gspca_dev) +static void setcamquality(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 quality_commands[][2] = { + {0x71, 0x1E}, + {0x70, 0x06} + }; + u8 camquality; + + /* adapt camera quality from jpeg quality */ + camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX) + / (QUALITY_MAX - QUALITY_MIN); + quality_commands[0][1] += camquality; + + jlj_write2(gspca_dev, quality_commands[0]); + jlj_write2(gspca_dev, quality_commands[1]); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 autogain_commands[][2] = { + {0x94, 0x02}, + {0xcf, 0x00} + }; + + autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4); + + jlj_write2(gspca_dev, autogain_commands[0]); + jlj_write2(gspca_dev, autogain_commands[1]); +} + +static void setred(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 setred_commands[][2] = { + {0x94, 0x02}, + {0xe6, 0x00} + }; + + setred_commands[1][1] = sd->ctrls[RED].val; + + jlj_write2(gspca_dev, setred_commands[0]); + jlj_write2(gspca_dev, setred_commands[1]); +} + +static void setgreen(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 setgreen_commands[][2] = { + {0x94, 0x02}, + {0xe7, 0x00} + }; + + setgreen_commands[1][1] = sd->ctrls[GREEN].val; + + jlj_write2(gspca_dev, setgreen_commands[0]); + jlj_write2(gspca_dev, setgreen_commands[1]); +} + +static void setblue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 setblue_commands[][2] = { + {0x94, 0x02}, + {0xe9, 0x00} + }; + + setblue_commands[1][1] = sd->ctrls[BLUE].val; + + jlj_write2(gspca_dev, setblue_commands[0]); + jlj_write2(gspca_dev, setblue_commands[1]); +} + +static const struct ctrl sd_ctrls[NCTRLS] = { +[LIGHTFREQ] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Light frequency filter", + .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */ + .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */ + .step = 1, + .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, + }, + .set_control = setfreq + }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Automatic Gain (and Exposure)", + .minimum = 0, + .maximum = 3, + .step = 1, +#define AUTOGAIN_DEF 0 + .default_value = AUTOGAIN_DEF, + }, + .set_control = setautogain + }, +[RED] = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0, + .maximum = 3, + .step = 1, +#define RED_BALANCE_DEF 2 + .default_value = RED_BALANCE_DEF, + }, + .set_control = setred + }, + +[GREEN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "green balance", + .minimum = 0, + .maximum = 3, + .step = 1, +#define GREEN_BALANCE_DEF 2 + .default_value = GREEN_BALANCE_DEF, + }, + .set_control = setgreen + }, +[BLUE] = { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0, + .maximum = 3, + .step = 1, +#define BLUE_BALANCE_DEF 2 + .default_value = BLUE_BALANCE_DEF, + }, + .set_control = setblue + }, +}; + +static int jlj_start(struct gspca_dev *gspca_dev) { int i; - int retval; - struct jlj_command stop_commands[] = { - {{0x71, 0x00}, 0}, - {{0x70, 0x09}, 0}, - {{0x71, 0x80}, 0}, - {{0x70, 0x05}, 0} + int start_commands_size; + u8 response = 0xff; + struct sd *sd = (struct sd *) gspca_dev; + struct jlj_command start_commands[] = { + {{0x71, 0x81}, 0, 0}, + {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY}, + {{0x95, 0x70}, 1, 0}, + {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0}, + {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY}, + {{0x95, 0x70}, 1, 0}, + {{0x71, 0x00}, 0, 0}, /* start streaming ??*/ + {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY}, + {{0x95, 0x70}, 1, 0}, +#define SPORTSCAM_DV15_CMD_SIZE 9 + {{0x94, 0x02}, 0, 0}, + {{0xde, 0x24}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xdd, 0xf0}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xe3, 0x2c}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xe4, 0x00}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xe5, 0x00}, 0, 0}, + {{0x94, 0x02}, 0, 0}, + {{0xe6, 0x2c}, 0, 0}, + {{0x94, 0x03}, 0, 0}, + {{0xaa, 0x00}, 0, 0} }; - for (i = 0; i < ARRAY_SIZE(stop_commands); i++) { - retval = jlj_write2(gspca_dev, stop_commands[i].instruction); - if (retval < 0) - return retval; + + sd->blocks_left = 0; + /* Under Windows, USB spy shows that only the 9 first start + * commands are used for SPORTSCAM_DV15 webcam + */ + if (sd->type == SPORTSCAM_DV15) + start_commands_size = SPORTSCAM_DV15_CMD_SIZE; + else + start_commands_size = ARRAY_SIZE(start_commands); + + for (i = 0; i < start_commands_size; i++) { + jlj_write2(gspca_dev, start_commands[i].instruction); + if (start_commands[i].delay) + msleep(start_commands[i].delay); + if (start_commands[i].ack_wanted) + jlj_read1(gspca_dev, response); } - return retval; + setcamquality(gspca_dev); + msleep(2); + setfreq(gspca_dev); + if (gspca_dev->usb_err < 0) + PDEBUG(D_ERR, "Start streaming command failed"); + return gspca_dev->usb_err; } -/* This function is called as a workqueue function and runs whenever the camera - * is streaming data. Because it is a workqueue function it is allowed to sleep - * so we can use synchronous USB calls. To avoid possible collisions with other - * threads attempting to use the camera's USB interface the gspca usb_lock is - * used when performing the one USB control operation inside the workqueue, - * which tells the camera to close the stream. In practice the only thing - * which needs to be protected against is the usb_set_interface call that - * gspca makes during stream_off. Otherwise the camera doesn't provide any - * controls that the user could try to change. - */ - -static void jlj_dostream(struct work_struct *work) +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, int len) { - struct sd *dev = container_of(work, struct sd, work_struct); - struct gspca_dev *gspca_dev = &dev->gspca_dev; - int blocks_left; /* 0x200-sized blocks remaining in current frame. */ - int act_len; + struct sd *sd = (struct sd *) gspca_dev; int packet_type; - int ret; - u8 *buffer; + u32 header_marker; - buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); - if (!buffer) { - err("Couldn't allocate USB buffer"); - goto quit_stream; + PDEBUG(D_STREAM, "Got %d bytes out of %d for Block 0", + len, JEILINJ_MAX_TRANSFER); + if (len != JEILINJ_MAX_TRANSFER) { + PDEBUG(D_PACK, "bad length"); + goto discard; } - while (gspca_dev->present && gspca_dev->streaming) { - /* - * Now request data block 0. Line 0 reports the size - * to download, in blocks of size 0x200, and also tells the - * "actual" data size, in bytes, which seems best to ignore. - */ - ret = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x82), - buffer, JEILINJ_MAX_TRANSFER, &act_len, - JEILINJ_DATA_TIMEOUT); - PDEBUG(D_STREAM, - "Got %d bytes out of %d for Block 0", - act_len, JEILINJ_MAX_TRANSFER); - if (ret < 0 || act_len < FRAME_HEADER_LEN) - goto quit_stream; - blocks_left = buffer[0x0a] - 1; - PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left); - + /* check if it's start of frame */ + header_marker = ((u32 *)data)[0]; + if (header_marker == FRAME_START) { + sd->blocks_left = data[0x0a] - 1; + PDEBUG(D_STREAM, "blocks_left = 0x%x", sd->blocks_left); /* Start a new frame, and add the JPEG header, first thing */ gspca_frame_add(gspca_dev, FIRST_PACKET, - dev->jpeg_hdr, JPEG_HDR_SZ); + sd->jpeg_hdr, JPEG_HDR_SZ); /* Toss line 0 of data block 0, keep the rest. */ gspca_frame_add(gspca_dev, INTER_PACKET, - buffer + FRAME_HEADER_LEN, + data + FRAME_HEADER_LEN, JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); - - while (blocks_left > 0) { - if (!gspca_dev->present) - goto quit_stream; - ret = usb_bulk_msg(gspca_dev->dev, - usb_rcvbulkpipe(gspca_dev->dev, 0x82), - buffer, JEILINJ_MAX_TRANSFER, &act_len, - JEILINJ_DATA_TIMEOUT); - if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER) - goto quit_stream; - PDEBUG(D_STREAM, - "%d blocks remaining for frame", blocks_left); - blocks_left -= 1; - if (blocks_left == 0) - packet_type = LAST_PACKET; - else - packet_type = INTER_PACKET; - gspca_frame_add(gspca_dev, packet_type, - buffer, JEILINJ_MAX_TRANSFER); - } - } -quit_stream: - mutex_lock(&gspca_dev->usb_lock); - if (gspca_dev->present) - jlj_stop(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - kfree(buffer); + } else if (sd->blocks_left > 0) { + PDEBUG(D_STREAM, "%d blocks remaining for frame", + sd->blocks_left); + sd->blocks_left -= 1; + if (sd->blocks_left == 0) + packet_type = LAST_PACKET; + else + packet_type = INTER_PACKET; + gspca_frame_add(gspca_dev, packet_type, + data, JEILINJ_MAX_TRANSFER); + } else + goto discard; + return; +discard: + /* Discard data until a new frame starts. */ + gspca_dev->last_packet_type = DISCARD_PACKET; } /* This function is called at probe time just before sd_init */ @@ -254,78 +400,169 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam = &gspca_dev->cam; struct sd *dev = (struct sd *) gspca_dev; - dev->quality = 85; - dev->jpegqual = 85; + dev->type = id->driver_info; + gspca_dev->cam.ctrls = dev->ctrls; + dev->quality = QUALITY_DEF; + dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ; + dev->ctrls[RED].def = RED_BALANCE_DEF; + dev->ctrls[GREEN].def = GREEN_BALANCE_DEF; + dev->ctrls[BLUE].def = BLUE_BALANCE_DEF; PDEBUG(D_PROBE, "JEILINJ camera detected" " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); cam->cam_mode = jlj_mode; - cam->nmodes = 1; + cam->nmodes = ARRAY_SIZE(jlj_mode); cam->bulk = 1; - /* We don't use the buffer gspca allocates so make it small. */ - cam->bulk_size = 32; - INIT_WORK(&dev->work_struct, jlj_dostream); + cam->bulk_nurbs = 1; + cam->bulk_size = JEILINJ_MAX_TRANSFER; return 0; } -/* called on streamoff with alt==0 and on disconnect */ -/* the usb_lock is held at entry - restore on exit */ -static void sd_stop0(struct gspca_dev *gspca_dev) +static void sd_stopN(struct gspca_dev *gspca_dev) { - struct sd *dev = (struct sd *) gspca_dev; + int i; + u8 *buf; + u8 stop_commands[][2] = { + {0x71, 0x00}, + {0x70, 0x09}, + {0x71, 0x80}, + {0x70, 0x05} + }; + + for (;;) { + /* get the image remaining blocks */ + usb_bulk_msg(gspca_dev->dev, + gspca_dev->urb[0]->pipe, + gspca_dev->urb[0]->transfer_buffer, + JEILINJ_MAX_TRANSFER, NULL, + JEILINJ_DATA_TIMEOUT); + + /* search for 0xff 0xd9 (EOF for JPEG) */ + i = 0; + buf = gspca_dev->urb[0]->transfer_buffer; + while ((i < (JEILINJ_MAX_TRANSFER - 1)) && + ((buf[i] != 0xff) || (buf[i+1] != 0xd9))) + i++; - /* wait for the work queue to terminate */ - mutex_unlock(&gspca_dev->usb_lock); - /* This waits for jlj_dostream to finish */ - destroy_workqueue(dev->work_thread); - dev->work_thread = NULL; - mutex_lock(&gspca_dev->usb_lock); + if (i != (JEILINJ_MAX_TRANSFER - 1)) + /* last remaining block found */ + break; + } + + for (i = 0; i < ARRAY_SIZE(stop_commands); i++) + jlj_write2(gspca_dev, stop_commands[i]); } /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { - return 0; + return gspca_dev->usb_err; } /* Set up for getting frames. */ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *dev = (struct sd *) gspca_dev; - int ret; /* create the JPEG header */ jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ jpeg_set_qual(dev->jpeg_hdr, dev->quality); - PDEBUG(D_STREAM, "Start streaming at 320x240"); - ret = jlj_start(gspca_dev); - if (ret < 0) { - PDEBUG(D_ERR, "Start streaming command failed"); - return ret; - } - /* Start the workqueue function to do the streaming */ - dev->work_thread = create_singlethread_workqueue(MODULE_NAME); - queue_work(dev->work_thread, &dev->work_struct); - - return 0; + PDEBUG(D_STREAM, "Start streaming at %dx%d", + gspca_dev->height, gspca_dev->width); + jlj_start(gspca_dev); + return gspca_dev->usb_err; } /* Table of supported USB devices */ static const struct usb_device_id device_table[] = { - {USB_DEVICE(0x0979, 0x0280)}, + {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379}, + {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15}, {} }; MODULE_DEVICE_TABLE(usb, device_table); +static int sd_querymenu(struct gspca_dev *gspca_dev, + struct v4l2_querymenu *menu) +{ + switch (menu->id) { + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (menu->index) { + case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ + strcpy((char *) menu->name, "disable"); + return 0; + case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ + strcpy((char *) menu->name, "50 Hz"); + return 0; + case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ + strcpy((char *) menu->name, "60 Hz"); + return 0; + } + break; + } + return -EINVAL; +} + +static int sd_set_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (jcomp->quality < QUALITY_MIN) + sd->quality = QUALITY_MIN; + else if (jcomp->quality > QUALITY_MAX) + sd->quality = QUALITY_MAX; + else + sd->quality = jcomp->quality; + if (gspca_dev->streaming) { + jpeg_set_qual(sd->jpeg_hdr, sd->quality); + setcamquality(gspca_dev); + } + return 0; +} + +static int sd_get_jcomp(struct gspca_dev *gspca_dev, + struct v4l2_jpegcompression *jcomp) +{ + struct sd *sd = (struct sd *) gspca_dev; + + memset(jcomp, 0, sizeof *jcomp); + jcomp->quality = sd->quality; + jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT + | V4L2_JPEG_MARKER_DQT; + return 0; +} + + /* sub-driver description */ -static const struct sd_desc sd_desc = { +static const struct sd_desc sd_desc_sakar_57379 = { .name = MODULE_NAME, .config = sd_config, .init = sd_init, .start = sd_start, - .stop0 = sd_stop0, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* sub-driver description */ +static const struct sd_desc sd_desc_sportscam_dv15 = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .querymenu = sd_querymenu, + .get_jcomp = sd_get_jcomp, + .set_jcomp = sd_set_jcomp, +}; + +static const struct sd_desc *sd_desc[2] = { + &sd_desc_sakar_57379, + &sd_desc_sportscam_dv15 }; /* -- device connect -- */ @@ -333,7 +570,7 @@ static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, - &sd_desc, + sd_desc[id->driver_info], sizeof(struct sd), THIS_MODULE); } diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c new file mode 100644 index 00000000000..66671a4092e --- /dev/null +++ b/drivers/media/video/gspca/kinect.c @@ -0,0 +1,429 @@ +/* + * kinect sensor device camera, gspca driver + * + * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it> + * + * Based on the OpenKinect project and libfreenect + * http://openkinect.org/wiki/Init_Analysis + * + * Special thanks to Steven Toth and kernellabs.com for sponsoring a Kinect + * sensor device which I tested the driver on. + * + * 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 + * 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 + */ + +#define MODULE_NAME "kinect" + +#include "gspca.h" + +#define CTRL_TIMEOUT 500 + +MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); +MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); +MODULE_LICENSE("GPL"); + +#ifdef DEBUG +int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | + D_USBI | D_USBO | D_V4L2; +#endif + +struct pkt_hdr { + uint8_t magic[2]; + uint8_t pad; + uint8_t flag; + uint8_t unk1; + uint8_t seq; + uint8_t unk2; + uint8_t unk3; + uint32_t timestamp; +}; + +struct cam_hdr { + uint8_t magic[2]; + uint16_t len; + uint16_t cmd; + uint16_t tag; +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + uint16_t cam_tag; /* a sequence number for packets */ + uint8_t stream_flag; /* to identify different stream types */ + uint8_t obuf[0x400]; /* output buffer for control commands */ + uint8_t ibuf[0x200]; /* input buffer for control commands */ +}; + +/* V4L2 controls supported by the driver */ +/* controls prototypes here */ + +static const struct ctrl sd_ctrls[] = { +}; + +#define MODE_640x480 0x0001 +#define MODE_640x488 0x0002 +#define MODE_1280x1024 0x0004 + +#define FORMAT_BAYER 0x0010 +#define FORMAT_UYVY 0x0020 +#define FORMAT_Y10B 0x0040 + +#define FPS_HIGH 0x0100 + +static const struct v4l2_pix_format video_camera_mode[] = { + {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_640x480 | FORMAT_BAYER | FPS_HIGH}, + {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, + .bytesperline = 640 * 2, + .sizeimage = 640 * 480 * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_640x480 | FORMAT_UYVY}, + {1280, 1024, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 1280, + .sizeimage = 1280 * 1024, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_1280x1024 | FORMAT_BAYER}, + {640, 488, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, + .bytesperline = 640 * 10 / 8, + .sizeimage = 640 * 488 * 10 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_640x488 | FORMAT_Y10B | FPS_HIGH}, + {1280, 1024, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, + .bytesperline = 1280 * 10 / 8, + .sizeimage = 1280 * 1024 * 10 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_1280x1024 | FORMAT_Y10B}, +}; + +static int kinect_write(struct usb_device *udev, uint8_t *data, + uint16_t wLength) +{ + return usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + 0x00, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, data, wLength, CTRL_TIMEOUT); +} + +static int kinect_read(struct usb_device *udev, uint8_t *data, uint16_t wLength) +{ + return usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, data, wLength, CTRL_TIMEOUT); +} + +static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, + unsigned int cmd_len, void *replybuf, unsigned int reply_len) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *udev = gspca_dev->dev; + int res, actual_len; + uint8_t *obuf = sd->obuf; + uint8_t *ibuf = sd->ibuf; + struct cam_hdr *chdr = (void *)obuf; + struct cam_hdr *rhdr = (void *)ibuf; + + if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) { + err("send_cmd: Invalid command length (0x%x)", cmd_len); + return -1; + } + + chdr->magic[0] = 0x47; + chdr->magic[1] = 0x4d; + chdr->cmd = cpu_to_le16(cmd); + chdr->tag = cpu_to_le16(sd->cam_tag); + chdr->len = cpu_to_le16(cmd_len / 2); + + memcpy(obuf+sizeof(*chdr), cmdbuf, cmd_len); + + res = kinect_write(udev, obuf, cmd_len + sizeof(*chdr)); + PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd, + sd->cam_tag, cmd_len, res); + if (res < 0) { + err("send_cmd: Output control transfer failed (%d)", res); + return res; + } + + do { + actual_len = kinect_read(udev, ibuf, 0x200); + } while (actual_len == 0); + PDEBUG(D_USBO, "Control reply: %d", res); + if (actual_len < sizeof(*rhdr)) { + err("send_cmd: Input control transfer failed (%d)", res); + return res; + } + actual_len -= sizeof(*rhdr); + + if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) { + err("send_cmd: Bad magic %02x %02x", rhdr->magic[0], + rhdr->magic[1]); + return -1; + } + if (rhdr->cmd != chdr->cmd) { + err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd); + return -1; + } + if (rhdr->tag != chdr->tag) { + err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag); + return -1; + } + if (cpu_to_le16(rhdr->len) != (actual_len/2)) { + err("send_cmd: Bad len %04x != %04x", + cpu_to_le16(rhdr->len), (int)(actual_len/2)); + return -1; + } + + if (actual_len > reply_len) { + warn("send_cmd: Data buffer is %d bytes long, but got %d bytes", + reply_len, actual_len); + memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len); + } else { + memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len); + } + + sd->cam_tag++; + + return actual_len; +} + +static int write_register(struct gspca_dev *gspca_dev, uint16_t reg, + uint16_t data) +{ + uint16_t reply[2]; + uint16_t cmd[2]; + int res; + + cmd[0] = cpu_to_le16(reg); + cmd[1] = cpu_to_le16(data); + + PDEBUG(D_USBO, "Write Reg 0x%04x <= 0x%02x", reg, data); + res = send_cmd(gspca_dev, 0x03, cmd, 4, reply, 4); + if (res < 0) + return res; + if (res != 2) { + warn("send_cmd returned %d [%04x %04x], 0000 expected", + res, reply[0], reply[1]); + } + return 0; +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + sd->cam_tag = 0; + + /* Only video stream is supported for now, + * which has stream flag = 0x80 */ + sd->stream_flag = 0x80; + + cam = &gspca_dev->cam; + + cam->cam_mode = video_camera_mode; + cam->nmodes = ARRAY_SIZE(video_camera_mode); + +#if 0 + /* Setting those values is not needed for video stream */ + cam->npkt = 15; + gspca_dev->pkt_size = 960 * 2; +#endif + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + PDEBUG(D_PROBE, "Kinect Camera device."); + + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + int mode; + uint8_t fmt_reg, fmt_val; + uint8_t res_reg, res_val; + uint8_t fps_reg, fps_val; + uint8_t mode_val; + + mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; + + if (mode & FORMAT_Y10B) { + fmt_reg = 0x19; + res_reg = 0x1a; + fps_reg = 0x1b; + mode_val = 0x03; + } else { + fmt_reg = 0x0c; + res_reg = 0x0d; + fps_reg = 0x0e; + mode_val = 0x01; + } + + /* format */ + if (mode & FORMAT_UYVY) + fmt_val = 0x05; + else + fmt_val = 0x00; + + if (mode & MODE_1280x1024) + res_val = 0x02; + else + res_val = 0x01; + + if (mode & FPS_HIGH) + fps_val = 0x1e; + else + fps_val = 0x0f; + + + /* turn off IR-reset function */ + write_register(gspca_dev, 0x105, 0x00); + + /* Reset video stream */ + write_register(gspca_dev, 0x05, 0x00); + + /* Due to some ridiculous condition in the firmware, we have to start + * and stop the depth stream before the camera will hand us 1280x1024 + * IR. This is a stupid workaround, but we've yet to find a better + * solution. + * + * Thanks to Drew Fisher for figuring this out. + */ + if (mode & (FORMAT_Y10B | MODE_1280x1024)) { + write_register(gspca_dev, 0x13, 0x01); + write_register(gspca_dev, 0x14, 0x1e); + write_register(gspca_dev, 0x06, 0x02); + write_register(gspca_dev, 0x06, 0x00); + } + + write_register(gspca_dev, fmt_reg, fmt_val); + write_register(gspca_dev, res_reg, res_val); + write_register(gspca_dev, fps_reg, fps_val); + + /* Start video stream */ + write_register(gspca_dev, 0x05, mode_val); + + /* disable Hflip */ + write_register(gspca_dev, 0x47, 0x00); + + return 0; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + /* reset video stream */ + write_register(gspca_dev, 0x05, 0x00); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + + struct pkt_hdr *hdr = (void *)__data; + uint8_t *data = __data + sizeof(*hdr); + int datalen = len - sizeof(*hdr); + + uint8_t sof = sd->stream_flag | 1; + uint8_t mof = sd->stream_flag | 2; + uint8_t eof = sd->stream_flag | 5; + + if (len < 12) + return; + + if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') { + warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag, + hdr->magic[0], hdr->magic[1]); + return; + } + + if (hdr->flag == sof) + gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen); + + else if (hdr->flag == mof) + gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen); + + else if (hdr->flag == eof) + gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen); + + else + warn("Packet type not recognized..."); +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + /* + .querymenu = sd_querymenu, + .get_streamparm = sd_get_streamparm, + .set_streamparm = sd_set_streamparm, + */ +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x045e, 0x02ae)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 41dce49fb43..9d0b46027b9 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -1375,7 +1375,6 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - int data1, data2; const u16 (*init_data)[2]; static const u16 (*(init_data_tb[]))[2] = { spca508_vista_init_data, /* CreativeVista 0 */ @@ -1386,6 +1385,9 @@ static int sd_config(struct gspca_dev *gspca_dev, spca508_init_data, /* ViewQuestVQ110 5 */ }; +#ifdef GSPCA_DEBUG + int data1, data2; + /* Read from global register the USB product and vendor IDs, just to * prove that we can communicate with the device. This works, which * confirms at we are communicating properly and that the device @@ -1400,6 +1402,7 @@ static int sd_config(struct gspca_dev *gspca_dev, data1 = reg_read(gspca_dev, 0x8621); PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); +#endif cam = &gspca_dev->cam; cam->cam_mode = sif_mode; diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 87be52b5e1e..763747700f1 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -436,17 +436,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { + static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; + switch (menu->id) { case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; + if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm)) + break; + strcpy((char *) menu->name, freq_nm[menu->index]); + return 0; } return -EINVAL; } diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c index ac47b4c9438..75a5b9c2f15 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c @@ -217,6 +217,8 @@ static int pb0100_start(struct sd *sd) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); + if (!alt) + return -ENODEV; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); /* If we don't have enough bandwidth use a lower framerate */ diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 543542af272..b089c0d3ee9 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -396,57 +396,6 @@ static void reg_w_riv(struct gspca_dev *gspca_dev, req, index, value); } -/* read 1 byte */ -static u8 reg_r_1(struct gspca_dev *gspca_dev, - u16 value) /* wValue */ -{ - int ret; - - if (gspca_dev->usb_err < 0) - return 0; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0x20, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - 0, /* index */ - gspca_dev->usb_buf, 1, - 500); /* timeout */ - if (ret < 0) { - err("reg_r_1 err %d", ret); - gspca_dev->usb_err = ret; - return 0; - } - return gspca_dev->usb_buf[0]; -} - -/* read 1 or 2 bytes */ -static u16 reg_r_12(struct gspca_dev *gspca_dev, - u8 req, /* bRequest */ - u16 index, /* wIndex */ - u16 length) /* wLength (1 or 2 only) */ -{ - int ret; - - if (gspca_dev->usb_err < 0) - return 0; - gspca_dev->usb_buf[1] = 0; - ret = usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, - gspca_dev->usb_buf, length, - 500); - if (ret < 0) { - err("reg_r_12 err %d", ret); - gspca_dev->usb_err = ret; - return 0; - } - return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; -} - static void write_vector(struct gspca_dev *gspca_dev, const struct cmd *data, int ncmds) { @@ -473,44 +422,46 @@ static void setup_qtable(struct gspca_dev *gspca_dev, static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, u8 req, u16 idx, u16 val) { - u16 notdone; - reg_w_riv(gspca_dev, req, idx, val); - notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); + reg_r(gspca_dev, 0x01, 0x0001, 1); + PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]); reg_w_riv(gspca_dev, req, idx, val); - PDEBUG(D_FRAM, "before wait 0x%04x", notdone); - msleep(200); - notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); - PDEBUG(D_FRAM, "after wait 0x%04x", notdone); + reg_r(gspca_dev, 0x01, 0x0001, 1); + PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]); } +#ifdef GSPCA_DEBUG static void spca504_read_info(struct gspca_dev *gspca_dev) { int i; u8 info[6]; - for (i = 0; i < 6; i++) - info[i] = reg_r_1(gspca_dev, i); + for (i = 0; i < 6; i++) { + reg_r(gspca_dev, 0, i, 1); + info[i] = gspca_dev->usb_buf[0]; + } PDEBUG(D_STREAM, "Read info: %d %d %d %d %d %d." " Should be 1,0,2,2,0,0", info[0], info[1], info[2], info[3], info[4], info[5]); } +#endif static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, u8 req, - u16 idx, u16 val, u16 endcode, u8 count) + u16 idx, u16 val, u8 endcode, u8 count) { u16 status; reg_w_riv(gspca_dev, req, idx, val); - status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); + reg_r(gspca_dev, 0x01, 0x0001, 1); if (gspca_dev->usb_err < 0) return; - PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode); + PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x", + gspca_dev->usb_buf[0], endcode); if (!count) return; count = 200; @@ -518,7 +469,8 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, msleep(10); /* gsmart mini2 write a each wait setting 1 ms is enough */ /* reg_w_riv(gspca_dev, req, idx, val); */ - status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); + reg_r(gspca_dev, 0x01, 0x0001, 1); + status = gspca_dev->usb_buf[0]; if (status == endcode) { PDEBUG(D_FRAM, "status 0x%04x after wait %d", status, 200 - count); @@ -555,17 +507,19 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) } } +#ifdef GSPCA_DEBUG static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) { u8 *data; data = gspca_dev->usb_buf; reg_r(gspca_dev, 0x20, 0, 5); - PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ", + PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d", data[0], data[1], data[2], data[3], data[4]); reg_r(gspca_dev, 0x23, 0, 64); reg_r(gspca_dev, 0x23, 1, 64); } +#endif static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) { @@ -578,7 +532,9 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) reg_w_riv(gspca_dev, 0x31, 0, 0); spca504B_WaitCmdStatus(gspca_dev); spca504B_PollingDataReady(gspca_dev); +#ifdef GSPCA_DEBUG spca50x_GetFirmware(gspca_dev); +#endif reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ reg_r(gspca_dev, 0x24, 8, 1); @@ -628,7 +584,8 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev) cnt = 256; while (--cnt > 0) { /* With this we get the status, when return 0 it's all ok */ - if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0) + reg_r(gspca_dev, 0x06, 0x00, 1); + if (gspca_dev->usb_buf[0] == 0) return; msleep(10); } @@ -772,10 +729,14 @@ static int sd_init(struct gspca_dev *gspca_dev) /* fall thru */ case BRIDGE_SPCA533: spca504B_PollingDataReady(gspca_dev); +#ifdef GSPCA_DEBUG spca50x_GetFirmware(gspca_dev); +#endif break; case BRIDGE_SPCA536: +#ifdef GSPCA_DEBUG spca50x_GetFirmware(gspca_dev); +#endif reg_r(gspca_dev, 0x00, 0x5002, 1); reg_w_1(gspca_dev, 0x24, 0, 0, 0); reg_r(gspca_dev, 0x24, 0, 1); @@ -801,7 +762,9 @@ static int sd_init(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA504: */ PDEBUG(D_STREAM, "Opening SPCA504"); if (sd->subtype == AiptekMiniPenCam13) { +#ifdef GSPCA_DEBUG spca504_read_info(gspca_dev); +#endif /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ spca504A_acknowledged_command(gspca_dev, 0x24, @@ -873,7 +836,9 @@ static int sd_start(struct gspca_dev *gspca_dev) break; case BRIDGE_SPCA504: if (sd->subtype == AiptekMiniPenCam13) { +#ifdef GSPCA_DEBUG spca504_read_info(gspca_dev); +#endif /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ spca504A_acknowledged_command(gspca_dev, 0x24, @@ -885,7 +850,9 @@ static int sd_start(struct gspca_dev *gspca_dev) 0, 0, 0x9d, 1); } else { spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); +#ifdef GSPCA_DEBUG spca504_read_info(gspca_dev); +#endif spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); } diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index a3eccd81576..7e762d55109 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -92,8 +92,6 @@ static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val); static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val); static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val); static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu); static const struct ctrl sd_ctrls[] = { { @@ -1379,17 +1377,14 @@ static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val) static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { + static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; + switch (menu->id) { case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; + if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm)) + break; + strcpy((char *) menu->name, freq_nm[menu->index]); + return 0; case V4L2_CID_EFFECTS: if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { strncpy((char *) menu->name, diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index fa164e861cd..61cdd56a74a 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -3065,15 +3065,10 @@ static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */ {0xaa, 0x55, 0x0010}, /* 00,55,10,aa */ {0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */ {0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ - {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */ - {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */ {} }; -static const struct usb_action mc501cb_50HZScale[] = { +static const struct usb_action mc501cb_50HZ[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */ @@ -3082,15 +3077,10 @@ static const struct usb_action mc501cb_50HZScale[] = { {0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */ {0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */ {0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ - {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */ - {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */ {} }; -static const struct usb_action mc501cb_50HZ[] = { +static const struct usb_action mc501cb_50HZScale[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */ @@ -3099,15 +3089,10 @@ static const struct usb_action mc501cb_50HZ[] = { {0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */ {0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */ {0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ - {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ - {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ {} }; -static const struct usb_action mc501cb_60HZScale[] = { +static const struct usb_action mc501cb_60HZ[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ @@ -3116,15 +3101,10 @@ static const struct usb_action mc501cb_60HZScale[] = { {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ - {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ - {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ {} }; -static const struct usb_action mc501cb_60HZ[] = { +static const struct usb_action mc501cb_60HZScale[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ @@ -3133,15 +3113,10 @@ static const struct usb_action mc501cb_60HZ[] = { {0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */ {0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */ {0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ - {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */ - {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */ {} }; -static const struct usb_action mc501cb_NoFlikerScale[] = { +static const struct usb_action mc501cb_NoFliker[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ @@ -3150,15 +3125,10 @@ static const struct usb_action mc501cb_NoFlikerScale[] = { {0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */ {0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */ {0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */ - {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ - {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ - {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ - {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */ - {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */ {} }; -static const struct usb_action mc501cb_NoFliker[] = { +static const struct usb_action mc501cb_NoFlikerScale[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ @@ -6296,7 +6266,6 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int i; - u8 retbyte; u16 retword; /*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/ @@ -6389,8 +6358,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */ PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword); if (retword == 0x2030) { +#ifdef GSPCA_DEBUG + u8 retbyte; + retbyte = i2c_read(gspca_dev, 0x02); /* revision number */ PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte); +#endif send_unknown(gspca_dev, SENSOR_PO2030); return retword; } |