Commit 3baa0c9d authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

[PATCH] USB: add usb class support for usb drivers that use the USB major

This also consolodates the devfs calls for the USB drivers.
parent 264e19ff
...@@ -66,6 +66,10 @@ static struct file_operations usb_fops = { ...@@ -66,6 +66,10 @@ static struct file_operations usb_fops = {
.open = usb_open, .open = usb_open,
}; };
static struct class usb_class = {
.name = "usb",
};
int usb_major_init(void) int usb_major_init(void)
{ {
if (register_chrdev(USB_MAJOR, "usb", &usb_fops)) { if (register_chrdev(USB_MAJOR, "usb", &usb_fops)) {
...@@ -74,41 +78,53 @@ int usb_major_init(void) ...@@ -74,41 +78,53 @@ int usb_major_init(void)
} }
devfs_mk_dir("usb"); devfs_mk_dir("usb");
class_register(&usb_class);
return 0; return 0;
} }
void usb_major_cleanup(void) void usb_major_cleanup(void)
{ {
class_unregister(&usb_class);
devfs_remove("usb"); devfs_remove("usb");
unregister_chrdev(USB_MAJOR, "usb"); unregister_chrdev(USB_MAJOR, "usb");
} }
static ssize_t show_dev(struct class_device *class_dev, char *buf)
{
struct usb_interface *intf = class_dev_to_usb_interface(class_dev);
dev_t dev = MKDEV(USB_MAJOR, intf->minor);
return sprintf(buf, "%04x\n", dev);
}
static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
/** /**
* usb_register_dev - register a USB device, and ask for a minor number * usb_register_dev - register a USB device, and ask for a minor number
* @fops: the file operations for this USB device * @intf: pointer to the usb_interface that is being registered
* @minor: the requested starting minor for this device. * @class_driver: pointer to the usb_class_driver for this device
* @num_minors: number of minor numbers requested for this device
* @start_minor: place to put the new starting minor number
* *
* This should be called by all USB drivers that use the USB major number. * This should be called by all USB drivers that use the USB major number.
* If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be * If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be
* dynamically allocated out of the list of available ones. If it is not * dynamically allocated out of the list of available ones. If it is not
* enabled, the minor number will be based on the next available free minor, * enabled, the minor number will be based on the next available free minor,
* starting at the requested @minor. * starting at the class_driver->minor_base.
*
* This function also creates the devfs file for the usb device, if devfs
* is enabled, and creates a usb class device in the sysfs tree.
* *
* usb_deregister_dev() must be called when the driver is done with * usb_deregister_dev() must be called when the driver is done with
* the minor numbers given out by this function. * the minor numbers given out by this function.
* *
* Returns -EINVAL if something bad happens with trying to register a * Returns -EINVAL if something bad happens with trying to register a
* device, and 0 on success, alone with a value that the driver should * device, and 0 on success.
* use in start_minor.
*/ */
int usb_register_dev (struct file_operations *fops, int minor, int num_minors, int *start_minor) int usb_register_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver)
{ {
int i;
int j;
int good_spot;
int retval = -EINVAL; int retval = -EINVAL;
int minor_base = class_driver->minor_base;
int minor = 0;
char name[DEVICE_ID_SIZE];
char *temp;
#ifdef CONFIG_USB_DYNAMIC_MINORS #ifdef CONFIG_USB_DYNAMIC_MINORS
/* /*
...@@ -116,65 +132,94 @@ int usb_register_dev (struct file_operations *fops, int minor, int num_minors, i ...@@ -116,65 +132,94 @@ int usb_register_dev (struct file_operations *fops, int minor, int num_minors, i
* at zero to pack the devices into the smallest available space with * at zero to pack the devices into the smallest available space with
* no holes in the minor range. * no holes in the minor range.
*/ */
minor = 0; minor_base = 0;
#endif #endif
intf->minor = -1;
dbg ("asking for %d minors, starting at %d", num_minors, minor); dbg ("looking for a minor, starting at %d", minor_base);
if (fops == NULL) if (class_driver->fops == NULL)
goto exit; goto exit;
*start_minor = 0;
spin_lock (&minor_lock); spin_lock (&minor_lock);
for (i = minor; i < MAX_USB_MINORS; ++i) { for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
if (usb_minors[i]) if (usb_minors[minor])
continue; continue;
good_spot = 1; usb_minors[minor] = class_driver->fops;
for (j = 1; j <= num_minors-1; ++j)
if (usb_minors[i+j]) { retval = 0;
good_spot = 0;
break; break;
} }
if (good_spot == 0) spin_unlock (&minor_lock);
continue;
*start_minor = i;
dbg("found a minor chunk free, starting at %d", i);
for (i = *start_minor; i < (*start_minor + num_minors); ++i)
usb_minors[i] = fops;
retval = 0; if (retval)
goto exit; goto exit;
}
intf->minor = minor;
/* handle the devfs registration */
snprintf(name, DEVICE_ID_SIZE, class_driver->name, minor - minor_base);
devfs_register(NULL, name, 0, USB_MAJOR, minor, class_driver->mode,
class_driver->fops, NULL);
/* create a usb class device for this usb interface */
memset(&intf->class_dev, 0x00, sizeof(struct class_device));
intf->class_dev.class = &usb_class;
intf->class_dev.dev = &intf->dev;
temp = strrchr(name, '/');
if (temp && (temp[1] != 0x00))
++temp;
else
temp = name;
snprintf(intf->class_dev.class_id, BUS_ID_SIZE, "%s", temp);
class_device_register(&intf->class_dev);
class_device_create_file (&intf->class_dev, &class_device_attr_dev);
exit: exit:
spin_unlock (&minor_lock);
return retval; return retval;
} }
EXPORT_SYMBOL(usb_register_dev); EXPORT_SYMBOL(usb_register_dev);
/** /**
* usb_deregister_dev - deregister a USB device's dynamic minor. * usb_deregister_dev - deregister a USB device's dynamic minor.
* @num_minors: number of minor numbers to put back. * @intf: pointer to the usb_interface that is being deregistered
* @start_minor: the starting minor number * @class_driver: pointer to the usb_class_driver for this device
* *
* Used in conjunction with usb_register_dev(). This function is called * Used in conjunction with usb_register_dev(). This function is called
* when the USB driver is finished with the minor numbers gotten from a * when the USB driver is finished with the minor numbers gotten from a
* call to usb_register_dev() (usually when the device is disconnected * call to usb_register_dev() (usually when the device is disconnected
* from the system.) * from the system.)
* *
* This function also cleans up the devfs file for the usb device, if devfs
* is enabled, and removes the usb class device from the sysfs tree.
*
* This should be called by all drivers that use the USB major number. * This should be called by all drivers that use the USB major number.
*/ */
void usb_deregister_dev (int num_minors, int start_minor) void usb_deregister_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver)
{ {
int i; int minor_base = class_driver->minor_base;
char name[DEVICE_ID_SIZE];
dbg ("removing %d minors starting at %d", num_minors, start_minor); #ifdef CONFIG_USB_DYNAMIC_MINORS
minor_base = 0;
#endif
if (intf->minor == -1)
return;
dbg ("removing %d minor", intf->minor);
spin_lock (&minor_lock); spin_lock (&minor_lock);
for (i = start_minor; i < (start_minor + num_minors); ++i) usb_minors[intf->minor] = NULL;
usb_minors[i] = NULL;
spin_unlock (&minor_lock); spin_unlock (&minor_lock);
snprintf(name, DEVICE_ID_SIZE, class_driver->name, intf->minor - minor_base);
devfs_remove (name);
class_device_unregister(&intf->class_dev);
intf->minor = -1;
} }
EXPORT_SYMBOL(usb_deregister_dev); EXPORT_SYMBOL(usb_deregister_dev);
......
...@@ -88,6 +88,7 @@ struct usb_host_interface { ...@@ -88,6 +88,7 @@ struct usb_host_interface {
* function of the driver, after it has been assigned a minor * function of the driver, after it has been assigned a minor
* number from the USB core by calling usb_register_dev(). * number from the USB core by calling usb_register_dev().
* @dev: driver model's view of this device * @dev: driver model's view of this device
* @class_dev: driver model's class view of this device.
* *
* USB device drivers attach to interfaces on a physical device. Each * USB device drivers attach to interfaces on a physical device. Each
* interface encapsulates a single high level function, such as feeding * interface encapsulates a single high level function, such as feeding
...@@ -121,8 +122,10 @@ struct usb_interface { ...@@ -121,8 +122,10 @@ struct usb_interface {
struct usb_driver *driver; /* driver */ struct usb_driver *driver; /* driver */
int minor; /* minor number this interface is bound to */ int minor; /* minor number this interface is bound to */
struct device dev; /* interface specific device info */ struct device dev; /* interface specific device info */
struct class_device class_dev;
}; };
#define to_usb_interface(d) container_of(d, struct usb_interface, dev) #define to_usb_interface(d) container_of(d, struct usb_interface, dev)
#define class_dev_to_usb_interface(d) container_of(d, struct usb_interface, class_dev)
#define interface_to_usbdev(intf) \ #define interface_to_usbdev(intf) \
container_of(intf->dev.parent, struct usb_device, dev) container_of(intf->dev.parent, struct usb_device, dev)
...@@ -441,6 +444,25 @@ struct usb_driver { ...@@ -441,6 +444,25 @@ struct usb_driver {
extern struct bus_type usb_bus_type; extern struct bus_type usb_bus_type;
/**
* struct usb_class_driver - identifies a USB driver that wants to use the USB major number
* @name: devfs name for this driver. Will also be used by the driver
* class code to create a usb class device.
* @fops: pointer to the struct file_operations of this driver.
* @mode: the mode for the devfs file to be created for this driver.
* @minor_base: the start of the minor range for this driver.
*
* This structure is used for the usb_register_dev() and
* usb_unregister_dev() functions, to consolodate a number of the
* paramaters used for them.
*/
struct usb_class_driver {
char *name;
struct file_operations *fops;
mode_t mode;
int minor_base;
};
/* /*
* use these in module_init()/module_exit() * use these in module_init()/module_exit()
* and don't forget MODULE_DEVICE_TABLE(usb, ...) * and don't forget MODULE_DEVICE_TABLE(usb, ...)
...@@ -448,8 +470,10 @@ extern struct bus_type usb_bus_type; ...@@ -448,8 +470,10 @@ extern struct bus_type usb_bus_type;
extern int usb_register(struct usb_driver *); extern int usb_register(struct usb_driver *);
extern void usb_deregister(struct usb_driver *); extern void usb_deregister(struct usb_driver *);
extern int usb_register_dev(struct file_operations *fops, int minor, int num_minors, int *start_minor); extern int usb_register_dev(struct usb_interface *intf,
extern void usb_deregister_dev(int num_minors, int start_minor); struct usb_class_driver *class_driver);
extern void usb_deregister_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver);
extern int usb_device_probe(struct device *dev); extern int usb_device_probe(struct device *dev);
extern int usb_device_remove(struct device *dev); extern int usb_device_remove(struct device *dev);
......
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