From b71db443ea7998de4dfddce7adad640db70f221c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 24 Mar 2004 21:43:15 -0800 Subject: [PATCH] USB: USB gadgets can autoconfigure endpoints This adds some code that gadget drivers can call from driver initialization, to simplify the "configure against this hardware" step. Add endpoint autoconfiguration for gadget drivers. Endpoint selection is currently being done with conditional compilation. That doesn't look nice, but more importantly it doesn't work well with the model that some distributions won't be custom-matched to hardware. Say, a PDA distro running on iPaq (pxa2xx_udc) or Axim (mq11xx_udc). This code just makes it easier for drivers to match to hardware at run-time. It's a convenience function for something they could have been doing already, but weren't. --- include/linux/usb_gadget.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include/linux') diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h index 503abfe9a9aa..3ba4e10d0372 100644 --- a/include/linux/usb_gadget.h +++ b/include/linux/usb_gadget.h @@ -731,6 +731,15 @@ int usb_descriptor_fillbuf(void *, unsigned, int usb_gadget_config_buf(const struct usb_config_descriptor *config, void *buf, unsigned buflen, const struct usb_descriptor_header **desc); +/*-------------------------------------------------------------------------*/ + +/* utility wrapping a simple endpoint selection policy */ + +extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, + struct usb_endpoint_descriptor *) __init; + +extern void usb_ep_autoconfig_reset (struct usb_gadget *) __init; + #endif /* __KERNEL__ */ #endif /* __LINUX_USB_GADGET_H */ -- cgit v1.2.3 From 69dc1c65dbf699a526337a48b8ca64834f2d2acf Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 25 Mar 2004 20:31:15 -0800 Subject: [PATCH] USB: define USB feature bit indices This patch provides standard symbols for the various USB device and endpoint feature bits, so that drivers can use symbolic names for them. It also changes the code relating to endpoint halts so it uses those symbols. --- drivers/usb/core/hcd.h | 4 ---- drivers/usb/core/message.c | 3 ++- drivers/usb/gadget/goku_udc.c | 3 +-- drivers/usb/gadget/net2280.c | 4 ++-- drivers/usb/misc/usbtest.c | 3 ++- drivers/usb/storage/transport.c | 5 +++-- include/linux/usb_ch9.h | 14 ++++++++++++++ 7 files changed, 24 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 798c72279362..57143644b3ac 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -275,10 +275,6 @@ extern int usb_set_address(struct usb_device *dev); #define EndpointOutRequest \ ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) -/* table 9.6 standard features */ -#define DEVICE_REMOTE_WAKEUP 1 -#define ENDPOINT_HALT 0 - /* class requests from the USB 2.0 hub spec, table 11-15 */ /* GetBusState and SetHubDescriptor are optional, omitted */ #define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 3af6e2108e38..558c974ce5c9 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -722,7 +722,8 @@ int usb_clear_halt(struct usb_device *dev, int pipe) * this request for iso endpoints, which can't halt! */ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, endp, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); /* don't un-halt or force to DATA0 except on success */ diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index f39a67c1ba5e..61ce5b2eea41 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1562,8 +1562,7 @@ static void ep0_setup(struct goku_udc *dev) if (dev->ep[tmp].is_in) goto stall; } - /* endpoint halt */ - if (ctrl.wValue != 0) + if (ctrl.wValue != USB_ENDPOINT_HALT) goto stall; if (tmp) goku_clear_halt(&dev->ep[tmp]); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 9a71c7b73281..2ae8309600bb 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2401,7 +2401,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != 0 /* HALT feature */ + if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) @@ -2418,7 +2418,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != 0 /* HALT feature */ + if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 646a7884f496..f7be4dc9a06c 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1169,7 +1169,8 @@ static int test_halt (int ep, struct urb *urb) /* set halt (protocol test only), verify it worked */ retval = usb_control_msg (urb->dev, usb_sndctrlpipe (urb->dev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT, 0, ep, + USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, ep, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); if (retval < 0) { dbg ("ep %02x couldn't set halt, %d", ep, retval); diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index c0c05910fafb..bb738c8d99e5 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -256,8 +256,9 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) endp |= USB_DIR_IN; result = usb_stor_control_msg(us, us->send_ctrl_pipe, - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0, 3*HZ); + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, endp, + NULL, 0, 3*HZ); /* reset the toggles and endpoint flags */ usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), diff --git a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h index 682e95114870..2a9e19b10c64 100644 --- a/include/linux/usb_ch9.h +++ b/include/linux/usb_ch9.h @@ -68,6 +68,20 @@ #define USB_REQ_SET_INTERFACE 0x0B #define USB_REQ_SYNCH_FRAME 0x0C +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) + */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (high speed only) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* dev may initiate HNP */ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* other RH port does */ + +#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ + /** * struct usb_ctrlrequest - SETUP data for a USB device control request -- cgit v1.2.3 From 10766ddeeaf441451237794ad6c0a7ae6dcbf1f1 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 29 Mar 2004 17:25:17 -0800 Subject: [PATCH] USB: set_configuration locking cleanups I've posted all these before, the only notable change is treating that one gphoto2 case as warn-and-continue rather than return-with-failure. usb_set_configuration() cleanup * Remove it from the USB kernel driver API. No drivers need it now, and the sysadmin can change bConfigurationValue using sysfs (say, when hotplugging an otherwise problematic device). * Simpler/cleaner locking: caller must own dev->serialize. * Access from usbfs now uses usb_reset_configuration() sometimes, preventing sysfs thrash, and warns about some dangerous usage (which gphoto2 and other programs may be relying on). (This is from Alan Stern, but I morphed an error return into a warning.) * Prevent a couple potential "no configuration" oopses. (Alan's?) * Remove one broken call from usbcore, in the "device morphed" path of usb_reset_device(). This should be more polite now, hanging that one device rather than khubd. --- drivers/usb/core/devio.c | 47 ++++++++++++++++++++++++++++++++++++++++++++- drivers/usb/core/driverfs.c | 2 ++ drivers/usb/core/hub.c | 34 ++++++++------------------------ drivers/usb/core/message.c | 7 ++----- drivers/usb/core/usb.c | 4 ++++ drivers/usb/core/usb.h | 1 + include/linux/usb.h | 1 - 7 files changed, 63 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 1a2650ac5e3c..a3655d0e7ccb 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -430,6 +430,8 @@ static int findintfep(struct usb_device *dev, unsigned int ep) if (ep & ~(USB_DIR_IN|0xf)) return -EINVAL; + if (!dev->actconfig) + return -ESRCH; for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { iface = dev->actconfig->interface[i]; for (j = 0; j < iface->num_altsetting; j++) { @@ -450,6 +452,8 @@ static int findintfif(struct usb_device *dev, unsigned int ifn) if (ifn & ~0xff) return -EINVAL; + if (!dev->actconfig) + return -ESRCH; for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { if (dev->actconfig->interface[i]-> altsetting[0].desc.bInterfaceNumber == ifn) @@ -766,10 +770,51 @@ static int proc_setintf(struct dev_state *ps, void __user *arg) static int proc_setconfig(struct dev_state *ps, void __user *arg) { unsigned int u; + int status = 0; + struct usb_host_config *actconfig; if (get_user(u, (unsigned int __user *)arg)) return -EFAULT; - return usb_set_configuration(ps->dev, u); + + down(&ps->dev->serialize); + actconfig = ps->dev->actconfig; + + /* Don't touch the device if any interfaces are claimed. + * It could interfere with other drivers' operations, and if + * an interface is claimed by usbfs it could easily deadlock. + */ + if (actconfig) { + int i; + + for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { + if (usb_interface_claimed(actconfig->interface[i])) { + dev_warn (&ps->dev->dev, + "usbfs: interface %d claimed " + "while '%s' sets config #%d\n", + actconfig->interface[i] + ->cur_altsetting + ->desc.bInterfaceNumber, + current->comm, u); +#if 0 /* FIXME: enable in 2.6.10 or so */ + status = -EBUSY; + break; +#endif + } + } + } + + /* SET_CONFIGURATION is often abused as a "cheap" driver reset, + * so avoid usb_set_configuration()'s kick to sysfs + */ + if (status == 0) { + if (actconfig && actconfig->desc.bConfigurationValue == u) + status = usb_reset_configuration(ps->dev); + else + status = usb_set_configuration(ps->dev, u); + } + up(&ps->dev->serialize); + + return status; } static int proc_submiturb(struct dev_state *ps, void __user *arg) diff --git a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c index ed14bb6987b9..2284803bdeed 100644 --- a/drivers/usb/core/driverfs.c +++ b/drivers/usb/core/driverfs.c @@ -55,7 +55,9 @@ set_bConfigurationValue (struct device *dev, const char *buf, size_t count) if (sscanf (buf, "%u", &config) != 1 || config > 255) return -EINVAL; + down(&udev->serialize); value = usb_set_configuration (udev, config); + up(&udev->serialize); return (value < 0) ? value : count; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e8abb6929099..86adfdd5d439 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1299,33 +1299,15 @@ int usb_physical_reset_device(struct usb_device *dev) kfree(descriptor); usb_destroy_configuration(dev); - ret = usb_get_device_descriptor(dev, sizeof(dev->descriptor)); - if (ret != sizeof(dev->descriptor)) { - if (ret < 0) - err("unable to get device %s descriptor " - "(error=%d)", dev->devpath, ret); - else - err("USB device %s descriptor short read " - "(expected %Zi, got %i)", - dev->devpath, - sizeof(dev->descriptor), ret); - - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return -EIO; - } + /* FIXME Linux doesn't yet handle these "device morphed" + * paths. DFU variants need this to work ... and they + * include the "config descriptors changed" case this + * doesn't yet detect! + */ + dev->state = USB_STATE_NOTATTACHED; + dev_err(&dev->dev, "device morphed (DFU?), nyet supported\n"); - ret = usb_get_configuration(dev); - if (ret < 0) { - err("unable to get configuration (error=%d)", ret); - usb_destroy_configuration(dev); - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } - - usb_set_configuration(dev, dev->config[0].desc.bConfigurationValue); - return 1; + return -ENODEV; } kfree(descriptor); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 558c974ce5c9..5d9e3a88a80e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1075,11 +1075,11 @@ int usb_reset_configuration(struct usb_device *dev) return 0; } -/** +/* * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated * @configuration: the configuration being chosen. - * Context: !in_interrupt () + * Context: !in_interrupt(), caller holds dev->serialize * * This is used to enable non-default device modes. Not all devices * use this kind of configurability; many devices only have one @@ -1115,7 +1115,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) struct usb_host_config *cp = NULL; /* dev->serialize guards all config changes */ - down(&dev->serialize); for (i=0; idescriptor.bNumConfigurations; i++) { if (dev->config[i].desc.bConfigurationValue == configuration) { @@ -1191,7 +1190,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) } out: - up(&dev->serialize); return ret; } @@ -1300,6 +1298,5 @@ EXPORT_SYMBOL(usb_string); // synchronous calls that also maintain usbcore state EXPORT_SYMBOL(usb_clear_halt); EXPORT_SYMBOL(usb_reset_configuration); -EXPORT_SYMBOL(usb_set_configuration); EXPORT_SYMBOL(usb_set_interface); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 05dd49c24a61..0018f343c6c0 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1173,10 +1173,13 @@ int usb_new_device(struct usb_device *dev) usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); #endif + down(&dev->serialize); + /* put device-specific files into sysfs */ err = device_add (&dev->dev); if (err) { dev_err(&dev->dev, "can't device_add, error %d\n", err); + up(&dev->serialize); goto fail; } usb_create_driverfs_dev_files (dev); @@ -1211,6 +1214,7 @@ int usb_new_device(struct usb_device *dev) dev->descriptor.bNumConfigurations); } err = usb_set_configuration(dev, config); + up(&dev->serialize); if (err) { dev_err(&dev->dev, "can't set config #%d, error %d\n", config, err); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 499d9ae5642e..5126d551ce39 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -17,6 +17,7 @@ extern void usb_enable_interface (struct usb_device *dev, extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); +extern int usb_set_configuration(struct usb_device *dev, int configuration); /* for labeling diagnostics */ extern const char *usbcore_name; diff --git a/include/linux/usb.h b/include/linux/usb.h index e4b60511fc46..f6c4c170750d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -904,7 +904,6 @@ extern int usb_string(struct usb_device *dev, int index, /* wrappers that also update important state inside usbcore */ extern int usb_clear_halt(struct usb_device *dev, int pipe); extern int usb_reset_configuration(struct usb_device *dev); -extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); /* -- cgit v1.2.3 From e0d47b758e7645993c24c9ebe967c4735b9f0741 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 30 Mar 2004 21:35:04 -0800 Subject: [PATCH] USB: remove usb_interface.driver field Remove usb_interface.driver, and along with it the "half bound" state previously associated with drivers binding with claim() instead of probe(). This changes usb_driver_claim_interface() semantics slightly: drivers must now be prepared to accept disconnect() callbacks. Fixes more locking bugs, and a claim() oops that snuck in with a recent patch. --- drivers/usb/core/devices.c | 4 ++- drivers/usb/core/devio.c | 90 ++++++++++++++++++---------------------------- drivers/usb/core/message.c | 25 +++++++++++-- drivers/usb/core/usb.c | 87 +++++++++++++++----------------------------- include/linux/usb.h | 18 ++++++++-- 5 files changed, 103 insertions(+), 121 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 704ee35c0075..aa6f7baa6048 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -247,7 +247,9 @@ static char *usb_dump_interface_descriptor(char *start, char *end, const struct class_decode(desc->bInterfaceClass), desc->bInterfaceSubClass, desc->bInterfaceProtocol, - iface->driver ? iface->driver->name : "(none)"); + iface->dev.driver + ? iface->dev.driver->name + : "(none)"); up_read(&usb_bus_type.subsys.rwsem); return start; } diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index a3655d0e7ccb..ece587efd575 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -704,9 +704,9 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg) if ((ret = findintfif(ps->dev, gd.interface)) < 0) return ret; interface = ps->dev->actconfig->interface[ret]; - if (!interface->driver) + if (!interface->dev.driver) return -ENODATA; - strcpy(gd.driver, interface->driver->name); + strncpy(gd.driver, interface->dev.driver->name, sizeof(gd.driver)); if (copy_to_user(arg, &gd, sizeof(gd))) return -EFAULT; return 0; @@ -725,26 +725,11 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg) static int proc_resetdevice(struct dev_state *ps) { - int i, ret; - - ret = usb_reset_device(ps->dev); - if (ret < 0) - return ret; - - for (i = 0; i < ps->dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf = ps->dev->actconfig->interface[i]; - - /* Don't simulate interfaces we've claimed */ - if (test_bit(i, &ps->ifclaimed)) - continue; - - err ("%s - this function is broken", __FUNCTION__); - if (intf->driver && ps->dev) { - usb_probe_interface (&intf->dev); - } - } + /* FIXME when usb_reset_device() is fixed we'll need to grab + * ps->dev->serialize before calling it. + */ + return usb_reset_device(ps->dev); - return 0; } static int proc_setintf(struct dev_state *ps, void __user *arg) @@ -758,7 +743,7 @@ static int proc_setintf(struct dev_state *ps, void __user *arg) if ((ret = findintfif(ps->dev, setintf.interface)) < 0) return ret; interface = ps->dev->actconfig->interface[ret]; - if (interface->driver) { + if (interface->dev.driver) { if ((ret = checkintf(ps, ret))) return ret; } @@ -1141,58 +1126,51 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg) } } - if (!ps->dev) - retval = -ENODEV; - else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) + if (!ps->dev) { + if (buf) + kfree(buf); + return -ENODEV; + } + + down(&ps->dev->serialize); + if (ps->dev->state != USB_STATE_CONFIGURED) + retval = -ENODEV; + else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) retval = -EINVAL; - else switch (ctrl.ioctl_code) { - - /* disconnect kernel driver from interface, leaving it unbound. */ - /* maybe unbound - you get no guarantee it stays unbound */ - case USBDEVFS_DISCONNECT: - /* this function is misdesigned - retained for compatibility */ - lock_kernel(); - driver = ifp->driver; - if (driver) { - dbg ("disconnect '%s' from dev %d interface %d", - driver->name, ps->dev->devnum, ctrl.ifno); - usb_unbind_interface(&ifp->dev); + else switch (ctrl.ioctl_code) { + + /* disconnect kernel driver from interface */ + case USBDEVFS_DISCONNECT: + down_write(&usb_bus_type.subsys.rwsem); + if (ifp->dev.driver) { + driver = to_usb_driver(ifp->dev.driver); + dev_dbg (&ifp->dev, "disconnect by usbfs\n"); + usb_driver_release_interface(driver, ifp); } else retval = -ENODATA; - unlock_kernel(); + up_write(&usb_bus_type.subsys.rwsem); break; /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: - lock_kernel(); - retval = usb_probe_interface (&ifp->dev); - unlock_kernel(); + bus_rescan_devices(ifp->dev.bus); break; /* talk directly to the interface's driver */ default: - /* BKL used here to protect against changing the binding - * of this driver to this device, as well as unloading its - * driver module. - */ - lock_kernel (); - driver = ifp->driver; + down_read(&usb_bus_type.subsys.rwsem); + if (ifp->dev.driver) + driver = to_usb_driver(ifp->dev.driver); if (driver == 0 || driver->ioctl == 0) { - unlock_kernel(); - retval = -ENOSYS; + retval = -ENOTTY; } else { - if (!try_module_get (driver->owner)) { - unlock_kernel(); - retval = -ENOSYS; - break; - } - unlock_kernel (); retval = driver->ioctl (ifp, ctrl.ioctl_code, buf); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; - module_put (driver->owner); } + up_read(&usb_bus_type.subsys.rwsem); } + up(&ps->dev->serialize); /* cleanup and return */ if (retval >= 0 diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 5d9e3a88a80e..4b1641d5f47f 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1176,15 +1176,34 @@ int usb_set_configuration(struct usb_device *dev, int configuration) intf->dev.bus = &usb_bus_type; intf->dev.dma_mask = dev->dev.dma_mask; intf->dev.release = release_interface; + device_initialize (&intf->dev); sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, alt->desc.bInterfaceNumber); + } + + /* Now that all interfaces are setup, probe() calls + * may claim() any interface that's not yet bound. + * Many class drivers need that: CDC, audio, video, etc. + */ + for (i = 0; i < cp->desc.bNumInterfaces; ++i) { + struct usb_interface *intf = cp->interface[i]; + struct usb_interface_descriptor *desc; + + desc = &intf->altsetting [0].desc; dev_dbg (&dev->dev, - "registering %s (config #%d, interface %d)\n", + "adding %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, - alt->desc.bInterfaceNumber); - device_register (&intf->dev); + desc->bInterfaceNumber); + ret = device_add (&intf->dev); + if (ret != 0) { + dev_err(&dev->dev, + "device_add(%s) --> %d\n", + intf->dev.bus_id, + ret); + continue; + } usb_create_driverfs_intf_files (intf); } } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0018f343c6c0..bb2afb5de2aa 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -7,8 +7,7 @@ * (C) Copyright Gregory P. Smith 1999 * (C) Copyright Deti Fliegl 1999 (new USB architecture) * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id, - more docs, etc) + * (C) Copyright David Brownell 2000-2004 * (C) Copyright Yggdrasil Computing, Inc. 2000 * (usb_device_id matching changes by Adam J. Richter) * (C) Copyright Greg Kroah-Hartman 2002-2003 @@ -95,17 +94,11 @@ int usb_probe_interface(struct device *dev) if (!driver->probe) return error; - /* driver claim() doesn't yet affect dev->driver... */ - if (intf->driver) - return error; - id = usb_match_id (intf, driver->id_table); if (id) { dev_dbg (dev, "%s - got id\n", __FUNCTION__); error = driver->probe (intf, id); } - if (!error) - intf->driver = driver; return error; } @@ -114,7 +107,7 @@ int usb_probe_interface(struct device *dev) int usb_unbind_interface(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); - struct usb_driver *driver = intf->driver; + struct usb_driver *driver = to_usb_driver(intf->dev.driver); /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); @@ -127,7 +120,6 @@ int usb_unbind_interface(struct device *dev) intf->altsetting[0].desc.bInterfaceNumber, 0); usb_set_intfdata(intf, NULL); - intf->driver = NULL; return 0; } @@ -290,7 +282,8 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) /** * usb_driver_claim_interface - bind a driver to an interface * @driver: the driver to be bound - * @iface: the interface to which it will be bound + * @iface: the interface to which it will be bound; must be in the + * usb device's active configuration * @priv: driver data associated with that interface * * This is used by usb device drivers that need to claim more than one @@ -308,75 +301,52 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) */ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) { - if (!iface || !driver) - return -EINVAL; + struct device *dev = &iface->dev; - if (iface->driver) + if (dev->driver) return -EBUSY; - /* FIXME should device_bind_driver() */ - iface->driver = driver; + dev->driver = &driver->driver; usb_set_intfdata(iface, priv); - return 0; -} -/** - * usb_interface_claimed - returns true iff an interface is claimed - * @iface: the interface being checked - * - * This should be used by drivers to check other interfaces to see if - * they are available or not. If another driver has claimed the interface, - * they may not claim it. Otherwise it's OK to claim it using - * usb_driver_claim_interface(). - * - * Returns true (nonzero) iff the interface is claimed, else false (zero). - */ -int usb_interface_claimed(struct usb_interface *iface) -{ - if (!iface) - return 0; + /* if interface was already added, bind now; else let + * the future device_add() bind it, bypassing probe() + */ + if (!list_empty (&dev->bus_list)) + device_bind_driver(dev); - return (iface->driver != NULL); -} /* usb_interface_claimed() */ + return 0; +} /** * usb_driver_release_interface - unbind a driver from an interface * @driver: the driver to be unbound * @iface: the interface from which it will be unbound * - * In addition to unbinding the driver, this re-initializes the interface - * by selecting altsetting 0, the default alternate setting. - * * This can be used by drivers to release an interface without waiting - * for their disconnect() methods to be called. - * - * When the USB subsystem disconnect()s a driver from some interface, - * it automatically invokes this method for that interface. That - * means that even drivers that used usb_driver_claim_interface() - * usually won't need to call this. + * for their disconnect() methods to be called. In typical cases this + * also causes the driver disconnect() method to be called. * * This call is synchronous, and may not be used in an interrupt context. - * Callers must own the driver model's usb bus writelock. So driver - * disconnect() entries don't need extra locking, but other call contexts - * may need to explicitly claim that lock. + * Callers must own the usb_device serialize semaphore and the driver model's + * usb bus writelock. So driver disconnect() entries don't need extra locking, + * but other call contexts may need to explicitly claim those locks. */ -void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) +void usb_driver_release_interface(struct usb_driver *driver, + struct usb_interface *iface) { + struct device *dev = &iface->dev; + /* this should never happen, don't release something that's not ours */ - if (!iface || !iface->driver || iface->driver != driver) + if (!dev->driver || dev->driver != &driver->driver) return; - if (iface->dev.driver) { - /* FIXME should be the ONLY case here */ - device_release_driver(&iface->dev); - return; - } + /* don't disconnect from disconnect(), or before dev_add() */ + if (!list_empty (&dev->driver_list) && !list_empty (&dev->bus_list)) + device_release_driver(dev); - usb_set_interface(interface_to_usbdev(iface), - iface->altsetting[0].desc.bInterfaceNumber, - 0); + dev->driver = NULL; usb_set_intfdata(iface, NULL); - iface->driver = NULL; } /** @@ -1633,7 +1603,6 @@ EXPORT_SYMBOL(usb_get_dev); EXPORT_SYMBOL(usb_hub_tt_clear_buffer); EXPORT_SYMBOL(usb_driver_claim_interface); -EXPORT_SYMBOL(usb_interface_claimed); EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_match_id); EXPORT_SYMBOL(usb_find_interface); diff --git a/include/linux/usb.h b/include/linux/usb.h index f6c4c170750d..739db8598207 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -31,6 +31,7 @@ static __inline__ void wait_ms(unsigned int ms) } struct usb_device; +struct usb_driver; /*-------------------------------------------------------------------------*/ @@ -123,7 +124,6 @@ struct usb_interface { * active alternate setting */ unsigned num_altsetting; /* number of alternate settings */ - struct usb_driver *driver; /* driver */ int minor; /* minor number this interface is bound to */ struct device dev; /* interface specific device info */ struct class_device *class_dev; @@ -318,7 +318,21 @@ extern int usb_get_current_frame_number (struct usb_device *usb_dev); /* used these for multi-interface device registration */ extern int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv); -extern int usb_interface_claimed(struct usb_interface *iface); + +/** + * usb_interface_claimed - returns true iff an interface is claimed + * @iface: the interface being checked + * + * Returns true (nonzero) iff the interface is claimed, else false (zero). + * Callers must own the driver model's usb bus readlock. So driver + * probe() entries don't need extra locking, but other call contexts + * may need to explicitly claim that lock. + * + */ +static int inline usb_interface_claimed(struct usb_interface *iface) { + return (iface->dev.driver != NULL); +} + extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface); const struct usb_device_id *usb_match_id(struct usb_interface *interface, -- cgit v1.2.3 From 3ccbb87c83a53639cde9d14854b4976b0fe9e021 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 30 Mar 2004 21:46:06 -0800 Subject: USB: remove "released" field from struct usb_interface as it is not needed. --- include/linux/usb.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/usb.h b/include/linux/usb.h index 739db8598207..47a4e5c82af4 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -87,8 +87,6 @@ struct usb_host_interface { * number from the USB core by calling usb_register_dev(). * @dev: driver model's view of this device * @class_dev: driver model's class view of this device. - * @released: wait for the interface to be released when changing - * configurations. * * USB device drivers attach to interfaces on a physical device. Each * interface encapsulates a single high level function, such as feeding @@ -127,7 +125,6 @@ struct usb_interface { int minor; /* minor number this interface is bound to */ struct device dev; /* interface specific device info */ struct class_device *class_dev; - struct completion *released; /* wait for release */ }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) #define interface_to_usbdev(intf) \ -- cgit v1.2.3 From 622d3e6b0db6e4c6fc97a7e02627148176674d76 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 30 Mar 2004 22:17:38 -0800 Subject: USB: add usb_get_intf() and usb_put_intf() functions as they will be needed. --- drivers/usb/core/usb.c | 36 +++++++++++++++++++++++++++++++++++- include/linux/usb.h | 3 +++ 2 files changed, 38 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 11d5c1b94fce..0da70f7af71d 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -768,7 +768,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port) * * A pointer to the device with the incremented reference counter is returned. */ -struct usb_device *usb_get_dev (struct usb_device *dev) +struct usb_device *usb_get_dev(struct usb_device *dev) { if (dev) get_device(&dev->dev); @@ -788,6 +788,40 @@ void usb_put_dev(struct usb_device *dev) put_device(&dev->dev); } +/** + * usb_get_intf - increments the reference count of the usb interface structure + * @intf: the interface being referenced + * + * Each live reference to a interface must be refcounted. + * + * Drivers for USB interfaces should normally record such references in + * their probe() methods, when they bind to an interface, and release + * them by calling usb_put_intf(), in their disconnect() methods. + * + * A pointer to the interface with the incremented reference counter is + * returned. + */ +struct usb_interface *usb_get_intf(struct usb_interface *intf) +{ + if (intf) + get_device(&intf->dev); + return intf; +} + +/** + * usb_put_intf - release a use of the usb interface structure + * @intf: interface that's been decremented + * + * Must be called when a user of an interface is finished with it. When the + * last user of the interface calls this function, the memory of the interface + * is freed. + */ +void usb_put_intf(struct usb_interface *intf) +{ + if (intf) + put_device(&intf->dev); +} + static struct usb_device *match_device(struct usb_device *dev, u16 vendor_id, u16 product_id) { diff --git a/include/linux/usb.h b/include/linux/usb.h index 47a4e5c82af4..608e3a297340 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -140,6 +140,9 @@ static inline void usb_set_intfdata (struct usb_interface *intf, void *data) dev_set_drvdata(&intf->dev, data); } +struct usb_interface *usb_get_intf(struct usb_interface *intf); +void usb_put_intf(struct usb_interface *intf); + /* this maximum is arbitrary */ #define USB_MAXINTERFACES 32 -- cgit v1.2.3 From f1a40c850b54a213bd746f91bd7c92786fc744ed Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 1 Apr 2004 17:56:28 -0800 Subject: [PATCH] USB: ehci updates: CONFIG_PCI, integrated TT Generalize the driver a bit: - PCI-specific handling is restricted to a small chunk of init code. Non-PCI implementations are in the pipeline. - Merge support from ARC International (Craig Nadler) for their integrated root hub transaction translators (on PCI). Other implementations should be similar. --- drivers/usb/host/Kconfig | 11 ++++++++++ drivers/usb/host/ehci-dbg.c | 6 ++++-- drivers/usb/host/ehci-hcd.c | 50 +++++++++++++++++++++++++++++++++++++-------- drivers/usb/host/ehci-hub.c | 18 ++++++++++++++-- drivers/usb/host/ehci-q.c | 15 +++++++++++--- drivers/usb/host/ehci.h | 40 ++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 3 +++ 7 files changed, 127 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 55ec90a82ed6..946898ac46da 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -38,6 +38,17 @@ config USB_EHCI_SPLIT_ISO EHCI or USB 2.0 transaction translator implementations. It should work for ISO-OUT transfers, like audio. +config USB_EHCI_ROOT_HUB_TT + bool "Root Hub Transaction Translators (EXPERIMENTAL)" + depends on USB_EHCI_HCD && EXPERIMENTAL + ---help--- + Some EHCI chips have vendor-specific extensions to integrate + transaction translators, so that no OHCI or UHCI companion + controller is needed. It's safe to say "y" even if your + controller doesn't support this feature. + + This supports the EHCI implementation from ARC International. + config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 989a37804491..530cfd9f84ca 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -628,8 +628,10 @@ show_registers (struct class_device *class_dev, char *buf) /* Capability Registers */ i = HC_VERSION(readl (&ehci->caps->hc_capbase)); temp = scnprintf (next, size, - "PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n", - pci_name(to_pci_dev(hcd->self.controller)), + "bus %s device %s\n" + "EHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n", + hcd->self.controller->bus->name, + hcd->self.controller->bus_id, i >> 8, i & 0x0ff, ehci->hcd.state); size -= temp; next += temp; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 75d6db2b0540..1e61876ca0a7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -279,6 +279,8 @@ static void ehci_watchdog (unsigned long param) spin_unlock_irqrestore (&ehci->lock, flags); } +#ifdef CONFIG_PCI + /* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... * off the controller (maybe it can boot from highspeed USB disks). */ @@ -307,6 +309,8 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) return 0; } +#endif + static int ehci_reboot (struct notifier_block *self, unsigned long code, void *null) { @@ -335,8 +339,12 @@ static int ehci_hc_reset (struct usb_hcd *hcd) dbg_hcs_params (ehci, "reset"); dbg_hcc_params (ehci, "reset"); +#ifdef CONFIG_PCI /* EHCI 0.96 and later may have "extended capabilities" */ - temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + if (hcd->self.controller->bus == &pci_bus_type) + temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + else + temp = 0; while (temp) { u32 cap; @@ -356,6 +364,7 @@ static int ehci_hc_reset (struct usb_hcd *hcd) } temp = (cap >> 8) & 0xff; } +#endif /* cache this readonly data; minimize PCI reads */ ehci->hcs_params = readl (&ehci->caps->hcs_params); @@ -372,7 +381,7 @@ static int ehci_start (struct usb_hcd *hcd) struct usb_bus *bus; int retval; u32 hcc_params; - u8 tempbyte; + u8 sbrn = 0; init_timer (&ehci->watchdog); ehci->watchdog.function = ehci_watchdog; @@ -406,6 +415,29 @@ static int ehci_start (struct usb_hcd *hcd) writel (INTR_MASK, &ehci->regs->intr_enable); writel (ehci->periodic_dma, &ehci->regs->frame_list); +#ifdef CONFIG_PCI + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev; + + pdev = to_pci_dev(hcd->self.controller); + + /* Serial Bus Release Number is at PCI 0x60 offset */ + pci_read_config_byte(pdev, 0x60, &sbrn); + + /* help hc dma work well with cachelines */ + pci_set_mwi (pdev); + + /* chip-specific init */ + switch (pdev->vendor) { + case PCI_VENDOR_ID_ARC: + if (pdev->device == PCI_DEVICE_ID_ARC_EHCI) + ehci->is_arc_rh_tt = 1; + break; + } + + } +#endif + /* * dedicate a qh for the async ring head, since we couldn't unlink * a 'real' qh without stopping the async schedule [4.8]. use it @@ -443,9 +475,6 @@ static int ehci_start (struct usb_hcd *hcd) #endif } - /* help hc dma work well with cachelines */ - pci_set_mwi (to_pci_dev(ehci->hcd.self.controller)); - /* clear interrupt enables, set irq latency */ temp = readl (&ehci->regs->command) & 0x0fff; if (log2_irq_thresh < 0 || log2_irq_thresh > 6) @@ -493,12 +522,10 @@ done2: writel (FLAG_CF, &ehci->regs->configured_flag); readl (&ehci->regs->command); /* unblock posted write */ - /* PCI Serial Bus Release Number is at 0x60 offset */ - pci_read_config_byte(to_pci_dev(hcd->self.controller), 0x60, &tempbyte); temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); ehci_info (ehci, "USB %x.%x enabled, EHCI %x.%02x, driver %s\n", - ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f), + ((sbrn & 0xf0)>>4), (sbrn & 0x0f), temp >> 8, temp & 0xff, DRIVER_VERSION); /* @@ -995,7 +1022,9 @@ static const struct hc_driver ehci_driver = { /*-------------------------------------------------------------------------*/ -/* EHCI spec says PCI is required. */ +/* EHCI 1.0 doesn't require PCI */ + +#ifdef CONFIG_PCI /* PCI driver selection metadata; PCI hotplugging uses this */ static const struct pci_device_id pci_ids [] = { { @@ -1021,6 +1050,9 @@ static struct pci_driver ehci_pci_driver = { #endif }; +#endif /* PCI */ + + #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_DESCRIPTION (DRIVER_INFO); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 2c5cf36c90ba..5c3a0615211c 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -40,6 +40,15 @@ static int check_reset_complete ( /* if reset finished and it's still not enabled -- handoff */ if (!(port_status & PORT_PE)) { + + /* with integrated TT, there's nobody to hand it to! */ + if (ehci_is_ARC(ehci)) { + ehci_dbg (ehci, + "Failed to enable port %d on root hub TT\n", + index+1); + return port_status; + } + ehci_dbg (ehci, "port %d full speed --> companion\n", index + 1); @@ -257,7 +266,8 @@ static int ehci_hub_control ( if (!(temp & PORT_OWNER)) { if (temp & PORT_CONNECT) { status |= 1 << USB_PORT_FEAT_CONNECTION; - status |= 1 << USB_PORT_FEAT_HIGHSPEED; + // status may be from integrated TT + status |= ehci_port_speed(ehci, temp); } if (temp & PORT_PE) status |= 1 << USB_PORT_FEAT_ENABLE; @@ -307,8 +317,12 @@ static int ehci_hub_control ( &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_RESET: - /* line status bits may report this as low speed */ + /* line status bits may report this as low speed, + * which can be fine if this root hub has a + * transaction translator built in. + */ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT + && !ehci_is_ARC(ehci) && PORT_USB11 (temp)) { ehci_dbg (ehci, "port %d low speed --> companion\n", diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 69ca6429af12..fd8634b31231 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -165,7 +165,10 @@ static void qtd_copy_status ( /* if async CSPLIT failed, try cleaning out the TT buffer */ } else if (urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 - || QTD_CERR(token) == 0)) { + || QTD_CERR(token) == 0) + && (!ehci_is_ARC(ehci) + || urb->dev->tt->hub != + ehci->hcd.self.root_hub)) { #ifdef DEBUG struct usb_device *tt = urb->dev->tt->hub; dev_dbg (&tt->dev, @@ -576,7 +579,7 @@ clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh) // when each interface/altsetting is established. Unlink // any previous qh and cancel its urbs first; endpoints are // implicitly reset then (data toggle too). -// That'd mean updating how usbcore talks to HCDs. (2.5?) +// That'd mean updating how usbcore talks to HCDs. (2.7?) /* @@ -674,7 +677,13 @@ qh_make ( info2 |= (EHCI_TUNE_MULT_TT << 30); info2 |= urb->dev->ttport << 23; - info2 |= urb->dev->tt->hub->devnum << 16; + + /* set the address of the TT; for ARC's integrated + * root hub tt, leave it zeroed. + */ + if (!ehci_is_ARC(ehci) + || urb->dev->tt->hub != ehci->hcd.self.root_hub) + info2 |= urb->dev->tt->hub->devnum << 16; /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 5c6eef9674d6..8cd5b7b2c97a 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -85,6 +85,8 @@ struct ehci_hcd { /* one per controller */ unsigned long actions; unsigned stamp; + unsigned is_arc_rh_tt:1; /* ARC roothub with TT */ + /* irq statistics */ #ifdef EHCI_STATS struct ehci_stats stats; @@ -552,6 +554,44 @@ struct ehci_fstn { /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT + +/* + * Some EHCI controllers have a Transaction Translator built into the + * root hub. This is a non-standard feature. Each controller will need + * to add code to the following inline functions, and call them as + * needed (mostly in root hub code). + */ + +#define ehci_is_ARC(e) ((e)->is_arc_rh_tt) + +/* Returns the speed of a device attached to a port on the root hub. */ +static inline unsigned int +ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) +{ + if (ehci_is_ARC(ehci)) { + switch ((portsc>>26)&3) { + case 0: + return 0; + case 1: + return (1< Date: Thu, 1 Apr 2004 19:02:14 -0800 Subject: [PATCH] I2C: Add ALi 1563 Device ID to pci_ids.h --- include/linux/pci_ids.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4582d414df81..554eda2eac27 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -994,6 +994,7 @@ #define PCI_DEVICE_ID_AL_M1531 0x1531 #define PCI_DEVICE_ID_AL_M1533 0x1533 #define PCI_DEVICE_ID_AL_M1541 0x1541 +#define PCI_DEVICE_ID_AL_M1563 0x1563 #define PCI_DEVICE_ID_AL_M1621 0x1621 #define PCI_DEVICE_ID_AL_M1631 0x1631 #define PCI_DEVICE_ID_AL_M1632 0x1632 -- cgit v1.2.3 From f86225ee432e7d0ca8bd6cca78b0a48af7ef2d25 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 6 Apr 2004 00:28:52 -0400 Subject: [PATCH] remove magic '31' for netdev priv. alignment [resend/rediff] // linux-2.6.5 // remove magic number of '31' from net_device and private alignment; --- drivers/net/net_init.c | 8 +++++--- include/linux/netdevice.h | 7 ++++++- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c index 718108487c1e..854bc2b70cee 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -79,8 +79,9 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *mask, /* ensure 32-byte alignment of both the device and private area */ - alloc_size = (sizeof(struct net_device) + 31) & ~31; - alloc_size += sizeof_priv + 31; + alloc_size = (sizeof(struct net_device) + NETDEV_ALIGN_CONST) + & ~NETDEV_ALIGN_CONST; + alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; p = kmalloc (alloc_size, GFP_KERNEL); if (!p) { @@ -90,7 +91,8 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *mask, memset(p, 0, alloc_size); - dev = (struct net_device *)(((long)p + 31) & ~31); + dev = (struct net_device *)(((long)p + NETDEV_ALIGN_CONST) + & ~NETDEV_ALIGN_CONST); dev->padded = (char *)dev - (char *)p; if (sizeof_priv) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 378777e11e94..5c5a551fe630 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -484,9 +484,14 @@ struct net_device int padded; }; +#define NETDEV_ALIGN 32 +#define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) + static inline void *netdev_priv(struct net_device *dev) { - return (char *)dev + ((sizeof(struct net_device) + 31) & ~31); + return (char *)dev + ((sizeof(struct net_device) + + NETDEV_ALIGN_CONST) + & ~NETDEV_ALIGN_CONST); } #define SET_MODULE_OWNER(dev) do { } while (0) -- cgit v1.2.3 From 7635947f63bee4eae9003f423513f0a4c9ca6011 Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Wed, 14 Apr 2004 00:46:25 -0700 Subject: [PATCH] yenta: interrupt routing for TI briges Some TI cardbus bridges found in notebooks and PCI add-on cards are uninitialized. This means the interrupt mode and the interrupt routing is wrong in most cases, ending up in non working PCI interrupts. This makes the TI Yenta driver probe the PCI interrupt and adjust the interrupt setting if no interrupts are delivered. It's done in a safe way, that doesn't hurt working setups. Function 1 on two slot devices is handled differently from function 0 since both share the settings. --- drivers/pcmcia/ti113x.h | 344 +++++++++++++++++++++++++++++++++++------- drivers/pcmcia/yenta_socket.c | 72 ++++++++- drivers/pcmcia/yenta_socket.h | 3 + include/linux/pci_ids.h | 2 + 4 files changed, 367 insertions(+), 54 deletions(-) (limited to 'include/linux') diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index 0ef9acd21d0c..496a51923285 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -76,7 +76,23 @@ #define TI1250_GPIO1_CONTROL 0x0089 /* 8 bit */ #define TI1250_GPIO2_CONTROL 0x008a /* 8 bit */ #define TI1250_GPIO3_CONTROL 0x008b /* 8 bit */ -#define TI122X_IRQMUX 0x008c /* 32 bit */ +#define TI1250_GPIO_MODE_MASK 0xc0 + +/* IRQMUX/MFUNC Register */ +#define TI122X_MFUNC 0x008c /* 32 bit */ +#define TI122X_MFUNC0_MASK 0x0000000f +#define TI122X_MFUNC1_MASK 0x000000f0 +#define TI122X_MFUNC2_MASK 0x00000f00 +#define TI122X_MFUNC3_MASK 0x0000f000 +#define TI122X_MFUNC4_MASK 0x000f0000 +#define TI122X_MFUNC5_MASK 0x00f00000 +#define TI122X_MFUNC6_MASK 0x0f000000 + +#define TI122X_MFUNC0_INTA 0x00000002 +#define TI125X_MFUNC0_INTB 0x00000001 +#define TI122X_MFUNC1_INTB 0x00000020 +#define TI122X_MFUNC3_IRQSER 0x00001000 + /* Retry Status Register */ #define TI113X_RETRY_STATUS 0x0090 /* 8 bit */ @@ -143,7 +159,7 @@ #define ti_cardctl(socket) ((socket)->private[1]) #define ti_devctl(socket) ((socket)->private[2]) #define ti_diag(socket) ((socket)->private[3]) -#define ti_irqmux(socket) ((socket)->private[4]) +#define ti_mfunc(socket) ((socket)->private[4]) /* * These are the TI specific power management handlers. @@ -151,7 +167,7 @@ static void ti_save_state(struct yenta_socket *socket) { ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL); - ti_irqmux(socket) = config_readl(socket, TI122X_IRQMUX); + ti_mfunc(socket) = config_readl(socket, TI122X_MFUNC); ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL); ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL); ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC); @@ -160,7 +176,7 @@ static void ti_save_state(struct yenta_socket *socket) static void ti_restore_state(struct yenta_socket *socket) { config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket)); - config_writel(socket, TI122X_IRQMUX, ti_irqmux(socket)); + config_writel(socket, TI122X_MFUNC, ti_mfunc(socket)); config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket)); config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket)); config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket)); @@ -252,7 +268,7 @@ static void ti_set_zv(struct yenta_socket *socket) * INTCTL register that sets the PCI CSC interrupt. * Make sure we set it correctly at open and init * time - * - open: disable the PCI CSC interrupt. This makes + * - override: disable the PCI CSC interrupt. This makes * it possible to use the CSC interrupt to probe the * ISA interrupts. * - init: set the interrupt to match our PCI state. @@ -281,33 +297,6 @@ static int ti_override(struct yenta_socket *socket) ti_set_zv(socket); -#if 0 - /* - * If ISA interrupts don't work, then fall back to routing card - * interrupts to the PCI interrupt of the socket. - * - * Tweaking this when we are using serial PCI IRQs causes hangs - * --rmk - */ - if (!socket->socket.irq_mask) { - u8 irqmux, devctl; - - devctl = config_readb(socket, TI113X_DEVICE_CONTROL); - if ((devctl & TI113X_DCR_IMODE_MASK) != TI12XX_DCR_IMODE_ALL_SERIAL) { - printk (KERN_INFO "ti113x: Routing card interrupts to PCI\n"); - - devctl &= ~TI113X_DCR_IMODE_MASK; - - irqmux = config_readl(socket, TI122X_IRQMUX); - irqmux = (irqmux & ~0x0f) | 0x02; /* route INTA */ - irqmux = (irqmux & ~0xf0) | 0x20; /* route INTB */ - - config_writel(socket, TI122X_IRQMUX, irqmux); - config_writeb(socket, TI113X_DEVICE_CONTROL, devctl); - } - } -#endif - return 0; } @@ -325,6 +314,271 @@ static int ti113x_override(struct yenta_socket *socket) } +/* irqrouting for func0, probes PCI interrupt and ISA interrupts */ +static void ti12xx_irqroute_func0(struct yenta_socket *socket) +{ + u32 mfunc, mfunc_old, devctl; + u8 gpio3, gpio3_old; + int pci_irq_status; + + mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC); + devctl = config_readb(socket, TI113X_DEVICE_CONTROL); + printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n", + pci_name(socket->dev), mfunc, devctl); + + /* make sure PCI interrupts are enabled before probing */ + ti_init(socket); + + /* test PCI interrupts first. only try fixing if return value is 0! */ + pci_irq_status = yenta_probe_cb_irq(socket); + if (pci_irq_status) + goto out; + + /* + * We're here which means PCI interrupts are _not_ delivered. try to + * find the right setting (all serial or parallel) + */ + printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n", + pci_name(socket->dev)); + + /* for serial PCI make sure MFUNC3 is set to IRQSER */ + if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) { + switch (socket->dev->device) { + case PCI_DEVICE_ID_TI_1250: + case PCI_DEVICE_ID_TI_1251A: + case PCI_DEVICE_ID_TI_1251B: + case PCI_DEVICE_ID_TI_1450: + case PCI_DEVICE_ID_TI_1451A: + case PCI_DEVICE_ID_TI_4450: + case PCI_DEVICE_ID_TI_4451: + /* these chips have no IRQSER setting in MFUNC3 */ + break; + + default: + mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER; + + /* write down if changed, probe */ + if (mfunc != mfunc_old) { + config_writel(socket, TI122X_MFUNC, mfunc); + + pci_irq_status = yenta_probe_cb_irq(socket); + if (pci_irq_status == 1) { + printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts ok\n", + pci_name(socket->dev)); + mfunc_old = mfunc; + goto out; + } + + /* not working, back to old value */ + mfunc = mfunc_old; + config_writel(socket, TI122X_MFUNC, mfunc); + + if (pci_irq_status == -1) + goto out; + } + } + + /* serial PCI interrupts not working fall back to parallel */ + printk(KERN_INFO "Yenta TI: socket %s falling back to parallel PCI interrupts\n", + pci_name(socket->dev)); + devctl &= ~TI113X_DCR_IMODE_MASK; + devctl |= TI113X_DCR_IMODE_SERIAL; /* serial ISA could be right */ + config_writeb(socket, TI113X_DEVICE_CONTROL, devctl); + } + + /* parallel PCI interrupts: route INTA */ + switch (socket->dev->device) { + case PCI_DEVICE_ID_TI_1250: + case PCI_DEVICE_ID_TI_1251A: + case PCI_DEVICE_ID_TI_1251B: + case PCI_DEVICE_ID_TI_1450: + /* make sure GPIO3 is set to INTA */ + gpio3 = gpio3_old = config_readb(socket, TI1250_GPIO3_CONTROL); + gpio3 &= ~TI1250_GPIO_MODE_MASK; + if (gpio3 != gpio3_old) + config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3); + break; + + default: + gpio3 = gpio3_old = 0; + + mfunc = (mfunc & ~TI122X_MFUNC0_MASK) | TI122X_MFUNC0_INTA; + if (mfunc != mfunc_old) + config_writel(socket, TI122X_MFUNC, mfunc); + } + + /* time to probe again */ + pci_irq_status = yenta_probe_cb_irq(socket); + if (pci_irq_status == 1) { + mfunc_old = mfunc; + printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n", + pci_name(socket->dev)); + } else { + /* not working, back to old value */ + mfunc = mfunc_old; + config_writel(socket, TI122X_MFUNC, mfunc); + if (gpio3 != gpio3_old) + config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3_old); + } + +out: + if (pci_irq_status < 1) { + socket->cb_irq = 0; + printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n", + pci_name(socket->dev)); + } +} + + +/* + * ties INTA and INTB together. also changes the devices irq to that of + * the function 0 device. call from func1 only. + * returns 1 if INTRTIE changed, 0 otherwise. + */ +static int ti12xx_tie_interrupts(struct yenta_socket *socket, int *old_irq) +{ + struct pci_dev *func0; + u32 sysctl; + + sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL); + if (sysctl & TI122X_SCR_INTRTIE) + return 0; + + /* find func0 device */ + func0 = pci_get_slot(socket->dev->bus, socket->dev->devfn & ~0x07); + if (!func0) + return 0; + + /* change the interrupt to match func0, tie 'em up */ + *old_irq = socket->cb_irq; + socket->cb_irq = socket->dev->irq = func0->irq; + sysctl |= TI122X_SCR_INTRTIE; + config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl); + + pci_dev_put(func0); + + return 1; +} + +/* undo what ti12xx_tie_interrupts() did */ +static void ti12xx_untie_interrupts(struct yenta_socket *socket, int old_irq) +{ + u32 sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL); + sysctl &= ~TI122X_SCR_INTRTIE; + config_writel(socket, TI113X_SYSTEM_CONTROL, sysctl); + + socket->cb_irq = socket->dev->irq = old_irq; +} + +/* + * irqrouting for func1, plays with INTB routing + * only touches MFUNC for INTB routing. all other bits are taken + * care of in func0 already. + */ +static void ti12xx_irqroute_func1(struct yenta_socket *socket) +{ + u32 mfunc, mfunc_old, devctl; + int pci_irq_status; + + mfunc = mfunc_old = config_readl(socket, TI122X_MFUNC); + devctl = config_readb(socket, TI113X_DEVICE_CONTROL); + printk(KERN_INFO "Yenta TI: socket %s, mfunc 0x%08x, devctl 0x%02x\n", + pci_name(socket->dev), mfunc, devctl); + + /* make sure PCI interrupts are enabled before probing */ + ti_init(socket); + + /* test PCI interrupts first. only try fixing if return value is 0! */ + pci_irq_status = yenta_probe_cb_irq(socket); + if (pci_irq_status) + goto out; + + /* + * We're here which means PCI interrupts are _not_ delivered. try to + * find the right setting + */ + printk(KERN_INFO "Yenta TI: socket %s probing PCI interrupt failed, trying to fix\n", + pci_name(socket->dev)); + + + /* if all serial: set INTRTIE, probe again */ + if ((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) { + int old_irq; + + if (ti12xx_tie_interrupts(socket, &old_irq)) { + pci_irq_status = yenta_probe_cb_irq(socket); + if (pci_irq_status == 1) { + printk(KERN_INFO "Yenta TI: socket %s all-serial interrupts, tied ok\n", + pci_name(socket->dev)); + goto out; + } + + ti12xx_untie_interrupts(socket, old_irq); + } + } + /* parallel PCI: route INTB, probe again */ + else { + int old_irq; + + switch (socket->dev->device) { + case PCI_DEVICE_ID_TI_1250: + /* the 1250 has one pin for IRQSER/INTB depending on devctl */ + break; + + case PCI_DEVICE_ID_TI_1251A: + case PCI_DEVICE_ID_TI_1251B: + case PCI_DEVICE_ID_TI_1450: + /* + * those have a pin for IRQSER/INTB plus INTB in MFUNC0 + * we alread probed the shared pin, now go for MFUNC0 + */ + mfunc = (mfunc & ~TI122X_MFUNC0_MASK) | TI125X_MFUNC0_INTB; + break; + + default: + mfunc = (mfunc & ~TI122X_MFUNC1_MASK) | TI122X_MFUNC1_INTB; + break; + } + + /* write, probe */ + if (mfunc != mfunc_old) { + config_writel(socket, TI122X_MFUNC, mfunc); + + pci_irq_status = yenta_probe_cb_irq(socket); + if (pci_irq_status == 1) { + printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts ok\n", + pci_name(socket->dev)); + goto out; + } + + mfunc = mfunc_old; + config_writel(socket, TI122X_MFUNC, mfunc); + + if (pci_irq_status == -1) + goto out; + } + + /* still nothing: set INTRTIE */ + if (ti12xx_tie_interrupts(socket, &old_irq)) { + pci_irq_status = yenta_probe_cb_irq(socket); + if (pci_irq_status == 1) { + printk(KERN_INFO "Yenta TI: socket %s parallel PCI interrupts, tied ok\n", + pci_name(socket->dev)); + goto out; + } + + ti12xx_untie_interrupts(socket, old_irq); + } + } + +out: + if (pci_irq_status < 1) { + socket->cb_irq = 0; + printk(KERN_INFO "Yenta TI: socket %s no PCI interrupts. Fish. Please report.\n", + pci_name(socket->dev)); + } +} + static int ti12xx_override(struct yenta_socket *socket) { u32 val; @@ -347,6 +601,12 @@ static int ti12xx_override(struct yenta_socket *socket) printk(KERN_INFO "Yenta: Routing CardBus interrupts to %s\n", (val & TI1250_DIAG_PCI_IREQ) ? "PCI" : "ISA"); + /* do irqrouting, depending on function */ + if (PCI_FUNC(socket->dev->devfn) == 0) + ti12xx_irqroute_func0(socket); + else + ti12xx_irqroute_func1(socket); + return ti_override(socket); } @@ -366,26 +626,6 @@ static int ti1250_override(struct yenta_socket *socket) config_writeb(socket, TI1250_DIAGNOSTIC, diag); } -#if 0 - /* - * This is highly machine specific, and we should NOT touch - * this register - we have no knowledge how the hardware - * is actually wired. - * - * If we're going to do this, we should probably look into - * using the subsystem IDs. - * - * On ThinkPad 380XD, this changes MFUNC0 from the ISA IRQ3 - * output (which it is) to IRQ2. We also change MFUNC1 - * from ISA IRQ4 to IRQ6. - */ - irqmux = config_readl(socket, TI122X_IRQMUX); - irqmux = (irqmux & ~0x0f) | 0x02; /* route INTA */ - if (!(ti_sysctl(socket) & TI122X_SCR_INTRTIE)) - irqmux = (irqmux & ~0xf0) | 0x20; /* route INTB */ - config_writel(socket, TI122X_IRQMUX, irqmux); -#endif - return ti12xx_override(socket); } diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index da1221cd3950..b0d716ef07f4 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -39,6 +39,9 @@ #define to_cycles(ns) ((ns)/120) #define to_ns(cycles) ((cycles)*120) +static int yenta_probe_cb_irq(struct yenta_socket *socket); + + /* * Generate easy-to-use ways of reading a cardbus sockets * regular memory space ("cb_xxx"), configuration space @@ -768,6 +771,69 @@ static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mas return mask; } + +/* interrupt handler, only used during probing */ +static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct yenta_socket *socket = (struct yenta_socket *) dev_id; + u8 csc; + u32 cb_event; + + /* Clear interrupt status for the event */ + cb_event = cb_readl(socket, CB_SOCKET_EVENT); + cb_writel(socket, CB_SOCKET_EVENT, -1); + csc = exca_readb(socket, I365_CSC); + + if (cb_event || csc) { + socket->probe_status = 1; + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +/* probes the PCI interrupt, use only on override functions */ +static int yenta_probe_cb_irq(struct yenta_socket *socket) +{ + u16 bridge_ctrl; + + if (!socket->cb_irq) + return -1; + + socket->probe_status = 0; + + /* disable ISA interrupts */ + bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); + bridge_ctrl &= ~CB_BRIDGE_INTR; + config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); + + if (request_irq(socket->cb_irq, yenta_probe_handler, SA_SHIRQ, "yenta", socket)) { + printk(KERN_WARNING "Yenta: request_irq() in yenta_probe_cb_irq() failed!\n"); + return -1; + } + + /* generate interrupt, wait */ + exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG); + cb_writel(socket, CB_SOCKET_EVENT, -1); + cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); + cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/10); + + /* disable interrupts */ + cb_writel(socket, CB_SOCKET_MASK, 0); + exca_writeb(socket, I365_CSCINT, 0); + cb_writel(socket, CB_SOCKET_EVENT, -1); + exca_readb(socket, I365_CSC); + + free_irq(socket->cb_irq, socket); + + return (int) socket->probe_status; +} + + + /* * Set static data that doesn't need re-initializing.. */ @@ -997,7 +1063,6 @@ static struct pci_device_id yenta_table [] = { * data sheets for these devices. --rmk) */ CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210, TI), - CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B, TI), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130, TI113X), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131, TI113X), @@ -1007,11 +1072,14 @@ static struct pci_device_id yenta_table [] = { CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1451A, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1510, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4410, TI12XX), -// CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4450, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_4451, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250), diff --git a/drivers/pcmcia/yenta_socket.h b/drivers/pcmcia/yenta_socket.h index 13ff0f20a8ec..7c3bfbfaa28a 100644 --- a/drivers/pcmcia/yenta_socket.h +++ b/drivers/pcmcia/yenta_socket.h @@ -113,6 +113,9 @@ struct yenta_socket { struct pcmcia_socket socket; struct cardbus_type *type; + /* for PCI interrupt probing */ + unsigned int probe_status; + /* A few words of private data for special stuff of overrides... */ unsigned int private[8]; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c48f2b65d081..d2a38233a6c7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -708,6 +708,7 @@ #define PCI_VENDOR_ID_TI 0x104c #define PCI_DEVICE_ID_TI_TVP4010 0x3d04 #define PCI_DEVICE_ID_TI_TVP4020 0x3d07 +#define PCI_DEVICE_ID_TI_4450 0x8011 #define PCI_DEVICE_ID_TI_1130 0xac12 #define PCI_DEVICE_ID_TI_1031 0xac13 #define PCI_DEVICE_ID_TI_1131 0xac15 @@ -724,6 +725,7 @@ #define PCI_DEVICE_ID_TI_4451 0xac42 #define PCI_DEVICE_ID_TI_1410 0xac50 #define PCI_DEVICE_ID_TI_1420 0xac51 +#define PCI_DEVICE_ID_TI_1451A 0xac52 #define PCI_DEVICE_ID_TI_1520 0xac55 #define PCI_DEVICE_ID_TI_1510 0xac56 -- cgit v1.2.3 From e86f59c38f2b1ac0bdd12e59ca563232b43b4309 Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Wed, 14 Apr 2004 20:39:05 +0100 Subject: [ARM PATCH] 1810/1: Support for non-PXA XScale UARTs Patch from Deepak Saxena Supersedes 1809/1 --- drivers/serial/8250.c | 11 +++++++++-- include/linux/serial_core.h | 3 ++- include/linux/serial_reg.h | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 75e1e4a9648b..589a4134af8a 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -170,7 +170,8 @@ static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = { { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "NS16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI } + { "NS16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI }, + { "XScale", 32, UART_CLEAR_FIFO | UART_USE_FIFO }, }; static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) @@ -1512,6 +1513,8 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, up->ier &= ~UART_IER_MSI; if (UART_ENABLE_MS(&up->port, termios->c_cflag)) up->ier |= UART_IER_MSI; + if (up->port.type == PORT_XSCALE) + up->ier |= UART_IER_UUE | UART_IER_RTOIE; serial_out(up, UART_IER, up->ier); @@ -1953,7 +1956,11 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) * First save the UER then disable the interrupts */ ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); + + if (up->port.type == PORT_XSCALE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); /* * Now, do each character diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 701d138cefb8..4d7dd853874b 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -36,7 +36,8 @@ #define PORT_16850 12 #define PORT_RSA 13 #define PORT_NS16550A 14 -#define PORT_MAX_8250 14 /* max port ID */ +#define PORT_XSCALE 15 +#define PORT_MAX_8250 15 /* max port ID */ /* * ARM specific type numbers. These are not currently guaranteed diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h index 49aa0db7fa0e..7b2414bd5837 100644 --- a/include/linux/serial_reg.h +++ b/include/linux/serial_reg.h @@ -142,7 +142,7 @@ #define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ /* - * The Intel PXA2xx chip defines those bits + * The Intel XScale on-chip UARTs define these bits */ #define UART_IER_DMAE 0x80 /* DMA Requests Enable */ #define UART_IER_UUE 0x40 /* UART Unit Enable */ -- cgit v1.2.3