4 * USB stub driver - grabbing and managing USB devices.
6 * Copyright (C) 2009, FUJITSU LABORATORIES LTD.
7 * Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
24 * When distributed separately from the Linux kernel or incorporated into
25 * other software packages, subject to the following license:
27 * Permission is hereby granted, free of charge, to any person obtaining a copy
28 * of this software and associated documentation files (the "Software"), to
29 * deal in the Software without restriction, including without limitation the
30 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
31 * sell copies of the Software, and to permit persons to whom the Software is
32 * furnished to do so, subject to the following conditions:
34 * The above copyright notice and this permission notice shall be included in
35 * all copies or substantial portions of the Software.
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
42 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
43 * DEALINGS IN THE SOFTWARE.
48 static LIST_HEAD(port_list);
49 static DEFINE_SPINLOCK(port_list_lock);
51 struct vusb_port_id *find_portid_by_busid(const char *busid)
53 struct vusb_port_id *portid;
57 spin_lock_irqsave(&port_list_lock, flags);
58 list_for_each_entry(portid, &port_list, id_list) {
59 if (!(strncmp(portid->phys_bus, busid, USBBACK_BUS_ID_SIZE))) {
64 spin_unlock_irqrestore(&port_list_lock, flags);
72 struct vusb_port_id *find_portid(const domid_t domid,
73 const unsigned int handle,
76 struct vusb_port_id *portid;
80 spin_lock_irqsave(&port_list_lock, flags);
81 list_for_each_entry(portid, &port_list, id_list) {
82 if ((portid->domid == domid)
83 && (portid->handle == handle)
84 && (portid->portnum == portnum)) {
89 spin_unlock_irqrestore(&port_list_lock, flags);
97 int portid_add(const char *busid,
99 const unsigned int handle,
102 struct vusb_port_id *portid;
105 portid = kzalloc(sizeof(*portid), GFP_KERNEL);
109 portid->domid = domid;
110 portid->handle = handle;
111 portid->portnum = portnum;
113 strlcpy(portid->phys_bus, busid, USBBACK_BUS_ID_SIZE);
115 spin_lock_irqsave(&port_list_lock, flags);
116 list_add(&portid->id_list, &port_list);
117 spin_unlock_irqrestore(&port_list_lock, flags);
122 int portid_remove(const domid_t domid,
123 const unsigned int handle,
126 struct vusb_port_id *portid, *tmp;
130 spin_lock_irqsave(&port_list_lock, flags);
131 list_for_each_entry_safe(portid, tmp, &port_list, id_list) {
132 if (portid->domid == domid
133 && portid->handle == handle
134 && portid->portnum == portnum) {
135 list_del(&portid->id_list);
141 spin_unlock_irqrestore(&port_list_lock, flags);
146 static struct usbstub *usbstub_alloc(struct usb_device *udev,
147 struct vusb_port_id *portid)
149 struct usbstub *stub;
151 stub = kzalloc(sizeof(*stub), GFP_KERNEL);
153 pr_err("no memory for usbstub\n");
156 kref_init(&stub->kref);
157 stub->udev = usb_get_dev(udev);
158 stub->portid = portid;
159 spin_lock_init(&stub->submitting_lock);
160 INIT_LIST_HEAD(&stub->submitting_list);
165 static void usbstub_release(struct kref *kref)
167 struct usbstub *stub;
169 stub = container_of(kref, struct usbstub, kref);
171 usb_put_dev(stub->udev);
177 static inline void usbstub_get(struct usbstub *stub)
179 kref_get(&stub->kref);
182 static inline void usbstub_put(struct usbstub *stub)
184 kref_put(&stub->kref, usbstub_release);
187 static int usbstub_probe(struct usb_interface *intf,
188 const struct usb_device_id *id)
190 struct usb_device *udev = interface_to_usbdev(intf);
191 const char *busid = dev_name(intf->dev.parent);
192 struct vusb_port_id *portid = NULL;
193 struct usbstub *stub = NULL;
194 usbif_t *usbif = NULL;
195 int retval = -ENODEV;
197 /* hub currently not supported, so skip. */
198 if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
201 portid = find_portid_by_busid(busid);
205 usbif = find_usbif(portid->domid, portid->handle);
209 switch (udev->speed) {
214 if (usbif->usb_ver >= USB_VER_USB20)
221 stub = find_attached_device(usbif, portid->portnum);
224 stub = usbstub_alloc(udev, portid);
227 usbbk_attach_device(usbif, stub);
228 usbbk_hotplug_notify(usbif, portid->portnum, udev->speed);
230 /* maybe already called and connected by other intf */
231 if (strncmp(stub->portid->phys_bus, busid, USBBACK_BUS_ID_SIZE))
232 goto out; /* invalid call */
236 usb_set_intfdata(intf, stub);
243 static void usbstub_disconnect(struct usb_interface *intf)
246 = (struct usbstub *) usb_get_intfdata(intf);
248 usb_set_intfdata(intf, NULL);
254 usbbk_hotplug_notify(stub->usbif, stub->portid->portnum, 0);
255 usbbk_detach_device(stub->usbif, stub);
257 usbbk_unlink_urbs(stub);
261 static ssize_t usbstub_show_portids(struct device_driver *driver,
264 struct vusb_port_id *portid;
268 spin_lock_irqsave(&port_list_lock, flags);
269 list_for_each_entry(portid, &port_list, id_list) {
270 if (count >= PAGE_SIZE)
272 count += scnprintf((char *)buf + count, PAGE_SIZE - count,
274 &portid->phys_bus[0],
279 spin_unlock_irqrestore(&port_list_lock, flags);
283 static DRIVER_ATTR(port_ids, S_IRUSR, usbstub_show_portids, NULL);
285 /* table of devices that matches any usbdevice */
286 static const struct usb_device_id usbstub_table[] = {
287 { .driver_info = 1 }, /* wildcard, see usb_match_id() */
288 { } /* Terminating entry */
290 MODULE_DEVICE_TABLE(usb, usbstub_table);
292 static struct usb_driver usbback_usb_driver = {
294 .probe = usbstub_probe,
295 .disconnect = usbstub_disconnect,
296 .id_table = usbstub_table,
300 int __init usbstub_init(void)
304 err = usb_register(&usbback_usb_driver);
306 pr_err("usbback: usb_register failed (%d)\n", err);
310 err = driver_create_file(&usbback_usb_driver.drvwrap.driver,
311 &driver_attr_port_ids);
313 usb_deregister(&usbback_usb_driver);
319 void usbstub_exit(void)
321 driver_remove_file(&usbback_usb_driver.drvwrap.driver,
322 &driver_attr_port_ids);
323 usb_deregister(&usbback_usb_driver);