1*0c0d06caSMauro Carvalho Chehab /* 2*0c0d06caSMauro Carvalho Chehab * Jeilin JL2005B/C/D library 3*0c0d06caSMauro Carvalho Chehab * 4*0c0d06caSMauro Carvalho Chehab * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.edu> 5*0c0d06caSMauro Carvalho Chehab * 6*0c0d06caSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 7*0c0d06caSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 8*0c0d06caSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 9*0c0d06caSMauro Carvalho Chehab * any later version. 10*0c0d06caSMauro Carvalho Chehab * 11*0c0d06caSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 12*0c0d06caSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*0c0d06caSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*0c0d06caSMauro Carvalho Chehab * GNU General Public License for more details. 15*0c0d06caSMauro Carvalho Chehab * 16*0c0d06caSMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 17*0c0d06caSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 18*0c0d06caSMauro Carvalho Chehab * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19*0c0d06caSMauro Carvalho Chehab */ 20*0c0d06caSMauro Carvalho Chehab 21*0c0d06caSMauro Carvalho Chehab #define MODULE_NAME "jl2005bcd" 22*0c0d06caSMauro Carvalho Chehab 23*0c0d06caSMauro Carvalho Chehab #include <linux/workqueue.h> 24*0c0d06caSMauro Carvalho Chehab #include <linux/slab.h> 25*0c0d06caSMauro Carvalho Chehab #include "gspca.h" 26*0c0d06caSMauro Carvalho Chehab 27*0c0d06caSMauro Carvalho Chehab 28*0c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>"); 29*0c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver"); 30*0c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 31*0c0d06caSMauro Carvalho Chehab 32*0c0d06caSMauro Carvalho Chehab /* Default timeouts, in ms */ 33*0c0d06caSMauro Carvalho Chehab #define JL2005C_CMD_TIMEOUT 500 34*0c0d06caSMauro Carvalho Chehab #define JL2005C_DATA_TIMEOUT 1000 35*0c0d06caSMauro Carvalho Chehab 36*0c0d06caSMauro Carvalho Chehab /* Maximum transfer size to use. */ 37*0c0d06caSMauro Carvalho Chehab #define JL2005C_MAX_TRANSFER 0x200 38*0c0d06caSMauro Carvalho Chehab #define FRAME_HEADER_LEN 16 39*0c0d06caSMauro Carvalho Chehab 40*0c0d06caSMauro Carvalho Chehab 41*0c0d06caSMauro Carvalho Chehab /* specific webcam descriptor */ 42*0c0d06caSMauro Carvalho Chehab struct sd { 43*0c0d06caSMauro Carvalho Chehab struct gspca_dev gspca_dev; /* !! must be the first item */ 44*0c0d06caSMauro Carvalho Chehab unsigned char firmware_id[6]; 45*0c0d06caSMauro Carvalho Chehab const struct v4l2_pix_format *cap_mode; 46*0c0d06caSMauro Carvalho Chehab /* Driver stuff */ 47*0c0d06caSMauro Carvalho Chehab struct work_struct work_struct; 48*0c0d06caSMauro Carvalho Chehab struct workqueue_struct *work_thread; 49*0c0d06caSMauro Carvalho Chehab u8 frame_brightness; 50*0c0d06caSMauro Carvalho Chehab int block_size; /* block size of camera */ 51*0c0d06caSMauro Carvalho Chehab int vga; /* 1 if vga cam, 0 if cif cam */ 52*0c0d06caSMauro Carvalho Chehab }; 53*0c0d06caSMauro Carvalho Chehab 54*0c0d06caSMauro Carvalho Chehab 55*0c0d06caSMauro Carvalho Chehab /* Camera has two resolution settings. What they are depends on model. */ 56*0c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format cif_mode[] = { 57*0c0d06caSMauro Carvalho Chehab {176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 58*0c0d06caSMauro Carvalho Chehab .bytesperline = 176, 59*0c0d06caSMauro Carvalho Chehab .sizeimage = 176 * 144, 60*0c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 61*0c0d06caSMauro Carvalho Chehab .priv = 0}, 62*0c0d06caSMauro Carvalho Chehab {352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 63*0c0d06caSMauro Carvalho Chehab .bytesperline = 352, 64*0c0d06caSMauro Carvalho Chehab .sizeimage = 352 * 288, 65*0c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 66*0c0d06caSMauro Carvalho Chehab .priv = 0}, 67*0c0d06caSMauro Carvalho Chehab }; 68*0c0d06caSMauro Carvalho Chehab 69*0c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format vga_mode[] = { 70*0c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 71*0c0d06caSMauro Carvalho Chehab .bytesperline = 320, 72*0c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240, 73*0c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 74*0c0d06caSMauro Carvalho Chehab .priv = 0}, 75*0c0d06caSMauro Carvalho Chehab {640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 76*0c0d06caSMauro Carvalho Chehab .bytesperline = 640, 77*0c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480, 78*0c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB, 79*0c0d06caSMauro Carvalho Chehab .priv = 0}, 80*0c0d06caSMauro Carvalho Chehab }; 81*0c0d06caSMauro Carvalho Chehab 82*0c0d06caSMauro Carvalho Chehab /* 83*0c0d06caSMauro Carvalho Chehab * cam uses endpoint 0x03 to send commands, 0x84 for read commands, 84*0c0d06caSMauro Carvalho Chehab * and 0x82 for bulk data transfer. 85*0c0d06caSMauro Carvalho Chehab */ 86*0c0d06caSMauro Carvalho Chehab 87*0c0d06caSMauro Carvalho Chehab /* All commands are two bytes only */ 88*0c0d06caSMauro Carvalho Chehab static int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command) 89*0c0d06caSMauro Carvalho Chehab { 90*0c0d06caSMauro Carvalho Chehab int retval; 91*0c0d06caSMauro Carvalho Chehab 92*0c0d06caSMauro Carvalho Chehab memcpy(gspca_dev->usb_buf, command, 2); 93*0c0d06caSMauro Carvalho Chehab retval = usb_bulk_msg(gspca_dev->dev, 94*0c0d06caSMauro Carvalho Chehab usb_sndbulkpipe(gspca_dev->dev, 3), 95*0c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf, 2, NULL, 500); 96*0c0d06caSMauro Carvalho Chehab if (retval < 0) 97*0c0d06caSMauro Carvalho Chehab pr_err("command write [%02x] error %d\n", 98*0c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0], retval); 99*0c0d06caSMauro Carvalho Chehab return retval; 100*0c0d06caSMauro Carvalho Chehab } 101*0c0d06caSMauro Carvalho Chehab 102*0c0d06caSMauro Carvalho Chehab /* Response to a command is one byte in usb_buf[0], only if requested. */ 103*0c0d06caSMauro Carvalho Chehab static int jl2005c_read1(struct gspca_dev *gspca_dev) 104*0c0d06caSMauro Carvalho Chehab { 105*0c0d06caSMauro Carvalho Chehab int retval; 106*0c0d06caSMauro Carvalho Chehab 107*0c0d06caSMauro Carvalho Chehab retval = usb_bulk_msg(gspca_dev->dev, 108*0c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(gspca_dev->dev, 0x84), 109*0c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf, 1, NULL, 500); 110*0c0d06caSMauro Carvalho Chehab if (retval < 0) 111*0c0d06caSMauro Carvalho Chehab pr_err("read command [0x%02x] error %d\n", 112*0c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0], retval); 113*0c0d06caSMauro Carvalho Chehab return retval; 114*0c0d06caSMauro Carvalho Chehab } 115*0c0d06caSMauro Carvalho Chehab 116*0c0d06caSMauro Carvalho Chehab /* Response appears in gspca_dev->usb_buf[0] */ 117*0c0d06caSMauro Carvalho Chehab static int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg) 118*0c0d06caSMauro Carvalho Chehab { 119*0c0d06caSMauro Carvalho Chehab int retval; 120*0c0d06caSMauro Carvalho Chehab 121*0c0d06caSMauro Carvalho Chehab static u8 instruction[2] = {0x95, 0x00}; 122*0c0d06caSMauro Carvalho Chehab /* put register to read in byte 1 */ 123*0c0d06caSMauro Carvalho Chehab instruction[1] = reg; 124*0c0d06caSMauro Carvalho Chehab /* Send the read request */ 125*0c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction); 126*0c0d06caSMauro Carvalho Chehab if (retval < 0) 127*0c0d06caSMauro Carvalho Chehab return retval; 128*0c0d06caSMauro Carvalho Chehab retval = jl2005c_read1(gspca_dev); 129*0c0d06caSMauro Carvalho Chehab 130*0c0d06caSMauro Carvalho Chehab return retval; 131*0c0d06caSMauro Carvalho Chehab } 132*0c0d06caSMauro Carvalho Chehab 133*0c0d06caSMauro Carvalho Chehab static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev) 134*0c0d06caSMauro Carvalho Chehab { 135*0c0d06caSMauro Carvalho Chehab int i; 136*0c0d06caSMauro Carvalho Chehab int retval; 137*0c0d06caSMauro Carvalho Chehab int frame_brightness = 0; 138*0c0d06caSMauro Carvalho Chehab 139*0c0d06caSMauro Carvalho Chehab static u8 instruction[2] = {0x7f, 0x01}; 140*0c0d06caSMauro Carvalho Chehab 141*0c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction); 142*0c0d06caSMauro Carvalho Chehab if (retval < 0) 143*0c0d06caSMauro Carvalho Chehab return retval; 144*0c0d06caSMauro Carvalho Chehab 145*0c0d06caSMauro Carvalho Chehab i = 0; 146*0c0d06caSMauro Carvalho Chehab while (i < 20 && !frame_brightness) { 147*0c0d06caSMauro Carvalho Chehab /* If we tried 20 times, give up. */ 148*0c0d06caSMauro Carvalho Chehab retval = jl2005c_read_reg(gspca_dev, 0x7e); 149*0c0d06caSMauro Carvalho Chehab if (retval < 0) 150*0c0d06caSMauro Carvalho Chehab return retval; 151*0c0d06caSMauro Carvalho Chehab frame_brightness = gspca_dev->usb_buf[0]; 152*0c0d06caSMauro Carvalho Chehab retval = jl2005c_read_reg(gspca_dev, 0x7d); 153*0c0d06caSMauro Carvalho Chehab if (retval < 0) 154*0c0d06caSMauro Carvalho Chehab return retval; 155*0c0d06caSMauro Carvalho Chehab i++; 156*0c0d06caSMauro Carvalho Chehab } 157*0c0d06caSMauro Carvalho Chehab PDEBUG(D_FRAM, "frame_brightness is 0x%02x", gspca_dev->usb_buf[0]); 158*0c0d06caSMauro Carvalho Chehab return retval; 159*0c0d06caSMauro Carvalho Chehab } 160*0c0d06caSMauro Carvalho Chehab 161*0c0d06caSMauro Carvalho Chehab static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg, 162*0c0d06caSMauro Carvalho Chehab unsigned char value) 163*0c0d06caSMauro Carvalho Chehab { 164*0c0d06caSMauro Carvalho Chehab int retval; 165*0c0d06caSMauro Carvalho Chehab u8 instruction[2]; 166*0c0d06caSMauro Carvalho Chehab 167*0c0d06caSMauro Carvalho Chehab instruction[0] = reg; 168*0c0d06caSMauro Carvalho Chehab instruction[1] = value; 169*0c0d06caSMauro Carvalho Chehab 170*0c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction); 171*0c0d06caSMauro Carvalho Chehab if (retval < 0) 172*0c0d06caSMauro Carvalho Chehab return retval; 173*0c0d06caSMauro Carvalho Chehab 174*0c0d06caSMauro Carvalho Chehab return retval; 175*0c0d06caSMauro Carvalho Chehab } 176*0c0d06caSMauro Carvalho Chehab 177*0c0d06caSMauro Carvalho Chehab static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev) 178*0c0d06caSMauro Carvalho Chehab { 179*0c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *)gspca_dev; 180*0c0d06caSMauro Carvalho Chehab int i = 0; 181*0c0d06caSMauro Carvalho Chehab int retval = -1; 182*0c0d06caSMauro Carvalho Chehab unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f}; 183*0c0d06caSMauro Carvalho Chehab 184*0c0d06caSMauro Carvalho Chehab PDEBUG(D_PROBE, "Running jl2005c_get_firmware_id"); 185*0c0d06caSMauro Carvalho Chehab /* Read the first ID byte once for warmup */ 186*0c0d06caSMauro Carvalho Chehab retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]); 187*0c0d06caSMauro Carvalho Chehab PDEBUG(D_PROBE, "response is %02x", gspca_dev->usb_buf[0]); 188*0c0d06caSMauro Carvalho Chehab if (retval < 0) 189*0c0d06caSMauro Carvalho Chehab return retval; 190*0c0d06caSMauro Carvalho Chehab /* Now actually get the ID string */ 191*0c0d06caSMauro Carvalho Chehab for (i = 0; i < 6; i++) { 192*0c0d06caSMauro Carvalho Chehab retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]); 193*0c0d06caSMauro Carvalho Chehab if (retval < 0) 194*0c0d06caSMauro Carvalho Chehab return retval; 195*0c0d06caSMauro Carvalho Chehab sd->firmware_id[i] = gspca_dev->usb_buf[0]; 196*0c0d06caSMauro Carvalho Chehab } 197*0c0d06caSMauro Carvalho Chehab PDEBUG(D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x", 198*0c0d06caSMauro Carvalho Chehab sd->firmware_id[0], 199*0c0d06caSMauro Carvalho Chehab sd->firmware_id[1], 200*0c0d06caSMauro Carvalho Chehab sd->firmware_id[2], 201*0c0d06caSMauro Carvalho Chehab sd->firmware_id[3], 202*0c0d06caSMauro Carvalho Chehab sd->firmware_id[4], 203*0c0d06caSMauro Carvalho Chehab sd->firmware_id[5]); 204*0c0d06caSMauro Carvalho Chehab return 0; 205*0c0d06caSMauro Carvalho Chehab } 206*0c0d06caSMauro Carvalho Chehab 207*0c0d06caSMauro Carvalho Chehab static int jl2005c_stream_start_vga_lg 208*0c0d06caSMauro Carvalho Chehab (struct gspca_dev *gspca_dev) 209*0c0d06caSMauro Carvalho Chehab { 210*0c0d06caSMauro Carvalho Chehab int i; 211*0c0d06caSMauro Carvalho Chehab int retval = -1; 212*0c0d06caSMauro Carvalho Chehab static u8 instruction[][2] = { 213*0c0d06caSMauro Carvalho Chehab {0x05, 0x00}, 214*0c0d06caSMauro Carvalho Chehab {0x7c, 0x00}, 215*0c0d06caSMauro Carvalho Chehab {0x7d, 0x18}, 216*0c0d06caSMauro Carvalho Chehab {0x02, 0x00}, 217*0c0d06caSMauro Carvalho Chehab {0x01, 0x00}, 218*0c0d06caSMauro Carvalho Chehab {0x04, 0x52}, 219*0c0d06caSMauro Carvalho Chehab }; 220*0c0d06caSMauro Carvalho Chehab 221*0c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(instruction); i++) { 222*0c0d06caSMauro Carvalho Chehab msleep(60); 223*0c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction[i]); 224*0c0d06caSMauro Carvalho Chehab if (retval < 0) 225*0c0d06caSMauro Carvalho Chehab return retval; 226*0c0d06caSMauro Carvalho Chehab } 227*0c0d06caSMauro Carvalho Chehab msleep(60); 228*0c0d06caSMauro Carvalho Chehab return retval; 229*0c0d06caSMauro Carvalho Chehab } 230*0c0d06caSMauro Carvalho Chehab 231*0c0d06caSMauro Carvalho Chehab static int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev) 232*0c0d06caSMauro Carvalho Chehab { 233*0c0d06caSMauro Carvalho Chehab int i; 234*0c0d06caSMauro Carvalho Chehab int retval = -1; 235*0c0d06caSMauro Carvalho Chehab static u8 instruction[][2] = { 236*0c0d06caSMauro Carvalho Chehab {0x06, 0x00}, 237*0c0d06caSMauro Carvalho Chehab {0x7c, 0x00}, 238*0c0d06caSMauro Carvalho Chehab {0x7d, 0x1a}, 239*0c0d06caSMauro Carvalho Chehab {0x02, 0x00}, 240*0c0d06caSMauro Carvalho Chehab {0x01, 0x00}, 241*0c0d06caSMauro Carvalho Chehab {0x04, 0x52}, 242*0c0d06caSMauro Carvalho Chehab }; 243*0c0d06caSMauro Carvalho Chehab 244*0c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(instruction); i++) { 245*0c0d06caSMauro Carvalho Chehab msleep(60); 246*0c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction[i]); 247*0c0d06caSMauro Carvalho Chehab if (retval < 0) 248*0c0d06caSMauro Carvalho Chehab return retval; 249*0c0d06caSMauro Carvalho Chehab } 250*0c0d06caSMauro Carvalho Chehab msleep(60); 251*0c0d06caSMauro Carvalho Chehab return retval; 252*0c0d06caSMauro Carvalho Chehab } 253*0c0d06caSMauro Carvalho Chehab 254*0c0d06caSMauro Carvalho Chehab static int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev) 255*0c0d06caSMauro Carvalho Chehab { 256*0c0d06caSMauro Carvalho Chehab int i; 257*0c0d06caSMauro Carvalho Chehab int retval = -1; 258*0c0d06caSMauro Carvalho Chehab static u8 instruction[][2] = { 259*0c0d06caSMauro Carvalho Chehab {0x05, 0x00}, 260*0c0d06caSMauro Carvalho Chehab {0x7c, 0x00}, 261*0c0d06caSMauro Carvalho Chehab {0x7d, 0x30}, 262*0c0d06caSMauro Carvalho Chehab {0x02, 0x00}, 263*0c0d06caSMauro Carvalho Chehab {0x01, 0x00}, 264*0c0d06caSMauro Carvalho Chehab {0x04, 0x42}, 265*0c0d06caSMauro Carvalho Chehab }; 266*0c0d06caSMauro Carvalho Chehab 267*0c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(instruction); i++) { 268*0c0d06caSMauro Carvalho Chehab msleep(60); 269*0c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction[i]); 270*0c0d06caSMauro Carvalho Chehab if (retval < 0) 271*0c0d06caSMauro Carvalho Chehab return retval; 272*0c0d06caSMauro Carvalho Chehab } 273*0c0d06caSMauro Carvalho Chehab msleep(60); 274*0c0d06caSMauro Carvalho Chehab return retval; 275*0c0d06caSMauro Carvalho Chehab } 276*0c0d06caSMauro Carvalho Chehab 277*0c0d06caSMauro Carvalho Chehab static int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev) 278*0c0d06caSMauro Carvalho Chehab { 279*0c0d06caSMauro Carvalho Chehab int i; 280*0c0d06caSMauro Carvalho Chehab int retval = -1; 281*0c0d06caSMauro Carvalho Chehab static u8 instruction[][2] = { 282*0c0d06caSMauro Carvalho Chehab {0x06, 0x00}, 283*0c0d06caSMauro Carvalho Chehab {0x7c, 0x00}, 284*0c0d06caSMauro Carvalho Chehab {0x7d, 0x32}, 285*0c0d06caSMauro Carvalho Chehab {0x02, 0x00}, 286*0c0d06caSMauro Carvalho Chehab {0x01, 0x00}, 287*0c0d06caSMauro Carvalho Chehab {0x04, 0x42}, 288*0c0d06caSMauro Carvalho Chehab }; 289*0c0d06caSMauro Carvalho Chehab 290*0c0d06caSMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(instruction); i++) { 291*0c0d06caSMauro Carvalho Chehab msleep(60); 292*0c0d06caSMauro Carvalho Chehab retval = jl2005c_write2(gspca_dev, instruction[i]); 293*0c0d06caSMauro Carvalho Chehab if (retval < 0) 294*0c0d06caSMauro Carvalho Chehab return retval; 295*0c0d06caSMauro Carvalho Chehab } 296*0c0d06caSMauro Carvalho Chehab msleep(60); 297*0c0d06caSMauro Carvalho Chehab return retval; 298*0c0d06caSMauro Carvalho Chehab } 299*0c0d06caSMauro Carvalho Chehab 300*0c0d06caSMauro Carvalho Chehab 301*0c0d06caSMauro Carvalho Chehab static int jl2005c_stop(struct gspca_dev *gspca_dev) 302*0c0d06caSMauro Carvalho Chehab { 303*0c0d06caSMauro Carvalho Chehab int retval; 304*0c0d06caSMauro Carvalho Chehab 305*0c0d06caSMauro Carvalho Chehab retval = jl2005c_write_reg(gspca_dev, 0x07, 0x00); 306*0c0d06caSMauro Carvalho Chehab return retval; 307*0c0d06caSMauro Carvalho Chehab } 308*0c0d06caSMauro Carvalho Chehab 309*0c0d06caSMauro Carvalho Chehab /* This function is called as a workqueue function and runs whenever the camera 310*0c0d06caSMauro Carvalho Chehab * is streaming data. Because it is a workqueue function it is allowed to sleep 311*0c0d06caSMauro Carvalho Chehab * so we can use synchronous USB calls. To avoid possible collisions with other 312*0c0d06caSMauro Carvalho Chehab * threads attempting to use the camera's USB interface the gspca usb_lock is 313*0c0d06caSMauro Carvalho Chehab * used when performing the one USB control operation inside the workqueue, 314*0c0d06caSMauro Carvalho Chehab * which tells the camera to close the stream. In practice the only thing 315*0c0d06caSMauro Carvalho Chehab * which needs to be protected against is the usb_set_interface call that 316*0c0d06caSMauro Carvalho Chehab * gspca makes during stream_off. Otherwise the camera doesn't provide any 317*0c0d06caSMauro Carvalho Chehab * controls that the user could try to change. 318*0c0d06caSMauro Carvalho Chehab */ 319*0c0d06caSMauro Carvalho Chehab static void jl2005c_dostream(struct work_struct *work) 320*0c0d06caSMauro Carvalho Chehab { 321*0c0d06caSMauro Carvalho Chehab struct sd *dev = container_of(work, struct sd, work_struct); 322*0c0d06caSMauro Carvalho Chehab struct gspca_dev *gspca_dev = &dev->gspca_dev; 323*0c0d06caSMauro Carvalho Chehab int bytes_left = 0; /* bytes remaining in current frame. */ 324*0c0d06caSMauro Carvalho Chehab int data_len; /* size to use for the next read. */ 325*0c0d06caSMauro Carvalho Chehab int header_read = 0; 326*0c0d06caSMauro Carvalho Chehab unsigned char header_sig[2] = {0x4a, 0x4c}; 327*0c0d06caSMauro Carvalho Chehab int act_len; 328*0c0d06caSMauro Carvalho Chehab int packet_type; 329*0c0d06caSMauro Carvalho Chehab int ret; 330*0c0d06caSMauro Carvalho Chehab u8 *buffer; 331*0c0d06caSMauro Carvalho Chehab 332*0c0d06caSMauro Carvalho Chehab buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); 333*0c0d06caSMauro Carvalho Chehab if (!buffer) { 334*0c0d06caSMauro Carvalho Chehab pr_err("Couldn't allocate USB buffer\n"); 335*0c0d06caSMauro Carvalho Chehab goto quit_stream; 336*0c0d06caSMauro Carvalho Chehab } 337*0c0d06caSMauro Carvalho Chehab 338*0c0d06caSMauro Carvalho Chehab while (gspca_dev->dev && gspca_dev->streaming) { 339*0c0d06caSMauro Carvalho Chehab #ifdef CONFIG_PM 340*0c0d06caSMauro Carvalho Chehab if (gspca_dev->frozen) 341*0c0d06caSMauro Carvalho Chehab break; 342*0c0d06caSMauro Carvalho Chehab #endif 343*0c0d06caSMauro Carvalho Chehab /* Check if this is a new frame. If so, start the frame first */ 344*0c0d06caSMauro Carvalho Chehab if (!header_read) { 345*0c0d06caSMauro Carvalho Chehab mutex_lock(&gspca_dev->usb_lock); 346*0c0d06caSMauro Carvalho Chehab ret = jl2005c_start_new_frame(gspca_dev); 347*0c0d06caSMauro Carvalho Chehab mutex_unlock(&gspca_dev->usb_lock); 348*0c0d06caSMauro Carvalho Chehab if (ret < 0) 349*0c0d06caSMauro Carvalho Chehab goto quit_stream; 350*0c0d06caSMauro Carvalho Chehab ret = usb_bulk_msg(gspca_dev->dev, 351*0c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(gspca_dev->dev, 0x82), 352*0c0d06caSMauro Carvalho Chehab buffer, JL2005C_MAX_TRANSFER, &act_len, 353*0c0d06caSMauro Carvalho Chehab JL2005C_DATA_TIMEOUT); 354*0c0d06caSMauro Carvalho Chehab PDEBUG(D_PACK, 355*0c0d06caSMauro Carvalho Chehab "Got %d bytes out of %d for header", 356*0c0d06caSMauro Carvalho Chehab act_len, JL2005C_MAX_TRANSFER); 357*0c0d06caSMauro Carvalho Chehab if (ret < 0 || act_len < JL2005C_MAX_TRANSFER) 358*0c0d06caSMauro Carvalho Chehab goto quit_stream; 359*0c0d06caSMauro Carvalho Chehab /* Check whether we actually got the first blodk */ 360*0c0d06caSMauro Carvalho Chehab if (memcmp(header_sig, buffer, 2) != 0) { 361*0c0d06caSMauro Carvalho Chehab pr_err("First block is not the first block\n"); 362*0c0d06caSMauro Carvalho Chehab goto quit_stream; 363*0c0d06caSMauro Carvalho Chehab } 364*0c0d06caSMauro Carvalho Chehab /* total size to fetch is byte 7, times blocksize 365*0c0d06caSMauro Carvalho Chehab * of which we already got act_len */ 366*0c0d06caSMauro Carvalho Chehab bytes_left = buffer[0x07] * dev->block_size - act_len; 367*0c0d06caSMauro Carvalho Chehab PDEBUG(D_PACK, "bytes_left = 0x%x", bytes_left); 368*0c0d06caSMauro Carvalho Chehab /* We keep the header. It has other information, too.*/ 369*0c0d06caSMauro Carvalho Chehab packet_type = FIRST_PACKET; 370*0c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, packet_type, 371*0c0d06caSMauro Carvalho Chehab buffer, act_len); 372*0c0d06caSMauro Carvalho Chehab header_read = 1; 373*0c0d06caSMauro Carvalho Chehab } 374*0c0d06caSMauro Carvalho Chehab while (bytes_left > 0 && gspca_dev->dev) { 375*0c0d06caSMauro Carvalho Chehab data_len = bytes_left > JL2005C_MAX_TRANSFER ? 376*0c0d06caSMauro Carvalho Chehab JL2005C_MAX_TRANSFER : bytes_left; 377*0c0d06caSMauro Carvalho Chehab ret = usb_bulk_msg(gspca_dev->dev, 378*0c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(gspca_dev->dev, 0x82), 379*0c0d06caSMauro Carvalho Chehab buffer, data_len, &act_len, 380*0c0d06caSMauro Carvalho Chehab JL2005C_DATA_TIMEOUT); 381*0c0d06caSMauro Carvalho Chehab if (ret < 0 || act_len < data_len) 382*0c0d06caSMauro Carvalho Chehab goto quit_stream; 383*0c0d06caSMauro Carvalho Chehab PDEBUG(D_PACK, 384*0c0d06caSMauro Carvalho Chehab "Got %d bytes out of %d for frame", 385*0c0d06caSMauro Carvalho Chehab data_len, bytes_left); 386*0c0d06caSMauro Carvalho Chehab bytes_left -= data_len; 387*0c0d06caSMauro Carvalho Chehab if (bytes_left == 0) { 388*0c0d06caSMauro Carvalho Chehab packet_type = LAST_PACKET; 389*0c0d06caSMauro Carvalho Chehab header_read = 0; 390*0c0d06caSMauro Carvalho Chehab } else 391*0c0d06caSMauro Carvalho Chehab packet_type = INTER_PACKET; 392*0c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, packet_type, 393*0c0d06caSMauro Carvalho Chehab buffer, data_len); 394*0c0d06caSMauro Carvalho Chehab } 395*0c0d06caSMauro Carvalho Chehab } 396*0c0d06caSMauro Carvalho Chehab quit_stream: 397*0c0d06caSMauro Carvalho Chehab if (gspca_dev->dev) { 398*0c0d06caSMauro Carvalho Chehab mutex_lock(&gspca_dev->usb_lock); 399*0c0d06caSMauro Carvalho Chehab jl2005c_stop(gspca_dev); 400*0c0d06caSMauro Carvalho Chehab mutex_unlock(&gspca_dev->usb_lock); 401*0c0d06caSMauro Carvalho Chehab } 402*0c0d06caSMauro Carvalho Chehab kfree(buffer); 403*0c0d06caSMauro Carvalho Chehab } 404*0c0d06caSMauro Carvalho Chehab 405*0c0d06caSMauro Carvalho Chehab 406*0c0d06caSMauro Carvalho Chehab 407*0c0d06caSMauro Carvalho Chehab 408*0c0d06caSMauro Carvalho Chehab /* This function is called at probe time */ 409*0c0d06caSMauro Carvalho Chehab static int sd_config(struct gspca_dev *gspca_dev, 410*0c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 411*0c0d06caSMauro Carvalho Chehab { 412*0c0d06caSMauro Carvalho Chehab struct cam *cam; 413*0c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 414*0c0d06caSMauro Carvalho Chehab 415*0c0d06caSMauro Carvalho Chehab cam = &gspca_dev->cam; 416*0c0d06caSMauro Carvalho Chehab /* We don't use the buffer gspca allocates so make it small. */ 417*0c0d06caSMauro Carvalho Chehab cam->bulk_size = 64; 418*0c0d06caSMauro Carvalho Chehab cam->bulk = 1; 419*0c0d06caSMauro Carvalho Chehab /* For the rest, the camera needs to be detected */ 420*0c0d06caSMauro Carvalho Chehab jl2005c_get_firmware_id(gspca_dev); 421*0c0d06caSMauro Carvalho Chehab /* Here are some known firmware IDs 422*0c0d06caSMauro Carvalho Chehab * First some JL2005B cameras 423*0c0d06caSMauro Carvalho Chehab * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2} Sakar KidzCam 424*0c0d06caSMauro Carvalho Chehab * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2} No-name JL2005B 425*0c0d06caSMauro Carvalho Chehab * JL2005C cameras 426*0c0d06caSMauro Carvalho Chehab * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8} Argus DC-1512 427*0c0d06caSMauro Carvalho Chehab * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8} ICarly 428*0c0d06caSMauro Carvalho Chehab * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4} Jazz 429*0c0d06caSMauro Carvalho Chehab * 430*0c0d06caSMauro Carvalho Chehab * Based upon this scanty evidence, we can detect a CIF camera by 431*0c0d06caSMauro Carvalho Chehab * testing byte 0 for 0x4x. 432*0c0d06caSMauro Carvalho Chehab */ 433*0c0d06caSMauro Carvalho Chehab if ((sd->firmware_id[0] & 0xf0) == 0x40) { 434*0c0d06caSMauro Carvalho Chehab cam->cam_mode = cif_mode; 435*0c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(cif_mode); 436*0c0d06caSMauro Carvalho Chehab sd->block_size = 0x80; 437*0c0d06caSMauro Carvalho Chehab } else { 438*0c0d06caSMauro Carvalho Chehab cam->cam_mode = vga_mode; 439*0c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(vga_mode); 440*0c0d06caSMauro Carvalho Chehab sd->block_size = 0x200; 441*0c0d06caSMauro Carvalho Chehab } 442*0c0d06caSMauro Carvalho Chehab 443*0c0d06caSMauro Carvalho Chehab INIT_WORK(&sd->work_struct, jl2005c_dostream); 444*0c0d06caSMauro Carvalho Chehab 445*0c0d06caSMauro Carvalho Chehab return 0; 446*0c0d06caSMauro Carvalho Chehab } 447*0c0d06caSMauro Carvalho Chehab 448*0c0d06caSMauro Carvalho Chehab /* this function is called at probe and resume time */ 449*0c0d06caSMauro Carvalho Chehab static int sd_init(struct gspca_dev *gspca_dev) 450*0c0d06caSMauro Carvalho Chehab { 451*0c0d06caSMauro Carvalho Chehab return 0; 452*0c0d06caSMauro Carvalho Chehab } 453*0c0d06caSMauro Carvalho Chehab 454*0c0d06caSMauro Carvalho Chehab static int sd_start(struct gspca_dev *gspca_dev) 455*0c0d06caSMauro Carvalho Chehab { 456*0c0d06caSMauro Carvalho Chehab 457*0c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 458*0c0d06caSMauro Carvalho Chehab sd->cap_mode = gspca_dev->cam.cam_mode; 459*0c0d06caSMauro Carvalho Chehab 460*0c0d06caSMauro Carvalho Chehab switch (gspca_dev->width) { 461*0c0d06caSMauro Carvalho Chehab case 640: 462*0c0d06caSMauro Carvalho Chehab PDEBUG(D_STREAM, "Start streaming at vga resolution"); 463*0c0d06caSMauro Carvalho Chehab jl2005c_stream_start_vga_lg(gspca_dev); 464*0c0d06caSMauro Carvalho Chehab break; 465*0c0d06caSMauro Carvalho Chehab case 320: 466*0c0d06caSMauro Carvalho Chehab PDEBUG(D_STREAM, "Start streaming at qvga resolution"); 467*0c0d06caSMauro Carvalho Chehab jl2005c_stream_start_vga_small(gspca_dev); 468*0c0d06caSMauro Carvalho Chehab break; 469*0c0d06caSMauro Carvalho Chehab case 352: 470*0c0d06caSMauro Carvalho Chehab PDEBUG(D_STREAM, "Start streaming at cif resolution"); 471*0c0d06caSMauro Carvalho Chehab jl2005c_stream_start_cif_lg(gspca_dev); 472*0c0d06caSMauro Carvalho Chehab break; 473*0c0d06caSMauro Carvalho Chehab case 176: 474*0c0d06caSMauro Carvalho Chehab PDEBUG(D_STREAM, "Start streaming at qcif resolution"); 475*0c0d06caSMauro Carvalho Chehab jl2005c_stream_start_cif_small(gspca_dev); 476*0c0d06caSMauro Carvalho Chehab break; 477*0c0d06caSMauro Carvalho Chehab default: 478*0c0d06caSMauro Carvalho Chehab pr_err("Unknown resolution specified\n"); 479*0c0d06caSMauro Carvalho Chehab return -1; 480*0c0d06caSMauro Carvalho Chehab } 481*0c0d06caSMauro Carvalho Chehab 482*0c0d06caSMauro Carvalho Chehab /* Start the workqueue function to do the streaming */ 483*0c0d06caSMauro Carvalho Chehab sd->work_thread = create_singlethread_workqueue(MODULE_NAME); 484*0c0d06caSMauro Carvalho Chehab queue_work(sd->work_thread, &sd->work_struct); 485*0c0d06caSMauro Carvalho Chehab 486*0c0d06caSMauro Carvalho Chehab return 0; 487*0c0d06caSMauro Carvalho Chehab } 488*0c0d06caSMauro Carvalho Chehab 489*0c0d06caSMauro Carvalho Chehab /* called on streamoff with alt==0 and on disconnect */ 490*0c0d06caSMauro Carvalho Chehab /* the usb_lock is held at entry - restore on exit */ 491*0c0d06caSMauro Carvalho Chehab static void sd_stop0(struct gspca_dev *gspca_dev) 492*0c0d06caSMauro Carvalho Chehab { 493*0c0d06caSMauro Carvalho Chehab struct sd *dev = (struct sd *) gspca_dev; 494*0c0d06caSMauro Carvalho Chehab 495*0c0d06caSMauro Carvalho Chehab /* wait for the work queue to terminate */ 496*0c0d06caSMauro Carvalho Chehab mutex_unlock(&gspca_dev->usb_lock); 497*0c0d06caSMauro Carvalho Chehab /* This waits for sq905c_dostream to finish */ 498*0c0d06caSMauro Carvalho Chehab destroy_workqueue(dev->work_thread); 499*0c0d06caSMauro Carvalho Chehab dev->work_thread = NULL; 500*0c0d06caSMauro Carvalho Chehab mutex_lock(&gspca_dev->usb_lock); 501*0c0d06caSMauro Carvalho Chehab } 502*0c0d06caSMauro Carvalho Chehab 503*0c0d06caSMauro Carvalho Chehab 504*0c0d06caSMauro Carvalho Chehab 505*0c0d06caSMauro Carvalho Chehab /* sub-driver description */ 506*0c0d06caSMauro Carvalho Chehab static const struct sd_desc sd_desc = { 507*0c0d06caSMauro Carvalho Chehab .name = MODULE_NAME, 508*0c0d06caSMauro Carvalho Chehab .config = sd_config, 509*0c0d06caSMauro Carvalho Chehab .init = sd_init, 510*0c0d06caSMauro Carvalho Chehab .start = sd_start, 511*0c0d06caSMauro Carvalho Chehab .stop0 = sd_stop0, 512*0c0d06caSMauro Carvalho Chehab }; 513*0c0d06caSMauro Carvalho Chehab 514*0c0d06caSMauro Carvalho Chehab /* -- module initialisation -- */ 515*0c0d06caSMauro Carvalho Chehab static const __devinitdata struct usb_device_id device_table[] = { 516*0c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x0979, 0x0227)}, 517*0c0d06caSMauro Carvalho Chehab {} 518*0c0d06caSMauro Carvalho Chehab }; 519*0c0d06caSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, device_table); 520*0c0d06caSMauro Carvalho Chehab 521*0c0d06caSMauro Carvalho Chehab /* -- device connect -- */ 522*0c0d06caSMauro Carvalho Chehab static int sd_probe(struct usb_interface *intf, 523*0c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 524*0c0d06caSMauro Carvalho Chehab { 525*0c0d06caSMauro Carvalho Chehab return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 526*0c0d06caSMauro Carvalho Chehab THIS_MODULE); 527*0c0d06caSMauro Carvalho Chehab } 528*0c0d06caSMauro Carvalho Chehab 529*0c0d06caSMauro Carvalho Chehab static struct usb_driver sd_driver = { 530*0c0d06caSMauro Carvalho Chehab .name = MODULE_NAME, 531*0c0d06caSMauro Carvalho Chehab .id_table = device_table, 532*0c0d06caSMauro Carvalho Chehab .probe = sd_probe, 533*0c0d06caSMauro Carvalho Chehab .disconnect = gspca_disconnect, 534*0c0d06caSMauro Carvalho Chehab #ifdef CONFIG_PM 535*0c0d06caSMauro Carvalho Chehab .suspend = gspca_suspend, 536*0c0d06caSMauro Carvalho Chehab .resume = gspca_resume, 537*0c0d06caSMauro Carvalho Chehab .reset_resume = gspca_resume, 538*0c0d06caSMauro Carvalho Chehab #endif 539*0c0d06caSMauro Carvalho Chehab }; 540*0c0d06caSMauro Carvalho Chehab 541*0c0d06caSMauro Carvalho Chehab /* -- module insert / remove -- */ 542*0c0d06caSMauro Carvalho Chehab static int __init sd_mod_init(void) 543*0c0d06caSMauro Carvalho Chehab { 544*0c0d06caSMauro Carvalho Chehab int ret; 545*0c0d06caSMauro Carvalho Chehab 546*0c0d06caSMauro Carvalho Chehab ret = usb_register(&sd_driver); 547*0c0d06caSMauro Carvalho Chehab if (ret < 0) 548*0c0d06caSMauro Carvalho Chehab return ret; 549*0c0d06caSMauro Carvalho Chehab return 0; 550*0c0d06caSMauro Carvalho Chehab } 551*0c0d06caSMauro Carvalho Chehab static void __exit sd_mod_exit(void) 552*0c0d06caSMauro Carvalho Chehab { 553*0c0d06caSMauro Carvalho Chehab usb_deregister(&sd_driver); 554*0c0d06caSMauro Carvalho Chehab } 555*0c0d06caSMauro Carvalho Chehab 556*0c0d06caSMauro Carvalho Chehab module_init(sd_mod_init); 557*0c0d06caSMauro Carvalho Chehab module_exit(sd_mod_exit); 558