#include "gspca.h"
#include "jpeg.h"
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
-static const char version[] = "2.1.5";
-
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
MODULE_LICENSE("GPL");
unsigned char contrast;
unsigned char colors;
unsigned char lightfreq;
-};
+ u8 quality;
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
-/* global parameters */
-static int sd_quant = 7; /* <= 4 KO - 7: good (enough!) */
+ u8 *jpeg_hdr;
+};
/* V4L2 controls supported by the driver */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
},
};
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 * 3 / 8 + 590,
/* -- read a register -- */
static int reg_r(struct gspca_dev *gspca_dev,
- __u16 index, __u8 *buf)
+ __u16 index)
{
struct usb_device *dev = gspca_dev->dev;
int ret;
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x00,
index,
- buf, 1,
+ gspca_dev->usb_buf, 1,
500);
- if (ret < 0)
+ if (ret < 0) {
PDEBUG(D_ERR, "reg_r err %d", ret);
- return ret;
+ return ret;
+ }
+ return gspca_dev->usb_buf[0];
}
/* -- write a register -- */
return ret;
}
-/* -- get a value -- */
+/* -- get a bulk value (4 bytes) -- */
static int rcv_val(struct gspca_dev *gspca_dev,
- int ads,
- int len)
+ int ads)
{
struct usb_device *dev = gspca_dev->dev;
int alen, ret;
- unsigned char bulk_buf[4];
reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);
reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);
reg_w(gspca_dev, 0x636, ads & 0xff);
reg_w(gspca_dev, 0x637, 0);
- reg_w(gspca_dev, 0x638, len & 0xff);
- reg_w(gspca_dev, 0x639, len >> 8);
+ reg_w(gspca_dev, 0x638, 4); /* len & 0xff */
+ reg_w(gspca_dev, 0x639, 0); /* len >> 8 */
reg_w(gspca_dev, 0x63a, 0);
reg_w(gspca_dev, 0x63b, 0);
reg_w(gspca_dev, 0x630, 5);
- if (len > sizeof bulk_buf)
- return -1;
ret = usb_bulk_msg(dev,
- usb_rcvbulkpipe(dev, 5),
- bulk_buf,
- len,
+ usb_rcvbulkpipe(dev, 0x05),
+ gspca_dev->usb_buf,
+ 4, /* length */
&alen,
- 500); /* timeout in milliseconds */
+ 500); /* timeout in milliseconds */
return ret;
}
-/* -- send a value -- */
+/* -- send a bulk value -- */
static int snd_val(struct gspca_dev *gspca_dev,
int ads,
unsigned int val)
{
struct usb_device *dev = gspca_dev->dev;
int alen, ret;
- __u8 value, seq;
- unsigned char bulk_buf[4];
+ __u8 seq = 0;
if (ads == 0x003f08) {
- ret = reg_r(gspca_dev, 0x0704, &value);
+ ret = reg_r(gspca_dev, 0x0704);
if (ret < 0)
goto ko;
- ret = reg_r(gspca_dev, 0x0705, &seq);
+ ret = reg_r(gspca_dev, 0x0705);
if (ret < 0)
goto ko;
- ret = reg_r(gspca_dev, 0x0650, &value);
+ seq = ret; /* keep the sequence number */
+ ret = reg_r(gspca_dev, 0x0650);
if (ret < 0)
goto ko;
reg_w(gspca_dev, 0x654, seq);
- } else
+ } else {
reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
+ }
reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);
reg_w(gspca_dev, 0x656, ads & 0xff);
reg_w(gspca_dev, 0x657, 0);
reg_w(gspca_dev, 0x65a, 0);
reg_w(gspca_dev, 0x65b, 0);
reg_w(gspca_dev, 0x650, 5);
- bulk_buf[0] = (val >> 24) & 0xff;
- bulk_buf[1] = (val >> 16) & 0xff;
- bulk_buf[2] = (val >> 8) & 0xff;
- bulk_buf[3] = val & 0xff;
+ gspca_dev->usb_buf[0] = val >> 24;
+ gspca_dev->usb_buf[1] = val >> 16;
+ gspca_dev->usb_buf[2] = val >> 8;
+ gspca_dev->usb_buf[3] = val;
ret = usb_bulk_msg(dev,
usb_sndbulkpipe(dev, 6),
- bulk_buf,
+ gspca_dev->usb_buf,
4,
&alen,
500); /* timeout in milliseconds */
const struct usb_device_id *id)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct cam *cam = &gspca_dev->cam;
- cam->dev_name = (char *) id->driver_info;
- cam->epaddr = 0x02;
gspca_dev->cam.cam_mode = vga_mode;
- gspca_dev->cam.nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->lightfreq = FREQ_DEF;
+ sd->quality = QUALITY_DEF;
return 0;
}
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
{
- __u8 value;
int ret;
/* check if the device responds */
usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
- ret = reg_r(gspca_dev, 0x0740, &value);
+ ret = reg_r(gspca_dev, 0x0740);
if (ret < 0)
return ret;
- if (value != 0xff) {
- PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", value);
+ if (ret != 0xff) {
+ PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret);
return -1;
}
return 0;
}
/* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
{
- __u8 dum;
+ struct sd *sd = (struct sd *) gspca_dev;
int ret, value;
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ if (!sd->jpeg_hdr)
+ return -ENOMEM;
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
/* work on alternate 1 */
usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
gspca_dev->iface, gspca_dev->alt);
goto out;
}
- ret = reg_r(gspca_dev, 0x0630, &dum);
+ ret = reg_r(gspca_dev, 0x0630);
if (ret < 0)
goto out;
- rcv_val(gspca_dev, 0x000020, 4); /* << (value ff ff ff ff) */
- ret = reg_r(gspca_dev, 0x0650, &dum);
+ rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */
+ ret = reg_r(gspca_dev, 0x0650);
if (ret < 0)
goto out;
snd_val(gspca_dev, 0x000020, 0xffffffff);
set_par(gspca_dev, 0x01000000);
set_par(gspca_dev, 0x01000000);
PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
- return;
+ return 0;
out:
PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret);
+ return ret;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
- __u8 value;
set_par(gspca_dev, 0x02000000);
set_par(gspca_dev, 0x02000000);
usb_set_interface(dev, gspca_dev->iface, 1);
- reg_r(gspca_dev, 0x0630, &value);
- rcv_val(gspca_dev, 0x000020, 4); /* << (value ff ff ff ff) */
- reg_r(gspca_dev, 0x0650, &value);
+ reg_r(gspca_dev, 0x0630);
+ rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */
+ reg_r(gspca_dev, 0x0650);
snd_val(gspca_dev, 0x000020, 0xffffffff);
reg_w(gspca_dev, 0x0620, 0);
reg_w(gspca_dev, 0x0630, 0);
static void sd_stop0(struct gspca_dev *gspca_dev)
{
-}
+ struct sd *sd = (struct sd *) gspca_dev;
-static void sd_close(struct gspca_dev *gspca_dev)
-{
+ kfree(sd->jpeg_hdr);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
static unsigned char ffd9[] = {0xff, 0xd9};
/* a frame starts with:
ffd9, 2);
/* put the JPEG 411 header */
- jpeg_put_header(gspca_dev, frame, sd_quant, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
/* beginning of the frame */
#define STKHDRSZ 12
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- data + STKHDRSZ, len - STKHDRSZ);
-#undef STKHDRSZ
- return;
+ data += STKHDRSZ;
+ len -= STKHDRSZ;
}
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
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);
+ 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 struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
- .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+ .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
- .open = sd_open,
+ .init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
-#define DVNM(name) .driver_info = (kernel_ulong_t) name
-static __devinitdata struct usb_device_id device_table[] = {
- {USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")},
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x05e1, 0x0893)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
.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)
{
- if (usb_register(&sd_driver) < 0)
- return -1;
- info("v%s registered", version);
+ int ret;
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ info("registered");
return 0;
}
static void __exit sd_mod_exit(void)
module_init(sd_mod_init);
module_exit(sd_mod_exit);
-
-module_param_named(quant, sd_quant, int, 0644);
-MODULE_PARM_DESC(quant, "Quantization index (0..8)");