18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Fujifilm Finepix subdriver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Frank Zago
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define MODULE_NAME "finepix"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "gspca.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Frank Zago <frank@zago.net>");
158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver");
168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Default timeout, in ms */
198c2ecf20Sopenharmony_ci#define FPIX_TIMEOUT 250
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* Maximum transfer size to use. The windows driver reads by chunks of
228c2ecf20Sopenharmony_ci * 0x2000 bytes, so do the same. Note: reading more seems to work
238c2ecf20Sopenharmony_ci * too. */
248c2ecf20Sopenharmony_ci#define FPIX_MAX_TRANSFER 0x2000
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* Structure to hold all of our device specific stuff */
278c2ecf20Sopenharmony_cistruct usb_fpix {
288c2ecf20Sopenharmony_ci	struct gspca_dev gspca_dev;	/* !! must be the first item */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	struct work_struct work_struct;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* Delay after which claim the next frame. If the delay is too small,
348c2ecf20Sopenharmony_ci * the camera will return old frames. On the 4800Z, 20ms is bad, 25ms
358c2ecf20Sopenharmony_ci * will fail every 4 or 5 frames, but 30ms is perfect. On the A210,
368c2ecf20Sopenharmony_ci * 30ms is bad while 35ms is perfect. */
378c2ecf20Sopenharmony_ci#define NEXT_FRAME_DELAY 35
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* These cameras only support 320x200. */
408c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format fpix_mode[1] = {
418c2ecf20Sopenharmony_ci	{ 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
428c2ecf20Sopenharmony_ci		.bytesperline = 320,
438c2ecf20Sopenharmony_ci		.sizeimage = 320 * 240 * 3 / 8 + 590,
448c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_SRGB,
458c2ecf20Sopenharmony_ci		.priv = 0}
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* send a command to the webcam */
498c2ecf20Sopenharmony_cistatic int command(struct gspca_dev *gspca_dev,
508c2ecf20Sopenharmony_ci		int order)	/* 0: reset, 1: frame request */
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	static u8 order_values[2][12] = {
538c2ecf20Sopenharmony_ci		{0xc6, 0, 0, 0, 0, 0, 0,    0, 0x20, 0, 0, 0},	/* reset */
548c2ecf20Sopenharmony_ci		{0xd3, 0, 0, 0, 0, 0, 0, 0x01,    0, 0, 0, 0},	/* fr req */
558c2ecf20Sopenharmony_ci	};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	memcpy(gspca_dev->usb_buf, order_values[order], 12);
588c2ecf20Sopenharmony_ci	return usb_control_msg(gspca_dev->dev,
598c2ecf20Sopenharmony_ci			usb_sndctrlpipe(gspca_dev->dev, 0),
608c2ecf20Sopenharmony_ci			USB_REQ_GET_STATUS,
618c2ecf20Sopenharmony_ci			USB_DIR_OUT | USB_TYPE_CLASS |
628c2ecf20Sopenharmony_ci			USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
638c2ecf20Sopenharmony_ci			12, FPIX_TIMEOUT);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/*
678c2ecf20Sopenharmony_ci * This function is called as a workqueue function and runs whenever the camera
688c2ecf20Sopenharmony_ci * is streaming data. Because it is a workqueue function it is allowed to sleep
698c2ecf20Sopenharmony_ci * so we can use synchronous USB calls. To avoid possible collisions with other
708c2ecf20Sopenharmony_ci * threads attempting to use gspca_dev->usb_buf we take the usb_lock when
718c2ecf20Sopenharmony_ci * performing USB operations using it. In practice we don't really need this
728c2ecf20Sopenharmony_ci * as the camera doesn't provide any controls.
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cistatic void dostream(struct work_struct *work)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct);
778c2ecf20Sopenharmony_ci	struct gspca_dev *gspca_dev = &dev->gspca_dev;
788c2ecf20Sopenharmony_ci	struct urb *urb = gspca_dev->urb[0];
798c2ecf20Sopenharmony_ci	u8 *data = urb->transfer_buffer;
808c2ecf20Sopenharmony_ci	int ret = 0;
818c2ecf20Sopenharmony_ci	int len;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "dostream started\n");
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* loop reading a frame */
868c2ecf20Sopenharmony_ciagain:
878c2ecf20Sopenharmony_ci	while (gspca_dev->present && gspca_dev->streaming) {
888c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
898c2ecf20Sopenharmony_ci		if (gspca_dev->frozen)
908c2ecf20Sopenharmony_ci			break;
918c2ecf20Sopenharmony_ci#endif
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		/* request a frame */
948c2ecf20Sopenharmony_ci		mutex_lock(&gspca_dev->usb_lock);
958c2ecf20Sopenharmony_ci		ret = command(gspca_dev, 1);
968c2ecf20Sopenharmony_ci		mutex_unlock(&gspca_dev->usb_lock);
978c2ecf20Sopenharmony_ci		if (ret < 0)
988c2ecf20Sopenharmony_ci			break;
998c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
1008c2ecf20Sopenharmony_ci		if (gspca_dev->frozen)
1018c2ecf20Sopenharmony_ci			break;
1028c2ecf20Sopenharmony_ci#endif
1038c2ecf20Sopenharmony_ci		if (!gspca_dev->present || !gspca_dev->streaming)
1048c2ecf20Sopenharmony_ci			break;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		/* the frame comes in parts */
1078c2ecf20Sopenharmony_ci		for (;;) {
1088c2ecf20Sopenharmony_ci			ret = usb_bulk_msg(gspca_dev->dev,
1098c2ecf20Sopenharmony_ci					urb->pipe,
1108c2ecf20Sopenharmony_ci					data,
1118c2ecf20Sopenharmony_ci					FPIX_MAX_TRANSFER,
1128c2ecf20Sopenharmony_ci					&len, FPIX_TIMEOUT);
1138c2ecf20Sopenharmony_ci			if (ret < 0) {
1148c2ecf20Sopenharmony_ci				/* Most of the time we get a timeout
1158c2ecf20Sopenharmony_ci				 * error. Just restart. */
1168c2ecf20Sopenharmony_ci				goto again;
1178c2ecf20Sopenharmony_ci			}
1188c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
1198c2ecf20Sopenharmony_ci			if (gspca_dev->frozen)
1208c2ecf20Sopenharmony_ci				goto out;
1218c2ecf20Sopenharmony_ci#endif
1228c2ecf20Sopenharmony_ci			if (!gspca_dev->present || !gspca_dev->streaming)
1238c2ecf20Sopenharmony_ci				goto out;
1248c2ecf20Sopenharmony_ci			if (len < FPIX_MAX_TRANSFER ||
1258c2ecf20Sopenharmony_ci				(data[len - 2] == 0xff &&
1268c2ecf20Sopenharmony_ci					data[len - 1] == 0xd9)) {
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci				/* If the result is less than what was asked
1298c2ecf20Sopenharmony_ci				 * for, then it's the end of the
1308c2ecf20Sopenharmony_ci				 * frame. Sometimes the jpeg is not complete,
1318c2ecf20Sopenharmony_ci				 * but there's nothing we can do. We also end
1328c2ecf20Sopenharmony_ci				 * here if the the jpeg ends right at the end
1338c2ecf20Sopenharmony_ci				 * of the frame. */
1348c2ecf20Sopenharmony_ci				gspca_frame_add(gspca_dev, LAST_PACKET,
1358c2ecf20Sopenharmony_ci						data, len);
1368c2ecf20Sopenharmony_ci				break;
1378c2ecf20Sopenharmony_ci			}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci			/* got a partial image */
1408c2ecf20Sopenharmony_ci			gspca_frame_add(gspca_dev,
1418c2ecf20Sopenharmony_ci					gspca_dev->last_packet_type
1428c2ecf20Sopenharmony_ci						== LAST_PACKET
1438c2ecf20Sopenharmony_ci					? FIRST_PACKET : INTER_PACKET,
1448c2ecf20Sopenharmony_ci					data, len);
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci		/* We must wait before trying reading the next
1488c2ecf20Sopenharmony_ci		 * frame. If we don't, or if the delay is too short,
1498c2ecf20Sopenharmony_ci		 * the camera will disconnect. */
1508c2ecf20Sopenharmony_ci		msleep(NEXT_FRAME_DELAY);
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ciout:
1548c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "dostream stopped\n");
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/* this function is called at probe time */
1588c2ecf20Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev,
1598c2ecf20Sopenharmony_ci		const struct usb_device_id *id)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
1628c2ecf20Sopenharmony_ci	struct cam *cam = &gspca_dev->cam;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	cam->cam_mode = fpix_mode;
1658c2ecf20Sopenharmony_ci	cam->nmodes = 1;
1668c2ecf20Sopenharmony_ci	cam->bulk = 1;
1678c2ecf20Sopenharmony_ci	cam->bulk_size = FPIX_MAX_TRANSFER;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	INIT_WORK(&dev->work_struct, dostream);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return 0;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/* this function is called at probe and resume time */
1758c2ecf20Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/* start the camera */
1818c2ecf20Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
1848c2ecf20Sopenharmony_ci	int ret, len;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* Init the device */
1878c2ecf20Sopenharmony_ci	ret = command(gspca_dev, 0);
1888c2ecf20Sopenharmony_ci	if (ret < 0) {
1898c2ecf20Sopenharmony_ci		pr_err("init failed %d\n", ret);
1908c2ecf20Sopenharmony_ci		return ret;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Read the result of the command. Ignore the result, for it
1948c2ecf20Sopenharmony_ci	 * varies with the device. */
1958c2ecf20Sopenharmony_ci	ret = usb_bulk_msg(gspca_dev->dev,
1968c2ecf20Sopenharmony_ci			gspca_dev->urb[0]->pipe,
1978c2ecf20Sopenharmony_ci			gspca_dev->urb[0]->transfer_buffer,
1988c2ecf20Sopenharmony_ci			FPIX_MAX_TRANSFER, &len,
1998c2ecf20Sopenharmony_ci			FPIX_TIMEOUT);
2008c2ecf20Sopenharmony_ci	if (ret < 0) {
2018c2ecf20Sopenharmony_ci		pr_err("usb_bulk_msg failed %d\n", ret);
2028c2ecf20Sopenharmony_ci		return ret;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* Request a frame, but don't read it */
2068c2ecf20Sopenharmony_ci	ret = command(gspca_dev, 1);
2078c2ecf20Sopenharmony_ci	if (ret < 0) {
2088c2ecf20Sopenharmony_ci		pr_err("frame request failed %d\n", ret);
2098c2ecf20Sopenharmony_ci		return ret;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/* Again, reset bulk in endpoint */
2138c2ecf20Sopenharmony_ci	usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	schedule_work(&dev->work_struct);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return 0;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/* called on streamoff with alt==0 and on disconnect */
2218c2ecf20Sopenharmony_ci/* the usb_lock is held at entry - restore on exit */
2228c2ecf20Sopenharmony_cistatic void sd_stop0(struct gspca_dev *gspca_dev)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/* wait for the work queue to terminate */
2278c2ecf20Sopenharmony_ci	mutex_unlock(&gspca_dev->usb_lock);
2288c2ecf20Sopenharmony_ci	flush_work(&dev->work_struct);
2298c2ecf20Sopenharmony_ci	mutex_lock(&gspca_dev->usb_lock);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/* Table of supported USB devices */
2338c2ecf20Sopenharmony_cistatic const struct usb_device_id device_table[] = {
2348c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0104)},
2358c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0109)},
2368c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x010b)},
2378c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x010f)},
2388c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0111)},
2398c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0113)},
2408c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0115)},
2418c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0117)},
2428c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0119)},
2438c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x011b)},
2448c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x011d)},
2458c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0121)},
2468c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0123)},
2478c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0125)},
2488c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0127)},
2498c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0129)},
2508c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x012b)},
2518c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x012d)},
2528c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x012f)},
2538c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x0131)},
2548c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x013b)},
2558c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x013d)},
2568c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04cb, 0x013f)},
2578c2ecf20Sopenharmony_ci	{}
2588c2ecf20Sopenharmony_ci};
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci/* sub-driver description */
2638c2ecf20Sopenharmony_cistatic const struct sd_desc sd_desc = {
2648c2ecf20Sopenharmony_ci	.name   = MODULE_NAME,
2658c2ecf20Sopenharmony_ci	.config = sd_config,
2668c2ecf20Sopenharmony_ci	.init   = sd_init,
2678c2ecf20Sopenharmony_ci	.start  = sd_start,
2688c2ecf20Sopenharmony_ci	.stop0  = sd_stop0,
2698c2ecf20Sopenharmony_ci};
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci/* -- device connect -- */
2728c2ecf20Sopenharmony_cistatic int sd_probe(struct usb_interface *intf,
2738c2ecf20Sopenharmony_ci		const struct usb_device_id *id)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	return gspca_dev_probe(intf, id,
2768c2ecf20Sopenharmony_ci			&sd_desc,
2778c2ecf20Sopenharmony_ci			sizeof(struct usb_fpix),
2788c2ecf20Sopenharmony_ci			THIS_MODULE);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic struct usb_driver sd_driver = {
2828c2ecf20Sopenharmony_ci	.name       = MODULE_NAME,
2838c2ecf20Sopenharmony_ci	.id_table   = device_table,
2848c2ecf20Sopenharmony_ci	.probe      = sd_probe,
2858c2ecf20Sopenharmony_ci	.disconnect = gspca_disconnect,
2868c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
2878c2ecf20Sopenharmony_ci	.suspend = gspca_suspend,
2888c2ecf20Sopenharmony_ci	.resume  = gspca_resume,
2898c2ecf20Sopenharmony_ci	.reset_resume = gspca_resume,
2908c2ecf20Sopenharmony_ci#endif
2918c2ecf20Sopenharmony_ci};
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cimodule_usb_driver(sd_driver);
294