18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Jeilin JL2005B/C/D library
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.edu>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define MODULE_NAME "jl2005bcd"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include "gspca.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciMODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver");
178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* Default timeouts, in ms */
208c2ecf20Sopenharmony_ci#define JL2005C_CMD_TIMEOUT 500
218c2ecf20Sopenharmony_ci#define JL2005C_DATA_TIMEOUT 1000
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Maximum transfer size to use. */
248c2ecf20Sopenharmony_ci#define JL2005C_MAX_TRANSFER 0x200
258c2ecf20Sopenharmony_ci#define FRAME_HEADER_LEN 16
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* specific webcam descriptor */
298c2ecf20Sopenharmony_cistruct sd {
308c2ecf20Sopenharmony_ci	struct gspca_dev gspca_dev;  /* !! must be the first item */
318c2ecf20Sopenharmony_ci	unsigned char firmware_id[6];
328c2ecf20Sopenharmony_ci	const struct v4l2_pix_format *cap_mode;
338c2ecf20Sopenharmony_ci	/* Driver stuff */
348c2ecf20Sopenharmony_ci	struct work_struct work_struct;
358c2ecf20Sopenharmony_ci	u8 frame_brightness;
368c2ecf20Sopenharmony_ci	int block_size;	/* block size of camera */
378c2ecf20Sopenharmony_ci	int vga;	/* 1 if vga cam, 0 if cif cam */
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* Camera has two resolution settings. What they are depends on model. */
428c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format cif_mode[] = {
438c2ecf20Sopenharmony_ci	{176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
448c2ecf20Sopenharmony_ci		.bytesperline = 176,
458c2ecf20Sopenharmony_ci		.sizeimage = 176 * 144,
468c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
478c2ecf20Sopenharmony_ci		.priv = 0},
488c2ecf20Sopenharmony_ci	{352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
498c2ecf20Sopenharmony_ci		.bytesperline = 352,
508c2ecf20Sopenharmony_ci		.sizeimage = 352 * 288,
518c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
528c2ecf20Sopenharmony_ci		.priv = 0},
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format vga_mode[] = {
568c2ecf20Sopenharmony_ci	{320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
578c2ecf20Sopenharmony_ci		.bytesperline = 320,
588c2ecf20Sopenharmony_ci		.sizeimage = 320 * 240,
598c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
608c2ecf20Sopenharmony_ci		.priv = 0},
618c2ecf20Sopenharmony_ci	{640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
628c2ecf20Sopenharmony_ci		.bytesperline = 640,
638c2ecf20Sopenharmony_ci		.sizeimage = 640 * 480,
648c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
658c2ecf20Sopenharmony_ci		.priv = 0},
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/*
698c2ecf20Sopenharmony_ci * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
708c2ecf20Sopenharmony_ci * and 0x82 for bulk data transfer.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/* All commands are two bytes only */
748c2ecf20Sopenharmony_cistatic int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	int retval;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	memcpy(gspca_dev->usb_buf, command, 2);
798c2ecf20Sopenharmony_ci	retval = usb_bulk_msg(gspca_dev->dev,
808c2ecf20Sopenharmony_ci			usb_sndbulkpipe(gspca_dev->dev, 3),
818c2ecf20Sopenharmony_ci			gspca_dev->usb_buf, 2, NULL, 500);
828c2ecf20Sopenharmony_ci	if (retval < 0)
838c2ecf20Sopenharmony_ci		pr_err("command write [%02x] error %d\n",
848c2ecf20Sopenharmony_ci		       gspca_dev->usb_buf[0], retval);
858c2ecf20Sopenharmony_ci	return retval;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/* Response to a command is one byte in usb_buf[0], only if requested. */
898c2ecf20Sopenharmony_cistatic int jl2005c_read1(struct gspca_dev *gspca_dev)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	int retval;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	retval = usb_bulk_msg(gspca_dev->dev,
948c2ecf20Sopenharmony_ci				usb_rcvbulkpipe(gspca_dev->dev, 0x84),
958c2ecf20Sopenharmony_ci				gspca_dev->usb_buf, 1, NULL, 500);
968c2ecf20Sopenharmony_ci	if (retval < 0)
978c2ecf20Sopenharmony_ci		pr_err("read command [0x%02x] error %d\n",
988c2ecf20Sopenharmony_ci		       gspca_dev->usb_buf[0], retval);
998c2ecf20Sopenharmony_ci	return retval;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/* Response appears in gspca_dev->usb_buf[0] */
1038c2ecf20Sopenharmony_cistatic int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int retval;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	static u8 instruction[2] = {0x95, 0x00};
1088c2ecf20Sopenharmony_ci	/* put register to read in byte 1 */
1098c2ecf20Sopenharmony_ci	instruction[1] = reg;
1108c2ecf20Sopenharmony_ci	/* Send the read request */
1118c2ecf20Sopenharmony_ci	retval = jl2005c_write2(gspca_dev, instruction);
1128c2ecf20Sopenharmony_ci	if (retval < 0)
1138c2ecf20Sopenharmony_ci		return retval;
1148c2ecf20Sopenharmony_ci	retval = jl2005c_read1(gspca_dev);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return retval;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int jl2005c_start_new_frame(struct gspca_dev *gspca_dev)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	int i;
1228c2ecf20Sopenharmony_ci	int retval;
1238c2ecf20Sopenharmony_ci	int frame_brightness = 0;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	static u8 instruction[2] = {0x7f, 0x01};
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	retval = jl2005c_write2(gspca_dev, instruction);
1288c2ecf20Sopenharmony_ci	if (retval < 0)
1298c2ecf20Sopenharmony_ci		return retval;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	i = 0;
1328c2ecf20Sopenharmony_ci	while (i < 20 && !frame_brightness) {
1338c2ecf20Sopenharmony_ci		/* If we tried 20 times, give up. */
1348c2ecf20Sopenharmony_ci		retval = jl2005c_read_reg(gspca_dev, 0x7e);
1358c2ecf20Sopenharmony_ci		if (retval < 0)
1368c2ecf20Sopenharmony_ci			return retval;
1378c2ecf20Sopenharmony_ci		frame_brightness = gspca_dev->usb_buf[0];
1388c2ecf20Sopenharmony_ci		retval = jl2005c_read_reg(gspca_dev, 0x7d);
1398c2ecf20Sopenharmony_ci		if (retval < 0)
1408c2ecf20Sopenharmony_ci			return retval;
1418c2ecf20Sopenharmony_ci		i++;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_FRAM, "frame_brightness is 0x%02x\n",
1448c2ecf20Sopenharmony_ci		  gspca_dev->usb_buf[0]);
1458c2ecf20Sopenharmony_ci	return retval;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg,
1498c2ecf20Sopenharmony_ci						    unsigned char value)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	int retval;
1528c2ecf20Sopenharmony_ci	u8 instruction[2];
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	instruction[0] = reg;
1558c2ecf20Sopenharmony_ci	instruction[1] = value;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	retval = jl2005c_write2(gspca_dev, instruction);
1588c2ecf20Sopenharmony_ci	if (retval < 0)
1598c2ecf20Sopenharmony_ci			return retval;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return retval;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *)gspca_dev;
1678c2ecf20Sopenharmony_ci	int i = 0;
1688c2ecf20Sopenharmony_ci	int retval;
1698c2ecf20Sopenharmony_ci	unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "Running jl2005c_get_firmware_id\n");
1728c2ecf20Sopenharmony_ci	/* Read the first ID byte once for warmup */
1738c2ecf20Sopenharmony_ci	retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]);
1748c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "response is %02x\n",
1758c2ecf20Sopenharmony_ci		  gspca_dev->usb_buf[0]);
1768c2ecf20Sopenharmony_ci	if (retval < 0)
1778c2ecf20Sopenharmony_ci		return retval;
1788c2ecf20Sopenharmony_ci	/* Now actually get the ID string */
1798c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++) {
1808c2ecf20Sopenharmony_ci		retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]);
1818c2ecf20Sopenharmony_ci		if (retval < 0)
1828c2ecf20Sopenharmony_ci			return retval;
1838c2ecf20Sopenharmony_ci		sd->firmware_id[i] = gspca_dev->usb_buf[0];
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x\n",
1868c2ecf20Sopenharmony_ci		  sd->firmware_id[0],
1878c2ecf20Sopenharmony_ci		  sd->firmware_id[1],
1888c2ecf20Sopenharmony_ci		  sd->firmware_id[2],
1898c2ecf20Sopenharmony_ci		  sd->firmware_id[3],
1908c2ecf20Sopenharmony_ci		  sd->firmware_id[4],
1918c2ecf20Sopenharmony_ci		  sd->firmware_id[5]);
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int jl2005c_stream_start_vga_lg
1968c2ecf20Sopenharmony_ci		    (struct gspca_dev *gspca_dev)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	int i;
1998c2ecf20Sopenharmony_ci	int retval = -1;
2008c2ecf20Sopenharmony_ci	static u8 instruction[][2] = {
2018c2ecf20Sopenharmony_ci		{0x05, 0x00},
2028c2ecf20Sopenharmony_ci		{0x7c, 0x00},
2038c2ecf20Sopenharmony_ci		{0x7d, 0x18},
2048c2ecf20Sopenharmony_ci		{0x02, 0x00},
2058c2ecf20Sopenharmony_ci		{0x01, 0x00},
2068c2ecf20Sopenharmony_ci		{0x04, 0x52},
2078c2ecf20Sopenharmony_ci	};
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(instruction); i++) {
2108c2ecf20Sopenharmony_ci		msleep(60);
2118c2ecf20Sopenharmony_ci		retval = jl2005c_write2(gspca_dev, instruction[i]);
2128c2ecf20Sopenharmony_ci		if (retval < 0)
2138c2ecf20Sopenharmony_ci			return retval;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci	msleep(60);
2168c2ecf20Sopenharmony_ci	return retval;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	int i;
2228c2ecf20Sopenharmony_ci	int retval = -1;
2238c2ecf20Sopenharmony_ci	static u8 instruction[][2] = {
2248c2ecf20Sopenharmony_ci		{0x06, 0x00},
2258c2ecf20Sopenharmony_ci		{0x7c, 0x00},
2268c2ecf20Sopenharmony_ci		{0x7d, 0x1a},
2278c2ecf20Sopenharmony_ci		{0x02, 0x00},
2288c2ecf20Sopenharmony_ci		{0x01, 0x00},
2298c2ecf20Sopenharmony_ci		{0x04, 0x52},
2308c2ecf20Sopenharmony_ci	};
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(instruction); i++) {
2338c2ecf20Sopenharmony_ci		msleep(60);
2348c2ecf20Sopenharmony_ci		retval = jl2005c_write2(gspca_dev, instruction[i]);
2358c2ecf20Sopenharmony_ci		if (retval < 0)
2368c2ecf20Sopenharmony_ci			return retval;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	msleep(60);
2398c2ecf20Sopenharmony_ci	return retval;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	int i;
2458c2ecf20Sopenharmony_ci	int retval = -1;
2468c2ecf20Sopenharmony_ci	static u8 instruction[][2] = {
2478c2ecf20Sopenharmony_ci		{0x05, 0x00},
2488c2ecf20Sopenharmony_ci		{0x7c, 0x00},
2498c2ecf20Sopenharmony_ci		{0x7d, 0x30},
2508c2ecf20Sopenharmony_ci		{0x02, 0x00},
2518c2ecf20Sopenharmony_ci		{0x01, 0x00},
2528c2ecf20Sopenharmony_ci		{0x04, 0x42},
2538c2ecf20Sopenharmony_ci	};
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(instruction); i++) {
2568c2ecf20Sopenharmony_ci		msleep(60);
2578c2ecf20Sopenharmony_ci		retval = jl2005c_write2(gspca_dev, instruction[i]);
2588c2ecf20Sopenharmony_ci		if (retval < 0)
2598c2ecf20Sopenharmony_ci			return retval;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci	msleep(60);
2628c2ecf20Sopenharmony_ci	return retval;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	int i;
2688c2ecf20Sopenharmony_ci	int retval = -1;
2698c2ecf20Sopenharmony_ci	static u8 instruction[][2] = {
2708c2ecf20Sopenharmony_ci		{0x06, 0x00},
2718c2ecf20Sopenharmony_ci		{0x7c, 0x00},
2728c2ecf20Sopenharmony_ci		{0x7d, 0x32},
2738c2ecf20Sopenharmony_ci		{0x02, 0x00},
2748c2ecf20Sopenharmony_ci		{0x01, 0x00},
2758c2ecf20Sopenharmony_ci		{0x04, 0x42},
2768c2ecf20Sopenharmony_ci	};
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(instruction); i++) {
2798c2ecf20Sopenharmony_ci		msleep(60);
2808c2ecf20Sopenharmony_ci		retval = jl2005c_write2(gspca_dev, instruction[i]);
2818c2ecf20Sopenharmony_ci		if (retval < 0)
2828c2ecf20Sopenharmony_ci			return retval;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci	msleep(60);
2858c2ecf20Sopenharmony_ci	return retval;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic int jl2005c_stop(struct gspca_dev *gspca_dev)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	return jl2005c_write_reg(gspca_dev, 0x07, 0x00);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/*
2958c2ecf20Sopenharmony_ci * This function is called as a workqueue function and runs whenever the camera
2968c2ecf20Sopenharmony_ci * is streaming data. Because it is a workqueue function it is allowed to sleep
2978c2ecf20Sopenharmony_ci * so we can use synchronous USB calls. To avoid possible collisions with other
2988c2ecf20Sopenharmony_ci * threads attempting to use gspca_dev->usb_buf we take the usb_lock when
2998c2ecf20Sopenharmony_ci * performing USB operations using it. In practice we don't really need this
3008c2ecf20Sopenharmony_ci * as the camera doesn't provide any controls.
3018c2ecf20Sopenharmony_ci */
3028c2ecf20Sopenharmony_cistatic void jl2005c_dostream(struct work_struct *work)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct sd *dev = container_of(work, struct sd, work_struct);
3058c2ecf20Sopenharmony_ci	struct gspca_dev *gspca_dev = &dev->gspca_dev;
3068c2ecf20Sopenharmony_ci	int bytes_left = 0; /* bytes remaining in current frame. */
3078c2ecf20Sopenharmony_ci	int data_len;   /* size to use for the next read. */
3088c2ecf20Sopenharmony_ci	int header_read = 0;
3098c2ecf20Sopenharmony_ci	unsigned char header_sig[2] = {0x4a, 0x4c};
3108c2ecf20Sopenharmony_ci	int act_len;
3118c2ecf20Sopenharmony_ci	int packet_type;
3128c2ecf20Sopenharmony_ci	int ret;
3138c2ecf20Sopenharmony_ci	u8 *buffer;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL);
3168c2ecf20Sopenharmony_ci	if (!buffer) {
3178c2ecf20Sopenharmony_ci		pr_err("Couldn't allocate USB buffer\n");
3188c2ecf20Sopenharmony_ci		goto quit_stream;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	while (gspca_dev->present && gspca_dev->streaming) {
3228c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
3238c2ecf20Sopenharmony_ci		if (gspca_dev->frozen)
3248c2ecf20Sopenharmony_ci			break;
3258c2ecf20Sopenharmony_ci#endif
3268c2ecf20Sopenharmony_ci		/* Check if this is a new frame. If so, start the frame first */
3278c2ecf20Sopenharmony_ci		if (!header_read) {
3288c2ecf20Sopenharmony_ci			mutex_lock(&gspca_dev->usb_lock);
3298c2ecf20Sopenharmony_ci			ret = jl2005c_start_new_frame(gspca_dev);
3308c2ecf20Sopenharmony_ci			mutex_unlock(&gspca_dev->usb_lock);
3318c2ecf20Sopenharmony_ci			if (ret < 0)
3328c2ecf20Sopenharmony_ci				goto quit_stream;
3338c2ecf20Sopenharmony_ci			ret = usb_bulk_msg(gspca_dev->dev,
3348c2ecf20Sopenharmony_ci				usb_rcvbulkpipe(gspca_dev->dev, 0x82),
3358c2ecf20Sopenharmony_ci				buffer, JL2005C_MAX_TRANSFER, &act_len,
3368c2ecf20Sopenharmony_ci				JL2005C_DATA_TIMEOUT);
3378c2ecf20Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK,
3388c2ecf20Sopenharmony_ci				  "Got %d bytes out of %d for header\n",
3398c2ecf20Sopenharmony_ci				  act_len, JL2005C_MAX_TRANSFER);
3408c2ecf20Sopenharmony_ci			if (ret < 0 || act_len < JL2005C_MAX_TRANSFER)
3418c2ecf20Sopenharmony_ci				goto quit_stream;
3428c2ecf20Sopenharmony_ci			/* Check whether we actually got the first blodk */
3438c2ecf20Sopenharmony_ci			if (memcmp(header_sig, buffer, 2) != 0) {
3448c2ecf20Sopenharmony_ci				pr_err("First block is not the first block\n");
3458c2ecf20Sopenharmony_ci				goto quit_stream;
3468c2ecf20Sopenharmony_ci			}
3478c2ecf20Sopenharmony_ci			/* total size to fetch is byte 7, times blocksize
3488c2ecf20Sopenharmony_ci			 * of which we already got act_len */
3498c2ecf20Sopenharmony_ci			bytes_left = buffer[0x07] * dev->block_size - act_len;
3508c2ecf20Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "bytes_left = 0x%x\n",
3518c2ecf20Sopenharmony_ci				  bytes_left);
3528c2ecf20Sopenharmony_ci			/* We keep the header. It has other information, too.*/
3538c2ecf20Sopenharmony_ci			packet_type = FIRST_PACKET;
3548c2ecf20Sopenharmony_ci			gspca_frame_add(gspca_dev, packet_type,
3558c2ecf20Sopenharmony_ci					buffer, act_len);
3568c2ecf20Sopenharmony_ci			header_read = 1;
3578c2ecf20Sopenharmony_ci		}
3588c2ecf20Sopenharmony_ci		while (bytes_left > 0 && gspca_dev->present) {
3598c2ecf20Sopenharmony_ci			data_len = bytes_left > JL2005C_MAX_TRANSFER ?
3608c2ecf20Sopenharmony_ci				JL2005C_MAX_TRANSFER : bytes_left;
3618c2ecf20Sopenharmony_ci			ret = usb_bulk_msg(gspca_dev->dev,
3628c2ecf20Sopenharmony_ci				usb_rcvbulkpipe(gspca_dev->dev, 0x82),
3638c2ecf20Sopenharmony_ci				buffer, data_len, &act_len,
3648c2ecf20Sopenharmony_ci				JL2005C_DATA_TIMEOUT);
3658c2ecf20Sopenharmony_ci			if (ret < 0 || act_len < data_len)
3668c2ecf20Sopenharmony_ci				goto quit_stream;
3678c2ecf20Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK,
3688c2ecf20Sopenharmony_ci				  "Got %d bytes out of %d for frame\n",
3698c2ecf20Sopenharmony_ci				  data_len, bytes_left);
3708c2ecf20Sopenharmony_ci			bytes_left -= data_len;
3718c2ecf20Sopenharmony_ci			if (bytes_left == 0) {
3728c2ecf20Sopenharmony_ci				packet_type = LAST_PACKET;
3738c2ecf20Sopenharmony_ci				header_read = 0;
3748c2ecf20Sopenharmony_ci			} else
3758c2ecf20Sopenharmony_ci				packet_type = INTER_PACKET;
3768c2ecf20Sopenharmony_ci			gspca_frame_add(gspca_dev, packet_type,
3778c2ecf20Sopenharmony_ci					buffer, data_len);
3788c2ecf20Sopenharmony_ci		}
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ciquit_stream:
3818c2ecf20Sopenharmony_ci	if (gspca_dev->present) {
3828c2ecf20Sopenharmony_ci		mutex_lock(&gspca_dev->usb_lock);
3838c2ecf20Sopenharmony_ci		jl2005c_stop(gspca_dev);
3848c2ecf20Sopenharmony_ci		mutex_unlock(&gspca_dev->usb_lock);
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci	kfree(buffer);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci/* This function is called at probe time */
3938c2ecf20Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev,
3948c2ecf20Sopenharmony_ci			const struct usb_device_id *id)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct cam *cam;
3978c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	cam = &gspca_dev->cam;
4008c2ecf20Sopenharmony_ci	/* We don't use the buffer gspca allocates so make it small. */
4018c2ecf20Sopenharmony_ci	cam->bulk_size = 64;
4028c2ecf20Sopenharmony_ci	cam->bulk = 1;
4038c2ecf20Sopenharmony_ci	/* For the rest, the camera needs to be detected */
4048c2ecf20Sopenharmony_ci	jl2005c_get_firmware_id(gspca_dev);
4058c2ecf20Sopenharmony_ci	/* Here are some known firmware IDs
4068c2ecf20Sopenharmony_ci	 * First some JL2005B cameras
4078c2ecf20Sopenharmony_ci	 * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2}	Sakar KidzCam
4088c2ecf20Sopenharmony_ci	 * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2}	No-name JL2005B
4098c2ecf20Sopenharmony_ci	 * JL2005C cameras
4108c2ecf20Sopenharmony_ci	 * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8}	Argus DC-1512
4118c2ecf20Sopenharmony_ci	 * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8}	ICarly
4128c2ecf20Sopenharmony_ci	 * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4}	Jazz
4138c2ecf20Sopenharmony_ci	 *
4148c2ecf20Sopenharmony_ci	 * Based upon this scanty evidence, we can detect a CIF camera by
4158c2ecf20Sopenharmony_ci	 * testing byte 0 for 0x4x.
4168c2ecf20Sopenharmony_ci	 */
4178c2ecf20Sopenharmony_ci	if ((sd->firmware_id[0] & 0xf0) == 0x40) {
4188c2ecf20Sopenharmony_ci		cam->cam_mode	= cif_mode;
4198c2ecf20Sopenharmony_ci		cam->nmodes	= ARRAY_SIZE(cif_mode);
4208c2ecf20Sopenharmony_ci		sd->block_size	= 0x80;
4218c2ecf20Sopenharmony_ci	} else {
4228c2ecf20Sopenharmony_ci		cam->cam_mode	= vga_mode;
4238c2ecf20Sopenharmony_ci		cam->nmodes	= ARRAY_SIZE(vga_mode);
4248c2ecf20Sopenharmony_ci		sd->block_size	= 0x200;
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	INIT_WORK(&sd->work_struct, jl2005c_dostream);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	return 0;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci/* this function is called at probe and resume time */
4338c2ecf20Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	return 0;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
4428c2ecf20Sopenharmony_ci	sd->cap_mode = gspca_dev->cam.cam_mode;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	switch (gspca_dev->pixfmt.width) {
4458c2ecf20Sopenharmony_ci	case 640:
4468c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_STREAM, "Start streaming at vga resolution\n");
4478c2ecf20Sopenharmony_ci		jl2005c_stream_start_vga_lg(gspca_dev);
4488c2ecf20Sopenharmony_ci		break;
4498c2ecf20Sopenharmony_ci	case 320:
4508c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_STREAM, "Start streaming at qvga resolution\n");
4518c2ecf20Sopenharmony_ci		jl2005c_stream_start_vga_small(gspca_dev);
4528c2ecf20Sopenharmony_ci		break;
4538c2ecf20Sopenharmony_ci	case 352:
4548c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_STREAM, "Start streaming at cif resolution\n");
4558c2ecf20Sopenharmony_ci		jl2005c_stream_start_cif_lg(gspca_dev);
4568c2ecf20Sopenharmony_ci		break;
4578c2ecf20Sopenharmony_ci	case 176:
4588c2ecf20Sopenharmony_ci		gspca_dbg(gspca_dev, D_STREAM, "Start streaming at qcif resolution\n");
4598c2ecf20Sopenharmony_ci		jl2005c_stream_start_cif_small(gspca_dev);
4608c2ecf20Sopenharmony_ci		break;
4618c2ecf20Sopenharmony_ci	default:
4628c2ecf20Sopenharmony_ci		pr_err("Unknown resolution specified\n");
4638c2ecf20Sopenharmony_ci		return -1;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	schedule_work(&sd->work_struct);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	return 0;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci/* called on streamoff with alt==0 and on disconnect */
4728c2ecf20Sopenharmony_ci/* the usb_lock is held at entry - restore on exit */
4738c2ecf20Sopenharmony_cistatic void sd_stop0(struct gspca_dev *gspca_dev)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct sd *dev = (struct sd *) gspca_dev;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	/* wait for the work queue to terminate */
4788c2ecf20Sopenharmony_ci	mutex_unlock(&gspca_dev->usb_lock);
4798c2ecf20Sopenharmony_ci	/* This waits for sq905c_dostream to finish */
4808c2ecf20Sopenharmony_ci	flush_work(&dev->work_struct);
4818c2ecf20Sopenharmony_ci	mutex_lock(&gspca_dev->usb_lock);
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci/* sub-driver description */
4878c2ecf20Sopenharmony_cistatic const struct sd_desc sd_desc = {
4888c2ecf20Sopenharmony_ci	.name = MODULE_NAME,
4898c2ecf20Sopenharmony_ci	.config = sd_config,
4908c2ecf20Sopenharmony_ci	.init = sd_init,
4918c2ecf20Sopenharmony_ci	.start = sd_start,
4928c2ecf20Sopenharmony_ci	.stop0 = sd_stop0,
4938c2ecf20Sopenharmony_ci};
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci/* -- module initialisation -- */
4968c2ecf20Sopenharmony_cistatic const struct usb_device_id device_table[] = {
4978c2ecf20Sopenharmony_ci	{USB_DEVICE(0x0979, 0x0227)},
4988c2ecf20Sopenharmony_ci	{}
4998c2ecf20Sopenharmony_ci};
5008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci/* -- device connect -- */
5038c2ecf20Sopenharmony_cistatic int sd_probe(struct usb_interface *intf,
5048c2ecf20Sopenharmony_ci				const struct usb_device_id *id)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
5078c2ecf20Sopenharmony_ci				THIS_MODULE);
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic struct usb_driver sd_driver = {
5118c2ecf20Sopenharmony_ci	.name = MODULE_NAME,
5128c2ecf20Sopenharmony_ci	.id_table = device_table,
5138c2ecf20Sopenharmony_ci	.probe = sd_probe,
5148c2ecf20Sopenharmony_ci	.disconnect = gspca_disconnect,
5158c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
5168c2ecf20Sopenharmony_ci	.suspend = gspca_suspend,
5178c2ecf20Sopenharmony_ci	.resume = gspca_resume,
5188c2ecf20Sopenharmony_ci	.reset_resume = gspca_resume,
5198c2ecf20Sopenharmony_ci#endif
5208c2ecf20Sopenharmony_ci};
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cimodule_usb_driver(sd_driver);
523