1*1da177e4SLinus Torvalds /****************************************************************************** 2*1da177e4SLinus Torvalds * speedtch.c - Alcatel SpeedTouch USB xDSL modem driver 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (C) 2001, Alcatel 5*1da177e4SLinus Torvalds * Copyright (C) 2003, Duncan Sands 6*1da177e4SLinus Torvalds * Copyright (C) 2004, David Woodhouse 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 9*1da177e4SLinus Torvalds * under the terms of the GNU General Public License as published by the Free 10*1da177e4SLinus Torvalds * Software Foundation; either version 2 of the License, or (at your option) 11*1da177e4SLinus Torvalds * any later version. 12*1da177e4SLinus Torvalds * 13*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, but WITHOUT 14*1da177e4SLinus Torvalds * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15*1da177e4SLinus Torvalds * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 16*1da177e4SLinus Torvalds * more details. 17*1da177e4SLinus Torvalds * 18*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License along with 19*1da177e4SLinus Torvalds * this program; if not, write to the Free Software Foundation, Inc., 59 20*1da177e4SLinus Torvalds * Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21*1da177e4SLinus Torvalds * 22*1da177e4SLinus Torvalds ******************************************************************************/ 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds #include <linux/module.h> 25*1da177e4SLinus Torvalds #include <linux/moduleparam.h> 26*1da177e4SLinus Torvalds #include <linux/gfp.h> 27*1da177e4SLinus Torvalds #include <linux/kernel.h> 28*1da177e4SLinus Torvalds #include <linux/sched.h> 29*1da177e4SLinus Torvalds #include <linux/timer.h> 30*1da177e4SLinus Torvalds #include <linux/errno.h> 31*1da177e4SLinus Torvalds #include <linux/proc_fs.h> 32*1da177e4SLinus Torvalds #include <linux/slab.h> 33*1da177e4SLinus Torvalds #include <linux/wait.h> 34*1da177e4SLinus Torvalds #include <linux/list.h> 35*1da177e4SLinus Torvalds #include <asm/processor.h> 36*1da177e4SLinus Torvalds #include <asm/uaccess.h> 37*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 38*1da177e4SLinus Torvalds #include <linux/interrupt.h> 39*1da177e4SLinus Torvalds #include <linux/atm.h> 40*1da177e4SLinus Torvalds #include <linux/atmdev.h> 41*1da177e4SLinus Torvalds #include <linux/crc32.h> 42*1da177e4SLinus Torvalds #include <linux/init.h> 43*1da177e4SLinus Torvalds #include <linux/firmware.h> 44*1da177e4SLinus Torvalds 45*1da177e4SLinus Torvalds #include "usb_atm.h" 46*1da177e4SLinus Torvalds 47*1da177e4SLinus Torvalds #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) 48*1da177e4SLinus Torvalds # define USE_FW_LOADER 49*1da177e4SLinus Torvalds #endif 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds #define DRIVER_AUTHOR "Johan Verrept, Duncan Sands <duncan.sands@free.fr>" 52*1da177e4SLinus Torvalds #define DRIVER_VERSION "1.8" 53*1da177e4SLinus Torvalds #define DRIVER_DESC "Alcatel SpeedTouch USB driver version " DRIVER_VERSION 54*1da177e4SLinus Torvalds 55*1da177e4SLinus Torvalds static const char speedtch_driver_name[] = "speedtch"; 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds #define SPEEDTOUCH_VENDORID 0x06b9 58*1da177e4SLinus Torvalds #define SPEEDTOUCH_PRODUCTID 0x4061 59*1da177e4SLinus Torvalds 60*1da177e4SLinus Torvalds /* Timeout in jiffies */ 61*1da177e4SLinus Torvalds #define CTRL_TIMEOUT 2000 62*1da177e4SLinus Torvalds #define DATA_TIMEOUT 2000 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds #define OFFSET_7 0 /* size 1 */ 65*1da177e4SLinus Torvalds #define OFFSET_b 1 /* size 8 */ 66*1da177e4SLinus Torvalds #define OFFSET_d 9 /* size 4 */ 67*1da177e4SLinus Torvalds #define OFFSET_e 13 /* size 1 */ 68*1da177e4SLinus Torvalds #define OFFSET_f 14 /* size 1 */ 69*1da177e4SLinus Torvalds #define TOTAL 15 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds #define SIZE_7 1 72*1da177e4SLinus Torvalds #define SIZE_b 8 73*1da177e4SLinus Torvalds #define SIZE_d 4 74*1da177e4SLinus Torvalds #define SIZE_e 1 75*1da177e4SLinus Torvalds #define SIZE_f 1 76*1da177e4SLinus Torvalds 77*1da177e4SLinus Torvalds static int dl_512_first = 0; 78*1da177e4SLinus Torvalds static int sw_buffering = 0; 79*1da177e4SLinus Torvalds 80*1da177e4SLinus Torvalds module_param(dl_512_first, bool, 0444); 81*1da177e4SLinus Torvalds MODULE_PARM_DESC(dl_512_first, "Read 512 bytes before sending firmware"); 82*1da177e4SLinus Torvalds 83*1da177e4SLinus Torvalds module_param(sw_buffering, uint, 0444); 84*1da177e4SLinus Torvalds MODULE_PARM_DESC(sw_buffering, "Enable software buffering"); 85*1da177e4SLinus Torvalds 86*1da177e4SLinus Torvalds #define UDSL_IOCTL_LINE_UP 1 87*1da177e4SLinus Torvalds #define UDSL_IOCTL_LINE_DOWN 2 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds #define SPEEDTCH_ENDPOINT_INT 0x81 90*1da177e4SLinus Torvalds #define SPEEDTCH_ENDPOINT_DATA 0x07 91*1da177e4SLinus Torvalds #define SPEEDTCH_ENDPOINT_FIRMWARE 0x05 92*1da177e4SLinus Torvalds 93*1da177e4SLinus Torvalds #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds static struct usb_device_id speedtch_usb_ids[] = { 96*1da177e4SLinus Torvalds {USB_DEVICE(SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)}, 97*1da177e4SLinus Torvalds {} 98*1da177e4SLinus Torvalds }; 99*1da177e4SLinus Torvalds 100*1da177e4SLinus Torvalds MODULE_DEVICE_TABLE(usb, speedtch_usb_ids); 101*1da177e4SLinus Torvalds 102*1da177e4SLinus Torvalds struct speedtch_instance_data { 103*1da177e4SLinus Torvalds struct udsl_instance_data u; 104*1da177e4SLinus Torvalds 105*1da177e4SLinus Torvalds /* Status */ 106*1da177e4SLinus Torvalds struct urb *int_urb; 107*1da177e4SLinus Torvalds unsigned char int_data[16]; 108*1da177e4SLinus Torvalds struct work_struct poll_work; 109*1da177e4SLinus Torvalds struct timer_list poll_timer; 110*1da177e4SLinus Torvalds }; 111*1da177e4SLinus Torvalds /* USB */ 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds static int speedtch_usb_probe(struct usb_interface *intf, 114*1da177e4SLinus Torvalds const struct usb_device_id *id); 115*1da177e4SLinus Torvalds static void speedtch_usb_disconnect(struct usb_interface *intf); 116*1da177e4SLinus Torvalds static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code, 117*1da177e4SLinus Torvalds void *user_data); 118*1da177e4SLinus Torvalds static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs); 119*1da177e4SLinus Torvalds static void speedtch_poll_status(struct speedtch_instance_data *instance); 120*1da177e4SLinus Torvalds 121*1da177e4SLinus Torvalds static struct usb_driver speedtch_usb_driver = { 122*1da177e4SLinus Torvalds .owner = THIS_MODULE, 123*1da177e4SLinus Torvalds .name = speedtch_driver_name, 124*1da177e4SLinus Torvalds .probe = speedtch_usb_probe, 125*1da177e4SLinus Torvalds .disconnect = speedtch_usb_disconnect, 126*1da177e4SLinus Torvalds .ioctl = speedtch_usb_ioctl, 127*1da177e4SLinus Torvalds .id_table = speedtch_usb_ids, 128*1da177e4SLinus Torvalds }; 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds /*************** 131*1da177e4SLinus Torvalds ** firmware ** 132*1da177e4SLinus Torvalds ***************/ 133*1da177e4SLinus Torvalds 134*1da177e4SLinus Torvalds static void speedtch_got_firmware(struct speedtch_instance_data *instance, 135*1da177e4SLinus Torvalds int got_it) 136*1da177e4SLinus Torvalds { 137*1da177e4SLinus Torvalds int err; 138*1da177e4SLinus Torvalds struct usb_interface *intf; 139*1da177e4SLinus Torvalds 140*1da177e4SLinus Torvalds down(&instance->u.serialize); /* vs self, speedtch_firmware_start */ 141*1da177e4SLinus Torvalds if (instance->u.status == UDSL_LOADED_FIRMWARE) 142*1da177e4SLinus Torvalds goto out; 143*1da177e4SLinus Torvalds if (!got_it) { 144*1da177e4SLinus Torvalds instance->u.status = UDSL_NO_FIRMWARE; 145*1da177e4SLinus Torvalds goto out; 146*1da177e4SLinus Torvalds } 147*1da177e4SLinus Torvalds if ((err = usb_set_interface(instance->u.usb_dev, 1, 1)) < 0) { 148*1da177e4SLinus Torvalds dbg("speedtch_got_firmware: usb_set_interface returned %d!", err); 149*1da177e4SLinus Torvalds instance->u.status = UDSL_NO_FIRMWARE; 150*1da177e4SLinus Torvalds goto out; 151*1da177e4SLinus Torvalds } 152*1da177e4SLinus Torvalds 153*1da177e4SLinus Torvalds /* Set up interrupt endpoint */ 154*1da177e4SLinus Torvalds intf = usb_ifnum_to_if(instance->u.usb_dev, 0); 155*1da177e4SLinus Torvalds if (intf && !usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) { 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds instance->int_urb = usb_alloc_urb(0, GFP_KERNEL); 158*1da177e4SLinus Torvalds if (instance->int_urb) { 159*1da177e4SLinus Torvalds 160*1da177e4SLinus Torvalds usb_fill_int_urb(instance->int_urb, instance->u.usb_dev, 161*1da177e4SLinus Torvalds usb_rcvintpipe(instance->u.usb_dev, SPEEDTCH_ENDPOINT_INT), 162*1da177e4SLinus Torvalds instance->int_data, 163*1da177e4SLinus Torvalds sizeof(instance->int_data), 164*1da177e4SLinus Torvalds speedtch_handle_int, instance, 50); 165*1da177e4SLinus Torvalds err = usb_submit_urb(instance->int_urb, GFP_KERNEL); 166*1da177e4SLinus Torvalds if (err) { 167*1da177e4SLinus Torvalds /* Doesn't matter; we'll poll anyway */ 168*1da177e4SLinus Torvalds dbg("speedtch_got_firmware: Submission of interrupt URB failed %d", err); 169*1da177e4SLinus Torvalds usb_free_urb(instance->int_urb); 170*1da177e4SLinus Torvalds instance->int_urb = NULL; 171*1da177e4SLinus Torvalds usb_driver_release_interface(&speedtch_usb_driver, intf); 172*1da177e4SLinus Torvalds } 173*1da177e4SLinus Torvalds } 174*1da177e4SLinus Torvalds } 175*1da177e4SLinus Torvalds /* Start status polling */ 176*1da177e4SLinus Torvalds mod_timer(&instance->poll_timer, jiffies + (1 * HZ)); 177*1da177e4SLinus Torvalds 178*1da177e4SLinus Torvalds instance->u.status = UDSL_LOADED_FIRMWARE; 179*1da177e4SLinus Torvalds tasklet_schedule(&instance->u.receive_tasklet); 180*1da177e4SLinus Torvalds out: 181*1da177e4SLinus Torvalds up(&instance->u.serialize); 182*1da177e4SLinus Torvalds wake_up_interruptible(&instance->u.firmware_waiters); 183*1da177e4SLinus Torvalds } 184*1da177e4SLinus Torvalds 185*1da177e4SLinus Torvalds static int speedtch_set_swbuff(struct speedtch_instance_data *instance, 186*1da177e4SLinus Torvalds int state) 187*1da177e4SLinus Torvalds { 188*1da177e4SLinus Torvalds struct usb_device *dev = instance->u.usb_dev; 189*1da177e4SLinus Torvalds int ret; 190*1da177e4SLinus Torvalds 191*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 192*1da177e4SLinus Torvalds 0x32, 0x40, state ? 0x01 : 0x00, 193*1da177e4SLinus Torvalds 0x00, NULL, 0, 100); 194*1da177e4SLinus Torvalds if (ret < 0) { 195*1da177e4SLinus Torvalds printk("Warning: %sabling SW buffering: usb_control_msg returned %d\n", 196*1da177e4SLinus Torvalds state ? "En" : "Dis", ret); 197*1da177e4SLinus Torvalds return ret; 198*1da177e4SLinus Torvalds } 199*1da177e4SLinus Torvalds 200*1da177e4SLinus Torvalds dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis"); 201*1da177e4SLinus Torvalds return 0; 202*1da177e4SLinus Torvalds } 203*1da177e4SLinus Torvalds 204*1da177e4SLinus Torvalds static void speedtch_test_sequence(struct speedtch_instance_data *instance) 205*1da177e4SLinus Torvalds { 206*1da177e4SLinus Torvalds struct usb_device *dev = instance->u.usb_dev; 207*1da177e4SLinus Torvalds unsigned char buf[10]; 208*1da177e4SLinus Torvalds int ret; 209*1da177e4SLinus Torvalds 210*1da177e4SLinus Torvalds /* URB 147 */ 211*1da177e4SLinus Torvalds buf[0] = 0x1c; 212*1da177e4SLinus Torvalds buf[1] = 0x50; 213*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 214*1da177e4SLinus Torvalds 0x01, 0x40, 0x0b, 0x00, buf, 2, 100); 215*1da177e4SLinus Torvalds if (ret < 0) 216*1da177e4SLinus Torvalds printk(KERN_WARNING "%s failed on URB147: %d\n", __func__, ret); 217*1da177e4SLinus Torvalds 218*1da177e4SLinus Torvalds /* URB 148 */ 219*1da177e4SLinus Torvalds buf[0] = 0x32; 220*1da177e4SLinus Torvalds buf[1] = 0x00; 221*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 222*1da177e4SLinus Torvalds 0x01, 0x40, 0x02, 0x00, buf, 2, 100); 223*1da177e4SLinus Torvalds if (ret < 0) 224*1da177e4SLinus Torvalds printk(KERN_WARNING "%s failed on URB148: %d\n", __func__, ret); 225*1da177e4SLinus Torvalds 226*1da177e4SLinus Torvalds /* URB 149 */ 227*1da177e4SLinus Torvalds buf[0] = 0x01; 228*1da177e4SLinus Torvalds buf[1] = 0x00; 229*1da177e4SLinus Torvalds buf[2] = 0x01; 230*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 231*1da177e4SLinus Torvalds 0x01, 0x40, 0x03, 0x00, buf, 3, 100); 232*1da177e4SLinus Torvalds if (ret < 0) 233*1da177e4SLinus Torvalds printk(KERN_WARNING "%s failed on URB149: %d\n", __func__, ret); 234*1da177e4SLinus Torvalds 235*1da177e4SLinus Torvalds /* URB 150 */ 236*1da177e4SLinus Torvalds buf[0] = 0x01; 237*1da177e4SLinus Torvalds buf[1] = 0x00; 238*1da177e4SLinus Torvalds buf[2] = 0x01; 239*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 240*1da177e4SLinus Torvalds 0x01, 0x40, 0x04, 0x00, buf, 3, 100); 241*1da177e4SLinus Torvalds if (ret < 0) 242*1da177e4SLinus Torvalds printk(KERN_WARNING "%s failed on URB150: %d\n", __func__, ret); 243*1da177e4SLinus Torvalds } 244*1da177e4SLinus Torvalds 245*1da177e4SLinus Torvalds static int speedtch_start_synchro(struct speedtch_instance_data *instance) 246*1da177e4SLinus Torvalds { 247*1da177e4SLinus Torvalds struct usb_device *dev = instance->u.usb_dev; 248*1da177e4SLinus Torvalds unsigned char buf[2]; 249*1da177e4SLinus Torvalds int ret; 250*1da177e4SLinus Torvalds 251*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 252*1da177e4SLinus Torvalds 0x12, 0xc0, 0x04, 0x00, 253*1da177e4SLinus Torvalds buf, sizeof(buf), CTRL_TIMEOUT); 254*1da177e4SLinus Torvalds if (ret < 0) { 255*1da177e4SLinus Torvalds printk(KERN_WARNING "SpeedTouch: Failed to start ADSL synchronisation: %d\n", ret); 256*1da177e4SLinus Torvalds return ret; 257*1da177e4SLinus Torvalds } 258*1da177e4SLinus Torvalds 259*1da177e4SLinus Torvalds dbg("speedtch_start_synchro: modem prodded. %d Bytes returned: %02x %02x", ret, buf[0], buf[1]); 260*1da177e4SLinus Torvalds return 0; 261*1da177e4SLinus Torvalds } 262*1da177e4SLinus Torvalds 263*1da177e4SLinus Torvalds static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs) 264*1da177e4SLinus Torvalds { 265*1da177e4SLinus Torvalds struct speedtch_instance_data *instance = urb->context; 266*1da177e4SLinus Torvalds unsigned int count = urb->actual_length; 267*1da177e4SLinus Torvalds int ret; 268*1da177e4SLinus Torvalds 269*1da177e4SLinus Torvalds /* The magic interrupt for "up state" */ 270*1da177e4SLinus Torvalds const static unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 }; 271*1da177e4SLinus Torvalds /* The magic interrupt for "down state" */ 272*1da177e4SLinus Torvalds const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 }; 273*1da177e4SLinus Torvalds 274*1da177e4SLinus Torvalds switch (urb->status) { 275*1da177e4SLinus Torvalds case 0: 276*1da177e4SLinus Torvalds /* success */ 277*1da177e4SLinus Torvalds break; 278*1da177e4SLinus Torvalds case -ECONNRESET: 279*1da177e4SLinus Torvalds case -ENOENT: 280*1da177e4SLinus Torvalds case -ESHUTDOWN: 281*1da177e4SLinus Torvalds /* this urb is terminated; clean up */ 282*1da177e4SLinus Torvalds dbg("%s - urb shutting down with status: %d", __func__, urb->status); 283*1da177e4SLinus Torvalds return; 284*1da177e4SLinus Torvalds default: 285*1da177e4SLinus Torvalds dbg("%s - nonzero urb status received: %d", __func__, urb->status); 286*1da177e4SLinus Torvalds goto exit; 287*1da177e4SLinus Torvalds } 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds if (count < 6) { 290*1da177e4SLinus Torvalds dbg("%s - int packet too short", __func__); 291*1da177e4SLinus Torvalds goto exit; 292*1da177e4SLinus Torvalds } 293*1da177e4SLinus Torvalds 294*1da177e4SLinus Torvalds if (!memcmp(up_int, instance->int_data, 6)) { 295*1da177e4SLinus Torvalds del_timer(&instance->poll_timer); 296*1da177e4SLinus Torvalds printk(KERN_NOTICE "DSL line goes up\n"); 297*1da177e4SLinus Torvalds } else if (!memcmp(down_int, instance->int_data, 6)) { 298*1da177e4SLinus Torvalds printk(KERN_NOTICE "DSL line goes down\n"); 299*1da177e4SLinus Torvalds } else { 300*1da177e4SLinus Torvalds int i; 301*1da177e4SLinus Torvalds 302*1da177e4SLinus Torvalds printk(KERN_DEBUG "Unknown interrupt packet of %d bytes:", count); 303*1da177e4SLinus Torvalds for (i = 0; i < count; i++) 304*1da177e4SLinus Torvalds printk(" %02x", instance->int_data[i]); 305*1da177e4SLinus Torvalds printk("\n"); 306*1da177e4SLinus Torvalds } 307*1da177e4SLinus Torvalds schedule_work(&instance->poll_work); 308*1da177e4SLinus Torvalds 309*1da177e4SLinus Torvalds exit: 310*1da177e4SLinus Torvalds rmb(); 311*1da177e4SLinus Torvalds if (!instance->int_urb) 312*1da177e4SLinus Torvalds return; 313*1da177e4SLinus Torvalds 314*1da177e4SLinus Torvalds ret = usb_submit_urb(urb, GFP_ATOMIC); 315*1da177e4SLinus Torvalds if (ret) 316*1da177e4SLinus Torvalds err("%s - usb_submit_urb failed with result %d", __func__, ret); 317*1da177e4SLinus Torvalds } 318*1da177e4SLinus Torvalds 319*1da177e4SLinus Torvalds static int speedtch_get_status(struct speedtch_instance_data *instance, 320*1da177e4SLinus Torvalds unsigned char *buf) 321*1da177e4SLinus Torvalds { 322*1da177e4SLinus Torvalds struct usb_device *dev = instance->u.usb_dev; 323*1da177e4SLinus Torvalds int ret; 324*1da177e4SLinus Torvalds 325*1da177e4SLinus Torvalds memset(buf, 0, TOTAL); 326*1da177e4SLinus Torvalds 327*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 328*1da177e4SLinus Torvalds 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, 329*1da177e4SLinus Torvalds CTRL_TIMEOUT); 330*1da177e4SLinus Torvalds if (ret < 0) { 331*1da177e4SLinus Torvalds dbg("MSG 7 failed"); 332*1da177e4SLinus Torvalds return ret; 333*1da177e4SLinus Torvalds } 334*1da177e4SLinus Torvalds 335*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 336*1da177e4SLinus Torvalds 0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b, 337*1da177e4SLinus Torvalds CTRL_TIMEOUT); 338*1da177e4SLinus Torvalds if (ret < 0) { 339*1da177e4SLinus Torvalds dbg("MSG B failed"); 340*1da177e4SLinus Torvalds return ret; 341*1da177e4SLinus Torvalds } 342*1da177e4SLinus Torvalds 343*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 344*1da177e4SLinus Torvalds 0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d, 345*1da177e4SLinus Torvalds CTRL_TIMEOUT); 346*1da177e4SLinus Torvalds if (ret < 0) { 347*1da177e4SLinus Torvalds dbg("MSG D failed"); 348*1da177e4SLinus Torvalds return ret; 349*1da177e4SLinus Torvalds } 350*1da177e4SLinus Torvalds 351*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 352*1da177e4SLinus Torvalds 0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e, 353*1da177e4SLinus Torvalds CTRL_TIMEOUT); 354*1da177e4SLinus Torvalds if (ret < 0) { 355*1da177e4SLinus Torvalds dbg("MSG E failed"); 356*1da177e4SLinus Torvalds return ret; 357*1da177e4SLinus Torvalds } 358*1da177e4SLinus Torvalds 359*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 360*1da177e4SLinus Torvalds 0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f, 361*1da177e4SLinus Torvalds CTRL_TIMEOUT); 362*1da177e4SLinus Torvalds if (ret < 0) { 363*1da177e4SLinus Torvalds dbg("MSG F failed"); 364*1da177e4SLinus Torvalds return ret; 365*1da177e4SLinus Torvalds } 366*1da177e4SLinus Torvalds 367*1da177e4SLinus Torvalds return 0; 368*1da177e4SLinus Torvalds } 369*1da177e4SLinus Torvalds 370*1da177e4SLinus Torvalds static void speedtch_poll_status(struct speedtch_instance_data *instance) 371*1da177e4SLinus Torvalds { 372*1da177e4SLinus Torvalds unsigned char buf[TOTAL]; 373*1da177e4SLinus Torvalds int ret; 374*1da177e4SLinus Torvalds 375*1da177e4SLinus Torvalds ret = speedtch_get_status(instance, buf); 376*1da177e4SLinus Torvalds if (ret) { 377*1da177e4SLinus Torvalds printk(KERN_WARNING 378*1da177e4SLinus Torvalds "SpeedTouch: Error %d fetching device status\n", ret); 379*1da177e4SLinus Torvalds return; 380*1da177e4SLinus Torvalds } 381*1da177e4SLinus Torvalds 382*1da177e4SLinus Torvalds dbg("Line state %02x", buf[OFFSET_7]); 383*1da177e4SLinus Torvalds 384*1da177e4SLinus Torvalds switch (buf[OFFSET_7]) { 385*1da177e4SLinus Torvalds case 0: 386*1da177e4SLinus Torvalds if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) { 387*1da177e4SLinus Torvalds instance->u.atm_dev->signal = ATM_PHY_SIG_LOST; 388*1da177e4SLinus Torvalds printk(KERN_NOTICE "ADSL line is down\n"); 389*1da177e4SLinus Torvalds } 390*1da177e4SLinus Torvalds break; 391*1da177e4SLinus Torvalds 392*1da177e4SLinus Torvalds case 0x08: 393*1da177e4SLinus Torvalds if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { 394*1da177e4SLinus Torvalds instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN; 395*1da177e4SLinus Torvalds printk(KERN_NOTICE "ADSL line is blocked?\n"); 396*1da177e4SLinus Torvalds } 397*1da177e4SLinus Torvalds break; 398*1da177e4SLinus Torvalds 399*1da177e4SLinus Torvalds case 0x10: 400*1da177e4SLinus Torvalds if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) { 401*1da177e4SLinus Torvalds instance->u.atm_dev->signal = ATM_PHY_SIG_LOST; 402*1da177e4SLinus Torvalds printk(KERN_NOTICE "ADSL line is synchronising\n"); 403*1da177e4SLinus Torvalds } 404*1da177e4SLinus Torvalds break; 405*1da177e4SLinus Torvalds 406*1da177e4SLinus Torvalds case 0x20: 407*1da177e4SLinus Torvalds if (instance->u.atm_dev->signal != ATM_PHY_SIG_FOUND) { 408*1da177e4SLinus Torvalds int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) 409*1da177e4SLinus Torvalds | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24); 410*1da177e4SLinus Torvalds int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) 411*1da177e4SLinus Torvalds | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24); 412*1da177e4SLinus Torvalds 413*1da177e4SLinus Torvalds if (!(down_speed & 0x0000ffff) && 414*1da177e4SLinus Torvalds !(up_speed & 0x0000ffff)) { 415*1da177e4SLinus Torvalds down_speed >>= 16; 416*1da177e4SLinus Torvalds up_speed >>= 16; 417*1da177e4SLinus Torvalds } 418*1da177e4SLinus Torvalds instance->u.atm_dev->link_rate = down_speed * 1000 / 424; 419*1da177e4SLinus Torvalds instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND; 420*1da177e4SLinus Torvalds 421*1da177e4SLinus Torvalds printk(KERN_NOTICE 422*1da177e4SLinus Torvalds "ADSL line is up (%d Kib/s down | %d Kib/s up)\n", 423*1da177e4SLinus Torvalds down_speed, up_speed); 424*1da177e4SLinus Torvalds } 425*1da177e4SLinus Torvalds break; 426*1da177e4SLinus Torvalds 427*1da177e4SLinus Torvalds default: 428*1da177e4SLinus Torvalds if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { 429*1da177e4SLinus Torvalds instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN; 430*1da177e4SLinus Torvalds printk(KERN_NOTICE "Unknown line state %02x\n", buf[OFFSET_7]); 431*1da177e4SLinus Torvalds } 432*1da177e4SLinus Torvalds break; 433*1da177e4SLinus Torvalds } 434*1da177e4SLinus Torvalds } 435*1da177e4SLinus Torvalds 436*1da177e4SLinus Torvalds static void speedtch_timer_poll(unsigned long data) 437*1da177e4SLinus Torvalds { 438*1da177e4SLinus Torvalds struct speedtch_instance_data *instance = (void *)data; 439*1da177e4SLinus Torvalds 440*1da177e4SLinus Torvalds schedule_work(&instance->poll_work); 441*1da177e4SLinus Torvalds mod_timer(&instance->poll_timer, jiffies + (5 * HZ)); 442*1da177e4SLinus Torvalds } 443*1da177e4SLinus Torvalds 444*1da177e4SLinus Torvalds #ifdef USE_FW_LOADER 445*1da177e4SLinus Torvalds static void speedtch_upload_firmware(struct speedtch_instance_data *instance, 446*1da177e4SLinus Torvalds const struct firmware *fw1, 447*1da177e4SLinus Torvalds const struct firmware *fw2) 448*1da177e4SLinus Torvalds { 449*1da177e4SLinus Torvalds unsigned char *buffer; 450*1da177e4SLinus Torvalds struct usb_device *usb_dev = instance->u.usb_dev; 451*1da177e4SLinus Torvalds struct usb_interface *intf; 452*1da177e4SLinus Torvalds int actual_length, ret; 453*1da177e4SLinus Torvalds int offset; 454*1da177e4SLinus Torvalds 455*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware"); 456*1da177e4SLinus Torvalds 457*1da177e4SLinus Torvalds if (!(intf = usb_ifnum_to_if(usb_dev, 2))) { 458*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: interface not found!"); 459*1da177e4SLinus Torvalds goto fail; 460*1da177e4SLinus Torvalds } 461*1da177e4SLinus Torvalds 462*1da177e4SLinus Torvalds if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) { 463*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: no memory for buffer!"); 464*1da177e4SLinus Torvalds goto fail; 465*1da177e4SLinus Torvalds } 466*1da177e4SLinus Torvalds 467*1da177e4SLinus Torvalds /* A user-space firmware loader may already have claimed interface #2 */ 468*1da177e4SLinus Torvalds if ((ret = 469*1da177e4SLinus Torvalds usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) < 0) { 470*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: interface in use (%d)!", ret); 471*1da177e4SLinus Torvalds goto fail_free; 472*1da177e4SLinus Torvalds } 473*1da177e4SLinus Torvalds 474*1da177e4SLinus Torvalds /* URB 7 */ 475*1da177e4SLinus Torvalds if (dl_512_first) { /* some modems need a read before writing the firmware */ 476*1da177e4SLinus Torvalds ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), 477*1da177e4SLinus Torvalds buffer, 0x200, &actual_length, 2000); 478*1da177e4SLinus Torvalds 479*1da177e4SLinus Torvalds if (ret < 0 && ret != -ETIMEDOUT) 480*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: read BLOCK0 from modem failed (%d)!", ret); 481*1da177e4SLinus Torvalds else 482*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: BLOCK0 downloaded (%d bytes)", ret); 483*1da177e4SLinus Torvalds } 484*1da177e4SLinus Torvalds 485*1da177e4SLinus Torvalds /* URB 8 : both leds are static green */ 486*1da177e4SLinus Torvalds for (offset = 0; offset < fw1->size; offset += PAGE_SIZE) { 487*1da177e4SLinus Torvalds int thislen = min_t(int, PAGE_SIZE, fw1->size - offset); 488*1da177e4SLinus Torvalds memcpy(buffer, fw1->data + offset, thislen); 489*1da177e4SLinus Torvalds 490*1da177e4SLinus Torvalds ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), 491*1da177e4SLinus Torvalds buffer, thislen, &actual_length, DATA_TIMEOUT); 492*1da177e4SLinus Torvalds 493*1da177e4SLinus Torvalds if (ret < 0) { 494*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: write BLOCK1 to modem failed (%d)!", ret); 495*1da177e4SLinus Torvalds goto fail_release; 496*1da177e4SLinus Torvalds } 497*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: BLOCK1 uploaded (%zu bytes)", fw1->size); 498*1da177e4SLinus Torvalds } 499*1da177e4SLinus Torvalds 500*1da177e4SLinus Torvalds /* USB led blinking green, ADSL led off */ 501*1da177e4SLinus Torvalds 502*1da177e4SLinus Torvalds /* URB 11 */ 503*1da177e4SLinus Torvalds ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), 504*1da177e4SLinus Torvalds buffer, 0x200, &actual_length, DATA_TIMEOUT); 505*1da177e4SLinus Torvalds 506*1da177e4SLinus Torvalds if (ret < 0) { 507*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: read BLOCK2 from modem failed (%d)!", ret); 508*1da177e4SLinus Torvalds goto fail_release; 509*1da177e4SLinus Torvalds } 510*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: BLOCK2 downloaded (%d bytes)", actual_length); 511*1da177e4SLinus Torvalds 512*1da177e4SLinus Torvalds /* URBs 12 to 139 - USB led blinking green, ADSL led off */ 513*1da177e4SLinus Torvalds for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) { 514*1da177e4SLinus Torvalds int thislen = min_t(int, PAGE_SIZE, fw2->size - offset); 515*1da177e4SLinus Torvalds memcpy(buffer, fw2->data + offset, thislen); 516*1da177e4SLinus Torvalds 517*1da177e4SLinus Torvalds ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), 518*1da177e4SLinus Torvalds buffer, thislen, &actual_length, DATA_TIMEOUT); 519*1da177e4SLinus Torvalds 520*1da177e4SLinus Torvalds if (ret < 0) { 521*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: write BLOCK3 to modem failed (%d)!", ret); 522*1da177e4SLinus Torvalds goto fail_release; 523*1da177e4SLinus Torvalds } 524*1da177e4SLinus Torvalds } 525*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: BLOCK3 uploaded (%zu bytes)", fw2->size); 526*1da177e4SLinus Torvalds 527*1da177e4SLinus Torvalds /* USB led static green, ADSL led static red */ 528*1da177e4SLinus Torvalds 529*1da177e4SLinus Torvalds /* URB 142 */ 530*1da177e4SLinus Torvalds ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE), 531*1da177e4SLinus Torvalds buffer, 0x200, &actual_length, DATA_TIMEOUT); 532*1da177e4SLinus Torvalds 533*1da177e4SLinus Torvalds if (ret < 0) { 534*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: read BLOCK4 from modem failed (%d)!", ret); 535*1da177e4SLinus Torvalds goto fail_release; 536*1da177e4SLinus Torvalds } 537*1da177e4SLinus Torvalds 538*1da177e4SLinus Torvalds /* success */ 539*1da177e4SLinus Torvalds dbg("speedtch_upload_firmware: BLOCK4 downloaded (%d bytes)", actual_length); 540*1da177e4SLinus Torvalds 541*1da177e4SLinus Torvalds /* Delay to allow firmware to start up. We can do this here 542*1da177e4SLinus Torvalds because we're in our own kernel thread anyway. */ 543*1da177e4SLinus Torvalds msleep(1000); 544*1da177e4SLinus Torvalds 545*1da177e4SLinus Torvalds /* Enable software buffering, if requested */ 546*1da177e4SLinus Torvalds if (sw_buffering) 547*1da177e4SLinus Torvalds speedtch_set_swbuff(instance, 1); 548*1da177e4SLinus Torvalds 549*1da177e4SLinus Torvalds /* Magic spell; don't ask us what this does */ 550*1da177e4SLinus Torvalds speedtch_test_sequence(instance); 551*1da177e4SLinus Torvalds 552*1da177e4SLinus Torvalds /* Start modem synchronisation */ 553*1da177e4SLinus Torvalds if (speedtch_start_synchro(instance)) 554*1da177e4SLinus Torvalds dbg("speedtch_start_synchro: failed"); 555*1da177e4SLinus Torvalds 556*1da177e4SLinus Torvalds speedtch_got_firmware(instance, 1); 557*1da177e4SLinus Torvalds 558*1da177e4SLinus Torvalds free_page((unsigned long)buffer); 559*1da177e4SLinus Torvalds return; 560*1da177e4SLinus Torvalds 561*1da177e4SLinus Torvalds fail_release: 562*1da177e4SLinus Torvalds /* Only release interface #2 if uploading failed; we don't release it 563*1da177e4SLinus Torvalds we succeeded. This prevents the userspace tools from trying to load 564*1da177e4SLinus Torvalds the firmware themselves */ 565*1da177e4SLinus Torvalds usb_driver_release_interface(&speedtch_usb_driver, intf); 566*1da177e4SLinus Torvalds fail_free: 567*1da177e4SLinus Torvalds free_page((unsigned long)buffer); 568*1da177e4SLinus Torvalds fail: 569*1da177e4SLinus Torvalds speedtch_got_firmware(instance, 0); 570*1da177e4SLinus Torvalds } 571*1da177e4SLinus Torvalds 572*1da177e4SLinus Torvalds static int speedtch_find_firmware(struct speedtch_instance_data 573*1da177e4SLinus Torvalds *instance, int phase, 574*1da177e4SLinus Torvalds const struct firmware **fw_p) 575*1da177e4SLinus Torvalds { 576*1da177e4SLinus Torvalds char buf[24]; 577*1da177e4SLinus Torvalds const u16 bcdDevice = le16_to_cpu(instance->u.usb_dev->descriptor.bcdDevice); 578*1da177e4SLinus Torvalds const u8 major_revision = bcdDevice >> 8; 579*1da177e4SLinus Torvalds const u8 minor_revision = bcdDevice & 0xff; 580*1da177e4SLinus Torvalds 581*1da177e4SLinus Torvalds sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision); 582*1da177e4SLinus Torvalds dbg("speedtch_find_firmware: looking for %s", buf); 583*1da177e4SLinus Torvalds 584*1da177e4SLinus Torvalds if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) { 585*1da177e4SLinus Torvalds sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision); 586*1da177e4SLinus Torvalds dbg("speedtch_find_firmware: looking for %s", buf); 587*1da177e4SLinus Torvalds 588*1da177e4SLinus Torvalds if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) { 589*1da177e4SLinus Torvalds sprintf(buf, "speedtch-%d.bin", phase); 590*1da177e4SLinus Torvalds dbg("speedtch_find_firmware: looking for %s", buf); 591*1da177e4SLinus Torvalds 592*1da177e4SLinus Torvalds if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) { 593*1da177e4SLinus Torvalds dev_warn(&instance->u.usb_dev->dev, "no stage %d firmware found!", phase); 594*1da177e4SLinus Torvalds return -ENOENT; 595*1da177e4SLinus Torvalds } 596*1da177e4SLinus Torvalds } 597*1da177e4SLinus Torvalds } 598*1da177e4SLinus Torvalds 599*1da177e4SLinus Torvalds dev_info(&instance->u.usb_dev->dev, "found stage %d firmware %s\n", phase, buf); 600*1da177e4SLinus Torvalds 601*1da177e4SLinus Torvalds return 0; 602*1da177e4SLinus Torvalds } 603*1da177e4SLinus Torvalds 604*1da177e4SLinus Torvalds static int speedtch_load_firmware(void *arg) 605*1da177e4SLinus Torvalds { 606*1da177e4SLinus Torvalds const struct firmware *fw1, *fw2; 607*1da177e4SLinus Torvalds struct speedtch_instance_data *instance = arg; 608*1da177e4SLinus Torvalds 609*1da177e4SLinus Torvalds BUG_ON(!instance); 610*1da177e4SLinus Torvalds 611*1da177e4SLinus Torvalds daemonize("firmware/speedtch"); 612*1da177e4SLinus Torvalds 613*1da177e4SLinus Torvalds if (!speedtch_find_firmware(instance, 1, &fw1)) { 614*1da177e4SLinus Torvalds if (!speedtch_find_firmware(instance, 2, &fw2)) { 615*1da177e4SLinus Torvalds speedtch_upload_firmware(instance, fw1, fw2); 616*1da177e4SLinus Torvalds release_firmware(fw2); 617*1da177e4SLinus Torvalds } 618*1da177e4SLinus Torvalds release_firmware(fw1); 619*1da177e4SLinus Torvalds } 620*1da177e4SLinus Torvalds 621*1da177e4SLinus Torvalds /* In case we failed, set state back to NO_FIRMWARE so that 622*1da177e4SLinus Torvalds another later attempt may work. Otherwise, we never actually 623*1da177e4SLinus Torvalds manage to recover if, for example, the firmware is on /usr and 624*1da177e4SLinus Torvalds we look for it too early. */ 625*1da177e4SLinus Torvalds speedtch_got_firmware(instance, 0); 626*1da177e4SLinus Torvalds 627*1da177e4SLinus Torvalds module_put(THIS_MODULE); 628*1da177e4SLinus Torvalds udsl_put_instance(&instance->u); 629*1da177e4SLinus Torvalds return 0; 630*1da177e4SLinus Torvalds } 631*1da177e4SLinus Torvalds #endif /* USE_FW_LOADER */ 632*1da177e4SLinus Torvalds 633*1da177e4SLinus Torvalds static void speedtch_firmware_start(struct speedtch_instance_data *instance) 634*1da177e4SLinus Torvalds { 635*1da177e4SLinus Torvalds #ifdef USE_FW_LOADER 636*1da177e4SLinus Torvalds int ret; 637*1da177e4SLinus Torvalds #endif 638*1da177e4SLinus Torvalds 639*1da177e4SLinus Torvalds dbg("speedtch_firmware_start"); 640*1da177e4SLinus Torvalds 641*1da177e4SLinus Torvalds down(&instance->u.serialize); /* vs self, speedtch_got_firmware */ 642*1da177e4SLinus Torvalds 643*1da177e4SLinus Torvalds if (instance->u.status >= UDSL_LOADING_FIRMWARE) { 644*1da177e4SLinus Torvalds up(&instance->u.serialize); 645*1da177e4SLinus Torvalds return; 646*1da177e4SLinus Torvalds } 647*1da177e4SLinus Torvalds 648*1da177e4SLinus Torvalds instance->u.status = UDSL_LOADING_FIRMWARE; 649*1da177e4SLinus Torvalds up(&instance->u.serialize); 650*1da177e4SLinus Torvalds 651*1da177e4SLinus Torvalds #ifdef USE_FW_LOADER 652*1da177e4SLinus Torvalds udsl_get_instance(&instance->u); 653*1da177e4SLinus Torvalds try_module_get(THIS_MODULE); 654*1da177e4SLinus Torvalds 655*1da177e4SLinus Torvalds ret = kernel_thread(speedtch_load_firmware, instance, 656*1da177e4SLinus Torvalds CLONE_FS | CLONE_FILES); 657*1da177e4SLinus Torvalds 658*1da177e4SLinus Torvalds if (ret >= 0) 659*1da177e4SLinus Torvalds return; /* OK */ 660*1da177e4SLinus Torvalds 661*1da177e4SLinus Torvalds dbg("speedtch_firmware_start: kernel_thread failed (%d)!", ret); 662*1da177e4SLinus Torvalds 663*1da177e4SLinus Torvalds module_put(THIS_MODULE); 664*1da177e4SLinus Torvalds udsl_put_instance(&instance->u); 665*1da177e4SLinus Torvalds /* Just pretend it never happened... hope modem_run happens */ 666*1da177e4SLinus Torvalds #endif /* USE_FW_LOADER */ 667*1da177e4SLinus Torvalds 668*1da177e4SLinus Torvalds speedtch_got_firmware(instance, 0); 669*1da177e4SLinus Torvalds } 670*1da177e4SLinus Torvalds 671*1da177e4SLinus Torvalds static int speedtch_firmware_wait(struct udsl_instance_data *instance) 672*1da177e4SLinus Torvalds { 673*1da177e4SLinus Torvalds speedtch_firmware_start((void *)instance); 674*1da177e4SLinus Torvalds 675*1da177e4SLinus Torvalds if (wait_event_interruptible(instance->firmware_waiters, instance->status != UDSL_LOADING_FIRMWARE) < 0) 676*1da177e4SLinus Torvalds return -ERESTARTSYS; 677*1da177e4SLinus Torvalds 678*1da177e4SLinus Torvalds return (instance->status == UDSL_LOADED_FIRMWARE) ? 0 : -EAGAIN; 679*1da177e4SLinus Torvalds } 680*1da177e4SLinus Torvalds 681*1da177e4SLinus Torvalds /********** 682*1da177e4SLinus Torvalds ** USB ** 683*1da177e4SLinus Torvalds **********/ 684*1da177e4SLinus Torvalds 685*1da177e4SLinus Torvalds static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code, 686*1da177e4SLinus Torvalds void *user_data) 687*1da177e4SLinus Torvalds { 688*1da177e4SLinus Torvalds struct speedtch_instance_data *instance = usb_get_intfdata(intf); 689*1da177e4SLinus Torvalds 690*1da177e4SLinus Torvalds dbg("speedtch_usb_ioctl entered"); 691*1da177e4SLinus Torvalds 692*1da177e4SLinus Torvalds if (!instance) { 693*1da177e4SLinus Torvalds dbg("speedtch_usb_ioctl: NULL instance!"); 694*1da177e4SLinus Torvalds return -ENODEV; 695*1da177e4SLinus Torvalds } 696*1da177e4SLinus Torvalds 697*1da177e4SLinus Torvalds switch (code) { 698*1da177e4SLinus Torvalds case UDSL_IOCTL_LINE_UP: 699*1da177e4SLinus Torvalds instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND; 700*1da177e4SLinus Torvalds speedtch_got_firmware(instance, 1); 701*1da177e4SLinus Torvalds return (instance->u.status == UDSL_LOADED_FIRMWARE) ? 0 : -EIO; 702*1da177e4SLinus Torvalds case UDSL_IOCTL_LINE_DOWN: 703*1da177e4SLinus Torvalds instance->u.atm_dev->signal = ATM_PHY_SIG_LOST; 704*1da177e4SLinus Torvalds return 0; 705*1da177e4SLinus Torvalds default: 706*1da177e4SLinus Torvalds return -ENOTTY; 707*1da177e4SLinus Torvalds } 708*1da177e4SLinus Torvalds } 709*1da177e4SLinus Torvalds 710*1da177e4SLinus Torvalds static int speedtch_usb_probe(struct usb_interface *intf, 711*1da177e4SLinus Torvalds const struct usb_device_id *id) 712*1da177e4SLinus Torvalds { 713*1da177e4SLinus Torvalds struct usb_device *dev = interface_to_usbdev(intf); 714*1da177e4SLinus Torvalds int ifnum = intf->altsetting->desc.bInterfaceNumber; 715*1da177e4SLinus Torvalds struct speedtch_instance_data *instance; 716*1da177e4SLinus Torvalds unsigned char mac_str[13]; 717*1da177e4SLinus Torvalds int ret, i; 718*1da177e4SLinus Torvalds char buf7[SIZE_7]; 719*1da177e4SLinus Torvalds 720*1da177e4SLinus Torvalds dbg("speedtch_usb_probe: trying device with vendor=0x%x, product=0x%x, ifnum %d", 721*1da177e4SLinus Torvalds le16_to_cpu(dev->descriptor.idVendor), 722*1da177e4SLinus Torvalds le16_to_cpu(dev->descriptor.idProduct), ifnum); 723*1da177e4SLinus Torvalds 724*1da177e4SLinus Torvalds if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) || 725*1da177e4SLinus Torvalds (ifnum != 1)) 726*1da177e4SLinus Torvalds return -ENODEV; 727*1da177e4SLinus Torvalds 728*1da177e4SLinus Torvalds dbg("speedtch_usb_probe: device accepted"); 729*1da177e4SLinus Torvalds 730*1da177e4SLinus Torvalds /* instance init */ 731*1da177e4SLinus Torvalds instance = kmalloc(sizeof(*instance), GFP_KERNEL); 732*1da177e4SLinus Torvalds if (!instance) { 733*1da177e4SLinus Torvalds dbg("speedtch_usb_probe: no memory for instance data!"); 734*1da177e4SLinus Torvalds return -ENOMEM; 735*1da177e4SLinus Torvalds } 736*1da177e4SLinus Torvalds 737*1da177e4SLinus Torvalds memset(instance, 0, sizeof(struct speedtch_instance_data)); 738*1da177e4SLinus Torvalds 739*1da177e4SLinus Torvalds if ((ret = usb_set_interface(dev, 0, 0)) < 0) 740*1da177e4SLinus Torvalds goto fail; 741*1da177e4SLinus Torvalds 742*1da177e4SLinus Torvalds if ((ret = usb_set_interface(dev, 2, 0)) < 0) 743*1da177e4SLinus Torvalds goto fail; 744*1da177e4SLinus Torvalds 745*1da177e4SLinus Torvalds instance->u.data_endpoint = SPEEDTCH_ENDPOINT_DATA; 746*1da177e4SLinus Torvalds instance->u.firmware_wait = speedtch_firmware_wait; 747*1da177e4SLinus Torvalds instance->u.driver_name = speedtch_driver_name; 748*1da177e4SLinus Torvalds 749*1da177e4SLinus Torvalds ret = udsl_instance_setup(dev, &instance->u); 750*1da177e4SLinus Torvalds if (ret) 751*1da177e4SLinus Torvalds goto fail; 752*1da177e4SLinus Torvalds 753*1da177e4SLinus Torvalds init_timer(&instance->poll_timer); 754*1da177e4SLinus Torvalds instance->poll_timer.function = speedtch_timer_poll; 755*1da177e4SLinus Torvalds instance->poll_timer.data = (unsigned long)instance; 756*1da177e4SLinus Torvalds 757*1da177e4SLinus Torvalds INIT_WORK(&instance->poll_work, (void *)speedtch_poll_status, instance); 758*1da177e4SLinus Torvalds 759*1da177e4SLinus Torvalds /* set MAC address, it is stored in the serial number */ 760*1da177e4SLinus Torvalds memset(instance->u.atm_dev->esi, 0, sizeof(instance->u.atm_dev->esi)); 761*1da177e4SLinus Torvalds if (usb_string(dev, dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) { 762*1da177e4SLinus Torvalds for (i = 0; i < 6; i++) 763*1da177e4SLinus Torvalds instance->u.atm_dev->esi[i] = 764*1da177e4SLinus Torvalds (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1])); 765*1da177e4SLinus Torvalds } 766*1da177e4SLinus Torvalds 767*1da177e4SLinus Torvalds /* First check whether the modem already seems to be alive */ 768*1da177e4SLinus Torvalds ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 769*1da177e4SLinus Torvalds 0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, 500); 770*1da177e4SLinus Torvalds 771*1da177e4SLinus Torvalds if (ret == SIZE_7) { 772*1da177e4SLinus Torvalds dbg("firmware appears to be already loaded"); 773*1da177e4SLinus Torvalds speedtch_got_firmware(instance, 1); 774*1da177e4SLinus Torvalds speedtch_poll_status(instance); 775*1da177e4SLinus Torvalds } else { 776*1da177e4SLinus Torvalds speedtch_firmware_start(instance); 777*1da177e4SLinus Torvalds } 778*1da177e4SLinus Torvalds 779*1da177e4SLinus Torvalds usb_set_intfdata(intf, instance); 780*1da177e4SLinus Torvalds 781*1da177e4SLinus Torvalds return 0; 782*1da177e4SLinus Torvalds 783*1da177e4SLinus Torvalds fail: 784*1da177e4SLinus Torvalds kfree(instance); 785*1da177e4SLinus Torvalds 786*1da177e4SLinus Torvalds return -ENOMEM; 787*1da177e4SLinus Torvalds } 788*1da177e4SLinus Torvalds 789*1da177e4SLinus Torvalds static void speedtch_usb_disconnect(struct usb_interface *intf) 790*1da177e4SLinus Torvalds { 791*1da177e4SLinus Torvalds struct speedtch_instance_data *instance = usb_get_intfdata(intf); 792*1da177e4SLinus Torvalds 793*1da177e4SLinus Torvalds dbg("speedtch_usb_disconnect entered"); 794*1da177e4SLinus Torvalds 795*1da177e4SLinus Torvalds if (!instance) { 796*1da177e4SLinus Torvalds dbg("speedtch_usb_disconnect: NULL instance!"); 797*1da177e4SLinus Torvalds return; 798*1da177e4SLinus Torvalds } 799*1da177e4SLinus Torvalds 800*1da177e4SLinus Torvalds /*QQ need to handle disconnects on interface #2 while uploading firmware */ 801*1da177e4SLinus Torvalds /*QQ and what about interface #1? */ 802*1da177e4SLinus Torvalds 803*1da177e4SLinus Torvalds if (instance->int_urb) { 804*1da177e4SLinus Torvalds struct urb *int_urb = instance->int_urb; 805*1da177e4SLinus Torvalds instance->int_urb = NULL; 806*1da177e4SLinus Torvalds wmb(); 807*1da177e4SLinus Torvalds usb_unlink_urb(int_urb); 808*1da177e4SLinus Torvalds usb_free_urb(int_urb); 809*1da177e4SLinus Torvalds } 810*1da177e4SLinus Torvalds 811*1da177e4SLinus Torvalds instance->int_data[0] = 1; 812*1da177e4SLinus Torvalds del_timer_sync(&instance->poll_timer); 813*1da177e4SLinus Torvalds wmb(); 814*1da177e4SLinus Torvalds flush_scheduled_work(); 815*1da177e4SLinus Torvalds 816*1da177e4SLinus Torvalds udsl_instance_disconnect(&instance->u); 817*1da177e4SLinus Torvalds 818*1da177e4SLinus Torvalds /* clean up */ 819*1da177e4SLinus Torvalds usb_set_intfdata(intf, NULL); 820*1da177e4SLinus Torvalds udsl_put_instance(&instance->u); 821*1da177e4SLinus Torvalds } 822*1da177e4SLinus Torvalds 823*1da177e4SLinus Torvalds /*********** 824*1da177e4SLinus Torvalds ** init ** 825*1da177e4SLinus Torvalds ***********/ 826*1da177e4SLinus Torvalds 827*1da177e4SLinus Torvalds static int __init speedtch_usb_init(void) 828*1da177e4SLinus Torvalds { 829*1da177e4SLinus Torvalds dbg("speedtch_usb_init: driver version " DRIVER_VERSION); 830*1da177e4SLinus Torvalds 831*1da177e4SLinus Torvalds return usb_register(&speedtch_usb_driver); 832*1da177e4SLinus Torvalds } 833*1da177e4SLinus Torvalds 834*1da177e4SLinus Torvalds static void __exit speedtch_usb_cleanup(void) 835*1da177e4SLinus Torvalds { 836*1da177e4SLinus Torvalds dbg("speedtch_usb_cleanup entered"); 837*1da177e4SLinus Torvalds 838*1da177e4SLinus Torvalds usb_deregister(&speedtch_usb_driver); 839*1da177e4SLinus Torvalds } 840*1da177e4SLinus Torvalds 841*1da177e4SLinus Torvalds module_init(speedtch_usb_init); 842*1da177e4SLinus Torvalds module_exit(speedtch_usb_cleanup); 843*1da177e4SLinus Torvalds 844*1da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR); 845*1da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC); 846*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 847*1da177e4SLinus Torvalds MODULE_VERSION(DRIVER_VERSION); 848