]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Driver for ST5481 USB ISDN modem | |
3 | * | |
4 | * Author Frode Isaksen | |
5 | * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> | |
6 | * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> | |
7 | * | |
8 | * This software may be used and distributed according to the terms | |
9 | * of the GNU General Public License, incorporated herein by reference. | |
10 | * | |
11 | */ | |
12 | ||
13 | /* | |
14 | * TODO: | |
15 | * | |
16 | * b layer1 delay? | |
17 | * hotplug / unregister issues | |
18 | * mod_inc/dec_use_count | |
19 | * unify parts of d/b channel usb handling | |
20 | * file header | |
21 | * avoid copy to isoc buffer? | |
22 | * improve usb delay? | |
23 | * merge l1 state machines? | |
24 | * clean up debug | |
25 | */ | |
26 | ||
27 | #include <linux/config.h> | |
28 | #include <linux/version.h> | |
29 | #include <linux/module.h> | |
30 | #include <linux/init.h> | |
31 | #include <linux/usb.h> | |
32 | #include <linux/slab.h> | |
33 | #include "st5481.h" | |
34 | ||
35 | MODULE_DESCRIPTION("ISDN4Linux: driver for ST5481 USB ISDN adapter"); | |
36 | MODULE_AUTHOR("Frode Isaksen"); | |
37 | MODULE_LICENSE("GPL"); | |
38 | ||
39 | static int protocol = 2; /* EURO-ISDN Default */ | |
40 | module_param(protocol, int, 0); | |
41 | ||
42 | static int number_of_leds = 2; /* 2 LEDs on the adpater default */ | |
43 | module_param(number_of_leds, int, 0); | |
44 | ||
45 | #ifdef CONFIG_HISAX_DEBUG | |
46 | static int debug = 0x1; | |
47 | module_param(debug, int, 0); | |
48 | int st5481_debug; | |
49 | #endif | |
50 | ||
51 | static LIST_HEAD(adapter_list); | |
52 | ||
53 | /* ====================================================================== | |
54 | * registration/deregistration with the USB layer | |
55 | */ | |
56 | ||
57 | /* | |
58 | * This function will be called when the adapter is plugged | |
59 | * into the USB bus. | |
60 | */ | |
61 | static int probe_st5481(struct usb_interface *intf, | |
62 | const struct usb_device_id *id) | |
63 | { | |
64 | struct usb_device *dev = interface_to_usbdev(intf); | |
65 | struct st5481_adapter *adapter; | |
66 | struct hisax_b_if *b_if[2]; | |
67 | int retval, i; | |
68 | ||
69 | printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n", | |
70 | le16_to_cpu(dev->descriptor.idVendor), | |
71 | le16_to_cpu(dev->descriptor.idProduct), | |
72 | number_of_leds); | |
73 | ||
74 | adapter = kmalloc(sizeof(struct st5481_adapter), GFP_KERNEL); | |
75 | if (!adapter) | |
76 | return -ENOMEM; | |
77 | ||
78 | memset(adapter, 0, sizeof(struct st5481_adapter)); | |
79 | ||
80 | adapter->number_of_leds = number_of_leds; | |
81 | adapter->usb_dev = dev; | |
82 | ||
83 | adapter->hisax_d_if.owner = THIS_MODULE; | |
84 | adapter->hisax_d_if.ifc.priv = adapter; | |
85 | adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1; | |
86 | ||
87 | for (i = 0; i < 2; i++) { | |
88 | adapter->bcs[i].adapter = adapter; | |
89 | adapter->bcs[i].channel = i; | |
90 | adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; | |
91 | adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1; | |
92 | } | |
93 | list_add(&adapter->list, &adapter_list); | |
94 | ||
95 | retval = st5481_setup_usb(adapter); | |
96 | if (retval < 0) | |
97 | goto err; | |
98 | ||
99 | retval = st5481_setup_d(adapter); | |
100 | if (retval < 0) | |
101 | goto err_usb; | |
102 | ||
103 | retval = st5481_setup_b(&adapter->bcs[0]); | |
104 | if (retval < 0) | |
105 | goto err_d; | |
106 | ||
107 | retval = st5481_setup_b(&adapter->bcs[1]); | |
108 | if (retval < 0) | |
109 | goto err_b; | |
110 | ||
111 | for (i = 0; i < 2; i++) | |
112 | b_if[i] = &adapter->bcs[i].b_if; | |
113 | ||
114 | hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb", protocol); | |
115 | st5481_start(adapter); | |
116 | ||
117 | usb_set_intfdata(intf, adapter); | |
118 | return 0; | |
119 | ||
120 | err_b: | |
121 | st5481_release_b(&adapter->bcs[0]); | |
122 | err_d: | |
123 | st5481_release_d(adapter); | |
124 | err_usb: | |
125 | st5481_release_usb(adapter); | |
126 | err: | |
127 | return -EIO; | |
128 | } | |
129 | ||
130 | /* | |
131 | * This function will be called when the adapter is removed | |
132 | * from the USB bus. | |
133 | */ | |
134 | static void disconnect_st5481(struct usb_interface *intf) | |
135 | { | |
136 | struct st5481_adapter *adapter = usb_get_intfdata(intf); | |
137 | ||
138 | DBG(1,""); | |
139 | ||
140 | usb_set_intfdata(intf, NULL); | |
141 | if (!adapter) | |
142 | return; | |
143 | ||
144 | list_del(&adapter->list); | |
145 | ||
146 | st5481_stop(adapter); | |
147 | st5481_release_b(&adapter->bcs[1]); | |
148 | st5481_release_b(&adapter->bcs[0]); | |
149 | st5481_release_d(adapter); | |
150 | // we would actually better wait for completion of outstanding urbs | |
151 | mdelay(2); | |
152 | st5481_release_usb(adapter); | |
153 | ||
154 | hisax_unregister(&adapter->hisax_d_if); | |
155 | ||
156 | kfree(adapter); | |
157 | } | |
158 | ||
159 | /* | |
160 | * The last 4 bits in the Product Id is set with 4 pins on the chip. | |
161 | */ | |
162 | static struct usb_device_id st5481_ids[] = { | |
163 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x0) }, | |
164 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x1) }, | |
165 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x2) }, | |
166 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x3) }, | |
167 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x4) }, | |
168 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x5) }, | |
169 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x6) }, | |
170 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x7) }, | |
171 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x8) }, | |
172 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x9) }, | |
173 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xA) }, | |
174 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xB) }, | |
175 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xC) }, | |
176 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xD) }, | |
177 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xE) }, | |
178 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xF) }, | |
179 | { } | |
180 | }; | |
181 | MODULE_DEVICE_TABLE (usb, st5481_ids); | |
182 | ||
183 | static struct usb_driver st5481_usb_driver = { | |
184 | .owner = THIS_MODULE, | |
185 | .name = "st5481_usb", | |
186 | .probe = probe_st5481, | |
187 | .disconnect = disconnect_st5481, | |
188 | .id_table = st5481_ids, | |
189 | }; | |
190 | ||
191 | static int __init st5481_usb_init(void) | |
192 | { | |
193 | int retval; | |
194 | ||
195 | #ifdef CONFIG_HISAX_DEBUG | |
196 | st5481_debug = debug; | |
197 | #endif | |
198 | ||
199 | printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n"); | |
200 | ||
201 | retval = st5481_d_init(); | |
202 | if (retval < 0) | |
203 | goto out; | |
204 | ||
205 | retval = usb_register(&st5481_usb_driver); | |
206 | if (retval < 0) | |
207 | goto out_d_exit; | |
208 | ||
209 | return 0; | |
210 | ||
211 | out_d_exit: | |
212 | st5481_d_exit(); | |
213 | out: | |
214 | return retval; | |
215 | } | |
216 | ||
217 | static void __exit st5481_usb_exit(void) | |
218 | { | |
219 | usb_deregister(&st5481_usb_driver); | |
220 | st5481_d_exit(); | |
221 | } | |
222 | ||
223 | module_init(st5481_usb_init); | |
224 | module_exit(st5481_usb_exit); |