summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <greg@kroah.com>2003-05-06 10:19:52 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2003-05-06 10:19:52 -0700
commit3baa0c9df0440eca8a7ee494f96c89b024f8695d (patch)
tree8f194c3693e2a0ab68f611a6cca23cfef3885618
parent264e19ffb8a2bfadb0cc19cd8a7fcfa7a5e9735d (diff)
[PATCH] USB: add usb class support for usb drivers that use the USB major
This also consolodates the devfs calls for the USB drivers.
-rw-r--r--drivers/usb/core/file.c123
-rw-r--r--include/linux/usb.h28
2 files changed, 110 insertions, 41 deletions
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 070811df5b3b..8e25a5bd26b5 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -66,6 +66,10 @@ static struct file_operations usb_fops = {
.open = usb_open,
};
+static struct class usb_class = {
+ .name = "usb",
+};
+
int usb_major_init(void)
{
if (register_chrdev(USB_MAJOR, "usb", &usb_fops)) {
@@ -74,41 +78,53 @@ int usb_major_init(void)
}
devfs_mk_dir("usb");
+ class_register(&usb_class);
return 0;
}
void usb_major_cleanup(void)
{
+ class_unregister(&usb_class);
devfs_remove("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
- * @fops: the file operations for this USB device
- * @minor: the requested starting minor for this device.
- * @num_minors: number of minor numbers requested for this device
- * @start_minor: place to put the new starting minor number
+ * @intf: pointer to the usb_interface that is being registered
+ * @class_driver: pointer to the usb_class_driver for this device
*
* 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
* 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,
- * 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
* the minor numbers given out by this function.
*
* Returns -EINVAL if something bad happens with trying to register a
- * device, and 0 on success, alone with a value that the driver should
- * use in start_minor.
+ * device, and 0 on success.
*/
-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 minor_base = class_driver->minor_base;
+ int minor = 0;
+ char name[DEVICE_ID_SIZE];
+ char *temp;
#ifdef CONFIG_USB_DYNAMIC_MINORS
/*
@@ -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
* no holes in the minor range.
*/
- minor = 0;
+ minor_base = 0;
#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;
- *start_minor = 0;
spin_lock (&minor_lock);
- for (i = minor; i < MAX_USB_MINORS; ++i) {
- if (usb_minors[i])
+ for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
+ if (usb_minors[minor])
continue;
- good_spot = 1;
- for (j = 1; j <= num_minors-1; ++j)
- if (usb_minors[i+j]) {
- good_spot = 0;
- break;
- }
- if (good_spot == 0)
- 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;
+ usb_minors[minor] = class_driver->fops;
retval = 0;
- goto exit;
+ break;
}
-exit:
spin_unlock (&minor_lock);
+
+ if (retval)
+ 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:
return retval;
}
EXPORT_SYMBOL(usb_register_dev);
/**
* usb_deregister_dev - deregister a USB device's dynamic minor.
- * @num_minors: number of minor numbers to put back.
- * @start_minor: the starting minor number
+ * @intf: pointer to the usb_interface that is being deregistered
+ * @class_driver: pointer to the usb_class_driver for this device
*
* Used in conjunction with usb_register_dev(). This function is called
* when the USB driver is finished with the minor numbers gotten from a
* call to usb_register_dev() (usually when the device is disconnected
* 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.
*/
-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];
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+ minor_base = 0;
+#endif
+
+ if (intf->minor == -1)
+ return;
- dbg ("removing %d minors starting at %d", num_minors, start_minor);
+ dbg ("removing %d minor", intf->minor);
spin_lock (&minor_lock);
- for (i = start_minor; i < (start_minor + num_minors); ++i)
- usb_minors[i] = NULL;
+ usb_minors[intf->minor] = NULL;
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);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 36dee7b0e228..9782078f56b6 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -88,6 +88,7 @@ struct usb_host_interface {
* function of the driver, after it has been assigned a minor
* 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.
*
* USB device drivers attach to interfaces on a physical device. Each
* interface encapsulates a single high level function, such as feeding
@@ -121,8 +122,10 @@ struct usb_interface {
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;
};
#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) \
container_of(intf->dev.parent, struct usb_device, dev)
@@ -441,6 +444,25 @@ struct usb_driver {
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()
* and don't forget MODULE_DEVICE_TABLE(usb, ...)
@@ -448,8 +470,10 @@ extern struct bus_type usb_bus_type;
extern int usb_register(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 void usb_deregister_dev(int num_minors, int start_minor);
+extern int usb_register_dev(struct usb_interface *intf,
+ 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_remove(struct device *dev);