18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2005-2006 Micronas USA Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/wait.h> 118c2ecf20Sopenharmony_ci#include <linux/list.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/time.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci#include <linux/usb.h> 168c2ecf20Sopenharmony_ci#include <linux/i2c.h> 178c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 188c2ecf20Sopenharmony_ci#include <media/i2c/saa7115.h> 198c2ecf20Sopenharmony_ci#include <media/tuner.h> 208c2ecf20Sopenharmony_ci#include <media/i2c/uda1342.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "go7007-priv.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic unsigned int assume_endura; 258c2ecf20Sopenharmony_cimodule_param(assume_endura, int, 0644); 268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(assume_endura, 278c2ecf20Sopenharmony_ci "when probing fails, hardware is a Pelco Endura"); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define HPI_STATUS_ADDR 0xFFF4 328c2ecf20Sopenharmony_ci#define INT_PARAM_ADDR 0xFFF6 338c2ecf20Sopenharmony_ci#define INT_INDEX_ADDR 0xFFF8 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Pipes on EZ-USB interface: 378c2ecf20Sopenharmony_ci * 0 snd - Control 388c2ecf20Sopenharmony_ci * 0 rcv - Control 398c2ecf20Sopenharmony_ci * 2 snd - Download firmware (control) 408c2ecf20Sopenharmony_ci * 4 rcv - Read Interrupt (interrupt) 418c2ecf20Sopenharmony_ci * 6 rcv - Read Video (bulk) 428c2ecf20Sopenharmony_ci * 8 rcv - Read Audio (bulk) 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define GO7007_USB_EZUSB (1<<0) 468c2ecf20Sopenharmony_ci#define GO7007_USB_EZUSB_I2C (1<<1) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct go7007_usb_board { 498c2ecf20Sopenharmony_ci unsigned int flags; 508c2ecf20Sopenharmony_ci struct go7007_board_info main_info; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct go7007_usb { 548c2ecf20Sopenharmony_ci const struct go7007_usb_board *board; 558c2ecf20Sopenharmony_ci struct mutex i2c_lock; 568c2ecf20Sopenharmony_ci struct usb_device *usbdev; 578c2ecf20Sopenharmony_ci struct urb *video_urbs[8]; 588c2ecf20Sopenharmony_ci struct urb *audio_urbs[8]; 598c2ecf20Sopenharmony_ci struct urb *intr_urb; 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/*********************** Product specification data ***********************/ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_matrix_ii = { 658c2ecf20Sopenharmony_ci .flags = GO7007_USB_EZUSB, 668c2ecf20Sopenharmony_ci .main_info = { 678c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_HAS_AUDIO | 688c2ecf20Sopenharmony_ci GO7007_BOARD_USE_ONBOARD_I2C, 698c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 708c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 718c2ecf20Sopenharmony_ci .audio_rate = 48000, 728c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 738c2ecf20Sopenharmony_ci .audio_main_div = 2, 748c2ecf20Sopenharmony_ci .hpi_buffer_cap = 7, 758c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 768c2ecf20Sopenharmony_ci GO7007_SENSOR_VALID_ENABLE | 778c2ecf20Sopenharmony_ci GO7007_SENSOR_TV | 788c2ecf20Sopenharmony_ci GO7007_SENSOR_SAA7115 | 798c2ecf20Sopenharmony_ci GO7007_SENSOR_VBI | 808c2ecf20Sopenharmony_ci GO7007_SENSOR_SCALING, 818c2ecf20Sopenharmony_ci .num_i2c_devs = 1, 828c2ecf20Sopenharmony_ci .i2c_devs = { 838c2ecf20Sopenharmony_ci { 848c2ecf20Sopenharmony_ci .type = "saa7115", 858c2ecf20Sopenharmony_ci .addr = 0x20, 868c2ecf20Sopenharmony_ci .is_video = 1, 878c2ecf20Sopenharmony_ci }, 888c2ecf20Sopenharmony_ci }, 898c2ecf20Sopenharmony_ci .num_inputs = 2, 908c2ecf20Sopenharmony_ci .inputs = { 918c2ecf20Sopenharmony_ci { 928c2ecf20Sopenharmony_ci .video_input = 0, 938c2ecf20Sopenharmony_ci .name = "Composite", 948c2ecf20Sopenharmony_ci }, 958c2ecf20Sopenharmony_ci { 968c2ecf20Sopenharmony_ci .video_input = 9, 978c2ecf20Sopenharmony_ci .name = "S-Video", 988c2ecf20Sopenharmony_ci }, 998c2ecf20Sopenharmony_ci }, 1008c2ecf20Sopenharmony_ci .video_config = SAA7115_IDQ_IS_DEFAULT, 1018c2ecf20Sopenharmony_ci }, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_matrix_reload = { 1058c2ecf20Sopenharmony_ci .flags = GO7007_USB_EZUSB, 1068c2ecf20Sopenharmony_ci .main_info = { 1078c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_HAS_AUDIO | 1088c2ecf20Sopenharmony_ci GO7007_BOARD_USE_ONBOARD_I2C, 1098c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 1108c2ecf20Sopenharmony_ci GO7007_AUDIO_I2S_MASTER | 1118c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 1128c2ecf20Sopenharmony_ci .audio_rate = 48000, 1138c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 1148c2ecf20Sopenharmony_ci .audio_main_div = 2, 1158c2ecf20Sopenharmony_ci .hpi_buffer_cap = 7, 1168c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 1178c2ecf20Sopenharmony_ci GO7007_SENSOR_TV, 1188c2ecf20Sopenharmony_ci .num_i2c_devs = 1, 1198c2ecf20Sopenharmony_ci .i2c_devs = { 1208c2ecf20Sopenharmony_ci { 1218c2ecf20Sopenharmony_ci .type = "saa7113", 1228c2ecf20Sopenharmony_ci .addr = 0x25, 1238c2ecf20Sopenharmony_ci .is_video = 1, 1248c2ecf20Sopenharmony_ci }, 1258c2ecf20Sopenharmony_ci }, 1268c2ecf20Sopenharmony_ci .num_inputs = 2, 1278c2ecf20Sopenharmony_ci .inputs = { 1288c2ecf20Sopenharmony_ci { 1298c2ecf20Sopenharmony_ci .video_input = 0, 1308c2ecf20Sopenharmony_ci .name = "Composite", 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci { 1338c2ecf20Sopenharmony_ci .video_input = 9, 1348c2ecf20Sopenharmony_ci .name = "S-Video", 1358c2ecf20Sopenharmony_ci }, 1368c2ecf20Sopenharmony_ci }, 1378c2ecf20Sopenharmony_ci .video_config = SAA7115_IDQ_IS_DEFAULT, 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_star_trek = { 1428c2ecf20Sopenharmony_ci .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, 1438c2ecf20Sopenharmony_ci .main_info = { 1448c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_HAS_AUDIO, /* | 1458c2ecf20Sopenharmony_ci GO7007_BOARD_HAS_TUNER, */ 1468c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 1478c2ecf20Sopenharmony_ci GO7007_SENSOR_VALID_ENABLE | 1488c2ecf20Sopenharmony_ci GO7007_SENSOR_TV | 1498c2ecf20Sopenharmony_ci GO7007_SENSOR_SAA7115 | 1508c2ecf20Sopenharmony_ci GO7007_SENSOR_VBI | 1518c2ecf20Sopenharmony_ci GO7007_SENSOR_SCALING, 1528c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 1538c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 1548c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 1558c2ecf20Sopenharmony_ci .audio_main_div = 2, 1568c2ecf20Sopenharmony_ci .hpi_buffer_cap = 7, 1578c2ecf20Sopenharmony_ci .num_i2c_devs = 1, 1588c2ecf20Sopenharmony_ci .i2c_devs = { 1598c2ecf20Sopenharmony_ci { 1608c2ecf20Sopenharmony_ci .type = "saa7115", 1618c2ecf20Sopenharmony_ci .addr = 0x20, 1628c2ecf20Sopenharmony_ci .is_video = 1, 1638c2ecf20Sopenharmony_ci }, 1648c2ecf20Sopenharmony_ci }, 1658c2ecf20Sopenharmony_ci .num_inputs = 2, 1668c2ecf20Sopenharmony_ci .inputs = { 1678c2ecf20Sopenharmony_ci /* { 1688c2ecf20Sopenharmony_ci * .video_input = 3, 1698c2ecf20Sopenharmony_ci * .audio_index = AUDIO_TUNER, 1708c2ecf20Sopenharmony_ci * .name = "Tuner", 1718c2ecf20Sopenharmony_ci * }, 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci { 1748c2ecf20Sopenharmony_ci .video_input = 1, 1758c2ecf20Sopenharmony_ci /* .audio_index = AUDIO_EXTERN, */ 1768c2ecf20Sopenharmony_ci .name = "Composite", 1778c2ecf20Sopenharmony_ci }, 1788c2ecf20Sopenharmony_ci { 1798c2ecf20Sopenharmony_ci .video_input = 8, 1808c2ecf20Sopenharmony_ci /* .audio_index = AUDIO_EXTERN, */ 1818c2ecf20Sopenharmony_ci .name = "S-Video", 1828c2ecf20Sopenharmony_ci }, 1838c2ecf20Sopenharmony_ci }, 1848c2ecf20Sopenharmony_ci .video_config = SAA7115_IDQ_IS_DEFAULT, 1858c2ecf20Sopenharmony_ci }, 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_px_tv402u = { 1898c2ecf20Sopenharmony_ci .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, 1908c2ecf20Sopenharmony_ci .main_info = { 1918c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_HAS_AUDIO | 1928c2ecf20Sopenharmony_ci GO7007_BOARD_HAS_TUNER, 1938c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 1948c2ecf20Sopenharmony_ci GO7007_SENSOR_VALID_ENABLE | 1958c2ecf20Sopenharmony_ci GO7007_SENSOR_TV | 1968c2ecf20Sopenharmony_ci GO7007_SENSOR_SAA7115 | 1978c2ecf20Sopenharmony_ci GO7007_SENSOR_VBI | 1988c2ecf20Sopenharmony_ci GO7007_SENSOR_SCALING, 1998c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 2008c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 2018c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 2028c2ecf20Sopenharmony_ci .audio_main_div = 2, 2038c2ecf20Sopenharmony_ci .hpi_buffer_cap = 7, 2048c2ecf20Sopenharmony_ci .num_i2c_devs = 5, 2058c2ecf20Sopenharmony_ci .i2c_devs = { 2068c2ecf20Sopenharmony_ci { 2078c2ecf20Sopenharmony_ci .type = "saa7115", 2088c2ecf20Sopenharmony_ci .addr = 0x20, 2098c2ecf20Sopenharmony_ci .is_video = 1, 2108c2ecf20Sopenharmony_ci }, 2118c2ecf20Sopenharmony_ci { 2128c2ecf20Sopenharmony_ci .type = "uda1342", 2138c2ecf20Sopenharmony_ci .addr = 0x1a, 2148c2ecf20Sopenharmony_ci .is_audio = 1, 2158c2ecf20Sopenharmony_ci }, 2168c2ecf20Sopenharmony_ci { 2178c2ecf20Sopenharmony_ci .type = "tuner", 2188c2ecf20Sopenharmony_ci .addr = 0x60, 2198c2ecf20Sopenharmony_ci }, 2208c2ecf20Sopenharmony_ci { 2218c2ecf20Sopenharmony_ci .type = "tuner", 2228c2ecf20Sopenharmony_ci .addr = 0x43, 2238c2ecf20Sopenharmony_ci }, 2248c2ecf20Sopenharmony_ci { 2258c2ecf20Sopenharmony_ci .type = "sony-btf-mpx", 2268c2ecf20Sopenharmony_ci .addr = 0x44, 2278c2ecf20Sopenharmony_ci }, 2288c2ecf20Sopenharmony_ci }, 2298c2ecf20Sopenharmony_ci .num_inputs = 3, 2308c2ecf20Sopenharmony_ci .inputs = { 2318c2ecf20Sopenharmony_ci { 2328c2ecf20Sopenharmony_ci .video_input = 3, 2338c2ecf20Sopenharmony_ci .audio_index = 0, 2348c2ecf20Sopenharmony_ci .name = "Tuner", 2358c2ecf20Sopenharmony_ci }, 2368c2ecf20Sopenharmony_ci { 2378c2ecf20Sopenharmony_ci .video_input = 1, 2388c2ecf20Sopenharmony_ci .audio_index = 1, 2398c2ecf20Sopenharmony_ci .name = "Composite", 2408c2ecf20Sopenharmony_ci }, 2418c2ecf20Sopenharmony_ci { 2428c2ecf20Sopenharmony_ci .video_input = 8, 2438c2ecf20Sopenharmony_ci .audio_index = 1, 2448c2ecf20Sopenharmony_ci .name = "S-Video", 2458c2ecf20Sopenharmony_ci }, 2468c2ecf20Sopenharmony_ci }, 2478c2ecf20Sopenharmony_ci .video_config = SAA7115_IDQ_IS_DEFAULT, 2488c2ecf20Sopenharmony_ci .num_aud_inputs = 2, 2498c2ecf20Sopenharmony_ci .aud_inputs = { 2508c2ecf20Sopenharmony_ci { 2518c2ecf20Sopenharmony_ci .audio_input = UDA1342_IN2, 2528c2ecf20Sopenharmony_ci .name = "Tuner", 2538c2ecf20Sopenharmony_ci }, 2548c2ecf20Sopenharmony_ci { 2558c2ecf20Sopenharmony_ci .audio_input = UDA1342_IN1, 2568c2ecf20Sopenharmony_ci .name = "Line In", 2578c2ecf20Sopenharmony_ci }, 2588c2ecf20Sopenharmony_ci }, 2598c2ecf20Sopenharmony_ci }, 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_xmen = { 2638c2ecf20Sopenharmony_ci .flags = 0, 2648c2ecf20Sopenharmony_ci .main_info = { 2658c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_USE_ONBOARD_I2C, 2668c2ecf20Sopenharmony_ci .hpi_buffer_cap = 0, 2678c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_VREF_POLAR, 2688c2ecf20Sopenharmony_ci .sensor_width = 320, 2698c2ecf20Sopenharmony_ci .sensor_height = 240, 2708c2ecf20Sopenharmony_ci .sensor_framerate = 30030, 2718c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_ONE_CHANNEL | 2728c2ecf20Sopenharmony_ci GO7007_AUDIO_I2S_MODE_3 | 2738c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_14 | 2748c2ecf20Sopenharmony_ci GO7007_AUDIO_I2S_MASTER | 2758c2ecf20Sopenharmony_ci GO7007_AUDIO_BCLK_POLAR | 2768c2ecf20Sopenharmony_ci GO7007_AUDIO_OKI_MODE, 2778c2ecf20Sopenharmony_ci .audio_rate = 8000, 2788c2ecf20Sopenharmony_ci .audio_bclk_div = 48, 2798c2ecf20Sopenharmony_ci .audio_main_div = 1, 2808c2ecf20Sopenharmony_ci .num_i2c_devs = 1, 2818c2ecf20Sopenharmony_ci .i2c_devs = { 2828c2ecf20Sopenharmony_ci { 2838c2ecf20Sopenharmony_ci .type = "ov7640", 2848c2ecf20Sopenharmony_ci .addr = 0x21, 2858c2ecf20Sopenharmony_ci }, 2868c2ecf20Sopenharmony_ci }, 2878c2ecf20Sopenharmony_ci .num_inputs = 1, 2888c2ecf20Sopenharmony_ci .inputs = { 2898c2ecf20Sopenharmony_ci { 2908c2ecf20Sopenharmony_ci .name = "Camera", 2918c2ecf20Sopenharmony_ci }, 2928c2ecf20Sopenharmony_ci }, 2938c2ecf20Sopenharmony_ci }, 2948c2ecf20Sopenharmony_ci}; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_matrix_revolution = { 2978c2ecf20Sopenharmony_ci .flags = GO7007_USB_EZUSB, 2988c2ecf20Sopenharmony_ci .main_info = { 2998c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_HAS_AUDIO | 3008c2ecf20Sopenharmony_ci GO7007_BOARD_USE_ONBOARD_I2C, 3018c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 3028c2ecf20Sopenharmony_ci GO7007_AUDIO_I2S_MASTER | 3038c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 3048c2ecf20Sopenharmony_ci .audio_rate = 48000, 3058c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 3068c2ecf20Sopenharmony_ci .audio_main_div = 2, 3078c2ecf20Sopenharmony_ci .hpi_buffer_cap = 7, 3088c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 3098c2ecf20Sopenharmony_ci GO7007_SENSOR_TV | 3108c2ecf20Sopenharmony_ci GO7007_SENSOR_VBI, 3118c2ecf20Sopenharmony_ci .num_i2c_devs = 1, 3128c2ecf20Sopenharmony_ci .i2c_devs = { 3138c2ecf20Sopenharmony_ci { 3148c2ecf20Sopenharmony_ci .type = "tw9903", 3158c2ecf20Sopenharmony_ci .is_video = 1, 3168c2ecf20Sopenharmony_ci .addr = 0x44, 3178c2ecf20Sopenharmony_ci }, 3188c2ecf20Sopenharmony_ci }, 3198c2ecf20Sopenharmony_ci .num_inputs = 2, 3208c2ecf20Sopenharmony_ci .inputs = { 3218c2ecf20Sopenharmony_ci { 3228c2ecf20Sopenharmony_ci .video_input = 2, 3238c2ecf20Sopenharmony_ci .name = "Composite", 3248c2ecf20Sopenharmony_ci }, 3258c2ecf20Sopenharmony_ci { 3268c2ecf20Sopenharmony_ci .video_input = 8, 3278c2ecf20Sopenharmony_ci .name = "S-Video", 3288c2ecf20Sopenharmony_ci }, 3298c2ecf20Sopenharmony_ci }, 3308c2ecf20Sopenharmony_ci }, 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci#if 0 3348c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_lifeview_lr192 = { 3358c2ecf20Sopenharmony_ci .flags = GO7007_USB_EZUSB, 3368c2ecf20Sopenharmony_ci .main_info = { 3378c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_HAS_AUDIO | 3388c2ecf20Sopenharmony_ci GO7007_BOARD_USE_ONBOARD_I2C, 3398c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 3408c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 3418c2ecf20Sopenharmony_ci .audio_rate = 48000, 3428c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 3438c2ecf20Sopenharmony_ci .audio_main_div = 2, 3448c2ecf20Sopenharmony_ci .hpi_buffer_cap = 7, 3458c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 3468c2ecf20Sopenharmony_ci GO7007_SENSOR_VALID_ENABLE | 3478c2ecf20Sopenharmony_ci GO7007_SENSOR_TV | 3488c2ecf20Sopenharmony_ci GO7007_SENSOR_VBI | 3498c2ecf20Sopenharmony_ci GO7007_SENSOR_SCALING, 3508c2ecf20Sopenharmony_ci .num_i2c_devs = 0, 3518c2ecf20Sopenharmony_ci .num_inputs = 1, 3528c2ecf20Sopenharmony_ci .inputs = { 3538c2ecf20Sopenharmony_ci { 3548c2ecf20Sopenharmony_ci .video_input = 0, 3558c2ecf20Sopenharmony_ci .name = "Composite", 3568c2ecf20Sopenharmony_ci }, 3578c2ecf20Sopenharmony_ci }, 3588c2ecf20Sopenharmony_ci }, 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ci#endif 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_endura = { 3638c2ecf20Sopenharmony_ci .flags = 0, 3648c2ecf20Sopenharmony_ci .main_info = { 3658c2ecf20Sopenharmony_ci .flags = 0, 3668c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 3678c2ecf20Sopenharmony_ci GO7007_AUDIO_I2S_MASTER | 3688c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 3698c2ecf20Sopenharmony_ci .audio_rate = 8000, 3708c2ecf20Sopenharmony_ci .audio_bclk_div = 48, 3718c2ecf20Sopenharmony_ci .audio_main_div = 8, 3728c2ecf20Sopenharmony_ci .hpi_buffer_cap = 0, 3738c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 3748c2ecf20Sopenharmony_ci GO7007_SENSOR_TV, 3758c2ecf20Sopenharmony_ci .sensor_h_offset = 8, 3768c2ecf20Sopenharmony_ci .num_i2c_devs = 0, 3778c2ecf20Sopenharmony_ci .num_inputs = 1, 3788c2ecf20Sopenharmony_ci .inputs = { 3798c2ecf20Sopenharmony_ci { 3808c2ecf20Sopenharmony_ci .name = "Camera", 3818c2ecf20Sopenharmony_ci }, 3828c2ecf20Sopenharmony_ci }, 3838c2ecf20Sopenharmony_ci }, 3848c2ecf20Sopenharmony_ci}; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_adlink_mpg24 = { 3878c2ecf20Sopenharmony_ci .flags = 0, 3888c2ecf20Sopenharmony_ci .main_info = { 3898c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_USE_ONBOARD_I2C, 3908c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 3918c2ecf20Sopenharmony_ci GO7007_AUDIO_I2S_MASTER | 3928c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 3938c2ecf20Sopenharmony_ci .audio_rate = 48000, 3948c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 3958c2ecf20Sopenharmony_ci .audio_main_div = 2, 3968c2ecf20Sopenharmony_ci .hpi_buffer_cap = 0, 3978c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 3988c2ecf20Sopenharmony_ci GO7007_SENSOR_TV | 3998c2ecf20Sopenharmony_ci GO7007_SENSOR_VBI, 4008c2ecf20Sopenharmony_ci .num_i2c_devs = 1, 4018c2ecf20Sopenharmony_ci .i2c_devs = { 4028c2ecf20Sopenharmony_ci { 4038c2ecf20Sopenharmony_ci .type = "tw2804", 4048c2ecf20Sopenharmony_ci .addr = 0x00, /* yes, really */ 4058c2ecf20Sopenharmony_ci .flags = I2C_CLIENT_TEN, 4068c2ecf20Sopenharmony_ci .is_video = 1, 4078c2ecf20Sopenharmony_ci }, 4088c2ecf20Sopenharmony_ci }, 4098c2ecf20Sopenharmony_ci .num_inputs = 1, 4108c2ecf20Sopenharmony_ci .inputs = { 4118c2ecf20Sopenharmony_ci { 4128c2ecf20Sopenharmony_ci .name = "Composite", 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci }, 4158c2ecf20Sopenharmony_ci }, 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_sensoray_2250 = { 4198c2ecf20Sopenharmony_ci .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, 4208c2ecf20Sopenharmony_ci .main_info = { 4218c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 4228c2ecf20Sopenharmony_ci GO7007_AUDIO_I2S_MASTER | 4238c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 4248c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_HAS_AUDIO, 4258c2ecf20Sopenharmony_ci .audio_rate = 48000, 4268c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 4278c2ecf20Sopenharmony_ci .audio_main_div = 2, 4288c2ecf20Sopenharmony_ci .hpi_buffer_cap = 7, 4298c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 4308c2ecf20Sopenharmony_ci GO7007_SENSOR_TV, 4318c2ecf20Sopenharmony_ci .num_i2c_devs = 1, 4328c2ecf20Sopenharmony_ci .i2c_devs = { 4338c2ecf20Sopenharmony_ci { 4348c2ecf20Sopenharmony_ci .type = "s2250", 4358c2ecf20Sopenharmony_ci .addr = 0x43, 4368c2ecf20Sopenharmony_ci .is_video = 1, 4378c2ecf20Sopenharmony_ci .is_audio = 1, 4388c2ecf20Sopenharmony_ci }, 4398c2ecf20Sopenharmony_ci }, 4408c2ecf20Sopenharmony_ci .num_inputs = 2, 4418c2ecf20Sopenharmony_ci .inputs = { 4428c2ecf20Sopenharmony_ci { 4438c2ecf20Sopenharmony_ci .video_input = 0, 4448c2ecf20Sopenharmony_ci .name = "Composite", 4458c2ecf20Sopenharmony_ci }, 4468c2ecf20Sopenharmony_ci { 4478c2ecf20Sopenharmony_ci .video_input = 1, 4488c2ecf20Sopenharmony_ci .name = "S-Video", 4498c2ecf20Sopenharmony_ci }, 4508c2ecf20Sopenharmony_ci }, 4518c2ecf20Sopenharmony_ci .num_aud_inputs = 3, 4528c2ecf20Sopenharmony_ci .aud_inputs = { 4538c2ecf20Sopenharmony_ci { 4548c2ecf20Sopenharmony_ci .audio_input = 0, 4558c2ecf20Sopenharmony_ci .name = "Line In", 4568c2ecf20Sopenharmony_ci }, 4578c2ecf20Sopenharmony_ci { 4588c2ecf20Sopenharmony_ci .audio_input = 1, 4598c2ecf20Sopenharmony_ci .name = "Mic", 4608c2ecf20Sopenharmony_ci }, 4618c2ecf20Sopenharmony_ci { 4628c2ecf20Sopenharmony_ci .audio_input = 2, 4638c2ecf20Sopenharmony_ci .name = "Mic Boost", 4648c2ecf20Sopenharmony_ci }, 4658c2ecf20Sopenharmony_ci }, 4668c2ecf20Sopenharmony_ci }, 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic const struct go7007_usb_board board_ads_usbav_709 = { 4708c2ecf20Sopenharmony_ci .flags = GO7007_USB_EZUSB, 4718c2ecf20Sopenharmony_ci .main_info = { 4728c2ecf20Sopenharmony_ci .flags = GO7007_BOARD_HAS_AUDIO | 4738c2ecf20Sopenharmony_ci GO7007_BOARD_USE_ONBOARD_I2C, 4748c2ecf20Sopenharmony_ci .audio_flags = GO7007_AUDIO_I2S_MODE_1 | 4758c2ecf20Sopenharmony_ci GO7007_AUDIO_I2S_MASTER | 4768c2ecf20Sopenharmony_ci GO7007_AUDIO_WORD_16, 4778c2ecf20Sopenharmony_ci .audio_rate = 48000, 4788c2ecf20Sopenharmony_ci .audio_bclk_div = 8, 4798c2ecf20Sopenharmony_ci .audio_main_div = 2, 4808c2ecf20Sopenharmony_ci .hpi_buffer_cap = 7, 4818c2ecf20Sopenharmony_ci .sensor_flags = GO7007_SENSOR_656 | 4828c2ecf20Sopenharmony_ci GO7007_SENSOR_TV | 4838c2ecf20Sopenharmony_ci GO7007_SENSOR_VBI, 4848c2ecf20Sopenharmony_ci .num_i2c_devs = 1, 4858c2ecf20Sopenharmony_ci .i2c_devs = { 4868c2ecf20Sopenharmony_ci { 4878c2ecf20Sopenharmony_ci .type = "tw9906", 4888c2ecf20Sopenharmony_ci .is_video = 1, 4898c2ecf20Sopenharmony_ci .addr = 0x44, 4908c2ecf20Sopenharmony_ci }, 4918c2ecf20Sopenharmony_ci }, 4928c2ecf20Sopenharmony_ci .num_inputs = 2, 4938c2ecf20Sopenharmony_ci .inputs = { 4948c2ecf20Sopenharmony_ci { 4958c2ecf20Sopenharmony_ci .video_input = 0, 4968c2ecf20Sopenharmony_ci .name = "Composite", 4978c2ecf20Sopenharmony_ci }, 4988c2ecf20Sopenharmony_ci { 4998c2ecf20Sopenharmony_ci .video_input = 10, 5008c2ecf20Sopenharmony_ci .name = "S-Video", 5018c2ecf20Sopenharmony_ci }, 5028c2ecf20Sopenharmony_ci }, 5038c2ecf20Sopenharmony_ci }, 5048c2ecf20Sopenharmony_ci}; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic const struct usb_device_id go7007_usb_id_table[] = { 5078c2ecf20Sopenharmony_ci { 5088c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | 5098c2ecf20Sopenharmony_ci USB_DEVICE_ID_MATCH_INT_INFO, 5108c2ecf20Sopenharmony_ci .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ 5118c2ecf20Sopenharmony_ci .idProduct = 0x7007, /* Product ID of GO7007SB chip */ 5128c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x200, /* Revision number of XMen */ 5138c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x200, 5148c2ecf20Sopenharmony_ci .bInterfaceClass = 255, 5158c2ecf20Sopenharmony_ci .bInterfaceSubClass = 0, 5168c2ecf20Sopenharmony_ci .bInterfaceProtocol = 255, 5178c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN, 5188c2ecf20Sopenharmony_ci }, 5198c2ecf20Sopenharmony_ci { 5208c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 5218c2ecf20Sopenharmony_ci .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ 5228c2ecf20Sopenharmony_ci .idProduct = 0x7007, /* Product ID of GO7007SB chip */ 5238c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x202, /* Revision number of Matrix II */ 5248c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x202, 5258c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II, 5268c2ecf20Sopenharmony_ci }, 5278c2ecf20Sopenharmony_ci { 5288c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 5298c2ecf20Sopenharmony_ci .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ 5308c2ecf20Sopenharmony_ci .idProduct = 0x7007, /* Product ID of GO7007SB chip */ 5318c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x204, /* Revision number of Matrix */ 5328c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x204, /* Reloaded */ 5338c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD, 5348c2ecf20Sopenharmony_ci }, 5358c2ecf20Sopenharmony_ci { 5368c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | 5378c2ecf20Sopenharmony_ci USB_DEVICE_ID_MATCH_INT_INFO, 5388c2ecf20Sopenharmony_ci .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ 5398c2ecf20Sopenharmony_ci .idProduct = 0x7007, /* Product ID of GO7007SB chip */ 5408c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x205, /* Revision number of XMen-II */ 5418c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x205, 5428c2ecf20Sopenharmony_ci .bInterfaceClass = 255, 5438c2ecf20Sopenharmony_ci .bInterfaceSubClass = 0, 5448c2ecf20Sopenharmony_ci .bInterfaceProtocol = 255, 5458c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II, 5468c2ecf20Sopenharmony_ci }, 5478c2ecf20Sopenharmony_ci { 5488c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 5498c2ecf20Sopenharmony_ci .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ 5508c2ecf20Sopenharmony_ci .idProduct = 0x7007, /* Product ID of GO7007SB chip */ 5518c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x208, /* Revision number of Star Trek */ 5528c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x208, 5538c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK, 5548c2ecf20Sopenharmony_ci }, 5558c2ecf20Sopenharmony_ci { 5568c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | 5578c2ecf20Sopenharmony_ci USB_DEVICE_ID_MATCH_INT_INFO, 5588c2ecf20Sopenharmony_ci .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ 5598c2ecf20Sopenharmony_ci .idProduct = 0x7007, /* Product ID of GO7007SB chip */ 5608c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x209, /* Revision number of XMen-III */ 5618c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x209, 5628c2ecf20Sopenharmony_ci .bInterfaceClass = 255, 5638c2ecf20Sopenharmony_ci .bInterfaceSubClass = 0, 5648c2ecf20Sopenharmony_ci .bInterfaceProtocol = 255, 5658c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III, 5668c2ecf20Sopenharmony_ci }, 5678c2ecf20Sopenharmony_ci { 5688c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 5698c2ecf20Sopenharmony_ci .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */ 5708c2ecf20Sopenharmony_ci .idProduct = 0x7007, /* Product ID of GO7007SB chip */ 5718c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x210, /* Revision number of Matrix */ 5728c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x210, /* Revolution */ 5738c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV, 5748c2ecf20Sopenharmony_ci }, 5758c2ecf20Sopenharmony_ci { 5768c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 5778c2ecf20Sopenharmony_ci .idVendor = 0x093b, /* Vendor ID of Plextor */ 5788c2ecf20Sopenharmony_ci .idProduct = 0xa102, /* Product ID of M402U */ 5798c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x1, /* revision number of Blueberry */ 5808c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x1, 5818c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U, 5828c2ecf20Sopenharmony_ci }, 5838c2ecf20Sopenharmony_ci { 5848c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 5858c2ecf20Sopenharmony_ci .idVendor = 0x093b, /* Vendor ID of Plextor */ 5868c2ecf20Sopenharmony_ci .idProduct = 0xa104, /* Product ID of TV402U */ 5878c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x1, 5888c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x1, 5898c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U, 5908c2ecf20Sopenharmony_ci }, 5918c2ecf20Sopenharmony_ci { 5928c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 5938c2ecf20Sopenharmony_ci .idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */ 5948c2ecf20Sopenharmony_ci .idProduct = 0xde00, /* Product ID of Lifeview LR192 */ 5958c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x1, 5968c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x1, 5978c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192, 5988c2ecf20Sopenharmony_ci }, 5998c2ecf20Sopenharmony_ci { 6008c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 6018c2ecf20Sopenharmony_ci .idVendor = 0x1943, /* Vendor ID Sensoray */ 6028c2ecf20Sopenharmony_ci .idProduct = 0x2250, /* Product ID of 2250/2251 */ 6038c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x1, 6048c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x1, 6058c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250, 6068c2ecf20Sopenharmony_ci }, 6078c2ecf20Sopenharmony_ci { 6088c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, 6098c2ecf20Sopenharmony_ci .idVendor = 0x06e1, /* Vendor ID of ADS Technologies */ 6108c2ecf20Sopenharmony_ci .idProduct = 0x0709, /* Product ID of DVD Xpress DX2 */ 6118c2ecf20Sopenharmony_ci .bcdDevice_lo = 0x204, 6128c2ecf20Sopenharmony_ci .bcdDevice_hi = 0x204, 6138c2ecf20Sopenharmony_ci .driver_info = (kernel_ulong_t)GO7007_BOARDID_ADS_USBAV_709, 6148c2ecf20Sopenharmony_ci }, 6158c2ecf20Sopenharmony_ci { } /* Terminating entry */ 6168c2ecf20Sopenharmony_ci}; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, go7007_usb_id_table); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci/********************* Driver for EZ-USB HPI interface *********************/ 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic int go7007_usb_vendor_request(struct go7007 *go, int request, 6238c2ecf20Sopenharmony_ci int value, int index, void *transfer_buffer, int length, int in) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 6268c2ecf20Sopenharmony_ci int timeout = 5000; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (in) { 6298c2ecf20Sopenharmony_ci return usb_control_msg(usb->usbdev, 6308c2ecf20Sopenharmony_ci usb_rcvctrlpipe(usb->usbdev, 0), request, 6318c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 6328c2ecf20Sopenharmony_ci value, index, transfer_buffer, length, timeout); 6338c2ecf20Sopenharmony_ci } else { 6348c2ecf20Sopenharmony_ci return usb_control_msg(usb->usbdev, 6358c2ecf20Sopenharmony_ci usb_sndctrlpipe(usb->usbdev, 0), request, 6368c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE, 6378c2ecf20Sopenharmony_ci value, index, transfer_buffer, length, timeout); 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int go7007_usb_interface_reset(struct go7007 *go) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 6448c2ecf20Sopenharmony_ci u16 intr_val, intr_data; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (go->status == STATUS_SHUTDOWN) 6478c2ecf20Sopenharmony_ci return -1; 6488c2ecf20Sopenharmony_ci /* Reset encoder */ 6498c2ecf20Sopenharmony_ci if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) 6508c2ecf20Sopenharmony_ci return -1; 6518c2ecf20Sopenharmony_ci msleep(100); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (usb->board->flags & GO7007_USB_EZUSB) { 6548c2ecf20Sopenharmony_ci /* Reset buffer in EZ-USB */ 6558c2ecf20Sopenharmony_ci pr_debug("resetting EZ-USB buffers\n"); 6568c2ecf20Sopenharmony_ci if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 || 6578c2ecf20Sopenharmony_ci go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0) 6588c2ecf20Sopenharmony_ci return -1; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Reset encoder again */ 6618c2ecf20Sopenharmony_ci if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) 6628c2ecf20Sopenharmony_ci return -1; 6638c2ecf20Sopenharmony_ci msleep(100); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* Wait for an interrupt to indicate successful hardware reset */ 6678c2ecf20Sopenharmony_ci if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || 6688c2ecf20Sopenharmony_ci (intr_val & ~0x1) != 0x55aa) { 6698c2ecf20Sopenharmony_ci dev_err(go->dev, "unable to reset the USB interface\n"); 6708c2ecf20Sopenharmony_ci return -1; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic int go7007_usb_ezusb_write_interrupt(struct go7007 *go, 6768c2ecf20Sopenharmony_ci int addr, int data) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 6798c2ecf20Sopenharmony_ci int i, r; 6808c2ecf20Sopenharmony_ci u16 status_reg = 0; 6818c2ecf20Sopenharmony_ci int timeout = 500; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci pr_debug("WriteInterrupt: %04x %04x\n", addr, data); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci for (i = 0; i < 100; ++i) { 6868c2ecf20Sopenharmony_ci r = usb_control_msg(usb->usbdev, 6878c2ecf20Sopenharmony_ci usb_rcvctrlpipe(usb->usbdev, 0), 0x14, 6888c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 6898c2ecf20Sopenharmony_ci 0, HPI_STATUS_ADDR, go->usb_buf, 6908c2ecf20Sopenharmony_ci sizeof(status_reg), timeout); 6918c2ecf20Sopenharmony_ci if (r < 0) 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci status_reg = le16_to_cpu(*((__le16 *)go->usb_buf)); 6948c2ecf20Sopenharmony_ci if (!(status_reg & 0x0010)) 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci msleep(10); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci if (r < 0) 6998c2ecf20Sopenharmony_ci goto write_int_error; 7008c2ecf20Sopenharmony_ci if (i == 100) { 7018c2ecf20Sopenharmony_ci dev_err(go->dev, "device is hung, status reg = 0x%04x\n", status_reg); 7028c2ecf20Sopenharmony_ci return -1; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12, 7058c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE, data, 7068c2ecf20Sopenharmony_ci INT_PARAM_ADDR, NULL, 0, timeout); 7078c2ecf20Sopenharmony_ci if (r < 0) 7088c2ecf20Sopenharmony_ci goto write_int_error; 7098c2ecf20Sopenharmony_ci r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 7108c2ecf20Sopenharmony_ci 0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr, 7118c2ecf20Sopenharmony_ci INT_INDEX_ADDR, NULL, 0, timeout); 7128c2ecf20Sopenharmony_ci if (r < 0) 7138c2ecf20Sopenharmony_ci goto write_int_error; 7148c2ecf20Sopenharmony_ci return 0; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ciwrite_int_error: 7178c2ecf20Sopenharmony_ci dev_err(go->dev, "error in WriteInterrupt: %d\n", r); 7188c2ecf20Sopenharmony_ci return r; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic int go7007_usb_onboard_write_interrupt(struct go7007 *go, 7228c2ecf20Sopenharmony_ci int addr, int data) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 7258c2ecf20Sopenharmony_ci int r; 7268c2ecf20Sopenharmony_ci int timeout = 500; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci pr_debug("WriteInterrupt: %04x %04x\n", addr, data); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci go->usb_buf[0] = data & 0xff; 7318c2ecf20Sopenharmony_ci go->usb_buf[1] = data >> 8; 7328c2ecf20Sopenharmony_ci go->usb_buf[2] = addr & 0xff; 7338c2ecf20Sopenharmony_ci go->usb_buf[3] = addr >> 8; 7348c2ecf20Sopenharmony_ci go->usb_buf[4] = go->usb_buf[5] = go->usb_buf[6] = go->usb_buf[7] = 0; 7358c2ecf20Sopenharmony_ci r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00, 7368c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa, 7378c2ecf20Sopenharmony_ci 0xf0f0, go->usb_buf, 8, timeout); 7388c2ecf20Sopenharmony_ci if (r < 0) { 7398c2ecf20Sopenharmony_ci dev_err(go->dev, "error in WriteInterrupt: %d\n", r); 7408c2ecf20Sopenharmony_ci return r; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci return 0; 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic void go7007_usb_readinterrupt_complete(struct urb *urb) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct go7007 *go = (struct go7007 *)urb->context; 7488c2ecf20Sopenharmony_ci __le16 *regs = (__le16 *)urb->transfer_buffer; 7498c2ecf20Sopenharmony_ci int status = urb->status; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (status) { 7528c2ecf20Sopenharmony_ci if (status != -ESHUTDOWN && 7538c2ecf20Sopenharmony_ci go->status != STATUS_SHUTDOWN) { 7548c2ecf20Sopenharmony_ci dev_err(go->dev, "error in read interrupt: %d\n", urb->status); 7558c2ecf20Sopenharmony_ci } else { 7568c2ecf20Sopenharmony_ci wake_up(&go->interrupt_waitq); 7578c2ecf20Sopenharmony_ci return; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci } else if (urb->actual_length != urb->transfer_buffer_length) { 7608c2ecf20Sopenharmony_ci dev_err(go->dev, "short read in interrupt pipe!\n"); 7618c2ecf20Sopenharmony_ci } else { 7628c2ecf20Sopenharmony_ci go->interrupt_available = 1; 7638c2ecf20Sopenharmony_ci go->interrupt_data = __le16_to_cpu(regs[0]); 7648c2ecf20Sopenharmony_ci go->interrupt_value = __le16_to_cpu(regs[1]); 7658c2ecf20Sopenharmony_ci pr_debug("ReadInterrupt: %04x %04x\n", 7668c2ecf20Sopenharmony_ci go->interrupt_value, go->interrupt_data); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci wake_up(&go->interrupt_waitq); 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic int go7007_usb_read_interrupt(struct go7007 *go) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 7758c2ecf20Sopenharmony_ci int r; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci r = usb_submit_urb(usb->intr_urb, GFP_KERNEL); 7788c2ecf20Sopenharmony_ci if (r < 0) { 7798c2ecf20Sopenharmony_ci dev_err(go->dev, "unable to submit interrupt urb: %d\n", r); 7808c2ecf20Sopenharmony_ci return r; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic void go7007_usb_read_video_pipe_complete(struct urb *urb) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct go7007 *go = (struct go7007 *)urb->context; 7888c2ecf20Sopenharmony_ci int r, status = urb->status; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (!vb2_is_streaming(&go->vidq)) { 7918c2ecf20Sopenharmony_ci wake_up_interruptible(&go->frame_waitq); 7928c2ecf20Sopenharmony_ci return; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci if (status) { 7958c2ecf20Sopenharmony_ci dev_err(go->dev, "error in video pipe: %d\n", status); 7968c2ecf20Sopenharmony_ci return; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci if (urb->actual_length != urb->transfer_buffer_length) { 7998c2ecf20Sopenharmony_ci dev_err(go->dev, "short read in video pipe!\n"); 8008c2ecf20Sopenharmony_ci return; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length); 8038c2ecf20Sopenharmony_ci r = usb_submit_urb(urb, GFP_ATOMIC); 8048c2ecf20Sopenharmony_ci if (r < 0) 8058c2ecf20Sopenharmony_ci dev_err(go->dev, "error in video pipe: %d\n", r); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic void go7007_usb_read_audio_pipe_complete(struct urb *urb) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct go7007 *go = (struct go7007 *)urb->context; 8118c2ecf20Sopenharmony_ci int r, status = urb->status; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (!vb2_is_streaming(&go->vidq)) 8148c2ecf20Sopenharmony_ci return; 8158c2ecf20Sopenharmony_ci if (status) { 8168c2ecf20Sopenharmony_ci dev_err(go->dev, "error in audio pipe: %d\n", 8178c2ecf20Sopenharmony_ci status); 8188c2ecf20Sopenharmony_ci return; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci if (urb->actual_length != urb->transfer_buffer_length) { 8218c2ecf20Sopenharmony_ci dev_err(go->dev, "short read in audio pipe!\n"); 8228c2ecf20Sopenharmony_ci return; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci if (go->audio_deliver != NULL) 8258c2ecf20Sopenharmony_ci go->audio_deliver(go, urb->transfer_buffer, urb->actual_length); 8268c2ecf20Sopenharmony_ci r = usb_submit_urb(urb, GFP_ATOMIC); 8278c2ecf20Sopenharmony_ci if (r < 0) 8288c2ecf20Sopenharmony_ci dev_err(go->dev, "error in audio pipe: %d\n", r); 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic int go7007_usb_stream_start(struct go7007 *go) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 8348c2ecf20Sopenharmony_ci int i, r; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) { 8378c2ecf20Sopenharmony_ci r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL); 8388c2ecf20Sopenharmony_ci if (r < 0) { 8398c2ecf20Sopenharmony_ci dev_err(go->dev, "error submitting video urb %d: %d\n", i, r); 8408c2ecf20Sopenharmony_ci goto video_submit_failed; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci if (!go->audio_enabled) 8448c2ecf20Sopenharmony_ci return 0; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) { 8478c2ecf20Sopenharmony_ci r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL); 8488c2ecf20Sopenharmony_ci if (r < 0) { 8498c2ecf20Sopenharmony_ci dev_err(go->dev, "error submitting audio urb %d: %d\n", i, r); 8508c2ecf20Sopenharmony_ci goto audio_submit_failed; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ciaudio_submit_failed: 8568c2ecf20Sopenharmony_ci for (i = 0; i < 7; ++i) 8578c2ecf20Sopenharmony_ci usb_kill_urb(usb->audio_urbs[i]); 8588c2ecf20Sopenharmony_civideo_submit_failed: 8598c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) 8608c2ecf20Sopenharmony_ci usb_kill_urb(usb->video_urbs[i]); 8618c2ecf20Sopenharmony_ci return -1; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic int go7007_usb_stream_stop(struct go7007 *go) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 8678c2ecf20Sopenharmony_ci int i; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (go->status == STATUS_SHUTDOWN) 8708c2ecf20Sopenharmony_ci return 0; 8718c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) 8728c2ecf20Sopenharmony_ci usb_kill_urb(usb->video_urbs[i]); 8738c2ecf20Sopenharmony_ci if (go->audio_enabled) 8748c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) 8758c2ecf20Sopenharmony_ci usb_kill_urb(usb->audio_urbs[i]); 8768c2ecf20Sopenharmony_ci return 0; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 8828c2ecf20Sopenharmony_ci int transferred, pipe; 8838c2ecf20Sopenharmony_ci int timeout = 500; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci pr_debug("DownloadBuffer sending %d bytes\n", len); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (usb->board->flags & GO7007_USB_EZUSB) 8888c2ecf20Sopenharmony_ci pipe = usb_sndbulkpipe(usb->usbdev, 2); 8898c2ecf20Sopenharmony_ci else 8908c2ecf20Sopenharmony_ci pipe = usb_sndbulkpipe(usb->usbdev, 3); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci return usb_bulk_msg(usb->usbdev, pipe, data, len, 8938c2ecf20Sopenharmony_ci &transferred, timeout); 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cistatic void go7007_usb_release(struct go7007 *go) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 8998c2ecf20Sopenharmony_ci struct urb *vurb, *aurb; 9008c2ecf20Sopenharmony_ci int i; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (usb->intr_urb) { 9038c2ecf20Sopenharmony_ci usb_kill_urb(usb->intr_urb); 9048c2ecf20Sopenharmony_ci kfree(usb->intr_urb->transfer_buffer); 9058c2ecf20Sopenharmony_ci usb_free_urb(usb->intr_urb); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* Free USB-related structs */ 9098c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) { 9108c2ecf20Sopenharmony_ci vurb = usb->video_urbs[i]; 9118c2ecf20Sopenharmony_ci if (vurb) { 9128c2ecf20Sopenharmony_ci usb_kill_urb(vurb); 9138c2ecf20Sopenharmony_ci kfree(vurb->transfer_buffer); 9148c2ecf20Sopenharmony_ci usb_free_urb(vurb); 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci aurb = usb->audio_urbs[i]; 9178c2ecf20Sopenharmony_ci if (aurb) { 9188c2ecf20Sopenharmony_ci usb_kill_urb(aurb); 9198c2ecf20Sopenharmony_ci kfree(aurb->transfer_buffer); 9208c2ecf20Sopenharmony_ci usb_free_urb(aurb); 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci kfree(go->hpi_context); 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic const struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = { 9288c2ecf20Sopenharmony_ci .interface_reset = go7007_usb_interface_reset, 9298c2ecf20Sopenharmony_ci .write_interrupt = go7007_usb_ezusb_write_interrupt, 9308c2ecf20Sopenharmony_ci .read_interrupt = go7007_usb_read_interrupt, 9318c2ecf20Sopenharmony_ci .stream_start = go7007_usb_stream_start, 9328c2ecf20Sopenharmony_ci .stream_stop = go7007_usb_stream_stop, 9338c2ecf20Sopenharmony_ci .send_firmware = go7007_usb_send_firmware, 9348c2ecf20Sopenharmony_ci .release = go7007_usb_release, 9358c2ecf20Sopenharmony_ci}; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic const struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = { 9388c2ecf20Sopenharmony_ci .interface_reset = go7007_usb_interface_reset, 9398c2ecf20Sopenharmony_ci .write_interrupt = go7007_usb_onboard_write_interrupt, 9408c2ecf20Sopenharmony_ci .read_interrupt = go7007_usb_read_interrupt, 9418c2ecf20Sopenharmony_ci .stream_start = go7007_usb_stream_start, 9428c2ecf20Sopenharmony_ci .stream_stop = go7007_usb_stream_stop, 9438c2ecf20Sopenharmony_ci .send_firmware = go7007_usb_send_firmware, 9448c2ecf20Sopenharmony_ci .release = go7007_usb_release, 9458c2ecf20Sopenharmony_ci}; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci/********************* Driver for EZ-USB I2C adapter *********************/ 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, 9508c2ecf20Sopenharmony_ci struct i2c_msg msgs[], int num) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct go7007 *go = i2c_get_adapdata(adapter); 9538c2ecf20Sopenharmony_ci struct go7007_usb *usb = go->hpi_context; 9548c2ecf20Sopenharmony_ci u8 *buf = go->usb_buf; 9558c2ecf20Sopenharmony_ci int buf_len, i; 9568c2ecf20Sopenharmony_ci int ret = -EIO; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (go->status == STATUS_SHUTDOWN) 9598c2ecf20Sopenharmony_ci return -ENODEV; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci mutex_lock(&usb->i2c_lock); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci for (i = 0; i < num; ++i) { 9648c2ecf20Sopenharmony_ci /* The hardware command is "write some bytes then read some 9658c2ecf20Sopenharmony_ci * bytes", so we try to coalesce a write followed by a read 9668c2ecf20Sopenharmony_ci * into a single USB transaction */ 9678c2ecf20Sopenharmony_ci if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr && 9688c2ecf20Sopenharmony_ci !(msgs[i].flags & I2C_M_RD) && 9698c2ecf20Sopenharmony_ci (msgs[i + 1].flags & I2C_M_RD)) { 9708c2ecf20Sopenharmony_ci#ifdef GO7007_I2C_DEBUG 9718c2ecf20Sopenharmony_ci pr_debug("i2c write/read %d/%d bytes on %02x\n", 9728c2ecf20Sopenharmony_ci msgs[i].len, msgs[i + 1].len, msgs[i].addr); 9738c2ecf20Sopenharmony_ci#endif 9748c2ecf20Sopenharmony_ci buf[0] = 0x01; 9758c2ecf20Sopenharmony_ci buf[1] = msgs[i].len + 1; 9768c2ecf20Sopenharmony_ci buf[2] = msgs[i].addr << 1; 9778c2ecf20Sopenharmony_ci memcpy(&buf[3], msgs[i].buf, msgs[i].len); 9788c2ecf20Sopenharmony_ci buf_len = msgs[i].len + 3; 9798c2ecf20Sopenharmony_ci buf[buf_len++] = msgs[++i].len; 9808c2ecf20Sopenharmony_ci } else if (msgs[i].flags & I2C_M_RD) { 9818c2ecf20Sopenharmony_ci#ifdef GO7007_I2C_DEBUG 9828c2ecf20Sopenharmony_ci pr_debug("i2c read %d bytes on %02x\n", 9838c2ecf20Sopenharmony_ci msgs[i].len, msgs[i].addr); 9848c2ecf20Sopenharmony_ci#endif 9858c2ecf20Sopenharmony_ci buf[0] = 0x01; 9868c2ecf20Sopenharmony_ci buf[1] = 1; 9878c2ecf20Sopenharmony_ci buf[2] = msgs[i].addr << 1; 9888c2ecf20Sopenharmony_ci buf[3] = msgs[i].len; 9898c2ecf20Sopenharmony_ci buf_len = 4; 9908c2ecf20Sopenharmony_ci } else { 9918c2ecf20Sopenharmony_ci#ifdef GO7007_I2C_DEBUG 9928c2ecf20Sopenharmony_ci pr_debug("i2c write %d bytes on %02x\n", 9938c2ecf20Sopenharmony_ci msgs[i].len, msgs[i].addr); 9948c2ecf20Sopenharmony_ci#endif 9958c2ecf20Sopenharmony_ci buf[0] = 0x00; 9968c2ecf20Sopenharmony_ci buf[1] = msgs[i].len + 1; 9978c2ecf20Sopenharmony_ci buf[2] = msgs[i].addr << 1; 9988c2ecf20Sopenharmony_ci memcpy(&buf[3], msgs[i].buf, msgs[i].len); 9998c2ecf20Sopenharmony_ci buf_len = msgs[i].len + 3; 10008c2ecf20Sopenharmony_ci buf[buf_len++] = 0; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci if (go7007_usb_vendor_request(go, 0x24, 0, 0, 10038c2ecf20Sopenharmony_ci buf, buf_len, 0) < 0) 10048c2ecf20Sopenharmony_ci goto i2c_done; 10058c2ecf20Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) { 10068c2ecf20Sopenharmony_ci memset(buf, 0, msgs[i].len + 1); 10078c2ecf20Sopenharmony_ci if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf, 10088c2ecf20Sopenharmony_ci msgs[i].len + 1, 1) < 0) 10098c2ecf20Sopenharmony_ci goto i2c_done; 10108c2ecf20Sopenharmony_ci memcpy(msgs[i].buf, buf + 1, msgs[i].len); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci ret = num; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cii2c_done: 10168c2ecf20Sopenharmony_ci mutex_unlock(&usb->i2c_lock); 10178c2ecf20Sopenharmony_ci return ret; 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_cistatic u32 go7007_usb_functionality(struct i2c_adapter *adapter) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci /* No errors are reported by the hardware, so we don't bother 10238c2ecf20Sopenharmony_ci * supporting quick writes to avoid confusing probing */ 10248c2ecf20Sopenharmony_ci return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic const struct i2c_algorithm go7007_usb_algo = { 10288c2ecf20Sopenharmony_ci .master_xfer = go7007_usb_i2c_master_xfer, 10298c2ecf20Sopenharmony_ci .functionality = go7007_usb_functionality, 10308c2ecf20Sopenharmony_ci}; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic struct i2c_adapter go7007_usb_adap_templ = { 10338c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10348c2ecf20Sopenharmony_ci .name = "WIS GO7007SB EZ-USB", 10358c2ecf20Sopenharmony_ci .algo = &go7007_usb_algo, 10368c2ecf20Sopenharmony_ci}; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/********************* USB add/remove functions *********************/ 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int go7007_usb_probe(struct usb_interface *intf, 10418c2ecf20Sopenharmony_ci const struct usb_device_id *id) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct go7007 *go; 10448c2ecf20Sopenharmony_ci struct go7007_usb *usb; 10458c2ecf20Sopenharmony_ci const struct go7007_usb_board *board; 10468c2ecf20Sopenharmony_ci struct usb_device *usbdev = interface_to_usbdev(intf); 10478c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep; 10488c2ecf20Sopenharmony_ci unsigned num_i2c_devs; 10498c2ecf20Sopenharmony_ci char *name; 10508c2ecf20Sopenharmony_ci int video_pipe, i, v_urb_len; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci pr_debug("probing new GO7007 USB board\n"); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci switch (id->driver_info) { 10558c2ecf20Sopenharmony_ci case GO7007_BOARDID_MATRIX_II: 10568c2ecf20Sopenharmony_ci name = "WIS Matrix II or compatible"; 10578c2ecf20Sopenharmony_ci board = &board_matrix_ii; 10588c2ecf20Sopenharmony_ci break; 10598c2ecf20Sopenharmony_ci case GO7007_BOARDID_MATRIX_RELOAD: 10608c2ecf20Sopenharmony_ci name = "WIS Matrix Reloaded or compatible"; 10618c2ecf20Sopenharmony_ci board = &board_matrix_reload; 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci case GO7007_BOARDID_MATRIX_REV: 10648c2ecf20Sopenharmony_ci name = "WIS Matrix Revolution or compatible"; 10658c2ecf20Sopenharmony_ci board = &board_matrix_revolution; 10668c2ecf20Sopenharmony_ci break; 10678c2ecf20Sopenharmony_ci case GO7007_BOARDID_STAR_TREK: 10688c2ecf20Sopenharmony_ci name = "WIS Star Trek or compatible"; 10698c2ecf20Sopenharmony_ci board = &board_star_trek; 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci case GO7007_BOARDID_XMEN: 10728c2ecf20Sopenharmony_ci name = "WIS XMen or compatible"; 10738c2ecf20Sopenharmony_ci board = &board_xmen; 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci case GO7007_BOARDID_XMEN_II: 10768c2ecf20Sopenharmony_ci name = "WIS XMen II or compatible"; 10778c2ecf20Sopenharmony_ci board = &board_xmen; 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci case GO7007_BOARDID_XMEN_III: 10808c2ecf20Sopenharmony_ci name = "WIS XMen III or compatible"; 10818c2ecf20Sopenharmony_ci board = &board_xmen; 10828c2ecf20Sopenharmony_ci break; 10838c2ecf20Sopenharmony_ci case GO7007_BOARDID_PX_M402U: 10848c2ecf20Sopenharmony_ci name = "Plextor PX-M402U"; 10858c2ecf20Sopenharmony_ci board = &board_matrix_ii; 10868c2ecf20Sopenharmony_ci break; 10878c2ecf20Sopenharmony_ci case GO7007_BOARDID_PX_TV402U: 10888c2ecf20Sopenharmony_ci name = "Plextor PX-TV402U (unknown tuner)"; 10898c2ecf20Sopenharmony_ci board = &board_px_tv402u; 10908c2ecf20Sopenharmony_ci break; 10918c2ecf20Sopenharmony_ci case GO7007_BOARDID_LIFEVIEW_LR192: 10928c2ecf20Sopenharmony_ci dev_err(&intf->dev, "The Lifeview TV Walker Ultra is not supported. Sorry!\n"); 10938c2ecf20Sopenharmony_ci return -ENODEV; 10948c2ecf20Sopenharmony_ci#if 0 10958c2ecf20Sopenharmony_ci name = "Lifeview TV Walker Ultra"; 10968c2ecf20Sopenharmony_ci board = &board_lifeview_lr192; 10978c2ecf20Sopenharmony_ci#endif 10988c2ecf20Sopenharmony_ci break; 10998c2ecf20Sopenharmony_ci case GO7007_BOARDID_SENSORAY_2250: 11008c2ecf20Sopenharmony_ci dev_info(&intf->dev, "Sensoray 2250 found\n"); 11018c2ecf20Sopenharmony_ci name = "Sensoray 2250/2251"; 11028c2ecf20Sopenharmony_ci board = &board_sensoray_2250; 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci case GO7007_BOARDID_ADS_USBAV_709: 11058c2ecf20Sopenharmony_ci name = "ADS Tech DVD Xpress DX2"; 11068c2ecf20Sopenharmony_ci board = &board_ads_usbav_709; 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci default: 11098c2ecf20Sopenharmony_ci dev_err(&intf->dev, "unknown board ID %d!\n", 11108c2ecf20Sopenharmony_ci (unsigned int)id->driver_info); 11118c2ecf20Sopenharmony_ci return -ENODEV; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci go = go7007_alloc(&board->main_info, &intf->dev); 11158c2ecf20Sopenharmony_ci if (go == NULL) 11168c2ecf20Sopenharmony_ci return -ENOMEM; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL); 11198c2ecf20Sopenharmony_ci if (usb == NULL) { 11208c2ecf20Sopenharmony_ci kfree(go); 11218c2ecf20Sopenharmony_ci return -ENOMEM; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci usb->board = board; 11258c2ecf20Sopenharmony_ci usb->usbdev = usbdev; 11268c2ecf20Sopenharmony_ci usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info)); 11278c2ecf20Sopenharmony_ci go->board_id = id->driver_info; 11288c2ecf20Sopenharmony_ci strscpy(go->name, name, sizeof(go->name)); 11298c2ecf20Sopenharmony_ci if (board->flags & GO7007_USB_EZUSB) 11308c2ecf20Sopenharmony_ci go->hpi_ops = &go7007_usb_ezusb_hpi_ops; 11318c2ecf20Sopenharmony_ci else 11328c2ecf20Sopenharmony_ci go->hpi_ops = &go7007_usb_onboard_hpi_ops; 11338c2ecf20Sopenharmony_ci go->hpi_context = usb; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci ep = usb->usbdev->ep_in[4]; 11368c2ecf20Sopenharmony_ci if (!ep) 11378c2ecf20Sopenharmony_ci goto allocfail; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* Allocate the URB and buffer for receiving incoming interrupts */ 11408c2ecf20Sopenharmony_ci usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); 11418c2ecf20Sopenharmony_ci if (usb->intr_urb == NULL) 11428c2ecf20Sopenharmony_ci goto allocfail; 11438c2ecf20Sopenharmony_ci usb->intr_urb->transfer_buffer = kmalloc_array(2, sizeof(u16), 11448c2ecf20Sopenharmony_ci GFP_KERNEL); 11458c2ecf20Sopenharmony_ci if (usb->intr_urb->transfer_buffer == NULL) 11468c2ecf20Sopenharmony_ci goto allocfail; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK) 11498c2ecf20Sopenharmony_ci usb_fill_bulk_urb(usb->intr_urb, usb->usbdev, 11508c2ecf20Sopenharmony_ci usb_rcvbulkpipe(usb->usbdev, 4), 11518c2ecf20Sopenharmony_ci usb->intr_urb->transfer_buffer, 2*sizeof(u16), 11528c2ecf20Sopenharmony_ci go7007_usb_readinterrupt_complete, go); 11538c2ecf20Sopenharmony_ci else 11548c2ecf20Sopenharmony_ci usb_fill_int_urb(usb->intr_urb, usb->usbdev, 11558c2ecf20Sopenharmony_ci usb_rcvintpipe(usb->usbdev, 4), 11568c2ecf20Sopenharmony_ci usb->intr_urb->transfer_buffer, 2*sizeof(u16), 11578c2ecf20Sopenharmony_ci go7007_usb_readinterrupt_complete, go, 8); 11588c2ecf20Sopenharmony_ci usb_set_intfdata(intf, &go->v4l2_dev); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci /* Boot the GO7007 */ 11618c2ecf20Sopenharmony_ci if (go7007_boot_encoder(go, go->board_info->flags & 11628c2ecf20Sopenharmony_ci GO7007_BOARD_USE_ONBOARD_I2C) < 0) 11638c2ecf20Sopenharmony_ci goto allocfail; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* Register the EZ-USB I2C adapter, if we're using it */ 11668c2ecf20Sopenharmony_ci if (board->flags & GO7007_USB_EZUSB_I2C) { 11678c2ecf20Sopenharmony_ci memcpy(&go->i2c_adapter, &go7007_usb_adap_templ, 11688c2ecf20Sopenharmony_ci sizeof(go7007_usb_adap_templ)); 11698c2ecf20Sopenharmony_ci mutex_init(&usb->i2c_lock); 11708c2ecf20Sopenharmony_ci go->i2c_adapter.dev.parent = go->dev; 11718c2ecf20Sopenharmony_ci i2c_set_adapdata(&go->i2c_adapter, go); 11728c2ecf20Sopenharmony_ci if (i2c_add_adapter(&go->i2c_adapter) < 0) { 11738c2ecf20Sopenharmony_ci dev_err(go->dev, "error: i2c_add_adapter failed\n"); 11748c2ecf20Sopenharmony_ci goto allocfail; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci go->i2c_adapter_online = 1; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Pelco and Adlink reused the XMen and XMen-III vendor and product 11808c2ecf20Sopenharmony_ci * IDs for their own incompatible designs. We can detect XMen boards 11818c2ecf20Sopenharmony_ci * by probing the sensor, but there is no way to probe the sensors on 11828c2ecf20Sopenharmony_ci * the Pelco and Adlink designs so we default to the Adlink. If it 11838c2ecf20Sopenharmony_ci * is actually a Pelco, the user must set the assume_endura module 11848c2ecf20Sopenharmony_ci * parameter. */ 11858c2ecf20Sopenharmony_ci if ((go->board_id == GO7007_BOARDID_XMEN || 11868c2ecf20Sopenharmony_ci go->board_id == GO7007_BOARDID_XMEN_III) && 11878c2ecf20Sopenharmony_ci go->i2c_adapter_online) { 11888c2ecf20Sopenharmony_ci union i2c_smbus_data data; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* Check to see if register 0x0A is 0x76 */ 11918c2ecf20Sopenharmony_ci i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB, 11928c2ecf20Sopenharmony_ci I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data); 11938c2ecf20Sopenharmony_ci if (data.byte != 0x76) { 11948c2ecf20Sopenharmony_ci if (assume_endura) { 11958c2ecf20Sopenharmony_ci go->board_id = GO7007_BOARDID_ENDURA; 11968c2ecf20Sopenharmony_ci usb->board = board = &board_endura; 11978c2ecf20Sopenharmony_ci go->board_info = &board->main_info; 11988c2ecf20Sopenharmony_ci strscpy(go->name, "Pelco Endura", 11998c2ecf20Sopenharmony_ci sizeof(go->name)); 12008c2ecf20Sopenharmony_ci } else { 12018c2ecf20Sopenharmony_ci u16 channel; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci /* read channel number from GPIO[1:0] */ 12048c2ecf20Sopenharmony_ci go7007_read_addr(go, 0x3c81, &channel); 12058c2ecf20Sopenharmony_ci channel &= 0x3; 12068c2ecf20Sopenharmony_ci go->board_id = GO7007_BOARDID_ADLINK_MPG24; 12078c2ecf20Sopenharmony_ci usb->board = board = &board_adlink_mpg24; 12088c2ecf20Sopenharmony_ci go->board_info = &board->main_info; 12098c2ecf20Sopenharmony_ci go->channel_number = channel; 12108c2ecf20Sopenharmony_ci snprintf(go->name, sizeof(go->name), 12118c2ecf20Sopenharmony_ci "Adlink PCI-MPG24, channel #%d", 12128c2ecf20Sopenharmony_ci channel); 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci go7007_update_board(go); 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci num_i2c_devs = go->board_info->num_i2c_devs; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* Probe the tuner model on the TV402U */ 12218c2ecf20Sopenharmony_ci if (go->board_id == GO7007_BOARDID_PX_TV402U) { 12228c2ecf20Sopenharmony_ci /* Board strapping indicates tuner model */ 12238c2ecf20Sopenharmony_ci if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3, 12248c2ecf20Sopenharmony_ci 1) < 0) { 12258c2ecf20Sopenharmony_ci dev_err(go->dev, "GPIO read failed!\n"); 12268c2ecf20Sopenharmony_ci goto allocfail; 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci switch (go->usb_buf[0] >> 6) { 12298c2ecf20Sopenharmony_ci case 1: 12308c2ecf20Sopenharmony_ci go->tuner_type = TUNER_SONY_BTF_PG472Z; 12318c2ecf20Sopenharmony_ci go->std = V4L2_STD_PAL; 12328c2ecf20Sopenharmony_ci strscpy(go->name, "Plextor PX-TV402U-EU", 12338c2ecf20Sopenharmony_ci sizeof(go->name)); 12348c2ecf20Sopenharmony_ci break; 12358c2ecf20Sopenharmony_ci case 2: 12368c2ecf20Sopenharmony_ci go->tuner_type = TUNER_SONY_BTF_PK467Z; 12378c2ecf20Sopenharmony_ci go->std = V4L2_STD_NTSC_M_JP; 12388c2ecf20Sopenharmony_ci num_i2c_devs -= 2; 12398c2ecf20Sopenharmony_ci strscpy(go->name, "Plextor PX-TV402U-JP", 12408c2ecf20Sopenharmony_ci sizeof(go->name)); 12418c2ecf20Sopenharmony_ci break; 12428c2ecf20Sopenharmony_ci case 3: 12438c2ecf20Sopenharmony_ci go->tuner_type = TUNER_SONY_BTF_PB463Z; 12448c2ecf20Sopenharmony_ci num_i2c_devs -= 2; 12458c2ecf20Sopenharmony_ci strscpy(go->name, "Plextor PX-TV402U-NA", 12468c2ecf20Sopenharmony_ci sizeof(go->name)); 12478c2ecf20Sopenharmony_ci break; 12488c2ecf20Sopenharmony_ci default: 12498c2ecf20Sopenharmony_ci pr_debug("unable to detect tuner type!\n"); 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci /* Configure tuner mode selection inputs connected 12538c2ecf20Sopenharmony_ci * to the EZ-USB GPIO output pins */ 12548c2ecf20Sopenharmony_ci if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0, 12558c2ecf20Sopenharmony_ci NULL, 0, 0) < 0) { 12568c2ecf20Sopenharmony_ci dev_err(go->dev, "GPIO write failed!\n"); 12578c2ecf20Sopenharmony_ci goto allocfail; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* Print a nasty message if the user attempts to use a USB2.0 device in 12628c2ecf20Sopenharmony_ci * a USB1.1 port. There will be silent corruption of the stream. */ 12638c2ecf20Sopenharmony_ci if ((board->flags & GO7007_USB_EZUSB) && 12648c2ecf20Sopenharmony_ci usbdev->speed != USB_SPEED_HIGH) 12658c2ecf20Sopenharmony_ci 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"); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* Allocate the URBs and buffers for receiving the video stream */ 12688c2ecf20Sopenharmony_ci if (board->flags & GO7007_USB_EZUSB) { 12698c2ecf20Sopenharmony_ci if (!usb->usbdev->ep_in[6]) 12708c2ecf20Sopenharmony_ci goto allocfail; 12718c2ecf20Sopenharmony_ci v_urb_len = 1024; 12728c2ecf20Sopenharmony_ci video_pipe = usb_rcvbulkpipe(usb->usbdev, 6); 12738c2ecf20Sopenharmony_ci } else { 12748c2ecf20Sopenharmony_ci if (!usb->usbdev->ep_in[1]) 12758c2ecf20Sopenharmony_ci goto allocfail; 12768c2ecf20Sopenharmony_ci v_urb_len = 512; 12778c2ecf20Sopenharmony_ci video_pipe = usb_rcvbulkpipe(usb->usbdev, 1); 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) { 12808c2ecf20Sopenharmony_ci usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); 12818c2ecf20Sopenharmony_ci if (usb->video_urbs[i] == NULL) 12828c2ecf20Sopenharmony_ci goto allocfail; 12838c2ecf20Sopenharmony_ci usb->video_urbs[i]->transfer_buffer = 12848c2ecf20Sopenharmony_ci kmalloc(v_urb_len, GFP_KERNEL); 12858c2ecf20Sopenharmony_ci if (usb->video_urbs[i]->transfer_buffer == NULL) 12868c2ecf20Sopenharmony_ci goto allocfail; 12878c2ecf20Sopenharmony_ci usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe, 12888c2ecf20Sopenharmony_ci usb->video_urbs[i]->transfer_buffer, v_urb_len, 12898c2ecf20Sopenharmony_ci go7007_usb_read_video_pipe_complete, go); 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* Allocate the URBs and buffers for receiving the audio stream */ 12938c2ecf20Sopenharmony_ci if ((board->flags & GO7007_USB_EZUSB) && 12948c2ecf20Sopenharmony_ci (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) { 12958c2ecf20Sopenharmony_ci if (!usb->usbdev->ep_in[8]) 12968c2ecf20Sopenharmony_ci goto allocfail; 12978c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) { 12988c2ecf20Sopenharmony_ci usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); 12998c2ecf20Sopenharmony_ci if (usb->audio_urbs[i] == NULL) 13008c2ecf20Sopenharmony_ci goto allocfail; 13018c2ecf20Sopenharmony_ci usb->audio_urbs[i]->transfer_buffer = kmalloc(4096, 13028c2ecf20Sopenharmony_ci GFP_KERNEL); 13038c2ecf20Sopenharmony_ci if (usb->audio_urbs[i]->transfer_buffer == NULL) 13048c2ecf20Sopenharmony_ci goto allocfail; 13058c2ecf20Sopenharmony_ci usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev, 13068c2ecf20Sopenharmony_ci usb_rcvbulkpipe(usb->usbdev, 8), 13078c2ecf20Sopenharmony_ci usb->audio_urbs[i]->transfer_buffer, 4096, 13088c2ecf20Sopenharmony_ci go7007_usb_read_audio_pipe_complete, go); 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* Do any final GO7007 initialization, then register the 13138c2ecf20Sopenharmony_ci * V4L2 and ALSA interfaces */ 13148c2ecf20Sopenharmony_ci if (go7007_register_encoder(go, num_i2c_devs) < 0) 13158c2ecf20Sopenharmony_ci goto allocfail; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci go->status = STATUS_ONLINE; 13188c2ecf20Sopenharmony_ci return 0; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ciallocfail: 13218c2ecf20Sopenharmony_ci go7007_usb_release(go); 13228c2ecf20Sopenharmony_ci kfree(go); 13238c2ecf20Sopenharmony_ci return -ENOMEM; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic void go7007_usb_disconnect(struct usb_interface *intf) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct go7007 *go = to_go7007(usb_get_intfdata(intf)); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci mutex_lock(&go->queue_lock); 13318c2ecf20Sopenharmony_ci mutex_lock(&go->serialize_lock); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (go->audio_enabled) 13348c2ecf20Sopenharmony_ci go7007_snd_remove(go); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci go->status = STATUS_SHUTDOWN; 13378c2ecf20Sopenharmony_ci v4l2_device_disconnect(&go->v4l2_dev); 13388c2ecf20Sopenharmony_ci video_unregister_device(&go->vdev); 13398c2ecf20Sopenharmony_ci mutex_unlock(&go->serialize_lock); 13408c2ecf20Sopenharmony_ci mutex_unlock(&go->queue_lock); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci v4l2_device_put(&go->v4l2_dev); 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistatic struct usb_driver go7007_usb_driver = { 13468c2ecf20Sopenharmony_ci .name = "go7007", 13478c2ecf20Sopenharmony_ci .probe = go7007_usb_probe, 13488c2ecf20Sopenharmony_ci .disconnect = go7007_usb_disconnect, 13498c2ecf20Sopenharmony_ci .id_table = go7007_usb_id_table, 13508c2ecf20Sopenharmony_ci}; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_cimodule_usb_driver(go7007_usb_driver); 13538c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1354