1fd9871f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 20c0d06caSMauro Carvalho Chehab /* 30c0d06caSMauro Carvalho Chehab * Jeilin JL2005B/C/D library 40c0d06caSMauro Carvalho Chehab * 50c0d06caSMauro Carvalho Chehab * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.edu> 60c0d06caSMauro Carvalho Chehab */ 70c0d06caSMauro Carvalho Chehab 80c0d06caSMauro Carvalho Chehab #define MODULE_NAME "jl2005bcd" 90c0d06caSMauro Carvalho Chehab 100c0d06caSMauro Carvalho Chehab #include <linux/workqueue.h> 110c0d06caSMauro Carvalho Chehab #include <linux/slab.h> 120c0d06caSMauro Carvalho Chehab #include "gspca.h" 130c0d06caSMauro Carvalho Chehab 140c0d06caSMauro Carvalho Chehab 150c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>"); 160c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver"); 170c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 180c0d06caSMauro Carvalho Chehab 190c0d06caSMauro Carvalho Chehab /* Default timeouts, in ms */ 200c0d06caSMauro Carvalho Chehab #define JL2005C_CMD_TIMEOUT 500 210c0d06caSMauro Carvalho Chehab #define JL2005C_DATA_TIMEOUT 1000 220c0d06caSMauro Carvalho Chehab 230c0d06caSMauro Carvalho Chehab /* Maximum transfer size to use. */ 240c0d06caSMauro Carvalho Chehab #define JL2005C_MAX_TRANSFER 0x200 250c0d06caSMauro Carvalho Chehab #define FRAME_HEADER_LEN 16 260c0d06caSMauro Carvalho Chehab 270c0d06caSMauro Carvalho Chehab 280c0d06caSMauro Carvalho Chehab /* specific webcam descriptor */ 290c0d06caSMauro Carvalho Chehab struct sd { 300c0d06caSMauro Carvalho Chehab struct gspca_dev gspca_dev; /* !! must be the first item */ 310c0d06caSMauro Carvalho Chehab unsigned char firmware_id[6]; 320c0d06caSMauro Carvalho Chehab const struct v4l2_pix_format *cap_mode; 330c0d06caSMauro Carvalho Chehab /* Driver stuff */ 340c0d06caSMauro Carvalho Chehab struct work_struct work_struct; 350c0d06caSMauro Carvalho Chehab u8 frame_brightness; 360c0d06caSMauro Carvalho Chehab int block_size; /* block size of camera */ 370c0d06caSMauro Carvalho Chehab int vga; /* 1 if vga cam, 0 if cif cam */ 380c0d06caSMauro Carvalho Chehab }; 390c0d06caSMauro Carvalho Chehab 400c0d06caSMauro Carvalho Chehab 410c0d06caSMauro Carvalho Chehab /* Camera has two resolution settings. What they are depends on model. */ 420c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format cif_mode[] = { 430c0d06caSMauro Carvalho Chehab {176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 440c0d06caSMauro Carvalho Chehab .bytesperline = 176, 450c0d06caSMauro Carvalho Chehab .sizeimage = 176 * 144, 460c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 470c0d06caSMauro Carvalho Chehab .priv = 0}, 480c0d06caSMauro Carvalho Chehab {352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 490c0d06caSMauro Carvalho Chehab .bytesperline = 352, 500c0d06caSMauro Carvalho Chehab .sizeimage = 352 * 288, 510c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 520c0d06caSMauro Carvalho Chehab .priv = 0}, 530c0d06caSMauro Carvalho Chehab }; 540c0d06caSMauro Carvalho Chehab 550c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format vga_mode[] = { 560c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 570c0d06caSMauro Carvalho Chehab .bytesperline = 320, 580c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240, 590c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 600c0d06caSMauro Carvalho Chehab .priv = 0}, 610c0d06caSMauro Carvalho Chehab {640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 620c0d06caSMauro Carvalho Chehab .bytesperline = 640, 630c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480, 640c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 650c0d06caSMauro Carvalho Chehab .priv = 0}, 660c0d06caSMauro Carvalho Chehab }; 670c0d06caSMauro Carvalho Chehab 680c0d06caSMauro Carvalho Chehab /* 690c0d06caSMauro Carvalho Chehab * cam uses endpoint 0x03 to send commands, 0x84 for read commands, 700c0d06caSMauro Carvalho Chehab * and 0x82 for bulk data transfer. 710c0d06caSMauro Carvalho Chehab */ 720c0d06caSMauro Carvalho Chehab 730c0d06caSMauro Carvalho Chehab /* All commands are two bytes only */ 740c0d06caSMauro Carvalho Chehab static int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command) 750c0d06caSMauro Carvalho Chehab { 760c0d06caSMauro Carvalho Chehab int retval; 770c0d06caSMauro Carvalho Chehab 780c0d06caSMauro Carvalho Chehab memcpy(gspca_dev->usb_buf, command, 2); 790c0d06caSMauro Carvalho Chehab retval = usb_bulk_msg(gspca_dev->dev, 800c0d06caSMauro Carvalho Chehab usb_sndbulkpipe(gspca_dev->dev, 3), 810c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf, 2, NULL, 500); 820c0d06caSMauro Carvalho Chehab if (retval < 0) 830c0d06caSMauro Carvalho Chehab pr_err("command write [%02x] error %d\n", 840c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0], retval); 850c0d06caSMauro Carvalho Chehab return retval; 860c0d06caSMauro Carvalho Chehab } 870c0d06caSMauro Carvalho Chehab 880c0d06caSMauro Carvalho Chehab /* Response to a command is one byte in usb_buf[0], only if requested. */ 890c0d06caSMauro Carvalho Chehab static int jl2005c_read1(struct gspca_dev *gspca_dev) 900c0d06caSMauro Carvalho Chehab { 910c0d06caSMauro Carvalho Chehab int retval; 920c0d06caSMauro Carvalho Chehab 930c0d06caSMauro Carvalho Chehab retval = usb_bulk_msg(gspca_dev->dev, 940c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(gspca_dev->dev, 0x84), 950c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf, 1, NULL, 500); 960c0d06caSMauro Carvalho Chehab if (retval < 0) 970c0d06caSMauro Carvalho Chehab pr_err("read command [0x%02x] error %d\n", 980c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0], retval); 990c0d06caSMauro Carvalho Chehab return retval; 1000c0d06caSMauro Carvalho Chehab } 1010c0d06caSMauro Carvalho Chehab 1020c0d06caSMauro Carvalho Chehab /* Response appears in gspca_dev->usb_buf[0] */ 1030c0d06caSMauro Carvalho Chehab static int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg) 1040c0d06caSMauro Carvalho Chehab { 1050c0d06caSMauro Carvalho Chehab int retval; 1060c0d06caSMauro Carvalho Chehab 1070c0d06caSMauro Carvalho Chehab static u8 instruction[2] = {0x95, 0x00}; 1080c0d06caSMauro Carvalho Chehab /* put register to read in byte 1 */ 1090c0d06caSMauro Carvalho Chehab instruction[1] = reg; 1100c0d06caSMauro Carvalho Chehab /* Send the read request */ 1110c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction); 1120c0d06caSMauro Carvalho Chehab if (retval < 0) 1130c0d06caSMauro Carvalho Chehab return retval; 1140c0d06caSMauro Carvalho Chehab retval = jl2005c_read1(gspca_dev); 1150c0d06caSMauro Carvalho Chehab 1160c0d06caSMauro Carvalho Chehab return retval; 1170c0d06caSMauro Carvalho Chehab } 1180c0d06caSMauro Carvalho Chehab 1190c0d06caSMauro Carvalho Chehab static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev) 1200c0d06caSMauro Carvalho Chehab { 1210c0d06caSMauro Carvalho Chehab int i; 1220c0d06caSMauro Carvalho Chehab int retval; 1230c0d06caSMauro Carvalho Chehab int frame_brightness = 0; 1240c0d06caSMauro Carvalho Chehab 1250c0d06caSMauro Carvalho Chehab static u8 instruction[2] = {0x7f, 0x01}; 1260c0d06caSMauro Carvalho Chehab 1270c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction); 1280c0d06caSMauro Carvalho Chehab if (retval < 0) 1290c0d06caSMauro Carvalho Chehab return retval; 1300c0d06caSMauro Carvalho Chehab 1310c0d06caSMauro Carvalho Chehab i = 0; 1320c0d06caSMauro Carvalho Chehab while (i < 20 && !frame_brightness) { 1330c0d06caSMauro Carvalho Chehab /* If we tried 20 times, give up. */ 1340c0d06caSMauro Carvalho Chehab retval = jl2005c_read_reg(gspca_dev, 0x7e); 1350c0d06caSMauro Carvalho Chehab if (retval < 0) 1360c0d06caSMauro Carvalho Chehab return retval; 1370c0d06caSMauro Carvalho Chehab frame_brightness = gspca_dev->usb_buf[0]; 1380c0d06caSMauro Carvalho Chehab retval = jl2005c_read_reg(gspca_dev, 0x7d); 1390c0d06caSMauro Carvalho Chehab if (retval < 0) 1400c0d06caSMauro Carvalho Chehab return retval; 1410c0d06caSMauro Carvalho Chehab i++; 1420c0d06caSMauro Carvalho Chehab } 14337d5efb0SJoe Perches gspca_dbg(gspca_dev, D_FRAM, "frame_brightness is 0x%02x\n", 14437d5efb0SJoe Perches gspca_dev->usb_buf[0]); 1450c0d06caSMauro Carvalho Chehab return retval; 1460c0d06caSMauro Carvalho Chehab } 1470c0d06caSMauro Carvalho Chehab 1480c0d06caSMauro Carvalho Chehab static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg, 1490c0d06caSMauro Carvalho Chehab unsigned char value) 1500c0d06caSMauro Carvalho Chehab { 1510c0d06caSMauro Carvalho Chehab int retval; 1520c0d06caSMauro Carvalho Chehab u8 instruction[2]; 1530c0d06caSMauro Carvalho Chehab 1540c0d06caSMauro Carvalho Chehab instruction[0] = reg; 1550c0d06caSMauro Carvalho Chehab instruction[1] = value; 1560c0d06caSMauro Carvalho Chehab 1570c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction); 1580c0d06caSMauro Carvalho Chehab if (retval < 0) 1590c0d06caSMauro Carvalho Chehab return retval; 1600c0d06caSMauro Carvalho Chehab 1610c0d06caSMauro Carvalho Chehab return retval; 1620c0d06caSMauro Carvalho Chehab } 1630c0d06caSMauro Carvalho Chehab 1640c0d06caSMauro Carvalho Chehab static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev) 1650c0d06caSMauro Carvalho Chehab { 1660c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *)gspca_dev; 1670c0d06caSMauro Carvalho Chehab int i = 0; 168*e1f60f42SColin Ian King int retval; 1690c0d06caSMauro Carvalho Chehab unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f}; 1700c0d06caSMauro Carvalho Chehab 17137d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Running jl2005c_get_firmware_id\n"); 1720c0d06caSMauro Carvalho Chehab /* Read the first ID byte once for warmup */ 1730c0d06caSMauro Carvalho Chehab retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]); 17437d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "response is %02x\n", 17537d5efb0SJoe Perches gspca_dev->usb_buf[0]); 1760c0d06caSMauro Carvalho Chehab if (retval < 0) 1770c0d06caSMauro Carvalho Chehab return retval; 1780c0d06caSMauro Carvalho Chehab /* Now actually get the ID string */ 1790c0d06caSMauro Carvalho Chehab for (i = 0; i < 6; i++) { 1800c0d06caSMauro Carvalho Chehab retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]); 1810c0d06caSMauro Carvalho Chehab if (retval < 0) 1820c0d06caSMauro Carvalho Chehab return retval; 1830c0d06caSMauro Carvalho Chehab sd->firmware_id[i] = gspca_dev->usb_buf[0]; 1840c0d06caSMauro Carvalho Chehab } 18537d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x\n", 1860c0d06caSMauro Carvalho Chehab sd->firmware_id[0], 1870c0d06caSMauro Carvalho Chehab sd->firmware_id[1], 1880c0d06caSMauro Carvalho Chehab sd->firmware_id[2], 1890c0d06caSMauro Carvalho Chehab sd->firmware_id[3], 1900c0d06caSMauro Carvalho Chehab sd->firmware_id[4], 1910c0d06caSMauro Carvalho Chehab sd->firmware_id[5]); 1920c0d06caSMauro Carvalho Chehab return 0; 1930c0d06caSMauro Carvalho Chehab } 1940c0d06caSMauro Carvalho Chehab 1950c0d06caSMauro Carvalho Chehab static int jl2005c_stream_start_vga_lg 1960c0d06caSMauro Carvalho Chehab (struct gspca_dev *gspca_dev) 1970c0d06caSMauro Carvalho Chehab { 1980c0d06caSMauro Carvalho Chehab int i; 1990c0d06caSMauro Carvalho Chehab int retval = -1; 2000c0d06caSMauro Carvalho Chehab static u8 instruction[][2] = { 2010c0d06caSMauro Carvalho Chehab {0x05, 0x00}, 2020c0d06caSMauro Carvalho Chehab {0x7c, 0x00}, 2030c0d06caSMauro Carvalho Chehab {0x7d, 0x18}, 2040c0d06caSMauro Carvalho Chehab {0x02, 0x00}, 2050c0d06caSMauro Carvalho Chehab {0x01, 0x00}, 2060c0d06caSMauro Carvalho Chehab {0x04, 0x52}, 2070c0d06caSMauro Carvalho Chehab }; 2080c0d06caSMauro Carvalho Chehab 2090c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(instruction); i++) { 2100c0d06caSMauro Carvalho Chehab msleep(60); 2110c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction[i]); 2120c0d06caSMauro Carvalho Chehab if (retval < 0) 2130c0d06caSMauro Carvalho Chehab return retval; 2140c0d06caSMauro Carvalho Chehab } 2150c0d06caSMauro Carvalho Chehab msleep(60); 2160c0d06caSMauro Carvalho Chehab return retval; 2170c0d06caSMauro Carvalho Chehab } 2180c0d06caSMauro Carvalho Chehab 2190c0d06caSMauro Carvalho Chehab static int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev) 2200c0d06caSMauro Carvalho Chehab { 2210c0d06caSMauro Carvalho Chehab int i; 2220c0d06caSMauro Carvalho Chehab int retval = -1; 2230c0d06caSMauro Carvalho Chehab static u8 instruction[][2] = { 2240c0d06caSMauro Carvalho Chehab {0x06, 0x00}, 2250c0d06caSMauro Carvalho Chehab {0x7c, 0x00}, 2260c0d06caSMauro Carvalho Chehab {0x7d, 0x1a}, 2270c0d06caSMauro Carvalho Chehab {0x02, 0x00}, 2280c0d06caSMauro Carvalho Chehab {0x01, 0x00}, 2290c0d06caSMauro Carvalho Chehab {0x04, 0x52}, 2300c0d06caSMauro Carvalho Chehab }; 2310c0d06caSMauro Carvalho Chehab 2320c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(instruction); i++) { 2330c0d06caSMauro Carvalho Chehab msleep(60); 2340c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction[i]); 2350c0d06caSMauro Carvalho Chehab if (retval < 0) 2360c0d06caSMauro Carvalho Chehab return retval; 2370c0d06caSMauro Carvalho Chehab } 2380c0d06caSMauro Carvalho Chehab msleep(60); 2390c0d06caSMauro Carvalho Chehab return retval; 2400c0d06caSMauro Carvalho Chehab } 2410c0d06caSMauro Carvalho Chehab 2420c0d06caSMauro Carvalho Chehab static int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev) 2430c0d06caSMauro Carvalho Chehab { 2440c0d06caSMauro Carvalho Chehab int i; 2450c0d06caSMauro Carvalho Chehab int retval = -1; 2460c0d06caSMauro Carvalho Chehab static u8 instruction[][2] = { 2470c0d06caSMauro Carvalho Chehab {0x05, 0x00}, 2480c0d06caSMauro Carvalho Chehab {0x7c, 0x00}, 2490c0d06caSMauro Carvalho Chehab {0x7d, 0x30}, 2500c0d06caSMauro Carvalho Chehab {0x02, 0x00}, 2510c0d06caSMauro Carvalho Chehab {0x01, 0x00}, 2520c0d06caSMauro Carvalho Chehab {0x04, 0x42}, 2530c0d06caSMauro Carvalho Chehab }; 2540c0d06caSMauro Carvalho Chehab 2550c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(instruction); i++) { 2560c0d06caSMauro Carvalho Chehab msleep(60); 2570c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction[i]); 2580c0d06caSMauro Carvalho Chehab if (retval < 0) 2590c0d06caSMauro Carvalho Chehab return retval; 2600c0d06caSMauro Carvalho Chehab } 2610c0d06caSMauro Carvalho Chehab msleep(60); 2620c0d06caSMauro Carvalho Chehab return retval; 2630c0d06caSMauro Carvalho Chehab } 2640c0d06caSMauro Carvalho Chehab 2650c0d06caSMauro Carvalho Chehab static int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev) 2660c0d06caSMauro Carvalho Chehab { 2670c0d06caSMauro Carvalho Chehab int i; 2680c0d06caSMauro Carvalho Chehab int retval = -1; 2690c0d06caSMauro Carvalho Chehab static u8 instruction[][2] = { 2700c0d06caSMauro Carvalho Chehab {0x06, 0x00}, 2710c0d06caSMauro Carvalho Chehab {0x7c, 0x00}, 2720c0d06caSMauro Carvalho Chehab {0x7d, 0x32}, 2730c0d06caSMauro Carvalho Chehab {0x02, 0x00}, 2740c0d06caSMauro Carvalho Chehab {0x01, 0x00}, 2750c0d06caSMauro Carvalho Chehab {0x04, 0x42}, 2760c0d06caSMauro Carvalho Chehab }; 2770c0d06caSMauro Carvalho Chehab 2780c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(instruction); i++) { 2790c0d06caSMauro Carvalho Chehab msleep(60); 2800c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction[i]); 2810c0d06caSMauro Carvalho Chehab if (retval < 0) 2820c0d06caSMauro Carvalho Chehab return retval; 2830c0d06caSMauro Carvalho Chehab } 2840c0d06caSMauro Carvalho Chehab msleep(60); 2850c0d06caSMauro Carvalho Chehab return retval; 2860c0d06caSMauro Carvalho Chehab } 2870c0d06caSMauro Carvalho Chehab 2880c0d06caSMauro Carvalho Chehab 2890c0d06caSMauro Carvalho Chehab static int jl2005c_stop(struct gspca_dev *gspca_dev) 2900c0d06caSMauro Carvalho Chehab { 29129a8d979SMasahiro Yamada return jl2005c_write_reg(gspca_dev, 0x07, 0x00); 2920c0d06caSMauro Carvalho Chehab } 2930c0d06caSMauro Carvalho Chehab 294844db450SHans de Goede /* 295844db450SHans de Goede * This function is called as a workqueue function and runs whenever the camera 2960c0d06caSMauro Carvalho Chehab * is streaming data. Because it is a workqueue function it is allowed to sleep 2970c0d06caSMauro Carvalho Chehab * so we can use synchronous USB calls. To avoid possible collisions with other 298844db450SHans de Goede * threads attempting to use gspca_dev->usb_buf we take the usb_lock when 299844db450SHans de Goede * performing USB operations using it. In practice we don't really need this 300844db450SHans de Goede * as the camera doesn't provide any controls. 3010c0d06caSMauro Carvalho Chehab */ 3020c0d06caSMauro Carvalho Chehab static void jl2005c_dostream(struct work_struct *work) 3030c0d06caSMauro Carvalho Chehab { 3040c0d06caSMauro Carvalho Chehab struct sd *dev = container_of(work, struct sd, work_struct); 3050c0d06caSMauro Carvalho Chehab struct gspca_dev *gspca_dev = &dev->gspca_dev; 3060c0d06caSMauro Carvalho Chehab int bytes_left = 0; /* bytes remaining in current frame. */ 3070c0d06caSMauro Carvalho Chehab int data_len; /* size to use for the next read. */ 3080c0d06caSMauro Carvalho Chehab int header_read = 0; 3090c0d06caSMauro Carvalho Chehab unsigned char header_sig[2] = {0x4a, 0x4c}; 3100c0d06caSMauro Carvalho Chehab int act_len; 3110c0d06caSMauro Carvalho Chehab int packet_type; 3120c0d06caSMauro Carvalho Chehab int ret; 3130c0d06caSMauro Carvalho Chehab u8 *buffer; 3140c0d06caSMauro Carvalho Chehab 3155334b342SHans de Goede buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL); 3160c0d06caSMauro Carvalho Chehab if (!buffer) { 3170c0d06caSMauro Carvalho Chehab pr_err("Couldn't allocate USB buffer\n"); 3180c0d06caSMauro Carvalho Chehab goto quit_stream; 3190c0d06caSMauro Carvalho Chehab } 3200c0d06caSMauro Carvalho Chehab 321345321dcSHans de Goede while (gspca_dev->present && gspca_dev->streaming) { 3220c0d06caSMauro Carvalho Chehab #ifdef CONFIG_PM 3230c0d06caSMauro Carvalho Chehab if (gspca_dev->frozen) 3240c0d06caSMauro Carvalho Chehab break; 3250c0d06caSMauro Carvalho Chehab #endif 3260c0d06caSMauro Carvalho Chehab /* Check if this is a new frame. If so, start the frame first */ 3270c0d06caSMauro Carvalho Chehab if (!header_read) { 3280c0d06caSMauro Carvalho Chehab mutex_lock(&gspca_dev->usb_lock); 3290c0d06caSMauro Carvalho Chehab ret = jl2005c_start_new_frame(gspca_dev); 3300c0d06caSMauro Carvalho Chehab mutex_unlock(&gspca_dev->usb_lock); 3310c0d06caSMauro Carvalho Chehab if (ret < 0) 3320c0d06caSMauro Carvalho Chehab goto quit_stream; 3330c0d06caSMauro Carvalho Chehab ret = usb_bulk_msg(gspca_dev->dev, 3340c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(gspca_dev->dev, 0x82), 3350c0d06caSMauro Carvalho Chehab buffer, JL2005C_MAX_TRANSFER, &act_len, 3360c0d06caSMauro Carvalho Chehab JL2005C_DATA_TIMEOUT); 33737d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PACK, 33837d5efb0SJoe Perches "Got %d bytes out of %d for header\n", 3390c0d06caSMauro Carvalho Chehab act_len, JL2005C_MAX_TRANSFER); 3400c0d06caSMauro Carvalho Chehab if (ret < 0 || act_len < JL2005C_MAX_TRANSFER) 3410c0d06caSMauro Carvalho Chehab goto quit_stream; 3420c0d06caSMauro Carvalho Chehab /* Check whether we actually got the first blodk */ 3430c0d06caSMauro Carvalho Chehab if (memcmp(header_sig, buffer, 2) != 0) { 3440c0d06caSMauro Carvalho Chehab pr_err("First block is not the first block\n"); 3450c0d06caSMauro Carvalho Chehab goto quit_stream; 3460c0d06caSMauro Carvalho Chehab } 3470c0d06caSMauro Carvalho Chehab /* total size to fetch is byte 7, times blocksize 3480c0d06caSMauro Carvalho Chehab * of which we already got act_len */ 3490c0d06caSMauro Carvalho Chehab bytes_left = buffer[0x07] * dev->block_size - act_len; 35037d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PACK, "bytes_left = 0x%x\n", 35137d5efb0SJoe Perches bytes_left); 3520c0d06caSMauro Carvalho Chehab /* We keep the header. It has other information, too.*/ 3530c0d06caSMauro Carvalho Chehab packet_type = FIRST_PACKET; 3540c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, packet_type, 3550c0d06caSMauro Carvalho Chehab buffer, act_len); 3560c0d06caSMauro Carvalho Chehab header_read = 1; 3570c0d06caSMauro Carvalho Chehab } 358345321dcSHans de Goede while (bytes_left > 0 && gspca_dev->present) { 3590c0d06caSMauro Carvalho Chehab data_len = bytes_left > JL2005C_MAX_TRANSFER ? 3600c0d06caSMauro Carvalho Chehab JL2005C_MAX_TRANSFER : bytes_left; 3610c0d06caSMauro Carvalho Chehab ret = usb_bulk_msg(gspca_dev->dev, 3620c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(gspca_dev->dev, 0x82), 3630c0d06caSMauro Carvalho Chehab buffer, data_len, &act_len, 3640c0d06caSMauro Carvalho Chehab JL2005C_DATA_TIMEOUT); 3650c0d06caSMauro Carvalho Chehab if (ret < 0 || act_len < data_len) 3660c0d06caSMauro Carvalho Chehab goto quit_stream; 36737d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PACK, 36837d5efb0SJoe Perches "Got %d bytes out of %d for frame\n", 3690c0d06caSMauro Carvalho Chehab data_len, bytes_left); 3700c0d06caSMauro Carvalho Chehab bytes_left -= data_len; 3710c0d06caSMauro Carvalho Chehab if (bytes_left == 0) { 3720c0d06caSMauro Carvalho Chehab packet_type = LAST_PACKET; 3730c0d06caSMauro Carvalho Chehab header_read = 0; 3740c0d06caSMauro Carvalho Chehab } else 3750c0d06caSMauro Carvalho Chehab packet_type = INTER_PACKET; 3760c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, packet_type, 3770c0d06caSMauro Carvalho Chehab buffer, data_len); 3780c0d06caSMauro Carvalho Chehab } 3790c0d06caSMauro Carvalho Chehab } 3800c0d06caSMauro Carvalho Chehab quit_stream: 381345321dcSHans de Goede if (gspca_dev->present) { 3820c0d06caSMauro Carvalho Chehab mutex_lock(&gspca_dev->usb_lock); 3830c0d06caSMauro Carvalho Chehab jl2005c_stop(gspca_dev); 3840c0d06caSMauro Carvalho Chehab mutex_unlock(&gspca_dev->usb_lock); 3850c0d06caSMauro Carvalho Chehab } 3860c0d06caSMauro Carvalho Chehab kfree(buffer); 3870c0d06caSMauro Carvalho Chehab } 3880c0d06caSMauro Carvalho Chehab 3890c0d06caSMauro Carvalho Chehab 3900c0d06caSMauro Carvalho Chehab 3910c0d06caSMauro Carvalho Chehab 3920c0d06caSMauro Carvalho Chehab /* This function is called at probe time */ 3930c0d06caSMauro Carvalho Chehab static int sd_config(struct gspca_dev *gspca_dev, 3940c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 3950c0d06caSMauro Carvalho Chehab { 3960c0d06caSMauro Carvalho Chehab struct cam *cam; 3970c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 3980c0d06caSMauro Carvalho Chehab 3990c0d06caSMauro Carvalho Chehab cam = &gspca_dev->cam; 4000c0d06caSMauro Carvalho Chehab /* We don't use the buffer gspca allocates so make it small. */ 4010c0d06caSMauro Carvalho Chehab cam->bulk_size = 64; 4020c0d06caSMauro Carvalho Chehab cam->bulk = 1; 4030c0d06caSMauro Carvalho Chehab /* For the rest, the camera needs to be detected */ 4040c0d06caSMauro Carvalho Chehab jl2005c_get_firmware_id(gspca_dev); 4050c0d06caSMauro Carvalho Chehab /* Here are some known firmware IDs 4060c0d06caSMauro Carvalho Chehab * First some JL2005B cameras 4070c0d06caSMauro Carvalho Chehab * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2} Sakar KidzCam 4080c0d06caSMauro Carvalho Chehab * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2} No-name JL2005B 4090c0d06caSMauro Carvalho Chehab * JL2005C cameras 4100c0d06caSMauro Carvalho Chehab * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8} Argus DC-1512 4110c0d06caSMauro Carvalho Chehab * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8} ICarly 4120c0d06caSMauro Carvalho Chehab * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4} Jazz 4130c0d06caSMauro Carvalho Chehab * 4140c0d06caSMauro Carvalho Chehab * Based upon this scanty evidence, we can detect a CIF camera by 4150c0d06caSMauro Carvalho Chehab * testing byte 0 for 0x4x. 4160c0d06caSMauro Carvalho Chehab */ 4170c0d06caSMauro Carvalho Chehab if ((sd->firmware_id[0] & 0xf0) == 0x40) { 4180c0d06caSMauro Carvalho Chehab cam->cam_mode = cif_mode; 4190c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(cif_mode); 4200c0d06caSMauro Carvalho Chehab sd->block_size = 0x80; 4210c0d06caSMauro Carvalho Chehab } else { 4220c0d06caSMauro Carvalho Chehab cam->cam_mode = vga_mode; 4230c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(vga_mode); 4240c0d06caSMauro Carvalho Chehab sd->block_size = 0x200; 4250c0d06caSMauro Carvalho Chehab } 4260c0d06caSMauro Carvalho Chehab 4270c0d06caSMauro Carvalho Chehab INIT_WORK(&sd->work_struct, jl2005c_dostream); 4280c0d06caSMauro Carvalho Chehab 4290c0d06caSMauro Carvalho Chehab return 0; 4300c0d06caSMauro Carvalho Chehab } 4310c0d06caSMauro Carvalho Chehab 4320c0d06caSMauro Carvalho Chehab /* this function is called at probe and resume time */ 4330c0d06caSMauro Carvalho Chehab static int sd_init(struct gspca_dev *gspca_dev) 4340c0d06caSMauro Carvalho Chehab { 4350c0d06caSMauro Carvalho Chehab return 0; 4360c0d06caSMauro Carvalho Chehab } 4370c0d06caSMauro Carvalho Chehab 4380c0d06caSMauro Carvalho Chehab static int sd_start(struct gspca_dev *gspca_dev) 4390c0d06caSMauro Carvalho Chehab { 4400c0d06caSMauro Carvalho Chehab 4410c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 4420c0d06caSMauro Carvalho Chehab sd->cap_mode = gspca_dev->cam.cam_mode; 4430c0d06caSMauro Carvalho Chehab 4441966bc2aSOndrej Zary switch (gspca_dev->pixfmt.width) { 4450c0d06caSMauro Carvalho Chehab case 640: 44637d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "Start streaming at vga resolution\n"); 4470c0d06caSMauro Carvalho Chehab jl2005c_stream_start_vga_lg(gspca_dev); 4480c0d06caSMauro Carvalho Chehab break; 4490c0d06caSMauro Carvalho Chehab case 320: 45037d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "Start streaming at qvga resolution\n"); 4510c0d06caSMauro Carvalho Chehab jl2005c_stream_start_vga_small(gspca_dev); 4520c0d06caSMauro Carvalho Chehab break; 4530c0d06caSMauro Carvalho Chehab case 352: 45437d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "Start streaming at cif resolution\n"); 4550c0d06caSMauro Carvalho Chehab jl2005c_stream_start_cif_lg(gspca_dev); 4560c0d06caSMauro Carvalho Chehab break; 4570c0d06caSMauro Carvalho Chehab case 176: 45837d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "Start streaming at qcif resolution\n"); 4590c0d06caSMauro Carvalho Chehab jl2005c_stream_start_cif_small(gspca_dev); 4600c0d06caSMauro Carvalho Chehab break; 4610c0d06caSMauro Carvalho Chehab default: 4620c0d06caSMauro Carvalho Chehab pr_err("Unknown resolution specified\n"); 4630c0d06caSMauro Carvalho Chehab return -1; 4640c0d06caSMauro Carvalho Chehab } 4650c0d06caSMauro Carvalho Chehab 466e5964689SBhaktipriya Shridhar schedule_work(&sd->work_struct); 4670c0d06caSMauro Carvalho Chehab 4680c0d06caSMauro Carvalho Chehab return 0; 4690c0d06caSMauro Carvalho Chehab } 4700c0d06caSMauro Carvalho Chehab 4710c0d06caSMauro Carvalho Chehab /* called on streamoff with alt==0 and on disconnect */ 4720c0d06caSMauro Carvalho Chehab /* the usb_lock is held at entry - restore on exit */ 4730c0d06caSMauro Carvalho Chehab static void sd_stop0(struct gspca_dev *gspca_dev) 4740c0d06caSMauro Carvalho Chehab { 4750c0d06caSMauro Carvalho Chehab struct sd *dev = (struct sd *) gspca_dev; 4760c0d06caSMauro Carvalho Chehab 4770c0d06caSMauro Carvalho Chehab /* wait for the work queue to terminate */ 4780c0d06caSMauro Carvalho Chehab mutex_unlock(&gspca_dev->usb_lock); 4790c0d06caSMauro Carvalho Chehab /* This waits for sq905c_dostream to finish */ 480e5964689SBhaktipriya Shridhar flush_work(&dev->work_struct); 4810c0d06caSMauro Carvalho Chehab mutex_lock(&gspca_dev->usb_lock); 4820c0d06caSMauro Carvalho Chehab } 4830c0d06caSMauro Carvalho Chehab 4840c0d06caSMauro Carvalho Chehab 4850c0d06caSMauro Carvalho Chehab 4860c0d06caSMauro Carvalho Chehab /* sub-driver description */ 4870c0d06caSMauro Carvalho Chehab static const struct sd_desc sd_desc = { 4880c0d06caSMauro Carvalho Chehab .name = MODULE_NAME, 4890c0d06caSMauro Carvalho Chehab .config = sd_config, 4900c0d06caSMauro Carvalho Chehab .init = sd_init, 4910c0d06caSMauro Carvalho Chehab .start = sd_start, 4920c0d06caSMauro Carvalho Chehab .stop0 = sd_stop0, 4930c0d06caSMauro Carvalho Chehab }; 4940c0d06caSMauro Carvalho Chehab 4950c0d06caSMauro Carvalho Chehab /* -- module initialisation -- */ 49679e8c7beSMauro Carvalho Chehab static const struct usb_device_id device_table[] = { 4970c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x0979, 0x0227)}, 4980c0d06caSMauro Carvalho Chehab {} 4990c0d06caSMauro Carvalho Chehab }; 5000c0d06caSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, device_table); 5010c0d06caSMauro Carvalho Chehab 5020c0d06caSMauro Carvalho Chehab /* -- device connect -- */ 5030c0d06caSMauro Carvalho Chehab static int sd_probe(struct usb_interface *intf, 5040c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 5050c0d06caSMauro Carvalho Chehab { 5060c0d06caSMauro Carvalho Chehab return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 5070c0d06caSMauro Carvalho Chehab THIS_MODULE); 5080c0d06caSMauro Carvalho Chehab } 5090c0d06caSMauro Carvalho Chehab 5100c0d06caSMauro Carvalho Chehab static struct usb_driver sd_driver = { 5110c0d06caSMauro Carvalho Chehab .name = MODULE_NAME, 5120c0d06caSMauro Carvalho Chehab .id_table = device_table, 5130c0d06caSMauro Carvalho Chehab .probe = sd_probe, 5140c0d06caSMauro Carvalho Chehab .disconnect = gspca_disconnect, 5150c0d06caSMauro Carvalho Chehab #ifdef CONFIG_PM 5160c0d06caSMauro Carvalho Chehab .suspend = gspca_suspend, 5170c0d06caSMauro Carvalho Chehab .resume = gspca_resume, 5180c0d06caSMauro Carvalho Chehab .reset_resume = gspca_resume, 5190c0d06caSMauro Carvalho Chehab #endif 5200c0d06caSMauro Carvalho Chehab }; 5210c0d06caSMauro Carvalho Chehab 522e52ec680SSachin Kamat module_usb_driver(sd_driver); 523