11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/****************************************************************************** 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * speedtch.c - Alcatel SpeedTouch USB xDSL modem driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, Alcatel 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003, Duncan Sands 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2004, David Woodhouse 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands * Based on "modem_run.c", copyright (C) 2001, Benoit Papillault 948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the Free 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Software Foundation; either version 2 of the License, or (at your option) 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any later version. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but WITHOUT 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * more details. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along with 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this program; if not, write to the Free Software Foundation, Inc., 59 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Temple Place - Suite 330, Boston, MA 02111-1307, USA. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ******************************************************************************/ 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <asm/page.h> 2748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/device.h> 2848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/errno.h> 2948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/firmware.h> 3048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/init.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 3248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/module.h> 3348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/moduleparam.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 3548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/stat.h> 3648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/timer.h> 3780aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands#include <linux/types.h> 385f848137744106ee737f559454ce5adfceb38347David Brownell#include <linux/usb/ch9.h> 3948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include <linux/workqueue.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#include "usbatm.h" 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Johan Verrept, Duncan Sands <duncan.sands@free.fr>" 449b0e54addf3ea8488c7b57166fb38feeb8ea28fdDuncan Sands#define DRIVER_VERSION "1.10" 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "Alcatel SpeedTouch USB driver version " DRIVER_VERSION 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char speedtch_driver_name[] = "speedtch"; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define CTRL_TIMEOUT 2000 /* milliseconds */ 5048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define DATA_TIMEOUT 2000 /* milliseconds */ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define OFFSET_7 0 /* size 1 */ 5348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define OFFSET_b 1 /* size 8 */ 5448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define OFFSET_d 9 /* size 4 */ 5548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define OFFSET_e 13 /* size 1 */ 5648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define OFFSET_f 14 /* size 1 */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define SIZE_7 1 5948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define SIZE_b 8 6048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define SIZE_d 4 6148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define SIZE_e 1 6248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define SIZE_f 1 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define MIN_POLL_DELAY 5000 /* milliseconds */ 6548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define MAX_POLL_DELAY 60000 /* milliseconds */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define RESUBMIT_DELAY 1000 /* milliseconds */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6980aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands#define DEFAULT_BULK_ALTSETTING 1 7067c752b41a4238c1a2d7eebcd061ff8c1127d3e9Duncan Sands#define DEFAULT_ISOC_ALTSETTING 3 7148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define DEFAULT_DL_512_FIRST 0 7280aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands#define DEFAULT_ENABLE_ISOC 0 7348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define DEFAULT_SW_BUFFERING 0 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7580aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sandsstatic unsigned int altsetting = 0; /* zero means: use the default */ 7690ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool dl_512_first = DEFAULT_DL_512_FIRST; 7790ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool enable_isoc = DEFAULT_ENABLE_ISOC; 7890ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool sw_buffering = DEFAULT_SW_BUFFERING; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 806a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands#define DEFAULT_B_MAX_DSL 8128 816a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands#define DEFAULT_MODEM_MODE 11 826a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands#define MODEM_OPTION_LENGTH 16 836a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sandsstatic const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = { 846a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 856a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands}; 866a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 876a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sandsstatic unsigned int BMaxDSL = DEFAULT_B_MAX_DSL; 886a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sandsstatic unsigned char ModemMode = DEFAULT_MODEM_MODE; 896a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sandsstatic unsigned char ModemOption[MODEM_OPTION_LENGTH]; 9064a6f9500d8e8a8e1b1adc2120e56cc88df5727fAl Virostatic unsigned int num_ModemOption; 916a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 9280aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sandsmodule_param(altsetting, uint, S_IRUGO | S_IWUSR); 9348da7267ff1631b0bff1eab15db86adace11ea91Duncan SandsMODULE_PARM_DESC(altsetting, 9480aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands "Alternative setting for data interface (bulk_default: " 9580aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands __MODULE_STRING(DEFAULT_BULK_ALTSETTING) "; isoc_default: " 9680aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands __MODULE_STRING(DEFAULT_ISOC_ALTSETTING) ")"); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsmodule_param(dl_512_first, bool, S_IRUGO | S_IWUSR); 9948da7267ff1631b0bff1eab15db86adace11ea91Duncan SandsMODULE_PARM_DESC(dl_512_first, 10048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands "Read 512 bytes before sending firmware (default: " 10148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands __MODULE_STRING(DEFAULT_DL_512_FIRST) ")"); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10380aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sandsmodule_param(enable_isoc, bool, S_IRUGO | S_IWUSR); 10480aae7a17afd21f7ba900dd566fb23a2444021f8Duncan SandsMODULE_PARM_DESC(enable_isoc, 10580aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands "Use isochronous transfers if available (default: " 10680aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands __MODULE_STRING(DEFAULT_ENABLE_ISOC) ")"); 10780aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 10848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsmodule_param(sw_buffering, bool, S_IRUGO | S_IWUSR); 10948da7267ff1631b0bff1eab15db86adace11ea91Duncan SandsMODULE_PARM_DESC(sw_buffering, 11048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands "Enable software buffering (default: " 11148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands __MODULE_STRING(DEFAULT_SW_BUFFERING) ")"); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1136a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sandsmodule_param(BMaxDSL, uint, S_IRUGO | S_IWUSR); 1146a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan SandsMODULE_PARM_DESC(BMaxDSL, 1156a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL)); 1166a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 1176a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sandsmodule_param(ModemMode, byte, S_IRUGO | S_IWUSR); 1186a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan SandsMODULE_PARM_DESC(ModemMode, 1196a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands "default: " __MODULE_STRING(DEFAULT_MODEM_MODE)); 1206a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 1216a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sandsmodule_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO); 1226a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan SandsMODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20"); 1236a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 1246f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands#define INTERFACE_DATA 1 12548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define ENDPOINT_INT 0x81 12680aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands#define ENDPOINT_BULK_DATA 0x07 12780aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands#define ENDPOINT_ISOC_DATA 0x07 12848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands#define ENDPOINT_FIRMWARE 0x05 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1306a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sandsstruct speedtch_params { 1316a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands unsigned int altsetting; 1326a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands unsigned int BMaxDSL; 1336a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands unsigned char ModemMode; 1346a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands unsigned char ModemOption[MODEM_OPTION_LENGTH]; 1356a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands}; 1366a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct speedtch_instance_data { 13848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usbatm_data *usbatm; 13948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 1406a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands struct speedtch_params params; /* set in probe, constant afterwards */ 1416f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands 14237c95bfe944babae817bfcf02c996729c9a3335dTejun Heo struct timer_list status_check_timer; 14337c95bfe944babae817bfcf02c996729c9a3335dTejun Heo struct work_struct status_check_work; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands unsigned char last_status; 1461a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands 14748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int poll_delay; /* milliseconds */ 14848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 14948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct timer_list resubmit_timer; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *int_urb; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char int_data[16]; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1536a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands unsigned char scratch_buffer[16]; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*************** 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** firmware ** 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds***************/ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic void speedtch_set_swbuff(struct speedtch_instance_data *instance, int state) 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usbatm_data *usbatm = instance->usbatm; 16348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_device *usb_dev = usbatm->usb_dev; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 16748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 0x32, 0x40, state ? 0x01 : 0x00, 0x00, NULL, 0, CTRL_TIMEOUT); 16848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0) 16948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_warn(usbatm, 17048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands "%sabling SW buffering: usb_control_msg returned %d\n", 17148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands state ? "En" : "Dis", ret); 17248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands else 17348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis"); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void speedtch_test_sequence(struct speedtch_instance_data *instance) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usbatm_data *usbatm = instance->usbatm; 17948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_device *usb_dev = usbatm->usb_dev; 18048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands unsigned char *buf = instance->scratch_buffer; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* URB 147 */ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x1c; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = 0x50; 18648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 18748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 0x01, 0x40, 0x0b, 0x00, buf, 2, CTRL_TIMEOUT); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 18948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_warn(usbatm, "%s failed on URB147: %d\n", __func__, ret); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* URB 148 */ 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x32; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = 0x00; 19448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 19548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 0x01, 0x40, 0x02, 0x00, buf, 2, CTRL_TIMEOUT); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 19748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_warn(usbatm, "%s failed on URB148: %d\n", __func__, ret); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* URB 149 */ 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x01; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = 0x00; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = 0x01; 20348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 20448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 0x01, 0x40, 0x03, 0x00, buf, 3, CTRL_TIMEOUT); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 20648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_warn(usbatm, "%s failed on URB149: %d\n", __func__, ret); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* URB 150 */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x01; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = 0x00; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = 0x01; 21248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 21348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) 21548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret); 2166a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 2176a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands /* Extra initialisation in recent drivers - gives higher speeds */ 2186a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 2196a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands /* URBext1 */ 2206a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands buf[0] = instance->params.ModemMode; 2216a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 2226a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT); 2236a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if (ret < 0) 2246a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret); 2256a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 2266a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands /* URBext2 */ 2276a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands /* This seems to be the one which actually triggers the higher sync 2286a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands rate -- it does require the new firmware too, although it works OK 2296a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands with older firmware */ 2306a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 2316a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 0x01, 0x40, 0x14, 0x00, 2326a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands instance->params.ModemOption, 2336a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands MODEM_OPTION_LENGTH, CTRL_TIMEOUT); 2346a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if (ret < 0) 2356a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret); 2366a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 2376a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands /* URBext3 */ 2386a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands buf[0] = instance->params.BMaxDSL & 0xff; 2396a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands buf[1] = instance->params.BMaxDSL >> 8; 2406a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 2416a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands 0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT); 2426a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if (ret < 0) 2436a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic int speedtch_upload_firmware(struct speedtch_instance_data *instance, 24748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands const struct firmware *fw1, 24848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands const struct firmware *fw2) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands unsigned char *buffer; 25148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usbatm_data *usbatm = instance->usbatm; 25248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_device *usb_dev = usbatm->usb_dev; 25348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int actual_length; 25448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int ret = 0; 25548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int offset; 25648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 25748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s entered\n", __func__); 25848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 25948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) { 26048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = -ENOMEM; 26148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__); 26248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto out; 26348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 26448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 265011db815231f40d4d53531b5d41b82c8dc7c44bfMicah Gruber if (!usb_ifnum_to_if(usb_dev, 2)) { 26648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = -ENODEV; 26748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s: interface not found!\n", __func__); 26848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto out_free; 26948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 27048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 27148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* URB 7 */ 27248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (dl_512_first) { /* some modems need a read before writing the firmware */ 27348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE), 27448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands buffer, 0x200, &actual_length, 2000); 27548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 27648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0 && ret != -ETIMEDOUT) 2770ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_warn(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret); 27848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands else 27948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s: BLOCK0 downloaded (%d bytes)\n", __func__, ret); 28048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 28148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 28248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* URB 8 : both leds are static green */ 28348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands for (offset = 0; offset < fw1->size; offset += PAGE_SIZE) { 28448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int thislen = min_t(int, PAGE_SIZE, fw1->size - offset); 28548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands memcpy(buffer, fw1->data + offset, thislen); 28648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 28748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE), 28848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands buffer, thislen, &actual_length, DATA_TIMEOUT); 28948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 29048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0) { 2910ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret); 29248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto out_free; 29348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 29448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s: BLOCK1 uploaded (%zu bytes)\n", __func__, fw1->size); 29548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 29648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 29748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* USB led blinking green, ADSL led off */ 29848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 29948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* URB 11 */ 30048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE), 30148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands buffer, 0x200, &actual_length, DATA_TIMEOUT); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 3040ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret); 30548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto out_free; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* URBs 12 to 139 - USB led blinking green, ADSL led off */ 31048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) { 31148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int thislen = min_t(int, PAGE_SIZE, fw2->size - offset); 31248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands memcpy(buffer, fw2->data + offset, thislen); 31348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 31448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE), 31548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands buffer, thislen, &actual_length, DATA_TIMEOUT); 31648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 31748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0) { 3180ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret); 31948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto out_free; 32048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 32148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 32248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s: BLOCK3 uploaded (%zu bytes)\n", __func__, fw2->size); 32348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 32448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* USB led static green, ADSL led static red */ 32548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 32648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* URB 142 */ 32748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE), 32848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands buffer, 0x200, &actual_length, DATA_TIMEOUT); 32948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 33048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0) { 3310ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret); 33248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto out_free; 33348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 33448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 33548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* success */ 33648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s: BLOCK4 downloaded (%d bytes)\n", __func__, actual_length); 33748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 33848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* Delay to allow firmware to start up. We can do this here 33948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands because we're in our own kernel thread anyway. */ 34048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands msleep_interruptible(1000); 34148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 3426a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { 3436a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret); 3446f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands goto out_free; 3456f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands } 3466f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands 34748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* Enable software buffering, if requested */ 34848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (sw_buffering) 34948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands speedtch_set_swbuff(instance, 1); 35048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 35148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* Magic spell; don't ask us what this does */ 35248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands speedtch_test_sequence(instance); 35348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 35448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = 0; 35548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 35648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsout_free: 35748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands free_page((unsigned long)buffer); 35848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsout: 35948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return ret; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3620ec3c7e856319b600311750d784262caa8ed94b9Duncan Sandsstatic int speedtch_find_firmware(struct usbatm_data *usbatm, struct usb_interface *intf, 3630ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands int phase, const struct firmware **fw_p) 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct device *dev = &intf->dev; 36648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands const u16 bcdDevice = le16_to_cpu(interface_to_usbdev(intf)->descriptor.bcdDevice); 36748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands const u8 major_revision = bcdDevice >> 8; 36848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands const u8 minor_revision = bcdDevice & 0xff; 36948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands char buf[24]; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision); 3720ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (request_firmware(fw_p, buf, dev)) { 37548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision); 3760ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (request_firmware(fw_p, buf, dev)) { 37948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands sprintf(buf, "speedtch-%d.bin", phase); 3800ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf); 38148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 38248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (request_firmware(fw_p, buf, dev)) { 3830ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: no stage %d firmware found!\n", __func__, phase); 38448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return -ENOENT; 38548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 38648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3890ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_info(usbatm, "found stage %d firmware %s\n", phase, buf); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return 0; 39248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands} 39348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 39448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic int speedtch_heavy_init(struct usbatm_data *usbatm, struct usb_interface *intf) 39548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands{ 39648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands const struct firmware *fw1, *fw2; 39748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct speedtch_instance_data *instance = usbatm->driver_data; 39848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int ret; 39948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 4000ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands if ((ret = speedtch_find_firmware(usbatm, intf, 1, &fw1)) < 0) 4010ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands return ret; 40248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 4030ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands if ((ret = speedtch_find_firmware(usbatm, intf, 2, &fw2)) < 0) { 40448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands release_firmware(fw1); 40548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return ret; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4080ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands if ((ret = speedtch_upload_firmware(instance, fw1, fw2)) < 0) 4090ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: firmware upload failed (%d)!\n", __func__, ret); 41048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 41148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands release_firmware(fw2); 41248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands release_firmware(fw1); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return ret; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 41848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands/********** 41948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands** ATM ** 42048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands**********/ 42148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 42248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic int speedtch_read_status(struct speedtch_instance_data *instance) 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usbatm_data *usbatm = instance->usbatm; 42548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_device *usb_dev = usbatm->usb_dev; 42648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands unsigned char *buf = instance->scratch_buffer; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4296a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands memset(buf, 0, 16); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CTRL_TIMEOUT); 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 43548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: MSG 7 failed\n", __func__); 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b, 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CTRL_TIMEOUT); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 44348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: MSG B failed\n", __func__); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d, 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CTRL_TIMEOUT); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 45148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: MSG D failed\n", __func__); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e, 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CTRL_TIMEOUT); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 45948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: MSG E failed\n", __func__); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f, 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CTRL_TIMEOUT); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 46748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: MSG F failed\n", __func__); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic int speedtch_start_synchro(struct speedtch_instance_data *instance) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 47648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usbatm_data *usbatm = instance->usbatm; 47748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_device *usb_dev = usbatm->usb_dev; 47848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands unsigned char *buf = instance->scratch_buffer; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s entered\n", __func__); 48248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 48348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands memset(buf, 0, 2); 48448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 48548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 48648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 0x12, 0xc0, 0x04, 0x00, 48748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands buf, 2, CTRL_TIMEOUT); 48848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 48948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0) 49048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_warn(usbatm, "failed to start ADSL synchronisation: %d\n", ret); 49148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands else 49248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: modem prodded. %d bytes returned: %02x %02x\n", 49348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands __func__, ret, buf[0], buf[1]); 49448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 49548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return ret; 49648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands} 49748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 498c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void speedtch_check_status(struct work_struct *work) 49948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands{ 500c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct speedtch_instance_data *instance = 501c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells container_of(work, struct speedtch_instance_data, 50237c95bfe944babae817bfcf02c996729c9a3335dTejun Heo status_check_work); 50348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usbatm_data *usbatm = instance->usbatm; 50448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct atm_dev *atm_dev = usbatm->atm_dev; 50548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands unsigned char *buf = instance->scratch_buffer; 5061a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands int down_speed, up_speed, ret; 5071a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands unsigned char status; 50848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 5090ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands#ifdef VERBOSE_DEBUG 51048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s entered\n", __func__); 5110ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands#endif 51248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 51348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = speedtch_read_status(instance); 51448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0) { 51548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_warn(usbatm, "error %d fetching device status\n", ret); 516cd5c08fb7b0d960b7cd48bc977feee7b3bd8b046Duncan Sands instance->poll_delay = min(2 * instance->poll_delay, MAX_POLL_DELAY); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 520cd5c08fb7b0d960b7cd48bc977feee7b3bd8b046Duncan Sands instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY); 52148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 5221a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands status = buf[OFFSET_7]; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands if ((status != instance->last_status) || !status) { 5250ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands atm_dbg(usbatm, "%s: line state 0x%02x\n", __func__, status); 5260ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands 5271a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands switch (status) { 5281a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands case 0: 52923f89f0488fa0fc843503fa07768d0d3edde3c44Karl Hiramoto atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); 5301a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands if (instance->last_status) 53152fbae2a392b6e084195bedc7a280991a94c14d0David S. Miller atm_info(usbatm, "ADSL line is down\n"); 5321a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands /* It may never resync again unless we ask it to... */ 53348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = speedtch_start_synchro(instance); 5341a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands break; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands case 0x08: 53723f89f0488fa0fc843503fa07768d0d3edde3c44Karl Hiramoto atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN); 53852fbae2a392b6e084195bedc7a280991a94c14d0David S. Miller atm_info(usbatm, "ADSL line is blocked?\n"); 5391a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands break; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5411a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands case 0x10: 54223f89f0488fa0fc843503fa07768d0d3edde3c44Karl Hiramoto atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); 54352fbae2a392b6e084195bedc7a280991a94c14d0David S. Miller atm_info(usbatm, "ADSL line is synchronising\n"); 5441a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands break; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5461a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands case 0x20: 5471a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24); 5491a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) { 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_speed >>= 16; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_speed >>= 16; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dev->link_rate = down_speed * 1000 / 424; 55823f89f0488fa0fc843503fa07768d0d3edde3c44Karl Hiramoto atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND); 55948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 56048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_info(usbatm, 561322a95bc8eba889d2f9d7222936d682c9aad8294Duncan Sands "ADSL line is up (%d kb/s down | %d kb/s up)\n", 56248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands down_speed, up_speed); 5631a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands break; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5651a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands default: 56623f89f0488fa0fc843503fa07768d0d3edde3c44Karl Hiramoto atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN); 5670ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands atm_info(usbatm, "unknown line state %02x\n", status); 5681a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands break; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5701a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands 5711a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands instance->last_status = status; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic void speedtch_status_poll(unsigned long data) 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct speedtch_instance_data *instance = (void *)data; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57937c95bfe944babae817bfcf02c996729c9a3335dTejun Heo schedule_work(&instance->status_check_work); 58048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 58148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* The following check is racy, but the race is harmless */ 58248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (instance->poll_delay < MAX_POLL_DELAY) 58337c95bfe944babae817bfcf02c996729c9a3335dTejun Heo mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(instance->poll_delay)); 58448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands else 58552fbae2a392b6e084195bedc7a280991a94c14d0David S. Miller atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n"); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic void speedtch_resubmit_int(unsigned long data) 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 59048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct speedtch_instance_data *instance = (void *)data; 59148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct urb *int_urb = instance->int_urb; 59248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int ret; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(instance->usbatm, "%s entered\n", __func__); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (int_urb) { 59748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_submit_urb(int_urb, GFP_ATOMIC); 59848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (!ret) 59937c95bfe944babae817bfcf02c996729c9a3335dTejun Heo schedule_work(&instance->status_check_work); 60048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands else { 60148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); 60248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 60548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands} 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6077d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void speedtch_handle_int(struct urb *int_urb) 60848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands{ 60948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct speedtch_instance_data *instance = int_urb->context; 61048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usbatm_data *usbatm = instance->usbatm; 61148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands unsigned int count = int_urb->actual_length; 6129a5a3e95b49c93813476974abaa038c9d36bdd14Greg Kroah-Hartman int status = int_urb->status; 6139a5a3e95b49c93813476974abaa038c9d36bdd14Greg Kroah-Hartman int ret; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* The magic interrupt for "up state" */ 6163c6bee1d4037a5c569f30d40bd852a57ba250912Jesper Juhl static const unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 }; 61748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* The magic interrupt for "down state" */ 6183c6bee1d4037a5c569f30d40bd852a57ba250912Jesper Juhl static const unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 }; 61948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 62048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s entered\n", __func__); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6229a5a3e95b49c93813476974abaa038c9d36bdd14Greg Kroah-Hartman if (status < 0) { 6239a5a3e95b49c93813476974abaa038c9d36bdd14Greg Kroah-Hartman atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status); 62448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto fail; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) { 62837c95bfe944babae817bfcf02c996729c9a3335dTejun Heo del_timer(&instance->status_check_timer); 62952fbae2a392b6e084195bedc7a280991a94c14d0David S. Miller atm_info(usbatm, "DSL line goes up\n"); 63048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) { 63152fbae2a392b6e084195bedc7a280991a94c14d0David S. Miller atm_info(usbatm, "DSL line goes down\n"); 63248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } else { 63348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int i; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: unknown interrupt packet of length %d:", __func__, count); 63648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands for (i = 0; i < count; i++) 63748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands printk(" %02x", instance->int_data[i]); 63848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands printk("\n"); 63948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto fail; 64048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if ((int_urb = instance->int_urb)) { 64348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_submit_urb(int_urb, GFP_ATOMIC); 64437c95bfe944babae817bfcf02c996729c9a3335dTejun Heo schedule_work(&instance->status_check_work); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret < 0) { 64648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); 64748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto fail; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsfail: 65448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if ((int_urb = instance->int_urb)) 65548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_dev) 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 66048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_device *usb_dev = usbatm->usb_dev; 66148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct speedtch_instance_data *instance = usbatm->driver_data; 66248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int i, ret; 66348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands unsigned char mac_str[13]; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s entered\n", __func__); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* Set MAC address, it is stored in the serial number */ 66848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands memset(atm_dev->esi, 0, sizeof(atm_dev->esi)); 66948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) { 67048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands for (i = 0; i < 6; i++) 67196b89f323d6af996a7f6bd84d2119cbf7145f9a4Andy Shevchenko atm_dev->esi[i] = (hex_to_bin(mac_str[i * 2]) << 4) + 67296b89f323d6af996a7f6bd84d2119cbf7145f9a4Andy Shevchenko hex_to_bin(mac_str[i * 2 + 1]); 67348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* Start modem synchronisation */ 67648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = speedtch_start_synchro(instance); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* Set up interrupt endpoint */ 67948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (instance->int_urb) { 68048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_submit_urb(instance->int_urb, GFP_KERNEL); 68148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0) { 68248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* Doesn't matter; we'll poll anyway */ 68348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s: submission of interrupt URB failed (%d)!\n", __func__, ret); 68448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_free_urb(instance->int_urb); 68548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->int_urb = NULL; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* Start status polling */ 69037c95bfe944babae817bfcf02c996729c9a3335dTejun Heo mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(1000)); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_dev) 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 69748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct speedtch_instance_data *instance = usbatm->driver_data; 69848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct urb *int_urb = instance->int_urb; 69948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 70048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands atm_dbg(usbatm, "%s entered\n", __func__); 70148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 70237c95bfe944babae817bfcf02c996729c9a3335dTejun Heo del_timer_sync(&instance->status_check_timer); 70348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 70448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* 70548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands * Since resubmit_timer and int_urb can schedule themselves and 70648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands * each other, shutting them down correctly takes some care 70748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands */ 70848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->int_urb = NULL; /* signal shutdown */ 70948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands mb(); 71048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_kill_urb(int_urb); 71148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands del_timer_sync(&instance->resubmit_timer); 71248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* 71348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands * At this point, speedtch_handle_int and speedtch_resubmit_int 71448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands * can run or be running, but instance->int_urb == NULL means that 71548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands * they will not reschedule 71648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands */ 71748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_kill_urb(int_urb); 71848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands del_timer_sync(&instance->resubmit_timer); 71948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_free_urb(int_urb); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721569ff2de2e1c8ac67c8df3a7367d46d0d9460a35Tejun Heo flush_work_sync(&instance->status_check_work); 72248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands} 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7248fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Sternstatic int speedtch_pre_reset(struct usb_interface *intf) 7258fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern{ 7268fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern return 0; 7278fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern} 7288fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern 7298fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Sternstatic int speedtch_post_reset(struct usb_interface *intf) 7308fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern{ 7318fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern return 0; 7328fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern} 7338fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands/********** 73648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands** USB ** 73748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands**********/ 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic struct usb_device_id speedtch_usb_ids[] = { 74048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands {USB_DEVICE(0x06b9, 0x4061)}, 74148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands {} 74248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands}; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74448da7267ff1631b0bff1eab15db86adace11ea91Duncan SandsMODULE_DEVICE_TABLE(usb, speedtch_usb_ids); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic struct usb_driver speedtch_usb_driver = { 74948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .name = speedtch_driver_name, 75048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .probe = speedtch_usb_probe, 75148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .disconnect = usbatm_usb_disconnect, 7528fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern .pre_reset = speedtch_pre_reset, 7538fc7aeab3851ed8c3ecf28901ca2c6f0400955c7Alan Stern .post_reset = speedtch_post_reset, 75448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .id_table = speedtch_usb_ids 75548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands}; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7576c4b7f70ba5ffb7fa1d19d2518664ea6ddb3cbf3Nicolas Kaiserstatic void speedtch_release_interfaces(struct usb_device *usb_dev, 7586c4b7f70ba5ffb7fa1d19d2518664ea6ddb3cbf3Nicolas Kaiser int num_interfaces) 7596c4b7f70ba5ffb7fa1d19d2518664ea6ddb3cbf3Nicolas Kaiser{ 76048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_interface *cur_intf; 76148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int i; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7639196cc7bb46bece079398c9846050e8c8dc9235cNicolas Kaiser for (i = 0; i < num_interfaces; i++) 76448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) { 76548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_set_intfdata(cur_intf, NULL); 76648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_driver_release_interface(&speedtch_usb_driver, cur_intf); 76748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic int speedtch_bind(struct usbatm_data *usbatm, 77148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_interface *intf, 77235644b0cce0ab8735944dcbfceb19e9e65da9a3dDuncan Sands const struct usb_device_id *id) 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 77448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_device *usb_dev = interface_to_usbdev(intf); 77580aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands struct usb_interface *cur_intf, *data_intf; 77648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct speedtch_instance_data *instance; 77748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int ifnum = intf->altsetting->desc.bInterfaceNumber; 77848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces; 77948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands int i, ret; 78080aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands int use_isoc; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 78248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s entered\n", __func__); 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7840ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands /* sanity checks */ 7850ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands 78648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { 7870ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79180aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands if (!(data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA))) { 79280aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands usb_err(usbatm, "%s: data interface not found!\n", __func__); 79380aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands return -ENODEV; 79480aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands } 79580aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 79648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* claim all interfaces */ 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7989196cc7bb46bece079398c9846050e8c8dc9235cNicolas Kaiser for (i = 0; i < num_interfaces; i++) { 79948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands cur_intf = usb_ifnum_to_if(usb_dev, i); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if ((i != ifnum) && cur_intf) { 80248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm); 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (ret < 0) { 8050ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: failed to claim interface %2d (%d)!\n", __func__, i, ret); 80648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands speedtch_release_interfaces(usb_dev, i); 80748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return ret; 80848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 80948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 81048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands } 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8129a734efec36c991a74610c6c81d28d4222e1c02bDuncan Sands instance = kzalloc(sizeof(*instance), GFP_KERNEL); 81348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!instance) { 8150ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: no memory for instance data!\n", __func__); 81648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = -ENOMEM; 81748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto fail_release; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->usbatm = usbatm; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8226a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands /* module parameters may change at any moment, so take a snapshot */ 8236a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands instance->params.altsetting = altsetting; 8246a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands instance->params.BMaxDSL = BMaxDSL; 8256a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands instance->params.ModemMode = ModemMode; 8266a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH); 8276a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands memcpy(instance->params.ModemOption, ModemOption, num_ModemOption); 82880aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands use_isoc = enable_isoc; 8296f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands 8306a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if (instance->params.altsetting) 8316a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { 8326a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret); 8336a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands instance->params.altsetting = 0; /* fall back to default */ 8346f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands } 8356f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands 8366a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if (!instance->params.altsetting && use_isoc) 83780aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) { 83880aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret); 83980aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands use_isoc = 0; /* fall back to bulk */ 8406f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands } 84180aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 84280aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands if (use_isoc) { 84380aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands const struct usb_host_interface *desc = data_intf->cur_altsetting; 84480aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands const __u8 target_address = USB_DIR_IN | usbatm->driver->isoc_in; 84580aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 84680aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands use_isoc = 0; /* fall back to bulk if endpoint not found */ 84780aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 8489196cc7bb46bece079398c9846050e8c8dc9235cNicolas Kaiser for (i = 0; i < desc->desc.bNumEndpoints; i++) { 84980aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc; 85080aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 85180aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands if ((endpoint_desc->bEndpointAddress == target_address)) { 852c5dd1f94246acdf6be6796db47efba8b2a93f93eLuiz Fernando N. Capitulino use_isoc = 853c5dd1f94246acdf6be6796db47efba8b2a93f93eLuiz Fernando N. Capitulino usb_endpoint_xfer_isoc(endpoint_desc); 85480aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands break; 85580aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands } 85680aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands } 85780aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 85880aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands if (!use_isoc) 85980aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands usb_info(usbatm, "isochronous transfer not supported - using bulk\n"); 8606f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands } 8616f7494759870ec6fbb066f7202c5585fe36fbe82Duncan Sands 8626a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if (!use_isoc && !instance->params.altsetting) 86380aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) { 86480aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret); 86580aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands goto fail_free; 86680aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands } 86780aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 8686a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands if (!instance->params.altsetting) 8696a4f1b41357d2bd65d39f7a5d44e92f69daaf04bDuncan Sands instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; 87080aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 87180aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); 87280aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands 87337c95bfe944babae817bfcf02c996729c9a3335dTejun Heo INIT_WORK(&instance->status_check_work, speedtch_check_status); 87437c95bfe944babae817bfcf02c996729c9a3335dTejun Heo init_timer(&instance->status_check_timer); 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87637c95bfe944babae817bfcf02c996729c9a3335dTejun Heo instance->status_check_timer.function = speedtch_status_poll; 87737c95bfe944babae817bfcf02c996729c9a3335dTejun Heo instance->status_check_timer.data = (unsigned long)instance; 8781a7aad15ff93be104c8e0851a43b94f8ccd92225Duncan Sands instance->last_status = 0xff; 87948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->poll_delay = MIN_POLL_DELAY; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands init_timer(&instance->resubmit_timer); 88248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->resubmit_timer.function = speedtch_resubmit_int; 88348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->resubmit_timer.data = (unsigned long)instance; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->int_urb = usb_alloc_urb(0, GFP_KERNEL); 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 88748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands if (instance->int_urb) 88848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_fill_int_urb(instance->int_urb, usb_dev, 88948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_rcvintpipe(usb_dev, ENDPOINT_INT), 89048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->int_data, sizeof(instance->int_data), 89148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands speedtch_handle_int, instance, 50); 89248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands else 89348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__); 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands /* check whether the modem already seems to be alive */ 89648da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 89748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 0x12, 0xc0, 0x07, 0x00, 89848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands instance->scratch_buffer + OFFSET_7, SIZE_7, 500); 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90080aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands usbatm->flags |= (ret == SIZE_7 ? UDSL_SKIP_HEAVY_INIT : 0); 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90235644b0cce0ab8735944dcbfceb19e9e65da9a3dDuncan Sands usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, usbatm->flags & UDSL_SKIP_HEAVY_INIT ? "already" : "not"); 90348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 90435644b0cce0ab8735944dcbfceb19e9e65da9a3dDuncan Sands if (!(usbatm->flags & UDSL_SKIP_HEAVY_INIT)) 9050ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands if ((ret = usb_reset_device(usb_dev)) < 0) { 9060ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands usb_err(usbatm, "%s: device reset failed (%d)!\n", __func__, ret); 90748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands goto fail_free; 9080ec3c7e856319b600311750d784262caa8ed94b9Duncan Sands } 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usbatm->driver_data = instance; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsfail_free: 91548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_free_urb(instance->int_urb); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(instance); 91748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsfail_release: 91848da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands speedtch_release_interfaces(usb_dev, num_interfaces); 91948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return ret; 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 92448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct usb_device *usb_dev = interface_to_usbdev(intf); 92548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands struct speedtch_instance_data *instance = usbatm->driver_data; 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92748da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_dbg(usbatm, "%s entered\n", __func__); 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands speedtch_release_interfaces(usb_dev, usb_dev->actconfig->desc.bNumInterfaces); 93048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands usb_free_urb(instance->int_urb); 93148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands kfree(instance); 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*********** 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** init ** 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds***********/ 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic struct usbatm_driver speedtch_usbatm_driver = { 94048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .driver_name = speedtch_driver_name, 94148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .bind = speedtch_bind, 94248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .heavy_init = speedtch_heavy_init, 94348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .unbind = speedtch_unbind, 94448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .atm_start = speedtch_atm_start, 94548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands .atm_stop = speedtch_atm_stop, 94680aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands .bulk_in = ENDPOINT_BULK_DATA, 94780aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands .bulk_out = ENDPOINT_BULK_DATA, 94880aae7a17afd21f7ba900dd566fb23a2444021f8Duncan Sands .isoc_in = ENDPOINT_ISOC_DATA 94948da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands}; 95048da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 95148da7267ff1631b0bff1eab15db86adace11ea91Duncan Sandsstatic int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 95248da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands{ 95348da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands return usbatm_usb_probe(intf, id, &speedtch_usbatm_driver); 95448da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands} 95548da7267ff1631b0bff1eab15db86adace11ea91Duncan Sands 95665db43054065790a75291b0834657445fea2cf56Greg Kroah-Hartmanmodule_usb_driver(speedtch_usb_driver); 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR(DRIVER_AUTHOR); 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(DRIVER_VERSION); 962