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