Exemple #1
0
void int_bios(hd_data_t *hd_data)
{
  hd_t *hd, *hd_boot;
  int i, start, bios = 0x80;
  int ide_1st;
  char ide_name[] = "/dev/hda";
  char scsi_name[] = "/dev/sda";
  char *s;

  hd_boot = hd_get_device_by_idx(hd_data, hd_boot_disk(hd_data, &i));

  if(hd_boot) {
    free_mem(hd_boot->rom_id);
    hd_boot->rom_id = new_str("0x80");
  }

  if(!hd_boot || i != 1) return;

  if(strstr(hd_boot->unix_dev_name, "/dev/sd") == hd_boot->unix_dev_name) {
    ide_1st = 0;
    start = hd_boot->unix_dev_name[sizeof "/dev/sd" - 1] - 'a';
  }
  else if(strstr(hd_boot->unix_dev_name, "/dev/hd") == hd_boot->unix_dev_name) {
    ide_1st = 1;
    start = hd_boot->unix_dev_name[sizeof "/dev/hd" - 1] - 'a';
  }
  else {
    return;
  }

  if(start < 0) return;

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(
      hd->base_class.id == bc_storage_device &&
      hd->sub_class.id == sc_sdev_disk
    ) {
      hd->rom_id = free_mem(hd->rom_id);
    }
  }

  s = ide_1st ? ide_name : scsi_name;

  for(i = start; i < 26; i++) {
    s[strlen(s) - 1] = 'a' + i;
    bios += set_bios_id(hd_data, s, bios);
  }

  for(i = 0; i < start; i++) {
    s[strlen(s) - 1] = 'a' + i;
    bios += set_bios_id(hd_data, s, bios);
  }

  s = ide_1st ? scsi_name : ide_name;

  for(i = 0; i < 26; i++) {
    s[strlen(s) - 1] = 'a' + i;
    bios += set_bios_id(hd_data, s, bios);
  }
}
Exemple #2
0
void int_bios(hd_data_t *hd_data)
{
  hd_t *hd, *hd_boot;
  unsigned *sctrl, *sctrl2;
  int sctrl_len, i, j;
  int bios_id, list_sorted;

  /* don't do anything if there is useful edd info */
  if(hd_data->flags.edd_used) return;

  for(i = 0, hd = hd_data->hd; hd; hd = hd->next) {
    if(
      hd->base_class.id == bc_storage_device &&
      hd->sub_class.id == sc_sdev_disk
    ) {
      i++;
    }
  }

  if(!i) return;

  sctrl = new_mem(i * sizeof *sctrl);

  /* sctrl: list of storage controllers with disks */

  for(sctrl_len = 0, hd = hd_data->hd; hd; hd = hd->next) {
    if(
      hd->base_class.id == bc_storage_device &&
      hd->sub_class.id == sc_sdev_disk
    ) {
      for(i = 0; i < sctrl_len; i++) {
        if(sctrl[i] == hd->attached_to) break;
      }
      if(i == sctrl_len) sctrl[sctrl_len++] = hd->attached_to;
    }
  }

  /* sort list, if possible */

  list_sorted = bios_ctrl_order(hd_data, sctrl, sctrl_len);

  hd_boot = hd_get_device_by_idx(hd_data, hd_boot_disk(hd_data, &i));

  /* if we know the boot device, make this controller the first */

  if(hd_boot && hd_boot->attached_to && i == 1) {
    for(i = 0; i < sctrl_len; i++) {
      if(sctrl[i] == hd_boot->attached_to) break;
    }
    if(i < sctrl_len) {
      sctrl2 = new_mem(sctrl_len * sizeof *sctrl2);
      *sctrl2 = hd_boot->attached_to;
      for(i = 0, j = 1; i < sctrl_len; i++) {
        if(sctrl[i] != hd_boot->attached_to) sctrl2[j++] = sctrl[i];
      }
      free_mem(sctrl);
      sctrl = sctrl2;
    }
  }
  else {
    hd_boot = NULL;
  }

  if(hd_boot) ADD2LOG("  bios boot dev: %d\n", hd_boot->idx);
  for(i = 0; i < sctrl_len; i++) {
    ADD2LOG("  bios ctrl %d: %d\n", i, sctrl[i]);
  }

  /* remove existing entries */

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(
      hd->base_class.id == bc_storage_device &&
      hd->sub_class.id == sc_sdev_disk
    ) {
      hd->rom_id = free_mem(hd->rom_id);
    }
  }

  if(!list_sorted && !hd_boot && sctrl_len > 1) {
    /* we have no info at all */
    sctrl_len = 0;
  }
  else if(!list_sorted && hd_boot && sctrl_len > 2) {
    /* we know which controller has the boot device */
    sctrl_len = 1;
  }

  bios_id = 0x80;

  /* rely on it */

  if(hd_boot) {
    bios_id += set_bios_id(hd_data, hd_boot, bios_id);
  }

  /* assign all the others */

  for(i = 0; i < sctrl_len; i++) {
    for(hd = hd_data->hd; hd; hd = hd->next) {
      if(
        hd->base_class.id == bc_storage_device &&
        hd->sub_class.id == sc_sdev_disk &&
        hd->attached_to == sctrl[i] &&
        !hd->rom_id
      ) {
        bios_id += set_bios_id(hd_data, hd, bios_id);
      }
    }
  }

  free_mem(sctrl);
}
Exemple #3
0
void add_serial_modem(hd_data_t *hd_data)
{
  hd_t *hd;
  char buf[4];
  ser_device_t *sm;
  hd_res_t *res;

  for(sm = hd_data->ser_modem; sm; sm = sm->next) {
    if(!sm->is_modem) continue;

    hd = hd_get_device_by_idx(hd_data, sm->hd_idx);
    if(hd && hd->base_class.id == bc_modem) {
      /* just *add* info */

    }
    else {
      hd = add_hd_entry(hd_data, __LINE__, 0);
      hd->base_class.id = bc_modem;
      hd->bus.id = bus_serial;
      hd->unix_dev_name = new_str(sm->dev_name);
      hd->attached_to = sm->hd_idx;
      res = add_res_entry(&hd->res, new_mem(sizeof *res));
      res->baud.type = res_baud;
      res->baud.speed = sm->max_baud;
      if(sm->pppd_option) {
	res = add_res_entry(&hd->res, new_mem(sizeof *res));
	res->pppd_option.type = res_pppd_option;
	res->pppd_option.option = new_str(sm->pppd_option);
      }
      if(*sm->pnp_id) {
        strncpy(buf, sm->pnp_id, 3);
        buf[3] = 0;
        hd->vendor.id = name2eisa_id(buf);
        hd->device.id = MAKE_ID(TAG_EISA, strtol(sm->pnp_id + 3, NULL, 16));
      }
      hd->serial = new_str(sm->serial);
      if(sm->user_name) hd->device.name = new_str(sm->user_name);
      if(sm->vend) hd->vendor.name = new_str(sm->vend);

      if(sm->dev_id && strlen(sm->dev_id) >= 7) {
        char buf[5], *s;
        unsigned u1, u2;

        u1 = name2eisa_id(sm->dev_id);
        if(u1) {
          strncpy(buf, sm->dev_id + 3, 4);
          buf[4] = 0;
          u2 = strtol(sm->dev_id + 3, &s, 16);
          if(!*s) {
            hd->compat_vendor.id = u1;
            hd->compat_device.id = MAKE_ID(TAG_EISA, u2);
          }
        }
      }

      if(!(hd->device.id || hd->device.name || hd->vendor.id || hd->vendor.name)) {
        hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x2000);
        hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
      }
    }
    res = add_res_entry(&hd->res, new_mem(sizeof *res));
    res->init_strings.type = res_init_strings;
    res->init_strings.init1 = new_str(sm->init_string1);
    res->init_strings.init2 = new_str(sm->init_string2);
  }
}
Exemple #4
0
static int ntfs_device_get_geo(struct ntfs_device *dev)
{
	int err;

	if (!dev) {
		errno = EINVAL;
		return -1;
	}
	err = EOPNOTSUPP;
#ifdef ENABLE_HD
	{
		hd_data_t *hddata;
		hd_t *hd, *devlist, *partlist = NULL;
		str_list_t *names;
		hd_res_t *res;
		const int d_name_len = strlen(dev->d_name) + 1;
		int done = 0;

		hddata = calloc(1, sizeof(*hddata));
		if (!hddata) {
			err = ENOMEM;
			goto skip_hd;
		}
		/* List all "disk" class devices on the system. */
		devlist = hd_list(hddata, hw_disk, 1, NULL);
		if (!devlist) {
			free(hddata);
			err = ENOMEM;
			goto skip_hd;
		}
		/*
		 * Loop over each disk device looking for the device with the
		 * same unix name as @dev.
		 */
		for (hd = devlist; hd; hd = hd->next) {
			if (hd->unix_dev_name && !strncmp(dev->d_name,
					hd->unix_dev_name, d_name_len))
				goto got_hd;
			if (hd->unix_dev_name2 && !strncmp(dev->d_name,
					hd->unix_dev_name2, d_name_len))
				goto got_hd;
			for (names = hd->unix_dev_names; names;
					names = names->next) {
				if (names->str && !strncmp(dev->d_name,
						names->str, d_name_len))
					goto got_hd;
			}
		}
		/*
		 * Device was not a whole disk device.  Unless it is a file it
		 * is likely to be a partition device.  List all "partition"
		 * class devices on the system.
		 */
		partlist = hd_list(hddata, hw_partition, 1, NULL);
		for (hd = partlist; hd; hd = hd->next) {
			if (hd->unix_dev_name && !strncmp(dev->d_name,
					hd->unix_dev_name, d_name_len))
				goto got_part_hd;
			if (hd->unix_dev_name2 && !strncmp(dev->d_name,
					hd->unix_dev_name2, d_name_len))
				goto got_part_hd;
			for (names = hd->unix_dev_names; names;
					names = names->next) {
				if (names->str && !strncmp(dev->d_name,
						names->str, d_name_len))
					goto got_part_hd;
			}
		}
		/* Failed to find the device.  Stop trying and clean up. */
		goto end_hd;
got_part_hd:
		/* Get the whole block device the partition device is on. */
		hd = hd_get_device_by_idx(hddata, hd->attached_to);
		if (!hd)
			goto end_hd;
got_hd:
		/*
		 * @hd is now the whole block device either being formatted or
		 * that the partition being formatted is on.
		 *
		 * Loop over each resource of the disk device looking for the
		 * BIOS legacy geometry obtained from EDD which is what Windows
		 * needs to boot.
		 */
		for (res = hd->res; res; res = res->next) {
			/* geotype 3 is BIOS legacy. */
			if (res->any.type != res_disk_geo ||
					res->disk_geo.geotype != 3)
				continue;
			dev->d_heads = res->disk_geo.heads;
			dev->d_sectors_per_track = res->disk_geo.sectors;
			done = 1;
		}
end_hd:
		if (partlist)
			hd_free_hd_list(partlist);
		hd_free_hd_list(devlist);
		hd_free_hd_data(hddata);
		free(hddata);
		if (done) {
			ntfs_log_debug("EDD/BIOD legacy heads = %u, sectors "
					"per track = %u\n", dev->d_heads,
					dev->d_sectors_per_track);
			return 0;
		}
	}
skip_hd:
#endif
#ifdef HDIO_GETGEO
	{	struct hd_geometry geo;

		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
			dev->d_heads = geo.heads;
			dev->d_sectors_per_track = geo.sectors;
			ntfs_log_debug("HDIO_GETGEO heads = %u, sectors per "
					"track = %u\n", dev->d_heads,
					dev->d_sectors_per_track);
			return 0;
		}
		err = errno;
	}
#endif
	errno = err;
	return -1;
}
Exemple #5
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);
        }
      }
    }
  }
}
void pcmcia_ctrl_read_data(hd_data_t *hd_data)
{
  hd_t *hd, *bridge_hd;
  char *s;
  unsigned u;
  unsigned sockets[16 /* just large enough */] = { };
  str_list_t *sf_class, *sf_class_e;
  char *sf_cdev = NULL, *sf_dev;

  sf_class = reverse_str_list(read_dir("/sys/class/pcmcia_socket", 'd'));

  if(!sf_class) {
    ADD2LOG("sysfs: no such class: pcmcia_socket\n");
  }
  else {
    for(sf_class_e = sf_class; sf_class_e; sf_class_e = sf_class_e->next) {
      str_printf(&sf_cdev, 0, "/sys/class/pcmcia_socket/%s", sf_class_e->str);
      sf_dev = new_str(hd_read_sysfs_link(sf_cdev, "device"));

      if(
        sf_dev &&
        sscanf(sf_class_e->str, "pcmcia_socket%u", &u) == 1
      ) {
        s = hd_sysfs_id(sf_dev);
        hd = hd_find_sysfs_id(hd_data, s);
        if(hd && u < sizeof sockets / sizeof *sockets) sockets[u] = hd->idx;

        ADD2LOG("  pcmcia socket %u: %s\n", u, s);
      }

      free_mem(sf_dev);
    }

    sf_cdev = free_mem(sf_cdev);
  }

  sf_class = free_str_list(sf_class);

  /* find card bus devices & assign them socket numbers */

  for(hd = hd_data->hd; hd; hd = hd->next) {
    if(hd->bus.id != bus_pcmcia) continue;
    if((bridge_hd = hd_get_device_by_idx(hd_data, hd->attached_to))) {
      if(
        bridge_hd->base_class.id == bc_bridge &&
        bridge_hd->sub_class.id == sc_bridge_cardbus
      ) {
        hd->hotplug = hp_cardbus;
      }
     else if(
        bridge_hd->base_class.id == bc_bridge &&
        bridge_hd->sub_class.id == sc_bridge_pcmcia
      ) {
        hd->hotplug = hp_pcmcia;
      }

      for(u = 0; u < sizeof sockets / sizeof *sockets; u++) {
        if(sockets[u] == bridge_hd->idx) {
          hd->hotplug_slot = u + 1;
        }
      }
    }
  }
}