X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fhwinfo%2Fsrc%2Fhd%2Fmanual.c;fp=src%2Fhwinfo%2Fsrc%2Fhd%2Fmanual.c;h=c8b9afa5fe4f6ba09d6a33dc9c426b0bdd841c02;hb=a6316ce423a6d559ea026061b689591e8f5872ed;hp=0000000000000000000000000000000000000000;hpb=c66941dd94e4c37be7a1c48b98f385b6bdc64752;p=people%2Fpmueller%2Fipfire-2.x.git diff --git a/src/hwinfo/src/hd/manual.c b/src/hwinfo/src/hd/manual.c new file mode 100644 index 0000000000..c8b9afa5fe --- /dev/null +++ b/src/hwinfo/src/hd/manual.c @@ -0,0 +1,1549 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hd.h" +#include "hd_int.h" +#include "manual.h" +#include "hddb.h" + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + * hardware in /var/lib/hardware/ + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + */ + +typedef struct { + int key; + char *value; +} hash_t; + +/* corresponds to hd_status_value_t */ +static hash_t status_names[] = { + { status_no, "no" }, + { status_yes, "yes" }, + { status_unknown, "unknown" }, + { status_new, "new" }, + { 0, NULL } +}; + +/* corresponds to hd_hw_item_t */ +static hash_t hw_items[] = { + { hw_sys, "system" }, + { hw_cpu, "cpu" }, + { hw_keyboard, "keyboard" }, + { hw_braille, "braille" }, + { hw_mouse, "mouse" }, + { hw_joystick, "joystick" }, + { hw_printer, "printer" }, + { hw_scanner, "scanner" }, + { hw_chipcard, "chipcard" }, + { hw_monitor, "monitor" }, + { hw_tv, "tv card" }, + { hw_display, "graphics card" }, + { hw_framebuffer, "framebuffer" }, + { hw_camera, "camera" }, + { hw_sound, "sound" }, + { hw_storage_ctrl, "storage" }, + { hw_network_ctrl, "network" }, + { hw_isdn, "isdn adapter" }, + { hw_modem, "modem" }, + { hw_network, "network interface" }, + { hw_disk, "disk" }, + { hw_partition, "partition" }, + { hw_cdrom, "cdrom" }, + { hw_floppy, "floppy" }, + { hw_manual, "manual" }, + { hw_usb_ctrl, "usb controller" }, + { hw_usb, "usb" }, + { hw_bios, "bios" }, + { hw_pci, "pci" }, + { hw_isapnp, "isapnp" }, + { hw_bridge, "bridge" }, + { hw_hub, "hub" }, + { hw_scsi, "scsi" }, + { hw_ide, "ide" }, + { hw_memory, "memory" }, + { hw_dvb, "dvb card" }, + { hw_pcmcia, "pcmcia" }, + { hw_pcmcia_ctrl, "pcmcia controller" }, + { hw_ieee1394, "firewire" }, + { hw_ieee1394_ctrl, "firewire controller" }, + { hw_hotplug, "hotplug" }, + { hw_hotplug_ctrl, "hotplug controller" }, + { hw_zip, "zip" }, + { hw_pppoe, "pppoe" }, + { hw_wlan, "wlan card" }, + { hw_dsl, "DSL adapter" }, + { hw_block, "block device" }, + { hw_tape, "tape" }, + { hw_vbe, "vesa bios" }, + { hw_bluetooth, "bluetooth" }, + { hw_unknown, "unknown" }, + { 0, NULL } +}; + +typedef enum { + hw_id_unique = 1, hw_id_parent, hw_id_child, hw_id_hwclass, hw_id_model, + hw_id_configured, hw_id_available, hw_id_needed, hw_id_cfgstring, hw_id_active +} hw_id_t; + +#ifndef LIBHD_TINY + +#define MAN_SECT_GENERAL "General" +#define MAN_SECT_STATUS "Status" +#define MAN_SECT_HARDWARE "Hardware" + +static hash_t hw_ids_general[] = { + { hw_id_unique, "UniqueID" }, + { hw_id_parent, "ParentID" }, + { hw_id_child, "ChildIDs" }, + { hw_id_hwclass, "HWClass" }, + { hw_id_model, "Model" }, + { 0, NULL } +}; + +static hash_t hw_ids_status[] = { + { hw_id_configured, "Configured" }, + { hw_id_available, "Available" }, + { hw_id_needed, "Needed" }, + { hw_id_cfgstring, "ConfigString" }, + { hw_id_active, "Active" }, + { 0, NULL } +}; + +/* structure elements from hd_t */ +typedef enum { + hwdi_bus = 1, hwdi_slot, hwdi_func, hwdi_base_class, hwdi_sub_class, + hwdi_prog_if, hwdi_dev, hwdi_vend, hwdi_sub_dev, hwdi_sub_vend, hwdi_rev, + hwdi_compat_dev, hwdi_compat_vend, hwdi_dev_name, hwdi_vend_name, + hwdi_sub_dev_name, hwdi_sub_vend_name, hwdi_rev_name, hwdi_serial, + hwdi_unix_dev_name, hwdi_unix_dev_name2, hwdi_unix_dev_names, hwdi_rom_id, + hwdi_broken, hwdi_usb_guid, hwdi_res_mem, hwdi_res_phys_mem, hwdi_res_io, + hwdi_res_irq, hwdi_res_dma, hwdi_res_size, hwdi_res_baud, hwdi_res_cache, + hwdi_res_disk_geo, hwdi_res_monitor, hwdi_res_framebuffer, hwdi_features, + hwdi_hotplug, hwdi_class_list, hwdi_drivers, hwdi_sysfs_id, + hwdi_sysfs_busid, hwdi_sysfs_link +} hw_hd_items_t; + +static hash_t hw_ids_hd_items[] = { + { hwdi_bus, "Bus" }, + { hwdi_slot, "Slot" }, + { hwdi_func, "Function" }, + { hwdi_base_class, "BaseClass" }, + { hwdi_sub_class, "SubClass" }, + { hwdi_prog_if, "ProgIF" }, + { hwdi_dev, "DeviceID" }, + { hwdi_vend, "VendorID" }, + { hwdi_sub_dev, "SubDeviceID" }, + { hwdi_sub_vend, "SubVendorID" }, + { hwdi_rev, "RevisionID" }, + { hwdi_compat_dev, "CompatDeviceID" }, + { hwdi_compat_vend, "CompatVendorID" }, + { hwdi_dev_name, "DeviceName" }, + { hwdi_vend_name, "VendorName" }, + { hwdi_sub_dev_name, "SubDeviceName" }, + { hwdi_sub_vend_name, "SubVendorName" }, + { hwdi_rev_name, "RevisionName" }, + { hwdi_serial, "Serial" }, + { hwdi_unix_dev_name, "UnixDevice" }, + { hwdi_unix_dev_name2, "UnixDeviceAlt" }, + { hwdi_unix_dev_names, "UnixDeviceList" }, + { hwdi_rom_id, "ROMID" }, + { hwdi_broken, "Broken" }, + { hwdi_usb_guid, "USBGUID" }, + { hwdi_res_phys_mem, "Res.PhysMemory" }, + { hwdi_res_mem, "Res.Memory" }, + { hwdi_res_io, "Res.IO" }, + { hwdi_res_irq, "Res.Interrupts" }, + { hwdi_res_dma, "Res.DMA" }, + { hwdi_res_size, "Res.Size" }, + { hwdi_res_baud, "Res.Baud" }, + { hwdi_res_cache, "Res.Cache" }, + { hwdi_res_disk_geo, "Res.DiskGeometry" }, + { hwdi_res_monitor, "Res.Monitor" }, + { hwdi_res_framebuffer, "Res.Framebuffer" }, + { hwdi_features, "Features" }, + { hwdi_hotplug, "Hotplug" }, + { hwdi_class_list, "HWClassList" }, + { hwdi_drivers, "Drivers" }, + { hwdi_sysfs_id, "SysfsID" }, + { hwdi_sysfs_busid, "SysfsBusID" }, + { hwdi_sysfs_link, "SysfsLink" }, + { 0, NULL } +}; +#endif + +static char *key2value(hash_t *hash, int id); + +#ifndef LIBHD_TINY + +static int value2key(hash_t *hash, char *str); +static void dump_manual(hd_data_t *hd_data); +static unsigned str2id(char *str); +static void manual2hd(hd_data_t *hd_data, hd_manual_t *entry, hd_t *hd); +static void hd2manual(hd_t *hd, hd_manual_t *entry); + +void hd_scan_manual(hd_data_t *hd_data) +{ + DIR *dir; + struct dirent *de; + hd_manual_t *entry, **entry_next; + int i; + hd_t *hd, *hd1; + + if(!hd_probe_feature(hd_data, pr_manual)) return; + + hd_data->module = mod_manual; + + /* some clean-up */ + remove_hd_entries(hd_data); + + hd_data->manual = hd_free_manual(hd_data->manual); + entry_next = &hd_data->manual; + + if((dir = opendir(HARDWARE_UNIQUE_KEYS))) { + i = 0; + while((de = readdir(dir))) { + if(*de->d_name == '.') continue; + PROGRESS(1, ++i, "read"); + if((entry = hd_manual_read_entry(hd_data, de->d_name))) { + ADD2LOG(" got %s\n", entry->unique_id); + *entry_next = entry; + entry_next = &entry->next; + } + } + closedir(dir); + } + + /* for compatibility: read old files, too */ + if((dir = opendir(HARDWARE_DIR))) { + i = 0; + while((de = readdir(dir))) { + if(*de->d_name == '.') continue; + for(entry = hd_data->manual; entry; entry = entry->next) { + if(entry->unique_id && !strcmp(entry->unique_id, de->d_name)) break; + } + if(entry) continue; + PROGRESS(2, ++i, "read"); + if((entry = hd_manual_read_entry(hd_data, de->d_name))) { + ADD2LOG(" got %s\n", entry->unique_id); + *entry_next = entry; + entry_next = &entry->next; + } + } + closedir(dir); + } + + if(hd_data->debug) dump_manual(hd_data); + + /* initialize some useful status value */ + for(hd = hd_data->hd; hd; hd = hd->next) { + if( + !hd->status.configured && + !hd->status.available && + !hd->status.needed && + !hd->status.active && + !hd->status.invalid + ) { + hd->status.configured = status_new; + hd->status.available = hd->module == mod_manual ? status_unknown : status_yes; + hd->status.needed = status_no; + hd->status.active = status_unknown; + } + } + + hd_data->flags.keep_kmods = 1; + for(entry = hd_data->manual; entry; entry = entry->next) { + + for(hd = hd_data->hd; hd; hd = hd->next) { + if(hd->unique_id && !strcmp(hd->unique_id, entry->unique_id)) break; + } + + if(hd) { + /* just update config status */ + hd->status = entry->status; + hd->status.available = status_yes; + + hd->config_string = new_str(entry->config_string); + } + else { + /* add new entry */ + hd = add_hd_entry(hd_data, __LINE__, 0); + + manual2hd(hd_data, entry, hd); + + if(hd->status.available != status_unknown) hd->status.available = status_no; + + if(hd->parent_id) { + for(hd1 = hd_data->hd; hd1; hd1 = hd1->next) { + if(hd1->unique_id && !strcmp(hd1->unique_id, hd->parent_id)) { + hd->attached_to = hd1->idx; + break; + } + } + } + } + } + hd_data->flags.keep_kmods = 0; + +} + + +void hd_scan_manual2(hd_data_t *hd_data) +{ + hd_t *hd, *hd1; + + /* check if it's necessary to reconfigure this hardware */ + for(hd = hd_data->hd; hd; hd = hd->next) { + hd->status.reconfig = status_no; + + if(hd->status.needed != status_yes) continue; + + if(hd->status.available == status_no) { + hd->status.reconfig = status_yes; + continue; + } + + if(hd->status.available != status_unknown) continue; + + for(hd1 = hd_data->hd; hd1; hd1 = hd1->next) { + if(hd1 == hd) continue; + + if( + hd1->hw_class == hd->hw_class && + hd1->status.configured == status_new && + hd1->status.available == status_yes + ) break; + } + + if(hd1) hd->status.reconfig = status_yes; + } +} + + +int value2key(hash_t *hash, char *str) +{ + for(; hash->value; hash++) { + if(!strcmp(hash->value, str)) break; + } + + return hash->key; +} + +#endif + +char *key2value(hash_t *hash, int id) +{ + for(; hash->value; hash++) { + if(hash->key == id) break; + } + + return hash->value; +} + +char *hd_hw_item_name(hd_hw_item_t item) +{ + return key2value(hw_items, item); +} + + +#ifndef LIBHD_TINY + +char *hd_status_value_name(hd_status_value_t status) +{ + return key2value(status_names, status); +} + +/* + * read an entry + */ +hd_manual_t *hd_manual_read_entry(hd_data_t *hd_data, const char *id) +{ + char path[PATH_MAX]; + int i, j, line; + str_list_t *sl, *sl0; + hd_manual_t *entry; + hash_t *sect; + char *s, *s1, *s2; + int err = 0; + + snprintf(path, sizeof path, "%s/%s", HARDWARE_UNIQUE_KEYS, id); + + if(!(sl0 = read_file(path, 0, 0))) { + /* try old location, too */ + snprintf(path, sizeof path, "%s/%s", HARDWARE_DIR, id); + if(!(sl0 = read_file(path, 0, 0))) return NULL; + } + + entry = new_mem(sizeof *entry); + + // default list: no valid entries + sect = hw_ids_general + sizeof hw_ids_general / sizeof *hw_ids_general - 1; + + 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 == '[') { + s2 = s + 1; + s1 = strsep(&s2, "]"); + if(s1) { + if(!strcmp(s1, MAN_SECT_GENERAL)) { + sect = hw_ids_general; + continue; + } + if(!strcmp(s1, MAN_SECT_STATUS)) { + sect = hw_ids_status; + continue; + } + if(!strcmp(s1, MAN_SECT_HARDWARE)) { + sect = NULL; + continue; + } + } + s2 = NULL; + } + + if(!s2) { + ADD2LOG(" %s: invalid line %d\n", id, line); + err = 1; + break; + } + + if(sect) { + i = value2key(sect, s1); + if(!i) { + ADD2LOG(" %s: invalid line %d\n", id, line); + err = 1; + break; + } + s = canon_str(s2, strlen(s2)); + switch(i) { + case hw_id_unique: + entry->unique_id = s; + s = NULL; + break; + + case hw_id_parent: + entry->parent_id = s; + s = NULL; + break; + + case hw_id_child: + entry->child_ids = s; + s = NULL; + break; + + case hw_id_hwclass: + j = value2key(hw_items, s); + entry->hw_class = j; + if(!j) err = 1; + break; + + case hw_id_model: + entry->model = s; + s = NULL; + break; + + case hw_id_configured: + j = value2key(status_names, s); + entry->status.configured = j; + if(!j) err = 1; + break; + + case hw_id_available: + j = value2key(status_names, s); + entry->status.available_orig = + entry->status.available = j; + if(!j) err = 1; + break; + + case hw_id_needed: + j = value2key(status_names, s); + entry->status.needed = j; + if(!j) err = 1; + break; + + case hw_id_active: + j = value2key(status_names, s); + entry->status.active = j; + if(!j) err = 1; + break; + + case hw_id_cfgstring: + entry->config_string = s; + s = NULL; + break; + + default: + err = 1; + } + + free_mem(s); + + if(err) { + ADD2LOG(" %s: invalid line %d\n", id, line); + break; + } + } + else { + add_str_list(&entry->key, s1); + s = canon_str(s2, strlen(s2)); + add_str_list(&entry->value, s); + free_mem(s); + } + } + + free_str_list(sl0); + + /* + * do some basic consistency checks + */ + + if(!entry->unique_id || strcmp(entry->unique_id, id)) { + ADD2LOG(" %s: unique id does not match file name\n", id); + err = 1; + } + + /* + * if the status info is completely missing, fake some: + * new hardware, not autodetectable, not needed + */ + if( + !entry->status.configured && + !entry->status.available && + !entry->status.needed && + !entry->status.invalid + ) { + entry->status.configured = status_new; + entry->status.available = status_unknown; + entry->status.needed = status_no; + } + + if(!entry->status.active) entry->status.active = status_unknown; + + if( + !entry->status.configured || + !entry->status.available || + !entry->status.needed || + !entry->status.active + ) { + ADD2LOG(" %s: incomplete status\n", id); + err = 1; + } + + if(!entry->hw_class) { + ADD2LOG(" %s: no class\n", id); + err = 1; + } + + if(!entry->model) { + ADD2LOG(" %s: no model\n", id); + err = 1; + } + + if(err) { + entry = hd_free_manual(entry); + } + + return entry; +} + + +/* + * write an entry + */ + +int hd_manual_write_entry(hd_data_t *hd_data, hd_manual_t *entry) +{ + FILE *f; + char path[PATH_MAX]; + int error = 0; + struct stat sbuf; + str_list_t *sl1, *sl2; + + if(!entry) return 0; + if(!entry->unique_id || entry->status.invalid) return 1; + + snprintf(path, sizeof path, "%s/%s", HARDWARE_UNIQUE_KEYS, entry->unique_id); + + if(!(f = fopen(path, "w"))) { + /* maybe we have to create the HARDWARE_UNIQUE_KEYS directory first... */ + + if(lstat(HARDWARE_DIR, &sbuf)) { + mkdir(HARDWARE_DIR, 0755); + } + + if(lstat(HARDWARE_UNIQUE_KEYS, &sbuf)) { + mkdir(HARDWARE_UNIQUE_KEYS, 0755); + } + + if(!(f = fopen(path, "w"))) return 2; + } + + fprintf(f, "[%s]\n", MAN_SECT_GENERAL); + + if( + !fprintf(f, "%s=%s\n", + key2value(hw_ids_general, hw_id_unique), + entry->unique_id + ) + ) error = 3; + + if( + entry->parent_id && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_general, hw_id_parent), + entry->parent_id + ) + ) error = 3; + + if( + entry->child_ids && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_general, hw_id_child), + entry->child_ids + ) + ) error = 3; + + if( + (entry->hw_class && key2value(hw_items, entry->hw_class)) && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_general, hw_id_hwclass), + key2value(hw_items, entry->hw_class) + ) + ) error = 3; + + if( + entry->model && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_general, hw_id_model), + entry->model + ) + ) error = 3; + + fprintf(f, "\n[%s]\n", MAN_SECT_STATUS); + + if( + (entry->status.configured && key2value(status_names, entry->status.configured)) && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_status, hw_id_configured), + key2value(status_names, entry->status.configured) + ) + ) error = 4; + + if( + (entry->status.available && key2value(status_names, entry->status.available)) && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_status, hw_id_available), + key2value(status_names, entry->status.available) + ) + ) error = 4; + + if( + (entry->status.needed && key2value(status_names, entry->status.needed)) && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_status, hw_id_needed), + key2value(status_names, entry->status.needed) + ) + ) error = 4; + + if( + (entry->status.active && key2value(status_names, entry->status.active)) && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_status, hw_id_active), + key2value(status_names, entry->status.active) + ) + ) error = 4; + + if( + entry->config_string && + !fprintf(f, "%s=%s\n", + key2value(hw_ids_status, hw_id_cfgstring), + entry->config_string + ) + ) error = 4; + + fprintf(f, "\n[%s]\n", MAN_SECT_HARDWARE); + + for( + sl1 = entry->key, sl2 = entry->value; + sl1 && sl2; + sl1 = sl1->next, sl2 = sl2->next + ) { + if(!fprintf(f, "%s=%s\n", sl1->str, sl2->str)) { + error = 5; + break; + } + } + + fputs("\n", f); + + fclose(f); + + /* remove old file */ + if(!error) { + snprintf(path, sizeof path, "%s/%s", HARDWARE_DIR, entry->unique_id); + unlink(path); + } + + return error; +} + + +void dump_manual(hd_data_t *hd_data) +{ + hd_manual_t *entry; + static const char *txt = "manually configured hardware"; + str_list_t *sl1, *sl2; + + if(!hd_data->manual) return; + + ADD2LOG("----- %s -----\n", txt); + for(entry = hd_data->manual; entry; entry = entry->next) { + ADD2LOG(" %s=%s\n", + key2value(hw_ids_general, hw_id_unique), + entry->unique_id + ); + if(entry->parent_id) + ADD2LOG(" %s=%s\n", + key2value(hw_ids_general, hw_id_parent), + entry->parent_id + ); + if(entry->child_ids) + ADD2LOG(" %s=%s\n", + key2value(hw_ids_general, hw_id_child), + entry->child_ids + ); + ADD2LOG(" %s=%s\n", + key2value(hw_ids_general, hw_id_hwclass), + key2value(hw_items, entry->hw_class) + ); + ADD2LOG(" %s=%s\n", + key2value(hw_ids_general, hw_id_model), + entry->model + ); + ADD2LOG(" %s=%s\n", + key2value(hw_ids_status, hw_id_configured), + key2value(status_names, entry->status.configured) + ); + ADD2LOG(" %s=%s\n", + key2value(hw_ids_status, hw_id_available), + key2value(status_names, entry->status.available) + ); + ADD2LOG(" %s=%s\n", + key2value(hw_ids_status, hw_id_needed), + key2value(status_names, entry->status.needed) + ); + ADD2LOG(" %s=%s\n", + key2value(hw_ids_status, hw_id_active), + key2value(status_names, entry->status.active) + ); + if(entry->config_string) + ADD2LOG(" %s=%s\n", + key2value(hw_ids_status, hw_id_cfgstring), + entry->config_string + ); + for( + sl1 = entry->key, sl2 = entry->value; + sl1 && sl2; + sl1 = sl1->next, sl2 = sl2->next + ) { + ADD2LOG(" %s=%s\n", sl1->str, sl2->str); + } + } + ADD2LOG("----- %s end -----\n", txt); +} + + +unsigned str2id(char *str) +{ + unsigned id; + unsigned tag = 0; + + if(strlen(str) == 3) return name2eisa_id(str); + + switch(*str) { + case 'p': + tag = TAG_PCI; str++; break; + + case 'r': + str++; break; + + case 'u': + tag = TAG_USB; str++; break; + + case 's': + tag = TAG_SPECIAL; str++; break; + + case 'P': + tag = TAG_PCMCIA; str++; break; + + } + + id = strtoul(str, &str, 16); + if(*str) return 0; + + return MAKE_ID(tag, ID_VALUE(id)); +} + + +/* + * move info from hd_manual_t to hd_t + */ +void manual2hd(hd_data_t *hd_data, hd_manual_t *entry, hd_t *hd) +{ + str_list_t *sl1, *sl2; + hw_hd_items_t item; + unsigned tag, u0, u1, u2, u3, u4; + hd_res_t *res; + uint64_t u64_0, u64_1; + char *s; + int i; + + if(!hd || !entry) return; + + hd->unique_id = new_str(entry->unique_id); + hd->parent_id = new_str(entry->parent_id); + hd->child_ids = hd_split(',', entry->child_ids); + hd->model = new_str(entry->model); + hd->hw_class = entry->hw_class; + + hd->config_string = new_str(entry->config_string); + + hd->status = entry->status; + + for( + sl1 = entry->key, sl2 = entry->value; + sl1 && sl2; + sl1 = sl1->next, sl2 = sl2->next + ) { + switch(item = value2key(hw_ids_hd_items, sl1->str)) { + case hwdi_bus: + hd->bus.id = strtoul(sl2->str, NULL, 0); + break; + + case hwdi_slot: + hd->slot = strtoul(sl2->str, NULL, 0); + break; + + case hwdi_func: + hd->func = strtoul(sl2->str, NULL, 0); + break; + + case hwdi_base_class: + hd->base_class.id = strtoul(sl2->str, NULL, 0); + break; + + case hwdi_sub_class: + hd->sub_class.id = strtoul(sl2->str, NULL, 0); + break; + + case hwdi_prog_if: + hd->prog_if.id = strtoul(sl2->str, NULL, 0); + break; + + case hwdi_dev: + hd->device.id = str2id(sl2->str); + break; + + case hwdi_vend: + hd->vendor.id = str2id(sl2->str); + break; + + case hwdi_sub_dev: + hd->sub_device.id = str2id(sl2->str); + break; + + case hwdi_sub_vend: + hd->sub_vendor.id = str2id(sl2->str); + break; + + case hwdi_rev: + hd->revision.id = strtoul(sl2->str, NULL, 0); + break; + + case hwdi_compat_dev: + hd->compat_device.id = str2id(sl2->str); + break; + + case hwdi_compat_vend: + hd->compat_vendor.id = str2id(sl2->str); + break; + + case hwdi_dev_name: + hd->device.name = new_str(sl2->str); + break; + + case hwdi_vend_name: + hd->vendor.name = new_str(sl2->str); + break; + + case hwdi_sub_dev_name: + hd->sub_device.name = new_str(sl2->str); + break; + + case hwdi_sub_vend_name: + hd->sub_vendor.name = new_str(sl2->str); + break; + + case hwdi_rev_name: + hd->revision.name = new_str(sl2->str); + break; + + case hwdi_serial: + hd->serial = new_str(sl2->str); + break; + + case hwdi_unix_dev_name: + hd->unix_dev_name = new_str(sl2->str); + break; + + case hwdi_unix_dev_name2: + hd->unix_dev_name2 = new_str(sl2->str); + break; + + case hwdi_unix_dev_names: + hd->unix_dev_names = hd_split(' ', sl2->str); + break; + + case hwdi_drivers: + hd->drivers = hd_split('|', sl2->str); + break; + + case hwdi_sysfs_id: + hd->sysfs_id = new_str(sl2->str); + break; + + case hwdi_sysfs_busid: + hd->sysfs_bus_id = new_str(sl2->str); + break; + + case hwdi_sysfs_link: + hd->sysfs_device_link = new_str(sl2->str); + break; + + case hwdi_rom_id: + hd->rom_id = new_str(sl2->str); + break; + + case hwdi_broken: + hd->broken = strtoul(sl2->str, NULL, 0); + break; + + case hwdi_usb_guid: + hd->usb_guid = new_str(sl2->str); + break; + + case hwdi_hotplug: + hd->hotplug = strtol(sl2->str, NULL, 0); + break; + + case hwdi_class_list: + for( + u0 = 0, s = sl2->str; + u0 < sizeof hd->hw_class_list / sizeof *hd->hw_class_list; + u0++ + ) { + if(*s && s[1] && (i = hex(s, 2)) >= 0) { + hd->hw_class_list[u0] = i; + s += 2; + } + else { + break; + } + } + break; + + case hwdi_res_mem: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_mem; + if(sscanf(sl2->str, "0x%"SCNx64",0x%"SCNx64",%u,%u,%u", &u64_0, &u64_1, &u0, &u1, &u2) == 5) { + res->mem.base = u64_0; + res->mem.range = u64_1; + res->mem.enabled = u0; + res->mem.access = u1; + res->mem.prefetch = u2; + } + break; + + case hwdi_res_phys_mem: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_phys_mem; + if(sscanf(sl2->str, "0x%"SCNx64"", &u64_0) == 1) { + res->phys_mem.range = u64_0; + } + break; + + case hwdi_res_io: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_io; + if(sscanf(sl2->str, "0x%"SCNx64",0x%"SCNx64",%u,%u", &u64_0, &u64_1, &u0, &u1) == 4) { + res->io.base = u64_0; + res->io.range = u64_1; + res->io.enabled = u0; + res->io.access = u1; + } + break; + + case hwdi_res_irq: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_irq; + if(sscanf(sl2->str, "%u,%u,%u", &u0, &u1, &u2) == 3) { + res->irq.base = u0; + res->irq.triggered = u1; + res->irq.enabled = u2; + } + break; + + case hwdi_res_dma: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_dma; + if(sscanf(sl2->str, "%u,%u", &u0, &u1) == 2) { + res->dma.base = u0; + res->dma.enabled = u1; + } + break; + + case hwdi_res_size: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_size; + if(sscanf(sl2->str, "%u,%u,%u", &u0, &u1, &u2) == 3) { + res->size.unit = u0; + res->size.val1 = u1; + res->size.val2 = u2; + } + break; + + case hwdi_res_baud: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_baud; + if(sscanf(sl2->str, "%u,%u,%u,%u,%u", &u0, &u1, &u2, &u3, &u4) == 5) { + res->baud.speed = u0; + res->baud.bits = u1; + res->baud.stopbits = u2; + res->baud.parity = (char) u3; + res->baud.handshake = (char) u4; + } + break; + + case hwdi_res_cache: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_cache; + if(sscanf(sl2->str, "%u", &u0) == 1) { + res->cache.size = u0; + } + break; + + case hwdi_res_disk_geo: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_disk_geo; + if(sscanf(sl2->str, "%u,%u,%u,%u", &u0, &u1, &u2, &u3) == 4) { + res->disk_geo.cyls = u0; + res->disk_geo.heads = u1; + res->disk_geo.sectors = u2; + res->disk_geo.geotype = u3; + } + break; + + case hwdi_res_monitor: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_monitor; + if(sscanf(sl2->str, "%u,%u,%u,%u", &u0, &u1, &u2, &u3) == 4) { + res->monitor.width = u0; + res->monitor.height = u1; + res->monitor.vfreq = u2; + res->monitor.interlaced = u3; + } + break; + + case hwdi_res_framebuffer: + res = add_res_entry(&hd->res, new_mem(sizeof *res)); + res->any.type = res_framebuffer; + if(sscanf(sl2->str, "%u,%u,%u,%u,%u", &u0, &u1, &u2, &u3, &u4) == 5) { + res->framebuffer.width = u0; + res->framebuffer.height = u1; + res->framebuffer.bytes_p_line = u2; + res->framebuffer.colorbits = u3; + res->framebuffer.mode = u4; + } + break; + + case hwdi_features: + u0 = strtoul(sl2->str, NULL, 0); + if(u0 & (1 << 0)) hd->is.agp = 1; + if(u0 & (1 << 1)) hd->is.isapnp = 1; + if(u0 & (1 << 2)) hd->is.softraiddisk = 1; + if(u0 & (1 << 3)) hd->is.zip = 1; + if(u0 & (1 << 4)) hd->is.cdr = 1; + if(u0 & (1 << 5)) hd->is.cdrw = 1; + if(u0 & (1 << 6)) hd->is.dvd = 1; + if(u0 & (1 << 7)) hd->is.dvdr = 1; + if(u0 & (1 << 8)) hd->is.dvdram = 1; + if(u0 & (1 << 9)) hd->is.pppoe = 1; + if(u0 & (1 << 10)) hd->is.wlan = 1; + break; + } + } + + if(hd->device.id || hd->vendor.id) { + tag = ID_TAG(hd->device.id); + tag = tag ? tag : ID_TAG(hd->vendor.id); + tag = tag ? tag : TAG_PCI; + hd->device.id = MAKE_ID(tag, ID_VALUE(hd->device.id)); + hd->vendor.id = MAKE_ID(tag, ID_VALUE(hd->vendor.id)); + } + + if(hd->sub_device.id || hd->sub_vendor.id) { + tag = ID_TAG(hd->sub_device.id); + tag = tag ? tag : ID_TAG(hd->sub_vendor.id); + tag = tag ? tag : TAG_PCI; + hd->sub_device.id = MAKE_ID(tag, ID_VALUE(hd->sub_device.id)); + hd->sub_vendor.id = MAKE_ID(tag, ID_VALUE(hd->sub_vendor.id)); + } + + if(hd->compat_device.id || hd->compat_vendor.id) { + tag = ID_TAG(hd->compat_device.id); + tag = tag ? tag : ID_TAG(hd->compat_vendor.id); + tag = tag ? tag : TAG_PCI; + hd->compat_device.id = MAKE_ID(tag, ID_VALUE(hd->compat_device.id)); + hd->compat_vendor.id = MAKE_ID(tag, ID_VALUE(hd->compat_vendor.id)); + } + + if(hd->status.available == status_unknown) hd->is.manual = 1; + + /* create some entries, if missing */ + + if(!hd->device.id && !hd->vendor.id && !hd->device.name) { + hd->device.name = new_str(hd->model); + } + + if(hd->hw_class && !hd->base_class.id) { + switch(hd->hw_class) { + case hw_cdrom: + hd->base_class.id = bc_storage_device; + hd->sub_class.id = sc_sdev_cdrom; + break; + + case hw_mouse: + hd->base_class.id = bc_mouse; + hd->sub_class.id = sc_mou_other; + break; + + default: + break; + } + } + + hddb_add_info(hd_data, hd); +} + + +void hd2manual(hd_t *hd, hd_manual_t *entry) +{ + char *s, *t; + hd_res_t *res; + str_list_t *sl; + unsigned u; + + if(!hd || !entry) return; + + entry->unique_id = new_str(hd->unique_id); + entry->parent_id = new_str(hd->parent_id); + entry->child_ids = hd_join(",", hd->child_ids); + entry->model = new_str(hd->model); + entry->hw_class = hd->hw_class; + + entry->config_string = new_str(hd->config_string); + + entry->status = hd->status; + + if( + !entry->status.configured && + !entry->status.available && + !entry->status.needed && + !entry->status.active && + !entry->status.invalid + ) { + entry->status.configured = status_new; + entry->status.available = hd->module == mod_manual ? status_unknown : status_yes; + entry->status.needed = status_no; + entry->status.active = status_unknown; + } + + s = NULL; + + if(hd->broken) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_broken)); + str_printf(&s, 0, "0x%x", hd->broken); + add_str_list(&entry->value, s); + } + + if(hd->bus.id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_bus)); + str_printf(&s, 0, "0x%x", hd->bus.id); + add_str_list(&entry->value, s); + } + + if(hd->slot) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_slot)); + str_printf(&s, 0, "0x%x", hd->slot); + add_str_list(&entry->value, s); + } + + if(hd->func) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_func)); + str_printf(&s, 0, "0x%x", hd->func); + add_str_list(&entry->value, s); + } + + if(hd->base_class.id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_base_class)); + str_printf(&s, 0, "0x%x", hd->base_class.id); + add_str_list(&entry->value, s); + } + + if(hd->sub_class.id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_sub_class)); + str_printf(&s, 0, "0x%x", hd->sub_class.id); + add_str_list(&entry->value, s); + } + + if(hd->prog_if.id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_prog_if)); + str_printf(&s, 0, "0x%x", hd->prog_if.id); + add_str_list(&entry->value, s); + } + + if(hd->device.id || hd->vendor.id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_vend)); + add_str_list(&entry->value, vend_id2str(hd->vendor.id)); + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_dev)); + str_printf(&s, 0, "%04x", ID_VALUE(hd->device.id)); + add_str_list(&entry->value, s); + } + + if(hd->sub_device.id || hd->sub_vendor.id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_sub_vend)); + add_str_list(&entry->value, vend_id2str(hd->sub_vendor.id)); + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_sub_dev)); + str_printf(&s, 0, "%04x", ID_VALUE(hd->sub_device.id)); + add_str_list(&entry->value, s); + } + + if(hd->revision.id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_rev)); + str_printf(&s, 0, "0x%x", hd->revision.id); + add_str_list(&entry->value, s); + } + + if(hd->compat_device.id || hd->compat_vendor.id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_compat_vend)); + add_str_list(&entry->value, vend_id2str(hd->compat_vendor.id)); + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_compat_dev)); + str_printf(&s, 0, "%04x", ID_VALUE(hd->compat_device.id)); + add_str_list(&entry->value, s); + } + + if(hd->device.name) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_dev_name)); + add_str_list(&entry->value, hd->device.name); + } + + if(hd->vendor.name) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_vend_name)); + add_str_list(&entry->value, hd->vendor.name); + } + + if(hd->sub_device.name) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_sub_dev_name)); + add_str_list(&entry->value, hd->sub_device.name); + } + + if(hd->sub_vendor.name) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_sub_vend_name)); + add_str_list(&entry->value, hd->sub_vendor.name); + } + + if(hd->revision.name) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_rev_name)); + add_str_list(&entry->value, hd->revision.name); + } + + if(hd->serial) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_serial)); + add_str_list(&entry->value, hd->serial); + } + + if(hd->unix_dev_name) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_unix_dev_name)); + add_str_list(&entry->value, hd->unix_dev_name); + } + + if(hd->unix_dev_name2) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_unix_dev_name2)); + add_str_list(&entry->value, hd->unix_dev_name2); + } + + if(hd->unix_dev_names) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_unix_dev_names)); + s = free_mem(s); + s = hd_join(" ", hd->unix_dev_names); + add_str_list(&entry->value, s); + } + + if(hd->drivers) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_drivers)); + s = free_mem(s); + s = hd_join("|", hd->drivers); + add_str_list(&entry->value, s); + } + + if(hd->sysfs_id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_sysfs_id)); + add_str_list(&entry->value, hd->sysfs_id); + } + + if(hd->sysfs_bus_id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_sysfs_busid)); + add_str_list(&entry->value, hd->sysfs_bus_id); + } + + if(hd->sysfs_device_link) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_sysfs_link)); + add_str_list(&entry->value, hd->sysfs_device_link); + } + + if(hd->rom_id) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_rom_id)); + add_str_list(&entry->value, hd->rom_id); + } + + if(hd->usb_guid) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_usb_guid)); + add_str_list(&entry->value, hd->usb_guid); + } + + if(hd->hotplug) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_hotplug)); + str_printf(&s, 0, "%d", hd->hotplug); + add_str_list(&entry->value, s); + } + + s = free_mem(s); + for(u = 0; u < sizeof hd->hw_class_list / sizeof *hd->hw_class_list; u++) { + str_printf(&s, -1, "%02x", hd->hw_class_list[u]); + } + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_class_list)); + add_str_list(&entry->value, s); + + u = 0; + if(hd->is.agp) u |= 1 << 0; + if(hd->is.isapnp) u |= 1 << 1; + if(hd->is.softraiddisk) u |= 1 << 2; + if(hd->is.zip) u |= 1 << 3; + if(hd->is.cdr) u |= 1 << 4; + if(hd->is.cdrw) u |= 1 << 5; + if(hd->is.dvd) u |= 1 << 6; + if(hd->is.dvdr) u |= 1 << 7; + if(hd->is.dvdram) u |= 1 << 8; + if(hd->is.pppoe) u |= 1 << 9; + if(hd->is.wlan) u |= 1 << 10; + + if(u) { + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_features)); + str_printf(&s, 0, "0x%x", u); + add_str_list(&entry->value, s); + } + + for(res = hd->res; res; res = res->next) { + sl = NULL; + switch(res->any.type) { + case res_mem: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_mem)); + str_printf(&s, 0, "0x%"PRIx64"", res->mem.base); + add_str_list(&sl, s); + str_printf(&s, 0, "0x%"PRIx64"", res->mem.range); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->mem.enabled); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->mem.access); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->mem.prefetch); + add_str_list(&sl, s); + break; + + case res_phys_mem: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_phys_mem)); + str_printf(&s, 0, "0x%"PRIx64"", res->phys_mem.range); + add_str_list(&sl, s); + break; + + case res_io: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_io)); + str_printf(&s, 0, "0x%"PRIx64"", res->io.base); + add_str_list(&sl, s); + str_printf(&s, 0, "0x%"PRIx64"", res->io.range); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->io.enabled); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->io.access); + add_str_list(&sl, s); + break; + + case res_irq: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_irq)); + str_printf(&s, 0, "%u", res->irq.base); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->irq.triggered); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->irq.enabled); + add_str_list(&sl, s); + break; + + case res_dma: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_dma)); + str_printf(&s, 0, "%u", res->dma.base); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->dma.enabled); + add_str_list(&sl, s); + break; + + case res_size: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_size)); + str_printf(&s, 0, "%u", res->size.unit); + add_str_list(&sl, s); + str_printf(&s, 0, "%"PRIu64, res->size.val1); + add_str_list(&sl, s); + str_printf(&s, 0, "%"PRIu64, res->size.val2); + add_str_list(&sl, s); + break; + + case res_baud: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_baud)); + str_printf(&s, 0, "%u", res->baud.speed); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->baud.bits); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->baud.stopbits); + add_str_list(&sl, s); + str_printf(&s, 0, "0x%02x", (unsigned) res->baud.parity); + add_str_list(&sl, s); + str_printf(&s, 0, "0x%02x", (unsigned) res->baud.handshake); + add_str_list(&sl, s); + break; + + case res_cache: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_cache)); + str_printf(&s, 0, "%u", res->cache.size); + add_str_list(&sl, s); + break; + + case res_disk_geo: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_disk_geo)); + str_printf(&s, 0, "%u", res->disk_geo.cyls); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->disk_geo.heads); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->disk_geo.sectors); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->disk_geo.geotype); + add_str_list(&sl, s); + break; + + case res_monitor: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_monitor)); + str_printf(&s, 0, "%u", res->monitor.width); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->monitor.height); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->monitor.vfreq); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->monitor.interlaced); + add_str_list(&sl, s); + break; + + case res_framebuffer: + add_str_list(&entry->key, key2value(hw_ids_hd_items, hwdi_res_framebuffer)); + str_printf(&s, 0, "%u", res->framebuffer.width); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->framebuffer.height); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->framebuffer.bytes_p_line); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->framebuffer.colorbits); + add_str_list(&sl, s); + str_printf(&s, 0, "%u", res->framebuffer.mode); + add_str_list(&sl, s); + break; + + default: + break; + } + /* keep entry->key & entry->value symmetrical! */ + if(sl) { + t = hd_join(",", sl); + add_str_list(&entry->value, t); + free_mem(t); + free_str_list(sl); + } + } + + free_mem(s); +} + + +hd_t *hd_read_config(hd_data_t *hd_data, const char *id) +{ + hd_t *hd = NULL; + hd_manual_t *entry; + + hddb_init(hd_data); + + entry = hd_manual_read_entry(hd_data, id); + + if(entry) { + hd = new_mem(sizeof *hd); + hd->module = hd_data->module; + hd->line = __LINE__; + hd->tag.freeit = 1; /* make it a 'stand alone' entry */ + manual2hd(hd_data, entry, hd); + hd_free_manual(entry); + } + + return hd; +} + + +int hd_write_config(hd_data_t *hd_data, hd_t *hd) +{ + int err = 0; + hd_manual_t *entry; + + if(!hd_report_this(hd_data, hd)) return 0; + + entry = new_mem(sizeof *entry); + + hd2manual(hd, entry); + + err = entry->unique_id ? hd_manual_write_entry(hd_data, entry) : 5; + + hd_free_manual(entry); + + return err; +} + + +#endif /* LIBHD_TINY */ +