patch-2.3.34 linux/drivers/usb/proc_usb.c
Next file: linux/drivers/usb/uhci-debug.c
Previous file: linux/drivers/usb/ohci.h
Back to the patch index
Back to the overall index
- Lines: 1057
- Date:
Mon Dec 20 14:10:06 1999
- Orig file:
v2.3.33/linux/drivers/usb/proc_usb.c
- Orig date:
Tue Dec 7 09:32:46 1999
diff -u --recursive --new-file v2.3.33/linux/drivers/usb/proc_usb.c linux/drivers/usb/proc_usb.c
@@ -37,14 +37,21 @@
* but it was just unplugged, so the directory is now deleted.
* But programs would just have to be prepared for situations like
* this in any plug-and-play environment.)
+ *
+ * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ * Converted the whole proc stuff to real
+ * read methods. Now not the whole device list needs to fit
+ * into one page, only the device list for one bus.
+ * Added a poll method to /proc/bus/usb/devices, to wake
+ * up an eventual usbd
+ *
+ * $Id: proc_usb.c,v 1.14 1999/12/17 10:51:41 fliegl Exp $
*/
-#define __KERNEL__ 1
-
+#define __NO_VERSION__
+#include <linux/module.h>
#include <linux/types.h>
-#include <asm/types.h>
#include <linux/kernel.h>
-/* #include <linux/module.h> */
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
@@ -53,18 +60,34 @@
#include <linux/bitops.h>
#include <asm/uaccess.h>
#include <linux/mm.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
#include "usb.h"
-#define DUMP_LIMIT (PAGE_SIZE - 100)
- /* limit to only one memory page of output */
#define MAX_TOPO_LEVEL 6
+/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
+#define ALLOW_SERIAL_NUMBER
static char *format_topo =
-/* T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
- "T: Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
+/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
+ "T: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
+
+static char *format_string_manufacturer =
+/* S: Manufacturer=xxxx */
+ "S: Manufacturer=%s\n";
+
+static char *format_string_product =
+/* S: Product=xxxx */
+ "S: Product=%s\n";
+
+#ifdef ALLOW_SERIAL_NUMBER
+static char *format_string_serialnumber =
+/* S: SerialNumber=xxxx */
+ "S: SerialNumber=%s\n";
+#endif
static char *format_bandwidth =
/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
@@ -83,7 +106,7 @@
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
static char *format_iface =
-/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx */
+/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
"I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
static char *format_endpt =
@@ -106,12 +129,20 @@
static struct proc_dir_entry *usbdir = NULL, *driversdir = NULL;
static struct proc_dir_entry *devicesdir = NULL;
+static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
+static unsigned int conndiscevcnt = 0;
+
+/* this struct stores the poll state for /proc/bus/usb/devices pollers */
+struct usb_device_status {
+ unsigned int lastev;
+};
+
struct class_info {
int class;
char *class_name;
};
-struct class_info clas_info [] =
+static const struct class_info clas_info[] =
{ /* max. 5 chars. per name string */
{USB_CLASS_PER_INTERFACE, ">ifc"},
{USB_CLASS_AUDIO, "audio"},
@@ -127,78 +158,70 @@
/*****************************************************************/
-static char *class_decode (const int class)
+extern inline void conndiscevent(void)
{
- int ix;
+ wake_up(&deviceconndiscwq);
+ conndiscevcnt++;
+}
- for (ix = 0; clas_info [ix].class != -1; ix++)
- if (clas_info [ix].class == class)
- break;
+static const char *class_decode(const int class)
+{
+ int ix;
- return (clas_info [ix].class_name);
+ for (ix = 0; clas_info[ix].class != -1; ix++)
+ if (clas_info[ix].class == class)
+ break;
+ return (clas_info[ix].class_name);
}
-static int usb_dump_endpoint_descriptor (const struct usb_endpoint_descriptor *desc,
- char *buf, int *len)
+
+static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc)
{
char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
- *len += sprintf (buf + *len, format_endpt,
- desc->bEndpointAddress,
- (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
- desc->bmAttributes,
- EndpointType[desc->bmAttributes & 3],
- desc->wMaxPacketSize,
- desc->bInterval
- );
-
- return (*len >= DUMP_LIMIT) ? -1 : 0;
+ if (start > end)
+ return start;
+ start += sprintf(start, format_endpt, desc->bEndpointAddress,
+ (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
+ desc->bmAttributes, EndpointType[desc->bmAttributes & 3],
+ desc->wMaxPacketSize, desc->bInterval);
+ return start;
}
-static int usb_dump_endpoint (const struct usb_endpoint_descriptor *endpoint,
- char *buf, int *len)
+static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint)
{
- if (usb_dump_endpoint_descriptor (endpoint, buf, len) < 0)
- return -1;
-
- return 0;
+ return usb_dump_endpoint_descriptor(start, end, endpoint);
}
-static int usb_dump_interface_descriptor (const struct usb_interface *iface,
- int setno, char *buf, int *len)
+static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
{
- struct usb_interface_descriptor *desc =
- &iface->altsetting[setno];
-
- *len += sprintf (buf + *len, format_iface,
- desc->bInterfaceNumber,
- desc->bAlternateSetting,
- desc->bNumEndpoints,
- desc->bInterfaceClass,
- class_decode (desc->bInterfaceClass),
- desc->bInterfaceSubClass,
- desc->bInterfaceProtocol,
- iface->driver ? iface->driver->name : "(none)"
- );
+ struct usb_interface_descriptor *desc = &iface->altsetting[setno];
- return (*len >= DUMP_LIMIT) ? -1 : 0;
+ if (start > end)
+ return start;
+ start += sprintf(start, format_iface,
+ desc->bInterfaceNumber,
+ desc->bAlternateSetting,
+ desc->bNumEndpoints,
+ desc->bInterfaceClass,
+ class_decode(desc->bInterfaceClass),
+ desc->bInterfaceSubClass,
+ desc->bInterfaceProtocol,
+ iface->driver ? iface->driver->name : "(none)");
+ return start;
}
-static int usb_dump_interface (const struct usb_interface *iface,
- int setno, char *buf, int *len)
+static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno)
{
+ struct usb_interface_descriptor *desc = &iface->altsetting[setno];
int i;
- struct usb_interface_descriptor *desc =
- &iface->altsetting[setno];
-
- if (usb_dump_interface_descriptor (iface, setno, buf, len) < 0)
- return -1;
+ start = usb_dump_interface_descriptor(start, end, iface, setno);
for (i = 0; i < desc->bNumEndpoints; i++) {
- if (usb_dump_endpoint (desc->endpoint + i, buf, len) < 0)
- return -1;
+ if (start > end)
+ return start;
+ start = usb_dump_endpoint(start, end, desc->endpoint + i);
}
-
- return 0;
+ return start;
}
/* TBD:
@@ -208,225 +231,299 @@
* 2. add <halted> status to each endpoint line
*/
-static int usb_dump_config_descriptor (const struct usb_config_descriptor *desc,
- const int active, char *buf, int *len)
+static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, const int active)
{
- *len += sprintf (buf + *len, format_config,
- active ? '*' : ' ', /* mark active/actual/current cfg. */
- desc->bNumInterfaces,
- desc->bConfigurationValue,
- desc->bmAttributes,
- desc->MaxPower * 2
- );
-
- return (*len >= DUMP_LIMIT) ? -1 : 0;
+ if (start > end)
+ return start;
+ start += sprintf(start, format_config,
+ active ? '*' : ' ', /* mark active/actual/current cfg. */
+ desc->bNumInterfaces,
+ desc->bConfigurationValue,
+ desc->bmAttributes,
+ desc->MaxPower * 2);
+ return start;
}
-static int usb_dump_config (const struct usb_config_descriptor *config,
- const int active, char *buf, int *len)
+static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, const int active)
{
int i, j;
struct usb_interface *interface;
- if (!config) { /* getting these some in 2.3.7; none in 2.3.6 */
- *len += sprintf (buf + *len, "(null Cfg. desc.)\n");
- return 0;
- }
-
- if (usb_dump_config_descriptor (config, active, buf, len) < 0)
- return -1;
-
+ if (start > end)
+ return start;
+ if (!config) /* getting these some in 2.3.7; none in 2.3.6 */
+ return start + sprintf(start, "(null Cfg. desc.)\n");
+ start = usb_dump_config_descriptor(start, end, config, active);
for (i = 0; i < config->bNumInterfaces; i++) {
interface = config->interface + i;
if (!interface)
break;
-
- for (j = 0; j < interface->num_altsetting; j++)
- if (usb_dump_interface (interface, j, buf, len) < 0)
- return -1;
+ for (j = 0; j < interface->num_altsetting; j++) {
+ if (start > end)
+ return start;
+ start = usb_dump_interface(start, end, interface, j);
+ }
}
-
- return 0;
+ return start;
}
/*
* Dump the different USB descriptors.
*/
-static int usb_dump_device_descriptor (const struct usb_device_descriptor *desc,
- char *buf, int *len)
+static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
{
- *len += sprintf (buf + *len, format_device1,
- desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
- desc->bDeviceClass,
- class_decode (desc->bDeviceClass),
- desc->bDeviceSubClass,
- desc->bDeviceProtocol,
- desc->bMaxPacketSize0,
- desc->bNumConfigurations
- );
- if (*len >= DUMP_LIMIT) return -1;
-
- *len += sprintf (buf + *len, format_device2,
- desc->idVendor, desc->idProduct,
- desc->bcdDevice >> 8, desc->bcdDevice & 0xff
- );
-
- return (*len >= DUMP_LIMIT) ? -1 : 0;
+ if (start > end)
+ return start;
+ start += sprintf (start, format_device1,
+ desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
+ desc->bDeviceClass,
+ class_decode (desc->bDeviceClass),
+ desc->bDeviceSubClass,
+ desc->bDeviceProtocol,
+ desc->bMaxPacketSize0,
+ desc->bNumConfigurations);
+ if (start > end)
+ return start;
+ start += sprintf(start, format_device2,
+ desc->idVendor, desc->idProduct,
+ desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
+ return start;
}
-static int usb_dump_desc (const struct usb_device *dev, char *buf, int *len)
+/*
+ * Dump the different strings that this device holds.
+ */
+static char *usb_dump_device_strings (char *start, char *end, const struct usb_device *dev)
{
- int i;
+ if (start > end)
+ return start;
- if (usb_dump_device_descriptor (&dev->descriptor, buf, len) < 0)
- return -1;
+ if (dev->descriptor.iManufacturer) {
+ char * string = usb_string ((struct usb_device *)dev,
+ dev->descriptor.iManufacturer);
+ if (string) {
+ start += sprintf (start, format_string_manufacturer,
+ string
+ );
+ if (start > end)
+ return start;
+
+ }
+ }
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
- if (usb_dump_config (dev->config + i,
- (dev->config + i) == dev->actconfig, /* active ? */
- buf, len) < 0)
- return -1;
+ if (dev->descriptor.iProduct) {
+ char * string = usb_string ((struct usb_device *)dev,
+ dev->descriptor.iProduct);
+ if (string) {
+ start += sprintf (start, format_string_product,
+ string
+ );
+ if (start > end)
+ return start;
+
+ }
}
- return 0;
+#ifdef ALLOW_SERIAL_NUMBER
+ if (dev->descriptor.iSerialNumber) {
+ char * string = usb_string ((struct usb_device *)dev,
+ dev->descriptor.iSerialNumber);
+ if (string) {
+ start += sprintf (start, format_string_serialnumber,
+ string
+ );
+ }
+ }
+#endif
+
+ return start;
}
-static int usb_hcd_bandwidth (const struct usb_device *dev, char *buf, int *len)
+static char *usb_dump_desc(char *start, char *end, const struct usb_device *dev)
{
- *len += sprintf (buf + *len, format_bandwidth,
- dev->bus->bandwidth_allocated,
- FRAME_TIME_MAX_USECS_ALLOC,
- (100 * dev->bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) /
- FRAME_TIME_MAX_USECS_ALLOC,
- dev->bus->bandwidth_int_reqs,
- dev->bus->bandwidth_isoc_reqs
- );
+ int i;
- return (*len >= DUMP_LIMIT) ? -1 : 0;
+ if (start > end)
+ return start;
+
+ start = usb_dump_device_descriptor(start, end, &dev->descriptor);
+
+ if (start > end)
+ return start;
+
+ start = usb_dump_device_strings (start, end, dev);
+
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ if (start > end)
+ return start;
+ start = usb_dump_config(start, end, dev->config + i,
+ (dev->config + i) == dev->actconfig); /* active ? */
+ }
+ return start;
}
+
#ifdef PROC_EXTRA /* TBD: may want to add this code later */
-static int usb_dump_hub_descriptor (const struct usb_hub_descriptor * desc,
- char *buf, int *len)
+static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
{
int leng = USB_DT_HUB_NONVAR_SIZE;
- unsigned char *ptr = (unsigned char *) desc;
-
- *len += sprintf (buf + *len, "Interface:");
+ unsigned char *ptr = (unsigned char *)desc;
+ if (start > end)
+ return start;
+ start += sprintf(start, "Interface:");
while (leng) {
- *len += sprintf (buf + *len, " %02x", *ptr);
+ start += sprintf(start, " %02x", *ptr);
ptr++; leng--;
}
- *len += sprintf (buf + *len, "\n");
-
- return (*len >= DUMP_LIMIT) ? -1 : 0;
+ start += sprintf(start, "\n");
+ return start;
}
-static int usb_dump_string (const struct usb_device *dev, char *id, int index,
- char *buf, int *len)
+static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index)
{
+ if (start > end)
+ return start;
+ start += sprintf(start, "Interface:");
if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
- *len += sprintf (buf + *len, "%s: %s ", id, dev->stringindex[index]);
-
- return (*len >= DUMP_LIMIT) ? -1 : 0;
+ start += sprintf(start, "%s: %s ", id, dev->stringindex[index]);
+ return start;
}
#endif /* PROC_EXTRA */
/*****************************************************************/
-static int usb_device_dump (char *buf, int *len,
- const struct usb_device *usbdev,
- int level, int index, int count)
-{
- int chix;
- int cnt = 0;
- int parent_devnum;
-
- if (level > MAX_TOPO_LEVEL) return -1;
-
- parent_devnum = usbdev->parent ? (usbdev->parent->devnum == -1) ? 0
- : usbdev->parent->devnum : 0;
- /*
- * So the root hub's parent is 0 and any device that is
- * plugged into the root hub has a parent of 0.
- */
- *len += sprintf (buf + *len, format_topo,
- level, parent_devnum, index, count,
- usbdev->devnum,
- usbdev->slow ? "1.5" : "12 ",
- usbdev->maxchild
- );
- /*
- * level = topology-tier level;
- * parent_devnum = parent device number;
- * index = parent's connector number;
- * count = device count at this level
- */
-
- if (*len >= DUMP_LIMIT)
- return -1;
-
- if ((level == 0) && (usbdev->devnum < 0)) { /* for root hub */
- if (usb_hcd_bandwidth (usbdev, buf, len) < 0)
- return -1;
- }
- else { /* for anything but a root hub */
- if (usb_dump_desc (usbdev, buf, len) < 0)
- return -1;
- }
+static char *usb_device_dump(char *start, char *end, const struct usb_device *usbdev,
+ int bus, int level, int index, int count)
+{
+ int chix;
+ int cnt = 0;
+ int parent_devnum = 0;
+ if (level > MAX_TOPO_LEVEL)
+ return start;
+ if (usbdev->parent && usbdev->parent->devnum != -1)
+ parent_devnum = usbdev->parent->devnum;
+ /*
+ * So the root hub's parent is 0 and any device that is
+ * plugged into the root hub has a parent of 0.
+ */
+ start += sprintf(start, format_topo, bus, level, parent_devnum, index, count,
+ usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild);
+ /*
+ * level = topology-tier level;
+ * parent_devnum = parent device number;
+ * index = parent's connector number;
+ * count = device count at this level
+ */
+ /* do not dump descriptors for root hub */
+ if (usbdev->devnum >= 0)
+ start = usb_dump_desc(start, end, usbdev);
+ if (start > end)
+ return start + sprintf(start, "(truncated)\n");
/* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) {
- if (usbdev->children [chix]) {
- if (usb_device_dump (buf, len,
- usbdev->children [chix],
- level + 1, chix, ++cnt) < 0)
- return -1;
- }
+ if (start > end)
+ return start;
+ if (usbdev->children[chix])
+ start = usb_device_dump(start, end, usbdev->children[chix], bus, level + 1, chix, ++cnt);
}
-
- return 0;
+ return start;
}
-static int usb_bus_list_dump (char *buf, int len)
+static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
{
- struct list_head *usb_bus_list = usb_bus_get_list ();
- struct list_head *list = usb_bus_list->next;
-
- len = 0;
-
- /*
- * Go thru each usb_bus. Within each usb_bus: each usb_device.
- * Within each usb_device: all of its device & config. descriptors,
- * marking the currently active ones.
- */
-
-
- while (list != usb_bus_list) {
- struct usb_bus *bus = list_entry (list, struct usb_bus, bus_list);
-
- if (usb_device_dump (buf, &len, bus->root_hub, 0, 0, 0)
- < 0)
- break;
+ struct list_head *usb_bus_list, *buslist;
+ struct usb_bus *bus;
+ char *page, *end;
+ ssize_t ret = 0;
+ unsigned int pos, len;
+ int busnum = 0;
- list = list->next;
+ if (*ppos < 0)
+ return -EINVAL;
+ if (nbytes <= 0)
+ return 0;
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ pos = *ppos;
+ usb_bus_list = usb_bus_get_list();
+ /* enumerate busses */
+ for (buslist = usb_bus_list->next; buslist != usb_bus_list; buslist = buslist->next, ++busnum) {
+ /* print bandwidth allocation */
+ bus = list_entry(buslist, struct usb_bus, bus_list);
+ len = sprintf(page, format_bandwidth, bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC,
+ (100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
+ bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
+ end = usb_device_dump(page + len, page + (PAGE_SIZE - 100), bus->root_hub, busnum, 0, 0, 0);
+ len = end - page;
+ if (len > pos) {
+ len -= pos;
+ if (len > nbytes)
+ len = nbytes;
+ if (copy_to_user(buf, page + pos, len)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ nbytes -= len;
+ buf += len;
+ ret += len;
+ pos = 0;
+ *ppos += len;
+ } else
+ pos -= len;
+ }
+ free_page((unsigned long)page);
+ return ret;
+}
- if (len >= DUMP_LIMIT) {
- len += sprintf (buf + len, "(truncated)\n");
- break;
- }
- }
+static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct usb_device_status *st = (struct usb_device_status *)file->private_data;
+ unsigned int mask = 0;
+
+ if (!st) {
+ st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
+ if (!st)
+ return POLLIN;
+ /*
+ * need to prevent the module from being unloaded, since
+ * proc_unregister does not call the release method and
+ * we would have a memory leak
+ */
+ st->lastev = conndiscevcnt;
+ file->private_data = st;
+ MOD_INC_USE_COUNT;
+ mask = POLLIN;
+ }
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &deviceconndiscwq, wait);
+ if (st->lastev != conndiscevcnt)
+ mask |= POLLIN;
+ st->lastev = conndiscevcnt;
+ return mask;
+}
- return (len);
+static int usb_device_open(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ MOD_INC_USE_COUNT;
+ return 0;
}
-static int usb_bus_list_dump_devices (char *buf, char **start, off_t offset,
- int len, int *eof, void *data)
+static int usb_device_release(struct inode *inode, struct file *file)
{
- return usb_bus_list_dump (buf, len);
+ if (file->private_data) {
+ kfree(file->private_data);
+ file->private_data = NULL;
+ }
+ MOD_DEC_USE_COUNT;
+ return 0;
}
/*
@@ -434,34 +531,89 @@
*
* We now walk the list of registered USB drivers.
*/
-static int usb_driver_list_dump (char *buf, char **start, off_t offset,
- int len, int *eof, void *data)
+static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
{
- struct list_head *usb_driver_list = usb_driver_get_list ();
+ struct list_head *usb_driver_list = usb_driver_get_list();
struct list_head *tmp = usb_driver_list->next;
- int cnt = 0;
-
- len = 0;
-
- while (tmp != usb_driver_list) {
- struct usb_driver *driver = list_entry (tmp, struct usb_driver,
- driver_list);
- len += sprintf (buf + len, "%s\n", driver->name);
- cnt++;
- tmp = tmp->next;
+ char *page, *start, *end;
+ ssize_t ret = 0;
+ unsigned int pos, len;
- if (len >= DUMP_LIMIT)
- {
- len += sprintf (buf + len, "(truncated)\n");
- return (len);
+ if (*ppos < 0)
+ return -EINVAL;
+ if (nbytes <= 0)
+ return 0;
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ start = page;
+ end = page + (PAGE_SIZE - 100);
+ pos = *ppos;
+ for (; tmp != usb_driver_list; tmp = tmp->next) {
+ struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
+ start += sprintf (start, "%s\n", driver->name);
+ if (start > end) {
+ start += sprintf(start, "(truncated)\n");
+ break;
}
}
-
- if (!cnt)
- len += sprintf (buf + len, "(none)\n");
- return (len);
+ if (start == page)
+ start += sprintf(start, "(none)\n");
+ len = start - page;
+ if (len > pos) {
+ len -= pos;
+ if (len > nbytes)
+ len = nbytes;
+ ret = len;
+ if (copy_to_user(buf, page + pos, len))
+ ret = -EFAULT;
+ else
+ *ppos += len;
+ }
+ free_page((unsigned long)page);
+ return ret;
}
+static long long usbdev_lseek(struct file * file, long long offset, int orig);
+
+static struct file_operations proc_usb_devlist_file_operations = {
+ usbdev_lseek, /* lseek */
+ usb_device_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ usb_device_poll, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ usb_device_open, /* open */
+ NULL, /* flush */
+ usb_device_release, /* release */
+ NULL /* fsync */
+};
+
+static struct inode_operations proc_usb_devlist_inode_operations = {
+ &proc_usb_devlist_file_operations, /* file-ops */
+};
+
+static struct file_operations proc_usb_drvlist_file_operations = {
+ usbdev_lseek, /* lseek */
+ usb_driver_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* flush */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+static struct inode_operations proc_usb_drvlist_inode_operations = {
+ &proc_usb_drvlist_file_operations, /* file-ops */
+};
+
+
/*
* proc entry for every device
*/
@@ -487,7 +639,7 @@
static ssize_t usbdev_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip;
struct usb_device *dev = (struct usb_device *)dp->data;
ssize_t ret = 0;
@@ -548,7 +700,7 @@
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
ctrl.value, ctrl.index, tbuf, ctrl.length,
(ctrl.timeout * HZ + 500) / 1000);
- if (!i && ctrl.length) {
+ if ((i > 0) && ctrl.length) {
copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
}
} else {
@@ -560,12 +712,12 @@
(ctrl.timeout * HZ + 500) / 1000);
}
free_page((unsigned long)tbuf);
- if (i) {
+ if (i < 0) {
printk(KERN_WARNING "procusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n",
ctrl.requesttype, ctrl.request, ctrl.length, i);
- return -ENXIO;
+ return i;
}
- return 0;
+ return i;
case EZUSB_BULK:
if (obsolete_warn < 20) {
@@ -593,7 +745,7 @@
return -EINVAL;
}
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, (ctrl.timeout * HZ + 500) / 1000);
- if (!i && len2) {
+ if ((i > 0) && len2) {
copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
}
} else {
@@ -603,10 +755,10 @@
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, (ctrl.timeout * HZ + 500) / 1000);
}
free_page((unsigned long)tbuf);
- if (i) {
+ if (i < 0) {
printk(KERN_WARNING "procusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n",
bulk.ep, bulk.len, i);
- return -ENXIO;
+ return i;
}
return len2;
@@ -628,23 +780,23 @@
free_page((unsigned long)tbuf);
return -EINVAL;
}
- i = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
- if (!i && octrl.dlen) {
+ i = usb_internal_control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
+ if ((i > 0) && octrl.dlen) {
copy_to_user_ret(octrl.data, tbuf, octrl.dlen, -EFAULT);
}
} else {
if (octrl.dlen) {
copy_from_user_ret(tbuf, octrl.data, octrl.dlen, -EFAULT);
}
- i = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
- }
+ i = usb_internal_control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
+ }
free_page((unsigned long)tbuf);
- if (i) {
+ if (i < 0) {
printk(KERN_WARNING "procusb: EZUSB_OLD_CONTROL failed rqt %u rq %u len %u ret %d\n",
octrl.requesttype, octrl.request, octrl.length, i);
- return -ENXIO;
+ return i;
}
- return 0;
+ return i;
case EZUSB_OLD_BULK:
if (obsolete_warn < 20) {
@@ -672,7 +824,7 @@
return -EINVAL;
}
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
- if (!i && len2) {
+ if ((i > 0) && len2) {
copy_to_user_ret(obulk.data, tbuf, len2, -EFAULT);
}
} else {
@@ -682,10 +834,10 @@
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
}
free_page((unsigned long)tbuf);
- if (i) {
+ if (i < 0) {
printk(KERN_WARNING "procusb: EZUSB_OLD_BULK failed ep 0x%x len %u ret %d\n",
obulk.ep, obulk.len, i);
- return -ENXIO;
+ return i;
}
return len2;
@@ -766,7 +918,7 @@
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request,
ctrl.requesttype, ctrl.value, ctrl.index, tbuf,
ctrl.length, (ctrl.timeout * HZ + 500) / 1000);
- if (!i && ctrl.length) {
+ if ((i > 0) && ctrl.length) {
copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
}
} else {
@@ -778,10 +930,10 @@
ctrl.length, (ctrl.timeout * HZ + 500) / 1000);
}
free_page((unsigned long)tbuf);
- if (i) {
+ if (i<0) {
printk(KERN_WARNING "/proc/bus/usb: USB_PROC_CONTROL failed rqt %u rq %u len %u ret %d\n",
ctrl.requesttype, ctrl.request, ctrl.length, i);
- return -ENXIO;
+ return i;
}
return 0;
@@ -839,7 +991,7 @@
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), octrl.request,
octrl.requesttype, octrl.value, octrl.index, tbuf,
octrl.length, HZ);
- if (!i && octrl.length) {
+ if ((i > 0) && octrl.length) {
copy_to_user_ret(octrl.data, tbuf, octrl.length, -EFAULT);
}
} else {
@@ -851,10 +1003,10 @@
octrl.length, HZ);
}
free_page((unsigned long)tbuf);
- if (i) {
+ if (i < 0) {
printk(KERN_WARNING "/proc/bus/usb: USB_PROC_OLD_CONTROL failed rqt %u rq %u len %u ret %d\n",
octrl.requesttype, octrl.request, octrl.length, i);
- return -ENXIO;
+ return i;
}
return 0;
@@ -879,7 +1031,7 @@
return -EINVAL;
}
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
- if (!i && len2) {
+ if ((i > 0) && len2) {
copy_to_user_ret(obulk.data, tbuf, len2, -EFAULT);
}
} else {
@@ -889,10 +1041,10 @@
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
}
free_page((unsigned long)tbuf);
- if (i) {
+ if (i < 0) {
printk(KERN_WARNING "/proc/bus/usb: USB_PROC_OLD_BULK failed ep 0x%x len %u ret %d\n",
obulk.ep, obulk.len, i);
- return -ENXIO;
+ return i;
}
return len2;
@@ -948,7 +1100,7 @@
};
static struct inode_operations proc_usb_device_inode_operations = {
- &proc_usb_device_file_operations, /* file-ops */
+ &proc_usb_device_file_operations, /* file-ops */
};
void proc_usb_add_bus(struct usb_bus *bus)
@@ -959,9 +1111,14 @@
if (!usbdir)
return;
sprintf(buf, "%03d", bus->busnum);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,31)
+ if (!(bus->proc_entry = create_proc_entry(buf, S_IFDIR, usbdir)))
+#else
if (!(bus->proc_entry = proc_mkdir(buf, usbdir)))
+#endif
return;
bus->proc_entry->data = bus;
+ conndiscevent();
}
/* devices need already be removed! */
@@ -970,6 +1127,7 @@
if (!bus->proc_entry)
return;
remove_proc_entry(bus->proc_entry->name, usbdir);
+ conndiscevent();
}
void proc_usb_add_device(struct usb_device *dev)
@@ -984,48 +1142,54 @@
return;
dev->proc_entry->ops = &proc_usb_device_inode_operations;
dev->proc_entry->data = dev;
+ conndiscevent();
}
void proc_usb_remove_device(struct usb_device *dev)
{
if (dev->proc_entry)
remove_proc_entry(dev->proc_entry->name, dev->bus->proc_entry);
+ conndiscevent();
}
void proc_usb_cleanup (void)
{
if (driversdir)
- remove_proc_entry ("drivers", usbdir);
+ remove_proc_entry("drivers", usbdir);
if (devicesdir)
- remove_proc_entry ("devices", usbdir);
+ remove_proc_entry("devices", usbdir);
if (usbdir)
- remove_proc_entry ("usb", proc_bus);
+ remove_proc_entry("usb", proc_bus);
}
int proc_usb_init (void)
{
- usbdir = proc_mkdir ("usb", proc_bus);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,31)
+ usbdir = create_proc_entry("usb", S_IFDIR, proc_bus);
+#else
+ usbdir = proc_mkdir("usb", proc_bus);
+#endif
if (!usbdir) {
printk ("proc_usb: cannot create /proc/bus/usb entry\n");
return -1;
}
- driversdir = create_proc_read_entry("drivers", 0, usbdir,
- usb_driver_list_dump, NULL);
+ driversdir = create_proc_entry("drivers", 0, usbdir);
if (!driversdir) {
printk ("proc_usb: cannot create /proc/bus/usb/drivers entry\n");
- proc_usb_cleanup ();
+ proc_usb_cleanup();
return -1;
}
+ driversdir->ops = &proc_usb_drvlist_inode_operations;
- devicesdir = create_proc_read_entry ("devices", 0, usbdir,
- usb_bus_list_dump_devices, NULL);
+ devicesdir = create_proc_entry("devices", 0, usbdir);
if (!devicesdir) {
printk ("proc_usb: cannot create /proc/bus/usb/devices entry\n");
proc_usb_cleanup ();
return -1;
}
+ devicesdir->ops = &proc_usb_devlist_inode_operations;
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)