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

linux_usb.c

00001 /***************************************************************************
00002  * CVSID: $Id: linux_usb.c,v 1.10 2004/01/02 12:11:24 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 usb_ids_line_iter_init()
00061 {
00062     usb_ids_iter_pos = 0;
00063 }
00064 
00066 #define USB_IDS_MAX_LINE_LEN 512
00067 
00075 static char* usb_ids_line_iter_get_line(unsigned int* line_len)
00076 {
00077     unsigned int i;
00078     static char line[USB_IDS_MAX_LINE_LEN];
00079 
00080     for(i=0; 
00081         usb_ids_iter_pos<usb_ids_len && 
00082             i<USB_IDS_MAX_LINE_LEN-1 && 
00083             usb_ids[usb_ids_iter_pos]!='\n';
00084         i++, usb_ids_iter_pos++)
00085     {
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 usb_ids_line_iter_has_more()
00103 {
00104     return usb_ids_iter_pos<usb_ids_len;
00105 }
00106 
00117 static void usb_ids_find(int vendor_id, int product_id,
00118                          char** vendor_name, char** product_name)
00119 {
00120     char* line;
00121     unsigned int i;
00122     unsigned int line_len;
00123     unsigned int num_tabs;
00124     char rep_vi[8];
00125     char rep_pi[8];
00126     static char store_vn[USB_IDS_MAX_LINE_LEN];
00127     static char store_pn[USB_IDS_MAX_LINE_LEN];
00128     dbus_bool_t vendor_matched=FALSE;
00129 
00130     snprintf(rep_vi, 8, "%04x", vendor_id);
00131     snprintf(rep_pi, 8, "%04x", product_id);
00132 
00133     *vendor_name = NULL;
00134     *product_name = NULL;
00135 
00136     for(usb_ids_line_iter_init(); usb_ids_line_iter_has_more(); )
00137     {
00138         line = usb_ids_line_iter_get_line(&line_len);
00139 
00140         /* skip lines with no content */
00141         if( line_len<4 )
00142             continue;
00143 
00144         /* skip comments */
00145         if( line[0]=='#' )
00146             continue;
00147 
00148         /* count number of tabs */
00149         num_tabs = 0;
00150         for(i=0; i<line_len; i++)
00151         {
00152             if( line[i]!='\t' )
00153                 break;
00154             num_tabs++;
00155         }
00156 
00157         switch( num_tabs )
00158         {
00159         case 0:
00160             /* vendor names */
00161             vendor_matched = FALSE;
00162 
00163             /* check vendor_id */
00164             if( vendor_id!=0 )
00165             {
00166                 if( memcmp(line, rep_vi, 4)==0 )
00167                 {
00168                     /* found it */
00169                     vendor_matched = TRUE;
00170 
00171                     for(i=4; i<line_len; i++)
00172                     {
00173                         if( !isspace(line[i]) )
00174                             break;
00175                     }
00176                     strncpy(store_vn, line+i, USB_IDS_MAX_LINE_LEN);
00177                     *vendor_name = store_vn;
00178                 }
00179             }            
00180             break;
00181 
00182         case 1:
00183             /* product names */
00184             if( !vendor_matched )
00185                 continue;
00186 
00187             /* check product_id */
00188             if( product_id!=0 )
00189             {
00190                 if( memcmp(line+1, rep_pi, 4)==0 )
00191                 {
00192                     /* found it */
00193                     for(i=5; i<line_len; i++)
00194                     {
00195                         if( !isspace(line[i]) )
00196                             break;
00197                     }
00198                     strncpy(store_pn, line+i, USB_IDS_MAX_LINE_LEN);
00199                     *product_name = store_pn;
00200 
00201                     /* no need to continue the search */
00202                     return;
00203                 }
00204             }
00205             break;
00206 
00207         default:
00208             break;
00209         }
00210         
00211     }
00212 }
00213 
00221 static dbus_bool_t usb_ids_load(const char* path)
00222 {
00223     FILE* fp;
00224     unsigned int num_read;
00225 
00226     fp = fopen(path, "r");
00227     if( fp==NULL )
00228     {
00229         printf("couldn't open USB database at %s,", path);
00230         return FALSE;
00231     }
00232 
00233     fseek(fp, 0, SEEK_END);
00234     usb_ids_len = ftell(fp);
00235     fseek(fp, 0, SEEK_SET);
00236 
00237     usb_ids = malloc(usb_ids_len);
00238     if( usb_ids==NULL )
00239     {
00240         printf("Couldn't allocate %d bytes for USB database file\n",
00241                usb_ids_len);
00242         return FALSE;
00243     }
00244     
00245     num_read = fread(usb_ids, sizeof(char), usb_ids_len, fp);
00246     if( usb_ids_len!=num_read )
00247     {
00248         printf("Error loading USB database file\n");
00249         free(usb_ids);
00250         usb_ids=NULL;
00251         return FALSE;
00252     }    
00253 
00254     return TRUE;
00255 }
00256 
00261 static dbus_bool_t usb_ids_free()
00262 {
00263     if( usb_ids!=NULL )
00264     {
00265         free(usb_ids);
00266         usb_ids=NULL;
00267         return TRUE;
00268     }
00269     return FALSE;
00270 }
00271 
00272 
00276 typedef struct usb_proc_info_s
00277 {
00278     int t_bus;               
00279     int t_level;             
00280     int t_parent;            
00281     int t_port;              
00282     int t_count;             
00283     int t_device;            
00284     int t_speed_bcd;         
00285     int t_max_children;      
00286     int d_version_bcd;       
00288     struct usb_proc_info_s* next; 
00289 } usb_proc_info;
00290 
00292 static usb_proc_info* usb_proc_head = NULL;
00293 
00295 static usb_proc_info* usb_proc_cur_info = NULL;
00296 
00303 static usb_proc_info* usb_proc_find_virtual_hub(int bus_number)
00304 {
00305     usb_proc_info* i;
00306     for(i=usb_proc_head; i!=NULL; i=i->next)
00307     {
00308         if( i->t_bus==bus_number && i->t_level==0 )
00309             return i;
00310     }
00311 
00312     return NULL;
00313 }
00314 
00315 
00323 static usb_proc_info* usb_proc_find_virtual_hub_child(int bus_number,
00324                                                       int port_number)
00325 {
00326     usb_proc_info* i;
00327     for(i=usb_proc_head; i!=NULL; i=i->next)
00328     {
00329         /* Note that /proc counts port starting from zero */
00330         if( i->t_bus==bus_number && i->t_level==1 && 
00331             i->t_port==port_number-1 )
00332             return i;
00333     }
00334 
00335     return NULL;
00336 }
00337 
00346 static usb_proc_info* usb_proc_find_on_hub(int bus_number, int port_number, 
00347                                            int parent_device_number)
00348 {
00349     usb_proc_info* i;
00350     for(i=usb_proc_head; i!=NULL; i=i->next)
00351     {
00352         /* Note that /proc counts port starting from zero */
00353         if( i->t_bus==bus_number  && i->t_port==port_number-1 && 
00354             i->t_parent==parent_device_number )
00355             return i;
00356     }
00357 
00358     return NULL;
00359 }
00360 
00361 
00368 static void usb_proc_handle_topology(usb_proc_info* info, char* s)
00369 {
00370     info->t_bus = find_num("Bus=", s, 10);
00371     info->t_level = find_num("Lev=", s, 10);
00372     info->t_parent = find_num("Prnt=", s, 10);
00373     info->t_port = find_num("Port=", s, 10);
00374     info->t_count = find_num("Cnt=", s, 10);
00375     info->t_device = find_num("Dev#=",s, 10);
00376     info->t_speed_bcd = find_bcd2("Spd=",s);
00377     info->t_max_children = find_num("MxCh=",s, 10);
00378 }
00379 
00386 static void usb_proc_handle_device_info(usb_proc_info* info, char* s)
00387 {
00388     info->d_version_bcd = find_bcd2("Ver=",s);
00389 }
00390 
00391 
00396 static void usb_proc_device_done(usb_proc_info* info)
00397 {
00398     info->next = usb_proc_head;
00399     usb_proc_head = info;
00400 }
00401 
00402 
00403 
00408 static void usb_proc_parse_line(char* s)
00409 {
00410     switch( s[0] )
00411     {
00412     case 'T': /* topology; always present, indicates a new device */
00413         if( usb_proc_cur_info!=NULL )
00414         {
00415             // beginning of a new device, done with current
00416             usb_proc_device_done(usb_proc_cur_info);
00417         }
00418 
00419         usb_proc_cur_info = malloc(sizeof(usb_proc_info));
00420 
00421         if( usb_proc_cur_info==NULL )
00422             DIE(("Cannot allocated memory"));
00423 
00424         usb_proc_handle_topology(usb_proc_cur_info, s);
00425         break;
00426 
00427     case 'B': /* bandwidth */
00428         break;
00429 
00430     case 'D': /* device information */
00431         usb_proc_handle_device_info(usb_proc_cur_info, s);
00432         break;
00433 
00434     case 'P': /* more device information */
00435         break;
00436 
00437     case 'S': /* device string information */
00438         break;
00439 
00440     case 'C': /* config descriptor info */
00441         break;
00442 
00443     case 'I': /* interface descriptor info */
00444         break;
00445 
00446     case 'E': /* endpoint descriptor info */
00447         break;
00448 
00449     default:
00450         break;
00451     }
00452 }
00453 
00456 static void usb_proc_parse()
00457 {
00458     FILE* f;
00459     char buf[256];
00460 
00461     /* We may be called multiple times; in fact we are called on every
00462      * hotplug.. so clean up old info
00463      */
00464     if( usb_proc_head!=NULL )
00465     {
00466         usb_proc_info* i;
00467         usb_proc_info* next;
00468 
00469         for(i=usb_proc_head; i!=NULL; i=next)
00470         {
00471             next = i->next;
00472             free(i);
00473         }
00474         usb_proc_head = NULL;
00475     }
00476 
00477     usb_proc_cur_info = NULL;
00478 
00479     f = fopen("/proc/bus/usb/devices", "r");
00480     if( f==NULL )
00481     {
00482         DIE(("Couldn't open /proc/bus/usb/devices"));
00483     }
00484 
00485     while( !feof(f) )
00486     {
00487         fgets(buf, 256, f);
00488         usb_proc_parse_line(buf);
00489     }
00490     usb_proc_device_done(usb_proc_cur_info);
00491 
00492     {
00493         usb_proc_info* i;
00494         for(i=usb_proc_head; i!=NULL; i=i->next)
00495         {
00496             printf("/p/b/u/d entry\n");
00497             printf("  bus               %d\n", i->t_bus);
00498             printf("  level             %d\n", i->t_level);
00499             printf("  parent            %d\n", i->t_parent);
00500             printf("  port              %d\n", i->t_port);
00501             printf("  count             %d\n", i->t_count);
00502             printf("  device            %d\n", i->t_device);
00503             printf("  speed_bcd         %x.%x (0x%06x)\n", i->t_speed_bcd>>8, 
00504                    i->t_speed_bcd&0xff, i->t_speed_bcd);
00505             printf("  max_children      %d\n", i->t_max_children);
00506             printf("  version_bcd       %x.%x (0x%06x)\n", i->d_version_bcd>>8,
00507                    i->d_version_bcd&0xff, i->d_version_bcd);
00508             printf("\n");
00509         }
00510     }
00511 }
00512 
00513 
00523 static char* usbif_compute_udi(HalDevice* d, int append_num)
00524 {
00525     int i, len;
00526     const char* format;
00527     const char* pd;
00528     const char* name;
00529     static char buf[256];
00530 
00531     if( append_num==-1 )
00532         format = "/org/freedesktop/Hal/devices/usbif_%s_%d";
00533     else
00534         format = "/org/freedesktop/Hal/devices/usbif_%s_%d-%d";
00535 
00536     pd = ds_property_get_string(d, "info.parent");
00537     len = strlen(pd);
00538     for(i=len-1; pd[i]!='/' && i>=0; i--)
00539         ;
00540     name = pd+i+1;
00541 
00542     snprintf(buf, 256, format, 
00543              name,
00544              ds_property_get_int(d, "usbif.number"),
00545              append_num);
00546     
00547     return buf;
00548 }
00549 
00550 
00570 static char* usb_compute_udi(HalDevice* d, int append_num)
00571 {
00572     const char* serial;
00573     const char* format;
00574     static char buf[256];
00575 
00576     if( append_num==-1 )
00577         format = "/org/freedesktop/Hal/devices/usb_%x_%x_%x_%d_%s";
00578     else
00579         format = "/org/freedesktop/Hal/devices/usb_%x_%x_%x_%d_%s-%d";
00580 
00581     if( ds_property_exists(d, "usb.serial") )
00582         serial = ds_property_get_string(d, "usb.serial");
00583     else
00584         serial = "noserial";
00585 
00586     snprintf(buf, 256, format, 
00587              ds_property_get_int(d, "usb.vendor_id"),
00588              ds_property_get_int(d, "usb.product_id"),
00589              ds_property_get_int(d, "usb.device_revision_bcd"),
00590              ds_property_get_int(d, "usb.cfg_value"),
00591              serial, append_num);
00592     
00593     return buf;
00594 }
00595 
00596 
00605 static void usb_add_caps_from_class(HalDevice* d,
00606                                     int if_class, 
00607                                     int if_sub_class, 
00608                                     int if_proto)
00609 {
00610     char* cat = NULL;
00611 
00612     switch( if_class )
00613     {
00614     case 0x01:
00615         cat = "multimedia.audio";
00616         ds_add_capability(d, "multimedia.audio");
00617         break;
00618     case 0x02:
00619         if( if_sub_class==0x06 )
00620         {
00621             cat = "net";
00622             ds_add_capability(d, "net");
00623             ds_add_capability(d, "net.ethernet");
00624         }
00625         else if( if_sub_class==0x02 && if_proto==0x01 )
00626         {
00627             cat = "modem";
00628             ds_add_capability(d, "modem");
00629         }
00630         break;
00631     case 0x03:
00632         cat = "input";
00633         ds_add_capability(d, "input");
00634         if( if_sub_class==0x00 || if_sub_class==0x01 )
00635         {
00636             if( if_proto==0x01 )
00637             {
00638                 cat = "input.keyboard";
00639                 ds_add_capability(d, "input.keyboard");
00640             }
00641             else if( if_proto==0x02 )
00642             {
00643                 cat = "input.mouse";
00644                 ds_add_capability(d, "input.mouse");
00645             }
00646         }
00647         break;
00648     case 0x04:
00649         break;
00650     case 0x05:
00651         break;
00652     case 0x06:
00653         break;
00654     case 0x07:
00655         cat = "printer";
00656         ds_add_capability(d, "printer");
00657         break;
00658     case 0x08:
00659         cat = "storage_controller";
00660         ds_add_capability(d, "storage_controller");
00661         break;
00662     case 0x09:
00663         cat = "hub";
00664         ds_add_capability(d, "hub");
00665         break;
00666     case 0x0a:
00667         break;
00668     case 0xe0:
00669         if( if_sub_class==0x01 && if_proto==0x01 ) 
00670         {
00671             cat = "bluetooth_adaptor";
00672             ds_add_capability(d, "bluetooth_adaptor");
00673         }
00674         break;
00675     }
00676 
00677     if( cat!=NULL )
00678         ds_property_set_string(d, "info.category", cat);
00679 }
00680 
00681 
00682 /* fwd decl */
00683 static void visit_device_usbif_got_parent(HalDevice* parent, 
00684                                           void* data1, void* data2);
00685 
00691 static void visit_device_usb_interface(const char* path,
00692                                        struct sysfs_device *device)
00693 {
00694     int i;
00695     int len;
00696     struct sysfs_attribute* cur;
00697     HalDevice* d;
00698     const char* driver;
00699     char attr_name[SYSFS_NAME_LEN];
00700     char* parent_sysfs_path;
00701 
00702     /*printf("usb_interface: path=%s\n", path);*/
00703 
00704     /* Create HAL device representing the interface */
00705     d = ds_device_new();
00706     ds_property_set_string(d, "info.bus", "usbif");
00707     ds_property_set_string(d, "linux.sysfs_path", path);
00708     ds_property_set_string(d, "linux.sysfs_path_device", path);
00713     ds_property_set_string(d, "usbif.linux.sysfs_path", path);
00714     ds_property_set_bool(d, "info.virtual", TRUE);
00715 
00716     /* set driver */
00717     driver = drivers_lookup(path);
00718     if( driver!=NULL )
00719         ds_property_set_string(d, "linux.driver", driver);
00720 
00721 
00722     if( device->directory==NULL || device->directory->attributes==NULL )
00723         return;
00724 
00725     dlist_for_each_data(sysfs_get_device_attributes(device), cur,
00726                         struct sysfs_attribute)
00727     {
00728         
00729         if( sysfs_get_name_from_path(cur->path, 
00730                                      attr_name, SYSFS_NAME_LEN) != 0 )
00731             continue;
00732 
00733         /* strip whitespace */
00734         len = strlen(cur->value);
00735         for(i=len-1; i>0 && isspace(cur->value[i]); --i)
00736             cur->value[i] = '\0';
00737         
00738         /*printf("attr_name=%s -> '%s'\n", attr_name, cur->value);*/
00739 
00740         if( strcmp(attr_name, "bInterfaceClass")==0 )
00741             ds_property_set_int(d, "usbif.interface_class", 
00742                                 parse_dec(cur->value));
00743         else if( strcmp(attr_name, "bInterfaceSubClass")==0 )
00744             ds_property_set_int(d, "usbif.interface_subclass", 
00745                                 parse_dec(cur->value));
00746         else if( strcmp(attr_name, "bInterfaceProtocol")==0 )
00747             ds_property_set_int(d, "usbif.interface_protocol", 
00748                                 parse_dec(cur->value));
00749         else if( strcmp(attr_name, "bInterfaceNumber")==0 )
00750             ds_property_set_int(d, "usbif.number", 
00751                                         parse_dec(cur->value));
00752     }
00753 
00754     parent_sysfs_path = get_parent_sysfs_path(path);
00755 
00756     /* Find parent; this happens asynchronously as our parent might
00757      * be added later. If we are probing this can't happen so the
00758      * timeout is set to zero in that event..
00759      */
00760     ds_device_async_find_by_key_value_string("linux.sysfs_path_device",
00761                                              parent_sysfs_path, 
00762                                              TRUE,
00763                                              visit_device_usbif_got_parent,
00764                                              (void*) d, NULL, 
00765                                              is_probing ? 0 :
00766                                              HAL_LINUX_HOTPLUG_TIMEOUT);
00767 
00768     free(parent_sysfs_path);
00769 }
00770 
00778 static void visit_device_usbif_got_parent(HalDevice* parent, 
00779                                           void* data1, void* data2)
00780 {
00781     char* new_udi = NULL;
00782     HalDevice* new_d = NULL;
00783     HalDevice* d = (HalDevice*) data1;
00784 
00785     if( parent==NULL )
00786     {
00787         /* An USB interface should always have a parent! */
00788         HAL_ERROR(("No parent for USB interface!"));
00789         ds_device_destroy(d);
00790         return;
00791     }
00792 
00793     ds_property_set_string(d, "info.parent", parent->udi);
00794 
00795     /* We set the caps derived from this USB interface on the parent USB
00796      * device 
00797      */
00798     usb_add_caps_from_class(parent, 
00799                             ds_property_get_int(d, "usbif.interface_class"),
00800                             ds_property_get_int(d, "usbif.interface_subclass"),
00801                            ds_property_get_int(d, "usbif.interface_protocol"));
00802 
00803     ds_property_set_string(d, "info.parent", parent->udi);
00804     ds_property_set_string(d, "info.physical_device", parent->udi);
00805     ds_property_set_int(d, "usbif.device_vendor_id",
00806         ds_property_get_int(parent, "usb.vendor_id"));
00807     ds_property_set_int(d, "usbif.device_product_id",
00808         ds_property_get_int(parent, "usb.product_id"));
00809 
00810     new_udi = rename_and_merge(d, usbif_compute_udi, "usbif");
00811     if( new_udi!=NULL )
00812     {
00813         new_d = ds_device_find(new_udi);
00814         if( new_d!=NULL )
00815         {
00816             ds_gdl_add(new_d);
00817         }
00818     }
00819 
00820 }
00821 
00822 
00823 /* fwd decl */
00824 static void visit_device_usb_got_parent(HalDevice* parent, 
00825                                         void* data1, void* data2);
00826 
00835 void visit_device_usb(const char* path, struct sysfs_device *device)
00836 {
00837     int i;
00838     int len;
00839     dbus_bool_t is_interface;
00840     struct sysfs_attribute* cur;
00841     HalDevice* d;
00842     char attr_name[SYSFS_NAME_LEN];
00843     int vendor_id=0;
00844     int product_id=0;
00845     char* vendor_name;
00846     char* product_name;
00847     char* vendor_name_kernel = NULL;
00848     char* product_name_kernel = NULL;
00849     const char* driver;
00850     char* parent_sysfs_path;
00851     char numeric_name[32];
00852 
00853     /*printf("usb: %s, bus_id=%s\n", path, device->bus_id);*/
00854 
00855     if( device->directory==NULL || device->directory->attributes==NULL )
00856         return;
00857 
00858     /* Check if this is an USB interface */
00859     is_interface = FALSE;
00860     dlist_for_each_data(sysfs_get_device_attributes(device), cur,
00861                         struct sysfs_attribute)
00862     {
00863         if( is_interface )
00864             break;
00865 
00866         if( sysfs_get_name_from_path(cur->path, 
00867                                      attr_name, SYSFS_NAME_LEN) != 0 )
00868             continue;
00869         
00870         if( strcmp(attr_name, "iInterface")==0 )
00871             is_interface = TRUE;
00872     }
00873     
00874     /* USB interfaces are handled by a separate function */
00875     if( is_interface )
00876     {
00877         HAL_INFO(("usb device @ %s is an interface", path));
00878         visit_device_usb_interface(path, device);
00879         return;
00880     }
00881     
00882     /* Must be a new USB device */
00883     d = ds_device_new();
00884     ds_property_set_string(d, "info.bus", "usb");
00885     ds_property_set_string(d, "linux.sysfs_path", path);
00886     ds_property_set_string(d, "linux.sysfs_bus_id", device->bus_id);
00887     ds_property_set_string(d, "linux.sysfs_path_device", path);
00892     ds_property_set_string(d, "usb.linux.sysfs_path", path);
00893     /*printf("*** created udi=%s for path=%s\n", d, path);*/
00894 
00895     /* set driver */
00896     driver = drivers_lookup(path);
00897     if( driver!=NULL )
00898         ds_property_set_string(d, "linux.driver", driver);
00899     
00900     dlist_for_each_data(sysfs_get_device_attributes(device), cur,
00901                         struct sysfs_attribute)
00902     {
00903         
00904         if( sysfs_get_name_from_path(cur->path, 
00905                                      attr_name, SYSFS_NAME_LEN) != 0 )
00906             continue;
00907 
00908         /* strip whitespace */
00909         len = strlen(cur->value);
00910         for(i=len-1; i>=0 && isspace(cur->value[i]); --i)
00911             cur->value[i] = '\0';
00912 
00913         /*printf("attr_name=%s -> '%s'\n", attr_name, cur->value);*/
00914         
00915         if( strcmp(attr_name, "idProduct")==0 )
00916             product_id = parse_hex(cur->value);
00917         else if( strcmp(attr_name, "idVendor")==0 )
00918             vendor_id = parse_hex(cur->value);
00919         else if( strcmp(attr_name, "bcdDevice")==0 )
00920             ds_property_set_int(d, "usb.device_revision_bcd", 
00921                                 parse_hex(cur->value));
00922         else if( strcmp(attr_name, "bMaxPower")==0 )
00923             ds_property_set_int(d, "usb.max_power", 
00924                                 parse_dec(cur->value));
00925         else if( strcmp(attr_name, "serial")==0 && strlen(cur->value)>0 )
00926             ds_property_set_string(d, "usb.serial", cur->value);
00927         else if( strcmp(attr_name, "bmAttributes")==0 )
00928         {
00929             int bmAttributes = parse_hex(cur->value);
00930 
00931             /* USB_CONFIG_ATT_SELFPOWER */
00932             ds_property_set_bool(d, "usb.is_self_powered",
00933                                  (bmAttributes&0x40)!=0 );
00934             ds_property_set_bool(d, "usb.can_wake_up",
00935                                  (bmAttributes&0x20)!=0 );
00936         }
00937 /*
00938         else if( strcmp(attr_name, "speed")==0 )
00939             hal_device_set_property_double(d, "usb.speed", 
00940                                            parse_double(cur->value));
00941 */
00942         
00943         else if( strcmp(attr_name, "manufacturer")==0 )
00944             vendor_name_kernel = cur->value;
00945         else if( strcmp(attr_name, "product")==0 )
00946             product_name_kernel = cur->value;
00947         else if( strcmp(attr_name, "bDeviceClass")==0 )
00948             ds_property_set_int(d, "usb.device_class", 
00949                                 parse_hex(cur->value));
00950         else if( strcmp(attr_name, "bDeviceSubClass")==0 )
00951             ds_property_set_int(d, "usb.device_subclass", 
00952                                 parse_hex(cur->value));
00953         else if( strcmp(attr_name, "bDeviceProtocol")==0 )
00954             ds_property_set_int(d, "usb.device_protocol", 
00955                                 parse_hex(cur->value));
00956         
00957         else if( strcmp(attr_name, "bNumConfigurations")==0 )
00958             ds_property_set_int(d, "usb.num_configurations", 
00959                                 parse_dec(cur->value));
00960         else if( strcmp(attr_name, "bConfigurationValue")==0 )
00961             ds_property_set_int(d, "usb.configuration_value", 
00962                                 parse_dec(cur->value));
00963         
00964         else if( strcmp(attr_name, "bNumInterfaces")==0 )
00965             ds_property_set_int(d, "usb.num_interfaces", 
00966                                 parse_dec(cur->value));
00967         
00968     } /* for all attributes */
00969 
00970     ds_property_set_int(d, "usb.product_id", product_id);
00971     ds_property_set_int(d, "usb.vendor_id", vendor_id);
00972 
00973     /* Lookup names in usb.ids; these may override what the kernel told
00974      * us, but, hey, it's only a name; it's not something we are going
00975      * to match a device on... We prefer names from usb.ids as the kernel
00976      * name sometimes is just a hexnumber :-/
00977      *
00978      * Also provide best guess on name, Product and Vendor properties;
00979      * these can both be overridden in .fdi files.
00980      */
00981     usb_ids_find(vendor_id, product_id, &vendor_name, &product_name);
00982     if( vendor_name!=NULL )
00983     {
00984         ds_property_set_string(d, "usb.vendor", vendor_name);
00985         ds_property_set_string(d, "info.vendor", vendor_name);
00986     }
00987     else if( vendor_name_kernel!=NULL )
00988     {
00989         /* fallback on name supplied from kernel */
00990         ds_property_set_string(d, "usb.vendor", vendor_name_kernel);
00991         ds_property_set_string(d, "info.vendor", vendor_name_kernel);
00992     }
00993     else
00994     {
00995         /* last resort; use numeric name */
00996         snprintf(numeric_name, 32, "Unknown (0x%04x)", vendor_id);
00997         ds_property_set_string(d, "usb.vendor", numeric_name);
00998         ds_property_set_string(d, "info.vendor", numeric_name);
00999     }
01000 
01001     if( product_name!=NULL )
01002     {
01003         ds_property_set_string(d, "usb.product", product_name);
01004         ds_property_set_string(d, "info.product", product_name);
01005     }
01006     else if( product_name_kernel!=NULL )
01007     {
01008         /* name supplied from kernel (if available) */
01009         ds_property_set_string(d, "usb.product", product_name_kernel);
01010         ds_property_set_string(d, "info.product", product_name_kernel);
01011     }
01012     else
01013     {
01014         /* last resort; use numeric name */
01015         snprintf(numeric_name, 32, "Unknown (0x%04x)", product_id);
01016         ds_property_set_string(d, "usb.product", numeric_name);
01017         ds_property_set_string(d, "info.product", numeric_name);
01018     }
01019 
01020 
01021     /* Check device class */
01022     usb_add_caps_from_class(d, 
01023                             ds_property_get_int(d, "usb.device_class"),
01024                             ds_property_get_int(d, "usb.device_subclass"),
01025                             ds_property_get_int(d, "usb.device_protocol"));
01026 
01027     parent_sysfs_path = get_parent_sysfs_path(path);
01028 
01029     /* Find parent; this happens asynchronously as our parent might
01030      * be added later. If we are probing this can't happen so the
01031      * timeout is set to zero in that event..
01032      */
01033     ds_device_async_find_by_key_value_string("linux.sysfs_path_device",
01034                                              parent_sysfs_path,
01035                                              TRUE,
01036                                              visit_device_usb_got_parent,
01037                                              (void*) d, NULL, 
01038                                              is_probing ? 0 :
01039                                              HAL_LINUX_HOTPLUG_TIMEOUT);
01040 
01041     free(parent_sysfs_path);
01042 }
01043 
01051 static void visit_device_usb_got_parent(HalDevice* parent, 
01052                                         void* data1, void* data2)
01053 {
01054     char* new_udi = NULL;
01055     HalDevice* new_d = NULL;
01056     int bus_number;
01057     const char* bus_id;
01058     usb_proc_info* proc_info;
01059     HalDevice* d = (HalDevice*) data1;
01060 
01061     if( parent!=NULL )
01062     {
01063         ds_property_set_string(d, "info.parent", parent->udi);
01064     }
01065     else
01066     {
01067         /* An USB device should always have a parent! */
01068         HAL_WARNING(("No parent for USB device!"));
01069     }
01070 
01071     /* Merge information from /proc/bus/usb/devices */
01072     proc_info = NULL;
01073 
01074     bus_id = ds_property_get_string(d, "linux.sysfs_bus_id");
01075 
01076     if( !is_probing )
01077     {
01078         /* reload proc info if we are not probing on startup */
01079         usb_proc_parse();
01080     }
01081 
01082     if( sscanf(bus_id, "usb%d", &bus_number)==1 )
01083     {
01084         /* Is of form "usb%d" which means that this is a USB virtual root
01085          * hub, cf. drivers/usb/hcd.c in kernel 2.6
01086          */
01087         ds_property_set_int(d, "usb.bus_number", bus_number);
01088 
01089         proc_info = usb_proc_find_virtual_hub(bus_number);
01090     }
01091     else
01092     {
01093         int i;
01094         int len;
01095         int digit;
01096         int port_number;
01097         /* Not a root hub; According to the Linux kernel sources,
01098          * the name is of the form
01099          *
01100          *  "%d-%s[.%d]"
01101          *
01102          * where the first number is the bus-number, the middle string is
01103          * the parent device and the last, optional, number is the port
01104          * number in the event that the USB device is a hub.
01105          */
01106 
01107         len = strlen(bus_id);
01108 
01109         /* the first part is easy */
01110         bus_number = atoi(bus_id);
01111 
01112         ds_property_set_int(d, "usb.bus_number", bus_number);
01113 
01114         /* The naming convention also guarantees that
01115          *
01116          *   device is on a (non-virtual) hub    
01117          *
01118          *            IF AND ONLY IF  
01119          *
01120          *   the bus_id contains a "."
01121          */
01122         for(i=0; i<len; i++)
01123         {
01124             if( bus_id[i]=='.' )
01125                 break;
01126         }
01127 
01128         if( i==len )
01129         {
01130             /* Not on a hub; this means we must be a child of the root
01131              * hub... Thus the name must is of the form "%d-%d"
01132              */
01133             if( sscanf(bus_id, "%d-%d", 
01134                        &bus_number, &port_number) == 2 )
01135             {
01136 
01137                 proc_info = usb_proc_find_virtual_hub_child(bus_number, 
01138                                                             port_number);
01139                 ds_property_set_int(d, "usb.port_number", port_number);
01140             }
01141         }
01142         else
01143         {
01144             int parent_device_number;
01145 
01146             /* On a hub */
01147 
01148             /* This is quite a hack */
01149             port_number = 0;
01150             for(i=len-1; i>0 && isdigit(bus_id[i]); --i)
01151             {
01152                 digit = (int)(bus_id[i] - '0');
01153                 port_number *= 10;
01154                 port_number += digit;
01155             }
01156 
01157             ds_property_set_int(d, "usb.port_number", port_number);
01158 
01159             /* Ok, got the port number and bus number; this is not quite
01160              * enough though.. We take the usb.linux.device_number from
01161              * our parent and then we are set.. */
01162             if( parent==NULL )
01163             {
01164                 HAL_WARNING(("USB device is on a hub but no parent??"));
01165                 /* have to give up then */
01166                 proc_info = NULL;
01167             }
01168             else
01169             {
01170                 parent_device_number = 
01171                     ds_property_get_int(parent,
01172                                         "usb.linux.device_number");
01173                 //printf("parent_device_number = %d\n", parent_device_number);
01174                 proc_info = usb_proc_find_on_hub(bus_number, port_number,
01175                                                  parent_device_number);
01176             }
01177 
01178         }
01179     }
01180 
01181 
01182     if( proc_info!=NULL )
01183     {
01184         char kernel_path[32+1];
01185 
01186         ds_property_set_int(d, "usb.level_number", proc_info->t_level);
01187         ds_property_set_int(d, "usb.linux.device_number",
01188                                     proc_info->t_device);
01189         ds_property_set_int(d, "usb.linux.parent_number",
01190                                     proc_info->t_device);
01191         ds_property_set_int(d, "usb.num_ports", 
01192                                     proc_info->t_max_children);
01193         ds_property_set_int(d, "usb.speed_bcd", proc_info->t_speed_bcd);
01194         ds_property_set_int(d, "usb.version_bcd", 
01195                                     proc_info->d_version_bcd);
01196 
01197         /* Ok, now compute the unique name that the kernel sometimes use
01198          * to refer to the device; it's #usb_make_path() as defined in
01199          * include/linux/usb.h
01200          */
01201         if( proc_info->t_level==0 )
01202         {
01203             snprintf(kernel_path, 32, "usb-%s", 
01204                      ds_property_get_string(d, "usb.serial"));
01205             ds_property_set_string(d, "linux.kernel_devname",
01206                                            kernel_path);
01207         }
01208         else
01209         {
01210             if( parent!=NULL )
01211             {
01212                 if( proc_info->t_level==1 )
01213                 {
01214                     snprintf(kernel_path, 32, "%s-%d", 
01215                              ds_property_get_string(parent, 
01216                                                     "linux.kernel_devname"),
01217                              ds_property_get_int(d, "usb.port_number"));
01218                 }
01219                 else
01220                 {
01221                     snprintf(kernel_path, 32, "%s.%d", 
01222                              ds_property_get_string(parent,
01223                                                     "linux.kernel_devname"),
01224                              ds_property_get_int(d, "usb.port_number"));
01225                 }
01226                 ds_property_set_string(d, "linux.kernel_devname",
01227                                        kernel_path);
01228             }
01229         }
01230 
01231     }
01232 
01233     /* Uncomment this line to test that sleeping works when handling USB
01234      * interfaces on not-yet added USB devices
01235      *
01236      * (you might need to tweak number of seconds to fit with your system)
01237      */
01238     /*sleep(5);*/
01239 
01240     /* Finally, Compute a proper UDI (unique device id), try to locate
01241      * a persistent unplugged device or add it
01242      */
01243     new_udi = rename_and_merge(d, usb_compute_udi, "usb");
01244     if( new_udi!=NULL )
01245     {
01246         new_d = ds_device_find(new_udi);
01247         if( new_d!=NULL )
01248         {
01249             ds_gdl_add(new_d);
01250         }
01251     }
01252 }
01253 
01254 
01258 void linux_usb_init()
01259 {
01260 
01261     /* get all drivers under /sys/bus/usb/drivers */
01262     drivers_collect("usb");
01263 
01264     /* Load /usr/share/hwdata/usb.ids */
01265     usb_ids_load(HWDATA_DIR "/usb.ids");
01266 
01267     /* Parse /proc/bus/usb/devices */
01268 
01269     usb_proc_parse();
01270 }
01271 
01276 void linux_usb_detection_done()
01277 {
01278 }
01279 
01280 
01284 void linux_usb_shutdown()
01285 {
01286     usb_ids_free();
01287 }
01288 

Generated on Sat Feb 7 22:11:47 2004 for HAL by doxygen 1.3.5