linux-old/drivers/usb/devices.c
<<
>>
Prefs
   1/*
   2 * devices.c
   3 * (C) Copyright 1999 Randy Dunlap.
   4 * (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
   5 * (C) Copyright 1999 Deti Fliegl (new USB architecture)
   6 *
   7 * $id$
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22 *
  23 *************************************************************
  24 *
  25 * <mountpoint>/devices contains USB topology, device, config, class,
  26 * interface, & endpoint data.
  27 *
  28 * I considered using /proc/bus/usb/devices/device# for each device
  29 * as it is attached or detached, but I didn't like this for some
  30 * reason -- maybe it's just too deep of a directory structure.
  31 * I also don't like looking in multiple places to gather and view
  32 * the data.  Having only one file for ./devices also prevents race
  33 * conditions that could arise if a program was reading device info
  34 * for devices that are being removed (unplugged).  (That is, the
  35 * program may find a directory for devnum_12 then try to open it,
  36 * but it was just unplugged, so the directory is now deleted.
  37 * But programs would just have to be prepared for situations like
  38 * this in any plug-and-play environment.)
  39 *
  40 * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
  41 *   Converted the whole proc stuff to real
  42 *   read methods. Now not the whole device list needs to fit
  43 *   into one page, only the device list for one bus.
  44 *   Added a poll method to /proc/bus/usb/devices, to wake
  45 *   up an eventual usbd
  46 * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
  47 *   Turned into its own filesystem
  48 * 2000-07-05: Ashley Montanaro <ashley@compsoc.man.ac.uk>
  49 *   Converted file reading routine to dump to buffer once
  50 *   per device, not per bus
  51 *
  52 * $Id: devices.c,v 1.5 2000/01/11 13:58:21 tom Exp $
  53 */
  54
  55#include <linux/fs.h>
  56#include <linux/mm.h>
  57#include <linux/slab.h>
  58#include <linux/poll.h>
  59#include <linux/usb.h>
  60#include <linux/smp_lock.h>
  61#include <linux/usbdevice_fs.h>
  62#include <asm/uaccess.h>
  63
  64#include "hcd.h"
  65
  66#define MAX_TOPO_LEVEL          6
  67
  68/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
  69#define ALLOW_SERIAL_NUMBER
  70
  71static char *format_topo =
  72/* T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
  73  "T:  Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
  74
  75static char *format_string_manufacturer =
  76/* S:  Manufacturer=xxxx */
  77  "S:  Manufacturer=%.100s\n";
  78
  79static char *format_string_product =
  80/* S:  Product=xxxx */
  81  "S:  Product=%.100s\n";
  82
  83#ifdef ALLOW_SERIAL_NUMBER
  84static char *format_string_serialnumber =
  85/* S:  SerialNumber=xxxx */
  86  "S:  SerialNumber=%.100s\n";
  87#endif
  88
  89static char *format_bandwidth =
  90/* B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
  91  "B:  Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
  92  
  93static char *format_device1 =
  94/* D:  Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
  95  "D:  Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
  96
  97static char *format_device2 =
  98/* P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx */
  99  "P:  Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
 100
 101static char *format_config =
 102/* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
 103  "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
 104  
 105static char *format_iface =
 106/* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
 107  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
 108
 109static char *format_endpt =
 110/* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
 111  "E:  Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
 112
 113
 114/*
 115 * Need access to the driver and USB bus lists.
 116 * extern struct list_head usb_driver_list;
 117 * extern struct list_head usb_bus_list;
 118 * However, these will come from functions that return ptrs to each of them.
 119 */
 120
 121static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
 122static unsigned int conndiscevcnt = 0;
 123
 124/* this struct stores the poll state for <mountpoint>/devices pollers */
 125struct usb_device_status {
 126        unsigned int lastev;
 127};
 128
 129struct class_info {
 130        int class;
 131        char *class_name;
 132};
 133
 134static const struct class_info clas_info[] =
 135{                                       /* max. 5 chars. per name string */
 136        {USB_CLASS_PER_INTERFACE,       ">ifc"},
 137        {USB_CLASS_AUDIO,               "audio"},
 138        {USB_CLASS_COMM,                "comm."},
 139        {USB_CLASS_HID,                 "HID"},
 140        {USB_CLASS_HUB,                 "hub"},
 141        {USB_CLASS_PHYSICAL,            "PID"},
 142        {USB_CLASS_PRINTER,             "print"},
 143        {USB_CLASS_MASS_STORAGE,        "stor."},
 144        {USB_CLASS_CDC_DATA,            "data"},
 145        {USB_CLASS_APP_SPEC,            "app."},
 146        {USB_CLASS_VENDOR_SPEC,         "vend."},
 147        {USB_CLASS_STILL_IMAGE,         "still"},
 148        {USB_CLASS_CSCID,               "scard"},
 149        {USB_CLASS_CONTENT_SEC,         "c-sec"},
 150        {-1,                            "unk."}         /* leave as last */
 151};
 152
 153/*****************************************************************/
 154
 155void usbdevfs_conn_disc_event(void)
 156{
 157        wake_up(&deviceconndiscwq);
 158        conndiscevcnt++;
 159}
 160
 161static const char *class_decode(const int class)
 162{
 163        int ix;
 164
 165        for (ix = 0; clas_info[ix].class != -1; ix++)
 166                if (clas_info[ix].class == class)
 167                        break;
 168        return (clas_info[ix].class_name);
 169}
 170
 171static char *usb_dump_endpoint_descriptor (
 172        int speed,
 173        char *start,
 174        char *end,
 175        const struct usb_endpoint_descriptor *desc
 176)
 177{
 178        char dir, unit, *type;
 179        unsigned interval, in, bandwidth = 1;
 180
 181        if (start > end)
 182                return start;
 183        in = (desc->bEndpointAddress & USB_DIR_IN);
 184        dir = in ? 'I' : 'O';
 185        if (speed == USB_SPEED_HIGH) {
 186                switch (desc->wMaxPacketSize & (0x03 << 11)) {
 187                case 1 << 11:   bandwidth = 2; break;
 188                case 2 << 11:   bandwidth = 3; break;
 189                }
 190        }
 191
 192        /* this isn't checking for illegal values */
 193        switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
 194        case USB_ENDPOINT_XFER_CONTROL:
 195                type = "Ctrl";
 196                if (speed == USB_SPEED_HIGH)    /* uframes per NAK */
 197                        interval = desc->bInterval;
 198                else
 199                        interval = 0;
 200                dir = 'B';                      /* ctrl is bidirectional */
 201                break;
 202        case USB_ENDPOINT_XFER_ISOC:
 203                type = "Isoc";
 204                interval = 1 << (desc->bInterval - 1);
 205                break;
 206        case USB_ENDPOINT_XFER_BULK:
 207                type = "Bulk";
 208                if (speed == USB_SPEED_HIGH && !in)     /* uframes per NAK */
 209                        interval = desc->bInterval;
 210                else
 211                        interval = 0;
 212                break;
 213        case USB_ENDPOINT_XFER_INT:
 214                type = "Int.";
 215                if (speed == USB_SPEED_HIGH) {
 216                        interval = 1 << (desc->bInterval - 1);
 217                } else
 218                        interval = desc->bInterval;
 219                break;
 220        default:        /* "can't happen" */
 221                return start;
 222        }
 223        interval *= (speed == USB_SPEED_HIGH) ? 125 : 1000;
 224        if (interval % 1000)
 225                unit = 'u';
 226        else {
 227                unit = 'm';
 228                interval /= 1000;
 229        }
 230
 231        start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
 232                         desc->bmAttributes, type,
 233                         (desc->wMaxPacketSize & 0x07ff) * bandwidth,
 234                         interval, unit);
 235        return start;
 236}
 237
 238static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
 239{
 240        struct usb_interface_descriptor *desc = &iface->altsetting[setno];
 241
 242        if (start > end)
 243                return start;
 244        start += sprintf(start, format_iface,
 245                         desc->bInterfaceNumber,
 246                         desc->bAlternateSetting,
 247                         desc->bNumEndpoints,
 248                         desc->bInterfaceClass,
 249                         class_decode(desc->bInterfaceClass),
 250                         desc->bInterfaceSubClass,
 251                         desc->bInterfaceProtocol,
 252                         iface->driver ? iface->driver->name : "(none)");
 253        return start;
 254}
 255
 256static char *usb_dump_interface(
 257        int speed,
 258        char *start,
 259        char *end,
 260        const struct usb_interface *iface,
 261        int setno
 262) {
 263        struct usb_interface_descriptor *desc = &iface->altsetting[setno];
 264        int i;
 265
 266        start = usb_dump_interface_descriptor(start, end, iface, setno);
 267        for (i = 0; i < desc->bNumEndpoints; i++) {
 268                if (start > end)
 269                        return start;
 270                start = usb_dump_endpoint_descriptor(speed,
 271                                start, end, desc->endpoint + i);
 272        }
 273        return start;
 274}
 275
 276/* TBD:
 277 * 0. TBDs
 278 * 1. marking active config and ifaces (code lists all, but should mark
 279 *    which ones are active, if any)
 280 * 2. add <halted> status to each endpoint line
 281 */
 282
 283static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active)
 284{
 285        if (start > end)
 286                return start;
 287        start += sprintf(start, format_config,
 288                         active ? '*' : ' ',    /* mark active/actual/current cfg. */
 289                         desc->bNumInterfaces,
 290                         desc->bConfigurationValue,
 291                         desc->bmAttributes,
 292                         desc->MaxPower * 2);
 293        return start;
 294}
 295
 296static char *usb_dump_config (
 297        int speed,
 298        char *start,
 299        char *end,
 300        const struct usb_config_descriptor *config,
 301        int active
 302)
 303{
 304        int i, j;
 305        struct usb_interface *interface;
 306
 307        if (start > end)
 308                return start;
 309        if (!config)            /* getting these some in 2.3.7; none in 2.3.6 */
 310                return start + sprintf(start, "(null Cfg. desc.)\n");
 311        start = usb_dump_config_descriptor(start, end, config, active);
 312        for (i = 0; i < config->bNumInterfaces; i++) {
 313                interface = config->interface + i;
 314                if (!interface)
 315                        break;
 316                for (j = 0; j < interface->num_altsetting; j++) {
 317                        if (start > end)
 318                                return start;
 319                        start = usb_dump_interface(speed,
 320                                        start, end, interface, j);
 321                }
 322        }
 323        return start;
 324}
 325
 326/*
 327 * Dump the different USB descriptors.
 328 */
 329static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
 330{
 331        if (start > end)
 332                return start;
 333        start += sprintf (start, format_device1,
 334                          desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
 335                          desc->bDeviceClass,
 336                          class_decode (desc->bDeviceClass),
 337                          desc->bDeviceSubClass,
 338                          desc->bDeviceProtocol,
 339                          desc->bMaxPacketSize0,
 340                          desc->bNumConfigurations);
 341        if (start > end)
 342                return start;
 343        start += sprintf(start, format_device2,
 344                         desc->idVendor, desc->idProduct,
 345                         desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
 346        return start;
 347}
 348
 349/*
 350 * Dump the different strings that this device holds.
 351 */
 352static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
 353{
 354        char *buf;
 355
 356        if (start > end)
 357                return start;
 358        buf = kmalloc(128, GFP_KERNEL);
 359        if (!buf)
 360                return start;
 361        if (dev->descriptor.iManufacturer) {
 362                if (usb_string(dev, dev->descriptor.iManufacturer, buf, 128) > 0)
 363                        start += sprintf(start, format_string_manufacturer, buf);
 364        }                               
 365        if (start > end)
 366                goto out;
 367        if (dev->descriptor.iProduct) {
 368                if (usb_string(dev, dev->descriptor.iProduct, buf, 128) > 0)
 369                        start += sprintf(start, format_string_product, buf);
 370        }
 371        if (start > end)
 372                goto out;
 373#ifdef ALLOW_SERIAL_NUMBER
 374        if (dev->descriptor.iSerialNumber) {
 375                if (usb_string(dev, dev->descriptor.iSerialNumber, buf, 128) > 0)
 376                        start += sprintf(start, format_string_serialnumber, buf);
 377        }
 378#endif
 379 out:
 380        kfree(buf);
 381        return start;
 382}
 383
 384static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
 385{
 386        int i;
 387
 388        if (start > end)
 389                return start;
 390
 391        /*
 392         * Grab device's exclusive_access mutex to prevent its driver or
 393         * devio from using this device while we are accessing it.
 394         */
 395        down (&dev->exclusive_access);
 396
 397        start = usb_dump_device_descriptor(start, end, &dev->descriptor);
 398
 399        if (start > end)
 400                goto out;
 401
 402        start = usb_dump_device_strings (start, end, dev);
 403        
 404        for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 405                if (start > end)
 406                        goto out;
 407                start = usb_dump_config(dev->speed,
 408                                start, end, dev->config + i,
 409                                /* active ? */
 410                                (dev->config + i) == dev->actconfig);
 411        }
 412
 413out:
 414        up (&dev->exclusive_access);
 415        return start;
 416}
 417
 418
 419#ifdef PROC_EXTRA /* TBD: may want to add this code later */
 420
 421static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
 422{
 423        int leng = USB_DT_HUB_NONVAR_SIZE;
 424        unsigned char *ptr = (unsigned char *)desc;
 425
 426        if (start > end)
 427                return start;
 428        start += sprintf(start, "Interface:");
 429        while (leng && start <= end) {
 430                start += sprintf(start, " %02x", *ptr);
 431                ptr++; leng--;
 432        }
 433        *start++ = '\n';
 434        return start;
 435}
 436
 437static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index)
 438{
 439        if (start > end)
 440                return start;
 441        start += sprintf(start, "Interface:");
 442        if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
 443                start += sprintf(start, "%s: %.100s ", id, dev->stringindex[index]);
 444        return start;
 445}
 446
 447#endif /* PROC_EXTRA */
 448
 449/*****************************************************************/
 450
 451/* This is a recursive function. Parameters:
 452 * buffer - the user-space buffer to write data into
 453 * nbytes - the maximum number of bytes to write
 454 * skip_bytes - the number of bytes to skip before writing anything
 455 * file_offset - the offset into the devices file on completion
 456 */
 457static ssize_t usb_device_dump(char **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
 458                                struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
 459{
 460        int chix;
 461        int ret, cnt = 0;
 462        int parent_devnum = 0;
 463        char *pages_start, *data_end, *speed;
 464        unsigned int length;
 465        ssize_t total_written = 0;
 466        
 467        /* don't bother with anything else if we're not writing any data */
 468        if (*nbytes <= 0)
 469                return 0;
 470        
 471        if (level > MAX_TOPO_LEVEL)
 472                return total_written;
 473        /* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */
 474        if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1)))
 475                return -ENOMEM;
 476                
 477        if (usbdev->parent && usbdev->parent->devnum != -1)
 478                parent_devnum = usbdev->parent->devnum;
 479        /*
 480         * So the root hub's parent is 0 and any device that is
 481         * plugged into the root hub has a parent of 0.
 482         */
 483        switch (usbdev->speed) {
 484        case USB_SPEED_LOW:
 485                speed = "1.5"; break;
 486        case USB_SPEED_UNKNOWN:         /* usb 1.1 root hub code */
 487        case USB_SPEED_FULL:
 488                speed = "12 "; break;
 489        case USB_SPEED_HIGH:
 490                speed = "480"; break;
 491        default:
 492                speed = "?? ";
 493        }
 494        data_end = pages_start + sprintf(pages_start, format_topo,
 495                        bus->busnum, level, parent_devnum,
 496                        index, count, usbdev->devnum,
 497                        speed, usbdev->maxchild);
 498        /*
 499         * level = topology-tier level;
 500         * parent_devnum = parent device number;
 501         * index = parent's connector number;
 502         * count = device count at this level
 503         */
 504        /* If this is the root hub, display the bandwidth information */
 505        if (level == 0) {
 506                int     max;
 507 
 508                /* high speed reserves 80%, full/low reserves 90% */
 509                if (usbdev->speed == USB_SPEED_HIGH)
 510                        max = 800;
 511                else
 512                        max = FRAME_TIME_MAX_USECS_ALLOC;
 513 
 514                /* report "average" periodic allocation over a microsecond.
 515                 * the schedules are actually bursty, HCDs need to deal with
 516                 * that and just compute/report this average.
 517                 */
 518                data_end += sprintf(data_end, format_bandwidth,
 519                                bus->bandwidth_allocated, max,
 520                                (100 * bus->bandwidth_allocated + max / 2)
 521                                        / max,
 522                                 bus->bandwidth_int_reqs,
 523                                 bus->bandwidth_isoc_reqs);
 524        }
 525        data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
 526        
 527        if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
 528                data_end += sprintf(data_end, "(truncated)\n");
 529        
 530        length = data_end - pages_start;
 531        /* if we can start copying some data to the user */
 532        if (length > *skip_bytes) {
 533                length -= *skip_bytes;
 534                if (length > *nbytes)
 535                        length = *nbytes;
 536                if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) {
 537                        free_pages((unsigned long)pages_start, 1);
 538                        
 539                        if (total_written == 0)
 540                                return -EFAULT;
 541                        return total_written;
 542                }
 543                *nbytes -= length;
 544                *file_offset += length;
 545                total_written += length;
 546                *buffer += length;
 547                *skip_bytes = 0;
 548        } else
 549                *skip_bytes -= length;
 550        
 551        free_pages((unsigned long)pages_start, 1);
 552        
 553        /* Now look at all of this device's children. */
 554        for (chix = 0; chix < usbdev->maxchild; chix++) {
 555                struct usb_device *childdev = usbdev->children[chix];
 556                if (childdev) {
 557                        usb_inc_dev_use(childdev);
 558                        ret = usb_device_dump(buffer, nbytes, skip_bytes,
 559                                        file_offset, childdev,
 560                                        bus, level + 1, chix, ++cnt);
 561                        usb_dec_dev_use(childdev);
 562                        if (ret == -EFAULT)
 563                                return total_written;
 564                        total_written += ret;
 565                }
 566        }
 567        return total_written;
 568}
 569
 570static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
 571{
 572        struct list_head *buslist;
 573        struct usb_bus *bus;
 574        ssize_t ret, total_written = 0;
 575        loff_t skip_bytes = *ppos;
 576
 577        if (*ppos < 0)
 578                return -EINVAL;
 579        if (nbytes <= 0)
 580                return 0;
 581        if (!access_ok(VERIFY_WRITE, buf, nbytes))
 582                return -EFAULT;
 583
 584        /* enumerate busses */
 585        down (&usb_bus_list_lock);
 586        for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
 587                /* print devices for this bus */
 588                bus = list_entry(buslist, struct usb_bus, bus_list);
 589                /* recurse through all children of the root hub */
 590                ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
 591                if (ret < 0) {
 592                        up(&usb_bus_list_lock);
 593                        return ret;
 594                }
 595                total_written += ret;
 596        }
 597        up (&usb_bus_list_lock);
 598        return total_written;
 599}
 600
 601/* Kernel lock for "lastev" protection */
 602static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
 603{
 604        struct usb_device_status *st = (struct usb_device_status *)file->private_data;
 605        unsigned int mask = 0;
 606
 607        lock_kernel();
 608        if (!st) {
 609                st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
 610                if (!st) {
 611                        unlock_kernel();
 612                        return POLLIN;
 613                }
 614                /*
 615                 * need to prevent the module from being unloaded, since
 616                 * proc_unregister does not call the release method and
 617                 * we would have a memory leak
 618                 */
 619                st->lastev = conndiscevcnt;
 620                file->private_data = st;
 621                mask = POLLIN;
 622        }
 623        if (file->f_mode & FMODE_READ)
 624                poll_wait(file, &deviceconndiscwq, wait);
 625        if (st->lastev != conndiscevcnt)
 626                mask |= POLLIN;
 627        st->lastev = conndiscevcnt;
 628        unlock_kernel();
 629        return mask;
 630}
 631
 632static int usb_device_open(struct inode *inode, struct file *file)
 633{
 634        file->private_data = NULL;
 635        return 0;
 636}
 637
 638static int usb_device_release(struct inode *inode, struct file *file)
 639{
 640        if (file->private_data) {
 641                kfree(file->private_data);
 642                file->private_data = NULL;
 643        }
 644
 645        return 0;
 646}
 647
 648static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
 649{
 650        switch (orig) {
 651        case 0:
 652                file->f_pos = offset;
 653                return file->f_pos;
 654
 655        case 1:
 656                file->f_pos += offset;
 657                return file->f_pos;
 658
 659        case 2:
 660                return -EINVAL;
 661
 662        default:
 663                return -EINVAL;
 664        }
 665}
 666
 667struct file_operations usbdevfs_devices_fops = {
 668        llseek:         usb_device_lseek,
 669        read:           usb_device_read,
 670        poll:           usb_device_poll,
 671        open:           usb_device_open,
 672        release:        usb_device_release,
 673};
 674
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.