/[qemu]/qemu/usb-linux.c
ViewVC logotype

Diff of /qemu/usb-linux.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by bellard, Sat Nov 5 14:22:27 2005 UTC revision 1.2 by bellard, Sun Nov 6 16:13:29 2005 UTC
# Line 40  struct usb_ctrltransfer { Line 40  struct usb_ctrltransfer {
40      void *data;      void *data;
41  };  };
42    
43  //#define DEBUG  typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
44                            int vendor_id, int product_id,
45                            const char *product_name, int speed);
46    static int usb_host_find_device(int *pbus_num, int *paddr,
47                                    const char *devname);
48    
49  #define MAX_DEVICES 8  //#define DEBUG
50    
51  #define USBDEVFS_PATH "/proc/bus/usb"  #define USBDEVFS_PATH "/proc/bus/usb"
52    
# Line 51  typedef struct USBHostDevice { Line 55  typedef struct USBHostDevice {
55      int fd;      int fd;
56  } USBHostDevice;  } USBHostDevice;
57    
 typedef struct USBHostHubState {  
     USBDevice *hub_dev;  
     USBPort *hub_ports[MAX_DEVICES];  
     USBDevice *hub_devices[MAX_DEVICES];  
 } USBHostHubState;  
   
58  static void usb_host_handle_reset(USBDevice *dev)  static void usb_host_handle_reset(USBDevice *dev)
59  {  {
60  #if 0  #if 0
# Line 137  static int usb_host_handle_data(USBDevic Line 135  static int usb_host_handle_data(USBDevic
135      }      }
136  }  }
137    
 static int usb_host_handle_packet(USBDevice *dev, int pid,  
                                   uint8_t devaddr, uint8_t devep,  
                                   uint8_t *data, int len)  
 {  
     return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);  
 }  
   
138  /* XXX: exclude high speed devices or implement EHCI */  /* XXX: exclude high speed devices or implement EHCI */
139  static void scan_host_device(USBHostHubState *s, const char *filename)  USBDevice *usb_host_device_open(const char *devname)
140  {  {
141      int fd, interface, ret, i;      int fd, interface, ret, i;
142      USBHostDevice *dev;      USBHostDevice *dev;
143      struct usbdevfs_connectinfo ci;      struct usbdevfs_connectinfo ci;
144      uint8_t descr[1024];      uint8_t descr[1024];
145        char buf[1024];
146      int descr_len, dev_descr_len, config_descr_len, nb_interfaces;      int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
147        int bus_num, addr;
148    
149  #ifdef DEBUG      if (usb_host_find_device(&bus_num, &addr, devname) < 0)
150      printf("scanning %s\n", filename);          return NULL;
151  #endif      
152      fd = open(filename, O_RDWR);      snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
153                 bus_num, addr);
154        fd = open(buf, O_RDWR);
155      if (fd < 0) {      if (fd < 0) {
156          perror(filename);          perror(buf);
157          return;          return NULL;
158      }      }
159    
160      /* read the config description */      /* read the config description */
# Line 180  static void scan_host_device(USBHostHubS Line 175  static void scan_host_device(USBHostHubS
175      nb_interfaces = descr[i + 4];      nb_interfaces = descr[i + 4];
176      if (nb_interfaces != 1) {      if (nb_interfaces != 1) {
177          /* NOTE: currently we grab only one interface */          /* NOTE: currently we grab only one interface */
178            fprintf(stderr, "usb_host: only one interface supported\n");
179          goto fail;          goto fail;
180      }      }
181    
182    #ifdef USBDEVFS_DISCONNECT
183        /* earlier Linux 2.4 do not support that */
184        ret = ioctl(fd, USBDEVFS_DISCONNECT);
185        if (ret < 0 && errno != ENODATA) {
186            perror("USBDEVFS_DISCONNECT");
187            goto fail;
188        }
189    #endif
190    
191      /* XXX: only grab if all interfaces are free */      /* XXX: only grab if all interfaces are free */
192      interface = 0;      interface = 0;
193      ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);      ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
194      if (ret < 0) {      if (ret < 0) {
195          if (errno == EBUSY) {          if (errno == EBUSY) {
196  #ifdef DEBUG              fprintf(stderr, "usb_host: device already grabbed\n");
             printf("%s already grabbed\n", filename);  
 #endif              
197          } else {          } else {
198              perror("USBDEVFS_CLAIMINTERFACE");              perror("USBDEVFS_CLAIMINTERFACE");
199          }          }
200      fail:      fail:
201          close(fd);          close(fd);
202          return;          return NULL;
203      }      }
204    
205      ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);      ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
# Line 205  static void scan_host_device(USBHostHubS Line 209  static void scan_host_device(USBHostHubS
209      }      }
210    
211  #ifdef DEBUG  #ifdef DEBUG
212      printf("%s grabbed\n", filename);      printf("host USB device %d.%d grabbed\n", bus_num, addr);
213  #endif      #endif    
214    
     /* find a free slot */  
     for(i = 0; i < MAX_DEVICES; i++) {  
         if (!s->hub_devices[i])  
             break;  
     }  
     if (i == MAX_DEVICES) {  
 #ifdef DEBUG  
         printf("too many host devices\n");  
         goto fail;  
 #endif  
     }  
   
215      dev = qemu_mallocz(sizeof(USBHostDevice));      dev = qemu_mallocz(sizeof(USBHostDevice));
216      if (!dev)      if (!dev)
217          goto fail;          goto fail;
# Line 228  static void scan_host_device(USBHostHubS Line 220  static void scan_host_device(USBHostHubS
220          dev->dev.speed = USB_SPEED_LOW;          dev->dev.speed = USB_SPEED_LOW;
221      else      else
222          dev->dev.speed = USB_SPEED_HIGH;          dev->dev.speed = USB_SPEED_HIGH;
223      dev->dev.handle_packet = usb_host_handle_packet;      dev->dev.handle_packet = usb_generic_handle_packet;
224    
225      dev->dev.handle_reset = usb_host_handle_reset;      dev->dev.handle_reset = usb_host_handle_reset;
226      dev->dev.handle_control = usb_host_handle_control;      dev->dev.handle_control = usb_host_handle_control;
227      dev->dev.handle_data = usb_host_handle_data;      dev->dev.handle_data = usb_host_handle_data;
228        return (USBDevice *)dev;
229    }
230    
231      s->hub_devices[i] = (USBDevice *)dev;  static int get_tag_value(char *buf, int buf_size,
232                             const char *str, const char *tag,
233      /* activate device on hub */                           const char *stopchars)
234      usb_attach(s->hub_ports[i], s->hub_devices[i]);  {
235        const char *p;
236        char *q;
237        p = strstr(str, tag);
238        if (!p)
239            return -1;
240        p += strlen(tag);
241        while (isspace(*p))
242            p++;
243        q = buf;
244        while (*p != '\0' && !strchr(stopchars, *p)) {
245            if ((q - buf) < (buf_size - 1))
246                *q++ = *p;
247            p++;
248        }
249        *q = '\0';
250        return q - buf;
251  }  }
252    
253  static void scan_host_devices(USBHostHubState *s, const char *bus_path)  static int usb_host_scan(void *opaque, USBScanFunc *func)
254  {  {
255      DIR *d;      FILE *f;
256      struct dirent *de;      char line[1024];
257      char buf[1024];      char buf[1024];
258        int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
259      d = opendir(bus_path);      int ret;
260      if (!d)      char product_name[512];
261          return;      
262        f = fopen(USBDEVFS_PATH "/devices", "r");
263        if (!f) {
264            term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
265            return 0;
266        }
267        device_count = 0;
268        bus_num = addr = speed = class_id = product_id = vendor_id = 0;
269        ret = 0;
270      for(;;) {      for(;;) {
271          de = readdir(d);          if (fgets(line, sizeof(line), f) == NULL)
         if (!de)  
272              break;              break;
273          if (de->d_name[0] != '.') {          if (strlen(line) > 0)
274              snprintf(buf, sizeof(buf), "%s/%s", bus_path, de->d_name);              line[strlen(line) - 1] = '\0';
275              scan_host_device(s, buf);          if (line[0] == 'T' && line[1] == ':') {
276                if (device_count) {
277                    ret = func(opaque, bus_num, addr, class_id, vendor_id,
278                               product_id, product_name, speed);
279                    if (ret)
280                        goto the_end;
281                }
282                if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
283                    goto fail;
284                bus_num = atoi(buf);
285                if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
286                    goto fail;
287                addr = atoi(buf);
288                if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
289                    goto fail;
290                if (!strcmp(buf, "480"))
291                    speed = USB_SPEED_HIGH;
292                else if (!strcmp(buf, "1.5"))
293                    speed = USB_SPEED_LOW;
294                else
295                    speed = USB_SPEED_FULL;
296                product_name[0] = '\0';
297                class_id = 0xff;
298                device_count++;
299                product_id = 0;
300                vendor_id = 0;
301            } else if (line[0] == 'P' && line[1] == ':') {
302                if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
303                    goto fail;
304                vendor_id = strtoul(buf, NULL, 16);
305                if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
306                    goto fail;
307                product_id = strtoul(buf, NULL, 16);
308            } else if (line[0] == 'S' && line[1] == ':') {
309                if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
310                    goto fail;
311                pstrcpy(product_name, sizeof(product_name), buf);
312            } else if (line[0] == 'D' && line[1] == ':') {
313                if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
314                    goto fail;
315                class_id = strtoul(buf, NULL, 16);
316          }          }
317        fail: ;
318      }      }
319      closedir(d);      if (device_count) {
320            ret = func(opaque, bus_num, addr, class_id, vendor_id,
321                       product_id, product_name, speed);
322        }
323     the_end:
324        fclose(f);
325        return ret;
326  }  }
327    
328  static void scan_host_buses(USBHostHubState *s)  typedef struct FindDeviceState {
329        int vendor_id;
330        int product_id;
331        int bus_num;
332        int addr;
333    } FindDeviceState;
334    
335    static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
336                                         int class_id,
337                                         int vendor_id, int product_id,
338                                         const char *product_name, int speed)
339  {  {
340      DIR *d;      FindDeviceState *s = opaque;
341      struct dirent *de;      if (vendor_id == s->vendor_id &&
342      char buf[1024];          product_id == s->product_id) {
343            s->bus_num = bus_num;
344            s->addr = addr;
345            return 1;
346        } else {
347            return 0;
348        }
349    }
350    
351      d = opendir(USBDEVFS_PATH);  /* the syntax is :
352      if (!d)     'bus.addr' (decimal numbers) or
353          return;     'vendor_id:product_id' (hexa numbers) */
354      for(;;) {  static int usb_host_find_device(int *pbus_num, int *paddr,
355          de = readdir(d);                                  const char *devname)
356          if (!de)  {
357              break;      const char *p;
358          if (isdigit(de->d_name[0])) {      int ret;
359              snprintf(buf, sizeof(buf), "%s/%s", USBDEVFS_PATH, de->d_name);      FindDeviceState fs;
360              scan_host_devices(s, buf);  
361        p = strchr(devname, '.');
362        if (p) {
363            *pbus_num = strtoul(devname, NULL, 0);
364            *paddr = strtoul(p + 1, NULL, 0);
365            return 0;
366        }
367        p = strchr(devname, ':');
368        if (p) {
369            fs.vendor_id = strtoul(devname, NULL, 16);
370            fs.product_id = strtoul(p + 1, NULL, 16);
371            ret = usb_host_scan(&fs, usb_host_find_device_scan);
372            if (ret) {
373                *pbus_num = fs.bus_num;
374                *paddr = fs.addr;
375                return 0;
376          }          }
377      }      }
378      closedir(d);      return -1;
379  }  }
380    
381  /* virtual hub containing the USB devices of the host */  /**********************/
382  USBDevice *usb_host_hub_init(void)  /* USB host device info */
383    
384    struct usb_class_info {
385        int class;
386        const char *class_name;
387    };
388    
389    static const struct usb_class_info usb_class_info[] = {
390        { USB_CLASS_AUDIO, "Audio"},
391        { USB_CLASS_COMM, "Communication"},
392        { USB_CLASS_HID, "HID"},
393        { USB_CLASS_HUB, "Hub" },
394        { USB_CLASS_PHYSICAL, "Physical" },
395        { USB_CLASS_PRINTER, "Printer" },
396        { USB_CLASS_MASS_STORAGE, "Storage" },
397        { USB_CLASS_CDC_DATA, "Data" },
398        { USB_CLASS_APP_SPEC, "Application Specific" },
399        { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
400        { USB_CLASS_STILL_IMAGE, "Still Image" },
401        { USB_CLASS_CSCID,  "Smart Card" },
402        { USB_CLASS_CONTENT_SEC, "Content Security" },
403        { -1, NULL }
404    };
405    
406    static const char *usb_class_str(uint8_t class)
407  {  {
408      USBHostHubState *s;      const struct usb_class_info *p;
409      s = qemu_mallocz(sizeof(USBHostHubState));      for(p = usb_class_info; p->class != -1; p++) {
410      if (!s)          if (p->class == class)
411          return NULL;              break;
     s->hub_dev = usb_hub_init(s->hub_ports, MAX_DEVICES);  
     if (!s->hub_dev) {  
         free(s);  
         return NULL;  
412      }      }
413      scan_host_buses(s);      return p->class_name;
414      return s->hub_dev;  }
415    
416    void usb_info_device(int bus_num, int addr, int class_id,
417                         int vendor_id, int product_id,
418                         const char *product_name,
419                         int speed)
420    {
421        const char *class_str, *speed_str;
422    
423        switch(speed) {
424        case USB_SPEED_LOW:
425            speed_str = "1.5";
426            break;
427        case USB_SPEED_FULL:
428            speed_str = "12";
429            break;
430        case USB_SPEED_HIGH:
431            speed_str = "480";
432            break;
433        default:
434            speed_str = "?";
435            break;
436        }
437    
438        term_printf("  Device %d.%d, speed %s Mb/s\n",
439                    bus_num, addr, speed_str);
440        class_str = usb_class_str(class_id);
441        if (class_str)
442            term_printf("    %s:", class_str);
443        else
444            term_printf("    Class %02x:", class_id);
445        term_printf(" USB device %04x:%04x", vendor_id, product_id);
446        if (product_name[0] != '\0')
447            term_printf(", %s", product_name);
448        term_printf("\n");
449    }
450    
451    static int usb_host_info_device(void *opaque, int bus_num, int addr,
452                                    int class_id,
453                                    int vendor_id, int product_id,
454                                    const char *product_name,
455                                    int speed)
456    {
457        usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
458                        product_name, speed);
459        return 0;
460    }
461    
462    void usb_host_info(void)
463    {
464        usb_host_scan(NULL, usb_host_info_device);
465  }  }
466    
467  #else  #else
468    
469    void usb_host_info(void)
470    {
471        term_printf("USB host devices not supported\n");
472    }
473    
474  /* XXX: modify configure to compile the right host driver */  /* XXX: modify configure to compile the right host driver */
475  USBDevice *usb_host_hub_init(void)  USBDevice *usb_host_device_open(const char *devname)
476  {  {
477      return NULL;      return NULL;
478  }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26