Commit e9b73ef9 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 3bf8a198 075769bc
...@@ -226,11 +226,21 @@ extern struct usb_driver usblp_driver; ...@@ -226,11 +226,21 @@ extern struct usb_driver usblp_driver;
static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len)
{ {
int retval = usb_control_msg(usblp->dev, int retval;
int index = usblp->ifnum;
/* High byte has the interface index.
Low byte has the alternate setting.
*/
if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) {
index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting;
}
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT); request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d", dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
request, !!dir, recip, value, len, retval); request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0; return retval < 0 ? retval : 0;
} }
...@@ -440,6 +450,9 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -440,6 +450,9 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
goto done; goto done;
} }
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */
switch (_IOC_NR(cmd)) { switch (_IOC_NR(cmd)) {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
usbcore-objs := usb.o hub.o hcd.o urb.o message.o \ usbcore-objs := usb.o hub.o hcd.o urb.o message.o \
config.o file.o buffer.o driverfs.o config.o file.o buffer.o sysfs.o
ifeq ($(CONFIG_PCI),y) ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o usbcore-objs += hcd-pci.o
......
...@@ -465,23 +465,24 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -465,23 +465,24 @@ int usb_get_configuration(struct usb_device *dev)
goto err2; goto err2;
memset(dev->rawdescriptors, 0, length); memset(dev->rawdescriptors, 0, length);
buffer = kmalloc(8, GFP_KERNEL); buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
if (!buffer) if (!buffer)
goto err2; goto err2;
desc = (struct usb_config_descriptor *)buffer; desc = (struct usb_config_descriptor *)buffer;
for (cfgno = 0; cfgno < ncfg; cfgno++) { for (cfgno = 0; cfgno < ncfg; cfgno++) {
/* We grab the first 8 bytes so we know how long the whole */ /* We grab just the first descriptor so we know how long
/* configuration is */ * the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, 8); buffer, USB_DT_CONFIG_SIZE);
if (result < 0) { if (result < 0) {
dev_err(ddev, "unable to read config index %d " dev_err(ddev, "unable to read config index %d "
"descriptor\n", cfgno); "descriptor/%s\n", cfgno, "start");
goto err; goto err;
} else if (result < 8) { } else if (result < 4) {
dev_err(ddev, "config index %d descriptor too short " dev_err(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno, 8, result); "(expected %i, got %i)\n", cfgno,
USB_DT_CONFIG_SIZE, result);
result = -EINVAL; result = -EINVAL;
goto err; goto err;
} }
...@@ -498,7 +499,7 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -498,7 +499,7 @@ int usb_get_configuration(struct usb_device *dev)
bigbuffer, length); bigbuffer, length);
if (result < 0) { if (result < 0) {
dev_err(ddev, "unable to read config index %d " dev_err(ddev, "unable to read config index %d "
"descriptor\n", cfgno); "descriptor/%s\n", cfgno, "all");
kfree(bigbuffer); kfree(bigbuffer);
goto err; goto err;
} }
......
...@@ -243,13 +243,13 @@ extern void usb_hc_died (struct usb_hcd *hcd); ...@@ -243,13 +243,13 @@ extern void usb_hc_died (struct usb_hcd *hcd);
extern struct usb_device *usb_alloc_dev(struct usb_device *parent, extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *, unsigned port); struct usb_bus *, unsigned port);
extern int usb_new_device(struct usb_device *dev); extern int usb_new_device(struct usb_device *dev);
extern void usb_choose_address(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **); extern void usb_disconnect(struct usb_device **);
extern void usb_choose_address(struct usb_device *dev);
extern void usb_release_address(struct usb_device *dev);
/* exported to hub driver ONLY to support usb_reset_device () */ /* exported to hub driver ONLY to support usb_reset_device () */
extern int usb_get_configuration(struct usb_device *dev); extern int usb_get_configuration(struct usb_device *dev);
extern void usb_destroy_configuration(struct usb_device *dev); extern void usb_destroy_configuration(struct usb_device *dev);
extern int usb_set_address(struct usb_device *dev);
/* use these only before the device's address has been set */ /* use these only before the device's address has been set */
#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30)) #define usb_snddefctrl(dev) ((PIPE_CONTROL << 30))
......
This diff is collapsed.
...@@ -1252,7 +1252,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) ...@@ -1252,7 +1252,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
ret); ret);
continue; continue;
} }
usb_create_driverfs_intf_files (intf); usb_create_sysfs_intf_files (intf);
} }
} }
......
/* /*
* drivers/usb/core/driverfs.c * drivers/usb/core/sysfs.c
* *
* (C) Copyright 2002 David Brownell * (C) Copyright 2002 David Brownell
* (C) Copyright 2002 Greg Kroah-Hartman * (C) Copyright 2002 Greg Kroah-Hartman
* (C) Copyright 2002 IBM Corp. * (C) Copyright 2002 IBM Corp.
* *
* All of the driverfs file attributes for usb devices and interfaces. * All of the sysfs file attributes for usb devices and interfaces.
* *
*/ */
...@@ -163,7 +163,7 @@ usb_descriptor_attr (bDeviceProtocol, "%02x\n") ...@@ -163,7 +163,7 @@ usb_descriptor_attr (bDeviceProtocol, "%02x\n")
usb_descriptor_attr (bNumConfigurations, "%d\n") usb_descriptor_attr (bNumConfigurations, "%d\n")
void usb_create_driverfs_dev_files (struct usb_device *udev) void usb_create_sysfs_dev_files (struct usb_device *udev)
{ {
struct device *dev = &udev->dev; struct device *dev = &udev->dev;
...@@ -217,7 +217,7 @@ usb_intf_attr (bInterfaceSubClass, "%02x\n") ...@@ -217,7 +217,7 @@ usb_intf_attr (bInterfaceSubClass, "%02x\n")
usb_intf_attr (bInterfaceProtocol, "%02x\n") usb_intf_attr (bInterfaceProtocol, "%02x\n")
usb_intf_attr (iInterface, "%02x\n") usb_intf_attr (iInterface, "%02x\n")
void usb_create_driverfs_intf_files (struct usb_interface *intf) void usb_create_sysfs_intf_files (struct usb_interface *intf)
{ {
device_create_file (&intf->dev, &dev_attr_bInterfaceNumber); device_create_file (&intf->dev, &dev_attr_bInterfaceNumber);
device_create_file (&intf->dev, &dev_attr_bAlternateSetting); device_create_file (&intf->dev, &dev_attr_bAlternateSetting);
......
...@@ -998,12 +998,10 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -998,12 +998,10 @@ void usb_disconnect(struct usb_device **pdev)
*/ */
usb_disable_device(dev, 0); usb_disable_device(dev, 0);
dev_dbg (&dev->dev, "unregistering device\n");
/* Free the device number and remove the /proc/bus/usb entry */ /* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) { dev_dbg (&dev->dev, "unregistering device\n");
clear_bit(dev->devnum, dev->bus->devmap.devicemap); usb_release_address(dev);
usbfs_remove_device(dev); usbfs_remove_device(dev);
}
up(&dev->serialize); up(&dev->serialize);
device_unregister(&dev->dev); device_unregister(&dev->dev);
} }
...@@ -1038,24 +1036,23 @@ void usb_choose_address(struct usb_device *dev) ...@@ -1038,24 +1036,23 @@ void usb_choose_address(struct usb_device *dev)
} }
} }
/**
// hub-only!! ... and only exported for reset/reinit path. * usb_release_address - deallocate device address (usbcore-internal)
// otherwise used internally, for usb_new_device() * @dev: newly removed device
int usb_set_address(struct usb_device *dev) *
* Removes and deallocates the address assigned to a device.
* Only hub drivers (but not virtual root hub drivers for host
* controllers) should ever call this.
*/
void usb_release_address(struct usb_device *dev)
{ {
int retval; if (dev->devnum > 0) {
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
if (dev->devnum == 0) dev->devnum = -1;
return -EINVAL; }
if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
return -EINVAL;
retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (retval == 0)
dev->state = USB_STATE_ADDRESS;
return retval;
} }
static inline void usb_show_string(struct usb_device *dev, char *id, int index) static inline void usb_show_string(struct usb_device *dev, char *id, int index)
{ {
char *buf; char *buf;
...@@ -1069,6 +1066,37 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index) ...@@ -1069,6 +1066,37 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index)
kfree(buf); kfree(buf);
} }
static int usb_choose_configuration(struct usb_device *dev)
{
int c, i;
c = dev->config[0].desc.bConfigurationValue;
if (dev->descriptor.bNumConfigurations != 1) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
struct usb_interface_descriptor *desc;
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
desc = &dev->config[i].intf_cache[0]
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
if (desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff)
continue;
c = dev->config[i].desc.bConfigurationValue;
break;
}
dev_info(&dev->dev,
"configuration #%d chosen from %d choices\n",
c, dev->descriptor.bNumConfigurations);
}
return c;
}
/* /*
* usb_new_device - perform initial device setup (usbcore-internal) * usb_new_device - perform initial device setup (usbcore-internal)
* @dev: newly addressed device (in ADDRESS state) * @dev: newly addressed device (in ADDRESS state)
...@@ -1090,8 +1118,7 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index) ...@@ -1090,8 +1118,7 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index)
int usb_new_device(struct usb_device *dev) int usb_new_device(struct usb_device *dev)
{ {
int err; int err;
int i; int c;
int config;
err = usb_get_configuration(dev); err = usb_get_configuration(dev);
if (err < 0) { if (err < 0) {
...@@ -1119,41 +1146,16 @@ int usb_new_device(struct usb_device *dev) ...@@ -1119,41 +1146,16 @@ int usb_new_device(struct usb_device *dev)
dev_err(&dev->dev, "can't device_add, error %d\n", err); dev_err(&dev->dev, "can't device_add, error %d\n", err);
goto fail; goto fail;
} }
usb_create_driverfs_dev_files (dev); usb_create_sysfs_dev_files (dev);
/* choose and set the configuration. that registers the interfaces /* choose and set the configuration. that registers the interfaces
* with the driver core, and lets usb device drivers bind to them. * with the driver core, and lets usb device drivers bind to them.
* NOTE: should interact with hub power budgeting. * NOTE: should interact with hub power budgeting.
*/ */
config = dev->config[0].desc.bConfigurationValue; c = usb_choose_configuration(dev);
if (dev->descriptor.bNumConfigurations != 1) { err = usb_set_configuration(dev, c);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
struct usb_interface_descriptor *desc;
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
desc = &dev->config[i].intf_cache[0]
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
if (desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff)
continue;
config = dev->config[i].desc.bConfigurationValue;
break;
}
dev_info(&dev->dev,
"configuration #%d chosen from %d choices\n",
config,
dev->descriptor.bNumConfigurations);
}
err = usb_set_configuration(dev, config);
if (err) { if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n", dev_err(&dev->dev, "can't set config #%d, error %d\n", c, err);
config, err);
device_del(&dev->dev); device_del(&dev->dev);
goto fail; goto fail;
} }
...@@ -1166,8 +1168,7 @@ int usb_new_device(struct usb_device *dev) ...@@ -1166,8 +1168,7 @@ int usb_new_device(struct usb_device *dev)
return 0; return 0;
fail: fail:
dev->state = USB_STATE_NOTATTACHED; dev->state = USB_STATE_NOTATTACHED;
clear_bit(dev->devnum, dev->bus->devmap.devicemap); usb_release_address(dev);
dev->devnum = -1;
usb_put_dev(dev); usb_put_dev(dev);
return err; return err;
} }
......
/* Functions local to drivers/usb/core/ */ /* Functions local to drivers/usb/core/ */
extern void usb_create_driverfs_dev_files (struct usb_device *dev); extern void usb_create_sysfs_dev_files (struct usb_device *dev);
extern void usb_create_driverfs_intf_files (struct usb_interface *intf); extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
extern int usb_probe_interface (struct device *dev); extern int usb_probe_interface (struct device *dev);
extern int usb_unbind_interface (struct device *dev); extern int usb_unbind_interface (struct device *dev);
......
...@@ -95,6 +95,7 @@ config USB_PXA2XX ...@@ -95,6 +95,7 @@ config USB_PXA2XX
config USB_PXA2XX_SMALL config USB_PXA2XX_SMALL
depends on USB_GADGET_PXA2XX depends on USB_GADGET_PXA2XX
bool bool
default n if USB_ETH_RNDIS
default y if USB_ZERO default y if USB_ZERO
default y if USB_ETH default y if USB_ETH
default y if USB_G_SERIAL default y if USB_G_SERIAL
......
...@@ -96,7 +96,8 @@ ep_matches ( ...@@ -96,7 +96,8 @@ ep_matches (
/* for now, avoid PXA "interrupt-in"; /* for now, avoid PXA "interrupt-in";
* it's documented as never using DATA1. * it's documented as never using DATA1.
*/ */
if (gadget_is_pxa (gadget)) if (gadget_is_pxa (gadget)
&& 'i' == tmp [1])
return 0; return 0;
break; break;
case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_BULK:
......
...@@ -154,14 +154,9 @@ do { \ ...@@ -154,14 +154,9 @@ do { \
#define GS_CLOSE_TIMEOUT 15 #define GS_CLOSE_TIMEOUT 15
/* debug macro */ /* debug settings */
#if G_SERIAL_DEBUG #if G_SERIAL_DEBUG
static int debug = G_SERIAL_DEBUG; static int debug = G_SERIAL_DEBUG;
#else
static int debug = 0;
#endif
#if G_SERIAL_DEBUG
#define gs_debug(format, arg...) \ #define gs_debug(format, arg...) \
do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0) do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
...@@ -598,8 +593,10 @@ MODULE_DESCRIPTION(GS_LONG_NAME); ...@@ -598,8 +593,10 @@ MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers"); MODULE_AUTHOR("Al Borchers");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#if G_SERIAL_DEBUG
MODULE_PARM(debug, "i"); MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif
MODULE_PARM(read_q_size, "i"); MODULE_PARM(read_q_size, "i");
MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32"); MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");
......
...@@ -95,6 +95,10 @@ static kmem_cache_t *uhci_up_cachep; /* urb_priv */ ...@@ -95,6 +95,10 @@ static kmem_cache_t *uhci_up_cachep; /* urb_priv */
static int uhci_get_current_frame_number(struct uhci_hcd *uhci); static int uhci_get_current_frame_number(struct uhci_hcd *uhci);
static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb); static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb); static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs);
static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
static void uhci_free_pending_tds(struct uhci_hcd *uhci);
static void hc_state_transitions(struct uhci_hcd *uhci); static void hc_state_transitions(struct uhci_hcd *uhci);
...@@ -373,6 +377,7 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -373,6 +377,7 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{ {
struct uhci_qh *pqh; struct uhci_qh *pqh;
u32 newlink; u32 newlink;
unsigned int age;
if (!qh) if (!qh)
return; return;
...@@ -425,6 +430,12 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) ...@@ -425,6 +430,12 @@ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
list_del_init(&qh->urbp->queue_list); list_del_init(&qh->urbp->queue_list);
qh->urbp = NULL; qh->urbp = NULL;
age = uhci_get_current_frame_number(uhci);
if (age != uhci->qh_remove_age) {
uhci_free_pending_qhs(uhci);
uhci->qh_remove_age = age;
}
/* Check to see if the remove list is empty. Set the IOC bit */ /* Check to see if the remove list is empty. Set the IOC bit */
/* to force an interrupt so we can remove the QH */ /* to force an interrupt so we can remove the QH */
if (list_empty(&uhci->qh_remove_list)) if (list_empty(&uhci->qh_remove_list))
...@@ -628,6 +639,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) ...@@ -628,6 +639,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
{ {
struct list_head *head, *tmp; struct list_head *head, *tmp;
struct urb_priv *urbp; struct urb_priv *urbp;
unsigned int age;
urbp = (struct urb_priv *)urb->hcpriv; urbp = (struct urb_priv *)urb->hcpriv;
if (!urbp) if (!urbp)
...@@ -637,6 +649,12 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) ...@@ -637,6 +649,12 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list " dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
"or uhci->remove_list!\n", urb); "or uhci->remove_list!\n", urb);
age = uhci_get_current_frame_number(uhci);
if (age != uhci->td_remove_age) {
uhci_free_pending_tds(uhci);
uhci->td_remove_age = age;
}
/* Check to see if the remove list is empty. Set the IOC bit */ /* Check to see if the remove list is empty. Set the IOC bit */
/* to force an interrupt so we can remove the TD's*/ /* to force an interrupt so we can remove the TD's*/
if (list_empty(&uhci->td_remove_list)) if (list_empty(&uhci->td_remove_list))
...@@ -1512,6 +1530,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -1512,6 +1530,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags; unsigned long flags;
struct urb_priv *urbp; struct urb_priv *urbp;
unsigned int age;
spin_lock_irqsave(&uhci->schedule_lock, flags); spin_lock_irqsave(&uhci->schedule_lock, flags);
urbp = urb->hcpriv; urbp = urb->hcpriv;
...@@ -1521,6 +1540,12 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -1521,6 +1540,12 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
uhci_unlink_generic(uhci, urb); uhci_unlink_generic(uhci, urb);
age = uhci_get_current_frame_number(uhci);
if (age != uhci->urb_remove_age) {
uhci_remove_pending_urbps(uhci);
uhci->urb_remove_age = age;
}
/* If we're the first, set the next interrupt bit */ /* If we're the first, set the next interrupt bit */
if (list_empty(&uhci->urb_remove_list)) if (list_empty(&uhci->urb_remove_list))
uhci_set_next_interrupt(uhci); uhci_set_next_interrupt(uhci);
...@@ -1590,6 +1615,12 @@ static void stall_callback(unsigned long ptr) ...@@ -1590,6 +1615,12 @@ static void stall_callback(unsigned long ptr)
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
spin_lock_irqsave(&uhci->schedule_lock, flags); spin_lock_irqsave(&uhci->schedule_lock, flags);
if (!list_empty(&uhci->urb_remove_list) &&
uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
uhci_remove_pending_urbps(uhci);
uhci_finish_completion(hcd, NULL);
}
head = &uhci->urb_list; head = &uhci->urb_list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
...@@ -1728,6 +1759,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1728,6 +1759,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
unsigned short status; unsigned short status;
struct list_head *tmp, *head; struct list_head *tmp, *head;
unsigned int age;
/* /*
* Read the interrupt status, and write it back to clear the * Read the interrupt status, and write it back to clear the
...@@ -1758,11 +1790,20 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -1758,11 +1790,20 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
spin_lock(&uhci->schedule_lock); spin_lock(&uhci->schedule_lock);
age = uhci_get_current_frame_number(uhci);
if (age != uhci->qh_remove_age)
uhci_free_pending_qhs(uhci); uhci_free_pending_qhs(uhci);
if (age != uhci->td_remove_age)
uhci_free_pending_tds(uhci); uhci_free_pending_tds(uhci);
if (age != uhci->urb_remove_age)
uhci_remove_pending_urbps(uhci); uhci_remove_pending_urbps(uhci);
if (list_empty(&uhci->urb_remove_list) &&
list_empty(&uhci->td_remove_list) &&
list_empty(&uhci->qh_remove_list))
uhci_clear_next_interrupt(uhci); uhci_clear_next_interrupt(uhci);
else
uhci_set_next_interrupt(uhci);
/* Walk the list of pending URB's to see which ones completed */ /* Walk the list of pending URB's to see which ones completed */
head = &uhci->urb_list; head = &uhci->urb_list;
......
...@@ -357,12 +357,15 @@ struct uhci_hcd { ...@@ -357,12 +357,15 @@ struct uhci_hcd {
/* List of QH's that are done, but waiting to be unlinked (race) */ /* List of QH's that are done, but waiting to be unlinked (race) */
struct list_head qh_remove_list; /* P: uhci->schedule_lock */ struct list_head qh_remove_list; /* P: uhci->schedule_lock */
unsigned int qh_remove_age; /* Age in frames */
/* List of TD's that are done, but waiting to be freed (race) */ /* List of TD's that are done, but waiting to be freed (race) */
struct list_head td_remove_list; /* P: uhci->schedule_lock */ struct list_head td_remove_list; /* P: uhci->schedule_lock */
unsigned int td_remove_age; /* Age in frames */
/* List of asynchronously unlinked URB's */ /* List of asynchronously unlinked URB's */
struct list_head urb_remove_list; /* P: uhci->schedule_lock */ struct list_head urb_remove_list; /* P: uhci->schedule_lock */
unsigned int urb_remove_age; /* Age in frames */
/* List of URB's awaiting completion callback */ /* List of URB's awaiting completion callback */
struct list_head complete_list; /* P: uhci->schedule_lock */ struct list_head complete_list; /* P: uhci->schedule_lock */
......
...@@ -232,7 +232,7 @@ static int hiddev_fasync(int fd, struct file *file, int on) ...@@ -232,7 +232,7 @@ static int hiddev_fasync(int fd, struct file *file, int on)
static struct usb_class_driver hiddev_class; static struct usb_class_driver hiddev_class;
static void hiddev_cleanup(struct hiddev *hiddev) static void hiddev_cleanup(struct hiddev *hiddev)
{ {
hiddev_table[hiddev->hid->minor] = NULL; hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
usb_deregister_dev(hiddev->hid->intf, &hiddev_class); usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
kfree(hiddev); kfree(hiddev);
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/usb.h> #include <linux/usb.h>
#define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */
...@@ -67,7 +68,7 @@ struct powermate_device { ...@@ -67,7 +68,7 @@ struct powermate_device {
dma_addr_t configcr_dma; dma_addr_t configcr_dma;
struct usb_device *udev; struct usb_device *udev;
struct input_dev input; struct input_dev input;
struct semaphore lock; spinlock_t lock;
int static_brightness; int static_brightness;
int pulse_speed; int pulse_speed;
int pulse_table; int pulse_table;
...@@ -116,7 +117,7 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs) ...@@ -116,7 +117,7 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs)
__FUNCTION__, retval); __FUNCTION__, retval);
} }
/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */ /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
static void powermate_sync_state(struct powermate_device *pm) static void powermate_sync_state(struct powermate_device *pm)
{ {
if (pm->requires_update == 0) if (pm->requires_update == 0)
...@@ -194,19 +195,22 @@ static void powermate_sync_state(struct powermate_device *pm) ...@@ -194,19 +195,22 @@ static void powermate_sync_state(struct powermate_device *pm)
static void powermate_config_complete(struct urb *urb, struct pt_regs *regs) static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
{ {
struct powermate_device *pm = urb->context; struct powermate_device *pm = urb->context;
unsigned long flags;
if (urb->status) if (urb->status)
printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
down(&pm->lock); spin_lock_irqsave(&pm->lock, flags);
powermate_sync_state(pm); powermate_sync_state(pm);
up(&pm->lock); spin_unlock_irqrestore(&pm->lock, flags);
} }
/* Set the LED up as described and begin the sync with the hardware if required */ /* Set the LED up as described and begin the sync with the hardware if required */
static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
int pulse_table, int pulse_asleep, int pulse_awake) int pulse_table, int pulse_asleep, int pulse_awake)
{ {
unsigned long flags;
if (pulse_speed < 0) if (pulse_speed < 0)
pulse_speed = 0; pulse_speed = 0;
if (pulse_table < 0) if (pulse_table < 0)
...@@ -219,7 +223,8 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne ...@@ -219,7 +223,8 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
pulse_asleep = !!pulse_asleep; pulse_asleep = !!pulse_asleep;
pulse_awake = !!pulse_awake; pulse_awake = !!pulse_awake;
down(&pm->lock);
spin_lock_irqsave(&pm->lock, flags);
/* mark state updates which are required */ /* mark state updates which are required */
if (static_brightness != pm->static_brightness){ if (static_brightness != pm->static_brightness){
...@@ -242,7 +247,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne ...@@ -242,7 +247,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
powermate_sync_state(pm); powermate_sync_state(pm);
up(&pm->lock); spin_unlock_irqrestore(&pm->lock, flags);
} }
/* Callback from the Input layer when an event arrives from userspace to configure the LED */ /* Callback from the Input layer when an event arrives from userspace to configure the LED */
...@@ -344,7 +349,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -344,7 +349,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
return -ENOMEM; return -ENOMEM;
} }
init_MUTEX(&pm->lock); pm->lock = SPIN_LOCK_UNLOCKED;
init_input_dev(&pm->input); init_input_dev(&pm->input);
/* get a handle to the interrupt data pipe */ /* get a handle to the interrupt data pipe */
...@@ -411,7 +416,6 @@ static void powermate_disconnect(struct usb_interface *intf) ...@@ -411,7 +416,6 @@ static void powermate_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (pm) { if (pm) {
down(&pm->lock);
pm->requires_update = 0; pm->requires_update = 0;
usb_unlink_urb(pm->irq); usb_unlink_urb(pm->irq);
input_unregister_device(&pm->input); input_unregister_device(&pm->input);
......
...@@ -1240,20 +1240,21 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) ...@@ -1240,20 +1240,21 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
init_waitqueue_head(&awd.wqh); init_waitqueue_head(&awd.wqh);
awd.done = 0; awd.done = 0;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&awd.wqh, &wait); add_wait_queue(&awd.wqh, &wait);
urb->context = &awd; urb->context = &awd;
status = usb_submit_urb(urb, GFP_ATOMIC); status = usb_submit_urb(urb, GFP_NOIO);
if (status) { if (status) {
// something went wrong // something went wrong
usb_free_urb(urb); usb_free_urb(urb);
set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait); remove_wait_queue(&awd.wqh, &wait);
return status; return status;
} }
while (timeout && !awd.done) set_current_state(TASK_UNINTERRUPTIBLE);
while (timeout && !awd.done) {
timeout = schedule_timeout(timeout); timeout = schedule_timeout(timeout);
set_current_state(TASK_UNINTERRUPTIBLE);
}
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait); remove_wait_queue(&awd.wqh, &wait);
......
...@@ -136,6 +136,7 @@ struct usb_eth_dev { ...@@ -136,6 +136,7 @@ struct usb_eth_dev {
#define VENDOR_LANEED 0x056e #define VENDOR_LANEED 0x056e
#define VENDOR_LINKSYS 0x066b #define VENDOR_LINKSYS 0x066b
#define VENDOR_MELCO 0x0411 #define VENDOR_MELCO 0x0411
#define VENDOR_MICROSOFT 0x045e
#define VENDOR_MOBILITY 0x1342 #define VENDOR_MOBILITY 0x1342
#define VENDOR_NETGEAR 0x0846 #define VENDOR_NETGEAR 0x0846
#define VENDOR_OCT 0x0b39 #define VENDOR_OCT 0x0b39
...@@ -265,6 +266,8 @@ PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005, ...@@ -265,6 +266,8 @@ PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009, PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020, PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109, PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109,
......
...@@ -314,8 +314,8 @@ config USB_SERIAL_KLSI ...@@ -314,8 +314,8 @@ config USB_SERIAL_KLSI
module will be called kl5kusb105. module will be called kl5kusb105.
config USB_SERIAL_KOBIL_SCT config USB_SERIAL_KOBIL_SCT
tristate "USB KOBIL chipcard reader (EXPERIMENTAL)" tristate "USB KOBIL chipcard reader"
depends on USB_SERIAL && EXPERIMENTAL depends on USB_SERIAL
---help--- ---help---
Say Y here if you want to use one of the following KOBIL USB chipcard Say Y here if you want to use one of the following KOBIL USB chipcard
readers: readers:
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
* See http://ftdi-usb-sio.sourceforge.net for upto date testing info * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
* and extra documentation * and extra documentation
* *
* (27/May/2004) Ian Abbott
* Improved throttling code, mostly stolen from the WhiteHEAT driver.
*
* (26/Mar/2004) Jan Capek * (26/Mar/2004) Jan Capek
* Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc. * Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc.
* *
...@@ -584,6 +587,10 @@ static struct usb_driver ftdi_driver = { ...@@ -584,6 +587,10 @@ static struct usb_driver ftdi_driver = {
#define BUFSZ 512 #define BUFSZ 512
#define PKTSZ 64 #define PKTSZ 64
/* rx_flags */
#define THROTTLED 0x01
#define ACTUALLY_THROTTLED 0x02
struct ftdi_private { struct ftdi_private {
ftdi_chip_type_t chip_type; ftdi_chip_type_t chip_type;
/* type of the device, either SIO or FT8U232AM */ /* type of the device, either SIO or FT8U232AM */
...@@ -598,6 +605,8 @@ struct ftdi_private { ...@@ -598,6 +605,8 @@ struct ftdi_private {
unsigned long last_dtr_rts; /* saved modem control outputs */ unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */ char prev_status, diff_status; /* Used for TIOCMIWAIT */
__u8 rx_flags; /* receive state flags (throttling) */
spinlock_t rx_lock; /* spinlock for receive state */
int force_baud; /* if non-zero, force the baud rate to this value */ int force_baud; /* if non-zero, force the baud rate to this value */
int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
...@@ -625,6 +634,7 @@ static int ftdi_write_room (struct usb_serial_port *port); ...@@ -625,6 +634,7 @@ static int ftdi_write_room (struct usb_serial_port *port);
static int ftdi_chars_in_buffer (struct usb_serial_port *port); static int ftdi_chars_in_buffer (struct usb_serial_port *port);
static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs); static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs); static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void ftdi_process_read (struct usb_serial_port *port);
static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old); static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old);
static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file); static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file);
static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear); static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear);
...@@ -1110,6 +1120,7 @@ static int ftdi_common_startup (struct usb_serial *serial) ...@@ -1110,6 +1120,7 @@ static int ftdi_common_startup (struct usb_serial *serial)
} }
memset(priv, 0, sizeof(*priv)); memset(priv, 0, sizeof(*priv));
spin_lock_init(&priv->rx_lock);
init_waitqueue_head(&priv->delta_msr_wait); init_waitqueue_head(&priv->delta_msr_wait);
/* This will push the characters through immediately rather /* This will push the characters through immediately rather
than queue a task to deliver them */ than queue a task to deliver them */
...@@ -1273,8 +1284,8 @@ static void ftdi_shutdown (struct usb_serial *serial) ...@@ -1273,8 +1284,8 @@ static void ftdi_shutdown (struct usb_serial *serial)
*/ */
if (priv) { if (priv) {
kfree(priv);
usb_set_serial_port_data(port, NULL); usb_set_serial_port_data(port, NULL);
kfree(priv);
} }
} /* ftdi_shutdown */ } /* ftdi_shutdown */
...@@ -1284,6 +1295,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) ...@@ -1284,6 +1295,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
struct termios tmp_termios; struct termios tmp_termios;
struct usb_device *dev = port->serial->dev; struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port); struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
int result = 0; int result = 0;
char buf[1]; /* Needed for the usb_control_msg I think */ char buf[1]; /* Needed for the usb_control_msg I think */
...@@ -1317,6 +1329,11 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) ...@@ -1317,6 +1329,11 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
err("%s Error from RTS HIGH urb", __FUNCTION__); err("%s Error from RTS HIGH urb", __FUNCTION__);
} }
/* Not throttled */
spin_lock_irqsave(&priv->rx_lock, flags);
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
spin_unlock_irqrestore(&priv->rx_lock, flags);
/* Start reading from the device */ /* Start reading from the device */
usb_fill_bulk_urb(port->read_urb, dev, usb_fill_bulk_urb(port->read_urb, dev,
usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress), usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
...@@ -1370,7 +1387,12 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) ...@@ -1370,7 +1387,12 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
/* shutdown our bulk read */ /* shutdown our bulk read */
if (port->read_urb) { if (port->read_urb) {
if (usb_unlink_urb (port->read_urb) < 0) { if (usb_unlink_urb (port->read_urb) < 0) {
err("Error unlinking read urb"); /* Generally, this isn't an error. If the previous
read bulk callback occurred (or is about to occur)
while the port was being closed or was throtted
(and is still throttled), the read urb will not
have been submitted. */
dbg("%s - failed to unlink read urb (generally not an error)", __FUNCTION__);
} }
} }
} /* ftdi_close */ } /* ftdi_close */
...@@ -1546,13 +1568,6 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1546,13 +1568,6 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty; struct tty_struct *tty;
struct ftdi_private *priv; struct ftdi_private *priv;
char error_flag;
unsigned char *data = urb->transfer_buffer;
int i;
int result;
int need_flip;
int packet_offset;
if (urb->number_of_packets > 0) { if (urb->number_of_packets > 0) {
err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
...@@ -1560,7 +1575,7 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1560,7 +1575,7 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags ); err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags );
} }
dbg("%s", __FUNCTION__); dbg("%s - port %d", __FUNCTION__, port->number);
if (port->open_count <= 0) if (port->open_count <= 0)
return; return;
...@@ -1572,6 +1587,14 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1572,6 +1587,14 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
} }
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
if (!priv) {
dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
return;
}
if (urb != port->read_urb) {
err("%s - Not my urb!", __FUNCTION__);
}
if (urb->status) { if (urb->status) {
/* This will happen at close every time so it is a dbg not an err */ /* This will happen at close every time so it is a dbg not an err */
...@@ -1579,6 +1602,59 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1579,6 +1602,59 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
return; return;
} }
/* If throttled, delay receive processing until unthrottled. */
spin_lock(&priv->rx_lock);
if (priv->rx_flags & THROTTLED) {
dbg("Deferring read urb processing until unthrottled");
priv->rx_flags |= ACTUALLY_THROTTLED;
spin_unlock(&priv->rx_lock);
return;
}
spin_unlock(&priv->rx_lock);
ftdi_process_read(port);
} /* ftdi_read_bulk_callback */
static void ftdi_process_read (struct usb_serial_port *port)
{ /* ftdi_process_read */
struct urb *urb;
struct tty_struct *tty;
struct ftdi_private *priv;
char error_flag;
unsigned char *data;
int i;
int result;
int need_flip;
int packet_offset;
dbg("%s - port %d", __FUNCTION__, port->number);
if (port->open_count <= 0)
return;
tty = port->tty;
if (!tty) {
dbg("%s - bad tty pointer - exiting",__FUNCTION__);
return;
}
priv = usb_get_serial_port_data(port);
if (!priv) {
dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
return;
}
urb = port->read_urb;
if (!urb) {
dbg("%s - bad read_urb pointer - exiting", __FUNCTION__);
return;
}
data = urb->transfer_buffer;
/* The first two bytes of every read packet are status */ /* The first two bytes of every read packet are status */
if (urb->actual_length > 2) { if (urb->actual_length > 2) {
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
...@@ -1683,7 +1759,7 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -1683,7 +1759,7 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
} }
return; return;
} /* ftdi_read_bulk_callback */ } /* ftdi_process_read */
static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
...@@ -2073,27 +2149,32 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne ...@@ -2073,27 +2149,32 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
static void ftdi_throttle (struct usb_serial_port *port) static void ftdi_throttle (struct usb_serial_port *port)
{ {
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
usb_unlink_urb (port->read_urb);
spin_lock_irqsave(&priv->rx_lock, flags);
priv->rx_flags |= THROTTLED;
spin_unlock_irqrestore(&priv->rx_lock, flags);
} }
static void ftdi_unthrottle (struct usb_serial_port *port) static void ftdi_unthrottle (struct usb_serial_port *port)
{ {
int result; struct ftdi_private *priv = usb_get_serial_port_data(port);
int actually_throttled;
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
port->read_urb->dev = port->serial->dev; spin_lock_irqsave(&priv->rx_lock, flags);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
spin_unlock_irqrestore(&priv->rx_lock, flags);
usb_fill_bulk_urb(port->read_urb, port->serial->dev, if (actually_throttled)
usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), ftdi_process_read(port);
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
ftdi_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
} }
static int __init ftdi_init (void) static int __init ftdi_init (void)
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
* Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
* (Adapter K), B1 Professional and KAAN Professional (Adapter B) * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
* *
* (21/05/2004) tw
* Fix bug with P'n'P readers
*
* (28/05/2003) tw * (28/05/2003) tw
* Add support for KAAN SIM * Add support for KAAN SIM
* *
...@@ -59,7 +62,7 @@ ...@@ -59,7 +62,7 @@
#include "usb-serial.h" #include "usb-serial.h"
/* Version Information */ /* Version Information */
#define DRIVER_VERSION "28/05/2003" #define DRIVER_VERSION "21/05/2004"
#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com" #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)" #define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
...@@ -339,6 +342,12 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp) ...@@ -339,6 +342,12 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
); );
dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
} }
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
// start reading (Adapter B 'cause PNP string)
result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC );
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
}
kfree(transfer_buffer); kfree(transfer_buffer);
return 0; return 0;
...@@ -456,6 +465,11 @@ static int kobil_write (struct usb_serial_port *port, int from_user, ...@@ -456,6 +465,11 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) ||
((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) { ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
// stop reading (except TWIN and KAAN SIM)
if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
usb_unlink_urb( port->interrupt_in_urb );
}
todo = priv->filled - priv->cur_pos; todo = priv->filled - priv->cur_pos;
while(todo > 0) { while(todo > 0) {
...@@ -463,25 +477,23 @@ static int kobil_write (struct usb_serial_port *port, int from_user, ...@@ -463,25 +477,23 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
length = (todo < 8) ? todo : 8; length = (todo < 8) ? todo : 8;
// copy data to transfer buffer // copy data to transfer buffer
memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length ); memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length );
usb_fill_int_urb( port->write_urb,
usb_fill_bulk_urb( port->write_urb,
port->serial->dev, port->serial->dev,
usb_sndbulkpipe( port->serial->dev, priv->write_int_endpoint_address), usb_sndintpipe(port->serial->dev, priv->write_int_endpoint_address),
port->write_urb->transfer_buffer, port->write_urb->transfer_buffer,
length, length,
kobil_write_callback, kobil_write_callback,
port port,
8
); );
priv->cur_pos = priv->cur_pos + length; priv->cur_pos = priv->cur_pos + length;
result = usb_submit_urb( port->write_urb, GFP_ATOMIC ); result = usb_submit_urb( port->write_urb, GFP_NOIO );
dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
todo = priv->filled - priv->cur_pos; todo = priv->filled - priv->cur_pos;
if (todo > 0) { if (todo > 0) {
//mdelay(16); msleep(24);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(24 * HZ / 1000);
} }
} // end while } // end while
...@@ -492,10 +504,15 @@ static int kobil_write (struct usb_serial_port *port, int from_user, ...@@ -492,10 +504,15 @@ static int kobil_write (struct usb_serial_port *port, int from_user,
// someone sets the dev to 0 if the close method has been called // someone sets the dev to 0 if the close method has been called
port->interrupt_in_urb->dev = port->serial->dev; port->interrupt_in_urb->dev = port->serial->dev;
// start reading // start reading (except TWIN and KAAN SIM)
result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC ); if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) {
// someone sets the dev to 0 if the close method has been called
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb( port->interrupt_in_urb, GFP_NOIO );
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result); dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
} }
}
return count; return count;
} }
......
...@@ -680,7 +680,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -680,7 +680,7 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
char *string; char *string;
int retval = 0; int retval = 0;
int i; int i;
int num_ports; int num_ports = 0;
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
...@@ -703,15 +703,11 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -703,15 +703,11 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
goto exit; goto exit;
} }
if (retval == sizeof(*connection_info)) {
connection_info = (struct visor_connection_info *)transfer_buffer; connection_info = (struct visor_connection_info *)transfer_buffer;
le16_to_cpus(&connection_info->num_ports); le16_to_cpus(&connection_info->num_ports);
num_ports = connection_info->num_ports; num_ports = connection_info->num_ports;
/* handle devices that report invalid stuff here */
if (num_ports > 2)
num_ports = 2;
dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
connection_info->num_ports);
for (i = 0; i < num_ports; ++i) { for (i = 0; i < num_ports; ++i) {
switch (connection_info->connections[i].port_function_id) { switch (connection_info->connections[i].port_function_id) {
...@@ -734,9 +730,22 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -734,9 +730,22 @@ static int palm_os_3_probe (struct usb_serial *serial, const struct usb_device_i
string = "unknown"; string = "unknown";
break; break;
} }
dev_info(dev, "%s: port %d, is for %s use\n", serial->type->name, dev_info(dev, "%s: port %d, is for %s use\n",
serial->type->name,
connection_info->connections[i].port, string); connection_info->connections[i].port, string);
} }
}
/*
* Handle devices that report invalid stuff here.
*/
if (num_ports == 0 || num_ports > 2) {
dev_warn (dev, "%s: No valid connect info available\n",
serial->type->name);
num_ports = 2;
}
dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
num_ports);
/* /*
* save off our num_ports info so that we can use it in the * save off our num_ports info so that we can use it in the
...@@ -868,8 +877,7 @@ static int clie_3_5_startup (struct usb_serial *serial) ...@@ -868,8 +877,7 @@ static int clie_3_5_startup (struct usb_serial *serial)
static int treo_attach (struct usb_serial *serial) static int treo_attach (struct usb_serial *serial)
{ {
struct usb_serial_port *port; struct usb_serial_port *swap_port;
int i;
/* Only do this endpoint hack for the Handspring devices with /* Only do this endpoint hack for the Handspring devices with
* interrupt in endpoints, which for now are the Treo devices. */ * interrupt in endpoints, which for now are the Treo devices. */
...@@ -879,31 +887,28 @@ static int treo_attach (struct usb_serial *serial) ...@@ -879,31 +887,28 @@ static int treo_attach (struct usb_serial *serial)
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
/* Ok, this is pretty ugly, but these devices want to use the /*
* interrupt endpoint as paired up with a bulk endpoint for a * It appears that Treos want to use the 1st interrupt endpoint to
* "virtual serial port". So let's force the endpoints to be * communicate with the 2nd bulk out endpoint, so let's swap the 1st
* where we want them to be. */ * and 2nd bulk in and interrupt endpoints. Note that swapping the
for (i = serial->num_bulk_in; i < serial->num_ports; ++i) { * bulk out endpoints would break lots of apps that want to communicate
port = serial->port[i]; * on the second port.
port->read_urb = serial->port[0]->read_urb; */
port->bulk_in_endpointAddress = serial->port[0]->bulk_in_endpointAddress; #define COPY_PORT(dest, src) \
port->bulk_in_buffer = serial->port[0]->bulk_in_buffer; dest->read_urb = src->read_urb; \
} dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress; \
dest->bulk_in_buffer = src->bulk_in_buffer; \
for (i = serial->num_bulk_out; i < serial->num_ports; ++i) { dest->interrupt_in_urb = src->interrupt_in_urb; \
port = serial->port[i]; dest->interrupt_in_endpointAddress = src->interrupt_in_endpointAddress; \
port->write_urb = serial->port[0]->write_urb; dest->interrupt_in_buffer = src->interrupt_in_buffer;
port->bulk_out_size = serial->port[0]->bulk_out_size;
port->bulk_out_endpointAddress = serial->port[0]->bulk_out_endpointAddress; swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL);
port->bulk_out_buffer = serial->port[0]->bulk_out_buffer; if (!swap_port)
} return -ENOMEM;
COPY_PORT(swap_port, serial->port[0]);
for (i = serial->num_interrupt_in; i < serial->num_ports; ++i) { COPY_PORT(serial->port[0], serial->port[1]);
port = serial->port[i]; COPY_PORT(serial->port[1], swap_port);
port->interrupt_in_urb = serial->port[0]->interrupt_in_urb; kfree(swap_port);
port->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
port->interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
}
return 0; return 0;
} }
......
...@@ -1112,8 +1112,7 @@ static int usb_stor_reset_common(struct us_data *us, ...@@ -1112,8 +1112,7 @@ static int usb_stor_reset_common(struct us_data *us,
/* long wait for reset, so unlock to allow disconnects */ /* long wait for reset, so unlock to allow disconnects */
up(&us->dev_semaphore); up(&us->dev_semaphore);
set_current_state(TASK_UNINTERRUPTIBLE); msleep(6000);
schedule_timeout(HZ*6);
down(&us->dev_semaphore); down(&us->dev_semaphore);
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
US_DEBUGP("Reset interrupted by disconnect\n"); US_DEBUGP("Reset interrupted by disconnect\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment