// note: hd_data parameter is needed for ADD2LOG macro void add_joystick_details(hd_data_t *hd_data, hd_t *h, const char *key, const char *abso) { // replace existing details if (h->detail) { free_hd_detail(h->detail); } // add buttons and axis details h->detail = new_mem(sizeof *h->detail); h->detail->type = hd_detail_joystick; joystick_t *jt = new_mem(sizeof jt); unsigned u; if(key) { for(u = BTN_JOYSTICK; u < BTN_JOYSTICK + 16; u++) { if(test_bit(key, u)) jt->buttons++; } } ADD2LOG(" joystick buttons = %u\n", jt->buttons); if(abso) { for(u = ABS_X; u < ABS_VOLUME; u++) { if(test_bit(abso, u)) jt->axes++; } } ADD2LOG(" joystick axes = %u\n", jt->axes); h->detail->joystick.data = jt; }
hd_t *hd_read_config(hd_data_t *hd_data, const char *id) { hd_t *hd = NULL; hal_prop_t *prop = NULL; const char *udi = NULL; /* only of we didn't already (check internal db pointer) */ /* prop2hd() makes db lookups */ if(!hd_data->hddb2[1]) hddb_init(hd_data); if(id && *id == '/') { udi = id; id = NULL; } prop = read_properties(hd_data, udi, id); if(prop) { hd = new_mem(sizeof *hd); hd->idx = ++(hd_data->last_idx); hd->module = hd_data->module; hd->line = __LINE__; hd->tag.freeit = 1; /* make it a 'stand alone' entry */ hd->persistent_prop = prop; prop2hd(hd_data, hd, 0); } return hd; }
/* * read an entry */ hal_prop_t *hd_manual_read_entry_old(const char *id) { char path[PATH_MAX]; int line; str_list_t *sl, *sl0; char *s, *s1, *s2; hal_prop_t *prop_list = NULL, *prop = NULL; if(!id) return NULL; snprintf(path, sizeof path, "%s/%s", hd_get_hddb_path("unique-keys"), id); if(!(sl0 = read_file(path, 0, 0))) return prop_list; for(line = 1, sl = sl0; sl; sl = sl->next, line++) { s = sl->str; while(isspace(*s)) s++; if(!*s || *s == '#' || *s == ';') continue; /* empty lines & comments */ s2 = s; s1 = strsep(&s2, "="); if(!s2 && *s == '[') continue; if(!s2) break; if(s1) { if(prop) { prop->next = new_mem(sizeof *prop); prop = prop->next; } else { prop_list = prop = new_mem(sizeof *prop); } prop->type = p_string; for(s = s1; *s; s++) if(*s >= 'A' && *s <= 'Z') *s += 'a' - 'A'; str_printf(&prop->key, 0, "hwinfo.%s", s1); prop->val.str = canon_str(s2, strlen(s2)); } } free_str_list(sl0); return prop_list; }
void int_legacy_geo(hd_data_t *hd_data) { hd_t *hd; hd_res_t *res; int id; char *s; edd_info_t *ei; if(!hd_data->edd) 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 ) { id = strtol(hd->rom_id, &s, 0) - 0x80; if(*s || id < 0 || id >= sizeof hd_data->edd / sizeof *hd_data->edd) continue; ei = hd_data->edd + id; if(ei->edd.cyls) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->disk_geo.type = res_disk_geo; res->disk_geo.cyls = ei->edd.cyls; res->disk_geo.heads = ei->edd.heads; res->disk_geo.sectors = ei->edd.sectors; res->disk_geo.size = ei->sectors; res->disk_geo.geotype = geo_bios_edd; } if(ei->legacy.cyls) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->disk_geo.type = res_disk_geo; res->disk_geo.cyls = ei->legacy.cyls; res->disk_geo.heads = ei->legacy.heads; res->disk_geo.sectors = ei->legacy.sectors; res->disk_geo.geotype = geo_bios_legacy; } } } }
hal_prop_t *hal_get_new(hal_prop_t **list, const char *key) { hal_prop_t *prop; prop = hal_get_any(*list, key); if(!prop) { prop = new_mem(sizeof *prop); prop->next = *list; *list = prop; prop->key = new_str(key); } else { hal_invalidate_all(prop, key); } return prop; }
void prop2hd(hd_data_t *hd_data, hd_t *hd, int status_only) { hal_prop_t *prop, *list; hd_res_t *res; int i; unsigned u, u0, u1, u2, u3, u4; char *s; uint64_t u64_0, u64_1; str_list_t *sl; list = hd->persistent_prop; hd->config_string = prop2hd_str(list, "hwinfo.configstring"); if((prop = hal_get_str(list, "hwinfo.configured"))) { hd->status.configured = value2key(status_names, prop->val.str); } if((prop = hal_get_str(list, "hwinfo.available"))) { hd->status.available_orig = hd->status.available = value2key(status_names, prop->val.str); } if((prop = hal_get_str(list, "hwinfo.needed"))) { hd->status.needed = value2key(status_names, prop->val.str); } if((prop = hal_get_str(list, "hwinfo.active"))) { hd->status.active = value2key(status_names, prop->val.str); } /* * if the status info is completely missing, fake some: * new hardware, autodetectable, not needed */ if( !hd->status.configured && !hd->status.available && !hd->status.needed && !hd->status.invalid ) { hd->status.configured = status_new; hd->status.available = status_yes; hd->status.needed = status_no; } if(!hd->status.active) hd->status.active = status_unknown; if(status_only || !list) return; hd->udi = prop2hd_str(list, "info.udi"); hd->unique_id = prop2hd_str(list, "hwinfo.uniqueid"); hd->parent_id = prop2hd_str(list, "hwinfo.parentid"); hd->child_ids = prop2hd_list(list, "hwinfo.childids"); hd->model = prop2hd_str(list, "hwinfo.model"); if((prop = hal_get_str(list, "hwinfo.hwclass"))) { hd->hw_class = value2key(hw_items, prop->val.str); } hd->broken = prop2hd_int32(list, "hwinfo.broken"); hd->bus.id = prop2hd_int32(list, "hwinfo.busid"); hd->slot = prop2hd_int32(list, "hwinfo.slot"); hd->func = prop2hd_int32(list, "hwinfo.func"); hd->base_class.id = prop2hd_int32(list, "hwinfo.baseclass"); hd->sub_class.id = prop2hd_int32(list, "hwinfo.subclass"); hd->prog_if.id = prop2hd_int32(list, "hwinfo.progif"); hd->revision.id = prop2hd_int32(list, "hwinfo.revisionid"); hd->revision.name = prop2hd_str(list, "hwinfo.revisionname"); hd->vendor.id = prop2hd_int32(list, "hwinfo.vendorid"); hd->vendor.name = prop2hd_str(list, "hwinfo.vendorname"); hd->device.id = prop2hd_int32(list, "hwinfo.deviceid"); hd->device.name = prop2hd_str(list, "hwinfo.devicename"); hd->sub_vendor.id = prop2hd_int32(list, "hwinfo.subvendorid"); hd->sub_vendor.name = prop2hd_str(list, "hwinfo.subvendorname"); hd->sub_device.id = prop2hd_int32(list, "hwinfo.subdeviceid"); hd->sub_device.name = prop2hd_str(list, "hwinfo.subdevicename"); hd->compat_device.id = prop2hd_int32(list, "hwinfo.compatdeviceid"); hd->compat_device.name = prop2hd_str(list, "hwinfo.compatdevicename"); hd->serial = prop2hd_str(list, "hwinfo.serial"); hd->unix_dev_name = prop2hd_str(list, "hwinfo.unixdevice"); hd->unix_dev_name2 = prop2hd_str(list, "hwinfo.unixdevicealt"); hd->unix_dev_names = prop2hd_list(list, "hwinfo.unixdevicelist"); hd->drivers = prop2hd_list(list, "hwinfo.drivers"); hd->sysfs_id = prop2hd_str(list, "hwinfo.sysfsid"); hd->sysfs_bus_id = prop2hd_str(list, "hwinfo.sysfsbusid"); hd->sysfs_device_link = prop2hd_str(list, "hwinfo.sysfslink"); hd->rom_id = prop2hd_str(list, "hwinfo.romid"); hd->usb_guid = prop2hd_str(list, "hwinfo.usbguid"); hd->hotplug = prop2hd_int32(list, "hwinfo.hotplug"); if((s = hal_get_useful_str(list, "hwinfo.hwclasslist"))) { for(u = 0; u < sizeof hd->hw_class_list / sizeof *hd->hw_class_list; u++) { if(*s && s[1] && (i = hex(s, 2)) >= 0) { hd->hw_class_list[u] = i; s += 2; } else { break; } } } u = prop2hd_int32(list, "hwinfo.features"); if(u & (1 << 0)) hd->is.agp = 1; if(u & (1 << 1)) hd->is.isapnp = 1; if(u & (1 << 2)) hd->is.softraiddisk = 1; if(u & (1 << 3)) hd->is.zip = 1; if(u & (1 << 4)) hd->is.cdr = 1; if(u & (1 << 5)) hd->is.cdrw = 1; if(u & (1 << 6)) hd->is.dvd = 1; if(u & (1 << 7)) hd->is.dvdr = 1; if(u & (1 << 8)) hd->is.dvdram = 1; if(u & (1 << 9)) hd->is.pppoe = 1; if(u & (1 << 10)) hd->is.wlan = 1; if((prop = hal_get_list(list, "hwinfo.res.memory"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "0x%"SCNx64",0x%"SCNx64",%u,%u,%u", &u64_0, &u64_1, &u0, &u1, &u2) == 5) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_mem; res->mem.base = u64_0; res->mem.range = u64_1; res->mem.enabled = u0; res->mem.access = u1; res->mem.prefetch = u2; } } } if((prop = hal_get_list(list, "hwinfo.res.physmemory"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "0x%"SCNx64"", &u64_0) == 1) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_phys_mem; res->phys_mem.range = u64_0; } } } if((prop = hal_get_list(list, "hwinfo.res.io"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "0x%"SCNx64",0x%"SCNx64",%u,%u", &u64_0, &u64_1, &u0, &u1) == 4) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_io; res->io.base = u64_0; res->io.range = u64_1; res->io.enabled = u0; res->io.access = u1; } } } if((prop = hal_get_list(list, "hwinfo.res.interrupts"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "%u,%u,%u", &u0, &u1, &u2) == 3) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_irq; res->irq.base = u0; res->irq.triggered = u1; res->irq.enabled = u2; } } } if((prop = hal_get_list(list, "hwinfo.res.dma"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "%u,%u", &u0, &u1) == 2) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_dma; res->dma.base = u0; res->dma.enabled = u1; } } } if((prop = hal_get_list(list, "hwinfo.res.size"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "%u,%u,%u", &u0, &u1, &u2) == 3) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_size; res->size.unit = u0; res->size.val1 = u1; res->size.val2 = u2; } } } if((prop = hal_get_list(list, "hwinfo.res.baud"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "%u,%u,%u,%u,%u", &u0, &u1, &u2, &u3, &u4) == 5) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_baud; res->baud.speed = u0; res->baud.bits = u1; res->baud.stopbits = u2; res->baud.parity = (char) u3; res->baud.handshake = (char) u4; } } } if((prop = hal_get_list(list, "hwinfo.res.cache"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "%u", &u0) == 1) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_cache; res->cache.size = u0; } } } if((prop = hal_get_list(list, "hwinfo.res.diskgeometry"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "%u,%u,%u,%u", &u0, &u1, &u2, &u3) == 4) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_disk_geo; res->disk_geo.cyls = u0; res->disk_geo.heads = u1; res->disk_geo.sectors = u2; res->disk_geo.geotype = u3; } } } if((prop = hal_get_list(list, "hwinfo.res.monitor"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "%u,%u,%u,%u", &u0, &u1, &u2, &u3) == 4) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_monitor; res->monitor.width = u0; res->monitor.height = u1; res->monitor.vfreq = u2; res->monitor.interlaced = u3; } } } if((prop = hal_get_list(list, "hwinfo.res.framebuffer"))) { for(sl = prop->val.list; sl; sl = sl->next) { if(sscanf(sl->str, "%u,%u,%u,%u,%u", &u0, &u1, &u2, &u3, &u4) == 5) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->any.type = res_framebuffer; res->framebuffer.width = u0; res->framebuffer.height = u1; res->framebuffer.bytes_p_line = u2; res->framebuffer.colorbits = u3; res->framebuffer.mode = u4; } } } hddb_add_info(hd_data, hd); }
/* * Get the (raw) PCI data, taken from /sys/bus/pci. * * Note: non-root users can only read the first 64 bytes (of 256) * of the device headers. */ void hd_pci_read_data(hd_data_t *hd_data) { uint64_t ul0, ul1, ul2; unsigned u, u0, u1, u2, u3; unsigned char nxt; str_list_t *sl; char *s; pci_t *pci; int fd, i; str_list_t *sf_bus, *sf_bus_e; char *sf_dev; sf_bus = reverse_str_list(read_dir("/sys/bus/pci/devices", 'l')); if(!sf_bus) { ADD2LOG("sysfs: no such bus: pci\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/pci/devices", sf_bus_e->str)); ADD2LOG( " pci device: name = %s\n path = %s\n", sf_bus_e->str, hd_sysfs_id(sf_dev) ); if(sscanf(sf_bus_e->str, "%x:%x:%x.%x", &u0, &u1, &u2, &u3) != 4) continue; pci = add_pci_entry(hd_data, new_mem(sizeof *pci)); pci->sysfs_id = new_str(sf_dev); pci->sysfs_bus_id = new_str(sf_bus_e->str); pci->bus = (u0 << 8) + u1; pci->slot = u2; pci->func = u3; if((s = get_sysfs_attr_by_path(sf_dev, "modalias"))) { pci->modalias = canon_str(s, strlen(s)); ADD2LOG(" modalias = \"%s\"\n", pci->modalias); } if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "class"), &ul0, 0)) { ADD2LOG(" class = 0x%x\n", (unsigned) ul0); pci->prog_if = ul0 & 0xff; pci->sub_class = (ul0 >> 8) & 0xff; pci->base_class = (ul0 >> 16) & 0xff; } if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "vendor"), &ul0, 0)) { ADD2LOG(" vendor = 0x%x\n", (unsigned) ul0); pci->vend = ul0 & 0xffff; } if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "device"), &ul0, 0)) { ADD2LOG(" device = 0x%x\n", (unsigned) ul0); pci->dev = ul0 & 0xffff; } if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "subsystem_vendor"), &ul0, 0)) { ADD2LOG(" subvendor = 0x%x\n", (unsigned) ul0); pci->sub_vend = ul0 & 0xffff; } if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "subsystem_device"), &ul0, 0)) { ADD2LOG(" subdevice = 0x%x\n", (unsigned) ul0); pci->sub_dev = ul0 & 0xffff; } if(hd_attr_uint(get_sysfs_attr_by_path(sf_dev, "irq"), &ul0, 0)) { ADD2LOG(" irq = %d\n", (unsigned) ul0); pci->irq = ul0; } sl = hd_attr_list(get_sysfs_attr_by_path(sf_dev, "resource")); for(u = 0; sl; sl = sl->next, u++) { if( sscanf(sl->str, "0x%"SCNx64" 0x%"SCNx64" 0x%"SCNx64, &ul0, &ul1, &ul2) == 3 && ul1 && u < sizeof pci->base_addr / sizeof *pci->base_addr ) { ADD2LOG(" res[%u] = 0x%"PRIx64" 0x%"PRIx64" 0x%"PRIx64"\n", u, ul0, ul1, ul2); pci->base_addr[u] = ul0; pci->base_len[u] = ul1 + 1 - ul0; pci->addr_flags[u] = ul2; } } s = NULL; str_printf(&s, 0, "%s/config", sf_dev); if((fd = open(s, O_RDONLY)) != -1) { pci->data_len = pci->data_ext_len = read(fd, pci->data, 0x40); ADD2LOG(" config[%u]\n", pci->data_len); if(pci->data_len >= 0x40) { pci->hdr_type = pci->data[PCI_HEADER_TYPE] & 0x7f; pci->cmd = pci->data[PCI_COMMAND] + (pci->data[PCI_COMMAND + 1] << 8); if(pci->hdr_type == 1 || pci->hdr_type == 2) { /* PCI or CB bridge */ pci->secondary_bus = pci->data[PCI_SECONDARY_BUS]; /* PCI_SECONDARY_BUS == PCI_CB_CARD_BUS */ } for(u = 0; u < sizeof pci->base_addr / sizeof *pci->base_addr; u++) { if((pci->addr_flags[u] & IORESOURCE_IO)) { if(!(pci->cmd & PCI_COMMAND_IO)) pci->addr_flags[u] |= IORESOURCE_DISABLED; } if((pci->addr_flags[u] & IORESOURCE_MEM)) { if(!(pci->cmd & PCI_COMMAND_MEMORY)) pci->addr_flags[u] |= IORESOURCE_DISABLED; } } /* let's go through the capability list */ if( pci->hdr_type == PCI_HEADER_TYPE_NORMAL && (nxt = pci->data[PCI_CAPABILITY_LIST]) ) { /* * Cut out after 16 capabilities to avoid infinite recursion due * to (potentially) malformed data. 16 is more or less * arbitrary, though (the capabilities are bits in a byte, so 8 entries * should suffice). */ for(u = 0; u < 16 && nxt && nxt <= 0xfe; u++) { switch(pci_cfg_byte(pci, fd, nxt)) { case PCI_CAP_ID_PM: pci->flags |= (1 << pci_flag_pm); break; case PCI_CAP_ID_AGP: pci->flags |= (1 << pci_flag_agp); break; } nxt = pci_cfg_byte(pci, fd, nxt + 1); } } } close(fd); } str_printf(&s, 0, "%s/edid1", sf_dev); if((fd = open(s, O_RDONLY)) != -1) { pci->edid_len = read(fd, pci->edid, sizeof pci->edid); ADD2LOG(" edid[%u]\n", pci->edid_len); if(pci->edid_len > 0) { for(i = 0; i < sizeof pci->edid; i += 0x10) { ADD2LOG(" "); hexdump(&hd_data->log, 1, 0x10, pci->edid + i); ADD2LOG("\n"); } } close(fd); } s = free_mem(s); pci->rev = pci->data[PCI_REVISION_ID]; if((pci->addr_flags[6] & IORESOURCE_MEM)) { if(!(pci->data[PCI_ROM_ADDRESS] & PCI_ROM_ADDRESS_ENABLE)) { pci->addr_flags[6] |= IORESOURCE_DISABLED; } } pci->flags |= (1 << pci_flag_ok); free_mem(sf_dev); }
void hd_scan_pppoe(hd_data_t *hd_data2) { hd_t *hd; int cnt, interfaces; PPPoEConnection *conn; hd_data = hd_data2; if(!hd_probe_feature(hd_data, pr_pppoe)) return; hd_data->module = mod_pppoe; PROGRESS(1, 0, "looking for pppoe"); for(interfaces = 0, hd = hd_data->hd; hd; hd = hd->next) { if( hd->base_class.id == bc_network_interface && hd->sub_class.id == sc_nif_ethernet && hd->unix_dev_name ) { interfaces++; } } if(!interfaces) return; conn = new_mem(interfaces * sizeof *conn); for(cnt = 0, hd = hd_data->hd; hd && cnt < interfaces; hd = hd->next) { if( hd->base_class.id == bc_network_interface && hd->sub_class.id == sc_nif_ethernet && hd->unix_dev_name ) { conn[cnt].hd = hd; conn[cnt].fd = -1; conn[cnt].ifname = hd->unix_dev_name; cnt++; } } PROGRESS(2, 0, "discovery"); discovery(interfaces, conn); for(cnt = 0; cnt < interfaces; cnt++) { conn[cnt].hd->is.pppoe = 0; if(conn[cnt].received_pado) { conn[cnt].hd->is.pppoe = 1; ADD2LOG( "pppoe %s: my mac %02x:%02x:%02x:%02x:%02x:%02x, " "peer mac %02x:%02x:%02x:%02x:%02x:%02x\n", conn[cnt].ifname, conn[cnt].my_mac[0], conn[cnt].my_mac[1], conn[cnt].my_mac[2], conn[cnt].my_mac[3], conn[cnt].my_mac[4], conn[cnt].my_mac[5], conn[cnt].peer_mac[0], conn[cnt].peer_mac[1], conn[cnt].peer_mac[2], conn[cnt].peer_mac[3], conn[cnt].peer_mac[4], conn[cnt].peer_mac[5] ); } } }
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); } }
void hd_scan_floppy(hd_data_t *hd_data) { hd_t *hd; char b0[10], b1[10], c; unsigned u; int fd, i, floppy_ctrls = 0, floppy_ctrl_idx = 0; str_list_t *sl; hd_res_t *res; int floppy_stat[2] = { 1, 1 }; unsigned floppy_created = 0; if(!hd_probe_feature(hd_data, pr_floppy)) return; hd_data->module = mod_floppy; /* some clean-up */ remove_hd_entries(hd_data); hd_data->floppy = free_str_list(hd_data->floppy); PROGRESS(1, 0, "get nvram"); /* * Look for existing floppy controller entries (typically there will be * *none*). */ for(hd = hd_data->hd; hd; hd = hd->next) { if(hd->base_class.id == bc_storage && hd->sub_class.id == sc_sto_floppy) { floppy_ctrls++; floppy_ctrl_idx = hd->idx; } } /* * Is enough to load the nvram module. * * Note: although you must be root to access /dev/nvram, every * user can read /proc/nvram. */ fd = open(DEV_NVRAM, O_RDONLY | O_NONBLOCK); if(fd >= 0) close(fd); if( !(hd_data->floppy = read_file(PROC_NVRAM_24, 0, 0)) && !(hd_data->floppy = read_file(PROC_NVRAM_22, 0, 0)) ); if(hd_data->floppy && (hd_data->debug & HD_DEB_FLOPPY)) dump_floppy_data(hd_data); if(!hd_data->klog) read_klog(hd_data); for(sl = hd_data->klog; sl; sl = sl->next) { if(sscanf(sl->str, "<4>floppy%u: no floppy controllers foun%c", &u, &c) == 2) { if(u < sizeof floppy_stat / sizeof *floppy_stat) { floppy_stat[u] = 0; } } } if(hd_data->floppy) { PROGRESS(2, 0, "nvram info"); sl = hd_data->floppy; } else { PROGRESS(2, 0, "klog info"); sl = hd_data->klog; } for(; sl; sl = sl->next) { if(hd_data->floppy) { i = sscanf(sl->str, " Floppy %u type : %8[0-9.]'' %8[0-9.]%c", &u, b0, b1, &c) == 4; } else { i = sscanf(sl->str, "<6>Floppy drive(s): fd%u is %8[0-9.]%c", &u, b1, &c) == 3; *b0 = 0; } if(i) { if( !floppy_ctrls && u < sizeof floppy_stat / sizeof *floppy_stat && floppy_stat[u] ) { /* create one, if missing (there's no floppy without a controller...) */ hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_storage; hd->sub_class.id = sc_sto_floppy; floppy_ctrl_idx = hd->idx; floppy_ctrls++; } if(floppy_ctrls && !(floppy_created & (1 << u))) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_storage_device; hd->sub_class.id = sc_sdev_floppy; hd->bus.id = bus_floppy; hd->slot = u; str_printf(&hd->unix_dev_name, 0, "/dev/fd%u", u); floppy_created |= 1 << u; if(*b0) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->size.type = res_size; res->size.val1 = str2float(b0, 2); res->size.unit = size_unit_cinch; } /* 'k' or 'M' */ i = c == 'M' ? str2float(b1, 3) : str2float(b1, 0); res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->size.type = res_size; res->size.val1 = i << 1; res->size.val2 = 0x200; res->size.unit = size_unit_sectors; /* the only choice... */ if(floppy_ctrls == 1) hd->attached_to = floppy_ctrl_idx; } } } }
/* * Gather serial mouse data and put it into hd_data->ser_mouse. */ void get_serial_mouse(hd_data_t *hd_data) { hd_t *hd; int j, fd, fd_max = 0, sel, max_len; unsigned modem_info; fd_set set, set0; struct timeval to; ser_device_t *sm; struct termios tio; FD_ZERO(&set); for(hd = hd_data->hd; hd; hd = hd->next) { if( hd->base_class.id == bc_comm && hd->sub_class.id == sc_com_ser && hd->unix_dev_name && !hd->tag.ser_skip && !has_something_attached(hd_data, hd) ) { if((fd = open(hd->unix_dev_name, O_RDWR | O_NONBLOCK)) >= 0) { if(tcgetattr(fd, &tio)) continue; sm = add_ser_mouse_entry(&hd_data->ser_mouse, new_mem(sizeof *sm)); sm->dev_name = new_str(hd->unix_dev_name); sm->fd = fd; sm->tio = tio; sm->hd_idx = hd->idx; if(fd > fd_max) fd_max = fd; FD_SET(fd, &set); /* * PnP COM spec black magic... */ setspeed(fd, 1200, 1, CS7); modem_info = TIOCM_DTR | TIOCM_RTS; ioctl(fd, TIOCMBIC, &modem_info); } } } if(!hd_data->ser_mouse) return; /* * 200 ms seems to be too fast for some mice... */ usleep(300000); /* PnP protocol */ for(sm = hd_data->ser_mouse; sm; sm = sm->next) { modem_info = TIOCM_DTR | TIOCM_RTS; ioctl(sm->fd, TIOCMBIS, &modem_info); } /* smaller buffer size, otherwise we might wait really long... */ max_len = sizeof sm->buf < 128 ? sizeof sm->buf : 128; to.tv_sec = 0; to.tv_usec = 300000; set0 = set; for(;;) { to.tv_sec = 0; to.tv_usec = 300000; set = set0; if((sel = select(fd_max + 1, &set, NULL, NULL, &to)) > 0) { for(sm = hd_data->ser_mouse; sm; sm = sm->next) { if(FD_ISSET(sm->fd, &set)) { if((j = read(sm->fd, sm->buf + sm->buf_len, max_len - sm->buf_len)) > 0) sm->buf_len += j; if(j <= 0) FD_CLR(sm->fd, &set0); // ##### } } } else { break; } } for(sm = hd_data->ser_mouse; sm; sm = sm->next) { chk4id(sm); /* reset serial lines */ tcflush(sm->fd, TCIOFLUSH); tcsetattr(sm->fd, TCSAFLUSH, &sm->tio); close(sm->fd); } }
/* * 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; }
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); } } } } }
/* * read /proc/interrupts * * This is somewhat more tricky, as the irq event counts are done separately * per cpu *and* there may be irq sharing. */ void read_irqs(misc_t *m) { char buf[100], buf2[100], *s; misc_irq_t *ir; int i, j; unsigned u, v, k; str_list_t *sl; if(!(m->proc_irq = read_file(PROC_INTERRUPTS, 1, 0))) return; for(sl = m->proc_irq; sl; sl = sl->next) { /* irq */ i = 0; if(sscanf(sl->str, " %u: %n", &u, &i) < 1) continue; v = 0; j = i; /* add up all event counters */ while(j < (int) strlen(sl->str) && sscanf(sl->str + j, " %u %n", &k, &i) >= 1) { if(!i) break; v += k; j += i; } /* device driver name string */ #if defined(__PPC__) if( sscanf(sl->str + j, " %*s Edge %99[^\n]", buf) == 1 || sscanf(sl->str + j, " %*s Level %99[^\n]", buf) == 1 || sscanf(sl->str + j, " %*s %99[^\n]", buf) == 1 ) { #else #if defined(__alpha__) || defined(__sparc__) if(sscanf(sl->str + j, " %99[^\n]", buf) == 1) { #else /* __i386__ || __x86_64__ || __ia64__ */ if(sscanf(sl->str + j, " %*s %99[^\n]", buf) == 1) { #endif #endif m->irq = add_mem(m->irq, sizeof *m->irq, m->irq_len); ir = m->irq + m->irq_len++; ir->irq = u; ir->events = v; /* split device driver names (separated by ',') */ s = buf; while(*s && sscanf(s, " %99[^,] %n", buf2, &j) >= 1) { ir->dev = add_mem(ir->dev, sizeof *ir->dev, ir->devs); ir->dev[ir->devs++] = new_str(buf2); s += j; if(*s) s++; /* skip ',' */ } } } } void gather_resources(misc_t *m, hd_res_t **r, char *name, unsigned which) { int i, j; hd_res_t *res; if(!m) return; if(!which) which = W_IO | W_DMA | W_IRQ; if((which & W_IO)) for(i = 0; (unsigned) i < m->io_len; i++) { if(!strcmp(name, m->io[i].dev)) { res = add_res_entry(r, new_mem(sizeof **r)); res->io.type = res_io; res->io.enabled = 1; res->io.base = m->io[i].addr; res->io.range = m->io[i].size; res->io.access = acc_rw; m->io[i].tag++; } } if((which & W_DMA)) for(i = 0; (unsigned) i < m->dma_len; i++) { if(!strcmp(name, m->dma[i].dev)) { res = add_res_entry(r, new_mem(sizeof **r)); res->dma.type = res_dma; res->dma.enabled = 1; res->dma.base = m->dma[i].channel; m->dma[i].tag++; } } if((which & W_IRQ)) for(i = 0; (unsigned) i < m->irq_len; i++) { for(j = 0; j < m->irq[i].devs; j++) { if(!strcmp(name, m->irq[i].dev[j])) { res = add_res_entry(r, new_mem(sizeof **r)); res->irq.type = res_irq; res->irq.enabled = 1; res->irq.base = m->irq[i].irq; res->irq.triggered = m->irq[i].events; m->irq[i].tag++; } } } } int active_vga_card(hd_t *hd) { hd_res_t *res; if(hd->bus.id != bus_pci) return 1; for(res = hd->res; res; res = res->next) { if( (res->mem.type == res_mem && res->mem.enabled) || (res->io.type == res_io && res->io.enabled) ) return 1; } return 0; }
void hd_scan_misc(hd_data_t *hd_data) { hd_t *hd; hd_res_t *res; int fd, i; char *s = NULL; bios_info_t *bt = NULL; char par[] = "parport0"; int fd_ser0, fd_ser1; if(!hd_probe_feature(hd_data, pr_misc)) return; hd_data->module = mod_misc; /* some clean-up */ remove_hd_entries(hd_data); hd_data->misc = free_misc(hd_data->misc); PROGRESS(9, 0, "kernel log"); read_klog(hd_data); if((hd_data->debug & HD_DEB_MISC)) dump_klog(hd_data); PROGRESS(1, 0, "misc data"); hd_data->misc = new_mem(sizeof *hd_data->misc); /* this is enough to load the module */ fd_ser0 = fd_ser1 = -1; #if !defined(__sparc__) /* On sparc, the close needs too long */ if(hd_probe_feature(hd_data, pr_misc_serial)) { PROGRESS(1, 1, "open serial"); fd_ser0 = open("/dev/ttyS0", O_RDONLY | O_NONBLOCK); fd_ser1 = open("/dev/ttyS1", O_RDONLY | O_NONBLOCK); /* keep the devices open until the resources have been read */ } #endif /* this is enough to load the module */ if(!hd_data->flags.no_parport && hd_probe_feature(hd_data, pr_misc_par)) { PROGRESS(1, 2, "open parallel"); /* what can the BIOS tell us? */ for(hd = hd_data->hd; hd; hd = hd->next) { if( hd->base_class.id == bc_internal && hd->sub_class.id == sc_int_bios && hd->detail && hd->detail->type == hd_detail_bios && hd->detail->bios.data ) break; } if(hd) { bt = hd->detail->bios.data; if(bt->par_port0) { str_printf(&s, 0, "io=0x%x", bt->par_port0); if(bt->par_port1) { str_printf(&s, -1, ",0x%x", bt->par_port1); if(bt->par_port2) str_printf(&s, -1, ",0x%x", bt->par_port2); } str_printf(&s, -1, " irq=none,none,none"); } unload_module(hd_data, "parport_probe"); unload_module(hd_data, "lp"); unload_module(hd_data, "parport_pc"); unload_module(hd_data, "parport"); /* now load it with the right io */ load_module(hd_data, "parport"); load_module_with_params(hd_data, "parport_pc", s); free_mem(s); } /* now load the rest of the modules */ fd = open("/dev/lp0", O_RDONLY | O_NONBLOCK); if(fd >= 0) close(fd); } /* * floppy driver resources are allocated only temporarily, * so we access it just before we read the resources */ if(hd_probe_feature(hd_data, pr_misc_floppy)) { /* look for a floppy *device* entry... */ for(hd = hd_data->hd; hd; hd = hd->next) { if( hd->base_class.id == bc_storage_device && hd->sub_class.id == sc_sdev_floppy && hd->unix_dev_name && !strncmp(hd->unix_dev_name, "/dev/fd", sizeof "/dev/fd" - 1) ) { PROGRESS(1, 3, "read floppy"); i = 5; hd->block0 = read_block0(hd_data, hd->unix_dev_name, &i); hd->is.notready = hd->block0 ? 0 : 1; if(i < 0) { hd->tag.remove = 1; ADD2LOG("misc.floppy: removing floppy entry %u (timed out)\n", hd->idx); } if(!hd->is.notready) { struct hd_geometry geo; int fd; unsigned size, blk_size = 0x200; fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK); if(fd >= 0) { if(!ioctl(fd, HDIO_GETGEO, &geo)) { ADD2LOG("floppy ioctl(geo) ok\n"); res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->disk_geo.type = res_disk_geo; res->disk_geo.cyls = geo.cylinders; res->disk_geo.heads = geo.heads; res->disk_geo.sectors = geo.sectors; res->disk_geo.geotype = geo_logical; size = geo.cylinders * geo.heads * geo.sectors; for(res = hd->res; res; res = res->next) { if(res->any.type == res_size && res->size.unit == size_unit_sectors) { res->size.val1 = size; res->size.val2 = blk_size; break; } } if(!res) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->size.type = res_size; res->size.unit = size_unit_sectors; res->size.val1 = size; res->size.val2 = blk_size; } } close(fd); } } break; } } remove_tagged_hd_entries(hd_data); } PROGRESS(2, 1, "io"); read_ioports(hd_data->misc); PROGRESS(2, 2, "dma"); read_dmas(hd_data->misc); PROGRESS(2, 3, "irq"); read_irqs(hd_data->misc); if((hd_data->debug & HD_DEB_MISC)) dump_misc_proc_data(hd_data); if(fd_ser0 >= 0) close(fd_ser0); if(fd_ser1 >= 0) close(fd_ser1); /* now create some system generic entries */ /* FPU */ PROGRESS(3, 0, "FPU"); res = NULL; gather_resources(hd_data->misc, &res, "fpu", 0); if(res) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_internal; hd->sub_class.id = sc_int_fpu; hd->res = res; } /* DMA */ PROGRESS(3, 1, "DMA"); res = NULL; gather_resources(hd_data->misc, &res, "dma1", 0); gather_resources(hd_data->misc, &res, "dma2", 0); gather_resources(hd_data->misc, &res, "dma page reg", 0); gather_resources(hd_data->misc, &res, "cascade", W_DMA); if(res) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_system; hd->sub_class.id = sc_sys_dma; hd->res = res; } /* PIC */ PROGRESS(3, 2, "PIC"); res = NULL; gather_resources(hd_data->misc, &res, "pic1", 0); gather_resources(hd_data->misc, &res, "pic2", 0); gather_resources(hd_data->misc, &res, "cascade", W_IRQ); if(res) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_system; hd->sub_class.id = sc_sys_pic; hd->res = res; } /* timer */ PROGRESS(3, 3, "timer"); res = NULL; gather_resources(hd_data->misc, &res, "timer", 0); if(res) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_system; hd->sub_class.id = sc_sys_timer; hd->res = res; } /* real time clock */ PROGRESS(3, 4, "RTC"); res = NULL; gather_resources(hd_data->misc, &res, "rtc", 0); if(res) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_system; hd->sub_class.id = sc_sys_rtc; hd->res = res; } /* keyboard */ res = NULL; gather_resources(hd_data->misc, &res, "keyboard", 0); if(res) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_input; hd->sub_class.id = sc_inp_keyb; hd->res = res; } /* parallel ports */ for(i = 0; i < 1; i++, par[sizeof par - 2]++) { res = NULL; gather_resources(hd_data->misc, &res, par, 0); if(res) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_comm; hd->sub_class.id = sc_com_par; str_printf(&hd->unix_dev_name, 0, "/dev/lp%d", i); hd->res = res; } } /* floppy controller */ res = NULL; gather_resources(hd_data->misc, &res, "floppy", 0); gather_resources(hd_data->misc, &res, "floppy DIR", 0); if(res) { /* look for an existing entry */ for(hd = hd_data->hd; hd; hd = hd->next) { if(hd->base_class.id == bc_storage && hd->sub_class.id == sc_sto_floppy) break; } /* missing, so create one */ if(!hd) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_storage; hd->sub_class.id = sc_sto_floppy; } hd->res = res; } /* * look for PS/2 port * * The catch is, that sometimes /dev/psaux is accessible only for root, * so the open() may fail but there are irq events registered. * */ fd = open(DEV_PSAUX, O_RDONLY | O_NONBLOCK); if(fd >= 0) close(fd); res = NULL; gather_resources(hd_data->misc, &res, "PS/2 Mouse", 0); if(res || fd >= 0) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_ps2; if(res) { hd->res = res; } } }
void hd_scan_misc2(hd_data_t *hd_data) { hd_t *hd, *hd1; misc_t *m; hd_res_t *res, *res1, *res2; int i; if(!hd_probe_feature(hd_data, pr_misc)) return; hd_data->module = mod_misc; PROGRESS(5, 0, "misc data"); /* create some more system generic entries */ /* IDE */ // ###### add special ide detail to hd_t!!! res = NULL; gather_resources(hd_data->misc, &res, "ide0", 0); gather_resources(hd_data->misc, &res, "ide1", 0); gather_resources(hd_data->misc, &res, "ide2", 0); gather_resources(hd_data->misc, &res, "ide3", 0); if(res) { for(hd = hd_data->hd; hd; hd = hd->next) { if( hd->base_class.id == bc_storage && hd->sub_class.id == sc_sto_ide && have_common_res(hd->res, res) ) break; } if(!hd) { /* eg. non-PCI IDE controller */ hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_storage; hd->sub_class.id = sc_sto_ide; hd->compat_vendor.id = MAKE_ID(TAG_SPECIAL, 0x3000); hd->compat_device.id = MAKE_ID(TAG_SPECIAL, 0x1000); /* use join_res to join the i/o ranges of ide0/1 */ join_res_io(&hd->res, res); join_res_irq(&hd->res, res); join_res_dma(&hd->res, res); free_res_list(res); } else { /* eg. PCI IDE controller, add resources */ join_res_io(&hd->res, res); join_res_irq(&hd->res, res); join_res_dma(&hd->res, res); free_res_list(res); } } /* VGA */ res = NULL; gather_resources(hd_data->misc, &res, "vga+", 0); gather_resources(hd_data->misc, &res, "vesafb", 0); if(res) { for(i = 0, hd1 = NULL, hd = hd_data->hd; hd; hd = hd->next) { if(hd->base_class.id == bc_display && hd->sub_class.id == sc_dis_vga) { i++; hd1 = hd; } } if(i == 0) { /* non-PCI VGA card ??? - really, we shouldn't care... */ /* FIX THIS !!! ############### */ #ifdef __alpha__ free_res_list(res); #else hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_display; hd->sub_class.id = sc_dis_vga; hd->res = res; #endif } else if(i == 1) { /* 1 PCI vga card, add resources */ join_res_io(&hd1->res, res); join_res_irq(&hd1->res, res); join_res_dma(&hd1->res, res); free_res_list(res); hd_data->display = hd1->idx; } else { /* more than 1: look again, now only 'active' cards */ for(i = 0, hd1 = NULL, hd = hd_data->hd; hd; hd = hd->next) { if( hd->base_class.id == bc_display && hd->sub_class.id == sc_dis_vga && active_vga_card(hd) ) { i++; hd1 = hd; } } if(i == 1) { /* 'the' active PCI vga card, add resources */ join_res_io(&hd1->res, res); join_res_irq(&hd1->res, res); join_res_dma(&hd1->res, res); hd_data->display = hd1->idx; } else { /* now, what??? */ ADD2LOG("Oopy, could not figure out *the* active display adapter!\n"); } free_res_list(res); } } /* serial ports */ res = NULL; gather_resources(hd_data->misc, &res, "serial(auto)", 0); gather_resources(hd_data->misc, &res, "serial(set)", 0); gather_resources(hd_data->misc, &res, "serial", 0); for(hd = hd_data->hd; hd; hd = hd->next) { if(hd->base_class.id == bc_comm && hd->sub_class.id == sc_com_ser) { for(res1 = hd->res; res1; res1 = res1->next) { for(res2 = res; res2; res2 = res2->next) { if(res1->any.type == res2->any.type) { switch(res1->any.type) { case res_irq: if(res1->irq.base == res2->irq.base) { res2->any.type = res_any; } break; case res_io: if( res1->io.base == res2->io.base && (!res1->io.range || res1->io.range == res2->io.range) ) { res1->io.range = res2->io.range; res2->any.type = res_any; } break; default: /* gcc -Wall */ break; } } } } } } /* if any of the serial resources are unaccounted for, make an extra entry */ for(res2 = res; res2; res2 = res2->next) { if(res2->any.type != res_any) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_comm; hd->sub_class.id = sc_com_ser; hd->prog_if.id = 0x80; for(; res2; res2 = res2->next) { if(res2->any.type != res_any) { res1 = add_res_entry(&hd->res, new_mem(sizeof *res)); *res1 = *res2; res1->next = NULL; } } break; } } free_res_list(res); /* go through our list and assign event counts to irq entries */ m = hd_data->misc; for(hd = hd_data->hd; hd; hd = hd->next) { for(res = hd->res; res; res = res->next) { if(res->irq.type == res_irq) { for(i = 0; (unsigned) i < m->irq_len; i++) { if(res->irq.base == m->irq[i].irq) { res->irq.triggered = m->irq[i].events; break; } } } } } /* look for entries with matching start address */ m = hd_data->misc; for(hd = hd_data->hd; hd; hd = hd->next) { for(res = hd->res; res; res = res->next) { if(res->io.type == res_io) { for(i = 0; (unsigned) i < m->io_len; i++) { if(res->io.base == m->io[i].addr && res->io.range < m->io[i].size) { res->io.range = m->io[i].size; break; } } } } } if((hd_data->debug & HD_DEB_MISC)) dump_misc_data(hd_data); }
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); }
void get_serial_info(hd_data_t *hd_data) { char buf[64]; unsigned u0, u1, u2; #if !defined(__PPC__) unsigned u3; #endif int i; str_list_t *sl, *sl0, **sll; serial_t *ser; #if !defined(__PPC__) /* * Max. 44 serial lines at the moment; the serial proc interface is * somewhat buggy at the moment (2.2.13), hence the explicit 44 lines * limit. That may be dropped later. */ sl0 = read_file(PROC_DRIVER_SERIAL, 1, 44); sll = &sl0; while(*sll) sll = &(*sll)->next; // append Agere modem devices *sll = read_file("/proc/tty/driver/agrserial", 1, 17); // ########## FIX !!!!!!!! ######## if(sl0) { for(sl = sl0; sl; sl = sl->next) { i = 0; if( sscanf(sl->str, "%u: uart:%31s port:%x irq:%u baud:%u", &u0, buf, &u1, &u2, &u3) == 5 || (i = 1, sscanf(sl->str, "%u: uart:%31s port:%x irq:%u tx:%u", &u0, buf, &u1, &u2, &u3) == 5) ) { /* * The 'baud' or 'tx' entries are only present for real interfaces. */ ser = add_serial_entry(&hd_data->serial, new_mem(sizeof *ser)); ser->line = u0; if(u1 >= 0x100) ser->port = u1; // Agere modem does not use real port numbers ser->irq = u2; if(!i) ser->baud = u3; ser->name = new_str(buf); } } if((hd_data->debug & HD_DEB_SERIAL)) { /* log just the first 16 entries */ ADD2LOG("----- "PROC_DRIVER_SERIAL" -----\n"); for(sl = sl0, i = 16; sl && i--; sl = sl->next) { ADD2LOG(" %s", sl->str); } ADD2LOG("----- "PROC_DRIVER_SERIAL" end -----\n"); } } #endif /* !defined(__PPC__) */ #if defined(__PPC__) sl0 = read_file(PROC_DRIVER_MACSERIAL, 1, 0); if(sl0) { for(sl = sl0; sl; sl = sl->next) { if( (i = sscanf(sl->str, "%u: port:%x irq:%u con:%63[^\n]", &u0, &u1, &u2, buf)) >= 3 ) { ser = add_serial_entry(&hd_data->serial, new_mem(sizeof *ser)); ser->line = u0; ser->port = u1; ser->irq = u2; ser->name = new_str("SCC"); if(i == 4) ser->device = new_str(buf); } } if((hd_data->debug & HD_DEB_SERIAL)) { /* log just the first 16 entries */ ADD2LOG("----- "PROC_DRIVER_MACSERIAL" -----\n"); for(sl = sl0, i = 16; sl && i--; sl = sl->next) { ADD2LOG(" %s", sl->str); } ADD2LOG("----- "PROC_DRIVER_MACSERIAL" end -----\n"); } } #endif /* defined(__PPC__) */ free_str_list(sl0); }
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); } } }
int bios_ctrl_order(hd_data_t *hd_data, unsigned *sctrl, int sctrl_len) { hd_t *hd; bios_info_t *bt; int i, j, k, sctrl2_len = 0; unsigned pci_slot, pci_func; unsigned *sctrl2 = NULL, *sctrl3 = NULL; int order_info = 0; for(bt = NULL, hd = hd_data->hd; hd; hd = hd->next) { if( hd->base_class.id == bc_internal && hd->sub_class.id == sc_int_bios && hd->detail && hd->detail->type == hd_detail_bios && (bt = hd->detail->bios.data) ) { break; } } if(!bt || !bt->bios32.ok || !bt->bios32.compaq) return 0; sctrl2 = new_mem((sizeof bt->bios32.cpq_ctrl / sizeof *bt->bios32.cpq_ctrl) * sizeof *sctrl2); for(i = 0; (unsigned) i < sizeof bt->bios32.cpq_ctrl / sizeof *bt->bios32.cpq_ctrl; i++) { if( bt->bios32.cpq_ctrl[i].id && !(bt->bios32.cpq_ctrl[i].misc & 0x40) /* bios support ??????? */ ) { pci_slot = PCI_SLOT(bt->bios32.cpq_ctrl[i].devfn) + (bt->bios32.cpq_ctrl[i].bus << 8); pci_func = PCI_FUNC(bt->bios32.cpq_ctrl[i].devfn); for(hd = hd_data->hd; hd; hd = hd->next) { if(hd->bus.id == bus_pci && hd->slot == pci_slot && hd->func == pci_func) { sctrl2[sctrl2_len++] = hd->idx; break; } } } } if(sctrl2_len) order_info = 1; for(i = 0; i < sctrl2_len; i++) { ADD2LOG(" bios ord %d: %d\n", i, sctrl2[i]); } /* sort list */ sctrl3 = new_mem(sctrl_len * sizeof *sctrl3); k = 0 ; for(i = 0; i < sctrl2_len; i++) { for(j = 0; j < sctrl_len; j++) { if(sctrl[j] == sctrl2[i]) { sctrl3[k++] = sctrl[j]; sctrl[j] = 0; break; } } } for(i = 0; i < sctrl_len; i++) { if(sctrl[i] && k < sctrl_len) sctrl3[k++] = sctrl[i]; } memcpy(sctrl, sctrl3, sctrl_len * sizeof *sctrl); free_mem(sctrl2); free_mem(sctrl3); return order_info; }
void hd_scan_serial(hd_data_t *hd_data) { hd_t *hd, *hd2; serial_t *ser, *next; hd_res_t *res, *res2; int i; char buf[4], *skip_dev[16]; str_list_t *sl, *cmd; unsigned skip_devs = 0; if(!hd_probe_feature(hd_data, pr_serial)) return; hd_data->module = mod_serial; /* some clean-up */ remove_hd_entries(hd_data); hd_data->serial = NULL; PROGRESS(1, 0, "read info"); get_serial_info(hd_data); if((hd_data->debug & HD_DEB_SERIAL)) dump_serial_data(hd_data); for(i = 0; i < 2; i++) { cmd = get_cmdline(hd_data, i == 0 ? "yast2ser" : "console"); for(sl = cmd; sl; sl = sl->next) { if(sscanf(sl->str, "tty%3[^,]", buf) == 1) { if(buf[1] == 0) { switch(*buf) { case 'a': strcpy(buf, "S0"); break; case 'b': strcpy(buf, "S1"); break; } } if(skip_devs < sizeof skip_dev / sizeof *skip_dev) { skip_dev[skip_devs] = NULL; str_printf(&skip_dev[skip_devs++], 0, "/dev/tty%s", buf); } } } free_str_list(cmd); } PROGRESS(2, 0, "build list"); for(ser = hd_data->serial; ser; ser = ser->next) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_comm; hd->sub_class.id = sc_com_ser; hd->prog_if.id = 0x80; for(i = 0; (unsigned) i < sizeof ser_names / sizeof *ser_names; i++) { if(strstr(ser->name, ser_names[i])) hd->prog_if.id = i; } hd->device.name = new_str(ser->name); hd->func = ser->line; if(ser->name && !strcmp(ser->name, "AgereModem")) { str_printf(&hd->unix_dev_name, 0, "/dev/ttyAGS%u", ser->line); } else { str_printf(&hd->unix_dev_name, 0, "/dev/ttyS%u", ser->line); } for(i = 0; i < (int) skip_devs; i++) { if(!strcmp(skip_dev[i], hd->unix_dev_name)) { hd->tag.skip_mouse = hd->tag.skip_modem = hd->tag.skip_braille = 1; break; } } if(ser->device) { if(strstr(ser->device, "modem-printer")) { hd->tag.ser_device = 1; } else if(strstr(ser->device, "infrared")) { hd->tag.ser_device = 2; } else if(strstr(ser->device, "modem")) { hd->tag.ser_device = 3; } } if(ser->baud) { res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->baud.type = res_baud; res->baud.speed = ser->baud; } res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->io.type = res_io; res->io.enabled = 1; res->io.base = ser->port; res->io.access = acc_rw; res = add_res_entry(&hd->res, new_mem(sizeof *res)); res->irq.type = res_irq; res->irq.enabled = 1; res->irq.base = ser->irq; /* skip Dell Remote Access Cards - bug #145051 */ for(hd2 = hd_data->hd; hd2; hd2 = hd2->next) { if( hd2->vendor.id == MAKE_ID(TAG_PCI, 0x1028) && /* Dell */ hd2->device.id >= MAKE_ID(TAG_PCI, 0x07) && hd2->device.id <= MAKE_ID(TAG_PCI, 0x12) /* range that covers DRACs */ ) { for(res2 = hd2->res; res2; res2 = res2->next) { if( res2->any.type == res_io && ser->port >= res2->io.base && ser->port < res2->io.base + res2->io.range ) { hd->tag.skip_mouse = hd->tag.skip_modem = hd->tag.skip_braille = 1; } } } } } for(ser = hd_data->serial; ser; ser = next) { next = ser->next; free_mem(ser->name); free_mem(ser->device); free_mem(ser); } hd_data->serial = NULL; #if 0 if(hd_module_is_active(hd_data, "irda")) { hd = add_hd_entry(hd_data, __LINE__, 0); hd->base_class.id = bc_comm; hd->sub_class.id = sc_com_ser; hd->prog_if.id = 0x80; hd->device.name = new_str("IrDA Serial"); hd->unix_dev_name = new_str("/dev/ircomm0"); } #endif }
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); }
void get_serial_modem(hd_data_t *hd_data) { hd_t *hd; int i, j, fd; unsigned modem_info, baud; char *command; ser_device_t *sm; int chk_usb = hd_probe_feature(hd_data, pr_modem_usb); /* serial modems & usb modems */ for(hd = hd_data->hd; hd; hd = hd->next) { if( ( ( hd->base_class.id == bc_comm && hd->sub_class.id == sc_com_ser && !hd->tag.ser_skip && hd->tag.ser_device != 2 && /* cf. serial.c */ !has_something_attached(hd_data, hd) ) || ( chk_usb && hd->bus.id == bus_usb && hd->base_class.id == bc_modem ) ) && hd->unix_dev_name ) { if(dev_name_duplicate(hd_data, hd->unix_dev_name)) continue; if((fd = open(hd->unix_dev_name, O_RDWR | O_NONBLOCK)) >= 0) { sm = add_ser_modem_entry(&hd_data->ser_modem, new_mem(sizeof *sm)); sm->dev_name = new_str(hd->unix_dev_name); sm->fd = fd; sm->hd_idx = hd->idx; sm->do_io = 1; init_modem(sm); } } } if(!hd_data->ser_modem) return; PROGRESS(2, 0, "init"); usleep(300000); /* PnP protocol; 200ms seems to be too fast */ for(sm = hd_data->ser_modem; sm; sm = sm->next) { modem_info = TIOCM_DTR | TIOCM_RTS; ioctl(sm->fd, TIOCMBIS, &modem_info); ioctl(sm->fd, TIOCMGET, &modem_info); if(!(modem_info & (TIOCM_DSR | TIOCM_CD))) { sm->do_io = 0; } } /* just a quick test if we get a response to an AT command */ for(i = 0; i < 4; i++) { PROGRESS(3, i + 1, "at test"); for(sm = hd_data->ser_modem; sm; sm = sm->next) { if(!sm->is_modem) set_modem_speed(sm, i == 0 ? 115200 : i == 1 ? 38400 : i == 2 ? 9600 : 1200); } at_cmd(hd_data, "AT\r", 1, 1); for(sm = hd_data->ser_modem; sm; sm = sm->next) { if(strstr(sm->buf, "OK") || strstr(sm->buf, "0")) { sm->is_modem = 1; sm->do_io = 0; } sm->buf_len = 0; /* clear buffer */ } } for(sm = hd_data->ser_modem; sm; sm = sm->next) { if((sm->do_io = sm->is_modem)) { sm->max_baud = sm->cur_baud; } } /* check for init string */ PROGRESS(4, 0, "init string"); command = NULL; for(i = 0; (unsigned) i < MAX_INIT_STRING; i++) { str_printf(&command, 0, "AT %s\r", init_strings[i]); at_cmd(hd_data, command, 1, 1); for(sm = hd_data->ser_modem; sm; sm = sm->next) { if(strstr(sm->buf, "OK") || strstr(sm->buf, "0")) { str_printf(&sm->init_string2, -1, "%s %s", sm->init_string2 ? "" : "AT", init_strings[i] ); } } } command = free_mem(command); for(sm = hd_data->ser_modem; sm; sm = sm->next) if(sm->is_modem) str_printf(&sm->init_string1, -1, "ATZ"); { int cmds[] = { 1, 3, 4, 5, 6 }; char at[10]; int i, j, ModemsCount = 0; str_list_t **responces = NULL; for(sm = hd_data->ser_modem; sm; sm = sm->next) if(sm->is_modem) ModemsCount++; responces = new_mem(ModemsCount * sizeof *responces); at_cmd(hd_data, "ATI\r", 0, 1); for(j = 0, sm = hd_data->ser_modem; sm; sm = sm->next) { if(sm->is_modem) responces[j++] = str_list_dup(sm->at_resp); } for(i = 0; (unsigned) i < sizeof cmds / sizeof *cmds; i++) { int atx = cmds[i]; sprintf(at, "ATI%d\r", atx); at_cmd(hd_data, at, 0, 1); for(j = 0, sm = hd_data->ser_modem; sm; sm = sm->next) { if(sm->is_modem) { if(atx == 1 && check_for_responce(responces[j], "Hagenuk", 7) && (check_for_responce(sm->at_resp, "Speed Dragon", 12) || check_for_responce(sm->at_resp, "Power Dragon", 12))) { free_mem(sm->init_string1); free_mem(sm->init_string2); sm->init_string1 = new_str("AT&F"); sm->init_string2 = new_str("ATB8"); } if(atx == 3 && check_for_responce(responces[j], "346900", 6) && check_for_responce(sm->at_resp, "3Com U.S. Robotics ISDN", 23)) { free_mem(sm->init_string1); free_mem(sm->init_string2); sm->init_string1 = new_str("AT&F"); sm->init_string2 = new_str("AT*PPP=1"); } if(atx == 4 && check_for_responce(responces[j], "SP ISDN", 7) && check_for_responce(sm->at_resp, "Sportster ISDN TA", 17)) { free_mem(sm->init_string1); free_mem(sm->init_string2); sm->init_string1 = new_str("AT&F"); sm->init_string2 = new_str("ATB3"); } if(atx == 6 && check_for_responce(responces[j], "644", 3) && check_for_responce(sm->at_resp, "ELSA MicroLink ISDN", 19)) { free_mem(sm->init_string1); free_mem(sm->init_string2); sm->init_string1 = new_str("AT&F"); sm->init_string2 = new_str("AT$IBP=HDLCP"); free_mem(sm->pppd_option); sm->pppd_option = new_str("default-asyncmap"); } if(atx == 6 && check_for_responce(responces[j], "643", 3) && check_for_responce(sm->at_resp, "MicroLink ISDN/TLV.34", 21)) { free_mem(sm->init_string1); free_mem(sm->init_string2); sm->init_string1 = new_str("AT&F"); sm->init_string2 = new_str("AT\\N10%P1"); } if(atx == 5 && check_for_responce(responces[j], "ISDN TA", 6) && check_for_responce(sm->at_resp, "ISDN TA;ASU", 4)) { free_mem(sm->vend); sm->vend = new_str("ASUS"); free_mem(sm->user_name); sm->user_name = new_str("ISDNLink TA"); free_mem(sm->init_string1); free_mem(sm->init_string2); sm->init_string1 = new_str("AT&F"); sm->init_string2 = new_str("ATB40"); } if(atx==3 && check_for_responce(responces[j], "128000", 6) && check_for_responce(sm->at_resp, "Lasat Speed", 11)) { free_mem(sm->init_string1); free_mem(sm->init_string2); sm->init_string1 = new_str("AT&F"); sm->init_string2 = new_str("AT\\P1&B2X3"); } if(atx == 1 && (check_for_responce(responces[j], "28642", 5) || check_for_responce(responces[j], "1281", 4) || check_for_responce(responces[j], "1282", 4) || check_for_responce(responces[j], "1283", 4) || check_for_responce(responces[j], "1291", 4) || check_for_responce(responces[j], "1292", 4) || check_for_responce(responces[j], "1293", 4)) && (check_for_responce(sm->at_resp, "Elite 2864I", 11) || check_for_responce(sm->at_resp, "ZyXEL omni", 10))) { free_mem(sm->init_string1); free_mem(sm->init_string2); sm->init_string1 = new_str("AT&F"); sm->init_string2 = new_str("AT&O2B40"); } j++; } } } for(i = 0; i < ModemsCount; i++) free_str_list(responces[i]); free_mem(responces); } /* now, go for the maximum speed... */ PROGRESS(5, 0, "speed"); for(i = MAX_SPEED - 1; i >= 0; i--) { baud = speeds[i].baud; for(j = 0, sm = hd_data->ser_modem; sm; sm = sm->next) { if(sm->is_modem) { if(baud > sm->max_baud) { sm->do_io = set_modem_speed(sm, baud) ? 0 : 1; if(sm->do_io) j++; } } } /* no modems */ if(!j) continue; at_cmd(hd_data, "AT\r", 1, 0); for(sm = hd_data->ser_modem; sm; sm = sm->next) { if(strstr(sm->buf, "OK") || strstr(sm->buf, "0")) { sm->max_baud = sm->cur_baud; } else { sm->do_io = 0; } sm->buf_len = 0; /* clear buffer */ } } /* now, fix it all up... */ for(sm = hd_data->ser_modem; sm; sm = sm->next) { if(sm->is_modem) { set_modem_speed(sm, sm->max_baud); sm->do_io = 1; } } #if 0 /* just for testing */ if((hd_data->debug & HD_DEB_MODEM)) { int i; int cmds[] = { 0, 1, 2, 3, 6 }; char at[10]; PROGRESS(8, 0, "testing"); at_cmd(hd_data, "ATI\r", 0, 1); for(i = 0; (unsigned) i < sizeof cmds / sizeof *cmds; i++) { sprintf(at, "ATI%d\r", cmds[i]); at_cmd(hd_data, at, 0, 1); } at_cmd(hd_data, "AT\r", 0, 1); } #endif PROGRESS(5, 0, "pnp id"); at_cmd(hd_data, "ATI9\r", 1, 1); for(sm = hd_data->ser_modem; sm; sm = sm->next) { if(sm->is_modem) { chk4id(sm); if(!sm->user_name) guess_modem_name(hd_data, sm); } /* reset serial lines */ tcflush(sm->fd, TCIOFLUSH); tcsetattr(sm->fd, TCSAFLUSH, &sm->tio); close(sm->fd); } }