Commit bcf9dcf9 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleeding_edge-2.5

into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents c2dd03a9 564dd8f4
...@@ -6,6 +6,8 @@ obj-y := core.o sys.o interface.o power.o bus.o \ ...@@ -6,6 +6,8 @@ obj-y := core.o sys.o interface.o power.o bus.o \
obj-y += fs/ obj-y += fs/
obj-$(CONFIG_HOTPLUG) += hotplug.o
export-objs := core.o power.o sys.o bus.o driver.o \ export-objs := core.o power.o sys.o bus.o driver.o \
class.o intf.o platform.o cpu.o class.o intf.o platform.o cpu.o
......
...@@ -50,3 +50,13 @@ extern void interface_remove(struct device_class *, struct device *); ...@@ -50,3 +50,13 @@ extern void interface_remove(struct device_class *, struct device *);
extern int driver_attach(struct device_driver * drv); extern int driver_attach(struct device_driver * drv);
extern void driver_detach(struct device_driver * drv); extern void driver_detach(struct device_driver * drv);
#ifdef CONFIG_HOTPLUG
extern int dev_hotplug(struct device *dev, const char *action);
#else
static inline int dev_hotplug(struct device *dev, const char *action)
{
return 0;
}
#endif
...@@ -200,6 +200,9 @@ int device_register(struct device *dev) ...@@ -200,6 +200,9 @@ int device_register(struct device *dev)
if (platform_notify) if (platform_notify)
platform_notify(dev); platform_notify(dev);
/* notify userspace of device entry */
dev_hotplug(dev, "add");
register_done: register_done:
if (error) { if (error) {
spin_lock(&device_lock); spin_lock(&device_lock);
...@@ -255,6 +258,9 @@ void put_device(struct device * dev) ...@@ -255,6 +258,9 @@ void put_device(struct device * dev)
if (platform_notify_remove) if (platform_notify_remove)
platform_notify_remove(dev); platform_notify_remove(dev);
/* notify userspace that this device is about to disappear */
dev_hotplug (dev, "remove");
device_detach(dev); device_detach(dev);
bus_remove_device(dev); bus_remove_device(dev);
......
/*
* drivers/base/hotplug.c - hotplug call code
*
* Copyright (c) 2000-2001 David Brownell
* Copyright (c) 2002 Greg Kroah-Hartman
* Copyright (c) 2002 IBM Corp.
*
* Based off of drivers/usb/core/usb.c:call_agent(), which was
* written by David Brownell.
*
*/
#define DEBUG 0
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/kmod.h>
#include <linux/interrupt.h>
#include "base.h"
/*
* hotplugging invokes what /proc/sys/kernel/hotplug says (normally
* /sbin/hotplug) when devices get added or removed.
*
* This invokes a user mode policy agent, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*/
#define BUFFER_SIZE 1024 /* should be enough memory for the env */
#define NUM_ENVP 32 /* number of env pointers */
int dev_hotplug (struct device *dev, const char *action)
{
char *argv [3], **envp, *buffer, *scratch;
int retval;
int i = 0;
pr_debug ("%s\n", __FUNCTION__);
if (!dev)
return -ENODEV;
if (!dev->bus || !dev->bus->hotplug)
return -ENODEV;
if (!hotplug_path [0])
return -ENODEV;
if (in_interrupt ()) {
pr_debug ("%s - in_interrupt, not allowed!", __FUNCTION__);
return -EIO;
}
if (!current->fs->root) {
/* don't try to do anything unless we have a root partition */
pr_debug ("%s - %s -- no FS yet\n", __FUNCTION__, action);
return -EIO;
}
envp = (char **) kmalloc (NUM_ENVP * sizeof (char *), GFP_KERNEL);
if (!envp)
return -ENOMEM;
buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
if (!buffer) {
kfree (envp);
return -ENOMEM;
}
/* only one standardized param to hotplug command: the bus name */
argv [0] = hotplug_path;
argv [1] = dev->bus->name;
argv [2] = 0;
/* minimal command environment */
envp [i++] = "HOME=/";
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
scratch = buffer;
/* action: add, remove */
envp [i++] = scratch;
scratch += sprintf (scratch, "ACTION=%s", action) + 1;
/* have the bus specific function set up the rest of the environment */
retval = dev->bus->hotplug (dev, &envp[i], NUM_ENVP - i,
scratch, BUFFER_SIZE - (scratch - buffer));
if (retval) {
pr_debug ("%s - hotplug() returned %d\n", __FUNCTION__, retval);
goto exit;
}
pr_debug ("%s: %s %s %s %s %s %s\n", __FUNCTION__, argv [0], argv[1],
action, envp[0], envp[1], envp[2]);
retval = call_usermodehelper (argv [0], argv, envp);
if (retval)
pr_debug ("%s - call_usermodehelper returned %d\n",
__FUNCTION__, retval);
exit:
kfree (buffer);
kfree (envp);
return retval;
}
...@@ -36,14 +36,11 @@ ...@@ -36,14 +36,11 @@
* This driver has been tested SUCCESSFULLY with the following drivers : * This driver has been tested SUCCESSFULLY with the following drivers :
* o usb-uhci-hcd (For Intel/Via USB controllers) * o usb-uhci-hcd (For Intel/Via USB controllers)
* o uhci-hcd (Alternate/JE driver for Intel/Via USB controllers) * o uhci-hcd (Alternate/JE driver for Intel/Via USB controllers)
* o ohci-hcd (For other USB controllers)
* *
* This driver has NOT been tested with the following drivers : * This driver has NOT been tested with the following drivers :
* o ehci-hcd (USB 2.0 controllers) * o ehci-hcd (USB 2.0 controllers)
* *
* This driver DOESN'T SEEM TO WORK with the following drivers :
* o ohci-hcd (For other USB controllers)
* The first outgoing URB never calls its completion/failure callback.
*
* Note that all HCD drivers do USB_ZERO_PACKET and timeout properly, * Note that all HCD drivers do USB_ZERO_PACKET and timeout properly,
* so we don't have to worry about that anymore. * so we don't have to worry about that anymore.
* One common problem is the failure to set the address on the dongle, * One common problem is the failure to set the address on the dongle,
...@@ -104,8 +101,8 @@ MODULE_DEVICE_TABLE(usb, dongles); ...@@ -104,8 +101,8 @@ MODULE_DEVICE_TABLE(usb, dongles);
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum); static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf);
static void irda_usb_disconnect(struct usb_device *dev, void *ptr); static void irda_usb_disconnect(struct usb_interface *intf);
static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev); static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
static int irda_usb_open(struct irda_usb_cb *self); static int irda_usb_open(struct irda_usb_cb *self);
...@@ -1340,7 +1337,7 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) ...@@ -1340,7 +1337,7 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Function irda_usb_find_class_desc(dev, ifnum) * Function irda_usb_find_class_desc(intf)
* *
* Returns instance of IrDA class descriptor, or NULL if not found * Returns instance of IrDA class descriptor, or NULL if not found
* *
...@@ -1348,8 +1345,9 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) ...@@ -1348,8 +1345,9 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
* offer to us, describing their IrDA characteristics. We will use that in * offer to us, describing their IrDA characteristics. We will use that in
* irda_usb_init_qos() * irda_usb_init_qos()
*/ */
static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf)
{ {
struct usb_device *dev = interface_to_usbdev (intf);
struct irda_class_desc *desc; struct irda_class_desc *desc;
int ret; int ret;
...@@ -1368,7 +1366,8 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device ...@@ -1368,7 +1366,8 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
IU_REQ_GET_CLASS_DESC, IU_REQ_GET_CLASS_DESC,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500)); 0, intf->altsetting->bInterfaceNumber, desc,
sizeof(*desc), MSECS_TO_JIFFIES(500));
IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret); IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret);
if (ret < sizeof(*desc)) { if (ret < sizeof(*desc)) {
...@@ -1403,9 +1402,10 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device ...@@ -1403,9 +1402,10 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device
* Note : it might be worth protecting this function by a global * Note : it might be worth protecting this function by a global
* spinlock... Or not, because maybe USB already deal with that... * spinlock... Or not, because maybe USB already deal with that...
*/ */
static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, static int irda_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
struct usb_device *dev = interface_to_usbdev(intf);
struct irda_usb_cb *self = NULL; struct irda_usb_cb *self = NULL;
struct usb_interface_descriptor *interface; struct usb_interface_descriptor *interface;
struct irda_class_desc *irda_desc; struct irda_class_desc *irda_desc;
...@@ -1430,7 +1430,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1430,7 +1430,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
(irda->present == 0) && (irda->present == 0) &&
(irda->netopen == 0)) { (irda->netopen == 0)) {
IRDA_DEBUG(0, "%s(), found a zombie instance !!!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), found a zombie instance !!!\n", __FUNCTION__);
irda_usb_disconnect(irda->usbdev, (void *) irda); irda_usb_disconnect(irda->usbintf);
} }
} }
...@@ -1445,7 +1445,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1445,7 +1445,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
if(self == NULL) { if(self == NULL) {
WARNING("Too many USB IrDA devices !!! (max = %d)\n", WARNING("Too many USB IrDA devices !!! (max = %d)\n",
NIRUSB); NIRUSB);
return NULL; return -ENFILE;
} }
/* Reset the instance */ /* Reset the instance */
...@@ -1459,35 +1459,35 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1459,35 +1459,35 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
int j; int j;
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
usb_free_urb(self->rx_urb[j]); usb_free_urb(self->rx_urb[j]);
return NULL; return -ENOMEM;
} }
} }
self->tx_urb = usb_alloc_urb(0, GFP_KERNEL); self->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!self->tx_urb) { if (!self->tx_urb) {
for (i = 0; i < IU_MAX_RX_URBS; i++) for (i = 0; i < IU_MAX_RX_URBS; i++)
usb_free_urb(self->rx_urb[i]); usb_free_urb(self->rx_urb[i]);
return NULL; return -ENOMEM;
} }
self->speed_urb = usb_alloc_urb(0, GFP_KERNEL); self->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!self->speed_urb) { if (!self->speed_urb) {
for (i = 0; i < IU_MAX_RX_URBS; i++) for (i = 0; i < IU_MAX_RX_URBS; i++)
usb_free_urb(self->rx_urb[i]); usb_free_urb(self->rx_urb[i]);
usb_free_urb(self->tx_urb); usb_free_urb(self->tx_urb);
return NULL; return -ENOMEM;
} }
/* Is this really necessary? */ /* Is this really necessary? */
if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) { if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
err("set_configuration failed"); err("set_configuration failed");
return NULL; return -EIO;
} }
/* Is this really necessary? */ /* Is this really necessary? */
/* Note : some driver do hardcode the interface number, some others /* Note : some driver do hardcode the interface number, some others
* specify an alternate, but very few driver do like this. * specify an alternate, but very few driver do like this.
* Jean II */ * Jean II */
ret = usb_set_interface(dev, ifnum, 0); ret = usb_set_interface(dev, intf->altsetting->bInterfaceNumber, 0);
IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", ifnum, ret); IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", intf->altsetting->bInterfaceNumber, ret);
switch (ret) { switch (ret) {
case 0: case 0:
break; break;
...@@ -1497,33 +1497,35 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1497,33 +1497,35 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
break; break;
default: default:
IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret); IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret);
return NULL; return -EIO;
break; break;
} }
/* Find our endpoints */ /* Find our endpoints */
interface = &dev->actconfig->interface[ifnum].altsetting[0]; interface = &intf->altsetting[0];
if(!irda_usb_parse_endpoints(self, interface->endpoint, if(!irda_usb_parse_endpoints(self, interface->endpoint,
interface->bNumEndpoints)) { interface->bNumEndpoints)) {
ERROR("%s(), Bogus endpoints...\n", __FUNCTION__); ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
return NULL; return -EIO;
} }
/* Find IrDA class descriptor */ /* Find IrDA class descriptor */
irda_desc = irda_usb_find_class_desc(dev, ifnum); irda_desc = irda_usb_find_class_desc(intf);
if (irda_desc == NULL) if (irda_desc == NULL)
return NULL; return -ENODEV;
self->irda_desc = irda_desc; self->irda_desc = irda_desc;
self->present = 1; self->present = 1;
self->netopen = 0; self->netopen = 0;
self->capability = id->driver_info; self->capability = id->driver_info;
self->usbdev = dev; self->usbdev = dev;
self->usbintf = intf;
ret = irda_usb_open(self); ret = irda_usb_open(self);
if (ret) if (ret)
return NULL; return -ENOMEM;
return self; dev_set_drvdata(&intf->dev, self);
return 0;
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
...@@ -1538,14 +1540,18 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1538,14 +1540,18 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
* So, we must make bloody sure that everything gets deactivated. * So, we must make bloody sure that everything gets deactivated.
* Jean II * Jean II
*/ */
static void irda_usb_disconnect(struct usb_device *dev, void *ptr) static void irda_usb_disconnect(struct usb_interface *intf)
{ {
unsigned long flags; unsigned long flags;
struct irda_usb_cb *self = (struct irda_usb_cb *) ptr; struct irda_usb_cb *self = dev_get_drvdata (&intf->dev);
int i; int i;
IRDA_DEBUG(1, "%s()\n", __FUNCTION__); IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
dev_set_drvdata(&intf->dev, NULL);
if (!self)
return;
/* Make sure that the Tx path is not executing. - Jean II */ /* Make sure that the Tx path is not executing. - Jean II */
spin_lock_irqsave(&self->lock, flags); spin_lock_irqsave(&self->lock, flags);
...@@ -1577,6 +1583,7 @@ static void irda_usb_disconnect(struct usb_device *dev, void *ptr) ...@@ -1577,6 +1583,7 @@ static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
irda_usb_close(self); irda_usb_close(self);
/* No longer attached to USB bus */ /* No longer attached to USB bus */
self->usbdev = NULL; self->usbdev = NULL;
self->usbintf = NULL;
/* Clean up our urbs */ /* Clean up our urbs */
for (i = 0; i < IU_MAX_RX_URBS; i++) for (i = 0; i < IU_MAX_RX_URBS; i++)
...@@ -1635,7 +1642,7 @@ void __exit usb_irda_cleanup(void) ...@@ -1635,7 +1642,7 @@ void __exit usb_irda_cleanup(void)
/* If the Device is zombie */ /* If the Device is zombie */
if((irda->usbdev != NULL) && (irda->present == 0)) { if((irda->usbdev != NULL) && (irda->present == 0)) {
IRDA_DEBUG(0, "%s(), disconnect zombie now !\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), disconnect zombie now !\n", __FUNCTION__);
irda_usb_disconnect(irda->usbdev, (void *) irda); irda_usb_disconnect(irda->usbintf);
} }
} }
......
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kmod.h> /* for hotplug_path */ #include "pci.h"
#ifndef FALSE
#define FALSE (0)
#define TRUE (!FALSE)
#endif
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
static void run_sbin_hotplug(struct pci_dev *pdev, int insert) int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{ {
int i; struct pci_dev *pdev;
char *argv[3], *envp[8]; char *scratch;
char id[20], sub_id[24], bus_id[24], class_id[20]; int i = 0;
int length = 0;
if (!hotplug_path[0])
return; if (!dev)
return -ENODEV;
sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device); pdev = to_pci_dev(dev);
sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device); if (!pdev)
sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name); return -ENODEV;
i = 0; scratch = buffer;
argv[i++] = hotplug_path;
argv[i++] = "pci"; /* stuff we want to pass to /sbin/hotplug */
argv[i] = 0; envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
i = 0; pdev->class);
/* minimal command environment */ if ((buffer_size - length <= 0) || (i >= num_envp))
envp[i++] = "HOME=/"; return -ENOMEM;
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++length;
scratch += length;
/* other stuff we want to pass to /sbin/hotplug */
envp[i++] = class_id; envp[i++] = scratch;
envp[i++] = id; length += snprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
envp[i++] = sub_id; pdev->vendor, pdev->device);
envp[i++] = bus_id; if ((buffer_size - length <= 0) || (i >= num_envp))
if (insert) return -ENOMEM;
envp[i++] = "ACTION=add"; ++length;
else scratch += length;
envp[i++] = "ACTION=remove";
envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
pdev->subsystem_device);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
pdev->slot_name);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
envp[i] = 0; envp[i] = 0;
call_usermodehelper (argv [0], argv, envp); return 0;
} }
#else #else
static void run_sbin_hotplug(struct pci_dev *pdev, int insert) { } int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
return -ENODEV;
}
#endif #endif
/** /**
...@@ -66,8 +82,6 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus) ...@@ -66,8 +82,6 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
pci_proc_attach_device(dev); pci_proc_attach_device(dev);
#endif #endif
/* notify userspace of new hotplug device */
run_sbin_hotplug(dev, TRUE);
} }
static void static void
...@@ -99,8 +113,6 @@ pci_remove_device(struct pci_dev *dev) ...@@ -99,8 +113,6 @@ pci_remove_device(struct pci_dev *dev)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
pci_proc_detach_device(dev); pci_proc_detach_device(dev);
#endif #endif
/* notify userspace of hotplug device removal */
run_sbin_hotplug(dev, FALSE);
} }
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include "pci.h"
/* /*
* Registration of PCI drivers and handling of hot-pluggable devices. * Registration of PCI drivers and handling of hot-pluggable devices.
...@@ -201,6 +202,7 @@ static int pci_bus_match(struct device * dev, struct device_driver * drv) ...@@ -201,6 +202,7 @@ static int pci_bus_match(struct device * dev, struct device_driver * drv)
struct bus_type pci_bus_type = { struct bus_type pci_bus_type = {
name: "pci", name: "pci",
match: pci_bus_match, match: pci_bus_match,
hotplug: pci_hotplug,
}; };
static int __init pci_driver_init(void) static int __init pci_driver_init(void)
......
/* Functions internal to the PCI core code */
extern int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size);
...@@ -510,57 +510,42 @@ static int usb_device_match (struct device *dev, struct device_driver *drv) ...@@ -510,57 +510,42 @@ static int usb_device_match (struct device *dev, struct device_driver *drv)
* cases, we know no other thread can recycle our address, since we must * cases, we know no other thread can recycle our address, since we must
* already have been serialized enough to prevent that. * already have been serialized enough to prevent that.
*/ */
static void call_policy (char *verb, struct usb_device *dev) static int usb_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{ {
char *argv [3], **envp, *buf, *scratch; struct usb_interface *intf;
int i = 0, value; struct usb_device *usb_dev;
char *scratch;
int i = 0;
int length = 0;
if (!hotplug_path [0]) dbg ("%s", __FUNCTION__);
return;
if (in_interrupt ()) {
dbg ("In_interrupt");
return;
}
if (!current->fs->root) {
/* statically linked USB is initted rather early */
dbg ("call_policy %s, num %d -- no FS yet", verb, dev->devnum);
return;
}
if (dev->devnum < 0) {
dbg ("device already deleted ??");
return;
}
if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
dbg ("enomem");
return;
}
if (!(buf = kmalloc (256, GFP_KERNEL))) {
kfree (envp);
dbg ("enomem2");
return;
}
/* only one standardized param to hotplug command: type */ if (!dev)
argv [0] = hotplug_path; return -ENODEV;
argv [1] = "usb";
argv [2] = 0;
/* minimal command environment */ /* check for generic driver, we do not call do hotplug calls for it */
envp [i++] = "HOME=/"; if (dev->driver == &usb_generic_driver)
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; return -ENODEV;
#ifdef DEBUG intf = to_usb_interface(dev);
/* hint that policy agent should enter no-stdout debug mode */ if (!intf)
envp [i++] = "DEBUG=kernel"; return -ENODEV;
#endif
/* extensible set of named bus-specific parameters,
* supporting multiple driver selection algorithms.
*/
scratch = buf;
/* action: add, remove */ usb_dev = interface_to_usbdev (intf);
envp [i++] = scratch; if (!usb_dev)
scratch += sprintf (scratch, "ACTION=%s", verb) + 1; return -ENODEV;
if (usb_dev->devnum < 0) {
dbg ("device already deleted ??");
return -ENODEV;
}
if (!usb_dev->bus) {
dbg ("bus already removed?");
return -ENODEV;
}
scratch = buffer;
#ifdef CONFIG_USB_DEVICEFS #ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read /* If this is available, userspace programs can directly read
...@@ -569,27 +554,48 @@ static void call_policy (char *verb, struct usb_device *dev) ...@@ -569,27 +554,48 @@ static void call_policy (char *verb, struct usb_device *dev)
* *
* FIXME reduce hardwired intelligence here * FIXME reduce hardwired intelligence here
*/ */
envp [i++] = "DEVFS=/proc/bus/usb";
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "DEVICE=/proc/bus/usb/%03d/%03d", length += snprintf (scratch, buffer_size - length,
dev->bus->busnum, dev->devnum) + 1; "%s", "DEVFS=/proc/bus/usb");
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
#endif #endif
/* per-device configuration hacks are common */ /* per-device configuration hacks are common */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "PRODUCT=%x/%x/%x", length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
dev->descriptor.idVendor, usb_dev->descriptor.idVendor,
dev->descriptor.idProduct, usb_dev->descriptor.idProduct,
dev->descriptor.bcdDevice) + 1; usb_dev->descriptor.bcdDevice);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
/* class-based driver binding models */ /* class-based driver binding models */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "TYPE=%d/%d/%d", length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceClass,
dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceSubClass,
dev->descriptor.bDeviceProtocol) + 1; usb_dev->descriptor.bDeviceProtocol);
if (dev->descriptor.bDeviceClass == 0) { if ((buffer_size - length <= 0) || (i >= num_envp))
int alt = dev->actconfig->interface [0].act_altsetting; return -ENOMEM;
++length;
scratch += length;
if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting;
/* a simple/common case: one config, one interface, one driver /* a simple/common case: one config, one interface, one driver
* with current altsetting being a reasonable setting. * with current altsetting being a reasonable setting.
...@@ -597,31 +603,29 @@ static void call_policy (char *verb, struct usb_device *dev) ...@@ -597,31 +603,29 @@ static void call_policy (char *verb, struct usb_device *dev)
* device-specific binding policies. * device-specific binding policies.
*/ */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "INTERFACE=%d/%d/%d", length += snprintf (scratch, buffer_size - length,
dev->actconfig->interface [0].altsetting [alt].bInterfaceClass, "INTERFACE=%d/%d/%d",
dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass, intf->altsetting[alt].bInterfaceClass,
dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol) intf->altsetting[alt].bInterfaceSubClass,
+ 1; intf->altsetting[alt].bInterfaceProtocol);
/* INTERFACE-0, INTERFACE-1, ... ? */ if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
} }
envp [i++] = 0; envp [i++] = 0;
/* assert: (scratch - buf) < sizeof buf */
/* NOTE: user mode daemons can call the agents too */ return 0;
dbg ("kusbd: %s %s %d", argv [0], verb, dev->devnum);
value = call_usermodehelper (argv [0], argv, envp);
kfree (buf);
kfree (envp);
if (value != 0)
dbg ("kusbd policy returned 0x%x", value);
} }
#else #else
static inline void static int usb_hotplug (struct device *dev, char **envp,
call_policy (char *verb, struct usb_device *dev) char *buffer, int buffer_size)
{ } {
return -ENODEV;
}
#endif /* CONFIG_HOTPLUG */ #endif /* CONFIG_HOTPLUG */
...@@ -894,9 +898,6 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -894,9 +898,6 @@ void usb_disconnect(struct usb_device **pdev)
put_device(&dev->dev); put_device(&dev->dev);
} }
/* Let policy agent unload modules etc */
call_policy ("remove", dev);
/* Decrement the reference count, it'll auto free everything when */ /* Decrement the reference count, it'll auto free everything when */
/* it hits 0 which could very well be now */ /* it hits 0 which could very well be now */
usb_put_dev(dev); usb_put_dev(dev);
...@@ -1174,9 +1175,6 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1174,9 +1175,6 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
/* add a /proc/bus/usb entry */ /* add a /proc/bus/usb entry */
usbfs_add_device(dev); usbfs_add_device(dev);
/* userspace may load modules and/or configure further */
call_policy ("add", dev);
return 0; return 0;
} }
...@@ -1439,6 +1437,7 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, ...@@ -1439,6 +1437,7 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
struct bus_type usb_bus_type = { struct bus_type usb_bus_type = {
.name = "usb", .name = "usb",
.match = usb_device_match, .match = usb_device_match,
.hotplug = usb_hotplug,
}; };
/* /*
......
...@@ -788,7 +788,7 @@ int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -788,7 +788,7 @@ int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us)
/* only check card status if the map isn't allocated, ie no card seen yet /* only check card status if the map isn't allocated, ie no card seen yet
* or if it's been over half a second since we last accessed it * or if it's been over half a second since we last accessed it
*/ */
if (info->lba_to_pba == NULL || jiffies > (info->last_access + HZ/2)) { if (info->lba_to_pba == NULL || time_after(jiffies, info->last_access + HZ/2)) {
/* check to see if a card is fitted */ /* check to see if a card is fitted */
result = sddr55_status (us); result = sddr55_status (us);
......
...@@ -859,6 +859,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -859,6 +859,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
* This must be called with scsi_lock(us->srb->host) held */ * This must be called with scsi_lock(us->srb->host) held */
void usb_stor_abort_transport(struct us_data *us) void usb_stor_abort_transport(struct us_data *us)
{ {
struct Scsi_Host *host;
int state = atomic_read(&us->sm_state); int state = atomic_read(&us->sm_state);
US_DEBUGP("usb_stor_abort_transport called\n"); US_DEBUGP("usb_stor_abort_transport called\n");
...@@ -870,7 +871,8 @@ void usb_stor_abort_transport(struct us_data *us) ...@@ -870,7 +871,8 @@ void usb_stor_abort_transport(struct us_data *us)
/* set state to abort and release the lock */ /* set state to abort and release the lock */
atomic_set(&us->sm_state, US_STATE_ABORTING); atomic_set(&us->sm_state, US_STATE_ABORTING);
scsi_unlock(us->srb->host); host = us->srb->host;
scsi_unlock(host);
/* If the state machine is blocked waiting for an URB or an IRQ, /* If the state machine is blocked waiting for an URB or an IRQ,
* let's wake it up */ * let's wake it up */
...@@ -892,8 +894,8 @@ void usb_stor_abort_transport(struct us_data *us) ...@@ -892,8 +894,8 @@ void usb_stor_abort_transport(struct us_data *us)
/* Wait for the aborted command to finish */ /* Wait for the aborted command to finish */
wait_for_completion(&us->notify); wait_for_completion(&us->notify);
/* Reacquire the lock */ /* Reacquire the lock: note that us->srb is now NULL */
scsi_lock(us->srb->host); scsi_lock(host);
} }
/* /*
......
...@@ -331,8 +331,10 @@ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, ...@@ -331,8 +331,10 @@ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff,
* Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly * Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly
* 36 bytes of data. No more, no less. That is the only reason this entry * 36 bytes of data. No more, no less. That is the only reason this entry
* is needed. * is needed.
*/ *
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, * ST818 slim drives (rev 0.02) don't need special care.
*/
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0x0001,
"EagleTec", "EagleTec",
"External Hard Disk", "External Hard Disk",
US_SC_SCSI, US_PR_BULK, NULL, US_SC_SCSI, US_PR_BULK, NULL,
...@@ -548,17 +550,22 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001, ...@@ -548,17 +550,22 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001,
US_SC_SCSI, US_PR_BULK, NULL, US_SC_SCSI, US_PR_BULK, NULL,
US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ),
/* Submitted by Brian Hall <brihall@bigfoot.com> /* Submitted by Brian Hall <brihall@pcisys.net>
* Needed for START_STOP flag */ * Needed for START_STOP flag */
UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100,
"JMTek", "JMTek",
"USBDrive", "USBDrive",
US_SC_SCSI, US_PR_BULK, NULL, US_SC_SCSI, US_PR_BULK, NULL,
US_FL_START_STOP ), US_FL_START_STOP ),
UNUSUAL_DEV( 0x0c76, 0x0005, 0x0100, 0x0100,
"JMTek",
"USBDrive",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_START_STOP ),
/* Reported by Dan Pilone <pilone@slac.com> /* Reported by Dan Pilone <pilone@slac.com>
* The device needs the flags only. * The device needs the flags only.
* Also reported by Brian Hall <brihall@bigfoot.com>, again for flags. * Also reported by Brian Hall <brihall@pcisys.net>, again for flags.
* I also suspect this device may have a broken serial number. * I also suspect this device may have a broken serial number.
*/ */
UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999,
......
/* /*
* USB Skeleton driver - 0.7 * USB Skeleton driver - 0.8
* *
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of * published by the Free Software Foundation, version 2.
* the License, or (at your option) any later version.
* *
* *
* This driver is to be used as a skeleton driver to be able to create a * This driver is to be used as a skeleton driver to be able to create a
...@@ -22,6 +21,8 @@ ...@@ -22,6 +21,8 @@
* *
* History: * History:
* *
* 2002_09_26 - 0.8 - changes due to USB core conversion to struct device
* driver.
* 2002_02_12 - 0.7 - zero out dev in probe function for devices that do * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do
* not have both a bulk in and bulk out endpoint. * not have both a bulk in and bulk out endpoint.
* Thanks to Holger Waechtler for the fix. * Thanks to Holger Waechtler for the fix.
...@@ -133,8 +134,8 @@ static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd ...@@ -133,8 +134,8 @@ static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd
static int skel_open (struct inode *inode, struct file *file); static int skel_open (struct inode *inode, struct file *file);
static int skel_release (struct inode *inode, struct file *file); static int skel_release (struct inode *inode, struct file *file);
static void * skel_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id); static int skel_probe (struct usb_interface *intf, const struct usb_device_id *id);
static void skel_disconnect (struct usb_device *dev, void *ptr); static void skel_disconnect (struct usb_interface *intf);
static void skel_write_bulk_callback (struct urb *urb); static void skel_write_bulk_callback (struct urb *urb);
...@@ -509,10 +510,10 @@ static void skel_write_bulk_callback (struct urb *urb) ...@@ -509,10 +510,10 @@ static void skel_write_bulk_callback (struct urb *urb)
* Called by the usb core when a new device is connected that it thinks * Called by the usb core when a new device is connected that it thinks
* this driver might be interested in. * this driver might be interested in.
*/ */
static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
{ {
struct usb_device *udev = interface_to_usbdev(interface);
struct usb_skel *dev = NULL; struct usb_skel *dev = NULL;
struct usb_interface *interface;
struct usb_interface_descriptor *iface_desc; struct usb_interface_descriptor *iface_desc;
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
int minor; int minor;
...@@ -525,7 +526,7 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru ...@@ -525,7 +526,7 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
/* See if the device offered us matches what we can accept */ /* See if the device offered us matches what we can accept */
if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) || if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) ||
(udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) { (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) {
return NULL; return -ENODEV;
} }
down (&minor_table_mutex); down (&minor_table_mutex);
...@@ -545,8 +546,6 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru ...@@ -545,8 +546,6 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
memset (dev, 0x00, sizeof (*dev)); memset (dev, 0x00, sizeof (*dev));
minor_table[minor] = dev; minor_table[minor] = dev;
interface = &udev->actconfig->interface[ifnum];
init_MUTEX (&dev->sem); init_MUTEX (&dev->sem);
dev->udev = udev; dev->udev = udev;
dev->interface = interface; dev->interface = interface;
...@@ -619,7 +618,11 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru ...@@ -619,7 +618,11 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
exit: exit:
up (&minor_table_mutex); up (&minor_table_mutex);
return dev; if (dev) {
dev_set_drvdata (&interface->dev, dev);
return 0;
}
return -ENODEV;
} }
...@@ -628,12 +631,16 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru ...@@ -628,12 +631,16 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
* *
* Called by the usb core when the device is removed from the system. * Called by the usb core when the device is removed from the system.
*/ */
static void skel_disconnect(struct usb_device *udev, void *ptr) static void skel_disconnect(struct usb_interface *interface)
{ {
struct usb_skel *dev; struct usb_skel *dev;
int minor; int minor;
dev = (struct usb_skel *)ptr; dev = dev_get_drvdata (&interface->dev);
dev_set_drvdata (&interface->dev, NULL);
if (!dev)
return;
down (&minor_table_mutex); down (&minor_table_mutex);
down (&dev->sem); down (&dev->sem);
......
...@@ -67,6 +67,8 @@ struct bus_type { ...@@ -67,6 +67,8 @@ struct bus_type {
int (*match)(struct device * dev, struct device_driver * drv); int (*match)(struct device * dev, struct device_driver * drv);
struct device * (*add) (struct device * parent, char * bus_id); struct device * (*add) (struct device * parent, char * bus_id);
int (*hotplug) (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
}; };
......
...@@ -127,7 +127,7 @@ struct irda_class_desc { ...@@ -127,7 +127,7 @@ struct irda_class_desc {
struct irda_usb_cb { struct irda_usb_cb {
struct irda_class_desc *irda_desc; struct irda_class_desc *irda_desc;
struct usb_device *usbdev; /* init: probe_irda */ struct usb_device *usbdev; /* init: probe_irda */
unsigned int ifnum; /* Interface number of the USB dev. */ struct usb_interface *usbintf; /* init: probe_irda */
int netopen; /* Device is active for network */ int netopen; /* Device is active for network */
int present; /* Device is present on the bus */ int present; /* Device is present on the bus */
__u32 capability; /* Capability of the hardware */ __u32 capability; /* Capability of the hardware */
......
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