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 | ||
1da177e4 LT |
27 | #include <linux/module.h> |
28 | #include <linux/init.h> | |
29 | #include <linux/usb.h> | |
30 | #include <linux/slab.h> | |
31 | #include "st5481.h" | |
32 | ||
33 | MODULE_DESCRIPTION("ISDN4Linux: driver for ST5481 USB ISDN adapter"); | |
34 | MODULE_AUTHOR("Frode Isaksen"); | |
35 | MODULE_LICENSE("GPL"); | |
36 | ||
37 | static int protocol = 2; /* EURO-ISDN Default */ | |
38 | module_param(protocol, int, 0); | |
39 | ||
40 | static int number_of_leds = 2; /* 2 LEDs on the adpater default */ | |
41 | module_param(number_of_leds, int, 0); | |
42 | ||
43 | #ifdef CONFIG_HISAX_DEBUG | |
61ffcafa | 44 | static int debug = 0; |
1da177e4 | 45 | module_param(debug, int, 0); |
1da177e4 | 46 | #endif |
61ffcafa | 47 | int st5481_debug; |
1da177e4 LT |
48 | |
49 | static LIST_HEAD(adapter_list); | |
50 | ||
51 | /* ====================================================================== | |
52 | * registration/deregistration with the USB layer | |
53 | */ | |
54 | ||
55 | /* | |
56 | * This function will be called when the adapter is plugged | |
57 | * into the USB bus. | |
58 | */ | |
59 | static int probe_st5481(struct usb_interface *intf, | |
60 | const struct usb_device_id *id) | |
61 | { | |
62 | struct usb_device *dev = interface_to_usbdev(intf); | |
63 | struct st5481_adapter *adapter; | |
64 | struct hisax_b_if *b_if[2]; | |
65 | int retval, i; | |
66 | ||
67 | printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n", | |
68 | le16_to_cpu(dev->descriptor.idVendor), | |
69 | le16_to_cpu(dev->descriptor.idProduct), | |
70 | number_of_leds); | |
71 | ||
41f96935 | 72 | adapter = kzalloc(sizeof(struct st5481_adapter), GFP_KERNEL); |
1da177e4 LT |
73 | if (!adapter) |
74 | return -ENOMEM; | |
75 | ||
1da177e4 LT |
76 | adapter->number_of_leds = number_of_leds; |
77 | adapter->usb_dev = dev; | |
78 | ||
79 | adapter->hisax_d_if.owner = THIS_MODULE; | |
80 | adapter->hisax_d_if.ifc.priv = adapter; | |
81 | adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1; | |
82 | ||
83 | for (i = 0; i < 2; i++) { | |
84 | adapter->bcs[i].adapter = adapter; | |
85 | adapter->bcs[i].channel = i; | |
86 | adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; | |
87 | adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1; | |
88 | } | |
89 | list_add(&adapter->list, &adapter_list); | |
90 | ||
91 | retval = st5481_setup_usb(adapter); | |
92 | if (retval < 0) | |
93 | goto err; | |
94 | ||
95 | retval = st5481_setup_d(adapter); | |
96 | if (retval < 0) | |
97 | goto err_usb; | |
98 | ||
99 | retval = st5481_setup_b(&adapter->bcs[0]); | |
100 | if (retval < 0) | |
101 | goto err_d; | |
102 | ||
103 | retval = st5481_setup_b(&adapter->bcs[1]); | |
104 | if (retval < 0) | |
105 | goto err_b; | |
106 | ||
107 | for (i = 0; i < 2; i++) | |
108 | b_if[i] = &adapter->bcs[i].b_if; | |
109 | ||
ae2d990e AS |
110 | if (hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb", |
111 | protocol) != 0) | |
112 | goto err_b1; | |
113 | ||
1da177e4 LT |
114 | st5481_start(adapter); |
115 | ||
116 | usb_set_intfdata(intf, adapter); | |
117 | return 0; | |
118 | ||
ae2d990e AS |
119 | err_b1: |
120 | st5481_release_b(&adapter->bcs[1]); | |
1da177e4 LT |
121 | err_b: |
122 | st5481_release_b(&adapter->bcs[0]); | |
123 | err_d: | |
124 | st5481_release_d(adapter); | |
125 | err_usb: | |
126 | st5481_release_usb(adapter); | |
127 | err: | |
128 | return -EIO; | |
129 | } | |
130 | ||
131 | /* | |
132 | * This function will be called when the adapter is removed | |
133 | * from the USB bus. | |
134 | */ | |
135 | static void disconnect_st5481(struct usb_interface *intf) | |
136 | { | |
137 | struct st5481_adapter *adapter = usb_get_intfdata(intf); | |
138 | ||
139 | DBG(1,""); | |
140 | ||
141 | usb_set_intfdata(intf, NULL); | |
142 | if (!adapter) | |
143 | return; | |
144 | ||
145 | list_del(&adapter->list); | |
146 | ||
147 | st5481_stop(adapter); | |
148 | st5481_release_b(&adapter->bcs[1]); | |
149 | st5481_release_b(&adapter->bcs[0]); | |
150 | st5481_release_d(adapter); | |
151 | // we would actually better wait for completion of outstanding urbs | |
152 | mdelay(2); | |
153 | st5481_release_usb(adapter); | |
154 | ||
155 | hisax_unregister(&adapter->hisax_d_if); | |
156 | ||
157 | kfree(adapter); | |
158 | } | |
159 | ||
160 | /* | |
161 | * The last 4 bits in the Product Id is set with 4 pins on the chip. | |
162 | */ | |
163 | static struct usb_device_id st5481_ids[] = { | |
164 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x0) }, | |
165 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x1) }, | |
166 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x2) }, | |
167 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x3) }, | |
168 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x4) }, | |
169 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x5) }, | |
170 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x6) }, | |
171 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x7) }, | |
172 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x8) }, | |
173 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x9) }, | |
174 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xA) }, | |
175 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xB) }, | |
176 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xC) }, | |
177 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xD) }, | |
178 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xE) }, | |
179 | { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xF) }, | |
180 | { } | |
181 | }; | |
182 | MODULE_DEVICE_TABLE (usb, st5481_ids); | |
183 | ||
184 | static struct usb_driver st5481_usb_driver = { | |
1da177e4 LT |
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); |