1*fd9871f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 23040b043STheodore Kilgore /* 33040b043STheodore Kilgore * Jeilinj subdriver 43040b043STheodore Kilgore * 53040b043STheodore Kilgore * Supports some Jeilin dual-mode cameras which use bulk transport and 63040b043STheodore Kilgore * download raw JPEG data. 73040b043STheodore Kilgore * 83040b043STheodore Kilgore * Copyright (C) 2009 Theodore Kilgore 95396e62fSPatrice Chotard * 105396e62fSPatrice Chotard * Sportscam DV15 support and control settings are 11c3d86927SPatrice Chotard * Copyright (C) 2011 Patrice Chotard 123040b043STheodore Kilgore */ 133040b043STheodore Kilgore 14133a9fe9SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15133a9fe9SJoe Perches 163040b043STheodore Kilgore #define MODULE_NAME "jeilinj" 173040b043STheodore Kilgore 185a0e3ad6STejun Heo #include <linux/slab.h> 193040b043STheodore Kilgore #include "gspca.h" 203040b043STheodore Kilgore #include "jpeg.h" 213040b043STheodore Kilgore 223040b043STheodore Kilgore MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>"); 233040b043STheodore Kilgore MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver"); 243040b043STheodore Kilgore MODULE_LICENSE("GPL"); 253040b043STheodore Kilgore 263040b043STheodore Kilgore /* Default timeouts, in ms */ 273040b043STheodore Kilgore #define JEILINJ_CMD_TIMEOUT 500 28713b466fSPatrice Chotard #define JEILINJ_CMD_DELAY 160 293040b043STheodore Kilgore #define JEILINJ_DATA_TIMEOUT 1000 303040b043STheodore Kilgore 313040b043STheodore Kilgore /* Maximum transfer size to use. */ 323040b043STheodore Kilgore #define JEILINJ_MAX_TRANSFER 0x200 333040b043STheodore Kilgore #define FRAME_HEADER_LEN 0x10 34c3d86927SPatrice Chotard #define FRAME_START 0xFFFFFFFF 353040b043STheodore Kilgore 36713b466fSPatrice Chotard enum { 37713b466fSPatrice Chotard SAKAR_57379, 38713b466fSPatrice Chotard SPORTSCAM_DV15, 39713b466fSPatrice Chotard }; 405396e62fSPatrice Chotard 415396e62fSPatrice Chotard #define CAMQUALITY_MIN 0 /* highest cam quality */ 425396e62fSPatrice Chotard #define CAMQUALITY_MAX 97 /* lowest cam quality */ 435396e62fSPatrice Chotard 443040b043STheodore Kilgore /* Structure to hold all of our device specific stuff */ 453040b043STheodore Kilgore struct sd { 463040b043STheodore Kilgore struct gspca_dev gspca_dev; /* !! must be the first item */ 47c3d86927SPatrice Chotard int blocks_left; 483040b043STheodore Kilgore const struct v4l2_pix_format *cap_mode; 49bfaab899SHans Verkuil struct v4l2_ctrl *freq; 50bfaab899SHans Verkuil struct v4l2_ctrl *jpegqual; 513040b043STheodore Kilgore /* Driver stuff */ 52713b466fSPatrice Chotard u8 type; 533040b043STheodore Kilgore u8 quality; /* image quality */ 545396e62fSPatrice Chotard #define QUALITY_MIN 35 555396e62fSPatrice Chotard #define QUALITY_MAX 85 565396e62fSPatrice Chotard #define QUALITY_DEF 85 579a731a32SJean-François Moine u8 jpeg_hdr[JPEG_HDR_SZ]; 583040b043STheodore Kilgore }; 593040b043STheodore Kilgore 603040b043STheodore Kilgore struct jlj_command { 613040b043STheodore Kilgore unsigned char instruction[2]; 623040b043STheodore Kilgore unsigned char ack_wanted; 63713b466fSPatrice Chotard unsigned char delay; 643040b043STheodore Kilgore }; 653040b043STheodore Kilgore 663040b043STheodore Kilgore /* AFAICT these cameras will only do 320x240. */ 673040b043STheodore Kilgore static struct v4l2_pix_format jlj_mode[] = { 683040b043STheodore Kilgore { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 693040b043STheodore Kilgore .bytesperline = 320, 703040b043STheodore Kilgore .sizeimage = 320 * 240, 713040b043STheodore Kilgore .colorspace = V4L2_COLORSPACE_JPEG, 726f8efcfbSPatrice Chotard .priv = 0}, 736f8efcfbSPatrice Chotard { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 746f8efcfbSPatrice Chotard .bytesperline = 640, 756f8efcfbSPatrice Chotard .sizeimage = 640 * 480, 766f8efcfbSPatrice Chotard .colorspace = V4L2_COLORSPACE_JPEG, 773040b043STheodore Kilgore .priv = 0} 783040b043STheodore Kilgore }; 793040b043STheodore Kilgore 803040b043STheodore Kilgore /* 813040b043STheodore Kilgore * cam uses endpoint 0x03 to send commands, 0x84 for read commands, 823040b043STheodore Kilgore * and 0x82 for bulk transfer. 833040b043STheodore Kilgore */ 843040b043STheodore Kilgore 853040b043STheodore Kilgore /* All commands are two bytes only */ 868715b16eSPatrice Chotard static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) 873040b043STheodore Kilgore { 883040b043STheodore Kilgore int retval; 893040b043STheodore Kilgore 908715b16eSPatrice Chotard if (gspca_dev->usb_err < 0) 918715b16eSPatrice Chotard return; 923040b043STheodore Kilgore memcpy(gspca_dev->usb_buf, command, 2); 933040b043STheodore Kilgore retval = usb_bulk_msg(gspca_dev->dev, 943040b043STheodore Kilgore usb_sndbulkpipe(gspca_dev->dev, 3), 953040b043STheodore Kilgore gspca_dev->usb_buf, 2, NULL, 500); 968715b16eSPatrice Chotard if (retval < 0) { 97133a9fe9SJoe Perches pr_err("command write [%02x] error %d\n", 983040b043STheodore Kilgore gspca_dev->usb_buf[0], retval); 998715b16eSPatrice Chotard gspca_dev->usb_err = retval; 1008715b16eSPatrice Chotard } 1013040b043STheodore Kilgore } 1023040b043STheodore Kilgore 1033040b043STheodore Kilgore /* Responses are one byte only */ 1049825f376SMauro Carvalho Chehab static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char *response) 1053040b043STheodore Kilgore { 1063040b043STheodore Kilgore int retval; 1073040b043STheodore Kilgore 1088715b16eSPatrice Chotard if (gspca_dev->usb_err < 0) 1098715b16eSPatrice Chotard return; 1103040b043STheodore Kilgore retval = usb_bulk_msg(gspca_dev->dev, 1113040b043STheodore Kilgore usb_rcvbulkpipe(gspca_dev->dev, 0x84), 1123040b043STheodore Kilgore gspca_dev->usb_buf, 1, NULL, 500); 1139825f376SMauro Carvalho Chehab *response = gspca_dev->usb_buf[0]; 1148715b16eSPatrice Chotard if (retval < 0) { 115133a9fe9SJoe Perches pr_err("read command [%02x] error %d\n", 1163040b043STheodore Kilgore gspca_dev->usb_buf[0], retval); 1178715b16eSPatrice Chotard gspca_dev->usb_err = retval; 1188715b16eSPatrice Chotard } 1193040b043STheodore Kilgore } 1203040b043STheodore Kilgore 121bfaab899SHans Verkuil static void setfreq(struct gspca_dev *gspca_dev, s32 val) 1225396e62fSPatrice Chotard { 1235396e62fSPatrice Chotard u8 freq_commands[][2] = { 1245396e62fSPatrice Chotard {0x71, 0x80}, 1255396e62fSPatrice Chotard {0x70, 0x07} 1265396e62fSPatrice Chotard }; 1275396e62fSPatrice Chotard 128bfaab899SHans Verkuil freq_commands[0][1] |= val >> 1; 1295396e62fSPatrice Chotard 1305396e62fSPatrice Chotard jlj_write2(gspca_dev, freq_commands[0]); 1315396e62fSPatrice Chotard jlj_write2(gspca_dev, freq_commands[1]); 1325396e62fSPatrice Chotard } 1335396e62fSPatrice Chotard 134bfaab899SHans Verkuil static void setcamquality(struct gspca_dev *gspca_dev, s32 val) 1355396e62fSPatrice Chotard { 1365396e62fSPatrice Chotard u8 quality_commands[][2] = { 1375396e62fSPatrice Chotard {0x71, 0x1E}, 1385396e62fSPatrice Chotard {0x70, 0x06} 1395396e62fSPatrice Chotard }; 1405396e62fSPatrice Chotard u8 camquality; 1415396e62fSPatrice Chotard 1425396e62fSPatrice Chotard /* adapt camera quality from jpeg quality */ 143bfaab899SHans Verkuil camquality = ((QUALITY_MAX - val) * CAMQUALITY_MAX) 1445396e62fSPatrice Chotard / (QUALITY_MAX - QUALITY_MIN); 1455396e62fSPatrice Chotard quality_commands[0][1] += camquality; 1465396e62fSPatrice Chotard 1475396e62fSPatrice Chotard jlj_write2(gspca_dev, quality_commands[0]); 1485396e62fSPatrice Chotard jlj_write2(gspca_dev, quality_commands[1]); 1495396e62fSPatrice Chotard } 1505396e62fSPatrice Chotard 151bfaab899SHans Verkuil static void setautogain(struct gspca_dev *gspca_dev, s32 val) 1525396e62fSPatrice Chotard { 1535396e62fSPatrice Chotard u8 autogain_commands[][2] = { 1545396e62fSPatrice Chotard {0x94, 0x02}, 1555396e62fSPatrice Chotard {0xcf, 0x00} 1565396e62fSPatrice Chotard }; 1575396e62fSPatrice Chotard 158bfaab899SHans Verkuil autogain_commands[1][1] = val << 4; 1595396e62fSPatrice Chotard 1605396e62fSPatrice Chotard jlj_write2(gspca_dev, autogain_commands[0]); 1615396e62fSPatrice Chotard jlj_write2(gspca_dev, autogain_commands[1]); 1625396e62fSPatrice Chotard } 1635396e62fSPatrice Chotard 164bfaab899SHans Verkuil static void setred(struct gspca_dev *gspca_dev, s32 val) 1655396e62fSPatrice Chotard { 1665396e62fSPatrice Chotard u8 setred_commands[][2] = { 1675396e62fSPatrice Chotard {0x94, 0x02}, 1685396e62fSPatrice Chotard {0xe6, 0x00} 1695396e62fSPatrice Chotard }; 1705396e62fSPatrice Chotard 171bfaab899SHans Verkuil setred_commands[1][1] = val; 1725396e62fSPatrice Chotard 1735396e62fSPatrice Chotard jlj_write2(gspca_dev, setred_commands[0]); 1745396e62fSPatrice Chotard jlj_write2(gspca_dev, setred_commands[1]); 1755396e62fSPatrice Chotard } 1765396e62fSPatrice Chotard 177bfaab899SHans Verkuil static void setgreen(struct gspca_dev *gspca_dev, s32 val) 1785396e62fSPatrice Chotard { 1795396e62fSPatrice Chotard u8 setgreen_commands[][2] = { 1805396e62fSPatrice Chotard {0x94, 0x02}, 1815396e62fSPatrice Chotard {0xe7, 0x00} 1825396e62fSPatrice Chotard }; 1835396e62fSPatrice Chotard 184bfaab899SHans Verkuil setgreen_commands[1][1] = val; 1855396e62fSPatrice Chotard 1865396e62fSPatrice Chotard jlj_write2(gspca_dev, setgreen_commands[0]); 1875396e62fSPatrice Chotard jlj_write2(gspca_dev, setgreen_commands[1]); 1885396e62fSPatrice Chotard } 1895396e62fSPatrice Chotard 190bfaab899SHans Verkuil static void setblue(struct gspca_dev *gspca_dev, s32 val) 1915396e62fSPatrice Chotard { 1925396e62fSPatrice Chotard u8 setblue_commands[][2] = { 1935396e62fSPatrice Chotard {0x94, 0x02}, 1945396e62fSPatrice Chotard {0xe9, 0x00} 1955396e62fSPatrice Chotard }; 1965396e62fSPatrice Chotard 197bfaab899SHans Verkuil setblue_commands[1][1] = val; 1985396e62fSPatrice Chotard 1995396e62fSPatrice Chotard jlj_write2(gspca_dev, setblue_commands[0]); 2005396e62fSPatrice Chotard jlj_write2(gspca_dev, setblue_commands[1]); 2015396e62fSPatrice Chotard } 2025396e62fSPatrice Chotard 2033040b043STheodore Kilgore static int jlj_start(struct gspca_dev *gspca_dev) 2043040b043STheodore Kilgore { 2053040b043STheodore Kilgore int i; 206713b466fSPatrice Chotard int start_commands_size; 2073040b043STheodore Kilgore u8 response = 0xff; 208c3d86927SPatrice Chotard struct sd *sd = (struct sd *) gspca_dev; 2093040b043STheodore Kilgore struct jlj_command start_commands[] = { 210713b466fSPatrice Chotard {{0x71, 0x81}, 0, 0}, 211713b466fSPatrice Chotard {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY}, 212713b466fSPatrice Chotard {{0x95, 0x70}, 1, 0}, 213713b466fSPatrice Chotard {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0}, 214713b466fSPatrice Chotard {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY}, 215713b466fSPatrice Chotard {{0x95, 0x70}, 1, 0}, 216713b466fSPatrice Chotard {{0x71, 0x00}, 0, 0}, /* start streaming ??*/ 217713b466fSPatrice Chotard {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY}, 218713b466fSPatrice Chotard {{0x95, 0x70}, 1, 0}, 219713b466fSPatrice Chotard #define SPORTSCAM_DV15_CMD_SIZE 9 220713b466fSPatrice Chotard {{0x94, 0x02}, 0, 0}, 221713b466fSPatrice Chotard {{0xde, 0x24}, 0, 0}, 222713b466fSPatrice Chotard {{0x94, 0x02}, 0, 0}, 223713b466fSPatrice Chotard {{0xdd, 0xf0}, 0, 0}, 224713b466fSPatrice Chotard {{0x94, 0x02}, 0, 0}, 225713b466fSPatrice Chotard {{0xe3, 0x2c}, 0, 0}, 226713b466fSPatrice Chotard {{0x94, 0x02}, 0, 0}, 227713b466fSPatrice Chotard {{0xe4, 0x00}, 0, 0}, 228713b466fSPatrice Chotard {{0x94, 0x02}, 0, 0}, 229713b466fSPatrice Chotard {{0xe5, 0x00}, 0, 0}, 230713b466fSPatrice Chotard {{0x94, 0x02}, 0, 0}, 231713b466fSPatrice Chotard {{0xe6, 0x2c}, 0, 0}, 232713b466fSPatrice Chotard {{0x94, 0x03}, 0, 0}, 2335396e62fSPatrice Chotard {{0xaa, 0x00}, 0, 0} 2343040b043STheodore Kilgore }; 235c3d86927SPatrice Chotard 236c3d86927SPatrice Chotard sd->blocks_left = 0; 237713b466fSPatrice Chotard /* Under Windows, USB spy shows that only the 9 first start 238713b466fSPatrice Chotard * commands are used for SPORTSCAM_DV15 webcam 239713b466fSPatrice Chotard */ 240713b466fSPatrice Chotard if (sd->type == SPORTSCAM_DV15) 241713b466fSPatrice Chotard start_commands_size = SPORTSCAM_DV15_CMD_SIZE; 242713b466fSPatrice Chotard else 243713b466fSPatrice Chotard start_commands_size = ARRAY_SIZE(start_commands); 244713b466fSPatrice Chotard 245713b466fSPatrice Chotard for (i = 0; i < start_commands_size; i++) { 2468715b16eSPatrice Chotard jlj_write2(gspca_dev, start_commands[i].instruction); 247713b466fSPatrice Chotard if (start_commands[i].delay) 248713b466fSPatrice Chotard msleep(start_commands[i].delay); 2493040b043STheodore Kilgore if (start_commands[i].ack_wanted) 2509825f376SMauro Carvalho Chehab jlj_read1(gspca_dev, &response); 2513040b043STheodore Kilgore } 252bfaab899SHans Verkuil setcamquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual)); 2535396e62fSPatrice Chotard msleep(2); 254bfaab899SHans Verkuil setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq)); 2558715b16eSPatrice Chotard if (gspca_dev->usb_err < 0) 25652173c5fSJoe Perches gspca_err(gspca_dev, "Start streaming command failed\n"); 2578715b16eSPatrice Chotard return gspca_dev->usb_err; 2583040b043STheodore Kilgore } 2593040b043STheodore Kilgore 260c3d86927SPatrice Chotard static void sd_pkt_scan(struct gspca_dev *gspca_dev, 261c3d86927SPatrice Chotard u8 *data, int len) 2623040b043STheodore Kilgore { 263c3d86927SPatrice Chotard struct sd *sd = (struct sd *) gspca_dev; 2643040b043STheodore Kilgore int packet_type; 265c3d86927SPatrice Chotard u32 header_marker; 2663040b043STheodore Kilgore 26737d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "Got %d bytes out of %d for Block 0\n", 268c3d86927SPatrice Chotard len, JEILINJ_MAX_TRANSFER); 269c3d86927SPatrice Chotard if (len != JEILINJ_MAX_TRANSFER) { 27037d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PACK, "bad length\n"); 271c3d86927SPatrice Chotard goto discard; 2723040b043STheodore Kilgore } 273c3d86927SPatrice Chotard /* check if it's start of frame */ 274c3d86927SPatrice Chotard header_marker = ((u32 *)data)[0]; 275c3d86927SPatrice Chotard if (header_marker == FRAME_START) { 276c3d86927SPatrice Chotard sd->blocks_left = data[0x0a] - 1; 27737d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "blocks_left = 0x%x\n", 27837d5efb0SJoe Perches sd->blocks_left); 2796ca3f255SHans de Goede /* Start a new frame, and add the JPEG header, first thing */ 28076dd272bSJean-Francois Moine gspca_frame_add(gspca_dev, FIRST_PACKET, 281c3d86927SPatrice Chotard sd->jpeg_hdr, JPEG_HDR_SZ); 2823040b043STheodore Kilgore /* Toss line 0 of data block 0, keep the rest. */ 2836ca3f255SHans de Goede gspca_frame_add(gspca_dev, INTER_PACKET, 284c3d86927SPatrice Chotard data + FRAME_HEADER_LEN, 2853040b043STheodore Kilgore JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); 286c3d86927SPatrice Chotard } else if (sd->blocks_left > 0) { 28737d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "%d blocks remaining for frame\n", 288c3d86927SPatrice Chotard sd->blocks_left); 289c3d86927SPatrice Chotard sd->blocks_left -= 1; 290c3d86927SPatrice Chotard if (sd->blocks_left == 0) 2913040b043STheodore Kilgore packet_type = LAST_PACKET; 2923040b043STheodore Kilgore else 2933040b043STheodore Kilgore packet_type = INTER_PACKET; 2943040b043STheodore Kilgore gspca_frame_add(gspca_dev, packet_type, 295c3d86927SPatrice Chotard data, JEILINJ_MAX_TRANSFER); 296c3d86927SPatrice Chotard } else 297c3d86927SPatrice Chotard goto discard; 298c3d86927SPatrice Chotard return; 299c3d86927SPatrice Chotard discard: 300c3d86927SPatrice Chotard /* Discard data until a new frame starts. */ 301c3d86927SPatrice Chotard gspca_dev->last_packet_type = DISCARD_PACKET; 3023040b043STheodore Kilgore } 3033040b043STheodore Kilgore 3043040b043STheodore Kilgore /* This function is called at probe time just before sd_init */ 3053040b043STheodore Kilgore static int sd_config(struct gspca_dev *gspca_dev, 3063040b043STheodore Kilgore const struct usb_device_id *id) 3073040b043STheodore Kilgore { 3083040b043STheodore Kilgore struct cam *cam = &gspca_dev->cam; 3093040b043STheodore Kilgore struct sd *dev = (struct sd *) gspca_dev; 3103040b043STheodore Kilgore 311713b466fSPatrice Chotard dev->type = id->driver_info; 3125396e62fSPatrice Chotard dev->quality = QUALITY_DEF; 3137d84a179SJean-François Moine 3143040b043STheodore Kilgore cam->cam_mode = jlj_mode; 3156f8efcfbSPatrice Chotard cam->nmodes = ARRAY_SIZE(jlj_mode); 3163040b043STheodore Kilgore cam->bulk = 1; 317c3d86927SPatrice Chotard cam->bulk_nurbs = 1; 318c3d86927SPatrice Chotard cam->bulk_size = JEILINJ_MAX_TRANSFER; 3193040b043STheodore Kilgore return 0; 3203040b043STheodore Kilgore } 3213040b043STheodore Kilgore 322c3d86927SPatrice Chotard static void sd_stopN(struct gspca_dev *gspca_dev) 3233040b043STheodore Kilgore { 324c3d86927SPatrice Chotard int i; 325c3d86927SPatrice Chotard u8 *buf; 3267d84a179SJean-François Moine static u8 stop_commands[][2] = { 327c3d86927SPatrice Chotard {0x71, 0x00}, 328c3d86927SPatrice Chotard {0x70, 0x09}, 329c3d86927SPatrice Chotard {0x71, 0x80}, 330c3d86927SPatrice Chotard {0x70, 0x05} 331c3d86927SPatrice Chotard }; 3323040b043STheodore Kilgore 333c3d86927SPatrice Chotard for (;;) { 334c3d86927SPatrice Chotard /* get the image remaining blocks */ 335c3d86927SPatrice Chotard usb_bulk_msg(gspca_dev->dev, 336c3d86927SPatrice Chotard gspca_dev->urb[0]->pipe, 337c3d86927SPatrice Chotard gspca_dev->urb[0]->transfer_buffer, 338c3d86927SPatrice Chotard JEILINJ_MAX_TRANSFER, NULL, 339c3d86927SPatrice Chotard JEILINJ_DATA_TIMEOUT); 340c3d86927SPatrice Chotard 341c3d86927SPatrice Chotard /* search for 0xff 0xd9 (EOF for JPEG) */ 342c3d86927SPatrice Chotard i = 0; 343c3d86927SPatrice Chotard buf = gspca_dev->urb[0]->transfer_buffer; 344c3d86927SPatrice Chotard while ((i < (JEILINJ_MAX_TRANSFER - 1)) && 345c3d86927SPatrice Chotard ((buf[i] != 0xff) || (buf[i+1] != 0xd9))) 346c3d86927SPatrice Chotard i++; 347c3d86927SPatrice Chotard 348c3d86927SPatrice Chotard if (i != (JEILINJ_MAX_TRANSFER - 1)) 349c3d86927SPatrice Chotard /* last remaining block found */ 350c3d86927SPatrice Chotard break; 351c3d86927SPatrice Chotard } 352c3d86927SPatrice Chotard 353c3d86927SPatrice Chotard for (i = 0; i < ARRAY_SIZE(stop_commands); i++) 354c3d86927SPatrice Chotard jlj_write2(gspca_dev, stop_commands[i]); 3553040b043STheodore Kilgore } 3563040b043STheodore Kilgore 3573040b043STheodore Kilgore /* this function is called at probe and resume time */ 3583040b043STheodore Kilgore static int sd_init(struct gspca_dev *gspca_dev) 3593040b043STheodore Kilgore { 3608715b16eSPatrice Chotard return gspca_dev->usb_err; 3613040b043STheodore Kilgore } 3623040b043STheodore Kilgore 3633040b043STheodore Kilgore /* Set up for getting frames. */ 3643040b043STheodore Kilgore static int sd_start(struct gspca_dev *gspca_dev) 3653040b043STheodore Kilgore { 3663040b043STheodore Kilgore struct sd *dev = (struct sd *) gspca_dev; 3673040b043STheodore Kilgore 3683040b043STheodore Kilgore /* create the JPEG header */ 3691966bc2aSOndrej Zary jpeg_define(dev->jpeg_hdr, gspca_dev->pixfmt.height, 3701966bc2aSOndrej Zary gspca_dev->pixfmt.width, 3713040b043STheodore Kilgore 0x21); /* JPEG 422 */ 3723040b043STheodore Kilgore jpeg_set_qual(dev->jpeg_hdr, dev->quality); 37337d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "Start streaming at %dx%d\n", 3741966bc2aSOndrej Zary gspca_dev->pixfmt.height, gspca_dev->pixfmt.width); 3758715b16eSPatrice Chotard jlj_start(gspca_dev); 3768715b16eSPatrice Chotard return gspca_dev->usb_err; 3773040b043STheodore Kilgore } 3783040b043STheodore Kilgore 3793040b043STheodore Kilgore /* Table of supported USB devices */ 38095c967c1SJean-François Moine static const struct usb_device_id device_table[] = { 381713b466fSPatrice Chotard {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379}, 382713b466fSPatrice Chotard {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15}, 3833040b043STheodore Kilgore {} 3843040b043STheodore Kilgore }; 3853040b043STheodore Kilgore 3863040b043STheodore Kilgore MODULE_DEVICE_TABLE(usb, device_table); 3873040b043STheodore Kilgore 388bfaab899SHans Verkuil static int sd_s_ctrl(struct v4l2_ctrl *ctrl) 3895396e62fSPatrice Chotard { 390bfaab899SHans Verkuil struct gspca_dev *gspca_dev = 391bfaab899SHans Verkuil container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 392bfaab899SHans Verkuil struct sd *sd = (struct sd *)gspca_dev; 393bfaab899SHans Verkuil 394bfaab899SHans Verkuil gspca_dev->usb_err = 0; 395bfaab899SHans Verkuil 396bfaab899SHans Verkuil if (!gspca_dev->streaming) 397bfaab899SHans Verkuil return 0; 398bfaab899SHans Verkuil 399bfaab899SHans Verkuil switch (ctrl->id) { 4005396e62fSPatrice Chotard case V4L2_CID_POWER_LINE_FREQUENCY: 401bfaab899SHans Verkuil setfreq(gspca_dev, ctrl->val); 402bfaab899SHans Verkuil break; 403bfaab899SHans Verkuil case V4L2_CID_RED_BALANCE: 404bfaab899SHans Verkuil setred(gspca_dev, ctrl->val); 405bfaab899SHans Verkuil break; 406bfaab899SHans Verkuil case V4L2_CID_GAIN: 407bfaab899SHans Verkuil setgreen(gspca_dev, ctrl->val); 408bfaab899SHans Verkuil break; 409bfaab899SHans Verkuil case V4L2_CID_BLUE_BALANCE: 410bfaab899SHans Verkuil setblue(gspca_dev, ctrl->val); 411bfaab899SHans Verkuil break; 412bfaab899SHans Verkuil case V4L2_CID_AUTOGAIN: 413bfaab899SHans Verkuil setautogain(gspca_dev, ctrl->val); 414bfaab899SHans Verkuil break; 415bfaab899SHans Verkuil case V4L2_CID_JPEG_COMPRESSION_QUALITY: 416bfaab899SHans Verkuil jpeg_set_qual(sd->jpeg_hdr, ctrl->val); 417bfaab899SHans Verkuil setcamquality(gspca_dev, ctrl->val); 4185396e62fSPatrice Chotard break; 4195396e62fSPatrice Chotard } 420bfaab899SHans Verkuil return gspca_dev->usb_err; 421bfaab899SHans Verkuil } 422bfaab899SHans Verkuil 423bfaab899SHans Verkuil static const struct v4l2_ctrl_ops sd_ctrl_ops = { 424bfaab899SHans Verkuil .s_ctrl = sd_s_ctrl, 425bfaab899SHans Verkuil }; 426bfaab899SHans Verkuil 427bfaab899SHans Verkuil static int sd_init_controls(struct gspca_dev *gspca_dev) 428bfaab899SHans Verkuil { 429bfaab899SHans Verkuil struct sd *sd = (struct sd *)gspca_dev; 430bfaab899SHans Verkuil struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 431bfaab899SHans Verkuil static const struct v4l2_ctrl_config custom_autogain = { 432bfaab899SHans Verkuil .ops = &sd_ctrl_ops, 433bfaab899SHans Verkuil .id = V4L2_CID_AUTOGAIN, 434bfaab899SHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 435bfaab899SHans Verkuil .name = "Automatic Gain (and Exposure)", 436bfaab899SHans Verkuil .max = 3, 437bfaab899SHans Verkuil .step = 1, 438bfaab899SHans Verkuil .def = 0, 439bfaab899SHans Verkuil }; 440bfaab899SHans Verkuil 441bfaab899SHans Verkuil gspca_dev->vdev.ctrl_handler = hdl; 442bfaab899SHans Verkuil v4l2_ctrl_handler_init(hdl, 6); 443bfaab899SHans Verkuil sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, 444bfaab899SHans Verkuil V4L2_CID_POWER_LINE_FREQUENCY, 445bfaab899SHans Verkuil V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1, 446bfaab899SHans Verkuil V4L2_CID_POWER_LINE_FREQUENCY_60HZ); 447bfaab899SHans Verkuil v4l2_ctrl_new_custom(hdl, &custom_autogain, NULL); 448bfaab899SHans Verkuil v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 449bfaab899SHans Verkuil V4L2_CID_RED_BALANCE, 0, 3, 1, 2); 450bfaab899SHans Verkuil v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 451bfaab899SHans Verkuil V4L2_CID_GAIN, 0, 3, 1, 2); 452bfaab899SHans Verkuil v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 453bfaab899SHans Verkuil V4L2_CID_BLUE_BALANCE, 0, 3, 1, 2); 454bfaab899SHans Verkuil sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 455bfaab899SHans Verkuil V4L2_CID_JPEG_COMPRESSION_QUALITY, 456bfaab899SHans Verkuil QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF); 457bfaab899SHans Verkuil 458bfaab899SHans Verkuil if (hdl->error) { 459bfaab899SHans Verkuil pr_err("Could not initialize controls\n"); 460bfaab899SHans Verkuil return hdl->error; 461bfaab899SHans Verkuil } 462bfaab899SHans Verkuil return 0; 4635396e62fSPatrice Chotard } 4645396e62fSPatrice Chotard 4655396e62fSPatrice Chotard static int sd_set_jcomp(struct gspca_dev *gspca_dev, 466d88aab53SHans Verkuil const struct v4l2_jpegcompression *jcomp) 4675396e62fSPatrice Chotard { 4685396e62fSPatrice Chotard struct sd *sd = (struct sd *) gspca_dev; 4695396e62fSPatrice Chotard 470bfaab899SHans Verkuil v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality); 4715396e62fSPatrice Chotard return 0; 4725396e62fSPatrice Chotard } 4735396e62fSPatrice Chotard 4745396e62fSPatrice Chotard static int sd_get_jcomp(struct gspca_dev *gspca_dev, 4755396e62fSPatrice Chotard struct v4l2_jpegcompression *jcomp) 4765396e62fSPatrice Chotard { 4775396e62fSPatrice Chotard struct sd *sd = (struct sd *) gspca_dev; 4785396e62fSPatrice Chotard 4795396e62fSPatrice Chotard memset(jcomp, 0, sizeof *jcomp); 480bfaab899SHans Verkuil jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); 4815396e62fSPatrice Chotard jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT 4825396e62fSPatrice Chotard | V4L2_JPEG_MARKER_DQT; 4835396e62fSPatrice Chotard return 0; 4845396e62fSPatrice Chotard } 4855396e62fSPatrice Chotard 4865396e62fSPatrice Chotard 4873040b043STheodore Kilgore /* sub-driver description */ 488713b466fSPatrice Chotard static const struct sd_desc sd_desc_sakar_57379 = { 4893040b043STheodore Kilgore .name = MODULE_NAME, 4903040b043STheodore Kilgore .config = sd_config, 4913040b043STheodore Kilgore .init = sd_init, 4923040b043STheodore Kilgore .start = sd_start, 493c3d86927SPatrice Chotard .stopN = sd_stopN, 494c3d86927SPatrice Chotard .pkt_scan = sd_pkt_scan, 4953040b043STheodore Kilgore }; 4963040b043STheodore Kilgore 497713b466fSPatrice Chotard /* sub-driver description */ 498713b466fSPatrice Chotard static const struct sd_desc sd_desc_sportscam_dv15 = { 499713b466fSPatrice Chotard .name = MODULE_NAME, 500713b466fSPatrice Chotard .config = sd_config, 501713b466fSPatrice Chotard .init = sd_init, 502bfaab899SHans Verkuil .init_controls = sd_init_controls, 503713b466fSPatrice Chotard .start = sd_start, 504713b466fSPatrice Chotard .stopN = sd_stopN, 505713b466fSPatrice Chotard .pkt_scan = sd_pkt_scan, 5065396e62fSPatrice Chotard .get_jcomp = sd_get_jcomp, 5075396e62fSPatrice Chotard .set_jcomp = sd_set_jcomp, 508713b466fSPatrice Chotard }; 509713b466fSPatrice Chotard 510713b466fSPatrice Chotard static const struct sd_desc *sd_desc[2] = { 511713b466fSPatrice Chotard &sd_desc_sakar_57379, 512713b466fSPatrice Chotard &sd_desc_sportscam_dv15 513713b466fSPatrice Chotard }; 514713b466fSPatrice Chotard 5153040b043STheodore Kilgore /* -- device connect -- */ 5163040b043STheodore Kilgore static int sd_probe(struct usb_interface *intf, 5173040b043STheodore Kilgore const struct usb_device_id *id) 5183040b043STheodore Kilgore { 5193040b043STheodore Kilgore return gspca_dev_probe(intf, id, 520713b466fSPatrice Chotard sd_desc[id->driver_info], 5213040b043STheodore Kilgore sizeof(struct sd), 5223040b043STheodore Kilgore THIS_MODULE); 5233040b043STheodore Kilgore } 5243040b043STheodore Kilgore 5253040b043STheodore Kilgore static struct usb_driver sd_driver = { 5263040b043STheodore Kilgore .name = MODULE_NAME, 5273040b043STheodore Kilgore .id_table = device_table, 5283040b043STheodore Kilgore .probe = sd_probe, 5293040b043STheodore Kilgore .disconnect = gspca_disconnect, 5303040b043STheodore Kilgore #ifdef CONFIG_PM 5313040b043STheodore Kilgore .suspend = gspca_suspend, 5323040b043STheodore Kilgore .resume = gspca_resume, 5338bb58964SHans de Goede .reset_resume = gspca_resume, 5343040b043STheodore Kilgore #endif 5353040b043STheodore Kilgore }; 5363040b043STheodore Kilgore 537ecb3b2b3SGreg Kroah-Hartman module_usb_driver(sd_driver); 538