Loading drivers/media/video/gspca/ov534.c +591 −85 Original line number Diff line number Diff line /* * ov534 gspca driver * * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> * Copyright (C) 2008 Jim Paris <jim@jtan.com> * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr Loading @@ -8,6 +9,8 @@ * USB protocol reverse engineered by Jim Paris <jim@jtan.com> * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ * * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.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 Loading Loading @@ -50,6 +53,14 @@ struct sd { __u32 last_pts; u16 last_fid; u8 frame_rate; u8 gain; u8 exposure; u8 redblc; u8 blueblc; u8 autogain; u8 sharpness; u8 hflip; u8 vflip; u8 sensor; #define SENSOR_OV772X 0 Loading @@ -57,10 +68,146 @@ struct sd { }; /* V4L2 controls supported by the driver */ static struct ctrl sd_ctrls[] = { static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val); static int sd_getredblc(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setblueblc(struct gspca_dev *gspca_dev, __s32 val); static int sd_getblueblc(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls_ov772x[] = { { { .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Main Gain", .minimum = 0, .maximum = 63, .step = 1, #define GAIN_DEF 20 .default_value = GAIN_DEF, }, .set = sd_setgain, .get = sd_getgain, }, { { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Exposure", .minimum = 0, .maximum = 255, .step = 1, #define EXPO_DEF 255 .default_value = EXPO_DEF, }, .set = sd_setexposure, .get = sd_getexposure, }, { { .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Red Balance", .minimum = 0, .maximum = 255, .step = 1, #define RED_BALANCE_DEF 128 .default_value = RED_BALANCE_DEF, }, .set = sd_setredblc, .get = sd_getredblc, }, { { .id = V4L2_CID_BLUE_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Blue Balance", .minimum = 0, .maximum = 255, .step = 1, #define BLUE_BALANCE_DEF 128 .default_value = BLUE_BALANCE_DEF, }, .set = sd_setblueblc, .get = sd_getblueblc, }, { { .id = V4L2_CID_AUTOGAIN, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Autogain", .minimum = 0, .maximum = 1, .step = 1, #define AUTOGAIN_DEF 1 .default_value = AUTOGAIN_DEF, }, .set = sd_setautogain, .get = sd_getautogain, }, { { .id = V4L2_CID_SHARPNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Sharpness", .minimum = 0, .maximum = 63, .step = 1, #define SHARPNESS_DEF 4 .default_value = SHARPNESS_DEF, }, .set = sd_setsharpness, .get = sd_getsharpness, }, { { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "HFlip", .minimum = 0, .maximum = 1, .step = 1, #define HFLIP_DEF 0 .default_value = HFLIP_DEF, }, .set = sd_sethflip, .get = sd_gethflip, }, { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "VFlip", .minimum = 0, .maximum = 1, .step = 1, #define VFLIP_DEF 0 .default_value = VFLIP_DEF, }, .set = sd_setvflip, .get = sd_getvflip, }, }; static struct ctrl sd_ctrls_ov965x[] = { }; static const struct v4l2_pix_format vga_yuyv_mode[] = { {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 320 * 2, .sizeimage = 320 * 240 * 2, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 640 * 2, .sizeimage = 640 * 480 * 2, Loading @@ -80,8 +227,7 @@ static const struct v4l2_pix_format vga_jpeg_mode[] = { .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; static const u8 bridge_init_ov722x[][2] = { static const u8 bridge_init_ov772x[][2] = { { 0xc2, 0x0c }, { 0x88, 0xf8 }, { 0xc3, 0x69 }, Loading Loading @@ -122,6 +268,7 @@ static const u8 bridge_init_ov722x[][2] = { { 0x1d, 0x40 }, { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */ { 0x1d, 0x00 }, /* payload size */ { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */ { 0x1d, 0x58 }, /* frame size */ { 0x1d, 0x00 }, /* frame size */ Loading @@ -138,10 +285,20 @@ static const u8 bridge_init_ov722x[][2] = { { 0xc1, 0x3c }, { 0xc2, 0x0c }, }; static const u8 sensor_init_ov722x[][2] = { static const u8 sensor_init_ov772x[][2] = { { 0x12, 0x80 }, { 0x11, 0x01 }, /*fixme: better have a delay?*/ { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x3d, 0x03 }, { 0x17, 0x26 }, Loading @@ -154,7 +311,7 @@ static const u8 sensor_init_ov722x[][2] = { { 0x65, 0x20 }, { 0x11, 0x01 }, { 0x42, 0x7f }, { 0x63, 0xe0 }, { 0x63, 0xaa }, /* was e0 */ { 0x64, 0xff }, { 0x66, 0x00 }, { 0x13, 0xf0 }, Loading Loading @@ -221,6 +378,46 @@ static const u8 sensor_init_ov722x[][2] = { { 0x8e, 0x00 }, { 0x0c, 0xd0 } }; static const u8 bridge_start_ov772x_vga[][2] = { {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, {0x1d, 0x00}, {0x1d, 0x02}, {0x1d, 0x58}, {0x1d, 0x00}, {0xc0, 0x50}, {0xc1, 0x3c}, }; static const u8 sensor_start_ov772x_vga[][2] = { {0x12, 0x00}, {0x17, 0x26}, {0x18, 0xa0}, {0x19, 0x07}, {0x1a, 0xf0}, {0x29, 0xa0}, {0x2c, 0xf0}, }; static const u8 bridge_start_ov772x_qvga[][2] = { {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, {0x1d, 0x00}, {0x1d, 0x01}, {0x1d, 0x4b}, {0x1d, 0x00}, {0xc0, 0x28}, {0xc1, 0x1e}, }; static const u8 sensor_start_ov772x_qvga[][2] = { {0x12, 0x40}, {0x17, 0x3f}, {0x18, 0x50}, {0x19, 0x03}, {0x1a, 0x78}, {0x29, 0x50}, {0x2c, 0x78}, }; static const u8 bridge_init_ov965x[][2] = { {0x88, 0xf8}, Loading Loading @@ -757,35 +954,150 @@ static void sccb_w_array(struct gspca_dev *gspca_dev, static void ov534_set_frame_rate(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int fr = sd->frame_rate; int i; struct rate_s { u8 fps; u8 r11; u8 r0d; u8 re5; }; const struct rate_s *r; static const struct rate_s rate_0[] = { /* 640x480 */ {60, 0x01, 0xc1, 0x04}, {50, 0x01, 0x41, 0x02}, {40, 0x02, 0xc1, 0x04}, {30, 0x04, 0x81, 0x02}, {15, 0x03, 0x41, 0x04}, }; static const struct rate_s rate_1[] = { /* 320x240 */ {125, 0x02, 0x81, 0x02}, {100, 0x02, 0xc1, 0x04}, {75, 0x03, 0xc1, 0x04}, {60, 0x04, 0xc1, 0x04}, {50, 0x02, 0x41, 0x04}, {40, 0x03, 0x41, 0x04}, {30, 0x04, 0x41, 0x04}, }; switch (fr) { case 50: sccb_reg_write(gspca_dev, 0x11, 0x01); sccb_reg_write(gspca_dev, 0x0d, 0x41); ov534_reg_write(gspca_dev, 0xe5, 0x02); if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) { r = rate_0; i = ARRAY_SIZE(rate_0); } else { r = rate_1; i = ARRAY_SIZE(rate_1); } while (--i > 0) { if (sd->frame_rate >= r->fps) break; case 40: sccb_reg_write(gspca_dev, 0x11, 0x02); sccb_reg_write(gspca_dev, 0x0d, 0xc1); ov534_reg_write(gspca_dev, 0xe5, 0x04); r++; } sccb_reg_write(gspca_dev, 0x11, r->r11); sccb_reg_write(gspca_dev, 0x0d, r->r0d); ov534_reg_write(gspca_dev, 0xe5, r->re5); PDEBUG(D_PROBE, "frame_rate: %d", r->fps); } /* ov772x controls */ static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; val = sd->gain; switch (val & 0x30) { case 0x00: val &= 0x0f; break; /* case 30: */ default: fr = 30; sccb_reg_write(gspca_dev, 0x11, 0x04); sccb_reg_write(gspca_dev, 0x0d, 0x81); ov534_reg_write(gspca_dev, 0xe5, 0x02); case 0x10: val &= 0x0f; val |= 0x30; break; case 15: sccb_reg_write(gspca_dev, 0x11, 0x03); sccb_reg_write(gspca_dev, 0x0d, 0x41); ov534_reg_write(gspca_dev, 0xe5, 0x04); case 0x20: val &= 0x0f; val |= 0x70; break; default: /* case 0x30: */ val &= 0x0f; val |= 0xf0; break; } sccb_reg_write(gspca_dev, 0x00, val); } static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; val = sd->exposure; sccb_reg_write(gspca_dev, 0x08, val >> 7); sccb_reg_write(gspca_dev, 0x10, val << 1); } sd->frame_rate = fr; PDEBUG(D_PROBE, "frame_rate: %d", fr); static void setredblc(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; sccb_reg_write(gspca_dev, 0x43, sd->redblc); } static void setblueblc(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; sccb_reg_write(gspca_dev, 0x42, sd->blueblc); } static void setautogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; if (sd->autogain) { sccb_reg_write(gspca_dev, 0x13, 0xf7); /* AGC,AEC,AWB ON */ sccb_reg_write(gspca_dev, 0x64, sccb_reg_read(gspca_dev, 0x64) | 0x03); } else { sccb_reg_write(gspca_dev, 0x13, 0xf0); /* AGC,AEC,AWB OFF */ sccb_reg_write(gspca_dev, 0x64, sccb_reg_read(gspca_dev, 0x64) & 0xfc); } } static void setsharpness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; val = sd->sharpness; sccb_reg_write(gspca_dev, 0x91, val); /* vga noise */ sccb_reg_write(gspca_dev, 0x8e, val); /* qvga noise */ } static void sethflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; if (sd->hflip == 0) sccb_reg_write(gspca_dev, 0x0c, sccb_reg_read(gspca_dev, 0x0c) | 0x40); else sccb_reg_write(gspca_dev, 0x0c, sccb_reg_read(gspca_dev, 0x0c) & 0xbf); } static void setvflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; if (sd->vflip == 0) sccb_reg_write(gspca_dev, 0x0c, sccb_reg_read(gspca_dev, 0x0c) | 0x80); else sccb_reg_write(gspca_dev, 0x0c, sccb_reg_read(gspca_dev, 0x0c) & 0x7f); } /* this function is called at probe time */ Loading @@ -811,6 +1123,19 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_jpeg_mode); } sd->frame_rate = 30; sd->gain = GAIN_DEF; sd->exposure = EXPO_DEF; sd->redblc = RED_BALANCE_DEF; sd->blueblc = BLUE_BALANCE_DEF; sd->autogain = AUTOGAIN_DEF; sd->sharpness = SHARPNESS_DEF; #if HFLIP_DEF != 0 sd->hflip = HFLIP_DEF; #endif #if VFLIP_DEF != 0 sd->vflip = VFLIP_DEF; #endif return 0; } Loading Loading @@ -847,11 +1172,11 @@ static int sd_init(struct gspca_dev *gspca_dev) /* initialize */ switch (sd->sensor) { case SENSOR_OV772X: reg_w_array(gspca_dev, bridge_init_ov722x, ARRAY_SIZE(bridge_init_ov722x)); reg_w_array(gspca_dev, bridge_init_ov772x, ARRAY_SIZE(bridge_init_ov772x)); ov534_set_led(gspca_dev, 1); sccb_w_array(gspca_dev, sensor_init_ov722x, ARRAY_SIZE(sensor_init_ov722x)); sccb_w_array(gspca_dev, sensor_init_ov772x, ARRAY_SIZE(sensor_init_ov772x)); ov534_reg_write(gspca_dev, 0xe0, 0x09); ov534_set_led(gspca_dev, 0); ov534_set_frame_rate(gspca_dev); Loading @@ -875,23 +1200,47 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } static int sd_start(struct gspca_dev *gspca_dev) static int sd_start_ov772x(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int mode; switch (sd->sensor) { case SENSOR_OV772X: mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; if (mode != 0) { /* 320x240 */ reg_w_array(gspca_dev, bridge_start_ov772x_qvga, ARRAY_SIZE(bridge_start_ov772x_qvga)); sccb_w_array(gspca_dev, sensor_start_ov772x_qvga, ARRAY_SIZE(sensor_start_ov772x_qvga)); } else { /* 640x480 */ reg_w_array(gspca_dev, bridge_start_ov772x_vga, ARRAY_SIZE(bridge_start_ov772x_vga)); sccb_w_array(gspca_dev, sensor_start_ov772x_vga, ARRAY_SIZE(sensor_start_ov772x_vga)); } ov534_set_frame_rate(gspca_dev); setautogain(gspca_dev); setgain(gspca_dev); setredblc(gspca_dev); setblueblc(gspca_dev); setexposure(gspca_dev); setsharpness(gspca_dev); setvflip(gspca_dev); sethflip(gspca_dev); ov534_set_led(gspca_dev, 1); ov534_reg_write(gspca_dev, 0xe0, 0x00); break; default: /* case SENSOR_OV965X: */ return 0; } static int sd_start_ov965x(struct gspca_dev *gspca_dev) { int mode; sccb_w_array(gspca_dev, sensor_start_ov965x, ARRAY_SIZE(sensor_start_ov965x)); reg_w_array(gspca_dev, bridge_start_ov965x, ARRAY_SIZE(bridge_start_ov965x)); mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; if (mode != 0) { /* 320x240 */ reg_w_array(gspca_dev, bridge_start_ov965x_cif, Loading @@ -909,26 +1258,20 @@ static int sd_start(struct gspca_dev *gspca_dev) ov534_reg_write(gspca_dev, 0xe0, 0x00); ov534_reg_write(gspca_dev, 0xe0, 0x00); ov534_set_led(gspca_dev, 1); } return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stopN_ov772x(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; switch (sd->sensor) { case SENSOR_OV772X: ov534_reg_write(gspca_dev, 0xe0, 0x09); ov534_set_led(gspca_dev, 0); break; default: /* case SENSOR_OV965X: */ } static void sd_stopN_ov965x(struct gspca_dev *gspca_dev) { ov534_reg_write(gspca_dev, 0xe0, 0x01); ov534_set_led(gspca_dev, 0); ov534_reg_write(gspca_dev, 0xe0, 0x00); break; } } /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ Loading Loading @@ -1002,7 +1345,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, data + 12, len - 12); } /* Done this payload */ goto scan_next; Loading @@ -1016,6 +1358,151 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, } while (remaining_len > 0); } /* ov772x controls */ static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->gain = val; if (gspca_dev->streaming) setgain(gspca_dev); return 0; } static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->gain; return 0; } static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->exposure = val; if (gspca_dev->streaming) setexposure(gspca_dev); return 0; } static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->exposure; return 0; } static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->redblc = val; if (gspca_dev->streaming) setredblc(gspca_dev); return 0; } static int sd_getredblc(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->redblc; return 0; } static int sd_setblueblc(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->blueblc = val; if (gspca_dev->streaming) setblueblc(gspca_dev); return 0; } static int sd_getblueblc(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->blueblc; return 0; } static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; if (gspca_dev->streaming) setautogain(gspca_dev); return 0; } static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->autogain; return 0; } static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->sharpness = val; if (gspca_dev->streaming) setsharpness(gspca_dev); return 0; } static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->sharpness; return 0; } static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->hflip = val; if (gspca_dev->streaming) sethflip(gspca_dev); return 0; } static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->hflip; return 0; } static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->vflip = val; if (gspca_dev->streaming) setvflip(gspca_dev); return 0; } static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->vflip; return 0; } /* get stream parameters (framerate) */ static int sd_get_streamparm(struct gspca_dev *gspca_dev, struct v4l2_streamparm *parm) Loading Loading @@ -1047,6 +1534,7 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev, /* Set requested framerate */ sd->frame_rate = tpf->denominator / tpf->numerator; if (gspca_dev->streaming) ov534_set_frame_rate(gspca_dev); /* Return the actual framerate */ Loading @@ -1057,14 +1545,27 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev, } /* sub-driver description */ static const struct sd_desc sd_desc = { static const struct sd_desc sd_desc_ov772x = { .name = MODULE_NAME, .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .ctrls = sd_ctrls_ov772x, .nctrls = ARRAY_SIZE(sd_ctrls_ov772x), .config = sd_config, .init = sd_init, .start = sd_start, .stopN = sd_stopN, .start = sd_start_ov772x, .stopN = sd_stopN_ov772x, .pkt_scan = sd_pkt_scan, .get_streamparm = sd_get_streamparm, .set_streamparm = sd_set_streamparm, }; static const struct sd_desc sd_desc_ov965x = { .name = MODULE_NAME, .ctrls = sd_ctrls_ov965x, .nctrls = ARRAY_SIZE(sd_ctrls_ov965x), .config = sd_config, .init = sd_init, .start = sd_start_ov965x, .stopN = sd_stopN_ov965x, .pkt_scan = sd_pkt_scan, .get_streamparm = sd_get_streamparm, .set_streamparm = sd_set_streamparm, Loading @@ -1082,7 +1583,11 @@ 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), return gspca_dev_probe(intf, id, id->driver_info == SENSOR_OV772X ? &sd_desc_ov772x : &sd_desc_ov965x, sizeof(struct sd), THIS_MODULE); } Loading @@ -1101,6 +1606,7 @@ static struct usb_driver sd_driver = { static int __init sd_mod_init(void) { int ret; ret = usb_register(&sd_driver); if (ret < 0) return ret; Loading Loading
drivers/media/video/gspca/ov534.c +591 −85 Original line number Diff line number Diff line /* * ov534 gspca driver * * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> * Copyright (C) 2008 Jim Paris <jim@jtan.com> * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr Loading @@ -8,6 +9,8 @@ * USB protocol reverse engineered by Jim Paris <jim@jtan.com> * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ * * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.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 Loading Loading @@ -50,6 +53,14 @@ struct sd { __u32 last_pts; u16 last_fid; u8 frame_rate; u8 gain; u8 exposure; u8 redblc; u8 blueblc; u8 autogain; u8 sharpness; u8 hflip; u8 vflip; u8 sensor; #define SENSOR_OV772X 0 Loading @@ -57,10 +68,146 @@ struct sd { }; /* V4L2 controls supported by the driver */ static struct ctrl sd_ctrls[] = { static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val); static int sd_getredblc(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setblueblc(struct gspca_dev *gspca_dev, __s32 val); static int sd_getblueblc(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls_ov772x[] = { { { .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Main Gain", .minimum = 0, .maximum = 63, .step = 1, #define GAIN_DEF 20 .default_value = GAIN_DEF, }, .set = sd_setgain, .get = sd_getgain, }, { { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Exposure", .minimum = 0, .maximum = 255, .step = 1, #define EXPO_DEF 255 .default_value = EXPO_DEF, }, .set = sd_setexposure, .get = sd_getexposure, }, { { .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Red Balance", .minimum = 0, .maximum = 255, .step = 1, #define RED_BALANCE_DEF 128 .default_value = RED_BALANCE_DEF, }, .set = sd_setredblc, .get = sd_getredblc, }, { { .id = V4L2_CID_BLUE_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Blue Balance", .minimum = 0, .maximum = 255, .step = 1, #define BLUE_BALANCE_DEF 128 .default_value = BLUE_BALANCE_DEF, }, .set = sd_setblueblc, .get = sd_getblueblc, }, { { .id = V4L2_CID_AUTOGAIN, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Autogain", .minimum = 0, .maximum = 1, .step = 1, #define AUTOGAIN_DEF 1 .default_value = AUTOGAIN_DEF, }, .set = sd_setautogain, .get = sd_getautogain, }, { { .id = V4L2_CID_SHARPNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Sharpness", .minimum = 0, .maximum = 63, .step = 1, #define SHARPNESS_DEF 4 .default_value = SHARPNESS_DEF, }, .set = sd_setsharpness, .get = sd_getsharpness, }, { { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "HFlip", .minimum = 0, .maximum = 1, .step = 1, #define HFLIP_DEF 0 .default_value = HFLIP_DEF, }, .set = sd_sethflip, .get = sd_gethflip, }, { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "VFlip", .minimum = 0, .maximum = 1, .step = 1, #define VFLIP_DEF 0 .default_value = VFLIP_DEF, }, .set = sd_setvflip, .get = sd_getvflip, }, }; static struct ctrl sd_ctrls_ov965x[] = { }; static const struct v4l2_pix_format vga_yuyv_mode[] = { {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 320 * 2, .sizeimage = 320 * 240 * 2, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 640 * 2, .sizeimage = 640 * 480 * 2, Loading @@ -80,8 +227,7 @@ static const struct v4l2_pix_format vga_jpeg_mode[] = { .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; static const u8 bridge_init_ov722x[][2] = { static const u8 bridge_init_ov772x[][2] = { { 0xc2, 0x0c }, { 0x88, 0xf8 }, { 0xc3, 0x69 }, Loading Loading @@ -122,6 +268,7 @@ static const u8 bridge_init_ov722x[][2] = { { 0x1d, 0x40 }, { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */ { 0x1d, 0x00 }, /* payload size */ { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */ { 0x1d, 0x58 }, /* frame size */ { 0x1d, 0x00 }, /* frame size */ Loading @@ -138,10 +285,20 @@ static const u8 bridge_init_ov722x[][2] = { { 0xc1, 0x3c }, { 0xc2, 0x0c }, }; static const u8 sensor_init_ov722x[][2] = { static const u8 sensor_init_ov772x[][2] = { { 0x12, 0x80 }, { 0x11, 0x01 }, /*fixme: better have a delay?*/ { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x11, 0x01 }, { 0x3d, 0x03 }, { 0x17, 0x26 }, Loading @@ -154,7 +311,7 @@ static const u8 sensor_init_ov722x[][2] = { { 0x65, 0x20 }, { 0x11, 0x01 }, { 0x42, 0x7f }, { 0x63, 0xe0 }, { 0x63, 0xaa }, /* was e0 */ { 0x64, 0xff }, { 0x66, 0x00 }, { 0x13, 0xf0 }, Loading Loading @@ -221,6 +378,46 @@ static const u8 sensor_init_ov722x[][2] = { { 0x8e, 0x00 }, { 0x0c, 0xd0 } }; static const u8 bridge_start_ov772x_vga[][2] = { {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, {0x1d, 0x00}, {0x1d, 0x02}, {0x1d, 0x58}, {0x1d, 0x00}, {0xc0, 0x50}, {0xc1, 0x3c}, }; static const u8 sensor_start_ov772x_vga[][2] = { {0x12, 0x00}, {0x17, 0x26}, {0x18, 0xa0}, {0x19, 0x07}, {0x1a, 0xf0}, {0x29, 0xa0}, {0x2c, 0xf0}, }; static const u8 bridge_start_ov772x_qvga[][2] = { {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, {0x1d, 0x00}, {0x1d, 0x01}, {0x1d, 0x4b}, {0x1d, 0x00}, {0xc0, 0x28}, {0xc1, 0x1e}, }; static const u8 sensor_start_ov772x_qvga[][2] = { {0x12, 0x40}, {0x17, 0x3f}, {0x18, 0x50}, {0x19, 0x03}, {0x1a, 0x78}, {0x29, 0x50}, {0x2c, 0x78}, }; static const u8 bridge_init_ov965x[][2] = { {0x88, 0xf8}, Loading Loading @@ -757,35 +954,150 @@ static void sccb_w_array(struct gspca_dev *gspca_dev, static void ov534_set_frame_rate(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int fr = sd->frame_rate; int i; struct rate_s { u8 fps; u8 r11; u8 r0d; u8 re5; }; const struct rate_s *r; static const struct rate_s rate_0[] = { /* 640x480 */ {60, 0x01, 0xc1, 0x04}, {50, 0x01, 0x41, 0x02}, {40, 0x02, 0xc1, 0x04}, {30, 0x04, 0x81, 0x02}, {15, 0x03, 0x41, 0x04}, }; static const struct rate_s rate_1[] = { /* 320x240 */ {125, 0x02, 0x81, 0x02}, {100, 0x02, 0xc1, 0x04}, {75, 0x03, 0xc1, 0x04}, {60, 0x04, 0xc1, 0x04}, {50, 0x02, 0x41, 0x04}, {40, 0x03, 0x41, 0x04}, {30, 0x04, 0x41, 0x04}, }; switch (fr) { case 50: sccb_reg_write(gspca_dev, 0x11, 0x01); sccb_reg_write(gspca_dev, 0x0d, 0x41); ov534_reg_write(gspca_dev, 0xe5, 0x02); if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) { r = rate_0; i = ARRAY_SIZE(rate_0); } else { r = rate_1; i = ARRAY_SIZE(rate_1); } while (--i > 0) { if (sd->frame_rate >= r->fps) break; case 40: sccb_reg_write(gspca_dev, 0x11, 0x02); sccb_reg_write(gspca_dev, 0x0d, 0xc1); ov534_reg_write(gspca_dev, 0xe5, 0x04); r++; } sccb_reg_write(gspca_dev, 0x11, r->r11); sccb_reg_write(gspca_dev, 0x0d, r->r0d); ov534_reg_write(gspca_dev, 0xe5, r->re5); PDEBUG(D_PROBE, "frame_rate: %d", r->fps); } /* ov772x controls */ static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; val = sd->gain; switch (val & 0x30) { case 0x00: val &= 0x0f; break; /* case 30: */ default: fr = 30; sccb_reg_write(gspca_dev, 0x11, 0x04); sccb_reg_write(gspca_dev, 0x0d, 0x81); ov534_reg_write(gspca_dev, 0xe5, 0x02); case 0x10: val &= 0x0f; val |= 0x30; break; case 15: sccb_reg_write(gspca_dev, 0x11, 0x03); sccb_reg_write(gspca_dev, 0x0d, 0x41); ov534_reg_write(gspca_dev, 0xe5, 0x04); case 0x20: val &= 0x0f; val |= 0x70; break; default: /* case 0x30: */ val &= 0x0f; val |= 0xf0; break; } sccb_reg_write(gspca_dev, 0x00, val); } static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; val = sd->exposure; sccb_reg_write(gspca_dev, 0x08, val >> 7); sccb_reg_write(gspca_dev, 0x10, val << 1); } sd->frame_rate = fr; PDEBUG(D_PROBE, "frame_rate: %d", fr); static void setredblc(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; sccb_reg_write(gspca_dev, 0x43, sd->redblc); } static void setblueblc(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; sccb_reg_write(gspca_dev, 0x42, sd->blueblc); } static void setautogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; if (sd->autogain) { sccb_reg_write(gspca_dev, 0x13, 0xf7); /* AGC,AEC,AWB ON */ sccb_reg_write(gspca_dev, 0x64, sccb_reg_read(gspca_dev, 0x64) | 0x03); } else { sccb_reg_write(gspca_dev, 0x13, 0xf0); /* AGC,AEC,AWB OFF */ sccb_reg_write(gspca_dev, 0x64, sccb_reg_read(gspca_dev, 0x64) & 0xfc); } } static void setsharpness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 val; val = sd->sharpness; sccb_reg_write(gspca_dev, 0x91, val); /* vga noise */ sccb_reg_write(gspca_dev, 0x8e, val); /* qvga noise */ } static void sethflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; if (sd->hflip == 0) sccb_reg_write(gspca_dev, 0x0c, sccb_reg_read(gspca_dev, 0x0c) | 0x40); else sccb_reg_write(gspca_dev, 0x0c, sccb_reg_read(gspca_dev, 0x0c) & 0xbf); } static void setvflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; if (sd->vflip == 0) sccb_reg_write(gspca_dev, 0x0c, sccb_reg_read(gspca_dev, 0x0c) | 0x80); else sccb_reg_write(gspca_dev, 0x0c, sccb_reg_read(gspca_dev, 0x0c) & 0x7f); } /* this function is called at probe time */ Loading @@ -811,6 +1123,19 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_jpeg_mode); } sd->frame_rate = 30; sd->gain = GAIN_DEF; sd->exposure = EXPO_DEF; sd->redblc = RED_BALANCE_DEF; sd->blueblc = BLUE_BALANCE_DEF; sd->autogain = AUTOGAIN_DEF; sd->sharpness = SHARPNESS_DEF; #if HFLIP_DEF != 0 sd->hflip = HFLIP_DEF; #endif #if VFLIP_DEF != 0 sd->vflip = VFLIP_DEF; #endif return 0; } Loading Loading @@ -847,11 +1172,11 @@ static int sd_init(struct gspca_dev *gspca_dev) /* initialize */ switch (sd->sensor) { case SENSOR_OV772X: reg_w_array(gspca_dev, bridge_init_ov722x, ARRAY_SIZE(bridge_init_ov722x)); reg_w_array(gspca_dev, bridge_init_ov772x, ARRAY_SIZE(bridge_init_ov772x)); ov534_set_led(gspca_dev, 1); sccb_w_array(gspca_dev, sensor_init_ov722x, ARRAY_SIZE(sensor_init_ov722x)); sccb_w_array(gspca_dev, sensor_init_ov772x, ARRAY_SIZE(sensor_init_ov772x)); ov534_reg_write(gspca_dev, 0xe0, 0x09); ov534_set_led(gspca_dev, 0); ov534_set_frame_rate(gspca_dev); Loading @@ -875,23 +1200,47 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } static int sd_start(struct gspca_dev *gspca_dev) static int sd_start_ov772x(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int mode; switch (sd->sensor) { case SENSOR_OV772X: mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; if (mode != 0) { /* 320x240 */ reg_w_array(gspca_dev, bridge_start_ov772x_qvga, ARRAY_SIZE(bridge_start_ov772x_qvga)); sccb_w_array(gspca_dev, sensor_start_ov772x_qvga, ARRAY_SIZE(sensor_start_ov772x_qvga)); } else { /* 640x480 */ reg_w_array(gspca_dev, bridge_start_ov772x_vga, ARRAY_SIZE(bridge_start_ov772x_vga)); sccb_w_array(gspca_dev, sensor_start_ov772x_vga, ARRAY_SIZE(sensor_start_ov772x_vga)); } ov534_set_frame_rate(gspca_dev); setautogain(gspca_dev); setgain(gspca_dev); setredblc(gspca_dev); setblueblc(gspca_dev); setexposure(gspca_dev); setsharpness(gspca_dev); setvflip(gspca_dev); sethflip(gspca_dev); ov534_set_led(gspca_dev, 1); ov534_reg_write(gspca_dev, 0xe0, 0x00); break; default: /* case SENSOR_OV965X: */ return 0; } static int sd_start_ov965x(struct gspca_dev *gspca_dev) { int mode; sccb_w_array(gspca_dev, sensor_start_ov965x, ARRAY_SIZE(sensor_start_ov965x)); reg_w_array(gspca_dev, bridge_start_ov965x, ARRAY_SIZE(bridge_start_ov965x)); mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; if (mode != 0) { /* 320x240 */ reg_w_array(gspca_dev, bridge_start_ov965x_cif, Loading @@ -909,26 +1258,20 @@ static int sd_start(struct gspca_dev *gspca_dev) ov534_reg_write(gspca_dev, 0xe0, 0x00); ov534_reg_write(gspca_dev, 0xe0, 0x00); ov534_set_led(gspca_dev, 1); } return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stopN_ov772x(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; switch (sd->sensor) { case SENSOR_OV772X: ov534_reg_write(gspca_dev, 0xe0, 0x09); ov534_set_led(gspca_dev, 0); break; default: /* case SENSOR_OV965X: */ } static void sd_stopN_ov965x(struct gspca_dev *gspca_dev) { ov534_reg_write(gspca_dev, 0xe0, 0x01); ov534_set_led(gspca_dev, 0); ov534_reg_write(gspca_dev, 0xe0, 0x00); break; } } /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ Loading Loading @@ -1002,7 +1345,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, data + 12, len - 12); } /* Done this payload */ goto scan_next; Loading @@ -1016,6 +1358,151 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, } while (remaining_len > 0); } /* ov772x controls */ static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->gain = val; if (gspca_dev->streaming) setgain(gspca_dev); return 0; } static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->gain; return 0; } static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->exposure = val; if (gspca_dev->streaming) setexposure(gspca_dev); return 0; } static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->exposure; return 0; } static int sd_setredblc(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->redblc = val; if (gspca_dev->streaming) setredblc(gspca_dev); return 0; } static int sd_getredblc(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->redblc; return 0; } static int sd_setblueblc(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->blueblc = val; if (gspca_dev->streaming) setblueblc(gspca_dev); return 0; } static int sd_getblueblc(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->blueblc; return 0; } static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; if (gspca_dev->streaming) setautogain(gspca_dev); return 0; } static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->autogain; return 0; } static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->sharpness = val; if (gspca_dev->streaming) setsharpness(gspca_dev); return 0; } static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->sharpness; return 0; } static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->hflip = val; if (gspca_dev->streaming) sethflip(gspca_dev); return 0; } static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->hflip; return 0; } static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->vflip = val; if (gspca_dev->streaming) setvflip(gspca_dev); return 0; } static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; *val = sd->vflip; return 0; } /* get stream parameters (framerate) */ static int sd_get_streamparm(struct gspca_dev *gspca_dev, struct v4l2_streamparm *parm) Loading Loading @@ -1047,6 +1534,7 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev, /* Set requested framerate */ sd->frame_rate = tpf->denominator / tpf->numerator; if (gspca_dev->streaming) ov534_set_frame_rate(gspca_dev); /* Return the actual framerate */ Loading @@ -1057,14 +1545,27 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev, } /* sub-driver description */ static const struct sd_desc sd_desc = { static const struct sd_desc sd_desc_ov772x = { .name = MODULE_NAME, .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .ctrls = sd_ctrls_ov772x, .nctrls = ARRAY_SIZE(sd_ctrls_ov772x), .config = sd_config, .init = sd_init, .start = sd_start, .stopN = sd_stopN, .start = sd_start_ov772x, .stopN = sd_stopN_ov772x, .pkt_scan = sd_pkt_scan, .get_streamparm = sd_get_streamparm, .set_streamparm = sd_set_streamparm, }; static const struct sd_desc sd_desc_ov965x = { .name = MODULE_NAME, .ctrls = sd_ctrls_ov965x, .nctrls = ARRAY_SIZE(sd_ctrls_ov965x), .config = sd_config, .init = sd_init, .start = sd_start_ov965x, .stopN = sd_stopN_ov965x, .pkt_scan = sd_pkt_scan, .get_streamparm = sd_get_streamparm, .set_streamparm = sd_set_streamparm, Loading @@ -1082,7 +1583,11 @@ 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), return gspca_dev_probe(intf, id, id->driver_info == SENSOR_OV772X ? &sd_desc_ov772x : &sd_desc_ov965x, sizeof(struct sd), THIS_MODULE); } Loading @@ -1101,6 +1606,7 @@ static struct usb_driver sd_driver = { static int __init sd_mod_init(void) { int ret; ret = usb_register(&sd_driver); if (ret < 0) return ret; Loading