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

Merge kroah.com:/home/greg/linux/BK/bleed-2.6

into kroah.com:/home/greg/linux/BK/driver-2.6
parents 32a8ed45 764dfe0b
...@@ -6,19 +6,20 @@ Definition ...@@ -6,19 +6,20 @@ Definition
struct bus_type { struct bus_type {
char * name; char * name;
rwlock_t lock;
atomic_t refcount;
struct list_head node; struct subsystem subsys;
struct list_head devices; struct kset drivers;
struct list_head drivers; struct kset devices;
struct driver_dir_entry dir; struct bus_attribute * bus_attrs;
struct driver_dir_entry device_dir; struct device_attribute * dev_attrs;
struct driver_dir_entry driver_dir; struct driver_attribute * drv_attrs;
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); int (*hotplug) (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
int (*suspend)(struct device * dev, u32 state);
int (*resume)(struct device * dev);
}; };
int bus_register(struct bus_type * bus); int bus_register(struct bus_type * bus);
...@@ -47,7 +48,7 @@ Registration ...@@ -47,7 +48,7 @@ Registration
When a bus driver is initialized, it calls bus_register. This When a bus driver is initialized, it calls bus_register. This
initializes the rest of the fields in the bus object and inserts it initializes the rest of the fields in the bus object and inserts it
into a global list of bus types. Once the bus object is registered, into a global list of bus types. Once the bus object is registered,
the fields in it (e.g. the rwlock_t) are usable by the bus driver. the fields in it are usable by the bus driver.
Callbacks Callbacks
...@@ -71,40 +72,6 @@ When a driver is registered with the bus, the bus's list of devices is ...@@ -71,40 +72,6 @@ When a driver is registered with the bus, the bus's list of devices is
iterated over, and the match callback is called for each device that iterated over, and the match callback is called for each device that
does not have a driver associated with it. does not have a driver associated with it.
add(): Adding a child device
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The add callback is available to notify the bus about a child device
at a particular location.
The parent parameter is the parent device of the child to be added. If
parent == NULL, the bus should add the device as a child of a default
parent device or as a child of the root. This policy decision is up to
the bus driver.
The format of the bus_id field should be consistent with the format of
the bus_id field of the rest of the devices on the bus. This requires
the caller to know the format.
On return, the bus driver should return a pointer to the device that
was created. If the device was not created, the bus driver should
return an appropriate error code. Refer to include/linux/err.h for
helper functions to encode errors. Some sample code:
struct device * pci_bus_add(struct device * parent, char * bus_id)
{
...
/* the device already exists */
return ERR_PTR(-EEXIST);
...
}
The caller can check the return value using IS_ERR():
struct device * newdev = pci_bus_type.add(parent,bus_id);
if (IS_ERR(newdev)) {
...
}
Device and Driver Lists Device and Driver Lists
...@@ -118,10 +85,11 @@ necessary. ...@@ -118,10 +85,11 @@ necessary.
The LDM core provides helper functions for iterating over each list. The LDM core provides helper functions for iterating over each list.
int bus_for_each_dev(struct bus_type * bus, void * data, int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
int (*callback)(struct device * dev, void * data)); int (*fn)(struct device *, void *));
int bus_for_each_drv(struct bus_type * bus, void * data,
int (*callback)(struct device_driver * drv, void * data)); int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
void * data, int (*fn)(struct device_driver *, void *));
These helpers iterate over the respective list, and call the callback These helpers iterate over the respective list, and call the callback
for each device or driver in the list. All list accesses are for each device or driver in the list. All list accesses are
...@@ -169,8 +137,8 @@ Exporting Attributes ...@@ -169,8 +137,8 @@ Exporting Attributes
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
struct bus_attribute { struct bus_attribute {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct bus_type *, char * buf, size_t count, loff_t off); ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off); ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
}; };
Bus drivers can export attributes using the BUS_ATTR macro that works Bus drivers can export attributes using the BUS_ATTR macro that works
......
...@@ -349,14 +349,19 @@ void class_device_initialize(struct class_device *class_dev) ...@@ -349,14 +349,19 @@ void class_device_initialize(struct class_device *class_dev)
int class_device_add(struct class_device *class_dev) int class_device_add(struct class_device *class_dev)
{ {
struct class * parent; struct class * parent = NULL;
struct class_interface * class_intf; struct class_interface * class_intf;
int error; int error;
class_dev = class_device_get(class_dev); class_dev = class_device_get(class_dev);
if (!class_dev || !strlen(class_dev->class_id)) if (!class_dev)
return -EINVAL; return -EINVAL;
if (!strlen(class_dev->class_id)) {
error = -EINVAL;
goto register_done;
}
parent = class_get(class_dev->class); parent = class_get(class_dev->class);
pr_debug("CLASS: registering class device: ID = '%s'\n", pr_debug("CLASS: registering class device: ID = '%s'\n",
......
...@@ -763,6 +763,17 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t ...@@ -763,6 +763,17 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t
return tty_write(file, buf, count, ppos); return tty_write(file, buf, count, ppos);
} }
static char ptychar[] = "pqrstuvwxyzabcde";
static inline void pty_line_name(struct tty_driver *driver, int index, char *p)
{
int i = index + driver->name_base;
/* ->name is initialized to "ttyp", but "tty" is expected */
sprintf(p, "%s%c%x",
driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
ptychar[i >> 4 & 0xf], i & 0xf);
}
static inline void tty_line_name(struct tty_driver *driver, int index, char *p) static inline void tty_line_name(struct tty_driver *driver, int index, char *p)
{ {
sprintf(p, "%s%d", driver->name, index + driver->name_base); sprintf(p, "%s%d", driver->name, index + driver->name_base);
...@@ -2175,6 +2186,7 @@ static struct class_simple *tty_class; ...@@ -2175,6 +2186,7 @@ static struct class_simple *tty_class;
void tty_register_device(struct tty_driver *driver, unsigned index, void tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device) struct device *device)
{ {
char name[64];
dev_t dev = MKDEV(driver->major, driver->minor_start) + index; dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
if (index >= driver->num) { if (index >= driver->num) {
...@@ -2186,13 +2198,11 @@ void tty_register_device(struct tty_driver *driver, unsigned index, ...@@ -2186,13 +2198,11 @@ void tty_register_device(struct tty_driver *driver, unsigned index,
devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
"%s%d", driver->devfs_name, index + driver->name_base); "%s%d", driver->devfs_name, index + driver->name_base);
/* we don't care about the ptys */ if (driver->type == TTY_DRIVER_TYPE_PTY)
/* how nice to hide this behind some crappy interface.. */ pty_line_name(driver, index, name);
if (driver->type != TTY_DRIVER_TYPE_PTY) { else
char name[64];
tty_line_name(driver, index, name); tty_line_name(driver, index, name);
class_simple_device_add(tty_class, dev, device, name); class_simple_device_add(tty_class, dev, device, name);
}
} }
/** /**
......
...@@ -182,16 +182,14 @@ static struct scsi_disk *scsi_disk_get(struct gendisk *disk) ...@@ -182,16 +182,14 @@ static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
if (disk->private_data == NULL) if (disk->private_data == NULL)
goto out; goto out;
sdkp = scsi_disk(disk); sdkp = scsi_disk(disk);
if (!kref_get(&sdkp->kref)) kref_get(&sdkp->kref);
goto out_sdkp;
if (scsi_device_get(sdkp->device)) if (scsi_device_get(sdkp->device))
goto out_put; goto out_put;
up(&sd_ref_sem); up(&sd_ref_sem);
return sdkp; return sdkp;
out_put: out_put:
kref_put(&sdkp->kref); kref_put(&sdkp->kref, scsi_disk_release);
out_sdkp:
sdkp = NULL; sdkp = NULL;
out: out:
up(&sd_ref_sem); up(&sd_ref_sem);
...@@ -202,7 +200,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp) ...@@ -202,7 +200,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
{ {
down(&sd_ref_sem); down(&sd_ref_sem);
scsi_device_put(sdkp->device); scsi_device_put(sdkp->device);
kref_put(&sdkp->kref); kref_put(&sdkp->kref, scsi_disk_release);
up(&sd_ref_sem); up(&sd_ref_sem);
} }
...@@ -1420,7 +1418,7 @@ static int sd_probe(struct device *dev) ...@@ -1420,7 +1418,7 @@ static int sd_probe(struct device *dev)
goto out; goto out;
memset (sdkp, 0, sizeof(*sdkp)); memset (sdkp, 0, sizeof(*sdkp));
kref_init(&sdkp->kref, scsi_disk_release); kref_init(&sdkp->kref);
/* Note: We can accomodate 64 partitions, but the genhd code /* Note: We can accomodate 64 partitions, but the genhd code
* assumes partitions allocate consecutive minors, which they don't. * assumes partitions allocate consecutive minors, which they don't.
...@@ -1522,7 +1520,7 @@ static int sd_remove(struct device *dev) ...@@ -1522,7 +1520,7 @@ static int sd_remove(struct device *dev)
del_gendisk(sdkp->disk); del_gendisk(sdkp->disk);
sd_shutdown(dev); sd_shutdown(dev);
down(&sd_ref_sem); down(&sd_ref_sem);
kref_put(&sdkp->kref); kref_put(&sdkp->kref, scsi_disk_release);
up(&sd_ref_sem); up(&sd_ref_sem);
return 0; return 0;
......
...@@ -140,15 +140,13 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk) ...@@ -140,15 +140,13 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk)
if (disk->private_data == NULL) if (disk->private_data == NULL)
goto out; goto out;
cd = scsi_cd(disk); cd = scsi_cd(disk);
if (!kref_get(&cd->kref)) kref_get(&cd->kref);
goto out_null;
if (scsi_device_get(cd->device)) if (scsi_device_get(cd->device))
goto out_put; goto out_put;
goto out; goto out;
out_put: out_put:
kref_put(&cd->kref); kref_put(&cd->kref, sr_kref_release);
out_null:
cd = NULL; cd = NULL;
out: out:
up(&sr_ref_sem); up(&sr_ref_sem);
...@@ -159,7 +157,7 @@ static inline void scsi_cd_put(struct scsi_cd *cd) ...@@ -159,7 +157,7 @@ static inline void scsi_cd_put(struct scsi_cd *cd)
{ {
down(&sr_ref_sem); down(&sr_ref_sem);
scsi_device_put(cd->device); scsi_device_put(cd->device);
kref_put(&cd->kref); kref_put(&cd->kref, sr_kref_release);
up(&sr_ref_sem); up(&sr_ref_sem);
} }
...@@ -576,7 +574,7 @@ static int sr_probe(struct device *dev) ...@@ -576,7 +574,7 @@ static int sr_probe(struct device *dev)
goto fail; goto fail;
memset(cd, 0, sizeof(*cd)); memset(cd, 0, sizeof(*cd));
kref_init(&cd->kref, sr_kref_release); kref_init(&cd->kref);
disk = alloc_disk(1); disk = alloc_disk(1);
if (!disk) if (!disk)
...@@ -937,7 +935,7 @@ static int sr_remove(struct device *dev) ...@@ -937,7 +935,7 @@ static int sr_remove(struct device *dev)
del_gendisk(cd->disk); del_gendisk(cd->disk);
down(&sr_ref_sem); down(&sr_ref_sem);
kref_put(&cd->kref); kref_put(&cd->kref, sr_kref_release);
up(&sr_ref_sem); up(&sr_ref_sem);
return 0; return 0;
......
...@@ -106,7 +106,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -106,7 +106,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
return buffer - buffer0 + i; return buffer - buffer0 + i;
} }
static void usb_release_interface_cache(struct kref *ref) void usb_release_interface_cache(struct kref *ref)
{ {
struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
int j; int j;
...@@ -356,7 +356,7 @@ int usb_parse_configuration(struct device *ddev, int cfgidx, ...@@ -356,7 +356,7 @@ int usb_parse_configuration(struct device *ddev, int cfgidx,
if (!intfc) if (!intfc)
return -ENOMEM; return -ENOMEM;
memset(intfc, 0, len); memset(intfc, 0, len);
kref_init(&intfc->ref, usb_release_interface_cache); kref_init(&intfc->ref);
} }
/* Skip over any Class Specific or Vendor Specific descriptors; /* Skip over any Class Specific or Vendor Specific descriptors;
...@@ -422,7 +422,8 @@ void usb_destroy_configuration(struct usb_device *dev) ...@@ -422,7 +422,8 @@ void usb_destroy_configuration(struct usb_device *dev)
for (i = 0; i < cf->desc.bNumInterfaces; i++) { for (i = 0; i < cf->desc.bNumInterfaces; i++) {
if (cf->intf_cache[i]) if (cf->intf_cache[i])
kref_put(&cf->intf_cache[i]->ref); kref_put(&cf->intf_cache[i]->ref,
usb_release_interface_cache);
} }
} }
kfree(dev->config); kfree(dev->config);
......
...@@ -1196,7 +1196,7 @@ static void release_interface(struct device *dev) ...@@ -1196,7 +1196,7 @@ static void release_interface(struct device *dev)
struct usb_interface_cache *intfc = struct usb_interface_cache *intfc =
altsetting_to_usb_interface_cache(intf->altsetting); altsetting_to_usb_interface_cache(intf->altsetting);
kref_put(&intfc->ref); kref_put(&intfc->ref, usb_release_interface_cache);
kfree(intf); kfree(intf);
} }
......
...@@ -39,7 +39,7 @@ void usb_init_urb(struct urb *urb) ...@@ -39,7 +39,7 @@ void usb_init_urb(struct urb *urb)
{ {
if (urb) { if (urb) {
memset(urb, 0, sizeof(*urb)); memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref, urb_destroy); kref_init(&urb->kref);
spin_lock_init(&urb->lock); spin_lock_init(&urb->lock);
} }
} }
...@@ -88,7 +88,7 @@ struct urb *usb_alloc_urb(int iso_packets, int mem_flags) ...@@ -88,7 +88,7 @@ struct urb *usb_alloc_urb(int iso_packets, int mem_flags)
void usb_free_urb(struct urb *urb) void usb_free_urb(struct urb *urb)
{ {
if (urb) if (urb)
kref_put(&urb->kref); kref_put(&urb->kref, urb_destroy);
} }
/** /**
......
...@@ -10,6 +10,7 @@ extern int usb_unbind_interface (struct device *dev); ...@@ -10,6 +10,7 @@ extern int usb_unbind_interface (struct device *dev);
extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface (struct usb_device *dev, extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf); struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0); extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
extern void usb_enable_endpoint (struct usb_device *dev, extern void usb_enable_endpoint (struct usb_device *dev,
......
...@@ -114,7 +114,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags) ...@@ -114,7 +114,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
return qh; return qh;
memset (qh, 0, sizeof *qh); memset (qh, 0, sizeof *qh);
kref_init(&qh->kref, qh_destroy); kref_init(&qh->kref);
qh->ehci = ehci; qh->ehci = ehci;
qh->qh_dma = dma; qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list); // INIT_LIST_HEAD (&qh->qh_list);
...@@ -139,7 +139,7 @@ static inline struct ehci_qh *qh_get (struct ehci_qh *qh) ...@@ -139,7 +139,7 @@ static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
static inline void qh_put (struct ehci_qh *qh) static inline void qh_put (struct ehci_qh *qh)
{ {
kref_put(&qh->kref); kref_put(&qh->kref, qh_destroy);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -421,6 +421,63 @@ static void return_serial (struct usb_serial *serial) ...@@ -421,6 +421,63 @@ static void return_serial (struct usb_serial *serial)
return; return;
} }
static void destroy_serial(struct kref *kref)
{
struct usb_serial *serial;
struct usb_serial_port *port;
int i;
serial = to_usb_serial(kref);
dbg ("%s - %s", __FUNCTION__, serial->type->name);
serial->type->shutdown(serial);
/* return the minor range that this device had */
return_serial(serial);
for (i = 0; i < serial->num_ports; ++i)
serial->port[i]->open_count = 0;
/* the ports are cleaned up and released in port_release() */
for (i = 0; i < serial->num_ports; ++i)
if (serial->port[i]->dev.parent != NULL) {
device_unregister(&serial->port[i]->dev);
serial->port[i] = NULL;
}
/* If this is a "fake" port, we have to clean it up here, as it will
* not get cleaned up in port_release() as it was never registered with
* the driver core */
if (serial->num_ports < serial->num_port_pointers) {
for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->read_urb) {
usb_unlink_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
usb_unlink_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
}
}
usb_put_dev(serial->dev);
/* free up any memory that we allocated */
kfree (serial);
}
/***************************************************************************** /*****************************************************************************
* Driver tty interface functions * Driver tty interface functions
*****************************************************************************/ *****************************************************************************/
...@@ -465,7 +522,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) ...@@ -465,7 +522,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
if (retval) { if (retval) {
port->open_count = 0; port->open_count = 0;
module_put(serial->type->owner); module_put(serial->type->owner);
kref_put(&serial->kref); kref_put(&serial->kref, destroy_serial);
} }
} }
bailout: bailout:
...@@ -496,7 +553,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) ...@@ -496,7 +553,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
} }
module_put(port->serial->type->owner); module_put(port->serial->type->owner);
kref_put(&port->serial->kref); kref_put(&port->serial->kref, destroy_serial);
} }
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
...@@ -654,13 +711,6 @@ static void serial_break (struct tty_struct *tty, int break_state) ...@@ -654,13 +711,6 @@ static void serial_break (struct tty_struct *tty, int break_state)
; ;
} }
static void serial_shutdown (struct usb_serial *serial)
{
dbg ("%s", __FUNCTION__);
serial->type->shutdown(serial);
}
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
{ {
struct usb_serial *serial; struct usb_serial *serial;
...@@ -694,7 +744,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int ...@@ -694,7 +744,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
begin += length; begin += length;
length = 0; length = 0;
} }
kref_put(&serial->kref); kref_put(&serial->kref, destroy_serial);
} }
*eof = 1; *eof = 1;
done: done:
...@@ -763,62 +813,6 @@ void usb_serial_port_softint(void *private) ...@@ -763,62 +813,6 @@ void usb_serial_port_softint(void *private)
wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->write_wait);
} }
static void destroy_serial(struct kref *kref)
{
struct usb_serial *serial;
struct usb_serial_port *port;
int i;
serial = to_usb_serial(kref);
dbg ("%s - %s", __FUNCTION__, serial->type->name);
serial_shutdown (serial);
/* return the minor range that this device had */
return_serial(serial);
for (i = 0; i < serial->num_ports; ++i)
serial->port[i]->open_count = 0;
/* the ports are cleaned up and released in port_release() */
for (i = 0; i < serial->num_ports; ++i)
if (serial->port[i]->dev.parent != NULL) {
device_unregister(&serial->port[i]->dev);
serial->port[i] = NULL;
}
/* If this is a "fake" port, we have to clean it up here, as it will
* not get cleaned up in port_release() as it was never registered with
* the driver core */
if (serial->num_ports < serial->num_port_pointers) {
for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->read_urb) {
usb_unlink_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
usb_unlink_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
}
}
usb_put_dev(serial->dev);
/* free up any memory that we allocated */
kfree (serial);
}
static void port_release(struct device *dev) static void port_release(struct device *dev)
{ {
struct usb_serial_port *port = to_usb_serial_port(dev); struct usb_serial_port *port = to_usb_serial_port(dev);
...@@ -859,7 +853,7 @@ static struct usb_serial * create_serial (struct usb_device *dev, ...@@ -859,7 +853,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
serial->interface = interface; serial->interface = interface;
serial->vendor = dev->descriptor.idVendor; serial->vendor = dev->descriptor.idVendor;
serial->product = dev->descriptor.idProduct; serial->product = dev->descriptor.idProduct;
kref_init(&serial->kref, destroy_serial); kref_init(&serial->kref);
return serial; return serial;
} }
...@@ -1209,7 +1203,7 @@ void usb_serial_disconnect(struct usb_interface *interface) ...@@ -1209,7 +1203,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (serial) { if (serial) {
/* let the last holder of this object /* let the last holder of this object
* cause it to be cleaned up */ * cause it to be cleaned up */
kref_put(&serial->kref); kref_put(&serial->kref, destroy_serial);
} }
dev_info(dev, "device disconnected\n"); dev_info(dev, "device disconnected\n");
} }
......
...@@ -59,7 +59,6 @@ struct bus_type { ...@@ -59,7 +59,6 @@ struct bus_type {
struct driver_attribute * drv_attrs; struct driver_attribute * drv_attrs;
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);
int (*hotplug) (struct device *dev, char **envp, int (*hotplug) (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size); int num_envp, char *buffer, int buffer_size);
int (*suspend)(struct device * dev, u32 state); int (*suspend)(struct device * dev, u32 state);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/kref.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#define KOBJ_NAME_LEN 20 #define KOBJ_NAME_LEN 20
...@@ -26,7 +27,7 @@ ...@@ -26,7 +27,7 @@
struct kobject { struct kobject {
char * k_name; char * k_name;
char name[KOBJ_NAME_LEN]; char name[KOBJ_NAME_LEN];
atomic_t refcount; struct kref kref;
struct list_head entry; struct list_head entry;
struct kobject * parent; struct kobject * parent;
struct kset * kset; struct kset * kset;
...@@ -58,6 +59,8 @@ extern void kobject_put(struct kobject *); ...@@ -58,6 +59,8 @@ extern void kobject_put(struct kobject *);
extern void kobject_hotplug(const char *action, struct kobject *); extern void kobject_hotplug(const char *action, struct kobject *);
extern char * kobject_get_path(struct kset *, struct kobject *, int);
struct kobj_type { struct kobj_type {
void (*release)(struct kobject *); void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops; struct sysfs_ops * sysfs_ops;
......
...@@ -18,15 +18,12 @@ ...@@ -18,15 +18,12 @@
#include <linux/types.h> #include <linux/types.h>
#include <asm/atomic.h> #include <asm/atomic.h>
struct kref { struct kref {
atomic_t refcount; atomic_t refcount;
void (*release)(struct kref *kref);
}; };
void kref_init(struct kref *kref, void (*release)(struct kref *)); void kref_init(struct kref *kref);
struct kref *kref_get(struct kref *kref); void kref_get(struct kref *kref);
void kref_put(struct kref *kref); void kref_put(struct kref *kref, void (*release) (struct kref *kref));
#endif /* _KREF_H_ */ #endif /* _KREF_H_ */
...@@ -5,12 +5,9 @@ ...@@ -5,12 +5,9 @@
lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
kobject.o idr.o div64.o parser.o int_sqrt.o \ kobject.o kref.o idr.o div64.o parser.o int_sqrt.o \
bitmap.o extable.o bitmap.o extable.o
# hack for now till some static code uses krefs, then it can move up above...
obj-y += kref.o
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
......
...@@ -58,14 +58,11 @@ static int create_dir(struct kobject * kobj) ...@@ -58,14 +58,11 @@ static int create_dir(struct kobject * kobj)
return error; return error;
} }
static inline struct kobject * to_kobj(struct list_head * entry) static inline struct kobject * to_kobj(struct list_head * entry)
{ {
return container_of(entry,struct kobject,entry); return container_of(entry,struct kobject,entry);
} }
#ifdef CONFIG_HOTPLUG
static int get_kobj_path_length(struct kset *kset, struct kobject *kobj) static int get_kobj_path_length(struct kset *kset, struct kobject *kobj)
{ {
int length = 1; int length = 1;
...@@ -98,6 +95,31 @@ static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path, ...@@ -98,6 +95,31 @@ static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path,
pr_debug("%s: path = '%s'\n",__FUNCTION__,path); pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
} }
/**
* kobject_get_path - generate and return the path associated with a given kobj
* and kset pair. The result must be freed by the caller with kfree().
*
* @kset: kset in question, with which to build the path
* @kobj: kobject in question, with which to build the path
* @gfp_mask: the allocation type used to allocate the path
*/
char * kobject_get_path(struct kset *kset, struct kobject *kobj, int gfp_mask)
{
char *path;
int len;
len = get_kobj_path_length(kset, kobj);
path = kmalloc(len, gfp_mask);
if (!path)
return NULL;
memset(path, 0x00, len);
fill_kobj_path(kset, kobj, path, len);
return path;
}
#ifdef CONFIG_HOTPLUG
#define BUFFER_SIZE 1024 /* should be enough memory for the env */ #define BUFFER_SIZE 1024 /* should be enough memory for the env */
#define NUM_ENVP 32 /* number of env pointers */ #define NUM_ENVP 32 /* number of env pointers */
static unsigned long sequence_num; static unsigned long sequence_num;
...@@ -112,7 +134,6 @@ static void kset_hotplug(const char *action, struct kset *kset, ...@@ -112,7 +134,6 @@ static void kset_hotplug(const char *action, struct kset *kset,
char *scratch; char *scratch;
int i = 0; int i = 0;
int retval; int retval;
int kobj_path_length;
char *kobj_path = NULL; char *kobj_path = NULL;
char *name = NULL; char *name = NULL;
unsigned long seq; unsigned long seq;
...@@ -163,12 +184,9 @@ static void kset_hotplug(const char *action, struct kset *kset, ...@@ -163,12 +184,9 @@ static void kset_hotplug(const char *action, struct kset *kset,
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1; scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1;
kobj_path_length = get_kobj_path_length (kset, kobj); kobj_path = kobject_get_path(kset, kobj, GFP_KERNEL);
kobj_path = kmalloc (kobj_path_length, GFP_KERNEL);
if (!kobj_path) if (!kobj_path)
goto exit; goto exit;
memset (kobj_path, 0x00, kobj_path_length);
fill_kobj_path (kset, kobj, kobj_path, kobj_path_length);
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1; scratch += sprintf (scratch, "DEVPATH=%s", kobj_path) + 1;
...@@ -225,10 +243,9 @@ void kobject_hotplug(const char *action, struct kobject *kobj) ...@@ -225,10 +243,9 @@ void kobject_hotplug(const char *action, struct kobject *kobj)
* kobject_init - initialize object. * kobject_init - initialize object.
* @kobj: object in question. * @kobj: object in question.
*/ */
void kobject_init(struct kobject * kobj) void kobject_init(struct kobject * kobj)
{ {
atomic_set(&kobj->refcount,1); kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry); INIT_LIST_HEAD(&kobj->entry);
kobj->kset = kset_get(kobj->kset); kobj->kset = kset_get(kobj->kset);
} }
...@@ -325,7 +342,7 @@ int kobject_register(struct kobject * kobj) ...@@ -325,7 +342,7 @@ int kobject_register(struct kobject * kobj)
* @kobj: object. * @kobj: object.
* @name: name. * @name: name.
* *
* If strlen(name) < KOBJ_NAME_LEN, then use a dynamically allocated * If strlen(name) >= KOBJ_NAME_LEN, then use a dynamically allocated
* string that @kobj->k_name points to. Otherwise, use the static * string that @kobj->k_name points to. Otherwise, use the static
* @kobj->name array. * @kobj->name array.
*/ */
...@@ -429,10 +446,8 @@ void kobject_unregister(struct kobject * kobj) ...@@ -429,10 +446,8 @@ void kobject_unregister(struct kobject * kobj)
struct kobject * kobject_get(struct kobject * kobj) struct kobject * kobject_get(struct kobject * kobj)
{ {
if (kobj) { if (kobj)
WARN_ON(!atomic_read(&kobj->refcount)); kref_get(&kobj->kref);
atomic_inc(&kobj->refcount);
}
return kobj; return kobj;
} }
...@@ -459,17 +474,21 @@ void kobject_cleanup(struct kobject * kobj) ...@@ -459,17 +474,21 @@ void kobject_cleanup(struct kobject * kobj)
kobject_put(parent); kobject_put(parent);
} }
static void kobject_release(struct kref *kref)
{
kobject_cleanup(container_of(kref, struct kobject, kref));
}
/** /**
* kobject_put - decrement refcount for object. * kobject_put - decrement refcount for object.
* @kobj: object. * @kobj: object.
* *
* Decrement the refcount, and if 0, call kobject_cleanup(). * Decrement the refcount, and if 0, call kobject_cleanup().
*/ */
void kobject_put(struct kobject * kobj) void kobject_put(struct kobject * kobj)
{ {
if (atomic_dec_and_test(&kobj->refcount)) if (kobj)
kobject_cleanup(kobj); kref_put(&kobj->kref, kobject_release);
} }
...@@ -626,7 +645,7 @@ void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a) ...@@ -626,7 +645,7 @@ void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
} }
} }
EXPORT_SYMBOL(kobject_get_path);
EXPORT_SYMBOL(kobject_init); EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_register); EXPORT_SYMBOL(kobject_register);
EXPORT_SYMBOL(kobject_unregister); EXPORT_SYMBOL(kobject_unregister);
......
...@@ -11,48 +11,45 @@ ...@@ -11,48 +11,45 @@
* *
*/ */
/* #define DEBUG */
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/module.h> #include <linux/module.h>
/** /**
* kref_init - initialize object. * kref_init - initialize object.
* @kref: object in question. * @kref: object in question.
* @release: pointer to a function that will clean up the object
* when the last reference to the object is released.
* This pointer is required.
*/ */
void kref_init(struct kref *kref, void (*release)(struct kref *kref)) void kref_init(struct kref *kref)
{ {
WARN_ON(release == NULL);
atomic_set(&kref->refcount,1); atomic_set(&kref->refcount,1);
kref->release = release;
} }
/** /**
* kref_get - increment refcount for object. * kref_get - increment refcount for object.
* @kref: object. * @kref: object.
*/ */
struct kref *kref_get(struct kref *kref) void kref_get(struct kref *kref)
{ {
WARN_ON(!atomic_read(&kref->refcount)); WARN_ON(!atomic_read(&kref->refcount));
atomic_inc(&kref->refcount); atomic_inc(&kref->refcount);
return kref;
} }
/** /**
* kref_put - decrement refcount for object. * kref_put - decrement refcount for object.
* @kref: object. * @kref: object.
* @release: pointer to the function that will clean up the object when the
* last reference to the object is released.
* This pointer is required, and it is not acceptable to pass kfree
* in as this function.
* *
* Decrement the refcount, and if 0, call kref->release(). * Decrement the refcount, and if 0, call release().
*/ */
void kref_put(struct kref *kref) void kref_put(struct kref *kref, void (*release) (struct kref *kref))
{ {
if (atomic_dec_and_test(&kref->refcount)) { WARN_ON(release == NULL);
pr_debug("kref cleaning up\n"); WARN_ON(release == (void (*)(struct kref *))kfree);
kref->release(kref);
} if (atomic_dec_and_test(&kref->refcount))
release(kref);
} }
EXPORT_SYMBOL(kref_init); EXPORT_SYMBOL(kref_init);
......
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