--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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 */
+