1// SPDX-License-Identifier: GPL-2.0-or-later
2/* Driver for Philips webcam
3   Functions that send various control messages to the webcam, including
4   video modes.
5   (C) 1999-2003 Nemosoft Unv.
6   (C) 2004-2006 Luc Saillard (luc@saillard.org)
7   (C) 2011 Hans de Goede <hdegoede@redhat.com>
8
9   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
10   driver and thus may have bugs that are not present in the original version.
11   Please send bug reports and support requests to <luc@saillard.org>.
12
13   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
14   driver and thus may have bugs that are not present in the original version.
15   Please send bug reports and support requests to <luc@saillard.org>.
16   The decompression routines have been implemented by reverse-engineering the
17   Nemosoft binary pwcx module. Caveat emptor.
18
19*/
20
21/*
22   Changes
23   2001/08/03  Alvarado   Added methods for changing white balance and
24			  red/green gains
25 */
26
27/* Control functions for the cam; brightness, contrast, video mode, etc. */
28
29#ifdef __KERNEL__
30#include <linux/uaccess.h>
31#endif
32#include <asm/errno.h>
33
34#include "pwc.h"
35#include "pwc-kiara.h"
36#include "pwc-timon.h"
37#include "pwc-dec1.h"
38#include "pwc-dec23.h"
39
40/* Selectors for status controls used only in this file */
41#define GET_STATUS_B00				0x0B00
42#define SENSOR_TYPE_FORMATTER1			0x0C00
43#define GET_STATUS_3000				0x3000
44#define READ_RAW_Y_MEAN_FORMATTER		0x3100
45#define SET_POWER_SAVE_MODE_FORMATTER		0x3200
46#define MIRROR_IMAGE_FORMATTER			0x3300
47#define LED_FORMATTER				0x3400
48#define LOWLIGHT				0x3500
49#define GET_STATUS_3600				0x3600
50#define SENSOR_TYPE_FORMATTER2			0x3700
51#define GET_STATUS_3800				0x3800
52#define GET_STATUS_4000				0x4000
53#define GET_STATUS_4100				0x4100	/* Get */
54#define CTL_STATUS_4200				0x4200	/* [GS] 1 */
55
56/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
57#define VIDEO_OUTPUT_CONTROL_FORMATTER		0x0100
58
59static const char *size2name[PSZ_MAX] =
60{
61	"subQCIF",
62	"QSIF",
63	"QCIF",
64	"SIF",
65	"CIF",
66	"VGA",
67};
68
69/********/
70
71/* Entries for the Nala (645/646) camera; the Nala doesn't have compression
72   preferences, so you either get compressed or non-compressed streams.
73
74   An alternate value of 0 means this mode is not available at all.
75 */
76
77#define PWC_FPS_MAX_NALA 8
78
79struct Nala_table_entry {
80	char alternate;			/* USB alternate setting */
81	int compressed;			/* Compressed yes/no */
82
83	unsigned char mode[3];		/* precomputed mode table */
84};
85
86static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 };
87
88static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
89{
90#include "pwc-nala.h"
91};
92
93/****************************************************************************/
94
95static int recv_control_msg(struct pwc_device *pdev,
96	u8 request, u16 value, int recv_count)
97{
98	int rc;
99
100	rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
101		request,
102		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
103		value, pdev->vcinterface,
104		pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT);
105	if (rc < 0)
106		PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
107			  rc, request, value);
108	return rc;
109}
110
111static inline int send_video_command(struct pwc_device *pdev,
112	int index, const unsigned char *buf, int buflen)
113{
114	int rc;
115
116	memcpy(pdev->ctrl_buf, buf, buflen);
117
118	rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
119			SET_EP_STREAM_CTL,
120			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
121			VIDEO_OUTPUT_CONTROL_FORMATTER, index,
122			pdev->ctrl_buf, buflen, USB_CTRL_SET_TIMEOUT);
123	if (rc >= 0)
124		memcpy(pdev->cmd_buf, buf, buflen);
125	else
126		PWC_ERROR("send_video_command error %d\n", rc);
127
128	return rc;
129}
130
131int send_control_msg(struct pwc_device *pdev,
132	u8 request, u16 value, void *buf, int buflen)
133{
134	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
135			request,
136			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
137			value, pdev->vcinterface,
138			buf, buflen, USB_CTRL_SET_TIMEOUT);
139}
140
141static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt,
142			       int frames, int *compression, int send_to_cam)
143{
144	int fps, ret = 0;
145	struct Nala_table_entry *pEntry;
146	int frames2frames[31] =
147	{ /* closest match of framerate */
148	   0,  0,  0,  0,  4,  /*  0-4  */
149	   5,  5,  7,  7, 10,  /*  5-9  */
150	  10, 10, 12, 12, 15,  /* 10-14 */
151	  15, 15, 15, 20, 20,  /* 15-19 */
152	  20, 20, 20, 24, 24,  /* 20-24 */
153	  24, 24, 24, 24, 24,  /* 25-29 */
154	  24                   /* 30    */
155	};
156	int frames2table[31] =
157	{ 0, 0, 0, 0, 0, /*  0-4  */
158	  1, 1, 1, 2, 2, /*  5-9  */
159	  3, 3, 4, 4, 4, /* 10-14 */
160	  5, 5, 5, 5, 5, /* 15-19 */
161	  6, 6, 6, 6, 7, /* 20-24 */
162	  7, 7, 7, 7, 7, /* 25-29 */
163	  7              /* 30    */
164	};
165
166	if (size < 0 || size > PSZ_CIF)
167		return -EINVAL;
168	if (frames < 4)
169		frames = 4;
170	else if (size > PSZ_QCIF && frames > 15)
171		frames = 15;
172	else if (frames > 25)
173		frames = 25;
174	frames = frames2frames[frames];
175	fps = frames2table[frames];
176	pEntry = &Nala_table[size][fps];
177	if (pEntry->alternate == 0)
178		return -EINVAL;
179
180	if (send_to_cam)
181		ret = send_video_command(pdev, pdev->vendpoint,
182					 pEntry->mode, 3);
183	if (ret < 0)
184		return ret;
185
186	if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420)
187		pwc_dec1_init(pdev, pEntry->mode);
188
189	/* Set various parameters */
190	pdev->pixfmt = pixfmt;
191	pdev->vframes = frames;
192	pdev->valternate = pEntry->alternate;
193	pdev->width  = pwc_image_sizes[size][0];
194	pdev->height = pwc_image_sizes[size][1];
195	pdev->frame_size = (pdev->width * pdev->height * 3) / 2;
196	if (pEntry->compressed) {
197		if (pdev->release < 5) { /* 4 fold compression */
198			pdev->vbandlength = 528;
199			pdev->frame_size /= 4;
200		}
201		else {
202			pdev->vbandlength = 704;
203			pdev->frame_size /= 3;
204		}
205	}
206	else
207		pdev->vbandlength = 0;
208
209	/* Let pwc-if.c:isoc_init know we don't support higher compression */
210	*compression = 3;
211
212	return 0;
213}
214
215
216static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt,
217				int frames, int *compression, int send_to_cam)
218{
219	const struct Timon_table_entry *pChoose;
220	int fps, ret = 0;
221
222	if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
223		return -EINVAL;
224	if (frames < 5)
225		frames = 5;
226	else if (size == PSZ_VGA && frames > 15)
227		frames = 15;
228	else if (frames > 30)
229		frames = 30;
230	fps = (frames / 5) - 1;
231
232	/* Find a supported framerate with progressively higher compression */
233	do {
234		pChoose = &Timon_table[size][fps][*compression];
235		if (pChoose->alternate != 0)
236			break;
237		(*compression)++;
238	} while (*compression <= 3);
239
240	if (pChoose->alternate == 0)
241		return -ENOENT; /* Not supported. */
242
243	if (send_to_cam)
244		ret = send_video_command(pdev, pdev->vendpoint,
245					 pChoose->mode, 13);
246	if (ret < 0)
247		return ret;
248
249	if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
250		pwc_dec23_init(pdev, pChoose->mode);
251
252	/* Set various parameters */
253	pdev->pixfmt = pixfmt;
254	pdev->vframes = (fps + 1) * 5;
255	pdev->valternate = pChoose->alternate;
256	pdev->width  = pwc_image_sizes[size][0];
257	pdev->height = pwc_image_sizes[size][1];
258	pdev->vbandlength = pChoose->bandlength;
259	if (pChoose->bandlength > 0)
260		pdev->frame_size = (pChoose->bandlength * pdev->height) / 4;
261	else
262		pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
263	return 0;
264}
265
266
267static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt,
268				int frames, int *compression, int send_to_cam)
269{
270	const struct Kiara_table_entry *pChoose;
271	int fps, ret = 0;
272
273	if (size >= PSZ_MAX || *compression < 0 || *compression > 3)
274		return -EINVAL;
275	if (frames < 5)
276		frames = 5;
277	else if (size == PSZ_VGA && frames > 15)
278		frames = 15;
279	else if (frames > 30)
280		frames = 30;
281	fps = (frames / 5) - 1;
282
283	/* Find a supported framerate with progressively higher compression */
284	do {
285		pChoose = &Kiara_table[size][fps][*compression];
286		if (pChoose->alternate != 0)
287			break;
288		(*compression)++;
289	} while (*compression <= 3);
290
291	if (pChoose->alternate == 0)
292		return -ENOENT; /* Not supported. */
293
294	/* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
295	if (send_to_cam)
296		ret = send_video_command(pdev, 4, pChoose->mode, 12);
297	if (ret < 0)
298		return ret;
299
300	if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420)
301		pwc_dec23_init(pdev, pChoose->mode);
302
303	/* All set and go */
304	pdev->pixfmt = pixfmt;
305	pdev->vframes = (fps + 1) * 5;
306	pdev->valternate = pChoose->alternate;
307	pdev->width  = pwc_image_sizes[size][0];
308	pdev->height = pwc_image_sizes[size][1];
309	pdev->vbandlength = pChoose->bandlength;
310	if (pdev->vbandlength > 0)
311		pdev->frame_size = (pdev->vbandlength * pdev->height) / 4;
312	else
313		pdev->frame_size = (pdev->width * pdev->height * 12) / 8;
314	PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
315	    pdev->frame_size, pdev->vframes, size, pdev->vbandlength);
316	return 0;
317}
318
319int pwc_set_video_mode(struct pwc_device *pdev, int width, int height,
320	int pixfmt, int frames, int *compression, int send_to_cam)
321{
322	int ret, size;
323
324	PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n",
325		       width, height, frames, pixfmt);
326	size = pwc_get_size(pdev, width, height);
327	PWC_TRACE("decode_size = %d.\n", size);
328
329	if (DEVICE_USE_CODEC1(pdev->type)) {
330		ret = set_video_mode_Nala(pdev, size, pixfmt, frames,
331					  compression, send_to_cam);
332	} else if (DEVICE_USE_CODEC3(pdev->type)) {
333		ret = set_video_mode_Kiara(pdev, size, pixfmt, frames,
334					   compression, send_to_cam);
335	} else {
336		ret = set_video_mode_Timon(pdev, size, pixfmt, frames,
337					   compression, send_to_cam);
338	}
339	if (ret < 0) {
340		PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
341		return ret;
342	}
343	pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
344	PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height);
345	return 0;
346}
347
348static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size)
349{
350	unsigned int i;
351
352	for (i = 0; i < PWC_FPS_MAX_NALA; i++) {
353		if (Nala_table[size][i].alternate) {
354			if (index--==0) return Nala_fps_vector[i];
355		}
356	}
357	return 0;
358}
359
360static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size)
361{
362	unsigned int i;
363
364	for (i = 0; i < PWC_FPS_MAX_KIARA; i++) {
365		if (Kiara_table[size][i][3].alternate) {
366			if (index--==0) return Kiara_fps_vector[i];
367		}
368	}
369	return 0;
370}
371
372static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size)
373{
374	unsigned int i;
375
376	for (i=0; i < PWC_FPS_MAX_TIMON; i++) {
377		if (Timon_table[size][i][3].alternate) {
378			if (index--==0) return Timon_fps_vector[i];
379		}
380	}
381	return 0;
382}
383
384unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size)
385{
386	unsigned int ret;
387
388	if (DEVICE_USE_CODEC1(pdev->type)) {
389		ret = pwc_get_fps_Nala(pdev, index, size);
390
391	} else if (DEVICE_USE_CODEC3(pdev->type)) {
392		ret = pwc_get_fps_Kiara(pdev, index, size);
393
394	} else {
395		ret = pwc_get_fps_Timon(pdev, index, size);
396	}
397
398	return ret;
399}
400
401int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
402{
403	int ret;
404
405	ret = recv_control_msg(pdev, request, value, 1);
406	if (ret < 0)
407		return ret;
408
409	*data = pdev->ctrl_buf[0];
410	return 0;
411}
412
413int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
414{
415	int ret;
416
417	pdev->ctrl_buf[0] = data;
418	ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1);
419	if (ret < 0)
420		return ret;
421
422	return 0;
423}
424
425int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
426{
427	int ret;
428
429	ret = recv_control_msg(pdev, request, value, 1);
430	if (ret < 0)
431		return ret;
432
433	*data = ((s8 *)pdev->ctrl_buf)[0];
434	return 0;
435}
436
437int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
438{
439	int ret;
440
441	ret = recv_control_msg(pdev, request, value, 2);
442	if (ret < 0)
443		return ret;
444
445	*data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0];
446	return 0;
447}
448
449int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data)
450{
451	int ret;
452
453	pdev->ctrl_buf[0] = data & 0xff;
454	pdev->ctrl_buf[1] = data >> 8;
455	ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2);
456	if (ret < 0)
457		return ret;
458
459	return 0;
460}
461
462int pwc_button_ctrl(struct pwc_device *pdev, u16 value)
463{
464	int ret;
465
466	ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0);
467	if (ret < 0)
468		return ret;
469
470	return 0;
471}
472
473/* POWER */
474void pwc_camera_power(struct pwc_device *pdev, int power)
475{
476	int r;
477
478	if (!pdev->power_save)
479		return;
480
481	if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
482		return;	/* Not supported by Nala or Timon < release 6 */
483
484	if (power)
485		pdev->ctrl_buf[0] = 0x00; /* active */
486	else
487		pdev->ctrl_buf[0] = 0xFF; /* power save */
488	r = send_control_msg(pdev, SET_STATUS_CTL,
489		SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1);
490	if (r < 0)
491		PWC_ERROR("Failed to power %s camera (%d)\n",
492			  power ? "on" : "off", r);
493}
494
495int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
496{
497	int r;
498
499	if (pdev->type < 730)
500		return 0;
501	on_value /= 100;
502	off_value /= 100;
503	if (on_value < 0)
504		on_value = 0;
505	if (on_value > 0xff)
506		on_value = 0xff;
507	if (off_value < 0)
508		off_value = 0;
509	if (off_value > 0xff)
510		off_value = 0xff;
511
512	pdev->ctrl_buf[0] = on_value;
513	pdev->ctrl_buf[1] = off_value;
514
515	r = send_control_msg(pdev,
516		SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2);
517	if (r < 0)
518		PWC_ERROR("Failed to set LED on/off time (%d)\n", r);
519
520	return r;
521}
522
523#ifdef CONFIG_USB_PWC_DEBUG
524int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
525{
526	int ret, request;
527
528	if (pdev->type < 675)
529		request = SENSOR_TYPE_FORMATTER1;
530	else if (pdev->type < 730)
531		return -1; /* The Vesta series doesn't have this call */
532	else
533		request = SENSOR_TYPE_FORMATTER2;
534
535	ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1);
536	if (ret < 0)
537		return ret;
538	if (pdev->type < 675)
539		*sensor = pdev->ctrl_buf[0] | 0x100;
540	else
541		*sensor = pdev->ctrl_buf[0];
542	return 0;
543}
544#endif
545