diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-07 22:23:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-07 22:23:21 -0500 |
commit | c96e2c92072d3e78954c961f53d8c7352f7abbd7 (patch) | |
tree | d844f26f926ff40e98e9eae0e11fd71acad81df4 /drivers/usb/serial/usb-serial.c | |
parent | f2aca47dc3c2d0c2d5dbd972558557e74232bbce (diff) | |
parent | 64358164f5bfe5e11d4040c1eb674c29e1436ce5 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (70 commits)
USB: remove duplicate device id from zc0301
USB: remove duplicate device id from usb_storage
USB: remove duplicate device id from keyspan
USB: remove duplicate device id from ftdi_sio
USB: remove duplicate device id from visor
USB: a bit more coding style cleanup
usbcore: trivial whitespace fixes
usb-storage: use first bulk endpoints, not last
EHCI: fix interrupt-driven remote wakeup
USB: switch ehci-hcd to new polling scheme
USB: autosuspend for usb printer driver
USB Input: Added kernel module to support all GTCO CalComp USB InterWrite School products
USB: Sierra Wireless auto set D0
USB: usb ethernet gadget recognizes HUSB2DEV
USB: list atmel husb2_udc gadget controller
USB: gadgetfs AIO tweaks
USB: gadgetfs behaves better on userspace init bug
USB: gadgetfs race fix
USB: gadgetfs simplifications
USB: gadgetfs cleanups
...
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 102 |
1 files changed, 81 insertions, 21 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 716f6806cc89..6bf22a28adb8 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = { | |||
59 | 59 | ||
60 | static int debug; | 60 | static int debug; |
61 | static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ | 61 | static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ |
62 | static spinlock_t table_lock; | ||
62 | static LIST_HEAD(usb_serial_driver_list); | 63 | static LIST_HEAD(usb_serial_driver_list); |
63 | 64 | ||
64 | struct usb_serial *usb_serial_get_by_index(unsigned index) | 65 | struct usb_serial *usb_serial_get_by_index(unsigned index) |
65 | { | 66 | { |
66 | struct usb_serial *serial = serial_table[index]; | 67 | struct usb_serial *serial; |
68 | |||
69 | spin_lock(&table_lock); | ||
70 | serial = serial_table[index]; | ||
67 | 71 | ||
68 | if (serial) | 72 | if (serial) |
69 | kref_get(&serial->kref); | 73 | kref_get(&serial->kref); |
74 | spin_unlock(&table_lock); | ||
70 | return serial; | 75 | return serial; |
71 | } | 76 | } |
72 | 77 | ||
@@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po | |||
78 | dbg("%s %d", __FUNCTION__, num_ports); | 83 | dbg("%s %d", __FUNCTION__, num_ports); |
79 | 84 | ||
80 | *minor = 0; | 85 | *minor = 0; |
86 | spin_lock(&table_lock); | ||
81 | for (i = 0; i < SERIAL_TTY_MINORS; ++i) { | 87 | for (i = 0; i < SERIAL_TTY_MINORS; ++i) { |
82 | if (serial_table[i]) | 88 | if (serial_table[i]) |
83 | continue; | 89 | continue; |
@@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po | |||
96 | dbg("%s - minor base = %d", __FUNCTION__, *minor); | 102 | dbg("%s - minor base = %d", __FUNCTION__, *minor); |
97 | for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) | 103 | for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) |
98 | serial_table[i] = serial; | 104 | serial_table[i] = serial; |
105 | spin_unlock(&table_lock); | ||
99 | return serial; | 106 | return serial; |
100 | } | 107 | } |
108 | spin_unlock(&table_lock); | ||
101 | return NULL; | 109 | return NULL; |
102 | } | 110 | } |
103 | 111 | ||
@@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial) | |||
110 | if (serial == NULL) | 118 | if (serial == NULL) |
111 | return; | 119 | return; |
112 | 120 | ||
121 | spin_lock(&table_lock); | ||
113 | for (i = 0; i < serial->num_ports; ++i) { | 122 | for (i = 0; i < serial->num_ports; ++i) { |
114 | serial_table[serial->minor + i] = NULL; | 123 | serial_table[serial->minor + i] = NULL; |
115 | } | 124 | } |
125 | spin_unlock(&table_lock); | ||
116 | } | 126 | } |
117 | 127 | ||
118 | static void destroy_serial(struct kref *kref) | 128 | static void destroy_serial(struct kref *kref) |
@@ -271,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) | |||
271 | static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) | 281 | static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) |
272 | { | 282 | { |
273 | struct usb_serial_port *port = tty->driver_data; | 283 | struct usb_serial_port *port = tty->driver_data; |
274 | int retval = -EINVAL; | 284 | int retval = -ENODEV; |
275 | 285 | ||
276 | if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) | 286 | if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) |
277 | goto exit; | 287 | goto exit; |
@@ -279,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int | |||
279 | dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); | 289 | dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); |
280 | 290 | ||
281 | if (!port->open_count) { | 291 | if (!port->open_count) { |
292 | retval = -EINVAL; | ||
282 | dbg("%s - port not opened", __FUNCTION__); | 293 | dbg("%s - port not opened", __FUNCTION__); |
283 | goto exit; | 294 | goto exit; |
284 | } | 295 | } |
@@ -559,15 +570,20 @@ static void port_release(struct device *dev) | |||
559 | port_free(port); | 570 | port_free(port); |
560 | } | 571 | } |
561 | 572 | ||
562 | static void port_free(struct usb_serial_port *port) | 573 | static void kill_traffic(struct usb_serial_port *port) |
563 | { | 574 | { |
564 | usb_kill_urb(port->read_urb); | 575 | usb_kill_urb(port->read_urb); |
565 | usb_free_urb(port->read_urb); | ||
566 | usb_kill_urb(port->write_urb); | 576 | usb_kill_urb(port->write_urb); |
567 | usb_free_urb(port->write_urb); | ||
568 | usb_kill_urb(port->interrupt_in_urb); | 577 | usb_kill_urb(port->interrupt_in_urb); |
569 | usb_free_urb(port->interrupt_in_urb); | ||
570 | usb_kill_urb(port->interrupt_out_urb); | 578 | usb_kill_urb(port->interrupt_out_urb); |
579 | } | ||
580 | |||
581 | static void port_free(struct usb_serial_port *port) | ||
582 | { | ||
583 | kill_traffic(port); | ||
584 | usb_free_urb(port->read_urb); | ||
585 | usb_free_urb(port->write_urb); | ||
586 | usb_free_urb(port->interrupt_in_urb); | ||
571 | usb_free_urb(port->interrupt_out_urb); | 587 | usb_free_urb(port->interrupt_out_urb); |
572 | kfree(port->bulk_in_buffer); | 588 | kfree(port->bulk_in_buffer); |
573 | kfree(port->bulk_out_buffer); | 589 | kfree(port->bulk_out_buffer); |
@@ -596,6 +612,39 @@ static struct usb_serial * create_serial (struct usb_device *dev, | |||
596 | return serial; | 612 | return serial; |
597 | } | 613 | } |
598 | 614 | ||
615 | static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, | ||
616 | struct usb_serial_driver *drv) | ||
617 | { | ||
618 | struct usb_dynid *dynid; | ||
619 | |||
620 | spin_lock(&drv->dynids.lock); | ||
621 | list_for_each_entry(dynid, &drv->dynids.list, node) { | ||
622 | if (usb_match_one_id(intf, &dynid->id)) { | ||
623 | spin_unlock(&drv->dynids.lock); | ||
624 | return &dynid->id; | ||
625 | } | ||
626 | } | ||
627 | spin_unlock(&drv->dynids.lock); | ||
628 | return NULL; | ||
629 | } | ||
630 | |||
631 | static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, | ||
632 | struct usb_interface *intf) | ||
633 | { | ||
634 | const struct usb_device_id *id; | ||
635 | |||
636 | id = usb_match_id(intf, drv->id_table); | ||
637 | if (id) { | ||
638 | dbg("static descriptor matches"); | ||
639 | goto exit; | ||
640 | } | ||
641 | id = match_dynamic_id(intf, drv); | ||
642 | if (id) | ||
643 | dbg("dynamic descriptor matches"); | ||
644 | exit: | ||
645 | return id; | ||
646 | } | ||
647 | |||
599 | static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) | 648 | static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) |
600 | { | 649 | { |
601 | struct list_head *p; | 650 | struct list_head *p; |
@@ -605,11 +654,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac | |||
605 | /* Check if the usb id matches a known device */ | 654 | /* Check if the usb id matches a known device */ |
606 | list_for_each(p, &usb_serial_driver_list) { | 655 | list_for_each(p, &usb_serial_driver_list) { |
607 | t = list_entry(p, struct usb_serial_driver, driver_list); | 656 | t = list_entry(p, struct usb_serial_driver, driver_list); |
608 | id = usb_match_id(iface, t->id_table); | 657 | id = get_iface_id(t, iface); |
609 | if (id != NULL) { | 658 | if (id) |
610 | dbg("descriptor matches"); | ||
611 | return t; | 659 | return t; |
612 | } | ||
613 | } | 660 | } |
614 | 661 | ||
615 | return NULL; | 662 | return NULL; |
@@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interface *interface, | |||
639 | int num_ports = 0; | 686 | int num_ports = 0; |
640 | int max_endpoints; | 687 | int max_endpoints; |
641 | 688 | ||
689 | lock_kernel(); /* guard against unloading a serial driver module */ | ||
642 | type = search_serial_device(interface); | 690 | type = search_serial_device(interface); |
643 | if (!type) { | 691 | if (!type) { |
692 | unlock_kernel(); | ||
644 | dbg("none matched"); | 693 | dbg("none matched"); |
645 | return -ENODEV; | 694 | return -ENODEV; |
646 | } | 695 | } |
647 | 696 | ||
648 | serial = create_serial (dev, interface, type); | 697 | serial = create_serial (dev, interface, type); |
649 | if (!serial) { | 698 | if (!serial) { |
699 | unlock_kernel(); | ||
650 | dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); | 700 | dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); |
651 | return -ENOMEM; | 701 | return -ENOMEM; |
652 | } | 702 | } |
@@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interface *interface, | |||
656 | const struct usb_device_id *id; | 706 | const struct usb_device_id *id; |
657 | 707 | ||
658 | if (!try_module_get(type->driver.owner)) { | 708 | if (!try_module_get(type->driver.owner)) { |
709 | unlock_kernel(); | ||
659 | dev_err(&interface->dev, "module get failed, exiting\n"); | 710 | dev_err(&interface->dev, "module get failed, exiting\n"); |
660 | kfree (serial); | 711 | kfree (serial); |
661 | return -EIO; | 712 | return -EIO; |
662 | } | 713 | } |
663 | 714 | ||
664 | id = usb_match_id(interface, type->id_table); | 715 | id = get_iface_id(type, interface); |
665 | retval = type->probe(serial, id); | 716 | retval = type->probe(serial, id); |
666 | module_put(type->driver.owner); | 717 | module_put(type->driver.owner); |
667 | 718 | ||
668 | if (retval) { | 719 | if (retval) { |
720 | unlock_kernel(); | ||
669 | dbg ("sub driver rejected device"); | 721 | dbg ("sub driver rejected device"); |
670 | kfree (serial); | 722 | kfree (serial); |
671 | return retval; | 723 | return retval; |
@@ -735,6 +787,7 @@ int usb_serial_probe(struct usb_interface *interface, | |||
735 | * properly during a later invocation of usb_serial_probe | 787 | * properly during a later invocation of usb_serial_probe |
736 | */ | 788 | */ |
737 | if (num_bulk_in == 0 || num_bulk_out == 0) { | 789 | if (num_bulk_in == 0 || num_bulk_out == 0) { |
790 | unlock_kernel(); | ||
738 | dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); | 791 | dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); |
739 | kfree (serial); | 792 | kfree (serial); |
740 | return -ENODEV; | 793 | return -ENODEV; |
@@ -750,6 +803,7 @@ int usb_serial_probe(struct usb_interface *interface, | |||
750 | if (type == &usb_serial_generic_device) { | 803 | if (type == &usb_serial_generic_device) { |
751 | num_ports = num_bulk_out; | 804 | num_ports = num_bulk_out; |
752 | if (num_ports == 0) { | 805 | if (num_ports == 0) { |
806 | unlock_kernel(); | ||
753 | dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); | 807 | dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); |
754 | kfree (serial); | 808 | kfree (serial); |
755 | return -EIO; | 809 | return -EIO; |
@@ -760,6 +814,7 @@ int usb_serial_probe(struct usb_interface *interface, | |||
760 | /* if this device type has a calc_num_ports function, call it */ | 814 | /* if this device type has a calc_num_ports function, call it */ |
761 | if (type->calc_num_ports) { | 815 | if (type->calc_num_ports) { |
762 | if (!try_module_get(type->driver.owner)) { | 816 | if (!try_module_get(type->driver.owner)) { |
817 | unlock_kernel(); | ||
763 | dev_err(&interface->dev, "module get failed, exiting\n"); | 818 | dev_err(&interface->dev, "module get failed, exiting\n"); |
764 | kfree (serial); | 819 | kfree (serial); |
765 | return -EIO; | 820 | return -EIO; |
@@ -771,12 +826,6 @@ int usb_serial_probe(struct usb_interface *interface, | |||
771 | num_ports = type->num_ports; | 826 | num_ports = type->num_ports; |
772 | } | 827 | } |
773 | 828 | ||
774 | if (get_free_serial (serial, num_ports, &minor) == NULL) { | ||
775 | dev_err(&interface->dev, "No more free serial devices\n"); | ||
776 | kfree (serial); | ||
777 | return -ENOMEM; | ||
778 | } | ||
779 | |||
780 | serial->minor = minor; | 829 | serial->minor = minor; |
781 | serial->num_ports = num_ports; | 830 | serial->num_ports = num_ports; |
782 | serial->num_bulk_in = num_bulk_in; | 831 | serial->num_bulk_in = num_bulk_in; |
@@ -791,6 +840,8 @@ int usb_serial_probe(struct usb_interface *interface, | |||
791 | max_endpoints = max(max_endpoints, num_interrupt_out); | 840 | max_endpoints = max(max_endpoints, num_interrupt_out); |
792 | max_endpoints = max(max_endpoints, (int)serial->num_ports); | 841 | max_endpoints = max(max_endpoints, (int)serial->num_ports); |
793 | serial->num_port_pointers = max_endpoints; | 842 | serial->num_port_pointers = max_endpoints; |
843 | unlock_kernel(); | ||
844 | |||
794 | dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); | 845 | dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); |
795 | for (i = 0; i < max_endpoints; ++i) { | 846 | for (i = 0; i < max_endpoints; ++i) { |
796 | port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); | 847 | port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); |
@@ -925,6 +976,11 @@ int usb_serial_probe(struct usb_interface *interface, | |||
925 | } | 976 | } |
926 | } | 977 | } |
927 | 978 | ||
979 | if (get_free_serial (serial, num_ports, &minor) == NULL) { | ||
980 | dev_err(&interface->dev, "No more free serial devices\n"); | ||
981 | goto probe_error; | ||
982 | } | ||
983 | |||
928 | /* register all of the individual ports with the driver core */ | 984 | /* register all of the individual ports with the driver core */ |
929 | for (i = 0; i < num_ports; ++i) { | 985 | for (i = 0; i < num_ports; ++i) { |
930 | port = serial->port[i]; | 986 | port = serial->port[i]; |
@@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
1002 | if (serial) { | 1058 | if (serial) { |
1003 | for (i = 0; i < serial->num_ports; ++i) { | 1059 | for (i = 0; i < serial->num_ports; ++i) { |
1004 | port = serial->port[i]; | 1060 | port = serial->port[i]; |
1005 | if (port && port->tty) | 1061 | if (port) { |
1006 | tty_hangup(port->tty); | 1062 | if (port->tty) |
1063 | tty_hangup(port->tty); | ||
1064 | kill_traffic(port); | ||
1065 | } | ||
1007 | } | 1066 | } |
1008 | /* let the last holder of this object | 1067 | /* let the last holder of this object |
1009 | * cause it to be cleaned up */ | 1068 | * cause it to be cleaned up */ |
@@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void) | |||
1040 | return -ENOMEM; | 1099 | return -ENOMEM; |
1041 | 1100 | ||
1042 | /* Initialize our global data */ | 1101 | /* Initialize our global data */ |
1102 | spin_lock_init(&table_lock); | ||
1043 | for (i = 0; i < SERIAL_TTY_MINORS; ++i) { | 1103 | for (i = 0; i < SERIAL_TTY_MINORS; ++i) { |
1044 | serial_table[i] = NULL; | 1104 | serial_table[i] = NULL; |
1045 | } | 1105 | } |
@@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_serial_driver *device) | |||
1138 | set_to_generic_if_null(device, shutdown); | 1198 | set_to_generic_if_null(device, shutdown); |
1139 | } | 1199 | } |
1140 | 1200 | ||
1141 | int usb_serial_register(struct usb_serial_driver *driver) | 1201 | int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ |
1142 | { | 1202 | { |
1143 | int retval; | 1203 | int retval; |
1144 | 1204 | ||
@@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_serial_driver *driver) | |||
1162 | } | 1222 | } |
1163 | 1223 | ||
1164 | 1224 | ||
1165 | void usb_serial_deregister(struct usb_serial_driver *device) | 1225 | void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */ |
1166 | { | 1226 | { |
1167 | info("USB Serial deregistering driver %s", device->description); | 1227 | info("USB Serial deregistering driver %s", device->description); |
1168 | list_del(&device->driver_list); | 1228 | list_del(&device->driver_list); |