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