patch-2.4.0-test4 linux/drivers/usb/devices.c
Next file: linux/drivers/usb/evdev.c
Previous file: linux/drivers/usb/dc2xx.c
Back to the patch index
Back to the overall index
- Lines: 171
- Date:
Wed Jul 12 17:27:36 2000
- Orig file:
v2.4.0-test3/linux/drivers/usb/devices.c
- Orig date:
Wed Apr 26 16:34:08 2000
diff -u --recursive --new-file v2.4.0-test3/linux/drivers/usb/devices.c linux/drivers/usb/devices.c
@@ -45,6 +45,9 @@
* up an eventual usbd
* 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
* Turned into its own filesystem
+ * 2000-07-05: Ashley Montanaro <ashley@compsoc.man.ac.uk>
+ * Converted file reading routine to dump to buffer once
+ * per device, not per bus
*
* $Id: devices.c,v 1.5 2000/01/11 13:58:21 tom Exp $
*/
@@ -367,23 +370,40 @@
/*****************************************************************/
-static char *usb_device_dump(char *start, char *end, struct usb_device *usbdev,
- struct usb_bus *bus, int level, int index, int count)
+/* This is a recursive function. Parameters:
+ * buffer - the user-space buffer to write data into
+ * nbytes - the maximum number of bytes to write
+ * skip_bytes - the number of bytes to skip before writing anything
+ * file_offset - the offset into the devices file on completion
+ */
+static ssize_t usb_device_dump(char **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
+ struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
{
int chix;
- int cnt = 0;
+ int ret, cnt = 0;
int parent_devnum = 0;
-
+ char *pages_start, *data_end;
+ unsigned int length;
+ ssize_t total_written = 0;
+
+ /* don't bother with anything else if we're not writing any data */
+ if (*nbytes <= 0)
+ return 0;
+
if (level > MAX_TOPO_LEVEL)
- return start;
+ return total_written;
+ /* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */
+ if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1)))
+ return -ENOMEM;
+
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->busnum, level, parent_devnum, index, count,
- usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild);
+ data_end = pages_start + sprintf(pages_start, format_topo, bus->busnum, level, parent_devnum, index, count,
+ usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild);
/*
* level = topology-tier level;
* parent_devnum = parent device number;
@@ -392,30 +412,58 @@
*/
/* If this is the root hub, display the bandwidth information */
if (level == 0)
- start += sprintf(start, format_bandwidth, bus->bandwidth_allocated,
+ data_end += sprintf(data_end, 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);
- start = usb_dump_desc(start, end, usbdev);
- if (start > end)
- return start + sprintf(start, "(truncated)\n");
+
+ data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
+
+ if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
+ data_end += sprintf(data_end, "(truncated)\n");
+
+ length = data_end - pages_start;
+ /* if we can start copying some data to the user */
+ if (length > *skip_bytes) {
+ length -= *skip_bytes;
+ if (length > *nbytes)
+ length = *nbytes;
+ if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) {
+ free_pages((unsigned long)pages_start, 1);
+
+ if (total_written == 0)
+ return -EFAULT;
+ return total_written;
+ }
+ *nbytes -= length;
+ *file_offset += length;
+ total_written += length;
+ *buffer += length;
+ *skip_bytes = 0;
+ } else
+ *skip_bytes -= length;
+
+ free_pages((unsigned long)pages_start, 1);
+
/* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) {
- if (start > end)
- return start;
- if (usbdev->children[chix])
- start = usb_device_dump(start, end, usbdev->children[chix], bus, level + 1, chix, ++cnt);
+ if (usbdev->children[chix]) {
+ ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, usbdev->children[chix],
+ bus, level + 1, chix, ++cnt);
+ if (ret == -EFAULT)
+ return total_written;
+ total_written += ret;
+ }
}
- return start;
+ return total_written;
}
static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
{
struct list_head *buslist;
struct usb_bus *bus;
- char *page, *end;
- ssize_t ret = 0;
- unsigned int pos, len;
+ ssize_t ret, total_written = 0;
+ loff_t skip_bytes = *ppos;
if (*ppos < 0)
return -EINVAL;
@@ -423,34 +471,18 @@
return 0;
if (!access_ok(VERIFY_WRITE, buf, nbytes))
return -EFAULT;
- if (!(page = (char*) __get_free_pages(GFP_KERNEL,1)))
- return -ENOMEM;
- pos = *ppos;
+
/* enumerate busses */
for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
/* print devices for this bus */
bus = list_entry(buslist, struct usb_bus, bus_list);
- end = usb_device_dump(page, page + (2*PAGE_SIZE - 256), bus->root_hub, bus, 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;
+ /* recurse through all children of the root hub */
+ ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
+ if (ret < 0)
+ return ret;
+ total_written += ret;
}
- free_pages((unsigned long)page, 1);
- return ret;
+ return total_written;
}
/* Kernel lock for "lastev" protection */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)