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