162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Jeilin JL2005B/C/D library 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.edu> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define MODULE_NAME "jl2005bcd" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/workqueue.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include "gspca.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciMODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>"); 1662306a36Sopenharmony_ciMODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver"); 1762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* Default timeouts, in ms */ 2062306a36Sopenharmony_ci#define JL2005C_CMD_TIMEOUT 500 2162306a36Sopenharmony_ci#define JL2005C_DATA_TIMEOUT 1000 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Maximum transfer size to use. */ 2462306a36Sopenharmony_ci#define JL2005C_MAX_TRANSFER 0x200 2562306a36Sopenharmony_ci#define FRAME_HEADER_LEN 16 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* specific webcam descriptor */ 2962306a36Sopenharmony_cistruct sd { 3062306a36Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 3162306a36Sopenharmony_ci unsigned char firmware_id[6]; 3262306a36Sopenharmony_ci const struct v4l2_pix_format *cap_mode; 3362306a36Sopenharmony_ci /* Driver stuff */ 3462306a36Sopenharmony_ci struct work_struct work_struct; 3562306a36Sopenharmony_ci u8 frame_brightness; 3662306a36Sopenharmony_ci int block_size; /* block size of camera */ 3762306a36Sopenharmony_ci int vga; /* 1 if vga cam, 0 if cif cam */ 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Camera has two resolution settings. What they are depends on model. */ 4262306a36Sopenharmony_cistatic const struct v4l2_pix_format cif_mode[] = { 4362306a36Sopenharmony_ci {176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 4462306a36Sopenharmony_ci .bytesperline = 176, 4562306a36Sopenharmony_ci .sizeimage = 176 * 144, 4662306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 4762306a36Sopenharmony_ci .priv = 0}, 4862306a36Sopenharmony_ci {352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 4962306a36Sopenharmony_ci .bytesperline = 352, 5062306a36Sopenharmony_ci .sizeimage = 352 * 288, 5162306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 5262306a36Sopenharmony_ci .priv = 0}, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic const struct v4l2_pix_format vga_mode[] = { 5662306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 5762306a36Sopenharmony_ci .bytesperline = 320, 5862306a36Sopenharmony_ci .sizeimage = 320 * 240, 5962306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 6062306a36Sopenharmony_ci .priv = 0}, 6162306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, 6262306a36Sopenharmony_ci .bytesperline = 640, 6362306a36Sopenharmony_ci .sizeimage = 640 * 480, 6462306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 6562306a36Sopenharmony_ci .priv = 0}, 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 6962306a36Sopenharmony_ci * cam uses endpoint 0x03 to send commands, 0x84 for read commands, 7062306a36Sopenharmony_ci * and 0x82 for bulk data transfer. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* All commands are two bytes only */ 7462306a36Sopenharmony_cistatic int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int retval; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci memcpy(gspca_dev->usb_buf, command, 2); 7962306a36Sopenharmony_ci retval = usb_bulk_msg(gspca_dev->dev, 8062306a36Sopenharmony_ci usb_sndbulkpipe(gspca_dev->dev, 3), 8162306a36Sopenharmony_ci gspca_dev->usb_buf, 2, NULL, 500); 8262306a36Sopenharmony_ci if (retval < 0) 8362306a36Sopenharmony_ci pr_err("command write [%02x] error %d\n", 8462306a36Sopenharmony_ci gspca_dev->usb_buf[0], retval); 8562306a36Sopenharmony_ci return retval; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* Response to a command is one byte in usb_buf[0], only if requested. */ 8962306a36Sopenharmony_cistatic int jl2005c_read1(struct gspca_dev *gspca_dev) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci int retval; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci retval = usb_bulk_msg(gspca_dev->dev, 9462306a36Sopenharmony_ci usb_rcvbulkpipe(gspca_dev->dev, 0x84), 9562306a36Sopenharmony_ci gspca_dev->usb_buf, 1, NULL, 500); 9662306a36Sopenharmony_ci if (retval < 0) 9762306a36Sopenharmony_ci pr_err("read command [0x%02x] error %d\n", 9862306a36Sopenharmony_ci gspca_dev->usb_buf[0], retval); 9962306a36Sopenharmony_ci return retval; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* Response appears in gspca_dev->usb_buf[0] */ 10362306a36Sopenharmony_cistatic int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci int retval; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci static u8 instruction[2] = {0x95, 0x00}; 10862306a36Sopenharmony_ci /* put register to read in byte 1 */ 10962306a36Sopenharmony_ci instruction[1] = reg; 11062306a36Sopenharmony_ci /* Send the read request */ 11162306a36Sopenharmony_ci retval = jl2005c_write2(gspca_dev, instruction); 11262306a36Sopenharmony_ci if (retval < 0) 11362306a36Sopenharmony_ci return retval; 11462306a36Sopenharmony_ci retval = jl2005c_read1(gspca_dev); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return retval; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int jl2005c_start_new_frame(struct gspca_dev *gspca_dev) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci int i; 12262306a36Sopenharmony_ci int retval; 12362306a36Sopenharmony_ci int frame_brightness = 0; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci static u8 instruction[2] = {0x7f, 0x01}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci retval = jl2005c_write2(gspca_dev, instruction); 12862306a36Sopenharmony_ci if (retval < 0) 12962306a36Sopenharmony_ci return retval; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci i = 0; 13262306a36Sopenharmony_ci while (i < 20 && !frame_brightness) { 13362306a36Sopenharmony_ci /* If we tried 20 times, give up. */ 13462306a36Sopenharmony_ci retval = jl2005c_read_reg(gspca_dev, 0x7e); 13562306a36Sopenharmony_ci if (retval < 0) 13662306a36Sopenharmony_ci return retval; 13762306a36Sopenharmony_ci frame_brightness = gspca_dev->usb_buf[0]; 13862306a36Sopenharmony_ci retval = jl2005c_read_reg(gspca_dev, 0x7d); 13962306a36Sopenharmony_ci if (retval < 0) 14062306a36Sopenharmony_ci return retval; 14162306a36Sopenharmony_ci i++; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_FRAM, "frame_brightness is 0x%02x\n", 14462306a36Sopenharmony_ci gspca_dev->usb_buf[0]); 14562306a36Sopenharmony_ci return retval; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg, 14962306a36Sopenharmony_ci unsigned char value) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci int retval; 15262306a36Sopenharmony_ci u8 instruction[2]; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci instruction[0] = reg; 15562306a36Sopenharmony_ci instruction[1] = value; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci retval = jl2005c_write2(gspca_dev, instruction); 15862306a36Sopenharmony_ci if (retval < 0) 15962306a36Sopenharmony_ci return retval; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return retval; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct sd *sd = (struct sd *)gspca_dev; 16762306a36Sopenharmony_ci int i = 0; 16862306a36Sopenharmony_ci int retval; 16962306a36Sopenharmony_ci static const unsigned char regs_to_read[] = { 17062306a36Sopenharmony_ci 0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f 17162306a36Sopenharmony_ci }; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "Running jl2005c_get_firmware_id\n"); 17462306a36Sopenharmony_ci /* Read the first ID byte once for warmup */ 17562306a36Sopenharmony_ci retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]); 17662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "response is %02x\n", 17762306a36Sopenharmony_ci gspca_dev->usb_buf[0]); 17862306a36Sopenharmony_ci if (retval < 0) 17962306a36Sopenharmony_ci return retval; 18062306a36Sopenharmony_ci /* Now actually get the ID string */ 18162306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 18262306a36Sopenharmony_ci retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]); 18362306a36Sopenharmony_ci if (retval < 0) 18462306a36Sopenharmony_ci return retval; 18562306a36Sopenharmony_ci sd->firmware_id[i] = gspca_dev->usb_buf[0]; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x\n", 18862306a36Sopenharmony_ci sd->firmware_id[0], 18962306a36Sopenharmony_ci sd->firmware_id[1], 19062306a36Sopenharmony_ci sd->firmware_id[2], 19162306a36Sopenharmony_ci sd->firmware_id[3], 19262306a36Sopenharmony_ci sd->firmware_id[4], 19362306a36Sopenharmony_ci sd->firmware_id[5]); 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int jl2005c_stream_start_vga_lg 19862306a36Sopenharmony_ci (struct gspca_dev *gspca_dev) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci int i; 20162306a36Sopenharmony_ci int retval = -1; 20262306a36Sopenharmony_ci static u8 instruction[][2] = { 20362306a36Sopenharmony_ci {0x05, 0x00}, 20462306a36Sopenharmony_ci {0x7c, 0x00}, 20562306a36Sopenharmony_ci {0x7d, 0x18}, 20662306a36Sopenharmony_ci {0x02, 0x00}, 20762306a36Sopenharmony_ci {0x01, 0x00}, 20862306a36Sopenharmony_ci {0x04, 0x52}, 20962306a36Sopenharmony_ci }; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(instruction); i++) { 21262306a36Sopenharmony_ci msleep(60); 21362306a36Sopenharmony_ci retval = jl2005c_write2(gspca_dev, instruction[i]); 21462306a36Sopenharmony_ci if (retval < 0) 21562306a36Sopenharmony_ci return retval; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci msleep(60); 21862306a36Sopenharmony_ci return retval; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci int i; 22462306a36Sopenharmony_ci int retval = -1; 22562306a36Sopenharmony_ci static u8 instruction[][2] = { 22662306a36Sopenharmony_ci {0x06, 0x00}, 22762306a36Sopenharmony_ci {0x7c, 0x00}, 22862306a36Sopenharmony_ci {0x7d, 0x1a}, 22962306a36Sopenharmony_ci {0x02, 0x00}, 23062306a36Sopenharmony_ci {0x01, 0x00}, 23162306a36Sopenharmony_ci {0x04, 0x52}, 23262306a36Sopenharmony_ci }; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(instruction); i++) { 23562306a36Sopenharmony_ci msleep(60); 23662306a36Sopenharmony_ci retval = jl2005c_write2(gspca_dev, instruction[i]); 23762306a36Sopenharmony_ci if (retval < 0) 23862306a36Sopenharmony_ci return retval; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci msleep(60); 24162306a36Sopenharmony_ci return retval; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci int i; 24762306a36Sopenharmony_ci int retval = -1; 24862306a36Sopenharmony_ci static u8 instruction[][2] = { 24962306a36Sopenharmony_ci {0x05, 0x00}, 25062306a36Sopenharmony_ci {0x7c, 0x00}, 25162306a36Sopenharmony_ci {0x7d, 0x30}, 25262306a36Sopenharmony_ci {0x02, 0x00}, 25362306a36Sopenharmony_ci {0x01, 0x00}, 25462306a36Sopenharmony_ci {0x04, 0x42}, 25562306a36Sopenharmony_ci }; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(instruction); i++) { 25862306a36Sopenharmony_ci msleep(60); 25962306a36Sopenharmony_ci retval = jl2005c_write2(gspca_dev, instruction[i]); 26062306a36Sopenharmony_ci if (retval < 0) 26162306a36Sopenharmony_ci return retval; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci msleep(60); 26462306a36Sopenharmony_ci return retval; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci int i; 27062306a36Sopenharmony_ci int retval = -1; 27162306a36Sopenharmony_ci static u8 instruction[][2] = { 27262306a36Sopenharmony_ci {0x06, 0x00}, 27362306a36Sopenharmony_ci {0x7c, 0x00}, 27462306a36Sopenharmony_ci {0x7d, 0x32}, 27562306a36Sopenharmony_ci {0x02, 0x00}, 27662306a36Sopenharmony_ci {0x01, 0x00}, 27762306a36Sopenharmony_ci {0x04, 0x42}, 27862306a36Sopenharmony_ci }; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(instruction); i++) { 28162306a36Sopenharmony_ci msleep(60); 28262306a36Sopenharmony_ci retval = jl2005c_write2(gspca_dev, instruction[i]); 28362306a36Sopenharmony_ci if (retval < 0) 28462306a36Sopenharmony_ci return retval; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci msleep(60); 28762306a36Sopenharmony_ci return retval; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int jl2005c_stop(struct gspca_dev *gspca_dev) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci return jl2005c_write_reg(gspca_dev, 0x07, 0x00); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci/* 29762306a36Sopenharmony_ci * This function is called as a workqueue function and runs whenever the camera 29862306a36Sopenharmony_ci * is streaming data. Because it is a workqueue function it is allowed to sleep 29962306a36Sopenharmony_ci * so we can use synchronous USB calls. To avoid possible collisions with other 30062306a36Sopenharmony_ci * threads attempting to use gspca_dev->usb_buf we take the usb_lock when 30162306a36Sopenharmony_ci * performing USB operations using it. In practice we don't really need this 30262306a36Sopenharmony_ci * as the camera doesn't provide any controls. 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cistatic void jl2005c_dostream(struct work_struct *work) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct sd *dev = container_of(work, struct sd, work_struct); 30762306a36Sopenharmony_ci struct gspca_dev *gspca_dev = &dev->gspca_dev; 30862306a36Sopenharmony_ci int bytes_left = 0; /* bytes remaining in current frame. */ 30962306a36Sopenharmony_ci int data_len; /* size to use for the next read. */ 31062306a36Sopenharmony_ci int header_read = 0; 31162306a36Sopenharmony_ci unsigned char header_sig[2] = {0x4a, 0x4c}; 31262306a36Sopenharmony_ci int act_len; 31362306a36Sopenharmony_ci int packet_type; 31462306a36Sopenharmony_ci int ret; 31562306a36Sopenharmony_ci u8 *buffer; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL); 31862306a36Sopenharmony_ci if (!buffer) { 31962306a36Sopenharmony_ci pr_err("Couldn't allocate USB buffer\n"); 32062306a36Sopenharmony_ci goto quit_stream; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci while (gspca_dev->present && gspca_dev->streaming) { 32462306a36Sopenharmony_ci#ifdef CONFIG_PM 32562306a36Sopenharmony_ci if (gspca_dev->frozen) 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci#endif 32862306a36Sopenharmony_ci /* Check if this is a new frame. If so, start the frame first */ 32962306a36Sopenharmony_ci if (!header_read) { 33062306a36Sopenharmony_ci mutex_lock(&gspca_dev->usb_lock); 33162306a36Sopenharmony_ci ret = jl2005c_start_new_frame(gspca_dev); 33262306a36Sopenharmony_ci mutex_unlock(&gspca_dev->usb_lock); 33362306a36Sopenharmony_ci if (ret < 0) 33462306a36Sopenharmony_ci goto quit_stream; 33562306a36Sopenharmony_ci ret = usb_bulk_msg(gspca_dev->dev, 33662306a36Sopenharmony_ci usb_rcvbulkpipe(gspca_dev->dev, 0x82), 33762306a36Sopenharmony_ci buffer, JL2005C_MAX_TRANSFER, &act_len, 33862306a36Sopenharmony_ci JL2005C_DATA_TIMEOUT); 33962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, 34062306a36Sopenharmony_ci "Got %d bytes out of %d for header\n", 34162306a36Sopenharmony_ci act_len, JL2005C_MAX_TRANSFER); 34262306a36Sopenharmony_ci if (ret < 0 || act_len < JL2005C_MAX_TRANSFER) 34362306a36Sopenharmony_ci goto quit_stream; 34462306a36Sopenharmony_ci /* Check whether we actually got the first blodk */ 34562306a36Sopenharmony_ci if (memcmp(header_sig, buffer, 2) != 0) { 34662306a36Sopenharmony_ci pr_err("First block is not the first block\n"); 34762306a36Sopenharmony_ci goto quit_stream; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci /* total size to fetch is byte 7, times blocksize 35062306a36Sopenharmony_ci * of which we already got act_len */ 35162306a36Sopenharmony_ci bytes_left = buffer[0x07] * dev->block_size - act_len; 35262306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, "bytes_left = 0x%x\n", 35362306a36Sopenharmony_ci bytes_left); 35462306a36Sopenharmony_ci /* We keep the header. It has other information, too.*/ 35562306a36Sopenharmony_ci packet_type = FIRST_PACKET; 35662306a36Sopenharmony_ci gspca_frame_add(gspca_dev, packet_type, 35762306a36Sopenharmony_ci buffer, act_len); 35862306a36Sopenharmony_ci header_read = 1; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci while (bytes_left > 0 && gspca_dev->present) { 36162306a36Sopenharmony_ci data_len = bytes_left > JL2005C_MAX_TRANSFER ? 36262306a36Sopenharmony_ci JL2005C_MAX_TRANSFER : bytes_left; 36362306a36Sopenharmony_ci ret = usb_bulk_msg(gspca_dev->dev, 36462306a36Sopenharmony_ci usb_rcvbulkpipe(gspca_dev->dev, 0x82), 36562306a36Sopenharmony_ci buffer, data_len, &act_len, 36662306a36Sopenharmony_ci JL2005C_DATA_TIMEOUT); 36762306a36Sopenharmony_ci if (ret < 0 || act_len < data_len) 36862306a36Sopenharmony_ci goto quit_stream; 36962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PACK, 37062306a36Sopenharmony_ci "Got %d bytes out of %d for frame\n", 37162306a36Sopenharmony_ci data_len, bytes_left); 37262306a36Sopenharmony_ci bytes_left -= data_len; 37362306a36Sopenharmony_ci if (bytes_left == 0) { 37462306a36Sopenharmony_ci packet_type = LAST_PACKET; 37562306a36Sopenharmony_ci header_read = 0; 37662306a36Sopenharmony_ci } else 37762306a36Sopenharmony_ci packet_type = INTER_PACKET; 37862306a36Sopenharmony_ci gspca_frame_add(gspca_dev, packet_type, 37962306a36Sopenharmony_ci buffer, data_len); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ciquit_stream: 38362306a36Sopenharmony_ci if (gspca_dev->present) { 38462306a36Sopenharmony_ci mutex_lock(&gspca_dev->usb_lock); 38562306a36Sopenharmony_ci jl2005c_stop(gspca_dev); 38662306a36Sopenharmony_ci mutex_unlock(&gspca_dev->usb_lock); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci kfree(buffer); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/* This function is called at probe time */ 39562306a36Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev, 39662306a36Sopenharmony_ci const struct usb_device_id *id) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct cam *cam; 39962306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci cam = &gspca_dev->cam; 40262306a36Sopenharmony_ci /* We don't use the buffer gspca allocates so make it small. */ 40362306a36Sopenharmony_ci cam->bulk_size = 64; 40462306a36Sopenharmony_ci cam->bulk = 1; 40562306a36Sopenharmony_ci /* For the rest, the camera needs to be detected */ 40662306a36Sopenharmony_ci jl2005c_get_firmware_id(gspca_dev); 40762306a36Sopenharmony_ci /* Here are some known firmware IDs 40862306a36Sopenharmony_ci * First some JL2005B cameras 40962306a36Sopenharmony_ci * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2} Sakar KidzCam 41062306a36Sopenharmony_ci * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2} No-name JL2005B 41162306a36Sopenharmony_ci * JL2005C cameras 41262306a36Sopenharmony_ci * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8} Argus DC-1512 41362306a36Sopenharmony_ci * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8} ICarly 41462306a36Sopenharmony_ci * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4} Jazz 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * Based upon this scanty evidence, we can detect a CIF camera by 41762306a36Sopenharmony_ci * testing byte 0 for 0x4x. 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_ci if ((sd->firmware_id[0] & 0xf0) == 0x40) { 42062306a36Sopenharmony_ci cam->cam_mode = cif_mode; 42162306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(cif_mode); 42262306a36Sopenharmony_ci sd->block_size = 0x80; 42362306a36Sopenharmony_ci } else { 42462306a36Sopenharmony_ci cam->cam_mode = vga_mode; 42562306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(vga_mode); 42662306a36Sopenharmony_ci sd->block_size = 0x200; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci INIT_WORK(&sd->work_struct, jl2005c_dostream); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci/* this function is called at probe and resume time */ 43562306a36Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 44462306a36Sopenharmony_ci sd->cap_mode = gspca_dev->cam.cam_mode; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci switch (gspca_dev->pixfmt.width) { 44762306a36Sopenharmony_ci case 640: 44862306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Start streaming at vga resolution\n"); 44962306a36Sopenharmony_ci jl2005c_stream_start_vga_lg(gspca_dev); 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci case 320: 45262306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Start streaming at qvga resolution\n"); 45362306a36Sopenharmony_ci jl2005c_stream_start_vga_small(gspca_dev); 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci case 352: 45662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Start streaming at cif resolution\n"); 45762306a36Sopenharmony_ci jl2005c_stream_start_cif_lg(gspca_dev); 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci case 176: 46062306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Start streaming at qcif resolution\n"); 46162306a36Sopenharmony_ci jl2005c_stream_start_cif_small(gspca_dev); 46262306a36Sopenharmony_ci break; 46362306a36Sopenharmony_ci default: 46462306a36Sopenharmony_ci pr_err("Unknown resolution specified\n"); 46562306a36Sopenharmony_ci return -1; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci schedule_work(&sd->work_struct); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/* called on streamoff with alt==0 and on disconnect */ 47462306a36Sopenharmony_ci/* the usb_lock is held at entry - restore on exit */ 47562306a36Sopenharmony_cistatic void sd_stop0(struct gspca_dev *gspca_dev) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct sd *dev = (struct sd *) gspca_dev; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* wait for the work queue to terminate */ 48062306a36Sopenharmony_ci mutex_unlock(&gspca_dev->usb_lock); 48162306a36Sopenharmony_ci /* This waits for sq905c_dostream to finish */ 48262306a36Sopenharmony_ci flush_work(&dev->work_struct); 48362306a36Sopenharmony_ci mutex_lock(&gspca_dev->usb_lock); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/* sub-driver description */ 48962306a36Sopenharmony_cistatic const struct sd_desc sd_desc = { 49062306a36Sopenharmony_ci .name = MODULE_NAME, 49162306a36Sopenharmony_ci .config = sd_config, 49262306a36Sopenharmony_ci .init = sd_init, 49362306a36Sopenharmony_ci .start = sd_start, 49462306a36Sopenharmony_ci .stop0 = sd_stop0, 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci/* -- module initialisation -- */ 49862306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = { 49962306a36Sopenharmony_ci {USB_DEVICE(0x0979, 0x0227)}, 50062306a36Sopenharmony_ci {} 50162306a36Sopenharmony_ci}; 50262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/* -- device connect -- */ 50562306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, 50662306a36Sopenharmony_ci const struct usb_device_id *id) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 50962306a36Sopenharmony_ci THIS_MODULE); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic struct usb_driver sd_driver = { 51362306a36Sopenharmony_ci .name = MODULE_NAME, 51462306a36Sopenharmony_ci .id_table = device_table, 51562306a36Sopenharmony_ci .probe = sd_probe, 51662306a36Sopenharmony_ci .disconnect = gspca_disconnect, 51762306a36Sopenharmony_ci#ifdef CONFIG_PM 51862306a36Sopenharmony_ci .suspend = gspca_suspend, 51962306a36Sopenharmony_ci .resume = gspca_resume, 52062306a36Sopenharmony_ci .reset_resume = gspca_resume, 52162306a36Sopenharmony_ci#endif 52262306a36Sopenharmony_ci}; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cimodule_usb_driver(sd_driver); 525