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