Example #1
0
/*
 * Add udev info.
 */
void int_udev(hd_data_t *hd_data)
{
  hd_udevinfo_t *ui;
  hd_t *hd;
  str_list_t *sl;

  if(!hd_data->udevinfo) read_udevinfo(hd_data);

  if(!hd_data->udevinfo) return;

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(!hd->unix_dev_names && hd->unix_dev_name) {
      add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
    }

    if(!hd->sysfs_id) continue;

    for(ui = hd_data->udevinfo; ui; ui = ui->next) {
      if(ui->name && !strcmp(ui->sysfs, hd->sysfs_id)) {
        if(!search_str_list(hd->unix_dev_names, ui->name)) {
          add_str_list(&hd->unix_dev_names, ui->name);
        }
        for(sl = ui->links; sl; sl = sl->next) {
          if(!search_str_list(hd->unix_dev_names, sl->str)) {
            add_str_list(&hd->unix_dev_names, sl->str);
          }
        }

        if(!hd->unix_dev_name || hd_data->flags.udev) {
          sl = hd->unix_dev_names;

          if(hd_data->flags.udev) {
            /* use first link as canonical device name */
            if(ui->links) sl = sl->next;
          }

          hd->unix_dev_name = new_str(sl->str);
        }

        break;
      }
    }
  }

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(!hd->unix_dev_names) continue;

    for(ui = hd_data->udevinfo; ui; ui = ui->next) {
      if(search_str_list(hd->unix_dev_names, ui->name)) {
        for(sl = ui->links; sl; sl = sl->next) {
          if(!search_str_list(hd->unix_dev_names, sl->str)) {
            add_str_list(&hd->unix_dev_names, sl->str);
          }
        }
      }
    }
  }
}
Example #2
0
void int_update_driver_data(hd_data_t *hd_data, hd_t *hd)
{
  hd_sysfsdrv_t *sf;
  str_list_t *sl;

  hd->driver_modules = free_str_list(hd->driver_modules);

  for(sl = hd->drivers; sl; sl = sl->next) {
    for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
      if(sf->module && !strcmp(sf->driver, sl->str)) {
        add_str_list(&hd->driver_modules, sf->module);
      }
    }
  }

  hd->driver = free_mem(hd->driver);
  hd->driver_module = free_mem(hd->driver_module);

  if(hd->drivers && hd->drivers->str) {
    hd->driver = new_str(hd->drivers->str);

    for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
      if(sf->module && !strcmp(sf->driver, hd->driver)) {
        hd->driver_module = new_str(sf->module);
      }
    }
  }
}
Example #3
0
t_str	*add_str(t_str *begin, char *str, char c)
{
	int i;
	t_str *list;

	i = 0;
	if (!begin)
		begin = add_str_list(NULL);
	list = begin;
	while (list->next)
		list = list->next;

	if (str)
	{
		while (str[i])
		{
			if (list->index < 32)
			{
				list->str[list->index] = str[i];
				list->index++;
				i++;
			}
			else
			{
				list->next = add_str_list(begin);
				list = list->next;
			}
		}
	}
	else if (c)
	{
		if (list->index < 32)
		{
			list->str[list->index] = c;
			list->index++;
		}
		else
		{
			list->next = add_str_list(begin);
			list = list->next;
			list->str[list->index] = c;
			list->index++;
		}
	}
	return (begin);
}
Example #4
0
void hd2prop_append_list(hal_prop_t **list, const char *key, char *str)
{
  hal_prop_t *prop;
  str_list_t *sl = NULL;

  if(!str) return;

  prop = hal_get_list(*list, key);

  if(!prop) {
    add_str_list(&sl, str);
    hd2prop_add_list(list, key, sl);
    return;
  }

  add_str_list(&prop->val.list, str);
}
Example #5
0
str_list_t *str_list_dup(str_list_t *orig)
{
  str_list_t *dup = NULL;

  for(; orig != NULL; orig = orig->next) {
    add_str_list(&dup, orig->str);
  }

  return dup;
}
Example #6
0
void at_cmd(hd_data_t *hd_data, char *at, int raw, int log_it)
{
  static unsigned u = 1;
  char *s, *s0;
  ser_device_t *sm;
  str_list_t *sl;
  int modems = 0;

  for(sm = hd_data->ser_modem; sm; sm = sm->next) {
    if(sm->do_io) {
      sm->buf_len = 0;
      modems++;
    }
  }

  if(modems == 0) return;

  PROGRESS(9, u, "write at cmd");
  write_modem(hd_data, at);
  PROGRESS(9, u, "read at resp");
  usleep (200000);
  read_modem(hd_data);
  PROGRESS(9, u, "read ok");
  u++;

  for(sm = hd_data->ser_modem; sm; sm = sm->next) {
    if(sm->do_io) {
      sm->at_resp = free_str_list(sm->at_resp);
      if(sm->buf_len == 0 || raw) continue;
      s0 = sm->buf;
      while((s = strsep(&s0, "\r\n"))) {
        if(*s) add_str_list(&sm->at_resp, s);
      }
    }
  }

  if(!(hd_data->debug & HD_DEB_MODEM) || !log_it) return;

  for(sm = hd_data->ser_modem; sm; sm = sm->next) {
    if(sm->do_io) {
      ADD2LOG("%s@%u: %s\n", sm->dev_name, sm->cur_baud, at);
      if(raw) {
        ADD2LOG("  ");
        hexdump(&hd_data->log, 1, sm->buf_len, sm->buf);
        ADD2LOG("\n");
      }
      else {
        for(sl = sm->at_resp; sl; sl = sl->next) ADD2LOG("  %s\n", sl->str);
      }
    }
  }
}
Example #7
0
/*
 * If hd->unix_dev_name is not in hd->unix_dev_names, add it.
 */
void int_devicenames(hd_data_t *hd_data)
{
  hd_t *hd;

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(
      hd->unix_dev_name &&
      !search_str_list(hd->unix_dev_names, hd->unix_dev_name)
    ) {
      add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
    }
  }
}
Example #8
0
/*
 * Add driver data, if it is missing.
 *
 * Interface function, don't use internally.
 */
void hd_add_driver_data(hd_data_t *hd_data, hd_t *hd)
{
  char *s;

  if(hd->drivers) return;

  hd_sysfs_driver_list(hd_data);

  s = hd_sysfs_find_driver(hd_data, hd->sysfs_id, 1);
  if(s) add_str_list(&hd->drivers, s);

  int_update_driver_data(hd_data, hd);
}
Example #9
0
str_list_t *prop2hd_list(hal_prop_t *prop, const char *id)
{
  str_list_t *sl0 = NULL, *sl;

  prop = hal_get_list(prop, id);

  if(prop) {
    for(sl = prop->val.list; sl; sl = sl->next) {
      add_str_list(&sl0, sl->str);
    }
  }

  return sl0;
}
Example #10
0
void hd2prop_add_list(hal_prop_t **list, const char *key, str_list_t *sl)
{
  hal_prop_t *prop;

  if(sl) {
    prop = hal_get_new(list, key);
    prop->type = p_list;
    for(; sl; sl = sl->next) {
      add_str_list(&prop->val.list, sl->str);
    }
  }
  else {
    hal_invalidate_all(*list, key);
  }
}
Example #11
0
/*
 * Tag ide soft raid disks.
 */
void int_softraid(hd_data_t *hd_data)
{
  hd_t *hd;
  str_list_t *raid, *sl, *raid_sysfs = NULL, *sl1;
  size_t len;
  char *s;

  if(hd_data->flags.fast) return;

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(
      hd->base_class.id == bc_storage_device &&
      hd->status.available != status_no
    ) break;
  }

  /* no disks -> no check necessary */
  if(!hd) return;
  
  raid = read_file("| /sbin/dmraid -rc 2>/dev/null", 0, 0);

  for(sl = raid; sl; sl = sl->next) {
    s = *sl->str ? strchr(sl->str + 1, '/') : NULL;
    if(s) {
      sl1 = add_str_list(&raid_sysfs, NULL);
      str_printf(&sl1->str, 0, "/block%s", s);
      len = strlen(sl1->str);
      if(len) sl1->str[len - 1] = 0;
    }
  }

  free_str_list(raid);

  ADD2LOG("----- soft raid devices -----\n");
  for(sl = raid_sysfs; sl; sl = sl->next) {
    ADD2LOG("  %s\n", sl->str);
  }
  ADD2LOG("----- soft raid devices end -----\n");

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(search_str_list(raid_sysfs, hd->sysfs_id)) {
      hd->is.softraiddisk = 1;
    }
  }

  free_str_list(raid_sysfs);

}
Example #12
0
char *export_str(t_str *begin)
{
	int i;
	int i2;
	char *str;

	i = 0;
	i2 = 0;
	if (!begin)
		begin = add_str_list(NULL);
	str = (char *)malloc(sizeof(char) * str_cpt_index(begin) + 1);
	if (begin->next)
	{
		while (begin->next)
		{
			while (i < 32 && begin->str[i] != 0)
			{
				str[i2] = begin->str[i];
				i2++;
				i++;
			}
			begin = begin->next;
			i = 0;
		}
		while (i < 32 && begin->str[i] != 0)
		{
			str[i2] = begin->str[i];
			i2++;
			i++;
		}
	}
	else
	{
		while (i < 32 && begin->str[i] != 0)
		{
			str[i2] = begin->str[i];
			i2++;
			i++;
		}
	}
	str[i2] = '\0';
	return(str);
}
Example #13
0
int str_cpt_index(t_str *begin)
{
	int total;

	total = 0;
	if (!begin)
		begin = add_str_list(NULL);
	if (begin->next)
	{
		while (begin->next)
		{
			total = total + begin->index;
			begin = begin->next;
		}
		total = total + begin->index;
		return (total);
	}
	else
		while (begin->str[total] != 0)
			total++;
	return (total);
}
Example #14
0
/*
 * Read kernel log info. Combine with /var/log/boot.msg.
 * Remove time stamps.
 */
void read_klog(hd_data_t *hd_data)
{
  str_list_t *sl, **sl_new;
  char *str, *s;

  _read_klog(hd_data);

  free_str_list(hd_data->klog_raw);
  hd_data->klog_raw = hd_data->klog;
  hd_data->klog = NULL;

  for(sl = hd_data->klog_raw, sl_new = &hd_data->klog; sl; sl = sl->next, sl_new = &(*sl_new)->next) {
    str = add_str_list(sl_new, sl->str)->str;
    if(str[0] == '<' && str[1] && str[2] == '>' && str[3] == '[') {
      s = str + 4;
      while(*s && *s != ']') s++;
      if(*s) s++;
      if(*s) s++;	// skip space
      for(str += 3; (*str++ = *s++););
    }
  }
}
Example #15
0
void hd_scan_wlan(hd_data_t *hd_data)
{
  hd_t *hd;
  hd_res_t *res;
  struct iw_range range;
  int k;
  int skfd;
  struct wpa_driver_ops *wpa_drv=NULL;

  if(!hd_probe_feature(hd_data, pr_wlan)) return;

  hd_data->module = mod_wlan;

  PROGRESS(1, 0, "detecting wlan features");

  if ((skfd = iw_sockets_open()) < 0) {
    ADD2LOG( "could not open socket, wlan feature query failed\n" );
    return;
  }

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(
      hd->base_class.id == bc_network &&
      hd->unix_dev_name ) {
      /* Get list of frequencies / channels */
      if(iw_get_range_info(skfd, hd->unix_dev_name, &range) < 0) {
	/* this failed, maybe device does not support wireless extensions */
	continue;
      }
      ADD2LOG("*** device %s is wireless ***\n", hd->unix_dev_name);
      hd->is.wlan = 1;

      hd->sub_class.id = 0x82;		/* wlan */

      res = new_mem(sizeof *res);
      res->any.type = res_wlan;

      if(range.num_frequency > 0) {
	char buff[20];
	for(k = 0; k < range.num_frequency; k++) {
	  snprintf(buff, 19, "%i", range.freq[k].i);
	  add_str_list(&res->wlan.channels, buff);
	  snprintf(buff, 19, "%g", (float)iw_freq2float(&(range.freq[k]))/1000000000);
	  add_str_list(&res->wlan.frequencies, buff);
	}
	for(k = 0; k < range.num_bitrates; k++) {
	  snprintf(buff, 19, "%g", (float)range.bitrate[k]/1000000);
	  add_str_list(&res->wlan.bitrates, buff);
	}
	for(k = 0; k < range.num_encoding_sizes; k++) {
	  snprintf(buff, 19, "WEP%i", range.encoding_size[k]*8);
	  add_str_list(&res->wlan.enc_modes, buff);
	}

	/* open mode is always supported */
	add_str_list(&res->wlan.auth_modes, "open");
	/* if WEP is supported, be assume shared key auth support */
	if(range.num_encoding_sizes) {
	  add_str_list(&res->wlan.auth_modes, "sharedkey");
	}

	/* detect WPA capabilities */
	if (!hd_data->flags.nowpa && hd->drivers) {
	  if (search_str_list(hd->drivers, "ath_pci"))
	    wpa_drv = &wpa_driver_madwifi_ops;
	  else if (strncmp(hd->drivers->str, "at76", 4)==0)
	    wpa_drv = &wpa_driver_atmel_ops;
	  else 
	    wpa_drv = &wpa_driver_wext_ops;
	}
	
	if (wpa_drv) {
	  if (wpa_drv->set_wpa(hd->unix_dev_name, 1) == 0) {
	    add_str_list(&res->wlan.auth_modes, "wpa-psk");
	    add_str_list(&res->wlan.auth_modes, "wpa-eap");
	    if (wpa_drv->set_auth_alg && 
		wpa_drv->set_auth_alg(hd->unix_dev_name, AUTH_ALG_LEAP)==0)
	      add_str_list(&res->wlan.auth_modes, "wpa-leap");
	    if (wpa_drv->set_key(hd->unix_dev_name, WPA_ALG_TKIP, "ff:ff:ff:ff:ff:ff",
				 0, 0, 0, 0,
				 "00000000000000000000000000000000", 32) ==0)
	      add_str_list(&res->wlan.enc_modes, "TKIP");
	    if (wpa_drv->set_key(hd->unix_dev_name, WPA_ALG_CCMP, "ff:ff:ff:ff:ff:ff",
				 0, 0, 0, 0, 
				 "0000000000000000", 16) ==0)
	      add_str_list(&res->wlan.enc_modes, "CCMP");
	    wpa_drv->set_wpa(hd->unix_dev_name, 0);
	  }
	}
      }
      add_res_entry(&hd->res, res);
    }
  }
}
Example #16
0
void hd_scan_net(hd_data_t *hd_data)
{
  unsigned u;
  int if_type, if_carrier;
  hd_t *hd, *hd_card;
  char *s, *t, *hw_addr;
  hd_res_t *res, *res1, *res2;
  uint64_t ul0;
  str_list_t *sf_class, *sf_class_e;
  char *sf_cdev = NULL, *sf_dev = NULL;
  char *sf_drv_name, *sf_drv;

  if(!hd_probe_feature(hd_data, pr_net)) return;

  hd_data->module = mod_net;

  /* some clean-up */
  remove_hd_entries(hd_data);
  hd_data->net = free_str_list(hd_data->net);

  PROGRESS(1, 0, "get network data");

  sf_class = read_dir("/sys/class/net", 'l');
  if(!sf_class) sf_class = read_dir("/sys/class/net", 'd');

  if(!sf_class) {
    ADD2LOG("sysfs: no such class: net\n");
    return;
  }

  for(sf_class_e = sf_class; sf_class_e; sf_class_e = sf_class_e->next) {
    str_printf(&sf_cdev, 0, "/sys/class/net/%s", sf_class_e->str);

    hd_card = NULL;

    ADD2LOG(
      "  net interface: name = %s, path = %s\n",
      sf_class_e->str,
      hd_sysfs_id(sf_cdev)
    );

    if_type = -1;
    if(hd_attr_uint(get_sysfs_attr_by_path(sf_cdev, "type"), &ul0, 0)) {
      if_type = ul0;
      ADD2LOG("    type = %d\n", if_type);
    }

    if_carrier = -1;
    if(hd_attr_uint(get_sysfs_attr_by_path(sf_cdev, "carrier"), &ul0, 0)) {
      if_carrier = ul0;
      ADD2LOG("    carrier = %d\n", if_carrier);
    }

    hw_addr = NULL;
    if((s = get_sysfs_attr_by_path(sf_cdev, "address"))) {
      hw_addr = canon_str(s, strlen(s));
      ADD2LOG("    hw_addr = %s\n", hw_addr);
    }

    sf_dev = new_str(hd_read_sysfs_link(sf_cdev, "device"));
    if(sf_dev) {
      ADD2LOG("    net device: path = %s\n", hd_sysfs_id(sf_dev));
    }

    sf_drv_name = NULL;
    sf_drv = hd_read_sysfs_link(sf_dev, "driver");
    if(sf_drv) {
      sf_drv_name = strrchr(sf_drv, '/');
      if(sf_drv_name) sf_drv_name++;
      ADD2LOG(
        "    net driver: name = %s, path = %s\n",
        sf_drv_name,
        hd_sysfs_id(sf_drv)
      );
    }

    hd = add_hd_entry(hd_data, __LINE__, 0);
    hd->base_class.id = bc_network_interface;
    hd->sub_class.id = sc_nif_other;

    res1 = NULL;
    if(hw_addr && strspn(hw_addr, "0:") != strlen(hw_addr)) {
      res1 = new_mem(sizeof *res1);
      res1->hwaddr.type = res_hwaddr;
      res1->hwaddr.addr = new_str(hw_addr);
      add_res_entry(&hd->res, res1);
    }

    res2 = NULL;
    if(if_carrier >= 0) {
      res = new_mem(sizeof *res);
      res->link.type = res_link;
      res->link.state = if_carrier ? 1 : 0;
      add_res_entry(&hd->res, res);
    }

    hd->unix_dev_name = new_str(sf_class_e->str);
    hd->sysfs_id = new_str(hd_sysfs_id(sf_cdev));

    if(sf_drv_name) {
      add_str_list(&hd->drivers, sf_drv_name);
    }
    else if(hd->res) {
      get_driverinfo(hd_data, hd);
    }

    switch(if_type) {
      case ARPHRD_ETHER:	/* eth */
        hd->sub_class.id = sc_nif_ethernet;
        break;
      case ARPHRD_LOOPBACK:	/* lo */
        hd->sub_class.id = sc_nif_loopback;
        break;
      case ARPHRD_SIT:		/* sit */
        hd->sub_class.id = sc_nif_sit;
        break;
      case ARPHRD_FDDI:		/* fddi */
        hd->sub_class.id = sc_nif_fddi;
        break;
      case ARPHRD_IEEE802_TR:	/* tr */
        hd->sub_class.id = sc_nif_tokenring;
        break;
#if 0
      case ARPHRD_IEEE802:	/* fc */
        hd->sub_class.id = sc_nif_fc;
        break;
#endif
      default:
        hd->sub_class.id = sc_nif_other;
    }

    if(!strcmp(hd->unix_dev_name, "lo")) {
      hd->sub_class.id = sc_nif_loopback;
    }
    else if(sscanf(hd->unix_dev_name, "eth%u", &u) == 1) {
      hd->sub_class.id = sc_nif_ethernet;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "tr%u", &u) == 1) {
      hd->sub_class.id = sc_nif_tokenring;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "fddi%u", &u) == 1) {
      hd->sub_class.id = sc_nif_fddi;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "ctc%u", &u) == 1) {
      hd->sub_class.id = sc_nif_ctc;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "iucv%u", &u) == 1) {
      hd->sub_class.id = sc_nif_iucv;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "hsi%u", &u) == 1) {
      hd->sub_class.id = sc_nif_hsi;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "qeth%u", &u) == 1) {
      hd->sub_class.id = sc_nif_qeth;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "escon%u", &u) == 1) {
      hd->sub_class.id = sc_nif_escon;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "myri%u", &u) == 1) {
      hd->sub_class.id = sc_nif_myrinet;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "sit%u", &u) == 1) {
      hd->sub_class.id = sc_nif_sit;	/* ipv6 over ipv4 tunnel */
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "wlan%u", &u) == 1) {
      hd->sub_class.id = sc_nif_wlan;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "xp%u", &u) == 1) {
      hd->sub_class.id = sc_nif_xp;
      hd->slot = u;
    }
    else if(sscanf(hd->unix_dev_name, "usb%u", &u) == 1) {
      hd->sub_class.id = sc_nif_usb;
      hd->slot = u;
    }
    /* ##### add more interface names here */
    else {
      for(s = hd->unix_dev_name; *s; s++) if(isdigit(*s)) break;
      if(*s && (u = strtoul(s, &s, 10), !*s)) {
        hd->slot = u;
      }
    }

    hd->bus.id = bus_none;

    hd_card = NULL;

    if(sf_dev) {
      s = new_str(hd_sysfs_id(sf_dev));

      hd->sysfs_device_link = new_str(s);

      hd_card = hd_find_sysfs_id(hd_data, s);

      // try one above, if not found
      if(!hd_card) {
        t = strrchr(s, '/');
        if(t) {
          *t = 0;
          hd_card = hd_find_sysfs_id(hd_data, s);
        }
      }

      /* if one card has several interfaces (as with PS3), check interface names, too */
      if(
        hd_card &&
        hd_card->unix_dev_name &&
        hd->unix_dev_name &&
        strcmp(hd->unix_dev_name, hd_card->unix_dev_name)
      ) {
        hd_card = hd_find_sysfs_id_devname(hd_data, s, hd->unix_dev_name);
      }

      s = free_mem(s);

      if(hd_card) {
        hd->attached_to = hd_card->idx;

        /* for cards with strange pci classes */
        hd_set_hw_class(hd_card, hw_network_ctrl);

        /* add hw addr to network card */
        if(res1) {
          u = 0;
          for(res = hd_card->res; res; res = res->next) {
            if(
              res->any.type == res_hwaddr &&
              !strcmp(res->hwaddr.addr, res1->hwaddr.addr)
            ) {
              u = 1;
              break;
            }
          }
          if(!u) {
            res = new_mem(sizeof *res);
            res->hwaddr.type = res_hwaddr;
            res->hwaddr.addr = new_str(res1->hwaddr.addr);
            add_res_entry(&hd_card->res, res);
          }
        }
        /*
         * add interface names...
         * but not wmasterX (bnc #441778)
         */
        if(if_type != 801) add_if_name(hd_card, hd);
      }
    }

    if(!hd_card && hw_addr) {
      /* try to find card based on hwaddr (for prom-based cards) */

      for(hd_card = hd_data->hd; hd_card; hd_card = hd_card->next) {
        if(
          hd_card->base_class.id != bc_network ||
          hd_card->sub_class.id != 0
        ) continue;
        for(res = hd_card->res; res; res = res->next) {
          if(
            res->any.type == res_hwaddr &&
            !strcmp(hw_addr, res->hwaddr.addr)
          ) break;
        }
        if(res) {
          hd->attached_to = hd_card->idx;
          break;
        }
      }
    }

    hw_addr = free_mem(hw_addr);

    /* fix card type */
    if(hd_card) {
      if(
        (hd_card->base_class.id == 0 && hd_card->sub_class.id == 0) ||
        (hd_card->base_class.id == bc_network && hd_card->sub_class.id == 0x80)
      ) {
        switch(hd->sub_class.id) {
          case sc_nif_ethernet:
            hd_card->base_class.id = bc_network;
            hd_card->sub_class.id = 0;
            break;

          case sc_nif_usb:
            hd_card->base_class.id = bc_network;
            hd_card->sub_class.id = 0x91;
            break;
        }
      }
    }

    sf_dev = free_mem(sf_dev);
  }

  sf_cdev = free_mem(sf_cdev);
  sf_class = free_str_list(sf_class);

  if(hd_is_sgi_altix(hd_data)) add_xpnet(hd_data);
  add_uml(hd_data);
  add_kma(hd_data);

  /* add link status info & dump eeprom */
  for(hd = hd_data->hd ; hd; hd = hd->next) {
    if(
      hd->module == hd_data->module &&
      hd->base_class.id == bc_network_interface
    ) {
      char *buf = NULL;
      str_list_t *sl0, *sl;

      if(hd_probe_feature(hd_data, pr_net_eeprom) && hd->unix_dev_name) {
        PROGRESS(2, 0, "eeprom dump");

        str_printf(&buf, 0, "|/usr/sbin/ethtool -e %s 2>/dev/null", hd->unix_dev_name);
        if((sl0 = read_file(buf, 0, 0))) {
          ADD2LOG("----- %s %s -----\n", hd->unix_dev_name, "EEPROM dump");
          for(sl = sl0; sl; sl = sl->next) {
            ADD2LOG("%s", sl->str);
          }
          ADD2LOG("----- %s end -----\n", "EEPROM dump");
          free_str_list(sl0);
        }
        free(buf);
      }

      for(res = hd->res; res; res = res->next) {
        if(res->any.type == res_link) break;
      }

      if(!res) get_linkstate(hd_data, hd);

      if(!(hd_card = hd_get_device_by_idx(hd_data, hd->attached_to))) continue;

      for(res = hd->res; res; res = res->next) {
        if(res->any.type == res_link) break;
      }

      if(res) {
        for(res1 = hd_card->res; res1; res1 = res1->next) {
          if(res1->any.type == res_link) break;
        }
        if(res && !res1) {
          res1 = new_mem(sizeof *res1);
          res1->link.type = res_link;
          res1->link.state = res->link.state;
          add_res_entry(&hd_card->res, res1);
        }
      }
    }
  }
}
Example #17
0
/*
 * Read kernel log info. Combine with /var/log/boot.msg.
 */
void _read_klog(hd_data_t *hd_data)
{
  char buf[0x2000 + 1], *s;
  int i, j, len, n;
  str_list_t *sl, *sl1, *sl2, *sl_last, **ssl, *sl_next;

  /* some clean-up */
  hd_data->klog = free_str_list(hd_data->klog);

  sl1 = read_file(KLOG_BOOT, 0, 0);
  sl2 = NULL;

  /*
   * remove non-canonical lines (not starting with <[0-9]>) at the start and
   * at the end
   */

  /* note: the implementations assumes that at least *one* line is ok */
  for(sl_last = NULL, sl = sl1; sl; sl = (sl_last = sl)->next) {
    if(str_ok(sl)) {
      if(sl_last) {
        sl_last->next = NULL;
        free_str_list(sl1);
        sl1 = sl;
      }
      break;
    }
  }

  for(sl_last = NULL, sl = sl1; sl; sl = (sl_last = sl)->next) {
    if(!str_ok(sl)) {
      if(sl_last) {
        sl_last->next = NULL;
        free_str_list(sl);
      }
      break;
    }
  }

  n = klogctl(3, buf, sizeof buf - 1);
  if(n <= 0) {
    hd_data->klog = sl1;
    return;
  }

  if(n > (int) sizeof buf - 1) n = sizeof buf - 1;
  buf[n] = 0;
  for(i = j = 0; i < n; i++) {
    if(buf[i] == '\n') {
      len = i - j + 1;
      s = new_mem(len + 1);
      memcpy(s, buf + j, len);
      add_str_list(&sl2, s);
      s = free_mem(s);
      j = i + 1;
    }
  }

  /* the 1st line may be incomplete */
  if(sl2 && !str_ok(sl2)) {
    sl_next = sl2->next;
    sl2->next = NULL;
    free_str_list(sl2);
    sl2 = sl_next;
  }

  if(!sl1) {
    hd_data->klog = sl2;
    return;
  }

  if(sl1 && !sl2) {
    hd_data->klog = sl1;
    return;
  }

  /* now, try to join sl1 & sl2 */
  for(sl_last = NULL, sl = sl1; sl; sl = (sl_last = sl)->next) {
    if(!str_list_cmp(sl, sl2)) {
      free_str_list(sl);
      if(sl_last)
        sl_last->next = NULL;
      else
        sl1 = NULL;
      break;
    }
  }

  /* append sl2 to sl1 */
  for(ssl = &sl1; *ssl; ssl = &(*ssl)->next);
  *ssl = sl2;

  hd_data->klog = sl1;
}
Example #18
0
void get_input_devices(hd_data_t *hd_data)
{
  hd_t *hd;
  str_list_t *input, *sl, *sl1;
  char *s;
  unsigned ok, u, is_mouse, is_joystick;
  unsigned bus, vendor, product, version;
  unsigned mouse_buttons, mouse_wheels;
  char *name = NULL, *handlers = NULL, *key = NULL, *rel = NULL, *abso = NULL;
  size_t len;
  str_list_t *handler_list;
  hd_dev_num_t dev_num = { type: 'c', range: 1 };

  input = read_file("/proc/bus/input/devices", 0, 0);

  ADD2LOG("----- /proc/bus/input/devices -----\n");
  for(sl = input; sl; sl = sl->next) {
    ADD2LOG("  %s", sl->str);
  }
  ADD2LOG("----- /proc/bus/input/devices end -----\n");

  for(ok = 0, sl = input; sl; sl = sl->next) {
    if(*sl->str == '\n') {
      ADD2LOG("bus = %u, name = %s\n", bus, name);
      if(handlers) ADD2LOG("  handlers = %s\n", handlers);
      if(key) ADD2LOG("  key = %s\n", key);
      if(rel) ADD2LOG("  rel = %s\n", rel);
      if(abso) ADD2LOG("  abs = %s\n", abso);

      mouse_buttons = 0;
      if(key) {
        for(u = BTN_MOUSE; u < BTN_MOUSE + 8; u++) {
          if(test_bit(key, u)) mouse_buttons++;
        }
      }
      ADD2LOG("  mouse buttons = %u\n", mouse_buttons);

      mouse_wheels = 0;
      if(rel) {
        for(u = REL_HWHEEL; u <= REL_MAX; u++) {
          if(test_bit(rel, u)) mouse_wheels++;
        }
      }
      ADD2LOG("  mouse wheels = %u\n", mouse_wheels);

      if(ok && handlers) {
        handler_list = hd_split(' ', handlers);

        is_mouse = strstr(handlers, "mouse") ? 1 : 0;
        is_joystick = strstr(handlers, "js") ? 1 : 0;

        if(	// HP Virtual Management Device
          vendor == 0x03f0 &&
          product == 0x1126 &&
          mouse_buttons >= 3
        ) is_mouse = 1;

        ADD2LOG("  is_mouse = %u\n", is_mouse);
        ADD2LOG("  is_joystick = %u\n", is_joystick);

        if(bus == BUS_USB) {
          s = NULL;
          for(sl1 = handler_list; sl1; sl1 = sl1->next) {
            if(sscanf(sl1->str, "mouse%u", &u) == 1) {
              str_printf(&s, 0, "/dev/input/mouse%u", u);
              break;
            }
          }

          if(!s && (is_mouse || is_joystick)) for(sl1 = handler_list; sl1; sl1 = sl1->next) {
            if(sscanf(sl1->str, "event%u", &u) == 1) {
              str_printf(&s, 0, "/dev/input/event%u", u);
              break;
            }
          }

          if(s) {
            for(hd = hd_data->hd; hd; hd = hd->next) {
              if(
                (hd->unix_dev_name2 && !strcmp(hd->unix_dev_name2, s)) ||
                (hd->unix_dev_name && !strcmp(hd->unix_dev_name, s))
              ) {
                if(!hd->base_class.id) {
		  if (is_mouse)
		  {
		    hd->base_class.id = bc_mouse;
		    hd->sub_class.id = sc_mou_usb;
		  }
		  else if (is_joystick)
		  {
		    hd->base_class.id = bc_joystick;
		  }
                }

		if (is_mouse)
		{
		  hd_set_hw_class(hd, hw_mouse);
                  hd->compat_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0210);
                  hd->compat_device.id = MAKE_ID(TAG_SPECIAL, (mouse_wheels << 4) + mouse_buttons);
		}
		else if (is_joystick)
		{
		  hd_set_hw_class(hd, hw_joystick);

		  /* add buttons and axis details */
		  add_joystick_details(hd_data, hd, key, abso);
		}

                if(hd->unix_dev_name) add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
                if(hd->unix_dev_name2) add_str_list(&hd->unix_dev_names, hd->unix_dev_name2);

                for(sl1 = handler_list; sl1; sl1 = sl1->next) {
                  if(sscanf(sl1->str, "event%u", &u) == 1) {
                    str_printf(&s, 0, "/dev/input/event%u", u);
                    if(!search_str_list(hd->unix_dev_names, s)) add_str_list(&hd->unix_dev_names, s);
                    s = free_mem(s);
                  }
		  /* add /dev/input/jsN joystick device name */
		  else if (is_joystick)
		  {
		    if(sscanf(sl1->str, "js%u", &u) == 1) {
		      str_printf(&s, 0, "/dev/input/js%u", u);
		      if(!search_str_list(hd->unix_dev_names, s)) add_str_list(&hd->unix_dev_names, s);
		      if(!hd->unix_dev_name2) hd->unix_dev_name2 = new_str(s);
		      s = free_mem(s);
		    }
		  }
                }

                break;
              }
            }
          }

          s = free_mem(s);

        }
        else {
	  // keyboard
          if(search_str_list(handler_list, "kbd") && test_bit(key, KEY_1)) {
            hd = add_hd_entry(hd_data, __LINE__, 0);
            hd->base_class.id = bc_keyboard;
            hd->sub_class.id = sc_keyboard_kbd;
            hd->bus.id = bus_ps2;

            hd->vendor.id = MAKE_ID(0, vendor);
            hd->device.id = MAKE_ID(0, product);
            hd->compat_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0211);
            hd->compat_device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
            hd->device.name = new_str(name);

            for(sl1 = handler_list; sl1; sl1 = sl1->next) {
              if(sscanf(sl1->str, "event%u", &u) == 1) {
                str_printf(&hd->unix_dev_name, 0, "/dev/input/event%u", u);
                dev_num.major = 13;
                dev_num.minor = 64 + u;
                hd->unix_dev_num = dev_num;
                break;
              }
            }
          }
	  // mouse
          else if(is_mouse) {
            hd = add_hd_entry(hd_data, __LINE__, 0);

            hd->vendor.id = MAKE_ID(0, vendor);
            hd->device.id = MAKE_ID(0, product);

            hd->compat_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0210);
            hd->compat_device.id = MAKE_ID(TAG_SPECIAL, (mouse_wheels << 4) + mouse_buttons);

            hd->base_class.id = bc_mouse;
            if(bus == BUS_ADB) {
              hd->sub_class.id = sc_mou_bus;
              hd->bus.id = bus_adb;
            }
            else {
              hd->sub_class.id = sc_mou_ps2;
              hd->bus.id = bus_ps2;
            }

            hd->device.name = new_str(name);

#if 0
            /* Synaptics/Alps TouchPad */
            if(
              vendor == 2 &&
              (product == 7 || product == 8) &&
              test_bit(abso, ABS_X) &&
              test_bit(abso, ABS_Y) &&
              test_bit(abso, ABS_PRESSURE) &&
              test_bit(key, BTN_TOOL_FINGER)
            ) {
            }
#endif

            hd->unix_dev_name = new_str(DEV_MICE);
            dev_num.major = 13;
            dev_num.minor = 63;
            hd->unix_dev_num = dev_num;

            for(sl1 = handler_list; sl1; sl1 = sl1->next) {
              if(sscanf(sl1->str, "mouse%u", &u) == 1) {
                str_printf(&hd->unix_dev_name2, 0, "/dev/input/mouse%u", u);
                dev_num.major = 13;
                dev_num.minor = 32 + u;
                hd->unix_dev_num2 = dev_num;
                break;
              }
            }

            add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
            add_str_list(&hd->unix_dev_names, hd->unix_dev_name2);

            for(sl1 = handler_list; sl1; sl1 = sl1->next) {
              if(sscanf(sl1->str, "event%u", &u) == 1) {
                s = NULL;
                str_printf(&s, 0, "/dev/input/event%u", u);
                add_str_list(&hd->unix_dev_names, s);
                s = free_mem(s);
                break;
              }
            }
          }
	  // joystick
          else if(is_joystick) {
            hd = add_hd_entry(hd_data, __LINE__, 0);

            hd->vendor.id = MAKE_ID(0, vendor);
            hd->device.id = MAKE_ID(0, product);

	    hd_set_hw_class(hd, hw_joystick);
            hd->base_class.id = bc_joystick;
            hd->device.name = new_str(name);

	    // gameport? (see <linux/input.h>)
	    if (bus == BUS_GAMEPORT) hd->bus.id = bus_gameport;

	    /* add buttons and axis details */
	    add_joystick_details(hd_data, hd, key, abso);

	    // add eventX device
            for(sl1 = handler_list; sl1; sl1 = sl1->next) {
              if(sscanf(sl1->str, "event%u", &u) == 1) {
                str_printf(&hd->unix_dev_name, 0, "/dev/input/event%u", u);
                dev_num.major = 13;
                dev_num.minor = 64 + u;
                hd->unix_dev_num = dev_num;
                break;
              }
            }

	    // add jsX device
            for(sl1 = handler_list; sl1; sl1 = sl1->next) {
              if(sscanf(sl1->str, "js%u", &u) == 1) {
                str_printf(&hd->unix_dev_name2, 0, "/dev/input/js%u", u);
                break;
              }
            }

            add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
            add_str_list(&hd->unix_dev_names, hd->unix_dev_name2);
	  }
	  else
	  {
	    ADD2LOG("unknown non-USB input device\n");
	  }
        }

        handler_list = free_str_list(handler_list);
      }

      ok = 0;

      name = free_mem(name);
      handlers = free_mem(handlers);
      key = free_mem(key);
      rel = free_mem(rel);
      abso = free_mem(abso);
    }

    if(sscanf(sl->str, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x", &bus, &vendor, &product, &version) == 4) {
      ok = 1;
      continue;
    }

    if(!strncmp(sl->str, INP_NAME, sizeof INP_NAME - 1)) {
      s = sl->str + sizeof INP_NAME;
      len = strlen(s);
      if(len > 2) {
        name = canon_str(s, len - 2);
      }
      continue;
    }

    if(!strncmp(sl->str, INP_HANDLERS, sizeof INP_HANDLERS - 1)) {
      s = sl->str + sizeof INP_HANDLERS - 1;
      handlers = canon_str(s, strlen(s));
      continue;
    }

    if(!strncmp(sl->str, INP_KEY, sizeof INP_KEY - 1)) {
      s = sl->str + sizeof INP_KEY - 1;
      key = canon_str(s, strlen(s));
      key = all_bits(key);
      continue;
    }

    if(!strncmp(sl->str, INP_REL, sizeof INP_REL - 1)) {
      s = sl->str + sizeof INP_REL - 1;
      rel = canon_str(s, strlen(s));
      rel = all_bits(rel);
      continue;
    }

    if(!strncmp(sl->str, INP_ABS, sizeof INP_ABS - 1)) {
      s = sl->str + sizeof INP_ABS - 1;
      abso = canon_str(s, strlen(s));
      abso = all_bits(abso);
      continue;
    }
  }

  free_str_list(input);

}


char *all_bits(char *str)
{
  str_list_t *sl, *sl0;
  char *s = NULL;
  unsigned long u;

  if(!str) return NULL;

  sl = sl0 = hd_split(' ', str);
  for(; sl; sl = sl->next) {
    u = strtoul(sl->str, NULL, 16);
    str_printf(&s, -1, "%0*lx", (int) sizeof (unsigned long) * 2, u);
  }
  free_str_list(sl0);
  free_mem(str);

  return s;
}
Example #19
0
void get_usb_devs(hd_data_t *hd_data)
{
  uint64_t ul0;
  unsigned u1, u2, u3;
  hd_t *hd, *hd1;
  usb_t *usb;
  str_list_t *sl, *usb_devs = NULL;
  char *s, *s1, *t;
  hd_res_t *res;
  size_t l;
  str_list_t *sf_bus, *sf_bus_e;
  char *sf_dev, *sf_dev_2;

  sf_bus = read_dir("/sys/bus/usb/devices", 'l');

  if(!sf_bus) {
    ADD2LOG("sysfs: no such bus: usb\n");
    return;
  }

  for(sf_bus_e = sf_bus; sf_bus_e; sf_bus_e = sf_bus_e->next) {
    sf_dev = hd_read_sysfs_link("/sys/bus/usb/devices", sf_bus_e->str);

    if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "bNumInterfaces"), &ul0, 0)) {
      add_str_list(&usb_devs, sf_dev);
      ADD2LOG("  usb dev: %s\n", hd_sysfs_id(sf_dev));
    }
  }

  for(sf_bus_e = sf_bus; sf_bus_e; sf_bus_e = sf_bus_e->next) {
    sf_dev = new_str(hd_read_sysfs_link("/sys/bus/usb/devices", sf_bus_e->str));

    ADD2LOG(
      "  usb device: name = %s\n    path = %s\n",
      sf_bus_e->str,
      hd_sysfs_id(sf_dev)
    );

    if(
      hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "bInterfaceNumber"), &ul0, 16)
    ) {
      hd = add_hd_entry(hd_data, __LINE__, 0);

      hd->detail = new_mem(sizeof *hd->detail);
      hd->detail->type = hd_detail_usb;
      hd->detail->usb.data = usb = new_mem(sizeof *usb);

      hd->sysfs_id = new_str(hd_sysfs_id(sf_dev));
      hd->sysfs_bus_id = new_str(sf_bus_e->str);

      hd->bus.id = bus_usb;
      hd->func = ul0;

      usb->ifdescr = ul0;

      if((s = get_sysfs_attr_by_path(sf_dev, "modalias"))) {
        s = canon_str(s, strlen(s));
        ADD2LOG("    modalias = \"%s\"\n", s);
        if(s && *s) {
          hd->modalias = s;
          s = NULL;
        }
        s = free_mem(s);
      }

      ADD2LOG("    bInterfaceNumber = %u\n", hd->func);

      if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "bInterfaceClass"), &ul0, 16)) {
        usb->i_cls = ul0;
        ADD2LOG("    bInterfaceClass = %u\n", usb->i_cls);
      }

      if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "bInterfaceSubClass"), &ul0, 16)) {
        usb->i_sub = ul0;
        ADD2LOG("    bInterfaceSubClass = %u\n", usb->i_sub);
      }

      if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "bInterfaceProtocol"), &ul0, 16)) {
        usb->i_prot = ul0;
        ADD2LOG("    bInterfaceProtocol = %u\n", usb->i_prot);
      }

      /* device has longest matching sysfs id */
      u2 = strlen(sf_dev);
      s = NULL;
      for(u3 = 0, sl = usb_devs; sl; sl = sl->next) {
        u1 = strlen(sl->str);
        if(u1 > u3 && u1 <= u2 && !strncmp(sf_dev, sl->str, u1)) {
          u3 = u1;
          s = sl->str;
        }
      }

      if(s) {
        ADD2LOG("    if: %s @ %s\n", hd->sysfs_bus_id, hd_sysfs_id(s));
        sf_dev_2 = new_str(s);
        if(sf_dev_2) {

          if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev_2, "bDeviceClass"), &ul0, 16)) {
            usb->d_cls = ul0;
            ADD2LOG("    bDeviceClass = %u\n", usb->d_cls);
          }

          if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev_2, "bDeviceSubClass"), &ul0, 16)) {
            usb->d_sub = ul0;
            ADD2LOG("    bDeviceSubClass = %u\n", usb->d_sub);
          }

          if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev_2, "bDeviceProtocol"), &ul0, 16)) {
            usb->d_prot = ul0;
            ADD2LOG("    bDeviceProtocol = %u\n", usb->d_prot);
          }

          if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev_2, "idVendor"), &ul0, 16)) {
            usb->vendor = ul0;
            ADD2LOG("    idVendor = 0x%04x\n", usb->vendor);
          }

          if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev_2, "idProduct"), &ul0, 16)) {
            usb->device = ul0;
            ADD2LOG("    idProduct = 0x%04x\n", usb->device);
          }

          if((s = get_sysfs_attr_by_path(sf_dev_2, "manufacturer"))) {
            usb->manufact = canon_str(s, strlen(s));
            ADD2LOG("    manufacturer = \"%s\"\n", usb->manufact);
          }

          if((s = get_sysfs_attr_by_path(sf_dev_2, "product"))) {
            usb->product = canon_str(s, strlen(s));
            ADD2LOG("    product = \"%s\"\n", usb->product);
          }

          if((s = get_sysfs_attr_by_path(sf_dev_2, "serial"))) {
            usb->serial = canon_str(s, strlen(s));
            ADD2LOG("    serial = \"%s\"\n", usb->serial);
          }

          if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev_2, "bcdDevice"), &ul0, 16)) {
            usb->rev = ul0;
            ADD2LOG("    bcdDevice = %04x\n", usb->rev);
          }

          if((s = get_sysfs_attr_by_path(sf_dev_2, "speed"))) {
            s = canon_str(s, strlen(s));
            if(!strcmp(s, "1.5")) usb->speed = 15*100000;
            else if(!strcmp(s, "12")) usb->speed = 12*1000000;
            else if(!strcmp(s, "480")) usb->speed = 480*1000000;
            ADD2LOG("    speed = \"%s\"\n", s);
            s = free_mem(s);
          }

          sf_dev_2 = free_mem(sf_dev_2);
        }
      }

      if(usb->vendor || usb->device) {
        hd->vendor.id = MAKE_ID(TAG_USB, usb->vendor);
        hd->device.id = MAKE_ID(TAG_USB, usb->device);
      }

      if(usb->manufact) hd->vendor.name = new_str(usb->manufact);
      if(usb->product) hd->device.name = new_str(usb->product);
      if(usb->serial) hd->serial = new_str(usb->serial);

      if(usb->rev) str_printf(&hd->revision.name, 0, "%x.%02x", usb->rev >> 8, usb->rev & 0xff);

      if(usb->speed) {
        res = add_res_entry(&hd->res, new_mem(sizeof *res));
        res->baud.type = res_baud;
        res->baud.speed = usb->speed;
      }

      s = hd_sysfs_find_driver(hd_data, hd->sysfs_id, 1);
      if(s) add_str_list(&hd->drivers, s);

      set_class_entries(hd_data, hd, usb);

      if(!hd_data->scanner_db) {
        hd_data->scanner_db = hd_module_list(hd_data, 1);
      }

      if(
        hd->drivers &&
        search_str_list(hd_data->scanner_db, hd->drivers->str)
      ) {
        hd->base_class.id = bc_scanner;
      }

      // ###### FIXME
      if(hd->base_class.id == bc_modem) {
        hd->unix_dev_name = new_str("/dev/ttyACM0");
      }
    }

    sf_dev = free_mem(sf_dev);
  }
Example #20
0
void pcmcia_read_data(hd_data_t *hd_data)
{
  hd_t *hd, *hd2;
  unsigned u0, u1, func_id;
  uint64_t ul0;
  char *s, *t;
  char *prod1, *prod2, *prod3, *prod4;
  str_list_t *sl;
  str_list_t *sf_bus, *sf_bus_e;
  char *sf_dev;

  sf_bus = reverse_str_list(read_dir("/sys/bus/pcmcia/devices", 'l'));

  if(!sf_bus) {
    ADD2LOG("sysfs: no such bus: pcmcia\n");
    return;
  }

  for(sf_bus_e = sf_bus; sf_bus_e; sf_bus_e = sf_bus_e->next) {
    sf_dev = new_str(hd_read_sysfs_link("/sys/bus/pcmcia/devices", sf_bus_e->str));

    ADD2LOG(
      "  pcmcia device: name = %s\n    path = %s\n",
      sf_bus_e->str,
      hd_sysfs_id(sf_dev)
    );

    if(sscanf(sf_bus_e->str, "%x.%x", &u0, &u1) != 2) continue;

    hd = add_hd_entry(hd_data, __LINE__, 0);

    hd->sysfs_id = new_str(hd_sysfs_id(sf_dev));
    hd->sysfs_bus_id = new_str(sf_bus_e->str);
    hd->bus.id = bus_pcmcia;

    hd->slot = u0;
    hd->func = u1;
    hd->hotplug_slot = u0 + 1;
    hd->hotplug = hp_pcmcia;

    s = hd_sysfs_find_driver(hd_data, hd->sysfs_id, 1);
    if(s) add_str_list(&hd->drivers, s);

    if((s = get_sysfs_attr_by_path(sf_dev, "modalias"))) {
      hd->modalias = canon_str(s, strlen(s));
      ADD2LOG("    modalias = \"%s\"\n", s);
    }

    if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "manf_id"), &ul0, 0)) {
      ADD2LOG("    manf_id = 0x%04x\n", (unsigned) ul0);
      hd->vendor.id = MAKE_ID(TAG_PCMCIA, ul0);
    }

    if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "card_id"), &ul0, 0)) {
      ADD2LOG("    card_id = 0x%04x\n", (unsigned) ul0);
      hd->device.id = MAKE_ID(TAG_PCMCIA, ul0);
    }

    /*
     * "multifunction", "memory", "serial", "parallel",
     * "fixed disk", "video", "network", "AIMS",
     * "SCSI"
     */
    func_id = 0;
    if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "func_id"), &ul0, 0)) {
      func_id = ul0;
      ADD2LOG("    func_id = 0x%04x\n", func_id);
    }

    prod1 = NULL;
    if((s = get_sysfs_attr_by_path(sf_dev, "prod_id1"))) {
      prod1 = canon_str(s, strlen(s));
      ADD2LOG("    prod_id1 = \"%s\"\n", prod1);
    }

    prod2 = NULL;
    if((s = get_sysfs_attr_by_path(sf_dev, "prod_id2"))) {
      prod2 = canon_str(s, strlen(s));
      ADD2LOG("    prod_id2 = \"%s\"\n", prod2);
    }

    prod3 = NULL;
    if((s = get_sysfs_attr_by_path(sf_dev, "prod_id3"))) {
      prod3 = canon_str(s, strlen(s));
      ADD2LOG("    prod_id3 = \"%s\"\n", prod3);
    }

    prod4 = NULL;
    if((s = get_sysfs_attr_by_path(sf_dev, "prod_id4"))) {
      prod4 = canon_str(s, strlen(s));
      ADD2LOG("    prod_id4 = \"%s\"\n", prod4);
    }

    if(func_id == 6) {
      hd->base_class.id = bc_network;
      hd->sub_class.id = 0x80;		/* other */
    }

    if(prod1 && *prod1) {
      add_str_list(&hd->extra_info, prod1);
      hd->vendor.name = prod1;
      prod1 = NULL;
    }
    if(prod2 && *prod2) {
      add_str_list(&hd->extra_info, prod2);
      hd->device.name = prod2;
      prod2 = NULL;
    }
    if(prod3 && *prod3) add_str_list(&hd->extra_info, prod3);
    if(prod4 && *prod4) add_str_list(&hd->extra_info, prod4);

    for(sl = hd->extra_info; sl ; sl = sl->next) {
      if(strstr(sl->str, "Ethernet")) hd->sub_class.id = 0;	/* ethernet */
      if(
        !hd->revision.name &&
        !sl->next &&
        (
          !strncasecmp(sl->str, "rev.", sizeof "rev." - 1) ||
          (
            (sl->str[0] == 'V' || sl->str[0] == 'v') &&
            (sl->str[1] >= '0' && sl->str[1] <= '9')
          )
        )
      ) {
        hd->revision.name = new_str(sl->str);
      }
    }

    prod1 = free_mem(prod1);
    prod2 = free_mem(prod2);
    prod3 = free_mem(prod3);
    prod4 = free_mem(prod4);

    s = new_str(hd->sysfs_id);

    if((t = strrchr(s, '/'))) {
      *t = 0;
      if((hd2 = hd_find_sysfs_id(hd_data, s))) {
        hd->attached_to = hd2->idx;
      }
    }
    free_mem(s);

    free_mem(sf_dev);
  }

  free_str_list(sf_bus);
}