st5481_init.c revision 61ffcafafb3d985e1ab8463be0187b421614775c
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for ST5481 USB ISDN modem 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author Frode Isaksen 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO: 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * b layer1 delay? 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hotplug / unregister issues 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mod_inc/dec_use_count 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unify parts of d/b channel usb handling 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file header 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * avoid copy to isoc buffer? 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * improve usb delay? 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * merge l1 state machines? 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clean up debug 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/version.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "st5481.h" 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ISDN4Linux: driver for ST5481 USB ISDN adapter"); 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Frode Isaksen"); 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int protocol = 2; /* EURO-ISDN Default */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(protocol, int, 0); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int number_of_leds = 2; /* 2 LEDs on the adpater default */ 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(number_of_leds, int, 0); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HISAX_DEBUG 4661ffcafafb3d985e1ab8463be0187b421614775cKarsten Keilstatic int debug = 0; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, int, 0); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4961ffcafafb3d985e1ab8463be0187b421614775cKarsten Keilint st5481_debug; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(adapter_list); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ====================================================================== 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registration/deregistration with the USB layer 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function will be called when the adapter is plugged 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into the USB bus. 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int probe_st5481(struct usb_interface *intf, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_device_id *id) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *dev = interface_to_usbdev(intf); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct st5481_adapter *adapter; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hisax_b_if *b_if[2]; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval, i; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n", 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpu(dev->descriptor.idVendor), 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le16_to_cpu(dev->descriptor.idProduct), 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds number_of_leds); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter = kmalloc(sizeof(struct st5481_adapter), GFP_KERNEL); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!adapter) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(adapter, 0, sizeof(struct st5481_adapter)); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->number_of_leds = number_of_leds; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->usb_dev = dev; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->hisax_d_if.owner = THIS_MODULE; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->hisax_d_if.ifc.priv = adapter; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) { 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->bcs[i].adapter = adapter; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->bcs[i].channel = i; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&adapter->list, &adapter_list); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = st5481_setup_usb(adapter); 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = st5481_setup_d(adapter); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_usb; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = st5481_setup_b(&adapter->bcs[0]); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_d; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = st5481_setup_b(&adapter->bcs[1]); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_b; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b_if[i] = &adapter->bcs[i].b_if; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb", protocol); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_start(adapter); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, adapter); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_b: 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_release_b(&adapter->bcs[0]); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_d: 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_release_d(adapter); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_usb: 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_release_usb(adapter); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err: 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function will be called when the adapter is removed 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from the USB bus. 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void disconnect_st5481(struct usb_interface *intf) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct st5481_adapter *adapter = usb_get_intfdata(intf); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(1,""); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(intf, NULL); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!adapter) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&adapter->list); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_stop(adapter); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_release_b(&adapter->bcs[1]); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_release_b(&adapter->bcs[0]); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_release_d(adapter); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // we would actually better wait for completion of outstanding urbs 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(2); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_release_usb(adapter); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hisax_unregister(&adapter->hisax_d_if); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(adapter); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The last 4 bits in the Product Id is set with 4 pins on the chip. 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id st5481_ids[] = { 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x0) }, 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x1) }, 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x2) }, 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x3) }, 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x4) }, 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x5) }, 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x6) }, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x7) }, 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x8) }, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x9) }, 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xA) }, 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xB) }, 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xC) }, 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xD) }, 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xE) }, 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xF) }, 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (usb, st5481_ids); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver st5481_usb_driver = { 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "st5481_usb", 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = probe_st5481, 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = disconnect_st5481, 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = st5481_ids, 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init st5481_usb_init(void) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_HISAX_DEBUG 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_debug = debug; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n"); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = st5481_d_init(); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&st5481_usb_driver); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_d_exit; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_d_exit: 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_d_exit(); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit st5481_usb_exit(void) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_deregister(&st5481_usb_driver); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds st5481_d_exit(); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(st5481_usb_init); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(st5481_usb_exit); 225