1 /******************************************************************************
2 * xusbatm.c - dumb usbatm-based driver for modems initialized in userspace
4 * Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59
18 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 ******************************************************************************/
22 #include <linux/module.h>
23 #include <linux/netdevice.h> /* FIXME: required by linux/etherdevice.h */
24 #include <linux/etherdevice.h> /* for random_ether_addr() */
29 #define XUSBATM_DRIVERS_MAX 8
31 #define XUSBATM_PARM(name, type, parmtype, desc) \
32 static type name[XUSBATM_DRIVERS_MAX]; \
33 static int num_##name; \
34 module_param_array(name, parmtype, &num_##name, 0444); \
35 MODULE_PARM_DESC(name, desc)
37 XUSBATM_PARM(vendor
, unsigned short, ushort
, "USB device vendor");
38 XUSBATM_PARM(product
, unsigned short, ushort
, "USB device product");
40 XUSBATM_PARM(rx_endpoint
, unsigned char, byte
, "rx endpoint number");
41 XUSBATM_PARM(tx_endpoint
, unsigned char, byte
, "tx endpoint number");
42 XUSBATM_PARM(rx_padding
, unsigned char, byte
, "rx padding (default 0)");
43 XUSBATM_PARM(tx_padding
, unsigned char, byte
, "tx padding (default 0)");
45 static const char xusbatm_driver_name
[] = "xusbatm";
47 static struct usbatm_driver xusbatm_drivers
[XUSBATM_DRIVERS_MAX
];
48 static struct usb_device_id xusbatm_usb_ids
[XUSBATM_DRIVERS_MAX
+ 1];
49 static struct usb_driver xusbatm_usb_driver
;
51 static int usb_intf_has_ep(const struct usb_interface
*intf
, u8 ep
)
55 for (i
= 0; i
< intf
->num_altsetting
; i
++) {
56 struct usb_host_interface
*alt
= intf
->altsetting
;
57 for (j
= 0; j
< alt
->desc
.bNumEndpoints
; j
++)
58 if ((alt
->endpoint
[i
].desc
.bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK
) == ep
)
64 static int xusbatm_bind(struct usbatm_data
*usbatm_instance
,
65 struct usb_interface
*intf
, const struct usb_device_id
*id
,
68 struct usb_device
*usb_dev
= interface_to_usbdev(intf
);
69 int drv_ix
= id
- xusbatm_usb_ids
;
70 int rx_ep_present
= usb_intf_has_ep(intf
, rx_endpoint
[drv_ix
]);
71 int tx_ep_present
= usb_intf_has_ep(intf
, tx_endpoint
[drv_ix
]);
72 u8 searched_ep
= rx_ep_present
? tx_endpoint
[drv_ix
] : rx_endpoint
[drv_ix
];
75 usb_dbg(usbatm_instance
, "%s: binding driver %d: vendor %#x product %#x"
76 " rx: ep %#x padd %d tx: ep %#x padd %d\n",
77 __func__
, drv_ix
, vendor
[drv_ix
], product
[drv_ix
],
78 rx_endpoint
[drv_ix
], rx_padding
[drv_ix
],
79 tx_endpoint
[drv_ix
], tx_padding
[drv_ix
]);
81 if (!rx_ep_present
&& !tx_ep_present
) {
82 usb_dbg(usbatm_instance
, "%s: intf #%d has neither rx (%#x) nor tx (%#x) endpoint\n",
83 __func__
, intf
->altsetting
->desc
.bInterfaceNumber
,
84 rx_endpoint
[drv_ix
], tx_endpoint
[drv_ix
]);
88 if (rx_ep_present
&& tx_ep_present
)
91 for(i
= 0; i
< usb_dev
->actconfig
->desc
.bNumInterfaces
; i
++) {
92 struct usb_interface
*cur_if
= usb_dev
->actconfig
->interface
[i
];
94 if (cur_if
!= intf
&& usb_intf_has_ep(cur_if
, searched_ep
)) {
95 ret
= usb_driver_claim_interface(&xusbatm_usb_driver
,
96 cur_if
, usbatm_instance
);
98 usb_err(usbatm_instance
, "%s: failed to claim interface #%d (%d)\n",
99 __func__
, cur_if
->altsetting
->desc
.bInterfaceNumber
, ret
);
104 usb_err(usbatm_instance
, "%s: no interface has endpoint %#x\n",
105 __func__
, searched_ep
);
109 static void xusbatm_unbind(struct usbatm_data
*usbatm_instance
,
110 struct usb_interface
*intf
)
112 struct usb_device
*usb_dev
= interface_to_usbdev(intf
);
114 usb_dbg(usbatm_instance
, "%s entered\n", __func__
);
116 for(i
= 0; i
< usb_dev
->actconfig
->desc
.bNumInterfaces
; i
++) {
117 struct usb_interface
*cur_if
= usb_dev
->actconfig
->interface
[i
];
118 usb_set_intfdata(cur_if
, NULL
);
119 usb_driver_release_interface(&xusbatm_usb_driver
, cur_if
);
123 static int xusbatm_atm_start(struct usbatm_data
*usbatm_instance
,
124 struct atm_dev
*atm_dev
)
126 atm_dbg(usbatm_instance
, "%s entered\n", __func__
);
128 /* use random MAC as we've no way to get it from the device */
129 random_ether_addr(atm_dev
->esi
);
135 static int xusbatm_usb_probe(struct usb_interface
*intf
,
136 const struct usb_device_id
*id
)
138 return usbatm_usb_probe(intf
, id
,
139 xusbatm_drivers
+ (id
- xusbatm_usb_ids
));
142 static struct usb_driver xusbatm_usb_driver
= {
143 .owner
= THIS_MODULE
,
144 .name
= xusbatm_driver_name
,
145 .probe
= xusbatm_usb_probe
,
146 .disconnect
= usbatm_usb_disconnect
,
147 .id_table
= xusbatm_usb_ids
150 static int __init
xusbatm_init(void)
157 num_vendor
!= num_product
||
158 num_vendor
!= num_rx_endpoint
||
159 num_vendor
!= num_tx_endpoint
) {
160 warn("malformed module parameters");
164 for (i
= 0; i
< num_vendor
; i
++) {
165 xusbatm_usb_ids
[i
].match_flags
= USB_DEVICE_ID_MATCH_DEVICE
;
166 xusbatm_usb_ids
[i
].idVendor
= vendor
[i
];
167 xusbatm_usb_ids
[i
].idProduct
= product
[i
];
170 xusbatm_drivers
[i
].owner
= THIS_MODULE
;
171 xusbatm_drivers
[i
].driver_name
= xusbatm_driver_name
;
172 xusbatm_drivers
[i
].bind
= xusbatm_bind
;
173 xusbatm_drivers
[i
].unbind
= xusbatm_unbind
;
174 xusbatm_drivers
[i
].atm_start
= xusbatm_atm_start
;
175 xusbatm_drivers
[i
].in
= rx_endpoint
[i
];
176 xusbatm_drivers
[i
].out
= tx_endpoint
[i
];
177 xusbatm_drivers
[i
].rx_padding
= rx_padding
[i
];
178 xusbatm_drivers
[i
].tx_padding
= tx_padding
[i
];
181 return usb_register(&xusbatm_usb_driver
);
183 module_init(xusbatm_init
);
185 static void __exit
xusbatm_exit(void)
187 dbg("xusbatm_exit entered");
189 usb_deregister(&xusbatm_usb_driver
);
191 module_exit(xusbatm_exit
);
193 MODULE_AUTHOR("Roman Kagan, Duncan Sands");
194 MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace");
195 MODULE_LICENSE("GPL");
196 MODULE_VERSION("0.1");