Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

linux_usb.c

00001 /***************************************************************************
00002  * CVSID: $Id: linux_usb.c,v 1.13 2004/03/03 17:56:56 david Exp $
00003  *
00004  * linux_usb.c : USB handling on Linux 2.6
00005  *
00006  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
00007  *
00008  * Licensed under the Academic Free License version 2.0
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  **************************************************************************/
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #  include <config.h>
00028 #endif
00029 
00030 #include <ctype.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <getopt.h>
00035 #include <assert.h>
00036 #include <unistd.h>
00037 #include <stdarg.h>
00038 
00039 #include "../logger.h"
00040 #include "../device_store.h"
00041 #include "linux_usb.h"
00042 
00051 static char *usb_ids = NULL;
00052 
00054 static unsigned int usb_ids_len;
00055 
00057 static unsigned int usb_ids_iter_pos;
00058 
00060 static void
00061 usb_ids_line_iter_init ()
00062 {
00063     usb_ids_iter_pos = 0;
00064 }
00065 
00067 #define USB_IDS_MAX_LINE_LEN 512
00068 
00076 static char *
00077 usb_ids_line_iter_get_line (unsigned int *line_len)
00078 {
00079     unsigned int i;
00080     static char line[USB_IDS_MAX_LINE_LEN];
00081 
00082     for (i = 0;
00083          usb_ids_iter_pos < usb_ids_len &&
00084          i < USB_IDS_MAX_LINE_LEN - 1 &&
00085          usb_ids[usb_ids_iter_pos] != '\n'; i++, usb_ids_iter_pos++) {
00086         line[i] = usb_ids[usb_ids_iter_pos];
00087     }
00088 
00089     line[i] = '\0';
00090     if (line_len != NULL)
00091         *line_len = i;
00092 
00093     usb_ids_iter_pos++;
00094 
00095     return line;
00096 }
00097 
00102 static dbus_bool_t
00103 usb_ids_line_iter_has_more ()
00104 {
00105     return usb_ids_iter_pos < usb_ids_len;
00106 }
00107 
00118 static void
00119 usb_ids_find (int vendor_id, int product_id,
00120           char **vendor_name, char **product_name)
00121 {
00122     char *line;
00123     unsigned int i;
00124     unsigned int line_len;
00125     unsigned int num_tabs;
00126     char rep_vi[8];
00127     char rep_pi[8];
00128     static char store_vn[USB_IDS_MAX_LINE_LEN];
00129     static char store_pn[USB_IDS_MAX_LINE_LEN];
00130     dbus_bool_t vendor_matched = FALSE;
00131 
00132     snprintf (rep_vi, 8, "%04x", vendor_id);
00133     snprintf (rep_pi, 8, "%04x", product_id);
00134 
00135     *vendor_name = NULL;
00136     *product_name = NULL;
00137 
00138     for (usb_ids_line_iter_init (); usb_ids_line_iter_has_more ();) {
00139         line = usb_ids_line_iter_get_line (&line_len);
00140 
00141         /* skip lines with no content */
00142         if (line_len < 4)
00143             continue;
00144 
00145         /* skip comments */
00146         if (line[0] == '#')
00147             continue;
00148 
00149         /* count number of tabs */
00150         num_tabs = 0;
00151         for (i = 0; i < line_len; i++) {
00152             if (line[i] != '\t')
00153                 break;
00154             num_tabs++;
00155         }
00156 
00157         switch (num_tabs) {
00158         case 0:
00159             /* vendor names */
00160             vendor_matched = FALSE;
00161 
00162             /* check vendor_id */
00163             if (vendor_id != 0) {
00164                 if (memcmp (line, rep_vi, 4) == 0) {
00165                     /* found it */
00166                     vendor_matched = TRUE;
00167 
00168                     for (i = 4; i < line_len; i++) {
00169                         if (!isspace (line[i]))
00170                             break;
00171                     }
00172                     strncpy (store_vn, line + i,
00173                          USB_IDS_MAX_LINE_LEN);
00174                     *vendor_name = store_vn;
00175                 }
00176             }
00177             break;
00178 
00179         case 1:
00180             /* product names */
00181             if (!vendor_matched)
00182                 continue;
00183 
00184             /* check product_id */
00185             if (product_id != 0) {
00186                 if (memcmp (line + 1, rep_pi, 4) == 0) {
00187                     /* found it */
00188                     for (i = 5; i < line_len; i++) {
00189                         if (!isspace (line[i]))
00190                             break;
00191                     }
00192                     strncpy (store_pn, line + i,
00193                          USB_IDS_MAX_LINE_LEN);
00194                     *product_name = store_pn;
00195 
00196                     /* no need to continue the search */
00197                     return;
00198                 }
00199             }
00200             break;
00201 
00202         default:
00203             break;
00204         }
00205 
00206     }
00207 }
00208 
00216 static dbus_bool_t
00217 usb_ids_load (const char *path)
00218 {
00219     FILE *fp;
00220     unsigned int num_read;
00221 
00222     fp = fopen (path, "r");
00223     if (fp == NULL) {
00224         printf ("couldn't open USB database at %s,", path);
00225         return FALSE;
00226     }
00227 
00228     fseek (fp, 0, SEEK_END);
00229     usb_ids_len = ftell (fp);
00230     fseek (fp, 0, SEEK_SET);
00231 
00232     usb_ids = malloc (usb_ids_len);
00233     if (usb_ids == NULL) {
00234         printf
00235             ("Couldn't allocate %d bytes for USB database file\n",
00236              usb_ids_len);
00237         return FALSE;
00238     }
00239 
00240     num_read = fread (usb_ids, sizeof (char), usb_ids_len, fp);
00241     if (usb_ids_len != num_read) {
00242         printf ("Error loading USB database file\n");
00243         free (usb_ids);
00244         usb_ids = NULL;
00245         return FALSE;
00246     }
00247 
00248     return TRUE;
00249 }
00250 
00255 static dbus_bool_t
00256 usb_ids_free ()
00257 {
00258     if (usb_ids != NULL) {
00259         free (usb_ids);
00260         usb_ids = NULL;
00261         return TRUE;
00262     }
00263     return FALSE;
00264 }
00265 
00266 
00270 typedef struct usb_proc_info_s {
00271     int t_bus;       
00272     int t_level;         
00273     int t_parent;        
00274     int t_port;      
00275     int t_count;         
00276     int t_device;        
00277     int t_speed_bcd;     
00278     int t_max_children;  
00279     int d_version_bcd;   
00281     struct usb_proc_info_s *next;
00283 } usb_proc_info;
00284 
00286 static usb_proc_info *usb_proc_head = NULL;
00287 
00289 static usb_proc_info *usb_proc_cur_info = NULL;
00290 
00297 static usb_proc_info *
00298 usb_proc_find_virtual_hub (int bus_number)
00299 {
00300     usb_proc_info *i;
00301     for (i = usb_proc_head; i != NULL; i = i->next) {
00302         if (i->t_bus == bus_number && i->t_level == 0)
00303             return i;
00304     }
00305 
00306     return NULL;
00307 }
00308 
00309 
00317 static usb_proc_info *
00318 usb_proc_find_virtual_hub_child (int bus_number, int port_number)
00319 {
00320     usb_proc_info *i;
00321     for (i = usb_proc_head; i != NULL; i = i->next) {
00322         /* Note that /proc counts port starting from zero */
00323         if (i->t_bus == bus_number && i->t_level == 1 &&
00324             i->t_port == port_number - 1)
00325             return i;
00326     }
00327 
00328     return NULL;
00329 }
00330 
00339 static usb_proc_info *
00340 usb_proc_find_on_hub (int bus_number, int port_number,
00341               int parent_device_number)
00342 {
00343     usb_proc_info *i;
00344     for (i = usb_proc_head; i != NULL; i = i->next) {
00345         /* Note that /proc counts port starting from zero */
00346         if (i->t_bus == bus_number && i->t_port == port_number - 1
00347             && i->t_parent == parent_device_number)
00348             return i;
00349     }
00350 
00351     return NULL;
00352 }
00353 
00354 
00361 static void
00362 usb_proc_handle_topology (usb_proc_info * info, char *s)
00363 {
00364     info->t_bus = find_num ("Bus=", s, 10);
00365     info->t_level = find_num ("Lev=", s, 10);
00366     info->t_parent = find_num ("Prnt=", s, 10);
00367     info->t_port = find_num ("Port=", s, 10);
00368     info->t_count = find_num ("Cnt=", s, 10);
00369     info->t_device = find_num ("Dev#=", s, 10);
00370     info->t_speed_bcd = find_bcd2 ("Spd=", s);
00371     info->t_max_children = find_num ("MxCh=", s, 10);
00372 }
00373 
00380 static void
00381 usb_proc_handle_device_info (usb_proc_info * info, char *s)
00382 {
00383     info->d_version_bcd = find_bcd2 ("Ver=", s);
00384 }
00385 
00386 
00391 static void
00392 usb_proc_device_done (usb_proc_info * info)
00393 {
00394     info->next = usb_proc_head;
00395     usb_proc_head = info;
00396 }
00397 
00398 
00399 
00404 static void
00405 usb_proc_parse_line (char *s)
00406 {
00407     switch (s[0]) {
00408     case 'T':  /* topology; always present, indicates a new device */
00409         if (usb_proc_cur_info != NULL) {
00410             // beginning of a new device, done with current
00411             usb_proc_device_done (usb_proc_cur_info);
00412         }
00413 
00414         usb_proc_cur_info = malloc (sizeof (usb_proc_info));
00415 
00416         if (usb_proc_cur_info == NULL)
00417             DIE (("Cannot allocated memory"));
00418 
00419         usb_proc_handle_topology (usb_proc_cur_info, s);
00420         break;
00421 
00422     case 'B':       /* bandwidth */
00423         break;
00424 
00425     case 'D':       /* device information */
00426         usb_proc_handle_device_info (usb_proc_cur_info, s);
00427         break;
00428 
00429     case 'P':       /* more device information */
00430         break;
00431 
00432     case 'S':       /* device string information */
00433         break;
00434 
00435     case 'C':       /* config descriptor info */
00436         break;
00437 
00438     case 'I':       /* interface descriptor info */
00439         break;
00440 
00441     case 'E':       /* endpoint descriptor info */
00442         break;
00443 
00444     default:
00445         break;
00446     }
00447 }
00448 
00451 static void
00452 usb_proc_parse ()
00453 {
00454     FILE *f;
00455     char buf[256];
00456 
00457     /* We may be called multiple times; in fact we are called on every
00458      * hotplug.. so clean up old info
00459      */
00460     if (usb_proc_head != NULL) {
00461         usb_proc_info *i;
00462         usb_proc_info *next;
00463 
00464         for (i = usb_proc_head; i != NULL; i = next) {
00465             next = i->next;
00466             free (i);
00467         }
00468         usb_proc_head = NULL;
00469     }
00470 
00471     usb_proc_cur_info = NULL;
00472 
00473     f = fopen ("/proc/bus/usb/devices", "r");
00474     if (f == NULL)
00475         f = fopen
00476             ("/proc/bus/usb/devices_please-use-sysfs-instead",
00477              "r");
00478     if (f == NULL) {
00479         return;
00480     }
00481 
00482     while (!feof (f)) {
00483         fgets (buf, 256, f);
00484         usb_proc_parse_line (buf);
00485     }
00486     usb_proc_device_done (usb_proc_cur_info);
00487 
00488     {
00489         usb_proc_info *i;
00490         for (i = usb_proc_head; i != NULL; i = i->next) {
00491             printf ("/p/b/u/d entry\n");
00492             printf ("  bus               %d\n", i->t_bus);
00493             printf ("  level             %d\n", i->t_level);
00494             printf ("  parent            %d\n", i->t_parent);
00495             printf ("  port              %d\n", i->t_port);
00496             printf ("  count             %d\n", i->t_count);
00497             printf ("  device            %d\n", i->t_device);
00498             printf ("  speed_bcd         %x.%x (0x%06x)\n",
00499                 i->t_speed_bcd >> 8, i->t_speed_bcd & 0xff,
00500                 i->t_speed_bcd);
00501             printf ("  max_children      %d\n",
00502                 i->t_max_children);
00503             printf ("  version_bcd       %x.%x (0x%06x)\n",
00504                 i->d_version_bcd >> 8,
00505                 i->d_version_bcd & 0xff, i->d_version_bcd);
00506             printf ("\n");
00507         }
00508     }
00509 }
00510 
00511 
00521 static char *
00522 usbif_compute_udi (HalDevice * d, int append_num)
00523 {
00524     int i, len;
00525     const char *format;
00526     const char *pd;
00527     const char *name;
00528     static char buf[256];
00529 
00530     if (append_num == -1)
00531         format = "/org/freedesktop/Hal/devices/usbif_%s_%d";
00532     else
00533         format = "/org/freedesktop/Hal/devices/usbif_%s_%d-%d";
00534 
00535     pd = ds_property_get_string (d, "info.parent");
00536     len = strlen (pd);
00537     for (i = len - 1; pd[i] != '/' && i >= 0; i--);
00538     name = pd + i + 1;
00539 
00540     snprintf (buf, 256, format,
00541           name,
00542           ds_property_get_int (d, "usbif.number"), append_num);
00543 
00544     return buf;
00545 }
00546 
00547 
00567 static char *
00568 usb_compute_udi (HalDevice * d, int append_num)
00569 {
00570     const char *serial;
00571     const char *format;
00572     static char buf[256];
00573 
00574     if (append_num == -1)
00575         format = "/org/freedesktop/Hal/devices/usb_%x_%x_%x_%d_%s";
00576     else
00577         format =
00578             "/org/freedesktop/Hal/devices/usb_%x_%x_%x_%d_%s-%d";
00579 
00580     if (ds_property_exists (d, "usb.serial"))
00581         serial = ds_property_get_string (d, "usb.serial");
00582     else
00583         serial = "noserial";
00584 
00585     snprintf (buf, 256, format,
00586           ds_property_get_int (d, "usb.vendor_id"),
00587           ds_property_get_int (d, "usb.product_id"),
00588           ds_property_get_int (d, "usb.device_revision_bcd"),
00589           ds_property_get_int (d, "usb.cfg_value"),
00590           serial, append_num);
00591 
00592     return buf;
00593 }
00594 
00595 
00604 static void
00605 usb_add_caps_from_class (HalDevice * d,
00606              int if_class, int if_sub_class, int if_proto)
00607 {
00608     char *cat = NULL;
00609 
00610     switch (if_class) {
00611     case 0x01:
00612         cat = "multimedia.audio";
00613         ds_add_capability (d, "multimedia.audio");
00614         break;
00615     case 0x02:
00616         if (if_sub_class == 0x06) {
00617             cat = "net";
00618             ds_add_capability (d, "net");
00619             ds_add_capability (d, "net.ethernet");
00620         } else if (if_sub_class == 0x02 && if_proto == 0x01) {
00621             cat = "modem";
00622             ds_add_capability (d, "modem");
00623         }
00624         break;
00625     case 0x03:
00626         cat = "input";
00627         ds_add_capability (d, "input");
00628         if (if_sub_class == 0x00 || if_sub_class == 0x01) {
00629             if (if_proto == 0x01) {
00630                 cat = "input.keyboard";
00631                 ds_add_capability (d, "input.keyboard");
00632             } else if (if_proto == 0x02) {
00633                 cat = "input.mouse";
00634                 ds_add_capability (d, "input.mouse");
00635             }
00636         }
00637         break;
00638     case 0x04:
00639         break;
00640     case 0x05:
00641         break;
00642     case 0x06:
00643         break;
00644     case 0x07:
00645         cat = "printer";
00646         ds_add_capability (d, "printer");
00647         break;
00648     case 0x08:
00649         cat = "storage_controller";
00650         ds_add_capability (d, "storage_controller");
00651         break;
00652     case 0x09:
00653         cat = "hub";
00654         ds_add_capability (d, "hub");
00655         break;
00656     case 0x0a:
00657         break;
00658     case 0xe0:
00659         if (if_sub_class == 0x01 && if_proto == 0x01) {
00660             cat = "bluetooth_adaptor";
00661             ds_add_capability (d, "bluetooth_adaptor");
00662         }
00663         break;
00664     }
00665 
00666     if (cat != NULL)
00667         ds_property_set_string (d, "info.category", cat);
00668 }
00669 
00670 
00671 /* fwd decl */
00672 static void visit_device_usbif_got_parent (HalDevice * parent,
00673                        void *data1, void *data2);
00674 
00680 static void
00681 visit_device_usb_interface (const char *path, struct sysfs_device *device)
00682 {
00683     int i;
00684     int len;
00685     struct sysfs_attribute *cur;
00686     HalDevice *d;
00687     const char *driver;
00688     char attr_name[SYSFS_NAME_LEN];
00689     char *parent_sysfs_path;
00690 
00691     /*printf("usb_interface: path=%s\n", path); */
00692 
00693     /* Create HAL device representing the interface */
00694     d = ds_device_new ();
00695     ds_property_set_string (d, "info.bus", "usbif");
00696     ds_property_set_string (d, "linux.sysfs_path", path);
00697     ds_property_set_string (d, "linux.sysfs_path_device", path);
00702     ds_property_set_string (d, "usbif.linux.sysfs_path", path);
00703     ds_property_set_bool (d, "info.virtual", TRUE);
00704 
00705     /* set driver */
00706     driver = drivers_lookup (path);
00707     if (driver != NULL)
00708         ds_property_set_string (d, "linux.driver", driver);
00709 
00710 
00711     if (device->directory == NULL
00712         || device->directory->attributes == NULL)
00713         return;
00714 
00715     dlist_for_each_data (sysfs_get_device_attributes (device), cur,
00716                  struct sysfs_attribute) {
00717 
00718         if (sysfs_get_name_from_path (cur->path,
00719                           attr_name,
00720                           SYSFS_NAME_LEN) != 0)
00721             continue;
00722 
00723         /* strip whitespace */
00724         len = strlen (cur->value);
00725         for (i = len - 1; i > 0 && isspace (cur->value[i]); --i)
00726             cur->value[i] = '\0';
00727 
00728         /*printf("attr_name=%s -> '%s'\n", attr_name, cur->value); */
00729 
00730         if (strcmp (attr_name, "bInterfaceClass") == 0)
00731             ds_property_set_int (d, "usbif.interface_class",
00732                          parse_dec (cur->value));
00733         else if (strcmp (attr_name, "bInterfaceSubClass") == 0)
00734             ds_property_set_int (d, "usbif.interface_subclass",
00735                          parse_dec (cur->value));
00736         else if (strcmp (attr_name, "bInterfaceProtocol") == 0)
00737             ds_property_set_int (d, "usbif.interface_protocol",
00738                          parse_dec (cur->value));
00739         else if (strcmp (attr_name, "bInterfaceNumber") == 0)
00740             ds_property_set_int (d, "usbif.number",
00741                          parse_dec (cur->value));
00742     }
00743 
00744     parent_sysfs_path = get_parent_sysfs_path (path);
00745 
00746     /* Find parent; this happens asynchronously as our parent might
00747      * be added later. If we are probing this can't happen so the
00748      * timeout is set to zero in that event..
00749      */
00750     ds_device_async_find_by_key_value_string
00751         ("linux.sysfs_path_device", parent_sysfs_path, TRUE,
00752          visit_device_usbif_got_parent, (void *) d, NULL,
00753          is_probing ? 0 : HAL_LINUX_HOTPLUG_TIMEOUT);
00754 
00755     free (parent_sysfs_path);
00756 }
00757 
00765 static void
00766 visit_device_usbif_got_parent (HalDevice * parent,
00767                    void *data1, void *data2)
00768 {
00769     char *new_udi = NULL;
00770     HalDevice *new_d = NULL;
00771     HalDevice *d = (HalDevice *) data1;
00772 
00773     if (parent == NULL) {
00774         /* An USB interface should always have a parent! */
00775         HAL_ERROR (("No parent for USB interface!"));
00776         ds_device_destroy (d);
00777         return;
00778     }
00779 
00780     ds_property_set_string (d, "info.parent", parent->udi);
00781 
00782     /* We set the caps derived from this USB interface on the parent USB
00783      * device 
00784      */
00785     usb_add_caps_from_class (parent,
00786                  ds_property_get_int (d,
00787                               "usbif.interface_class"),
00788                  ds_property_get_int (d,
00789                            "usbif.interface_subclass"),
00790                  ds_property_get_int (d,
00791                           "usbif.interface_protocol"));
00792 
00793     ds_property_set_string (d, "info.parent", parent->udi);
00794     ds_property_set_string (d, "info.physical_device", parent->udi);
00795     ds_property_set_int (d, "usbif.device_vendor_id",
00796                  ds_property_get_int (parent,
00797                           "usb.vendor_id"));
00798     ds_property_set_int (d, "usbif.device_product_id",
00799                  ds_property_get_int (parent,
00800                           "usb.product_id"));
00801 
00802     new_udi = rename_and_merge (d, usbif_compute_udi, "usbif");
00803     if (new_udi != NULL) {
00804         new_d = ds_device_find (new_udi);
00805         if (new_d != NULL) {
00806             ds_gdl_add (new_d);
00807         }
00808     }
00809 
00810 }
00811 
00812 
00813 /* fwd decl */
00814 static void visit_device_usb_got_parent (HalDevice * parent,
00815                      void *data1, void *data2);
00816 
00825 void
00826 visit_device_usb (const char *path, struct sysfs_device *device)
00827 {
00828     int i;
00829     int len;
00830     dbus_bool_t is_interface;
00831     struct sysfs_attribute *cur;
00832     HalDevice *d;
00833     char attr_name[SYSFS_NAME_LEN];
00834     int vendor_id = 0;
00835     int product_id = 0;
00836     char *vendor_name;
00837     char *product_name;
00838     char *vendor_name_kernel = NULL;
00839     char *product_name_kernel = NULL;
00840     const char *driver;
00841     char *parent_sysfs_path;
00842     char numeric_name[32];
00843 
00844     /*printf("usb: %s, bus_id=%s\n", path, device->bus_id); */
00845 
00846     if (device->directory == NULL
00847         || device->directory->attributes == NULL)
00848         return;
00849 
00850     /* Check if this is an USB interface */
00851     is_interface = FALSE;
00852     for (i = 0; device->bus_id[i] != 0; i++) {
00853         if (device->bus_id[i] == ':') {
00854             is_interface = TRUE;
00855             break;
00856         }
00857     }
00858 
00859     /* USB interfaces are handled by a separate function */
00860     if (is_interface) {
00861         HAL_INFO (("usb device @ %s is an interface", path));
00862         visit_device_usb_interface (path, device);
00863         return;
00864     }
00865 
00866     /* Must be a new USB device */
00867     d = ds_device_new ();
00868     ds_property_set_string (d, "info.bus", "usb");
00869     ds_property_set_string (d, "linux.sysfs_path", path);
00870     ds_property_set_string (d, "linux.sysfs_bus_id", device->bus_id);
00871     ds_property_set_string (d, "linux.sysfs_path_device", path);
00872 
00880     ds_property_set_string (d, "usb.linux.sysfs_path", path);
00881     /*printf("*** created udi=%s for path=%s\n", d, path); */
00882 
00883     /* set driver */
00884     driver = drivers_lookup (path);
00885     if (driver != NULL)
00886         ds_property_set_string (d, "linux.driver", driver);
00887 
00888     dlist_for_each_data (sysfs_get_device_attributes (device), cur,
00889                  struct sysfs_attribute) {
00890 
00891         if (sysfs_get_name_from_path (cur->path,
00892                           attr_name,
00893                           SYSFS_NAME_LEN) != 0)
00894             continue;
00895 
00896         /* strip whitespace */
00897         len = strlen (cur->value);
00898         for (i = len - 1; i >= 0 && isspace (cur->value[i]); --i)
00899             cur->value[i] = '\0';
00900 
00901         /*printf("attr_name=%s -> '%s'\n", attr_name, cur->value); */
00902 
00903         if (strcmp (attr_name, "idProduct") == 0)
00904             product_id = parse_hex (cur->value);
00905         else if (strcmp (attr_name, "idVendor") == 0)
00906             vendor_id = parse_hex (cur->value);
00907         else if (strcmp (attr_name, "bcdDevice") == 0)
00908             ds_property_set_int (d, "usb.device_revision_bcd",
00909                          parse_hex (cur->value));
00910         else if (strcmp (attr_name, "bMaxPower") == 0)
00911             ds_property_set_int (d, "usb.max_power",
00912                          parse_dec (cur->value));
00913         else if (strcmp (attr_name, "serial") == 0
00914              && strlen (cur->value) > 0)
00915             ds_property_set_string (d, "usb.serial",
00916                         cur->value);
00917         else if (strcmp (attr_name, "bmAttributes") == 0) {
00918             int bmAttributes = parse_hex (cur->value);
00919 
00920             /* USB_CONFIG_ATT_SELFPOWER */
00921             ds_property_set_bool (d, "usb.is_self_powered",
00922                           (bmAttributes & 0x40) != 0);
00923             ds_property_set_bool (d, "usb.can_wake_up",
00924                           (bmAttributes & 0x20) != 0);
00925         }
00926 /*
00927         else if( strcmp(attr_name, "speed")==0 )
00928             hal_device_set_property_double(d, "usb.speed", 
00929                                            parse_double(cur->value));
00930 */
00931 
00932         else if (strcmp (attr_name, "manufacturer") == 0)
00933             vendor_name_kernel = cur->value;
00934         else if (strcmp (attr_name, "product") == 0)
00935             product_name_kernel = cur->value;
00936         else if (strcmp (attr_name, "bDeviceClass") == 0)
00937             ds_property_set_int (d, "usb.device_class",
00938                          parse_hex (cur->value));
00939         else if (strcmp (attr_name, "bDeviceSubClass") == 0)
00940             ds_property_set_int (d, "usb.device_subclass",
00941                          parse_hex (cur->value));
00942         else if (strcmp (attr_name, "bDeviceProtocol") == 0)
00943             ds_property_set_int (d, "usb.device_protocol",
00944                          parse_hex (cur->value));
00945 
00946         else if (strcmp (attr_name, "bNumConfigurations") == 0)
00947             ds_property_set_int (d, "usb.num_configurations",
00948                          parse_dec (cur->value));
00949         else if (strcmp (attr_name, "bConfigurationValue") == 0)
00950             ds_property_set_int (d, "usb.configuration_value",
00951                          parse_dec (cur->value));
00952 
00953         else if (strcmp (attr_name, "bNumInterfaces") == 0)
00954             ds_property_set_int (d, "usb.num_interfaces",
00955                          parse_dec (cur->value));
00956 
00957     }           /* for all attributes */
00958 
00959     ds_property_set_int (d, "usb.product_id", product_id);
00960     ds_property_set_int (d, "usb.vendor_id", vendor_id);
00961 
00962     /* Lookup names in usb.ids; these may override what the kernel told
00963      * us, but, hey, it's only a name; it's not something we are going
00964      * to match a device on... We prefer names from usb.ids as the kernel
00965      * name sometimes is just a hexnumber :-/
00966      *
00967      * Also provide best guess on name, Product and Vendor properties;
00968      * these can both be overridden in .fdi files.
00969      */
00970     usb_ids_find (vendor_id, product_id, &vendor_name, &product_name);
00971     if (vendor_name != NULL) {
00972         ds_property_set_string (d, "usb.vendor", vendor_name);
00973         ds_property_set_string (d, "info.vendor", vendor_name);
00974     } else if (vendor_name_kernel != NULL) {
00975         /* fallback on name supplied from kernel */
00976         ds_property_set_string (d, "usb.vendor",
00977                     vendor_name_kernel);
00978         ds_property_set_string (d, "info.vendor",
00979                     vendor_name_kernel);
00980     } else {
00981         /* last resort; use numeric name */
00982         snprintf (numeric_name, 32, "Unknown (0x%04x)", vendor_id);
00983         ds_property_set_string (d, "usb.vendor", numeric_name);
00984         ds_property_set_string (d, "info.vendor", numeric_name);
00985     }
00986 
00987     if (product_name != NULL) {
00988         ds_property_set_string (d, "usb.product", product_name);
00989         ds_property_set_string (d, "info.product", product_name);
00990     } else if (product_name_kernel != NULL) {
00991         /* name supplied from kernel (if available) */
00992         ds_property_set_string (d, "usb.product",
00993                     product_name_kernel);
00994         ds_property_set_string (d, "info.product",
00995                     product_name_kernel);
00996     } else {
00997         /* last resort; use numeric name */
00998         snprintf (numeric_name, 32, "Unknown (0x%04x)",
00999               product_id);
01000         ds_property_set_string (d, "usb.product", numeric_name);
01001         ds_property_set_string (d, "info.product", numeric_name);
01002     }
01003 
01004 
01005     /* Check device class */
01006     usb_add_caps_from_class (d,
01007                  ds_property_get_int (d,
01008                               "usb.device_class"),
01009                  ds_property_get_int (d,
01010                               "usb.device_subclass"),
01011                  ds_property_get_int (d,
01012                               "usb.device_protocol"));
01013 
01014     parent_sysfs_path = get_parent_sysfs_path (path);
01015 
01016     /* Find parent; this happens asynchronously as our parent might
01017      * be added later. If we are probing this can't happen so the
01018      * timeout is set to zero in that event..
01019      */
01020     ds_device_async_find_by_key_value_string
01021         ("linux.sysfs_path_device", parent_sysfs_path, TRUE,
01022          visit_device_usb_got_parent, (void *) d, NULL,
01023          is_probing ? 0 : HAL_LINUX_HOTPLUG_TIMEOUT);
01024 
01025     free (parent_sysfs_path);
01026 }
01027 
01035 static void
01036 visit_device_usb_got_parent (HalDevice * parent, void *data1, void *data2)
01037 {
01038     char *new_udi = NULL;
01039     HalDevice *new_d = NULL;
01040     int bus_number;
01041     const char *bus_id;
01042     usb_proc_info *proc_info;
01043     HalDevice *d = (HalDevice *) data1;
01044 
01045     if (parent != NULL) {
01046         ds_property_set_string (d, "info.parent", parent->udi);
01047     } else {
01048         /* An USB device should always have a parent! */
01049         HAL_WARNING (("No parent for USB device!"));
01050     }
01051 
01052     /* Merge information from /proc/bus/usb/devices */
01053     proc_info = NULL;
01054 
01055     bus_id = ds_property_get_string (d, "linux.sysfs_bus_id");
01056 
01057     if (!is_probing) {
01058         /* reload proc info if we are not probing on startup */
01059         usb_proc_parse ();
01060     }
01061 
01062     if (sscanf (bus_id, "usb%d", &bus_number) == 1) {
01063         /* Is of form "usb%d" which means that this is a USB virtual 
01064          * root hub, cf. drivers/usb/hcd.c in kernel 2.6
01065          */
01066         ds_property_set_int (d, "usb.bus_number", bus_number);
01067 
01068         proc_info = usb_proc_find_virtual_hub (bus_number);
01069     } else {
01070         int i;
01071         int len;
01072         int digit;
01073         int port_number;
01074         /* Not a root hub; According to the Linux kernel sources,
01075          * the name is of the form
01076          *
01077          *  "%d-%s[.%d]"
01078          *
01079          * where the first number is the bus-number, the middle string 
01080          * is the parent device and the last, optional, number is the 
01081          * port number in the event that the USB device is a hub.
01082          */
01083 
01084         len = strlen (bus_id);
01085 
01086         /* the first part is easy */
01087         bus_number = atoi (bus_id);
01088 
01089         ds_property_set_int (d, "usb.bus_number", bus_number);
01090 
01091         /* The naming convention also guarantees that
01092          *
01093          *   device is on a (non-virtual) hub    
01094          *
01095          *            IF AND ONLY IF  
01096          *
01097          *   the bus_id contains a "."
01098          */
01099         for (i = 0; i < len; i++) {
01100             if (bus_id[i] == '.')
01101                 break;
01102         }
01103 
01104         if (i == len) {
01105             /* Not on a hub; this means we must be a child of the 
01106              * root hub... Thus the name must is of the 
01107              * form "%d-%d"
01108              */
01109             if (sscanf (bus_id, "%d-%d",
01110                     &bus_number, &port_number) == 2) {
01111 
01112                 proc_info =
01113                     usb_proc_find_virtual_hub_child
01114                     (bus_number, port_number);
01115                 ds_property_set_int (d, "usb.port_number",
01116                              port_number);
01117             }
01118         } else {
01119             int parent_device_number;
01120 
01121             /* On a hub */
01122 
01123             /* This is quite a hack */
01124             port_number = 0;
01125             for (i = len - 1; i > 0 && isdigit (bus_id[i]);
01126                  --i) {
01127                 digit = (int) (bus_id[i] - '0');
01128                 port_number *= 10;
01129                 port_number += digit;
01130             }
01131 
01132             ds_property_set_int (d, "usb.port_number",
01133                          port_number);
01134 
01135             /* Ok, got the port number and bus number; this is 
01136              * not quite enough though.. We take the 
01137              * usb.linux.device_number from our parent and then
01138              *  we are set.. */
01139             if (parent == NULL) {
01140                 HAL_WARNING (("USB device is on a hub but "
01141                           "no parent??"));
01142                 /* have to give up then */
01143                 proc_info = NULL;
01144             } else {
01145                 parent_device_number =
01146                     ds_property_get_int (
01147                         parent, "usb.linux.device_number");
01148                 //printf("parent_device_number = %d\n", parent_device_number);
01149                 proc_info =
01150                     usb_proc_find_on_hub (bus_number,
01151                               port_number,
01152                              parent_device_number);
01153             }
01154 
01155         }
01156     }
01157 
01158 
01159     if (proc_info != NULL) {
01160         char kernel_path[32 + 1];
01161 
01162         ds_property_set_int (d, "usb.level_number",
01163                      proc_info->t_level);
01164         ds_property_set_int (d, "usb.linux.device_number",
01165                      proc_info->t_device);
01166         ds_property_set_int (d, "usb.linux.parent_number",
01167                      proc_info->t_device);
01168         ds_property_set_int (d, "usb.num_ports",
01169                      proc_info->t_max_children);
01170         ds_property_set_int (d, "usb.speed_bcd",
01171                      proc_info->t_speed_bcd);
01172         ds_property_set_int (d, "usb.version_bcd",
01173                      proc_info->d_version_bcd);
01174 
01175         /* Ok, now compute the unique name that the kernel sometimes 
01176          * use to refer to the device; it's #usb_make_path() as 
01177          * defined in include/linux/usb.h
01178          */
01179         if (proc_info->t_level == 0) {
01180             snprintf (kernel_path, 32, "usb-%s",
01181                   ds_property_get_string (d,
01182                               "usb.serial"));
01183             ds_property_set_string (d, "linux.kernel_devname",
01184                         kernel_path);
01185         } else {
01186             if (parent != NULL) {
01187                 if (proc_info->t_level == 1) {
01188                     snprintf (kernel_path, 32, "%s-%d",
01189                           ds_property_get_string
01190                           (parent,
01191                            "linux.kernel_devname"),
01192                           ds_property_get_int (
01193                               d,
01194                               "usb.port_number"));
01195                 } else {
01196                     snprintf (kernel_path, 32, "%s.%d",
01197                           ds_property_get_string
01198                           (parent,
01199                            "linux.kernel_devname"),
01200                           ds_property_get_int (
01201                               d,
01202                               "usb.port_number"));
01203                 }
01204                 ds_property_set_string (d,
01205                             "linux.kernel_devname",
01206                             kernel_path);
01207             }
01208         }
01209 
01210     }
01211 
01212     /* Uncomment this line to test that sleeping works when handling USB
01213      * interfaces on not-yet added USB devices
01214      *
01215      * (you might need to tweak number of seconds to fit with your system)
01216      */
01217     /*sleep(5); */
01218 
01219     /* Finally, Compute a proper UDI (unique device id), try to locate
01220      * a persistent unplugged device or add it
01221      */
01222     new_udi = rename_and_merge (d, usb_compute_udi, "usb");
01223     if (new_udi != NULL) {
01224         new_d = ds_device_find (new_udi);
01225         if (new_d != NULL) {
01226             ds_gdl_add (new_d);
01227         }
01228     }
01229 }
01230 
01231 
01235 void
01236 linux_usb_init ()
01237 {
01238 
01239     /* get all drivers under /sys/bus/usb/drivers */
01240     drivers_collect ("usb");
01241 
01242     /* Load /usr/share/hwdata/usb.ids */
01243     usb_ids_load (HWDATA_DIR "/usb.ids");
01244 
01245     /* Parse /proc/bus/usb/devices */
01246 
01247     usb_proc_parse ();
01248 }
01249 
01254 void
01255 linux_usb_detection_done ()
01256 {
01257 }
01258 
01259 
01263 void
01264 linux_usb_shutdown ()
01265 {
01266     usb_ids_free ();
01267 }
01268 

Generated on Thu Mar 11 21:32:23 2004 for HAL by doxygen 1.3.6-20040222