1357 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2005-2006 Micronas USA Inc.4 */5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt7 8#include <linux/module.h>9#include <linux/kernel.h>10#include <linux/wait.h>11#include <linux/list.h>12#include <linux/slab.h>13#include <linux/time.h>14#include <linux/mm.h>15#include <linux/usb.h>16#include <linux/i2c.h>17#include <asm/byteorder.h>18#include <media/i2c/saa7115.h>19#include <media/tuner.h>20#include <media/i2c/uda1342.h>21 22#include "go7007-priv.h"23 24static unsigned int assume_endura;25module_param(assume_endura, int, 0644);26MODULE_PARM_DESC(assume_endura,27 "when probing fails, hardware is a Pelco Endura");28 29/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */30 31#define HPI_STATUS_ADDR 0xFFF432#define INT_PARAM_ADDR 0xFFF633#define INT_INDEX_ADDR 0xFFF834 35/*36 * Pipes on EZ-USB interface:37 * 0 snd - Control38 * 0 rcv - Control39 * 2 snd - Download firmware (control)40 * 4 rcv - Read Interrupt (interrupt)41 * 6 rcv - Read Video (bulk)42 * 8 rcv - Read Audio (bulk)43 */44 45#define GO7007_USB_EZUSB (1<<0)46#define GO7007_USB_EZUSB_I2C (1<<1)47 48struct go7007_usb_board {49 unsigned int flags;50 struct go7007_board_info main_info;51};52 53struct go7007_usb {54 const struct go7007_usb_board *board;55 struct mutex i2c_lock;56 struct usb_device *usbdev;57 struct urb *video_urbs[8];58 struct urb *audio_urbs[8];59 struct urb *intr_urb;60};61 62/*********************** Product specification data ***********************/63 64static const struct go7007_usb_board board_matrix_ii = {65 .flags = GO7007_USB_EZUSB,66 .main_info = {67 .flags = GO7007_BOARD_HAS_AUDIO |68 GO7007_BOARD_USE_ONBOARD_I2C,69 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |70 GO7007_AUDIO_WORD_16,71 .audio_rate = 48000,72 .audio_bclk_div = 8,73 .audio_main_div = 2,74 .hpi_buffer_cap = 7,75 .sensor_flags = GO7007_SENSOR_656 |76 GO7007_SENSOR_VALID_ENABLE |77 GO7007_SENSOR_TV |78 GO7007_SENSOR_SAA7115 |79 GO7007_SENSOR_VBI |80 GO7007_SENSOR_SCALING,81 .num_i2c_devs = 1,82 .i2c_devs = {83 {84 .type = "saa7115",85 .addr = 0x20,86 .is_video = 1,87 },88 },89 .num_inputs = 2,90 .inputs = {91 {92 .video_input = 0,93 .name = "Composite",94 },95 {96 .video_input = 9,97 .name = "S-Video",98 },99 },100 .video_config = SAA7115_IDQ_IS_DEFAULT,101 },102};103 104static const struct go7007_usb_board board_matrix_reload = {105 .flags = GO7007_USB_EZUSB,106 .main_info = {107 .flags = GO7007_BOARD_HAS_AUDIO |108 GO7007_BOARD_USE_ONBOARD_I2C,109 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |110 GO7007_AUDIO_I2S_MASTER |111 GO7007_AUDIO_WORD_16,112 .audio_rate = 48000,113 .audio_bclk_div = 8,114 .audio_main_div = 2,115 .hpi_buffer_cap = 7,116 .sensor_flags = GO7007_SENSOR_656 |117 GO7007_SENSOR_TV,118 .num_i2c_devs = 1,119 .i2c_devs = {120 {121 .type = "saa7113",122 .addr = 0x25,123 .is_video = 1,124 },125 },126 .num_inputs = 2,127 .inputs = {128 {129 .video_input = 0,130 .name = "Composite",131 },132 {133 .video_input = 9,134 .name = "S-Video",135 },136 },137 .video_config = SAA7115_IDQ_IS_DEFAULT,138 },139};140 141static const struct go7007_usb_board board_star_trek = {142 .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,143 .main_info = {144 .flags = GO7007_BOARD_HAS_AUDIO, /* |145 GO7007_BOARD_HAS_TUNER, */146 .sensor_flags = GO7007_SENSOR_656 |147 GO7007_SENSOR_VALID_ENABLE |148 GO7007_SENSOR_TV |149 GO7007_SENSOR_SAA7115 |150 GO7007_SENSOR_VBI |151 GO7007_SENSOR_SCALING,152 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |153 GO7007_AUDIO_WORD_16,154 .audio_bclk_div = 8,155 .audio_main_div = 2,156 .hpi_buffer_cap = 7,157 .num_i2c_devs = 1,158 .i2c_devs = {159 {160 .type = "saa7115",161 .addr = 0x20,162 .is_video = 1,163 },164 },165 .num_inputs = 2,166 .inputs = {167 /* {168 * .video_input = 3,169 * .audio_index = AUDIO_TUNER,170 * .name = "Tuner",171 * },172 */173 {174 .video_input = 1,175 /* .audio_index = AUDIO_EXTERN, */176 .name = "Composite",177 },178 {179 .video_input = 8,180 /* .audio_index = AUDIO_EXTERN, */181 .name = "S-Video",182 },183 },184 .video_config = SAA7115_IDQ_IS_DEFAULT,185 },186};187 188static const struct go7007_usb_board board_px_tv402u = {189 .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,190 .main_info = {191 .flags = GO7007_BOARD_HAS_AUDIO |192 GO7007_BOARD_HAS_TUNER,193 .sensor_flags = GO7007_SENSOR_656 |194 GO7007_SENSOR_VALID_ENABLE |195 GO7007_SENSOR_TV |196 GO7007_SENSOR_SAA7115 |197 GO7007_SENSOR_VBI |198 GO7007_SENSOR_SCALING,199 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |200 GO7007_AUDIO_WORD_16,201 .audio_bclk_div = 8,202 .audio_main_div = 2,203 .hpi_buffer_cap = 7,204 .num_i2c_devs = 5,205 .i2c_devs = {206 {207 .type = "saa7115",208 .addr = 0x20,209 .is_video = 1,210 },211 {212 .type = "uda1342",213 .addr = 0x1a,214 .is_audio = 1,215 },216 {217 .type = "tuner",218 .addr = 0x60,219 },220 {221 .type = "tuner",222 .addr = 0x43,223 },224 {225 .type = "sony-btf-mpx",226 .addr = 0x44,227 },228 },229 .num_inputs = 3,230 .inputs = {231 {232 .video_input = 3,233 .audio_index = 0,234 .name = "Tuner",235 },236 {237 .video_input = 1,238 .audio_index = 1,239 .name = "Composite",240 },241 {242 .video_input = 8,243 .audio_index = 1,244 .name = "S-Video",245 },246 },247 .video_config = SAA7115_IDQ_IS_DEFAULT,248 .num_aud_inputs = 2,249 .aud_inputs = {250 {251 .audio_input = UDA1342_IN2,252 .name = "Tuner",253 },254 {255 .audio_input = UDA1342_IN1,256 .name = "Line In",257 },258 },259 },260};261 262static const struct go7007_usb_board board_xmen = {263 .flags = 0,264 .main_info = {265 .flags = GO7007_BOARD_USE_ONBOARD_I2C,266 .hpi_buffer_cap = 0,267 .sensor_flags = GO7007_SENSOR_VREF_POLAR,268 .sensor_width = 320,269 .sensor_height = 240,270 .sensor_framerate = 30030,271 .audio_flags = GO7007_AUDIO_ONE_CHANNEL |272 GO7007_AUDIO_I2S_MODE_3 |273 GO7007_AUDIO_WORD_14 |274 GO7007_AUDIO_I2S_MASTER |275 GO7007_AUDIO_BCLK_POLAR |276 GO7007_AUDIO_OKI_MODE,277 .audio_rate = 8000,278 .audio_bclk_div = 48,279 .audio_main_div = 1,280 .num_i2c_devs = 1,281 .i2c_devs = {282 {283 .type = "ov7640",284 .addr = 0x21,285 },286 },287 .num_inputs = 1,288 .inputs = {289 {290 .name = "Camera",291 },292 },293 },294};295 296static const struct go7007_usb_board board_matrix_revolution = {297 .flags = GO7007_USB_EZUSB,298 .main_info = {299 .flags = GO7007_BOARD_HAS_AUDIO |300 GO7007_BOARD_USE_ONBOARD_I2C,301 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |302 GO7007_AUDIO_I2S_MASTER |303 GO7007_AUDIO_WORD_16,304 .audio_rate = 48000,305 .audio_bclk_div = 8,306 .audio_main_div = 2,307 .hpi_buffer_cap = 7,308 .sensor_flags = GO7007_SENSOR_656 |309 GO7007_SENSOR_TV |310 GO7007_SENSOR_VBI,311 .num_i2c_devs = 1,312 .i2c_devs = {313 {314 .type = "tw9903",315 .is_video = 1,316 .addr = 0x44,317 },318 },319 .num_inputs = 2,320 .inputs = {321 {322 .video_input = 2,323 .name = "Composite",324 },325 {326 .video_input = 8,327 .name = "S-Video",328 },329 },330 },331};332 333#if 0334static const struct go7007_usb_board board_lifeview_lr192 = {335 .flags = GO7007_USB_EZUSB,336 .main_info = {337 .flags = GO7007_BOARD_HAS_AUDIO |338 GO7007_BOARD_USE_ONBOARD_I2C,339 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |340 GO7007_AUDIO_WORD_16,341 .audio_rate = 48000,342 .audio_bclk_div = 8,343 .audio_main_div = 2,344 .hpi_buffer_cap = 7,345 .sensor_flags = GO7007_SENSOR_656 |346 GO7007_SENSOR_VALID_ENABLE |347 GO7007_SENSOR_TV |348 GO7007_SENSOR_VBI |349 GO7007_SENSOR_SCALING,350 .num_i2c_devs = 0,351 .num_inputs = 1,352 .inputs = {353 {354 .video_input = 0,355 .name = "Composite",356 },357 },358 },359};360#endif361 362static const struct go7007_usb_board board_endura = {363 .flags = 0,364 .main_info = {365 .flags = 0,366 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |367 GO7007_AUDIO_I2S_MASTER |368 GO7007_AUDIO_WORD_16,369 .audio_rate = 8000,370 .audio_bclk_div = 48,371 .audio_main_div = 8,372 .hpi_buffer_cap = 0,373 .sensor_flags = GO7007_SENSOR_656 |374 GO7007_SENSOR_TV,375 .sensor_h_offset = 8,376 .num_i2c_devs = 0,377 .num_inputs = 1,378 .inputs = {379 {380 .name = "Camera",381 },382 },383 },384};385 386static const struct go7007_usb_board board_adlink_mpg24 = {387 .flags = 0,388 .main_info = {389 .flags = GO7007_BOARD_USE_ONBOARD_I2C,390 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |391 GO7007_AUDIO_I2S_MASTER |392 GO7007_AUDIO_WORD_16,393 .audio_rate = 48000,394 .audio_bclk_div = 8,395 .audio_main_div = 2,396 .hpi_buffer_cap = 0,397 .sensor_flags = GO7007_SENSOR_656 |398 GO7007_SENSOR_TV |399 GO7007_SENSOR_VBI,400 .num_i2c_devs = 1,401 .i2c_devs = {402 {403 .type = "tw2804",404 .addr = 0x00, /* yes, really */405 .flags = I2C_CLIENT_TEN,406 .is_video = 1,407 },408 },409 .num_inputs = 1,410 .inputs = {411 {412 .name = "Composite",413 },414 },415 },416};417 418static const struct go7007_usb_board board_sensoray_2250 = {419 .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,420 .main_info = {421 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |422 GO7007_AUDIO_I2S_MASTER |423 GO7007_AUDIO_WORD_16,424 .flags = GO7007_BOARD_HAS_AUDIO,425 .audio_rate = 48000,426 .audio_bclk_div = 8,427 .audio_main_div = 2,428 .hpi_buffer_cap = 7,429 .sensor_flags = GO7007_SENSOR_656 |430 GO7007_SENSOR_TV,431 .num_i2c_devs = 1,432 .i2c_devs = {433 {434 .type = "s2250",435 .addr = 0x43,436 .is_video = 1,437 .is_audio = 1,438 },439 },440 .num_inputs = 2,441 .inputs = {442 {443 .video_input = 0,444 .name = "Composite",445 },446 {447 .video_input = 1,448 .name = "S-Video",449 },450 },451 .num_aud_inputs = 3,452 .aud_inputs = {453 {454 .audio_input = 0,455 .name = "Line In",456 },457 {458 .audio_input = 1,459 .name = "Mic",460 },461 {462 .audio_input = 2,463 .name = "Mic Boost",464 },465 },466 },467};468 469static const struct go7007_usb_board board_ads_usbav_709 = {470 .flags = GO7007_USB_EZUSB,471 .main_info = {472 .flags = GO7007_BOARD_HAS_AUDIO |473 GO7007_BOARD_USE_ONBOARD_I2C,474 .audio_flags = GO7007_AUDIO_I2S_MODE_1 |475 GO7007_AUDIO_I2S_MASTER |476 GO7007_AUDIO_WORD_16,477 .audio_rate = 48000,478 .audio_bclk_div = 8,479 .audio_main_div = 2,480 .hpi_buffer_cap = 7,481 .sensor_flags = GO7007_SENSOR_656 |482 GO7007_SENSOR_TV |483 GO7007_SENSOR_VBI,484 .num_i2c_devs = 1,485 .i2c_devs = {486 {487 .type = "tw9906",488 .is_video = 1,489 .addr = 0x44,490 },491 },492 .num_inputs = 2,493 .inputs = {494 {495 .video_input = 0,496 .name = "Composite",497 },498 {499 .video_input = 10,500 .name = "S-Video",501 },502 },503 },504};505 506static const struct usb_device_id go7007_usb_id_table[] = {507 {508 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |509 USB_DEVICE_ID_MATCH_INT_INFO,510 .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */511 .idProduct = 0x7007, /* Product ID of GO7007SB chip */512 .bcdDevice_lo = 0x200, /* Revision number of XMen */513 .bcdDevice_hi = 0x200,514 .bInterfaceClass = 255,515 .bInterfaceSubClass = 0,516 .bInterfaceProtocol = 255,517 .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN,518 },519 {520 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,521 .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */522 .idProduct = 0x7007, /* Product ID of GO7007SB chip */523 .bcdDevice_lo = 0x202, /* Revision number of Matrix II */524 .bcdDevice_hi = 0x202,525 .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,526 },527 {528 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,529 .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */530 .idProduct = 0x7007, /* Product ID of GO7007SB chip */531 .bcdDevice_lo = 0x204, /* Revision number of Matrix */532 .bcdDevice_hi = 0x204, /* Reloaded */533 .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,534 },535 {536 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |537 USB_DEVICE_ID_MATCH_INT_INFO,538 .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */539 .idProduct = 0x7007, /* Product ID of GO7007SB chip */540 .bcdDevice_lo = 0x205, /* Revision number of XMen-II */541 .bcdDevice_hi = 0x205,542 .bInterfaceClass = 255,543 .bInterfaceSubClass = 0,544 .bInterfaceProtocol = 255,545 .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II,546 },547 {548 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,549 .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */550 .idProduct = 0x7007, /* Product ID of GO7007SB chip */551 .bcdDevice_lo = 0x208, /* Revision number of Star Trek */552 .bcdDevice_hi = 0x208,553 .driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK,554 },555 {556 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |557 USB_DEVICE_ID_MATCH_INT_INFO,558 .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */559 .idProduct = 0x7007, /* Product ID of GO7007SB chip */560 .bcdDevice_lo = 0x209, /* Revision number of XMen-III */561 .bcdDevice_hi = 0x209,562 .bInterfaceClass = 255,563 .bInterfaceSubClass = 0,564 .bInterfaceProtocol = 255,565 .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III,566 },567 {568 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,569 .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */570 .idProduct = 0x7007, /* Product ID of GO7007SB chip */571 .bcdDevice_lo = 0x210, /* Revision number of Matrix */572 .bcdDevice_hi = 0x210, /* Revolution */573 .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV,574 },575 {576 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,577 .idVendor = 0x093b, /* Vendor ID of Plextor */578 .idProduct = 0xa102, /* Product ID of M402U */579 .bcdDevice_lo = 0x1, /* revision number of Blueberry */580 .bcdDevice_hi = 0x1,581 .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U,582 },583 {584 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,585 .idVendor = 0x093b, /* Vendor ID of Plextor */586 .idProduct = 0xa104, /* Product ID of TV402U */587 .bcdDevice_lo = 0x1,588 .bcdDevice_hi = 0x1,589 .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U,590 },591 {592 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,593 .idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */594 .idProduct = 0xde00, /* Product ID of Lifeview LR192 */595 .bcdDevice_lo = 0x1,596 .bcdDevice_hi = 0x1,597 .driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192,598 },599 {600 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,601 .idVendor = 0x1943, /* Vendor ID Sensoray */602 .idProduct = 0x2250, /* Product ID of 2250/2251 */603 .bcdDevice_lo = 0x1,604 .bcdDevice_hi = 0x1,605 .driver_info = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250,606 },607 {608 .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,609 .idVendor = 0x06e1, /* Vendor ID of ADS Technologies */610 .idProduct = 0x0709, /* Product ID of DVD Xpress DX2 */611 .bcdDevice_lo = 0x204,612 .bcdDevice_hi = 0x204,613 .driver_info = (kernel_ulong_t)GO7007_BOARDID_ADS_USBAV_709,614 },615 { } /* Terminating entry */616};617 618MODULE_DEVICE_TABLE(usb, go7007_usb_id_table);619 620/********************* Driver for EZ-USB HPI interface *********************/621 622static int go7007_usb_vendor_request(struct go7007 *go, int request,623 int value, int index, void *transfer_buffer, int length, int in)624{625 struct go7007_usb *usb = go->hpi_context;626 int timeout = 5000;627 628 if (in) {629 return usb_control_msg(usb->usbdev,630 usb_rcvctrlpipe(usb->usbdev, 0), request,631 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,632 value, index, transfer_buffer, length, timeout);633 } else {634 return usb_control_msg(usb->usbdev,635 usb_sndctrlpipe(usb->usbdev, 0), request,636 USB_TYPE_VENDOR | USB_RECIP_DEVICE,637 value, index, transfer_buffer, length, timeout);638 }639}640 641static int go7007_usb_interface_reset(struct go7007 *go)642{643 struct go7007_usb *usb = go->hpi_context;644 u16 intr_val, intr_data;645 646 if (go->status == STATUS_SHUTDOWN)647 return -1;648 /* Reset encoder */649 if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)650 return -1;651 msleep(100);652 653 if (usb->board->flags & GO7007_USB_EZUSB) {654 /* Reset buffer in EZ-USB */655 pr_debug("resetting EZ-USB buffers\n");656 if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 ||657 go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0)658 return -1;659 660 /* Reset encoder again */661 if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)662 return -1;663 msleep(100);664 }665 666 /* Wait for an interrupt to indicate successful hardware reset */667 if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||668 (intr_val & ~0x1) != 0x55aa) {669 dev_err(go->dev, "unable to reset the USB interface\n");670 return -1;671 }672 return 0;673}674 675static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,676 int addr, int data)677{678 struct go7007_usb *usb = go->hpi_context;679 int i, r;680 u16 status_reg = 0;681 int timeout = 500;682 683 pr_debug("WriteInterrupt: %04x %04x\n", addr, data);684 685 for (i = 0; i < 100; ++i) {686 r = usb_control_msg(usb->usbdev,687 usb_rcvctrlpipe(usb->usbdev, 0), 0x14,688 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,689 0, HPI_STATUS_ADDR, go->usb_buf,690 sizeof(status_reg), timeout);691 if (r < 0)692 break;693 status_reg = le16_to_cpu(*((__le16 *)go->usb_buf));694 if (!(status_reg & 0x0010))695 break;696 msleep(10);697 }698 if (r < 0)699 goto write_int_error;700 if (i == 100) {701 dev_err(go->dev, "device is hung, status reg = 0x%04x\n", status_reg);702 return -1;703 }704 r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12,705 USB_TYPE_VENDOR | USB_RECIP_DEVICE, data,706 INT_PARAM_ADDR, NULL, 0, timeout);707 if (r < 0)708 goto write_int_error;709 r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0),710 0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr,711 INT_INDEX_ADDR, NULL, 0, timeout);712 if (r < 0)713 goto write_int_error;714 return 0;715 716write_int_error:717 dev_err(go->dev, "error in WriteInterrupt: %d\n", r);718 return r;719}720 721static int go7007_usb_onboard_write_interrupt(struct go7007 *go,722 int addr, int data)723{724 struct go7007_usb *usb = go->hpi_context;725 int r;726 int timeout = 500;727 728 pr_debug("WriteInterrupt: %04x %04x\n", addr, data);729 730 go->usb_buf[0] = data & 0xff;731 go->usb_buf[1] = data >> 8;732 go->usb_buf[2] = addr & 0xff;733 go->usb_buf[3] = addr >> 8;734 go->usb_buf[4] = go->usb_buf[5] = go->usb_buf[6] = go->usb_buf[7] = 0;735 r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00,736 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa,737 0xf0f0, go->usb_buf, 8, timeout);738 if (r < 0) {739 dev_err(go->dev, "error in WriteInterrupt: %d\n", r);740 return r;741 }742 return 0;743}744 745static void go7007_usb_readinterrupt_complete(struct urb *urb)746{747 struct go7007 *go = (struct go7007 *)urb->context;748 __le16 *regs = (__le16 *)urb->transfer_buffer;749 int status = urb->status;750 751 if (status) {752 if (status != -ESHUTDOWN &&753 go->status != STATUS_SHUTDOWN) {754 dev_err(go->dev, "error in read interrupt: %d\n", urb->status);755 } else {756 wake_up(&go->interrupt_waitq);757 return;758 }759 } else if (urb->actual_length != urb->transfer_buffer_length) {760 dev_err(go->dev, "short read in interrupt pipe!\n");761 } else {762 go->interrupt_available = 1;763 go->interrupt_data = __le16_to_cpu(regs[0]);764 go->interrupt_value = __le16_to_cpu(regs[1]);765 pr_debug("ReadInterrupt: %04x %04x\n",766 go->interrupt_value, go->interrupt_data);767 }768 769 wake_up(&go->interrupt_waitq);770}771 772static int go7007_usb_read_interrupt(struct go7007 *go)773{774 struct go7007_usb *usb = go->hpi_context;775 int r;776 777 r = usb_submit_urb(usb->intr_urb, GFP_KERNEL);778 if (r < 0) {779 dev_err(go->dev, "unable to submit interrupt urb: %d\n", r);780 return r;781 }782 return 0;783}784 785static void go7007_usb_read_video_pipe_complete(struct urb *urb)786{787 struct go7007 *go = (struct go7007 *)urb->context;788 int r, status = urb->status;789 790 if (!vb2_is_streaming(&go->vidq)) {791 wake_up_interruptible(&go->frame_waitq);792 return;793 }794 if (status) {795 dev_err(go->dev, "error in video pipe: %d\n", status);796 return;797 }798 if (urb->actual_length != urb->transfer_buffer_length) {799 dev_err(go->dev, "short read in video pipe!\n");800 return;801 }802 go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length);803 r = usb_submit_urb(urb, GFP_ATOMIC);804 if (r < 0)805 dev_err(go->dev, "error in video pipe: %d\n", r);806}807 808static void go7007_usb_read_audio_pipe_complete(struct urb *urb)809{810 struct go7007 *go = (struct go7007 *)urb->context;811 int r, status = urb->status;812 813 if (!vb2_is_streaming(&go->vidq))814 return;815 if (status) {816 dev_err(go->dev, "error in audio pipe: %d\n",817 status);818 return;819 }820 if (urb->actual_length != urb->transfer_buffer_length) {821 dev_err(go->dev, "short read in audio pipe!\n");822 return;823 }824 if (go->audio_deliver != NULL)825 go->audio_deliver(go, urb->transfer_buffer, urb->actual_length);826 r = usb_submit_urb(urb, GFP_ATOMIC);827 if (r < 0)828 dev_err(go->dev, "error in audio pipe: %d\n", r);829}830 831static int go7007_usb_stream_start(struct go7007 *go)832{833 struct go7007_usb *usb = go->hpi_context;834 int i, r;835 836 for (i = 0; i < 8; ++i) {837 r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL);838 if (r < 0) {839 dev_err(go->dev, "error submitting video urb %d: %d\n", i, r);840 goto video_submit_failed;841 }842 }843 if (!go->audio_enabled)844 return 0;845 846 for (i = 0; i < 8; ++i) {847 r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL);848 if (r < 0) {849 dev_err(go->dev, "error submitting audio urb %d: %d\n", i, r);850 goto audio_submit_failed;851 }852 }853 return 0;854 855audio_submit_failed:856 for (i = 0; i < 7; ++i)857 usb_kill_urb(usb->audio_urbs[i]);858video_submit_failed:859 for (i = 0; i < 8; ++i)860 usb_kill_urb(usb->video_urbs[i]);861 return -1;862}863 864static int go7007_usb_stream_stop(struct go7007 *go)865{866 struct go7007_usb *usb = go->hpi_context;867 int i;868 869 if (go->status == STATUS_SHUTDOWN)870 return 0;871 for (i = 0; i < 8; ++i)872 usb_kill_urb(usb->video_urbs[i]);873 if (go->audio_enabled)874 for (i = 0; i < 8; ++i)875 usb_kill_urb(usb->audio_urbs[i]);876 return 0;877}878 879static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)880{881 struct go7007_usb *usb = go->hpi_context;882 int transferred, pipe;883 int timeout = 500;884 885 pr_debug("DownloadBuffer sending %d bytes\n", len);886 887 if (usb->board->flags & GO7007_USB_EZUSB)888 pipe = usb_sndbulkpipe(usb->usbdev, 2);889 else890 pipe = usb_sndbulkpipe(usb->usbdev, 3);891 892 return usb_bulk_msg(usb->usbdev, pipe, data, len,893 &transferred, timeout);894}895 896static void go7007_usb_release(struct go7007 *go)897{898 struct go7007_usb *usb = go->hpi_context;899 struct urb *vurb, *aurb;900 int i;901 902 if (usb->intr_urb) {903 usb_kill_urb(usb->intr_urb);904 kfree(usb->intr_urb->transfer_buffer);905 usb_free_urb(usb->intr_urb);906 }907 908 /* Free USB-related structs */909 for (i = 0; i < 8; ++i) {910 vurb = usb->video_urbs[i];911 if (vurb) {912 usb_kill_urb(vurb);913 kfree(vurb->transfer_buffer);914 usb_free_urb(vurb);915 }916 aurb = usb->audio_urbs[i];917 if (aurb) {918 usb_kill_urb(aurb);919 kfree(aurb->transfer_buffer);920 usb_free_urb(aurb);921 }922 }923 924 kfree(go->hpi_context);925}926 927static const struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {928 .interface_reset = go7007_usb_interface_reset,929 .write_interrupt = go7007_usb_ezusb_write_interrupt,930 .read_interrupt = go7007_usb_read_interrupt,931 .stream_start = go7007_usb_stream_start,932 .stream_stop = go7007_usb_stream_stop,933 .send_firmware = go7007_usb_send_firmware,934 .release = go7007_usb_release,935};936 937static const struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {938 .interface_reset = go7007_usb_interface_reset,939 .write_interrupt = go7007_usb_onboard_write_interrupt,940 .read_interrupt = go7007_usb_read_interrupt,941 .stream_start = go7007_usb_stream_start,942 .stream_stop = go7007_usb_stream_stop,943 .send_firmware = go7007_usb_send_firmware,944 .release = go7007_usb_release,945};946 947/********************* Driver for EZ-USB I2C adapter *********************/948 949static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,950 struct i2c_msg msgs[], int num)951{952 struct go7007 *go = i2c_get_adapdata(adapter);953 struct go7007_usb *usb = go->hpi_context;954 u8 *buf = go->usb_buf;955 int buf_len, i;956 int ret = -EIO;957 958 if (go->status == STATUS_SHUTDOWN)959 return -ENODEV;960 961 mutex_lock(&usb->i2c_lock);962 963 for (i = 0; i < num; ++i) {964 /* The hardware command is "write some bytes then read some965 * bytes", so we try to coalesce a write followed by a read966 * into a single USB transaction */967 if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr &&968 !(msgs[i].flags & I2C_M_RD) &&969 (msgs[i + 1].flags & I2C_M_RD)) {970#ifdef GO7007_I2C_DEBUG971 pr_debug("i2c write/read %d/%d bytes on %02x\n",972 msgs[i].len, msgs[i + 1].len, msgs[i].addr);973#endif974 buf[0] = 0x01;975 buf[1] = msgs[i].len + 1;976 buf[2] = msgs[i].addr << 1;977 memcpy(&buf[3], msgs[i].buf, msgs[i].len);978 buf_len = msgs[i].len + 3;979 buf[buf_len++] = msgs[++i].len;980 } else if (msgs[i].flags & I2C_M_RD) {981#ifdef GO7007_I2C_DEBUG982 pr_debug("i2c read %d bytes on %02x\n",983 msgs[i].len, msgs[i].addr);984#endif985 buf[0] = 0x01;986 buf[1] = 1;987 buf[2] = msgs[i].addr << 1;988 buf[3] = msgs[i].len;989 buf_len = 4;990 } else {991#ifdef GO7007_I2C_DEBUG992 pr_debug("i2c write %d bytes on %02x\n",993 msgs[i].len, msgs[i].addr);994#endif995 buf[0] = 0x00;996 buf[1] = msgs[i].len + 1;997 buf[2] = msgs[i].addr << 1;998 memcpy(&buf[3], msgs[i].buf, msgs[i].len);999 buf_len = msgs[i].len + 3;1000 buf[buf_len++] = 0;1001 }1002 if (go7007_usb_vendor_request(go, 0x24, 0, 0,1003 buf, buf_len, 0) < 0)1004 goto i2c_done;1005 if (msgs[i].flags & I2C_M_RD) {1006 memset(buf, 0, msgs[i].len + 1);1007 if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,1008 msgs[i].len + 1, 1) < 0)1009 goto i2c_done;1010 memcpy(msgs[i].buf, buf + 1, msgs[i].len);1011 }1012 }1013 ret = num;1014 1015i2c_done:1016 mutex_unlock(&usb->i2c_lock);1017 return ret;1018}1019 1020static u32 go7007_usb_functionality(struct i2c_adapter *adapter)1021{1022 /* No errors are reported by the hardware, so we don't bother1023 * supporting quick writes to avoid confusing probing */1024 return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK;1025}1026 1027static const struct i2c_algorithm go7007_usb_algo = {1028 .master_xfer = go7007_usb_i2c_master_xfer,1029 .functionality = go7007_usb_functionality,1030};1031 1032static struct i2c_adapter go7007_usb_adap_templ = {1033 .owner = THIS_MODULE,1034 .name = "WIS GO7007SB EZ-USB",1035 .algo = &go7007_usb_algo,1036};1037 1038/********************* USB add/remove functions *********************/1039 1040static int go7007_usb_probe(struct usb_interface *intf,1041 const struct usb_device_id *id)1042{1043 struct go7007 *go;1044 struct go7007_usb *usb;1045 const struct go7007_usb_board *board;1046 struct usb_device *usbdev = interface_to_usbdev(intf);1047 struct usb_host_endpoint *ep;1048 unsigned num_i2c_devs;1049 char *name;1050 int video_pipe, i, v_urb_len;1051 1052 pr_debug("probing new GO7007 USB board\n");1053 1054 switch (id->driver_info) {1055 case GO7007_BOARDID_MATRIX_II:1056 name = "WIS Matrix II or compatible";1057 board = &board_matrix_ii;1058 break;1059 case GO7007_BOARDID_MATRIX_RELOAD:1060 name = "WIS Matrix Reloaded or compatible";1061 board = &board_matrix_reload;1062 break;1063 case GO7007_BOARDID_MATRIX_REV:1064 name = "WIS Matrix Revolution or compatible";1065 board = &board_matrix_revolution;1066 break;1067 case GO7007_BOARDID_STAR_TREK:1068 name = "WIS Star Trek or compatible";1069 board = &board_star_trek;1070 break;1071 case GO7007_BOARDID_XMEN:1072 name = "WIS XMen or compatible";1073 board = &board_xmen;1074 break;1075 case GO7007_BOARDID_XMEN_II:1076 name = "WIS XMen II or compatible";1077 board = &board_xmen;1078 break;1079 case GO7007_BOARDID_XMEN_III:1080 name = "WIS XMen III or compatible";1081 board = &board_xmen;1082 break;1083 case GO7007_BOARDID_PX_M402U:1084 name = "Plextor PX-M402U";1085 board = &board_matrix_ii;1086 break;1087 case GO7007_BOARDID_PX_TV402U:1088 name = "Plextor PX-TV402U (unknown tuner)";1089 board = &board_px_tv402u;1090 break;1091 case GO7007_BOARDID_LIFEVIEW_LR192:1092 dev_err(&intf->dev, "The Lifeview TV Walker Ultra is not supported. Sorry!\n");1093 return -ENODEV;1094#if 01095 name = "Lifeview TV Walker Ultra";1096 board = &board_lifeview_lr192;1097#endif1098 break;1099 case GO7007_BOARDID_SENSORAY_2250:1100 dev_info(&intf->dev, "Sensoray 2250 found\n");1101 name = "Sensoray 2250/2251";1102 board = &board_sensoray_2250;1103 break;1104 case GO7007_BOARDID_ADS_USBAV_709:1105 name = "ADS Tech DVD Xpress DX2";1106 board = &board_ads_usbav_709;1107 break;1108 default:1109 dev_err(&intf->dev, "unknown board ID %d!\n",1110 (unsigned int)id->driver_info);1111 return -ENODEV;1112 }1113 1114 go = go7007_alloc(&board->main_info, &intf->dev);1115 if (go == NULL)1116 return -ENOMEM;1117 1118 usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL);1119 if (usb == NULL) {1120 kfree(go);1121 return -ENOMEM;1122 }1123 1124 usb->board = board;1125 usb->usbdev = usbdev;1126 usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info));1127 go->board_id = id->driver_info;1128 strscpy(go->name, name, sizeof(go->name));1129 if (board->flags & GO7007_USB_EZUSB)1130 go->hpi_ops = &go7007_usb_ezusb_hpi_ops;1131 else1132 go->hpi_ops = &go7007_usb_onboard_hpi_ops;1133 go->hpi_context = usb;1134 1135 ep = usb->usbdev->ep_in[4];1136 if (!ep)1137 goto allocfail;1138 1139 /* Allocate the URB and buffer for receiving incoming interrupts */1140 usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);1141 if (usb->intr_urb == NULL)1142 goto allocfail;1143 usb->intr_urb->transfer_buffer = kmalloc_array(2, sizeof(u16),1144 GFP_KERNEL);1145 if (usb->intr_urb->transfer_buffer == NULL)1146 goto allocfail;1147 1148 if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)1149 usb_fill_bulk_urb(usb->intr_urb, usb->usbdev,1150 usb_rcvbulkpipe(usb->usbdev, 4),1151 usb->intr_urb->transfer_buffer, 2*sizeof(u16),1152 go7007_usb_readinterrupt_complete, go);1153 else1154 usb_fill_int_urb(usb->intr_urb, usb->usbdev,1155 usb_rcvintpipe(usb->usbdev, 4),1156 usb->intr_urb->transfer_buffer, 2*sizeof(u16),1157 go7007_usb_readinterrupt_complete, go, 8);1158 usb_set_intfdata(intf, &go->v4l2_dev);1159 1160 /* Boot the GO7007 */1161 if (go7007_boot_encoder(go, go->board_info->flags &1162 GO7007_BOARD_USE_ONBOARD_I2C) < 0)1163 goto allocfail;1164 1165 /* Register the EZ-USB I2C adapter, if we're using it */1166 if (board->flags & GO7007_USB_EZUSB_I2C) {1167 memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,1168 sizeof(go7007_usb_adap_templ));1169 mutex_init(&usb->i2c_lock);1170 go->i2c_adapter.dev.parent = go->dev;1171 i2c_set_adapdata(&go->i2c_adapter, go);1172 if (i2c_add_adapter(&go->i2c_adapter) < 0) {1173 dev_err(go->dev, "error: i2c_add_adapter failed\n");1174 goto allocfail;1175 }1176 go->i2c_adapter_online = 1;1177 }1178 1179 /* Pelco and Adlink reused the XMen and XMen-III vendor and product1180 * IDs for their own incompatible designs. We can detect XMen boards1181 * by probing the sensor, but there is no way to probe the sensors on1182 * the Pelco and Adlink designs so we default to the Adlink. If it1183 * is actually a Pelco, the user must set the assume_endura module1184 * parameter. */1185 if ((go->board_id == GO7007_BOARDID_XMEN ||1186 go->board_id == GO7007_BOARDID_XMEN_III) &&1187 go->i2c_adapter_online) {1188 union i2c_smbus_data data;1189 1190 /* Check to see if register 0x0A is 0x76 */1191 i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,1192 I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);1193 if (data.byte != 0x76) {1194 if (assume_endura) {1195 go->board_id = GO7007_BOARDID_ENDURA;1196 usb->board = board = &board_endura;1197 go->board_info = &board->main_info;1198 strscpy(go->name, "Pelco Endura",1199 sizeof(go->name));1200 } else {1201 u16 channel;1202 1203 /* read channel number from GPIO[1:0] */1204 if (go7007_read_addr(go, 0x3c81, &channel))1205 goto allocfail;1206 1207 channel &= 0x3;1208 go->board_id = GO7007_BOARDID_ADLINK_MPG24;1209 usb->board = board = &board_adlink_mpg24;1210 go->board_info = &board->main_info;1211 go->channel_number = channel;1212 snprintf(go->name, sizeof(go->name),1213 "Adlink PCI-MPG24, channel #%d",1214 channel);1215 }1216 go7007_update_board(go);1217 }1218 }1219 1220 num_i2c_devs = go->board_info->num_i2c_devs;1221 1222 /* Probe the tuner model on the TV402U */1223 if (go->board_id == GO7007_BOARDID_PX_TV402U) {1224 /* Board strapping indicates tuner model */1225 if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3,1226 1) < 0) {1227 dev_err(go->dev, "GPIO read failed!\n");1228 goto allocfail;1229 }1230 switch (go->usb_buf[0] >> 6) {1231 case 1:1232 go->tuner_type = TUNER_SONY_BTF_PG472Z;1233 go->std = V4L2_STD_PAL;1234 strscpy(go->name, "Plextor PX-TV402U-EU",1235 sizeof(go->name));1236 break;1237 case 2:1238 go->tuner_type = TUNER_SONY_BTF_PK467Z;1239 go->std = V4L2_STD_NTSC_M_JP;1240 num_i2c_devs -= 2;1241 strscpy(go->name, "Plextor PX-TV402U-JP",1242 sizeof(go->name));1243 break;1244 case 3:1245 go->tuner_type = TUNER_SONY_BTF_PB463Z;1246 num_i2c_devs -= 2;1247 strscpy(go->name, "Plextor PX-TV402U-NA",1248 sizeof(go->name));1249 break;1250 default:1251 pr_debug("unable to detect tuner type!\n");1252 break;1253 }1254 /* Configure tuner mode selection inputs connected1255 * to the EZ-USB GPIO output pins */1256 if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,1257 NULL, 0, 0) < 0) {1258 dev_err(go->dev, "GPIO write failed!\n");1259 goto allocfail;1260 }1261 }1262 1263 /* Print a nasty message if the user attempts to use a USB2.0 device in1264 * a USB1.1 port. There will be silent corruption of the stream. */1265 if ((board->flags & GO7007_USB_EZUSB) &&1266 usbdev->speed != USB_SPEED_HIGH)1267 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");1268 1269 /* Allocate the URBs and buffers for receiving the video stream */1270 if (board->flags & GO7007_USB_EZUSB) {1271 if (!usb->usbdev->ep_in[6])1272 goto allocfail;1273 v_urb_len = 1024;1274 video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);1275 } else {1276 if (!usb->usbdev->ep_in[1])1277 goto allocfail;1278 v_urb_len = 512;1279 video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);1280 }1281 for (i = 0; i < 8; ++i) {1282 usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);1283 if (usb->video_urbs[i] == NULL)1284 goto allocfail;1285 usb->video_urbs[i]->transfer_buffer =1286 kmalloc(v_urb_len, GFP_KERNEL);1287 if (usb->video_urbs[i]->transfer_buffer == NULL)1288 goto allocfail;1289 usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,1290 usb->video_urbs[i]->transfer_buffer, v_urb_len,1291 go7007_usb_read_video_pipe_complete, go);1292 }1293 1294 /* Allocate the URBs and buffers for receiving the audio stream */1295 if ((board->flags & GO7007_USB_EZUSB) &&1296 (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) {1297 if (!usb->usbdev->ep_in[8])1298 goto allocfail;1299 for (i = 0; i < 8; ++i) {1300 usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);1301 if (usb->audio_urbs[i] == NULL)1302 goto allocfail;1303 usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,1304 GFP_KERNEL);1305 if (usb->audio_urbs[i]->transfer_buffer == NULL)1306 goto allocfail;1307 usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,1308 usb_rcvbulkpipe(usb->usbdev, 8),1309 usb->audio_urbs[i]->transfer_buffer, 4096,1310 go7007_usb_read_audio_pipe_complete, go);1311 }1312 }1313 1314 /* Do any final GO7007 initialization, then register the1315 * V4L2 and ALSA interfaces */1316 if (go7007_register_encoder(go, num_i2c_devs) < 0)1317 goto allocfail;1318 1319 go->status = STATUS_ONLINE;1320 return 0;1321 1322allocfail:1323 go7007_usb_release(go);1324 kfree(go);1325 return -ENOMEM;1326}1327 1328static void go7007_usb_disconnect(struct usb_interface *intf)1329{1330 struct go7007 *go = to_go7007(usb_get_intfdata(intf));1331 1332 mutex_lock(&go->queue_lock);1333 mutex_lock(&go->serialize_lock);1334 1335 if (go->audio_enabled)1336 go7007_snd_remove(go);1337 1338 go->status = STATUS_SHUTDOWN;1339 v4l2_device_disconnect(&go->v4l2_dev);1340 video_unregister_device(&go->vdev);1341 mutex_unlock(&go->serialize_lock);1342 mutex_unlock(&go->queue_lock);1343 1344 v4l2_device_put(&go->v4l2_dev);1345}1346 1347static struct usb_driver go7007_usb_driver = {1348 .name = "go7007",1349 .probe = go7007_usb_probe,1350 .disconnect = go7007_usb_disconnect,1351 .id_table = go7007_usb_id_table,1352};1353 1354module_usb_driver(go7007_usb_driver);1355MODULE_DESCRIPTION("WIS GO7007 USB support");1356MODULE_LICENSE("GPL v2");1357