xref: /openbmc/linux/drivers/media/usb/go7007/go7007-usb.c (revision b5dcee225ce972fecb054e104be22b2a6f65303d)
17955f03dSHans Verkuil /*
27955f03dSHans Verkuil  * Copyright (C) 2005-2006 Micronas USA Inc.
37955f03dSHans Verkuil  *
47955f03dSHans Verkuil  * This program is free software; you can redistribute it and/or modify
57955f03dSHans Verkuil  * it under the terms of the GNU General Public License (Version 2) as
67955f03dSHans Verkuil  * published by the Free Software Foundation.
77955f03dSHans Verkuil  *
87955f03dSHans Verkuil  * This program is distributed in the hope that it will be useful,
97955f03dSHans Verkuil  * but WITHOUT ANY WARRANTY; without even the implied warranty of
107955f03dSHans Verkuil  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
117955f03dSHans Verkuil  * GNU General Public License for more details.
127955f03dSHans Verkuil  */
137955f03dSHans Verkuil 
147955f03dSHans Verkuil #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
157955f03dSHans Verkuil 
167955f03dSHans Verkuil #include <linux/module.h>
177955f03dSHans Verkuil #include <linux/kernel.h>
187955f03dSHans Verkuil #include <linux/wait.h>
197955f03dSHans Verkuil #include <linux/list.h>
207955f03dSHans Verkuil #include <linux/slab.h>
217955f03dSHans Verkuil #include <linux/time.h>
227955f03dSHans Verkuil #include <linux/mm.h>
237955f03dSHans Verkuil #include <linux/usb.h>
247955f03dSHans Verkuil #include <linux/i2c.h>
257955f03dSHans Verkuil #include <asm/byteorder.h>
26*b5dcee22SMauro Carvalho Chehab #include <media/i2c/saa7115.h>
277955f03dSHans Verkuil #include <media/tuner.h>
28*b5dcee22SMauro Carvalho Chehab #include <media/i2c/uda1342.h>
297955f03dSHans Verkuil 
307955f03dSHans Verkuil #include "go7007-priv.h"
317955f03dSHans Verkuil 
327955f03dSHans Verkuil static unsigned int assume_endura;
337955f03dSHans Verkuil module_param(assume_endura, int, 0644);
347955f03dSHans Verkuil MODULE_PARM_DESC(assume_endura,
357955f03dSHans Verkuil 			"when probing fails, hardware is a Pelco Endura");
367955f03dSHans Verkuil 
377955f03dSHans Verkuil /* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */
387955f03dSHans Verkuil 
397955f03dSHans Verkuil #define	HPI_STATUS_ADDR	0xFFF4
407955f03dSHans Verkuil #define	INT_PARAM_ADDR	0xFFF6
417955f03dSHans Verkuil #define	INT_INDEX_ADDR	0xFFF8
427955f03dSHans Verkuil 
437955f03dSHans Verkuil /*
447955f03dSHans Verkuil  * Pipes on EZ-USB interface:
457955f03dSHans Verkuil  *	0 snd - Control
467955f03dSHans Verkuil  *	0 rcv - Control
477955f03dSHans Verkuil  *	2 snd - Download firmware (control)
487955f03dSHans Verkuil  *	4 rcv - Read Interrupt (interrupt)
497955f03dSHans Verkuil  *	6 rcv - Read Video (bulk)
507955f03dSHans Verkuil  *	8 rcv - Read Audio (bulk)
517955f03dSHans Verkuil  */
527955f03dSHans Verkuil 
537955f03dSHans Verkuil #define GO7007_USB_EZUSB		(1<<0)
547955f03dSHans Verkuil #define GO7007_USB_EZUSB_I2C		(1<<1)
557955f03dSHans Verkuil 
567955f03dSHans Verkuil struct go7007_usb_board {
577955f03dSHans Verkuil 	unsigned int flags;
587955f03dSHans Verkuil 	struct go7007_board_info main_info;
597955f03dSHans Verkuil };
607955f03dSHans Verkuil 
617955f03dSHans Verkuil struct go7007_usb {
627955f03dSHans Verkuil 	const struct go7007_usb_board *board;
637955f03dSHans Verkuil 	struct mutex i2c_lock;
647955f03dSHans Verkuil 	struct usb_device *usbdev;
657955f03dSHans Verkuil 	struct urb *video_urbs[8];
667955f03dSHans Verkuil 	struct urb *audio_urbs[8];
677955f03dSHans Verkuil 	struct urb *intr_urb;
687955f03dSHans Verkuil };
697955f03dSHans Verkuil 
707955f03dSHans Verkuil /*********************** Product specification data ***********************/
717955f03dSHans Verkuil 
727955f03dSHans Verkuil static const struct go7007_usb_board board_matrix_ii = {
737955f03dSHans Verkuil 	.flags		= GO7007_USB_EZUSB,
747955f03dSHans Verkuil 	.main_info	= {
757955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_HAS_AUDIO |
767955f03dSHans Verkuil 					GO7007_BOARD_USE_ONBOARD_I2C,
777955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
787955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
797955f03dSHans Verkuil 		.audio_rate	 = 48000,
807955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
817955f03dSHans Verkuil 		.audio_main_div	 = 2,
827955f03dSHans Verkuil 		.hpi_buffer_cap  = 7,
837955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
847955f03dSHans Verkuil 					GO7007_SENSOR_VALID_ENABLE |
857955f03dSHans Verkuil 					GO7007_SENSOR_TV |
867955f03dSHans Verkuil 					GO7007_SENSOR_SAA7115 |
877955f03dSHans Verkuil 					GO7007_SENSOR_VBI |
887955f03dSHans Verkuil 					GO7007_SENSOR_SCALING,
897955f03dSHans Verkuil 		.num_i2c_devs	 = 1,
907955f03dSHans Verkuil 		.i2c_devs	 = {
917955f03dSHans Verkuil 			{
927955f03dSHans Verkuil 				.type	= "saa7115",
937955f03dSHans Verkuil 				.addr	= 0x20,
947955f03dSHans Verkuil 				.is_video = 1,
957955f03dSHans Verkuil 			},
967955f03dSHans Verkuil 		},
977955f03dSHans Verkuil 		.num_inputs	 = 2,
987955f03dSHans Verkuil 		.inputs		 = {
997955f03dSHans Verkuil 			{
1007955f03dSHans Verkuil 				.video_input	= 0,
1017955f03dSHans Verkuil 				.name		= "Composite",
1027955f03dSHans Verkuil 			},
1037955f03dSHans Verkuil 			{
1047955f03dSHans Verkuil 				.video_input	= 9,
1057955f03dSHans Verkuil 				.name		= "S-Video",
1067955f03dSHans Verkuil 			},
1077955f03dSHans Verkuil 		},
1087955f03dSHans Verkuil 		.video_config	= SAA7115_IDQ_IS_DEFAULT,
1097955f03dSHans Verkuil 	},
1107955f03dSHans Verkuil };
1117955f03dSHans Verkuil 
1127955f03dSHans Verkuil static const struct go7007_usb_board board_matrix_reload = {
1137955f03dSHans Verkuil 	.flags		= GO7007_USB_EZUSB,
1147955f03dSHans Verkuil 	.main_info	= {
1157955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_HAS_AUDIO |
1167955f03dSHans Verkuil 					GO7007_BOARD_USE_ONBOARD_I2C,
1177955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
1187955f03dSHans Verkuil 					GO7007_AUDIO_I2S_MASTER |
1197955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
1207955f03dSHans Verkuil 		.audio_rate	 = 48000,
1217955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
1227955f03dSHans Verkuil 		.audio_main_div	 = 2,
1237955f03dSHans Verkuil 		.hpi_buffer_cap  = 7,
1247955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
1257955f03dSHans Verkuil 					GO7007_SENSOR_TV,
1267955f03dSHans Verkuil 		.num_i2c_devs	 = 1,
1277955f03dSHans Verkuil 		.i2c_devs	 = {
1287955f03dSHans Verkuil 			{
1297955f03dSHans Verkuil 				.type	= "saa7113",
1307955f03dSHans Verkuil 				.addr	= 0x25,
1317955f03dSHans Verkuil 				.is_video = 1,
1327955f03dSHans Verkuil 			},
1337955f03dSHans Verkuil 		},
1347955f03dSHans Verkuil 		.num_inputs	 = 2,
1357955f03dSHans Verkuil 		.inputs		 = {
1367955f03dSHans Verkuil 			{
1377955f03dSHans Verkuil 				.video_input	= 0,
1387955f03dSHans Verkuil 				.name		= "Composite",
1397955f03dSHans Verkuil 			},
1407955f03dSHans Verkuil 			{
1417955f03dSHans Verkuil 				.video_input	= 9,
1427955f03dSHans Verkuil 				.name		= "S-Video",
1437955f03dSHans Verkuil 			},
1447955f03dSHans Verkuil 		},
1457955f03dSHans Verkuil 		.video_config	= SAA7115_IDQ_IS_DEFAULT,
1467955f03dSHans Verkuil 	},
1477955f03dSHans Verkuil };
1487955f03dSHans Verkuil 
1497955f03dSHans Verkuil static const struct go7007_usb_board board_star_trek = {
1507955f03dSHans Verkuil 	.flags		= GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
1517955f03dSHans Verkuil 	.main_info	= {
1527955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_HAS_AUDIO, /* |
1537955f03dSHans Verkuil 					GO7007_BOARD_HAS_TUNER, */
1547955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
1557955f03dSHans Verkuil 					GO7007_SENSOR_VALID_ENABLE |
1567955f03dSHans Verkuil 					GO7007_SENSOR_TV |
1577955f03dSHans Verkuil 					GO7007_SENSOR_SAA7115 |
1587955f03dSHans Verkuil 					GO7007_SENSOR_VBI |
1597955f03dSHans Verkuil 					GO7007_SENSOR_SCALING,
1607955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
1617955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
1627955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
1637955f03dSHans Verkuil 		.audio_main_div	 = 2,
1647955f03dSHans Verkuil 		.hpi_buffer_cap  = 7,
1657955f03dSHans Verkuil 		.num_i2c_devs	 = 1,
1667955f03dSHans Verkuil 		.i2c_devs	 = {
1677955f03dSHans Verkuil 			{
1687955f03dSHans Verkuil 				.type	= "saa7115",
1697955f03dSHans Verkuil 				.addr	= 0x20,
1707955f03dSHans Verkuil 				.is_video = 1,
1717955f03dSHans Verkuil 			},
1727955f03dSHans Verkuil 		},
1737955f03dSHans Verkuil 		.num_inputs	 = 2,
1747955f03dSHans Verkuil 		.inputs		 = {
1757955f03dSHans Verkuil 		/*	{
1767955f03dSHans Verkuil 		 *		.video_input	= 3,
1777955f03dSHans Verkuil 		 *		.audio_index	= AUDIO_TUNER,
1787955f03dSHans Verkuil 		 *		.name		= "Tuner",
1797955f03dSHans Verkuil 		 *	},
1807955f03dSHans Verkuil 		 */
1817955f03dSHans Verkuil 			{
1827955f03dSHans Verkuil 				.video_input	= 1,
1837955f03dSHans Verkuil 			/*	.audio_index	= AUDIO_EXTERN, */
1847955f03dSHans Verkuil 				.name		= "Composite",
1857955f03dSHans Verkuil 			},
1867955f03dSHans Verkuil 			{
1877955f03dSHans Verkuil 				.video_input	= 8,
1887955f03dSHans Verkuil 			/*	.audio_index	= AUDIO_EXTERN, */
1897955f03dSHans Verkuil 				.name		= "S-Video",
1907955f03dSHans Verkuil 			},
1917955f03dSHans Verkuil 		},
1927955f03dSHans Verkuil 		.video_config	= SAA7115_IDQ_IS_DEFAULT,
1937955f03dSHans Verkuil 	},
1947955f03dSHans Verkuil };
1957955f03dSHans Verkuil 
1967955f03dSHans Verkuil static const struct go7007_usb_board board_px_tv402u = {
1977955f03dSHans Verkuil 	.flags		= GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
1987955f03dSHans Verkuil 	.main_info	= {
1997955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_HAS_AUDIO |
2007955f03dSHans Verkuil 					GO7007_BOARD_HAS_TUNER,
2017955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
2027955f03dSHans Verkuil 					GO7007_SENSOR_VALID_ENABLE |
2037955f03dSHans Verkuil 					GO7007_SENSOR_TV |
2047955f03dSHans Verkuil 					GO7007_SENSOR_SAA7115 |
2057955f03dSHans Verkuil 					GO7007_SENSOR_VBI |
2067955f03dSHans Verkuil 					GO7007_SENSOR_SCALING,
2077955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
2087955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
2097955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
2107955f03dSHans Verkuil 		.audio_main_div	 = 2,
2117955f03dSHans Verkuil 		.hpi_buffer_cap  = 7,
2127955f03dSHans Verkuil 		.num_i2c_devs	 = 5,
2137955f03dSHans Verkuil 		.i2c_devs	 = {
2147955f03dSHans Verkuil 			{
2157955f03dSHans Verkuil 				.type	= "saa7115",
2167955f03dSHans Verkuil 				.addr	= 0x20,
2177955f03dSHans Verkuil 				.is_video = 1,
2187955f03dSHans Verkuil 			},
2197955f03dSHans Verkuil 			{
2207955f03dSHans Verkuil 				.type	= "uda1342",
2217955f03dSHans Verkuil 				.addr	= 0x1a,
2227955f03dSHans Verkuil 				.is_audio = 1,
2237955f03dSHans Verkuil 			},
2247955f03dSHans Verkuil 			{
2257955f03dSHans Verkuil 				.type	= "tuner",
2267955f03dSHans Verkuil 				.addr	= 0x60,
2277955f03dSHans Verkuil 			},
2287955f03dSHans Verkuil 			{
2297955f03dSHans Verkuil 				.type	= "tuner",
2307955f03dSHans Verkuil 				.addr	= 0x43,
2317955f03dSHans Verkuil 			},
2327955f03dSHans Verkuil 			{
2337955f03dSHans Verkuil 				.type	= "sony-btf-mpx",
2347955f03dSHans Verkuil 				.addr	= 0x44,
2357955f03dSHans Verkuil 			},
2367955f03dSHans Verkuil 		},
2377955f03dSHans Verkuil 		.num_inputs	 = 3,
2387955f03dSHans Verkuil 		.inputs		 = {
2397955f03dSHans Verkuil 			{
2407955f03dSHans Verkuil 				.video_input	= 3,
2417955f03dSHans Verkuil 				.audio_index	= 0,
2427955f03dSHans Verkuil 				.name		= "Tuner",
2437955f03dSHans Verkuil 			},
2447955f03dSHans Verkuil 			{
2457955f03dSHans Verkuil 				.video_input	= 1,
2467955f03dSHans Verkuil 				.audio_index	= 1,
2477955f03dSHans Verkuil 				.name		= "Composite",
2487955f03dSHans Verkuil 			},
2497955f03dSHans Verkuil 			{
2507955f03dSHans Verkuil 				.video_input	= 8,
2517955f03dSHans Verkuil 				.audio_index	= 1,
2527955f03dSHans Verkuil 				.name		= "S-Video",
2537955f03dSHans Verkuil 			},
2547955f03dSHans Verkuil 		},
2557955f03dSHans Verkuil 		.video_config	= SAA7115_IDQ_IS_DEFAULT,
2567955f03dSHans Verkuil 		.num_aud_inputs	 = 2,
2577955f03dSHans Verkuil 		.aud_inputs	 = {
2587955f03dSHans Verkuil 			{
2597955f03dSHans Verkuil 				.audio_input	= UDA1342_IN2,
2607955f03dSHans Verkuil 				.name		= "Tuner",
2617955f03dSHans Verkuil 			},
2627955f03dSHans Verkuil 			{
2637955f03dSHans Verkuil 				.audio_input	= UDA1342_IN1,
2647955f03dSHans Verkuil 				.name		= "Line In",
2657955f03dSHans Verkuil 			},
2667955f03dSHans Verkuil 		},
2677955f03dSHans Verkuil 	},
2687955f03dSHans Verkuil };
2697955f03dSHans Verkuil 
2707955f03dSHans Verkuil static const struct go7007_usb_board board_xmen = {
2717955f03dSHans Verkuil 	.flags		= 0,
2727955f03dSHans Verkuil 	.main_info	= {
2737955f03dSHans Verkuil 		.flags		  = GO7007_BOARD_USE_ONBOARD_I2C,
2747955f03dSHans Verkuil 		.hpi_buffer_cap   = 0,
2757955f03dSHans Verkuil 		.sensor_flags	  = GO7007_SENSOR_VREF_POLAR,
2767955f03dSHans Verkuil 		.sensor_width	  = 320,
2777955f03dSHans Verkuil 		.sensor_height	  = 240,
2787955f03dSHans Verkuil 		.sensor_framerate = 30030,
2797955f03dSHans Verkuil 		.audio_flags	  = GO7007_AUDIO_ONE_CHANNEL |
2807955f03dSHans Verkuil 					GO7007_AUDIO_I2S_MODE_3 |
2817955f03dSHans Verkuil 					GO7007_AUDIO_WORD_14 |
2827955f03dSHans Verkuil 					GO7007_AUDIO_I2S_MASTER |
2837955f03dSHans Verkuil 					GO7007_AUDIO_BCLK_POLAR |
2847955f03dSHans Verkuil 					GO7007_AUDIO_OKI_MODE,
2857955f03dSHans Verkuil 		.audio_rate	  = 8000,
2867955f03dSHans Verkuil 		.audio_bclk_div	  = 48,
2877955f03dSHans Verkuil 		.audio_main_div	  = 1,
2887955f03dSHans Verkuil 		.num_i2c_devs	  = 1,
2897955f03dSHans Verkuil 		.i2c_devs	  = {
2907955f03dSHans Verkuil 			{
2917955f03dSHans Verkuil 				.type	= "ov7640",
2927955f03dSHans Verkuil 				.addr	= 0x21,
2937955f03dSHans Verkuil 			},
2947955f03dSHans Verkuil 		},
2957955f03dSHans Verkuil 		.num_inputs	  = 1,
2967955f03dSHans Verkuil 		.inputs		  = {
2977955f03dSHans Verkuil 			{
2987955f03dSHans Verkuil 				.name		= "Camera",
2997955f03dSHans Verkuil 			},
3007955f03dSHans Verkuil 		},
3017955f03dSHans Verkuil 	},
3027955f03dSHans Verkuil };
3037955f03dSHans Verkuil 
3047955f03dSHans Verkuil static const struct go7007_usb_board board_matrix_revolution = {
3057955f03dSHans Verkuil 	.flags		= GO7007_USB_EZUSB,
3067955f03dSHans Verkuil 	.main_info	= {
3077955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_HAS_AUDIO |
3087955f03dSHans Verkuil 					GO7007_BOARD_USE_ONBOARD_I2C,
3097955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
3107955f03dSHans Verkuil 					GO7007_AUDIO_I2S_MASTER |
3117955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
3127955f03dSHans Verkuil 		.audio_rate	 = 48000,
3137955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
3147955f03dSHans Verkuil 		.audio_main_div	 = 2,
3157955f03dSHans Verkuil 		.hpi_buffer_cap  = 7,
3167955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
3177955f03dSHans Verkuil 					GO7007_SENSOR_TV |
3187955f03dSHans Verkuil 					GO7007_SENSOR_VBI,
3197955f03dSHans Verkuil 		.num_i2c_devs	 = 1,
3207955f03dSHans Verkuil 		.i2c_devs	 = {
3217955f03dSHans Verkuil 			{
3227955f03dSHans Verkuil 				.type	= "tw9903",
3237955f03dSHans Verkuil 				.is_video = 1,
3247955f03dSHans Verkuil 				.addr	= 0x44,
3257955f03dSHans Verkuil 			},
3267955f03dSHans Verkuil 		},
3277955f03dSHans Verkuil 		.num_inputs	 = 2,
3287955f03dSHans Verkuil 		.inputs		 = {
3297955f03dSHans Verkuil 			{
3307955f03dSHans Verkuil 				.video_input	= 2,
3317955f03dSHans Verkuil 				.name		= "Composite",
3327955f03dSHans Verkuil 			},
3337955f03dSHans Verkuil 			{
3347955f03dSHans Verkuil 				.video_input	= 8,
3357955f03dSHans Verkuil 				.name		= "S-Video",
3367955f03dSHans Verkuil 			},
3377955f03dSHans Verkuil 		},
3387955f03dSHans Verkuil 	},
3397955f03dSHans Verkuil };
3407955f03dSHans Verkuil 
3416629e4deSMauro Carvalho Chehab #if 0
3427955f03dSHans Verkuil static const struct go7007_usb_board board_lifeview_lr192 = {
3437955f03dSHans Verkuil 	.flags		= GO7007_USB_EZUSB,
3447955f03dSHans Verkuil 	.main_info	= {
3457955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_HAS_AUDIO |
3467955f03dSHans Verkuil 					GO7007_BOARD_USE_ONBOARD_I2C,
3477955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
3487955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
3497955f03dSHans Verkuil 		.audio_rate	 = 48000,
3507955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
3517955f03dSHans Verkuil 		.audio_main_div	 = 2,
3527955f03dSHans Verkuil 		.hpi_buffer_cap  = 7,
3537955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
3547955f03dSHans Verkuil 					GO7007_SENSOR_VALID_ENABLE |
3557955f03dSHans Verkuil 					GO7007_SENSOR_TV |
3567955f03dSHans Verkuil 					GO7007_SENSOR_VBI |
3577955f03dSHans Verkuil 					GO7007_SENSOR_SCALING,
3587955f03dSHans Verkuil 		.num_i2c_devs	 = 0,
3597955f03dSHans Verkuil 		.num_inputs	 = 1,
3607955f03dSHans Verkuil 		.inputs		 = {
3617955f03dSHans Verkuil 			{
3627955f03dSHans Verkuil 				.video_input	= 0,
3637955f03dSHans Verkuil 				.name		= "Composite",
3647955f03dSHans Verkuil 			},
3657955f03dSHans Verkuil 		},
3667955f03dSHans Verkuil 	},
3677955f03dSHans Verkuil };
3686629e4deSMauro Carvalho Chehab #endif
3697955f03dSHans Verkuil 
3707955f03dSHans Verkuil static const struct go7007_usb_board board_endura = {
3717955f03dSHans Verkuil 	.flags		= 0,
3727955f03dSHans Verkuil 	.main_info	= {
3737955f03dSHans Verkuil 		.flags		 = 0,
3747955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
3757955f03dSHans Verkuil 					GO7007_AUDIO_I2S_MASTER |
3767955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
3777955f03dSHans Verkuil 		.audio_rate	 = 8000,
3787955f03dSHans Verkuil 		.audio_bclk_div	 = 48,
3797955f03dSHans Verkuil 		.audio_main_div	 = 8,
3807955f03dSHans Verkuil 		.hpi_buffer_cap  = 0,
3817955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
3827955f03dSHans Verkuil 					GO7007_SENSOR_TV,
3837955f03dSHans Verkuil 		.sensor_h_offset = 8,
3847955f03dSHans Verkuil 		.num_i2c_devs	 = 0,
3857955f03dSHans Verkuil 		.num_inputs	 = 1,
3867955f03dSHans Verkuil 		.inputs		 = {
3877955f03dSHans Verkuil 			{
3887955f03dSHans Verkuil 				.name		= "Camera",
3897955f03dSHans Verkuil 			},
3907955f03dSHans Verkuil 		},
3917955f03dSHans Verkuil 	},
3927955f03dSHans Verkuil };
3937955f03dSHans Verkuil 
3947955f03dSHans Verkuil static const struct go7007_usb_board board_adlink_mpg24 = {
3957955f03dSHans Verkuil 	.flags		= 0,
3967955f03dSHans Verkuil 	.main_info	= {
3977955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_USE_ONBOARD_I2C,
3987955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
3997955f03dSHans Verkuil 					GO7007_AUDIO_I2S_MASTER |
4007955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
4017955f03dSHans Verkuil 		.audio_rate	 = 48000,
4027955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
4037955f03dSHans Verkuil 		.audio_main_div	 = 2,
4047955f03dSHans Verkuil 		.hpi_buffer_cap  = 0,
4057955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
4067955f03dSHans Verkuil 					GO7007_SENSOR_TV |
4077955f03dSHans Verkuil 					GO7007_SENSOR_VBI,
4087955f03dSHans Verkuil 		.num_i2c_devs	 = 1,
4097955f03dSHans Verkuil 		.i2c_devs	 = {
4107955f03dSHans Verkuil 			{
4117955f03dSHans Verkuil 				.type	= "tw2804",
4127955f03dSHans Verkuil 				.addr	= 0x00, /* yes, really */
4137955f03dSHans Verkuil 				.flags  = I2C_CLIENT_TEN,
4147955f03dSHans Verkuil 				.is_video = 1,
4157955f03dSHans Verkuil 			},
4167955f03dSHans Verkuil 		},
4177955f03dSHans Verkuil 		.num_inputs	 = 1,
4187955f03dSHans Verkuil 		.inputs		 = {
4197955f03dSHans Verkuil 			{
4207955f03dSHans Verkuil 				.name		= "Composite",
4217955f03dSHans Verkuil 			},
4227955f03dSHans Verkuil 		},
4237955f03dSHans Verkuil 	},
4247955f03dSHans Verkuil };
4257955f03dSHans Verkuil 
4267955f03dSHans Verkuil static const struct go7007_usb_board board_sensoray_2250 = {
4277955f03dSHans Verkuil 	.flags		= GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
4287955f03dSHans Verkuil 	.main_info	= {
4297955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
4307955f03dSHans Verkuil 					GO7007_AUDIO_I2S_MASTER |
4317955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
4327955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_HAS_AUDIO,
4337955f03dSHans Verkuil 		.audio_rate	 = 48000,
4347955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
4357955f03dSHans Verkuil 		.audio_main_div	 = 2,
4367955f03dSHans Verkuil 		.hpi_buffer_cap  = 7,
4377955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
4387955f03dSHans Verkuil 					GO7007_SENSOR_TV,
4397955f03dSHans Verkuil 		.num_i2c_devs	 = 1,
4407955f03dSHans Verkuil 		.i2c_devs	 = {
4417955f03dSHans Verkuil 			{
4427955f03dSHans Verkuil 				.type	= "s2250",
4437955f03dSHans Verkuil 				.addr	= 0x43,
4447955f03dSHans Verkuil 				.is_video = 1,
4457955f03dSHans Verkuil 				.is_audio = 1,
4467955f03dSHans Verkuil 			},
4477955f03dSHans Verkuil 		},
4487955f03dSHans Verkuil 		.num_inputs	 = 2,
4497955f03dSHans Verkuil 		.inputs		 = {
4507955f03dSHans Verkuil 			{
4517955f03dSHans Verkuil 				.video_input	= 0,
4527955f03dSHans Verkuil 				.name		= "Composite",
4537955f03dSHans Verkuil 			},
4547955f03dSHans Verkuil 			{
4557955f03dSHans Verkuil 				.video_input	= 1,
4567955f03dSHans Verkuil 				.name		= "S-Video",
4577955f03dSHans Verkuil 			},
4587955f03dSHans Verkuil 		},
4597955f03dSHans Verkuil 		.num_aud_inputs	 = 3,
4607955f03dSHans Verkuil 		.aud_inputs	 = {
4617955f03dSHans Verkuil 			{
4627955f03dSHans Verkuil 				.audio_input	= 0,
4637955f03dSHans Verkuil 				.name		= "Line In",
4647955f03dSHans Verkuil 			},
4657955f03dSHans Verkuil 			{
4667955f03dSHans Verkuil 				.audio_input	= 1,
4677955f03dSHans Verkuil 				.name		= "Mic",
4687955f03dSHans Verkuil 			},
4697955f03dSHans Verkuil 			{
4707955f03dSHans Verkuil 				.audio_input	= 2,
4717955f03dSHans Verkuil 				.name		= "Mic Boost",
4727955f03dSHans Verkuil 			},
4737955f03dSHans Verkuil 		},
4747955f03dSHans Verkuil 	},
4757955f03dSHans Verkuil };
4767955f03dSHans Verkuil 
4777955f03dSHans Verkuil static const struct go7007_usb_board board_ads_usbav_709 = {
4787955f03dSHans Verkuil 	.flags		= GO7007_USB_EZUSB,
4797955f03dSHans Verkuil 	.main_info	= {
4807955f03dSHans Verkuil 		.flags		 = GO7007_BOARD_HAS_AUDIO |
4817955f03dSHans Verkuil 					GO7007_BOARD_USE_ONBOARD_I2C,
4827955f03dSHans Verkuil 		.audio_flags	 = GO7007_AUDIO_I2S_MODE_1 |
4837955f03dSHans Verkuil 					GO7007_AUDIO_I2S_MASTER |
4847955f03dSHans Verkuil 					GO7007_AUDIO_WORD_16,
4857955f03dSHans Verkuil 		.audio_rate	 = 48000,
4867955f03dSHans Verkuil 		.audio_bclk_div	 = 8,
4877955f03dSHans Verkuil 		.audio_main_div	 = 2,
4887955f03dSHans Verkuil 		.hpi_buffer_cap  = 7,
4897955f03dSHans Verkuil 		.sensor_flags	 = GO7007_SENSOR_656 |
4907955f03dSHans Verkuil 					GO7007_SENSOR_TV |
4917955f03dSHans Verkuil 					GO7007_SENSOR_VBI,
4927955f03dSHans Verkuil 		.num_i2c_devs	 = 1,
4937955f03dSHans Verkuil 		.i2c_devs	 = {
4947955f03dSHans Verkuil 			{
4957955f03dSHans Verkuil 				.type	= "tw9906",
4967955f03dSHans Verkuil 				.is_video = 1,
4977955f03dSHans Verkuil 				.addr	= 0x44,
4987955f03dSHans Verkuil 			},
4997955f03dSHans Verkuil 		},
5007955f03dSHans Verkuil 		.num_inputs	 = 2,
5017955f03dSHans Verkuil 		.inputs		 = {
5027955f03dSHans Verkuil 			{
5037955f03dSHans Verkuil 				.video_input	= 0,
5047955f03dSHans Verkuil 				.name		= "Composite",
5057955f03dSHans Verkuil 			},
5067955f03dSHans Verkuil 			{
5077955f03dSHans Verkuil 				.video_input	= 10,
5087955f03dSHans Verkuil 				.name		= "S-Video",
5097955f03dSHans Verkuil 			},
5107955f03dSHans Verkuil 		},
5117955f03dSHans Verkuil 	},
5127955f03dSHans Verkuil };
5137955f03dSHans Verkuil 
5147955f03dSHans Verkuil static const struct usb_device_id go7007_usb_id_table[] = {
5157955f03dSHans Verkuil 	{
5167955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
5177955f03dSHans Verkuil 					USB_DEVICE_ID_MATCH_INT_INFO,
5187955f03dSHans Verkuil 		.idVendor	= 0x0eb1,  /* Vendor ID of WIS Technologies */
5197955f03dSHans Verkuil 		.idProduct	= 0x7007,  /* Product ID of GO7007SB chip */
5207955f03dSHans Verkuil 		.bcdDevice_lo	= 0x200,   /* Revision number of XMen */
5217955f03dSHans Verkuil 		.bcdDevice_hi	= 0x200,
5227955f03dSHans Verkuil 		.bInterfaceClass	= 255,
5237955f03dSHans Verkuil 		.bInterfaceSubClass	= 0,
5247955f03dSHans Verkuil 		.bInterfaceProtocol	= 255,
5257955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_XMEN,
5267955f03dSHans Verkuil 	},
5277955f03dSHans Verkuil 	{
5287955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
5297955f03dSHans Verkuil 		.idVendor	= 0x0eb1,  /* Vendor ID of WIS Technologies */
5307955f03dSHans Verkuil 		.idProduct	= 0x7007,  /* Product ID of GO7007SB chip */
5317955f03dSHans Verkuil 		.bcdDevice_lo	= 0x202,   /* Revision number of Matrix II */
5327955f03dSHans Verkuil 		.bcdDevice_hi	= 0x202,
5337955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,
5347955f03dSHans Verkuil 	},
5357955f03dSHans Verkuil 	{
5367955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
5377955f03dSHans Verkuil 		.idVendor	= 0x0eb1,  /* Vendor ID of WIS Technologies */
5387955f03dSHans Verkuil 		.idProduct	= 0x7007,  /* Product ID of GO7007SB chip */
5397955f03dSHans Verkuil 		.bcdDevice_lo	= 0x204,   /* Revision number of Matrix */
5407955f03dSHans Verkuil 		.bcdDevice_hi	= 0x204,   /*     Reloaded */
5417955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,
5427955f03dSHans Verkuil 	},
5437955f03dSHans Verkuil 	{
5447955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
5457955f03dSHans Verkuil 					USB_DEVICE_ID_MATCH_INT_INFO,
5467955f03dSHans Verkuil 		.idVendor	= 0x0eb1,  /* Vendor ID of WIS Technologies */
5477955f03dSHans Verkuil 		.idProduct	= 0x7007,  /* Product ID of GO7007SB chip */
5487955f03dSHans Verkuil 		.bcdDevice_lo	= 0x205,   /* Revision number of XMen-II */
5497955f03dSHans Verkuil 		.bcdDevice_hi	= 0x205,
5507955f03dSHans Verkuil 		.bInterfaceClass	= 255,
5517955f03dSHans Verkuil 		.bInterfaceSubClass	= 0,
5527955f03dSHans Verkuil 		.bInterfaceProtocol	= 255,
5537955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_XMEN_II,
5547955f03dSHans Verkuil 	},
5557955f03dSHans Verkuil 	{
5567955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
5577955f03dSHans Verkuil 		.idVendor	= 0x0eb1,  /* Vendor ID of WIS Technologies */
5587955f03dSHans Verkuil 		.idProduct	= 0x7007,  /* Product ID of GO7007SB chip */
5597955f03dSHans Verkuil 		.bcdDevice_lo	= 0x208,   /* Revision number of Star Trek */
5607955f03dSHans Verkuil 		.bcdDevice_hi	= 0x208,
5617955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_STAR_TREK,
5627955f03dSHans Verkuil 	},
5637955f03dSHans Verkuil 	{
5647955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
5657955f03dSHans Verkuil 					USB_DEVICE_ID_MATCH_INT_INFO,
5667955f03dSHans Verkuil 		.idVendor	= 0x0eb1,  /* Vendor ID of WIS Technologies */
5677955f03dSHans Verkuil 		.idProduct	= 0x7007,  /* Product ID of GO7007SB chip */
5687955f03dSHans Verkuil 		.bcdDevice_lo	= 0x209,   /* Revision number of XMen-III */
5697955f03dSHans Verkuil 		.bcdDevice_hi	= 0x209,
5707955f03dSHans Verkuil 		.bInterfaceClass	= 255,
5717955f03dSHans Verkuil 		.bInterfaceSubClass	= 0,
5727955f03dSHans Verkuil 		.bInterfaceProtocol	= 255,
5737955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_XMEN_III,
5747955f03dSHans Verkuil 	},
5757955f03dSHans Verkuil 	{
5767955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
5777955f03dSHans Verkuil 		.idVendor	= 0x0eb1,  /* Vendor ID of WIS Technologies */
5787955f03dSHans Verkuil 		.idProduct	= 0x7007,  /* Product ID of GO7007SB chip */
5797955f03dSHans Verkuil 		.bcdDevice_lo	= 0x210,   /* Revision number of Matrix */
5807955f03dSHans Verkuil 		.bcdDevice_hi	= 0x210,   /*     Revolution */
5817955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV,
5827955f03dSHans Verkuil 	},
5837955f03dSHans Verkuil 	{
5847955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
5857955f03dSHans Verkuil 		.idVendor	= 0x093b,  /* Vendor ID of Plextor */
5867955f03dSHans Verkuil 		.idProduct	= 0xa102,  /* Product ID of M402U */
5877955f03dSHans Verkuil 		.bcdDevice_lo	= 0x1,	   /* revision number of Blueberry */
5887955f03dSHans Verkuil 		.bcdDevice_hi	= 0x1,
5897955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_PX_M402U,
5907955f03dSHans Verkuil 	},
5917955f03dSHans Verkuil 	{
5927955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
5937955f03dSHans Verkuil 		.idVendor	= 0x093b,  /* Vendor ID of Plextor */
5947955f03dSHans Verkuil 		.idProduct	= 0xa104,  /* Product ID of TV402U */
5957955f03dSHans Verkuil 		.bcdDevice_lo	= 0x1,
5967955f03dSHans Verkuil 		.bcdDevice_hi	= 0x1,
5977955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_PX_TV402U,
5987955f03dSHans Verkuil 	},
5997955f03dSHans Verkuil 	{
6007955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
6017955f03dSHans Verkuil 		.idVendor	= 0x10fd,  /* Vendor ID of Anubis Electronics */
6027955f03dSHans Verkuil 		.idProduct	= 0xde00,  /* Product ID of Lifeview LR192 */
6037955f03dSHans Verkuil 		.bcdDevice_lo	= 0x1,
6047955f03dSHans Verkuil 		.bcdDevice_hi	= 0x1,
6057955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192,
6067955f03dSHans Verkuil 	},
6077955f03dSHans Verkuil 	{
6087955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
6097955f03dSHans Verkuil 		.idVendor	= 0x1943,  /* Vendor ID Sensoray */
6107955f03dSHans Verkuil 		.idProduct	= 0x2250,  /* Product ID of 2250/2251 */
6117955f03dSHans Verkuil 		.bcdDevice_lo	= 0x1,
6127955f03dSHans Verkuil 		.bcdDevice_hi	= 0x1,
6137955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250,
6147955f03dSHans Verkuil 	},
6157955f03dSHans Verkuil 	{
6167955f03dSHans Verkuil 		.match_flags	= USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
6177955f03dSHans Verkuil 		.idVendor	= 0x06e1,  /* Vendor ID of ADS Technologies */
6187955f03dSHans Verkuil 		.idProduct	= 0x0709,  /* Product ID of DVD Xpress DX2 */
6197955f03dSHans Verkuil 		.bcdDevice_lo	= 0x204,
6207955f03dSHans Verkuil 		.bcdDevice_hi	= 0x204,
6217955f03dSHans Verkuil 		.driver_info	= (kernel_ulong_t)GO7007_BOARDID_ADS_USBAV_709,
6227955f03dSHans Verkuil 	},
6237955f03dSHans Verkuil 	{ }					/* Terminating entry */
6247955f03dSHans Verkuil };
6257955f03dSHans Verkuil 
6267955f03dSHans Verkuil MODULE_DEVICE_TABLE(usb, go7007_usb_id_table);
6277955f03dSHans Verkuil 
6287955f03dSHans Verkuil /********************* Driver for EZ-USB HPI interface *********************/
6297955f03dSHans Verkuil 
6307955f03dSHans Verkuil static int go7007_usb_vendor_request(struct go7007 *go, int request,
6317955f03dSHans Verkuil 		int value, int index, void *transfer_buffer, int length, int in)
6327955f03dSHans Verkuil {
6337955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
6347955f03dSHans Verkuil 	int timeout = 5000;
6357955f03dSHans Verkuil 
6367955f03dSHans Verkuil 	if (in) {
6377955f03dSHans Verkuil 		return usb_control_msg(usb->usbdev,
6387955f03dSHans Verkuil 				usb_rcvctrlpipe(usb->usbdev, 0), request,
6397955f03dSHans Verkuil 				USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
6407955f03dSHans Verkuil 				value, index, transfer_buffer, length, timeout);
6417955f03dSHans Verkuil 	} else {
6427955f03dSHans Verkuil 		return usb_control_msg(usb->usbdev,
6437955f03dSHans Verkuil 				usb_sndctrlpipe(usb->usbdev, 0), request,
6447955f03dSHans Verkuil 				USB_TYPE_VENDOR | USB_RECIP_DEVICE,
6457955f03dSHans Verkuil 				value, index, transfer_buffer, length, timeout);
6467955f03dSHans Verkuil 	}
6477955f03dSHans Verkuil }
6487955f03dSHans Verkuil 
6497955f03dSHans Verkuil static int go7007_usb_interface_reset(struct go7007 *go)
6507955f03dSHans Verkuil {
6517955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
6527955f03dSHans Verkuil 	u16 intr_val, intr_data;
6537955f03dSHans Verkuil 
6547955f03dSHans Verkuil 	if (go->status == STATUS_SHUTDOWN)
6557955f03dSHans Verkuil 		return -1;
6567955f03dSHans Verkuil 	/* Reset encoder */
6577955f03dSHans Verkuil 	if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
6587955f03dSHans Verkuil 		return -1;
6597955f03dSHans Verkuil 	msleep(100);
6607955f03dSHans Verkuil 
6617955f03dSHans Verkuil 	if (usb->board->flags & GO7007_USB_EZUSB) {
6627955f03dSHans Verkuil 		/* Reset buffer in EZ-USB */
6637955f03dSHans Verkuil 		pr_debug("resetting EZ-USB buffers\n");
6647955f03dSHans Verkuil 		if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 ||
6657955f03dSHans Verkuil 		    go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0)
6667955f03dSHans Verkuil 			return -1;
6677955f03dSHans Verkuil 
6687955f03dSHans Verkuil 		/* Reset encoder again */
6697955f03dSHans Verkuil 		if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
6707955f03dSHans Verkuil 			return -1;
6717955f03dSHans Verkuil 		msleep(100);
6727955f03dSHans Verkuil 	}
6737955f03dSHans Verkuil 
6747955f03dSHans Verkuil 	/* Wait for an interrupt to indicate successful hardware reset */
6757955f03dSHans Verkuil 	if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
6767955f03dSHans Verkuil 			(intr_val & ~0x1) != 0x55aa) {
6777955f03dSHans Verkuil 		dev_err(go->dev, "unable to reset the USB interface\n");
6787955f03dSHans Verkuil 		return -1;
6797955f03dSHans Verkuil 	}
6807955f03dSHans Verkuil 	return 0;
6817955f03dSHans Verkuil }
6827955f03dSHans Verkuil 
6837955f03dSHans Verkuil static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
6847955f03dSHans Verkuil 						int addr, int data)
6857955f03dSHans Verkuil {
6867955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
6877955f03dSHans Verkuil 	int i, r;
6887955f03dSHans Verkuil 	u16 status_reg = 0;
6897955f03dSHans Verkuil 	int timeout = 500;
6907955f03dSHans Verkuil 
6917955f03dSHans Verkuil 	pr_debug("WriteInterrupt: %04x %04x\n", addr, data);
6927955f03dSHans Verkuil 
6937955f03dSHans Verkuil 	for (i = 0; i < 100; ++i) {
6947955f03dSHans Verkuil 		r = usb_control_msg(usb->usbdev,
6957955f03dSHans Verkuil 				usb_rcvctrlpipe(usb->usbdev, 0), 0x14,
6967955f03dSHans Verkuil 				USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
6977955f03dSHans Verkuil 				0, HPI_STATUS_ADDR, go->usb_buf,
6987955f03dSHans Verkuil 				sizeof(status_reg), timeout);
6997955f03dSHans Verkuil 		if (r < 0)
7007955f03dSHans Verkuil 			break;
701616e3506SHans Verkuil 		status_reg = le16_to_cpu(*((__le16 *)go->usb_buf));
7027955f03dSHans Verkuil 		if (!(status_reg & 0x0010))
7037955f03dSHans Verkuil 			break;
7047955f03dSHans Verkuil 		msleep(10);
7057955f03dSHans Verkuil 	}
7067955f03dSHans Verkuil 	if (r < 0)
7077955f03dSHans Verkuil 		goto write_int_error;
7087955f03dSHans Verkuil 	if (i == 100) {
7097955f03dSHans Verkuil 		dev_err(go->dev, "device is hung, status reg = 0x%04x\n", status_reg);
7107955f03dSHans Verkuil 		return -1;
7117955f03dSHans Verkuil 	}
7127955f03dSHans Verkuil 	r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12,
7137955f03dSHans Verkuil 			USB_TYPE_VENDOR | USB_RECIP_DEVICE, data,
7147955f03dSHans Verkuil 			INT_PARAM_ADDR, NULL, 0, timeout);
7157955f03dSHans Verkuil 	if (r < 0)
7167955f03dSHans Verkuil 		goto write_int_error;
7177955f03dSHans Verkuil 	r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0),
7187955f03dSHans Verkuil 			0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr,
7197955f03dSHans Verkuil 			INT_INDEX_ADDR, NULL, 0, timeout);
7207955f03dSHans Verkuil 	if (r < 0)
7217955f03dSHans Verkuil 		goto write_int_error;
7227955f03dSHans Verkuil 	return 0;
7237955f03dSHans Verkuil 
7247955f03dSHans Verkuil write_int_error:
7257955f03dSHans Verkuil 	dev_err(go->dev, "error in WriteInterrupt: %d\n", r);
7267955f03dSHans Verkuil 	return r;
7277955f03dSHans Verkuil }
7287955f03dSHans Verkuil 
7297955f03dSHans Verkuil static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
7307955f03dSHans Verkuil 						int addr, int data)
7317955f03dSHans Verkuil {
7327955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
7337955f03dSHans Verkuil 	int r;
7347955f03dSHans Verkuil 	int timeout = 500;
7357955f03dSHans Verkuil 
7367955f03dSHans Verkuil 	pr_debug("WriteInterrupt: %04x %04x\n", addr, data);
7377955f03dSHans Verkuil 
7387955f03dSHans Verkuil 	go->usb_buf[0] = data & 0xff;
7397955f03dSHans Verkuil 	go->usb_buf[1] = data >> 8;
7407955f03dSHans Verkuil 	go->usb_buf[2] = addr & 0xff;
7417955f03dSHans Verkuil 	go->usb_buf[3] = addr >> 8;
7427955f03dSHans Verkuil 	go->usb_buf[4] = go->usb_buf[5] = go->usb_buf[6] = go->usb_buf[7] = 0;
7437955f03dSHans Verkuil 	r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00,
7447955f03dSHans Verkuil 			USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa,
7457955f03dSHans Verkuil 			0xf0f0, go->usb_buf, 8, timeout);
7467955f03dSHans Verkuil 	if (r < 0) {
7477955f03dSHans Verkuil 		dev_err(go->dev, "error in WriteInterrupt: %d\n", r);
7487955f03dSHans Verkuil 		return r;
7497955f03dSHans Verkuil 	}
7507955f03dSHans Verkuil 	return 0;
7517955f03dSHans Verkuil }
7527955f03dSHans Verkuil 
7537955f03dSHans Verkuil static void go7007_usb_readinterrupt_complete(struct urb *urb)
7547955f03dSHans Verkuil {
7557955f03dSHans Verkuil 	struct go7007 *go = (struct go7007 *)urb->context;
756616e3506SHans Verkuil 	__le16 *regs = (__le16 *)urb->transfer_buffer;
7577955f03dSHans Verkuil 	int status = urb->status;
7587955f03dSHans Verkuil 
7597955f03dSHans Verkuil 	if (status) {
7607955f03dSHans Verkuil 		if (status != -ESHUTDOWN &&
7617955f03dSHans Verkuil 				go->status != STATUS_SHUTDOWN) {
7627955f03dSHans Verkuil 			dev_err(go->dev, "error in read interrupt: %d\n", urb->status);
7637955f03dSHans Verkuil 		} else {
7647955f03dSHans Verkuil 			wake_up(&go->interrupt_waitq);
7657955f03dSHans Verkuil 			return;
7667955f03dSHans Verkuil 		}
7677955f03dSHans Verkuil 	} else if (urb->actual_length != urb->transfer_buffer_length) {
7687955f03dSHans Verkuil 		dev_err(go->dev, "short read in interrupt pipe!\n");
7697955f03dSHans Verkuil 	} else {
7707955f03dSHans Verkuil 		go->interrupt_available = 1;
7717955f03dSHans Verkuil 		go->interrupt_data = __le16_to_cpu(regs[0]);
7727955f03dSHans Verkuil 		go->interrupt_value = __le16_to_cpu(regs[1]);
7737955f03dSHans Verkuil 		pr_debug("ReadInterrupt: %04x %04x\n",
7747955f03dSHans Verkuil 				go->interrupt_value, go->interrupt_data);
7757955f03dSHans Verkuil 	}
7767955f03dSHans Verkuil 
7777955f03dSHans Verkuil 	wake_up(&go->interrupt_waitq);
7787955f03dSHans Verkuil }
7797955f03dSHans Verkuil 
7807955f03dSHans Verkuil static int go7007_usb_read_interrupt(struct go7007 *go)
7817955f03dSHans Verkuil {
7827955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
7837955f03dSHans Verkuil 	int r;
7847955f03dSHans Verkuil 
7857955f03dSHans Verkuil 	r = usb_submit_urb(usb->intr_urb, GFP_KERNEL);
7867955f03dSHans Verkuil 	if (r < 0) {
7877955f03dSHans Verkuil 		dev_err(go->dev, "unable to submit interrupt urb: %d\n", r);
7887955f03dSHans Verkuil 		return r;
7897955f03dSHans Verkuil 	}
7907955f03dSHans Verkuil 	return 0;
7917955f03dSHans Verkuil }
7927955f03dSHans Verkuil 
7937955f03dSHans Verkuil static void go7007_usb_read_video_pipe_complete(struct urb *urb)
7947955f03dSHans Verkuil {
7957955f03dSHans Verkuil 	struct go7007 *go = (struct go7007 *)urb->context;
7967955f03dSHans Verkuil 	int r, status = urb->status;
7977955f03dSHans Verkuil 
7987955f03dSHans Verkuil 	if (!vb2_is_streaming(&go->vidq)) {
7997955f03dSHans Verkuil 		wake_up_interruptible(&go->frame_waitq);
8007955f03dSHans Verkuil 		return;
8017955f03dSHans Verkuil 	}
8027955f03dSHans Verkuil 	if (status) {
8037955f03dSHans Verkuil 		dev_err(go->dev, "error in video pipe: %d\n", status);
8047955f03dSHans Verkuil 		return;
8057955f03dSHans Verkuil 	}
8067955f03dSHans Verkuil 	if (urb->actual_length != urb->transfer_buffer_length) {
8077955f03dSHans Verkuil 		dev_err(go->dev, "short read in video pipe!\n");
8087955f03dSHans Verkuil 		return;
8097955f03dSHans Verkuil 	}
8107955f03dSHans Verkuil 	go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length);
8117955f03dSHans Verkuil 	r = usb_submit_urb(urb, GFP_ATOMIC);
8127955f03dSHans Verkuil 	if (r < 0)
8137955f03dSHans Verkuil 		dev_err(go->dev, "error in video pipe: %d\n", r);
8147955f03dSHans Verkuil }
8157955f03dSHans Verkuil 
8167955f03dSHans Verkuil static void go7007_usb_read_audio_pipe_complete(struct urb *urb)
8177955f03dSHans Verkuil {
8187955f03dSHans Verkuil 	struct go7007 *go = (struct go7007 *)urb->context;
8197955f03dSHans Verkuil 	int r, status = urb->status;
8207955f03dSHans Verkuil 
8217955f03dSHans Verkuil 	if (!vb2_is_streaming(&go->vidq))
8227955f03dSHans Verkuil 		return;
8237955f03dSHans Verkuil 	if (status) {
8247955f03dSHans Verkuil 		dev_err(go->dev, "error in audio pipe: %d\n",
8257955f03dSHans Verkuil 			status);
8267955f03dSHans Verkuil 		return;
8277955f03dSHans Verkuil 	}
8287955f03dSHans Verkuil 	if (urb->actual_length != urb->transfer_buffer_length) {
8297955f03dSHans Verkuil 		dev_err(go->dev, "short read in audio pipe!\n");
8307955f03dSHans Verkuil 		return;
8317955f03dSHans Verkuil 	}
8327955f03dSHans Verkuil 	if (go->audio_deliver != NULL)
8337955f03dSHans Verkuil 		go->audio_deliver(go, urb->transfer_buffer, urb->actual_length);
8347955f03dSHans Verkuil 	r = usb_submit_urb(urb, GFP_ATOMIC);
8357955f03dSHans Verkuil 	if (r < 0)
8367955f03dSHans Verkuil 		dev_err(go->dev, "error in audio pipe: %d\n", r);
8377955f03dSHans Verkuil }
8387955f03dSHans Verkuil 
8397955f03dSHans Verkuil static int go7007_usb_stream_start(struct go7007 *go)
8407955f03dSHans Verkuil {
8417955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
8427955f03dSHans Verkuil 	int i, r;
8437955f03dSHans Verkuil 
8447955f03dSHans Verkuil 	for (i = 0; i < 8; ++i) {
8457955f03dSHans Verkuil 		r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL);
8467955f03dSHans Verkuil 		if (r < 0) {
8477955f03dSHans Verkuil 			dev_err(go->dev, "error submitting video urb %d: %d\n", i, r);
8487955f03dSHans Verkuil 			goto video_submit_failed;
8497955f03dSHans Verkuil 		}
8507955f03dSHans Verkuil 	}
8517955f03dSHans Verkuil 	if (!go->audio_enabled)
8527955f03dSHans Verkuil 		return 0;
8537955f03dSHans Verkuil 
8547955f03dSHans Verkuil 	for (i = 0; i < 8; ++i) {
8557955f03dSHans Verkuil 		r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL);
8567955f03dSHans Verkuil 		if (r < 0) {
8577955f03dSHans Verkuil 			dev_err(go->dev, "error submitting audio urb %d: %d\n", i, r);
8587955f03dSHans Verkuil 			goto audio_submit_failed;
8597955f03dSHans Verkuil 		}
8607955f03dSHans Verkuil 	}
8617955f03dSHans Verkuil 	return 0;
8627955f03dSHans Verkuil 
8637955f03dSHans Verkuil audio_submit_failed:
8647955f03dSHans Verkuil 	for (i = 0; i < 7; ++i)
8657955f03dSHans Verkuil 		usb_kill_urb(usb->audio_urbs[i]);
8667955f03dSHans Verkuil video_submit_failed:
8677955f03dSHans Verkuil 	for (i = 0; i < 8; ++i)
8687955f03dSHans Verkuil 		usb_kill_urb(usb->video_urbs[i]);
8697955f03dSHans Verkuil 	return -1;
8707955f03dSHans Verkuil }
8717955f03dSHans Verkuil 
8727955f03dSHans Verkuil static int go7007_usb_stream_stop(struct go7007 *go)
8737955f03dSHans Verkuil {
8747955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
8757955f03dSHans Verkuil 	int i;
8767955f03dSHans Verkuil 
8777955f03dSHans Verkuil 	if (go->status == STATUS_SHUTDOWN)
8787955f03dSHans Verkuil 		return 0;
8797955f03dSHans Verkuil 	for (i = 0; i < 8; ++i)
8807955f03dSHans Verkuil 		usb_kill_urb(usb->video_urbs[i]);
8817955f03dSHans Verkuil 	if (go->audio_enabled)
8827955f03dSHans Verkuil 		for (i = 0; i < 8; ++i)
8837955f03dSHans Verkuil 			usb_kill_urb(usb->audio_urbs[i]);
8847955f03dSHans Verkuil 	return 0;
8857955f03dSHans Verkuil }
8867955f03dSHans Verkuil 
8877955f03dSHans Verkuil static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)
8887955f03dSHans Verkuil {
8897955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
8907955f03dSHans Verkuil 	int transferred, pipe;
8917955f03dSHans Verkuil 	int timeout = 500;
8927955f03dSHans Verkuil 
8937955f03dSHans Verkuil 	pr_debug("DownloadBuffer sending %d bytes\n", len);
8947955f03dSHans Verkuil 
8957955f03dSHans Verkuil 	if (usb->board->flags & GO7007_USB_EZUSB)
8967955f03dSHans Verkuil 		pipe = usb_sndbulkpipe(usb->usbdev, 2);
8977955f03dSHans Verkuil 	else
8987955f03dSHans Verkuil 		pipe = usb_sndbulkpipe(usb->usbdev, 3);
8997955f03dSHans Verkuil 
9007955f03dSHans Verkuil 	return usb_bulk_msg(usb->usbdev, pipe, data, len,
9017955f03dSHans Verkuil 					&transferred, timeout);
9027955f03dSHans Verkuil }
9037955f03dSHans Verkuil 
9047955f03dSHans Verkuil static void go7007_usb_release(struct go7007 *go)
9057955f03dSHans Verkuil {
9067955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
9077955f03dSHans Verkuil 	struct urb *vurb, *aurb;
9087955f03dSHans Verkuil 	int i;
9097955f03dSHans Verkuil 
9107955f03dSHans Verkuil 	if (usb->intr_urb) {
9117955f03dSHans Verkuil 		usb_kill_urb(usb->intr_urb);
9127955f03dSHans Verkuil 		kfree(usb->intr_urb->transfer_buffer);
9137955f03dSHans Verkuil 		usb_free_urb(usb->intr_urb);
9147955f03dSHans Verkuil 	}
9157955f03dSHans Verkuil 
9167955f03dSHans Verkuil 	/* Free USB-related structs */
9177955f03dSHans Verkuil 	for (i = 0; i < 8; ++i) {
9187955f03dSHans Verkuil 		vurb = usb->video_urbs[i];
9197955f03dSHans Verkuil 		if (vurb) {
9207955f03dSHans Verkuil 			usb_kill_urb(vurb);
9217955f03dSHans Verkuil 			kfree(vurb->transfer_buffer);
9227955f03dSHans Verkuil 			usb_free_urb(vurb);
9237955f03dSHans Verkuil 		}
9247955f03dSHans Verkuil 		aurb = usb->audio_urbs[i];
9257955f03dSHans Verkuil 		if (aurb) {
9267955f03dSHans Verkuil 			usb_kill_urb(aurb);
9277955f03dSHans Verkuil 			kfree(aurb->transfer_buffer);
9287955f03dSHans Verkuil 			usb_free_urb(aurb);
9297955f03dSHans Verkuil 		}
9307955f03dSHans Verkuil 	}
9317955f03dSHans Verkuil 
9327955f03dSHans Verkuil 	kfree(go->hpi_context);
9337955f03dSHans Verkuil }
9347955f03dSHans Verkuil 
9357955f03dSHans Verkuil static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
9367955f03dSHans Verkuil 	.interface_reset	= go7007_usb_interface_reset,
9377955f03dSHans Verkuil 	.write_interrupt	= go7007_usb_ezusb_write_interrupt,
9387955f03dSHans Verkuil 	.read_interrupt		= go7007_usb_read_interrupt,
9397955f03dSHans Verkuil 	.stream_start		= go7007_usb_stream_start,
9407955f03dSHans Verkuil 	.stream_stop		= go7007_usb_stream_stop,
9417955f03dSHans Verkuil 	.send_firmware		= go7007_usb_send_firmware,
9427955f03dSHans Verkuil 	.release		= go7007_usb_release,
9437955f03dSHans Verkuil };
9447955f03dSHans Verkuil 
9457955f03dSHans Verkuil static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
9467955f03dSHans Verkuil 	.interface_reset	= go7007_usb_interface_reset,
9477955f03dSHans Verkuil 	.write_interrupt	= go7007_usb_onboard_write_interrupt,
9487955f03dSHans Verkuil 	.read_interrupt		= go7007_usb_read_interrupt,
9497955f03dSHans Verkuil 	.stream_start		= go7007_usb_stream_start,
9507955f03dSHans Verkuil 	.stream_stop		= go7007_usb_stream_stop,
9517955f03dSHans Verkuil 	.send_firmware		= go7007_usb_send_firmware,
9527955f03dSHans Verkuil 	.release		= go7007_usb_release,
9537955f03dSHans Verkuil };
9547955f03dSHans Verkuil 
9557955f03dSHans Verkuil /********************* Driver for EZ-USB I2C adapter *********************/
9567955f03dSHans Verkuil 
9577955f03dSHans Verkuil static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,
9587955f03dSHans Verkuil 					struct i2c_msg msgs[], int num)
9597955f03dSHans Verkuil {
9607955f03dSHans Verkuil 	struct go7007 *go = i2c_get_adapdata(adapter);
9617955f03dSHans Verkuil 	struct go7007_usb *usb = go->hpi_context;
9627955f03dSHans Verkuil 	u8 *buf = go->usb_buf;
9637955f03dSHans Verkuil 	int buf_len, i;
9647955f03dSHans Verkuil 	int ret = -EIO;
9657955f03dSHans Verkuil 
9667955f03dSHans Verkuil 	if (go->status == STATUS_SHUTDOWN)
9677955f03dSHans Verkuil 		return -ENODEV;
9687955f03dSHans Verkuil 
9697955f03dSHans Verkuil 	mutex_lock(&usb->i2c_lock);
9707955f03dSHans Verkuil 
9717955f03dSHans Verkuil 	for (i = 0; i < num; ++i) {
9727955f03dSHans Verkuil 		/* The hardware command is "write some bytes then read some
9737955f03dSHans Verkuil 		 * bytes", so we try to coalesce a write followed by a read
9747955f03dSHans Verkuil 		 * into a single USB transaction */
9757955f03dSHans Verkuil 		if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr &&
9767955f03dSHans Verkuil 				!(msgs[i].flags & I2C_M_RD) &&
9777955f03dSHans Verkuil 				(msgs[i + 1].flags & I2C_M_RD)) {
9787955f03dSHans Verkuil #ifdef GO7007_I2C_DEBUG
9797955f03dSHans Verkuil 			pr_debug("i2c write/read %d/%d bytes on %02x\n",
9807955f03dSHans Verkuil 				msgs[i].len, msgs[i + 1].len, msgs[i].addr);
9817955f03dSHans Verkuil #endif
9827955f03dSHans Verkuil 			buf[0] = 0x01;
9837955f03dSHans Verkuil 			buf[1] = msgs[i].len + 1;
9847955f03dSHans Verkuil 			buf[2] = msgs[i].addr << 1;
9857955f03dSHans Verkuil 			memcpy(&buf[3], msgs[i].buf, msgs[i].len);
9867955f03dSHans Verkuil 			buf_len = msgs[i].len + 3;
9877955f03dSHans Verkuil 			buf[buf_len++] = msgs[++i].len;
9887955f03dSHans Verkuil 		} else if (msgs[i].flags & I2C_M_RD) {
9897955f03dSHans Verkuil #ifdef GO7007_I2C_DEBUG
9907955f03dSHans Verkuil 			pr_debug("i2c read %d bytes on %02x\n",
9917955f03dSHans Verkuil 					msgs[i].len, msgs[i].addr);
9927955f03dSHans Verkuil #endif
9937955f03dSHans Verkuil 			buf[0] = 0x01;
9947955f03dSHans Verkuil 			buf[1] = 1;
9957955f03dSHans Verkuil 			buf[2] = msgs[i].addr << 1;
9967955f03dSHans Verkuil 			buf[3] = msgs[i].len;
9977955f03dSHans Verkuil 			buf_len = 4;
9987955f03dSHans Verkuil 		} else {
9997955f03dSHans Verkuil #ifdef GO7007_I2C_DEBUG
10007955f03dSHans Verkuil 			pr_debug("i2c write %d bytes on %02x\n",
10017955f03dSHans Verkuil 					msgs[i].len, msgs[i].addr);
10027955f03dSHans Verkuil #endif
10037955f03dSHans Verkuil 			buf[0] = 0x00;
10047955f03dSHans Verkuil 			buf[1] = msgs[i].len + 1;
10057955f03dSHans Verkuil 			buf[2] = msgs[i].addr << 1;
10067955f03dSHans Verkuil 			memcpy(&buf[3], msgs[i].buf, msgs[i].len);
10077955f03dSHans Verkuil 			buf_len = msgs[i].len + 3;
10087955f03dSHans Verkuil 			buf[buf_len++] = 0;
10097955f03dSHans Verkuil 		}
10107955f03dSHans Verkuil 		if (go7007_usb_vendor_request(go, 0x24, 0, 0,
10117955f03dSHans Verkuil 						buf, buf_len, 0) < 0)
10127955f03dSHans Verkuil 			goto i2c_done;
10137955f03dSHans Verkuil 		if (msgs[i].flags & I2C_M_RD) {
10147955f03dSHans Verkuil 			memset(buf, 0, msgs[i].len + 1);
10157955f03dSHans Verkuil 			if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,
10167955f03dSHans Verkuil 						msgs[i].len + 1, 1) < 0)
10177955f03dSHans Verkuil 				goto i2c_done;
10187955f03dSHans Verkuil 			memcpy(msgs[i].buf, buf + 1, msgs[i].len);
10197955f03dSHans Verkuil 		}
10207955f03dSHans Verkuil 	}
10217955f03dSHans Verkuil 	ret = num;
10227955f03dSHans Verkuil 
10237955f03dSHans Verkuil i2c_done:
10247955f03dSHans Verkuil 	mutex_unlock(&usb->i2c_lock);
10257955f03dSHans Verkuil 	return ret;
10267955f03dSHans Verkuil }
10277955f03dSHans Verkuil 
10287955f03dSHans Verkuil static u32 go7007_usb_functionality(struct i2c_adapter *adapter)
10297955f03dSHans Verkuil {
10307955f03dSHans Verkuil 	/* No errors are reported by the hardware, so we don't bother
10317955f03dSHans Verkuil 	 * supporting quick writes to avoid confusing probing */
10327955f03dSHans Verkuil 	return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK;
10337955f03dSHans Verkuil }
10347955f03dSHans Verkuil 
10357955f03dSHans Verkuil static struct i2c_algorithm go7007_usb_algo = {
10367955f03dSHans Verkuil 	.master_xfer	= go7007_usb_i2c_master_xfer,
10377955f03dSHans Verkuil 	.functionality	= go7007_usb_functionality,
10387955f03dSHans Verkuil };
10397955f03dSHans Verkuil 
10407955f03dSHans Verkuil static struct i2c_adapter go7007_usb_adap_templ = {
10417955f03dSHans Verkuil 	.owner			= THIS_MODULE,
10427955f03dSHans Verkuil 	.name			= "WIS GO7007SB EZ-USB",
10437955f03dSHans Verkuil 	.algo			= &go7007_usb_algo,
10447955f03dSHans Verkuil };
10457955f03dSHans Verkuil 
10467955f03dSHans Verkuil /********************* USB add/remove functions *********************/
10477955f03dSHans Verkuil 
10487955f03dSHans Verkuil static int go7007_usb_probe(struct usb_interface *intf,
10497955f03dSHans Verkuil 		const struct usb_device_id *id)
10507955f03dSHans Verkuil {
10517955f03dSHans Verkuil 	struct go7007 *go;
10527955f03dSHans Verkuil 	struct go7007_usb *usb;
10537955f03dSHans Verkuil 	const struct go7007_usb_board *board;
10547955f03dSHans Verkuil 	struct usb_device *usbdev = interface_to_usbdev(intf);
10557955f03dSHans Verkuil 	unsigned num_i2c_devs;
10567955f03dSHans Verkuil 	char *name;
10577955f03dSHans Verkuil 	int video_pipe, i, v_urb_len;
10587955f03dSHans Verkuil 
10597955f03dSHans Verkuil 	pr_debug("probing new GO7007 USB board\n");
10607955f03dSHans Verkuil 
10617955f03dSHans Verkuil 	switch (id->driver_info) {
10627955f03dSHans Verkuil 	case GO7007_BOARDID_MATRIX_II:
10637955f03dSHans Verkuil 		name = "WIS Matrix II or compatible";
10647955f03dSHans Verkuil 		board = &board_matrix_ii;
10657955f03dSHans Verkuil 		break;
10667955f03dSHans Verkuil 	case GO7007_BOARDID_MATRIX_RELOAD:
10677955f03dSHans Verkuil 		name = "WIS Matrix Reloaded or compatible";
10687955f03dSHans Verkuil 		board = &board_matrix_reload;
10697955f03dSHans Verkuil 		break;
10707955f03dSHans Verkuil 	case GO7007_BOARDID_MATRIX_REV:
10717955f03dSHans Verkuil 		name = "WIS Matrix Revolution or compatible";
10727955f03dSHans Verkuil 		board = &board_matrix_revolution;
10737955f03dSHans Verkuil 		break;
10747955f03dSHans Verkuil 	case GO7007_BOARDID_STAR_TREK:
10757955f03dSHans Verkuil 		name = "WIS Star Trek or compatible";
10767955f03dSHans Verkuil 		board = &board_star_trek;
10777955f03dSHans Verkuil 		break;
10787955f03dSHans Verkuil 	case GO7007_BOARDID_XMEN:
10797955f03dSHans Verkuil 		name = "WIS XMen or compatible";
10807955f03dSHans Verkuil 		board = &board_xmen;
10817955f03dSHans Verkuil 		break;
10827955f03dSHans Verkuil 	case GO7007_BOARDID_XMEN_II:
10837955f03dSHans Verkuil 		name = "WIS XMen II or compatible";
10847955f03dSHans Verkuil 		board = &board_xmen;
10857955f03dSHans Verkuil 		break;
10867955f03dSHans Verkuil 	case GO7007_BOARDID_XMEN_III:
10877955f03dSHans Verkuil 		name = "WIS XMen III or compatible";
10887955f03dSHans Verkuil 		board = &board_xmen;
10897955f03dSHans Verkuil 		break;
10907955f03dSHans Verkuil 	case GO7007_BOARDID_PX_M402U:
10917955f03dSHans Verkuil 		name = "Plextor PX-M402U";
10927955f03dSHans Verkuil 		board = &board_matrix_ii;
10937955f03dSHans Verkuil 		break;
10947955f03dSHans Verkuil 	case GO7007_BOARDID_PX_TV402U:
10957955f03dSHans Verkuil 		name = "Plextor PX-TV402U (unknown tuner)";
10967955f03dSHans Verkuil 		board = &board_px_tv402u;
10977955f03dSHans Verkuil 		break;
10987955f03dSHans Verkuil 	case GO7007_BOARDID_LIFEVIEW_LR192:
10997955f03dSHans Verkuil 		dev_err(&intf->dev, "The Lifeview TV Walker Ultra is not supported. Sorry!\n");
11007955f03dSHans Verkuil 		return -ENODEV;
11016629e4deSMauro Carvalho Chehab #if 0
11027955f03dSHans Verkuil 		name = "Lifeview TV Walker Ultra";
11037955f03dSHans Verkuil 		board = &board_lifeview_lr192;
11046629e4deSMauro Carvalho Chehab #endif
11057955f03dSHans Verkuil 		break;
11067955f03dSHans Verkuil 	case GO7007_BOARDID_SENSORAY_2250:
11077955f03dSHans Verkuil 		dev_info(&intf->dev, "Sensoray 2250 found\n");
11087955f03dSHans Verkuil 		name = "Sensoray 2250/2251";
11097955f03dSHans Verkuil 		board = &board_sensoray_2250;
11107955f03dSHans Verkuil 		break;
11117955f03dSHans Verkuil 	case GO7007_BOARDID_ADS_USBAV_709:
11127955f03dSHans Verkuil 		name = "ADS Tech DVD Xpress DX2";
11137955f03dSHans Verkuil 		board = &board_ads_usbav_709;
11147955f03dSHans Verkuil 		break;
11157955f03dSHans Verkuil 	default:
11167955f03dSHans Verkuil 		dev_err(&intf->dev, "unknown board ID %d!\n",
11177955f03dSHans Verkuil 				(unsigned int)id->driver_info);
11187955f03dSHans Verkuil 		return -ENODEV;
11197955f03dSHans Verkuil 	}
11207955f03dSHans Verkuil 
11217955f03dSHans Verkuil 	go = go7007_alloc(&board->main_info, &intf->dev);
11227955f03dSHans Verkuil 	if (go == NULL)
11237955f03dSHans Verkuil 		return -ENOMEM;
11247955f03dSHans Verkuil 
11257955f03dSHans Verkuil 	usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL);
11267955f03dSHans Verkuil 	if (usb == NULL) {
11277955f03dSHans Verkuil 		kfree(go);
11287955f03dSHans Verkuil 		return -ENOMEM;
11297955f03dSHans Verkuil 	}
11307955f03dSHans Verkuil 
11317955f03dSHans Verkuil 	usb->board = board;
11327955f03dSHans Verkuil 	usb->usbdev = usbdev;
11337955f03dSHans Verkuil 	usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info));
11347955f03dSHans Verkuil 	go->board_id = id->driver_info;
11357955f03dSHans Verkuil 	strncpy(go->name, name, sizeof(go->name));
11367955f03dSHans Verkuil 	if (board->flags & GO7007_USB_EZUSB)
11377955f03dSHans Verkuil 		go->hpi_ops = &go7007_usb_ezusb_hpi_ops;
11387955f03dSHans Verkuil 	else
11397955f03dSHans Verkuil 		go->hpi_ops = &go7007_usb_onboard_hpi_ops;
11407955f03dSHans Verkuil 	go->hpi_context = usb;
11417955f03dSHans Verkuil 
11427955f03dSHans Verkuil 	/* Allocate the URB and buffer for receiving incoming interrupts */
11437955f03dSHans Verkuil 	usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
11447955f03dSHans Verkuil 	if (usb->intr_urb == NULL)
11457955f03dSHans Verkuil 		goto allocfail;
11467955f03dSHans Verkuil 	usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL);
11477955f03dSHans Verkuil 	if (usb->intr_urb->transfer_buffer == NULL)
11487955f03dSHans Verkuil 		goto allocfail;
11497955f03dSHans Verkuil 
11507955f03dSHans Verkuil 	if (go->board_id == GO7007_BOARDID_SENSORAY_2250)
11517955f03dSHans Verkuil 		usb_fill_bulk_urb(usb->intr_urb, usb->usbdev,
11527955f03dSHans Verkuil 			usb_rcvbulkpipe(usb->usbdev, 4),
11537955f03dSHans Verkuil 			usb->intr_urb->transfer_buffer, 2*sizeof(u16),
11547955f03dSHans Verkuil 			go7007_usb_readinterrupt_complete, go);
11557955f03dSHans Verkuil 	else
11567955f03dSHans Verkuil 		usb_fill_int_urb(usb->intr_urb, usb->usbdev,
11577955f03dSHans Verkuil 			usb_rcvintpipe(usb->usbdev, 4),
11587955f03dSHans Verkuil 			usb->intr_urb->transfer_buffer, 2*sizeof(u16),
11597955f03dSHans Verkuil 			go7007_usb_readinterrupt_complete, go, 8);
11607955f03dSHans Verkuil 	usb_set_intfdata(intf, &go->v4l2_dev);
11617955f03dSHans Verkuil 
11627955f03dSHans Verkuil 	/* Boot the GO7007 */
11637955f03dSHans Verkuil 	if (go7007_boot_encoder(go, go->board_info->flags &
11647955f03dSHans Verkuil 					GO7007_BOARD_USE_ONBOARD_I2C) < 0)
11657955f03dSHans Verkuil 		goto allocfail;
11667955f03dSHans Verkuil 
11677955f03dSHans Verkuil 	/* Register the EZ-USB I2C adapter, if we're using it */
11687955f03dSHans Verkuil 	if (board->flags & GO7007_USB_EZUSB_I2C) {
11697955f03dSHans Verkuil 		memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
11707955f03dSHans Verkuil 				sizeof(go7007_usb_adap_templ));
11717955f03dSHans Verkuil 		mutex_init(&usb->i2c_lock);
11727955f03dSHans Verkuil 		go->i2c_adapter.dev.parent = go->dev;
11737955f03dSHans Verkuil 		i2c_set_adapdata(&go->i2c_adapter, go);
11747955f03dSHans Verkuil 		if (i2c_add_adapter(&go->i2c_adapter) < 0) {
11757955f03dSHans Verkuil 			dev_err(go->dev, "error: i2c_add_adapter failed\n");
11767955f03dSHans Verkuil 			goto allocfail;
11777955f03dSHans Verkuil 		}
11787955f03dSHans Verkuil 		go->i2c_adapter_online = 1;
11797955f03dSHans Verkuil 	}
11807955f03dSHans Verkuil 
11817955f03dSHans Verkuil 	/* Pelco and Adlink reused the XMen and XMen-III vendor and product
11827955f03dSHans Verkuil 	 * IDs for their own incompatible designs.  We can detect XMen boards
11837955f03dSHans Verkuil 	 * by probing the sensor, but there is no way to probe the sensors on
11847955f03dSHans Verkuil 	 * the Pelco and Adlink designs so we default to the Adlink.  If it
11857955f03dSHans Verkuil 	 * is actually a Pelco, the user must set the assume_endura module
11867955f03dSHans Verkuil 	 * parameter. */
11877955f03dSHans Verkuil 	if ((go->board_id == GO7007_BOARDID_XMEN ||
11887955f03dSHans Verkuil 				go->board_id == GO7007_BOARDID_XMEN_III) &&
11897955f03dSHans Verkuil 			go->i2c_adapter_online) {
11907955f03dSHans Verkuil 		union i2c_smbus_data data;
11917955f03dSHans Verkuil 
11927955f03dSHans Verkuil 		/* Check to see if register 0x0A is 0x76 */
11937955f03dSHans Verkuil 		i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
11947955f03dSHans Verkuil 			I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
11957955f03dSHans Verkuil 		if (data.byte != 0x76) {
11967955f03dSHans Verkuil 			if (assume_endura) {
11977955f03dSHans Verkuil 				go->board_id = GO7007_BOARDID_ENDURA;
11987955f03dSHans Verkuil 				usb->board = board = &board_endura;
11997955f03dSHans Verkuil 				go->board_info = &board->main_info;
12007955f03dSHans Verkuil 				strncpy(go->name, "Pelco Endura",
12017955f03dSHans Verkuil 					sizeof(go->name));
12027955f03dSHans Verkuil 			} else {
12037955f03dSHans Verkuil 				u16 channel;
12047955f03dSHans Verkuil 
12057955f03dSHans Verkuil 				/* read channel number from GPIO[1:0] */
12067955f03dSHans Verkuil 				go7007_read_addr(go, 0x3c81, &channel);
12077955f03dSHans Verkuil 				channel &= 0x3;
12087955f03dSHans Verkuil 				go->board_id = GO7007_BOARDID_ADLINK_MPG24;
12097955f03dSHans Verkuil 				usb->board = board = &board_adlink_mpg24;
12107955f03dSHans Verkuil 				go->board_info = &board->main_info;
12117955f03dSHans Verkuil 				go->channel_number = channel;
12127955f03dSHans Verkuil 				snprintf(go->name, sizeof(go->name),
12137955f03dSHans Verkuil 					"Adlink PCI-MPG24, channel #%d",
12147955f03dSHans Verkuil 					channel);
12157955f03dSHans Verkuil 			}
12167955f03dSHans Verkuil 			go7007_update_board(go);
12177955f03dSHans Verkuil 		}
12187955f03dSHans Verkuil 	}
12197955f03dSHans Verkuil 
12207955f03dSHans Verkuil 	num_i2c_devs = go->board_info->num_i2c_devs;
12217955f03dSHans Verkuil 
12227955f03dSHans Verkuil 	/* Probe the tuner model on the TV402U */
12237955f03dSHans Verkuil 	if (go->board_id == GO7007_BOARDID_PX_TV402U) {
12247955f03dSHans Verkuil 		/* Board strapping indicates tuner model */
12257955f03dSHans Verkuil 		if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3,
12267955f03dSHans Verkuil 					1) < 0) {
12277955f03dSHans Verkuil 			dev_err(go->dev, "GPIO read failed!\n");
12287955f03dSHans Verkuil 			goto allocfail;
12297955f03dSHans Verkuil 		}
12307955f03dSHans Verkuil 		switch (go->usb_buf[0] >> 6) {
12317955f03dSHans Verkuil 		case 1:
12327955f03dSHans Verkuil 			go->tuner_type = TUNER_SONY_BTF_PG472Z;
12337955f03dSHans Verkuil 			go->std = V4L2_STD_PAL;
12347955f03dSHans Verkuil 			strncpy(go->name, "Plextor PX-TV402U-EU",
12357955f03dSHans Verkuil 					sizeof(go->name));
12367955f03dSHans Verkuil 			break;
12377955f03dSHans Verkuil 		case 2:
12387955f03dSHans Verkuil 			go->tuner_type = TUNER_SONY_BTF_PK467Z;
12397955f03dSHans Verkuil 			go->std = V4L2_STD_NTSC_M_JP;
12407955f03dSHans Verkuil 			num_i2c_devs -= 2;
12417955f03dSHans Verkuil 			strncpy(go->name, "Plextor PX-TV402U-JP",
12427955f03dSHans Verkuil 					sizeof(go->name));
12437955f03dSHans Verkuil 			break;
12447955f03dSHans Verkuil 		case 3:
12457955f03dSHans Verkuil 			go->tuner_type = TUNER_SONY_BTF_PB463Z;
12467955f03dSHans Verkuil 			num_i2c_devs -= 2;
12477955f03dSHans Verkuil 			strncpy(go->name, "Plextor PX-TV402U-NA",
12487955f03dSHans Verkuil 					sizeof(go->name));
12497955f03dSHans Verkuil 			break;
12507955f03dSHans Verkuil 		default:
12517955f03dSHans Verkuil 			pr_debug("unable to detect tuner type!\n");
12527955f03dSHans Verkuil 			break;
12537955f03dSHans Verkuil 		}
12547955f03dSHans Verkuil 		/* Configure tuner mode selection inputs connected
12557955f03dSHans Verkuil 		 * to the EZ-USB GPIO output pins */
12567955f03dSHans Verkuil 		if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
12577955f03dSHans Verkuil 					NULL, 0, 0) < 0) {
12587955f03dSHans Verkuil 			dev_err(go->dev, "GPIO write failed!\n");
12597955f03dSHans Verkuil 			goto allocfail;
12607955f03dSHans Verkuil 		}
12617955f03dSHans Verkuil 	}
12627955f03dSHans Verkuil 
12637955f03dSHans Verkuil 	/* Print a nasty message if the user attempts to use a USB2.0 device in
12647955f03dSHans Verkuil 	 * a USB1.1 port.  There will be silent corruption of the stream. */
12657955f03dSHans Verkuil 	if ((board->flags & GO7007_USB_EZUSB) &&
12667955f03dSHans Verkuil 			usbdev->speed != USB_SPEED_HIGH)
12677955f03dSHans Verkuil 		dev_err(go->dev, "*** WARNING ***  This device must be connected to a USB 2.0 port! Attempting to capture video through a USB 1.1 port will result in stream corruption, even at low bitrates!\n");
12687955f03dSHans Verkuil 
12697955f03dSHans Verkuil 	/* Allocate the URBs and buffers for receiving the video stream */
12707955f03dSHans Verkuil 	if (board->flags & GO7007_USB_EZUSB) {
12717955f03dSHans Verkuil 		v_urb_len = 1024;
12727955f03dSHans Verkuil 		video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
12737955f03dSHans Verkuil 	} else {
12747955f03dSHans Verkuil 		v_urb_len = 512;
12757955f03dSHans Verkuil 		video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
12767955f03dSHans Verkuil 	}
12777955f03dSHans Verkuil 	for (i = 0; i < 8; ++i) {
12787955f03dSHans Verkuil 		usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
12797955f03dSHans Verkuil 		if (usb->video_urbs[i] == NULL)
12807955f03dSHans Verkuil 			goto allocfail;
12817955f03dSHans Verkuil 		usb->video_urbs[i]->transfer_buffer =
12827955f03dSHans Verkuil 						kmalloc(v_urb_len, GFP_KERNEL);
12837955f03dSHans Verkuil 		if (usb->video_urbs[i]->transfer_buffer == NULL)
12847955f03dSHans Verkuil 			goto allocfail;
12857955f03dSHans Verkuil 		usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
12867955f03dSHans Verkuil 				usb->video_urbs[i]->transfer_buffer, v_urb_len,
12877955f03dSHans Verkuil 				go7007_usb_read_video_pipe_complete, go);
12887955f03dSHans Verkuil 	}
12897955f03dSHans Verkuil 
12907955f03dSHans Verkuil 	/* Allocate the URBs and buffers for receiving the audio stream */
12917955f03dSHans Verkuil 	if ((board->flags & GO7007_USB_EZUSB) &&
12927955f03dSHans Verkuil 	    (board->flags & GO7007_BOARD_HAS_AUDIO)) {
12937955f03dSHans Verkuil 		for (i = 0; i < 8; ++i) {
12947955f03dSHans Verkuil 			usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
12957955f03dSHans Verkuil 			if (usb->audio_urbs[i] == NULL)
12967955f03dSHans Verkuil 				goto allocfail;
12977955f03dSHans Verkuil 			usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
12987955f03dSHans Verkuil 								GFP_KERNEL);
12997955f03dSHans Verkuil 			if (usb->audio_urbs[i]->transfer_buffer == NULL)
13007955f03dSHans Verkuil 				goto allocfail;
13017955f03dSHans Verkuil 			usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
13027955f03dSHans Verkuil 				usb_rcvbulkpipe(usb->usbdev, 8),
13037955f03dSHans Verkuil 				usb->audio_urbs[i]->transfer_buffer, 4096,
13047955f03dSHans Verkuil 				go7007_usb_read_audio_pipe_complete, go);
13057955f03dSHans Verkuil 		}
13067955f03dSHans Verkuil 	}
13077955f03dSHans Verkuil 
13087955f03dSHans Verkuil 	/* Do any final GO7007 initialization, then register the
13097955f03dSHans Verkuil 	 * V4L2 and ALSA interfaces */
13107955f03dSHans Verkuil 	if (go7007_register_encoder(go, num_i2c_devs) < 0)
13117955f03dSHans Verkuil 		goto allocfail;
13127955f03dSHans Verkuil 
13137955f03dSHans Verkuil 	go->status = STATUS_ONLINE;
13147955f03dSHans Verkuil 	return 0;
13157955f03dSHans Verkuil 
13167955f03dSHans Verkuil allocfail:
13177955f03dSHans Verkuil 	go7007_usb_release(go);
13187955f03dSHans Verkuil 	kfree(go);
13197955f03dSHans Verkuil 	return -ENOMEM;
13207955f03dSHans Verkuil }
13217955f03dSHans Verkuil 
13227955f03dSHans Verkuil static void go7007_usb_disconnect(struct usb_interface *intf)
13237955f03dSHans Verkuil {
13247955f03dSHans Verkuil 	struct go7007 *go = to_go7007(usb_get_intfdata(intf));
13257955f03dSHans Verkuil 
13267955f03dSHans Verkuil 	mutex_lock(&go->queue_lock);
13277955f03dSHans Verkuil 	mutex_lock(&go->serialize_lock);
13287955f03dSHans Verkuil 
13297955f03dSHans Verkuil 	if (go->audio_enabled)
13307955f03dSHans Verkuil 		go7007_snd_remove(go);
13317955f03dSHans Verkuil 
13327955f03dSHans Verkuil 	go->status = STATUS_SHUTDOWN;
13337955f03dSHans Verkuil 	v4l2_device_disconnect(&go->v4l2_dev);
13347955f03dSHans Verkuil 	video_unregister_device(&go->vdev);
13357955f03dSHans Verkuil 	mutex_unlock(&go->serialize_lock);
13367955f03dSHans Verkuil 	mutex_unlock(&go->queue_lock);
13377955f03dSHans Verkuil 
13387955f03dSHans Verkuil 	v4l2_device_put(&go->v4l2_dev);
13397955f03dSHans Verkuil }
13407955f03dSHans Verkuil 
13417955f03dSHans Verkuil static struct usb_driver go7007_usb_driver = {
13427955f03dSHans Verkuil 	.name		= "go7007",
13437955f03dSHans Verkuil 	.probe		= go7007_usb_probe,
13447955f03dSHans Verkuil 	.disconnect	= go7007_usb_disconnect,
13457955f03dSHans Verkuil 	.id_table	= go7007_usb_id_table,
13467955f03dSHans Verkuil };
13477955f03dSHans Verkuil 
13487955f03dSHans Verkuil module_usb_driver(go7007_usb_driver);
13497955f03dSHans Verkuil MODULE_LICENSE("GPL v2");
1350