]>
git.ipfire.org Git - people/trikolon/ipfire-2.x.git/blob - src/hwinfo/src/hd/manual.c
15 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
17 * hardware in /var/lib/hardware/
19 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
27 /* corresponds to hd_status_value_t */
28 static hash_t status_names
[] = {
30 { status_yes
, "yes" },
31 { status_unknown
, "unknown" },
32 { status_new
, "new" },
36 /* corresponds to hd_hw_item_t */
37 static hash_t hw_items
[] = {
40 { hw_keyboard
, "keyboard" },
41 { hw_braille
, "braille" },
42 { hw_mouse
, "mouse" },
43 { hw_joystick
, "joystick" },
44 { hw_printer
, "printer" },
45 { hw_scanner
, "scanner" },
46 { hw_chipcard
, "chipcard" },
47 { hw_monitor
, "monitor" },
49 { hw_display
, "graphics card" },
50 { hw_framebuffer
, "framebuffer" },
51 { hw_camera
, "camera" },
52 { hw_sound
, "sound" },
53 { hw_storage_ctrl
, "storage" },
54 { hw_network_ctrl
, "network" },
55 { hw_isdn
, "isdn adapter" },
56 { hw_modem
, "modem" },
57 { hw_network
, "network interface" },
59 { hw_partition
, "partition" },
60 { hw_cdrom
, "cdrom" },
61 { hw_floppy
, "floppy" },
62 { hw_manual
, "manual" },
63 { hw_usb_ctrl
, "usb controller" },
67 { hw_isapnp
, "isapnp" },
68 { hw_bridge
, "bridge" },
72 { hw_memory
, "memory" },
73 { hw_dvb
, "dvb card" },
74 { hw_pcmcia
, "pcmcia" },
75 { hw_pcmcia_ctrl
, "pcmcia controller" },
76 { hw_ieee1394
, "firewire" },
77 { hw_ieee1394_ctrl
, "firewire controller" },
78 { hw_hotplug
, "hotplug" },
79 { hw_hotplug_ctrl
, "hotplug controller" },
81 { hw_pppoe
, "pppoe" },
82 { hw_wlan
, "wlan card" },
83 { hw_dsl
, "DSL adapter" },
84 { hw_block
, "block device" },
86 { hw_vbe
, "vesa bios" },
87 { hw_bluetooth
, "bluetooth" },
88 { hw_unknown
, "unknown" },
93 hw_id_unique
= 1, hw_id_parent
, hw_id_child
, hw_id_hwclass
, hw_id_model
,
94 hw_id_configured
, hw_id_available
, hw_id_needed
, hw_id_cfgstring
, hw_id_active
99 #define MAN_SECT_GENERAL "General"
100 #define MAN_SECT_STATUS "Status"
101 #define MAN_SECT_HARDWARE "Hardware"
103 static hash_t hw_ids_general
[] = {
104 { hw_id_unique
, "UniqueID" },
105 { hw_id_parent
, "ParentID" },
106 { hw_id_child
, "ChildIDs" },
107 { hw_id_hwclass
, "HWClass" },
108 { hw_id_model
, "Model" },
112 static hash_t hw_ids_status
[] = {
113 { hw_id_configured
, "Configured" },
114 { hw_id_available
, "Available" },
115 { hw_id_needed
, "Needed" },
116 { hw_id_cfgstring
, "ConfigString" },
117 { hw_id_active
, "Active" },
121 /* structure elements from hd_t */
123 hwdi_bus
= 1, hwdi_slot
, hwdi_func
, hwdi_base_class
, hwdi_sub_class
,
124 hwdi_prog_if
, hwdi_dev
, hwdi_vend
, hwdi_sub_dev
, hwdi_sub_vend
, hwdi_rev
,
125 hwdi_compat_dev
, hwdi_compat_vend
, hwdi_dev_name
, hwdi_vend_name
,
126 hwdi_sub_dev_name
, hwdi_sub_vend_name
, hwdi_rev_name
, hwdi_serial
,
127 hwdi_unix_dev_name
, hwdi_unix_dev_name2
, hwdi_unix_dev_names
, hwdi_rom_id
,
128 hwdi_broken
, hwdi_usb_guid
, hwdi_res_mem
, hwdi_res_phys_mem
, hwdi_res_io
,
129 hwdi_res_irq
, hwdi_res_dma
, hwdi_res_size
, hwdi_res_baud
, hwdi_res_cache
,
130 hwdi_res_disk_geo
, hwdi_res_monitor
, hwdi_res_framebuffer
, hwdi_features
,
131 hwdi_hotplug
, hwdi_class_list
, hwdi_drivers
, hwdi_sysfs_id
,
132 hwdi_sysfs_busid
, hwdi_sysfs_link
135 static hash_t hw_ids_hd_items
[] = {
137 { hwdi_slot
, "Slot" },
138 { hwdi_func
, "Function" },
139 { hwdi_base_class
, "BaseClass" },
140 { hwdi_sub_class
, "SubClass" },
141 { hwdi_prog_if
, "ProgIF" },
142 { hwdi_dev
, "DeviceID" },
143 { hwdi_vend
, "VendorID" },
144 { hwdi_sub_dev
, "SubDeviceID" },
145 { hwdi_sub_vend
, "SubVendorID" },
146 { hwdi_rev
, "RevisionID" },
147 { hwdi_compat_dev
, "CompatDeviceID" },
148 { hwdi_compat_vend
, "CompatVendorID" },
149 { hwdi_dev_name
, "DeviceName" },
150 { hwdi_vend_name
, "VendorName" },
151 { hwdi_sub_dev_name
, "SubDeviceName" },
152 { hwdi_sub_vend_name
, "SubVendorName" },
153 { hwdi_rev_name
, "RevisionName" },
154 { hwdi_serial
, "Serial" },
155 { hwdi_unix_dev_name
, "UnixDevice" },
156 { hwdi_unix_dev_name2
, "UnixDeviceAlt" },
157 { hwdi_unix_dev_names
, "UnixDeviceList" },
158 { hwdi_rom_id
, "ROMID" },
159 { hwdi_broken
, "Broken" },
160 { hwdi_usb_guid
, "USBGUID" },
161 { hwdi_res_phys_mem
, "Res.PhysMemory" },
162 { hwdi_res_mem
, "Res.Memory" },
163 { hwdi_res_io
, "Res.IO" },
164 { hwdi_res_irq
, "Res.Interrupts" },
165 { hwdi_res_dma
, "Res.DMA" },
166 { hwdi_res_size
, "Res.Size" },
167 { hwdi_res_baud
, "Res.Baud" },
168 { hwdi_res_cache
, "Res.Cache" },
169 { hwdi_res_disk_geo
, "Res.DiskGeometry" },
170 { hwdi_res_monitor
, "Res.Monitor" },
171 { hwdi_res_framebuffer
, "Res.Framebuffer" },
172 { hwdi_features
, "Features" },
173 { hwdi_hotplug
, "Hotplug" },
174 { hwdi_class_list
, "HWClassList" },
175 { hwdi_drivers
, "Drivers" },
176 { hwdi_sysfs_id
, "SysfsID" },
177 { hwdi_sysfs_busid
, "SysfsBusID" },
178 { hwdi_sysfs_link
, "SysfsLink" },
183 static char *key2value(hash_t
*hash
, int id
);
187 static int value2key(hash_t
*hash
, char *str
);
188 static void dump_manual(hd_data_t
*hd_data
);
189 static unsigned str2id(char *str
);
190 static void manual2hd(hd_data_t
*hd_data
, hd_manual_t
*entry
, hd_t
*hd
);
191 static void hd2manual(hd_t
*hd
, hd_manual_t
*entry
);
193 void hd_scan_manual(hd_data_t
*hd_data
)
197 hd_manual_t
*entry
, **entry_next
;
201 if(!hd_probe_feature(hd_data
, pr_manual
)) return;
203 hd_data
->module
= mod_manual
;
206 remove_hd_entries(hd_data
);
208 hd_data
->manual
= hd_free_manual(hd_data
->manual
);
209 entry_next
= &hd_data
->manual
;
211 if((dir
= opendir(HARDWARE_UNIQUE_KEYS
))) {
213 while((de
= readdir(dir
))) {
214 if(*de
->d_name
== '.') continue;
215 PROGRESS(1, ++i
, "read");
216 if((entry
= hd_manual_read_entry(hd_data
, de
->d_name
))) {
217 ADD2LOG(" got %s\n", entry
->unique_id
);
219 entry_next
= &entry
->next
;
225 /* for compatibility: read old files, too */
226 if((dir
= opendir(HARDWARE_DIR
))) {
228 while((de
= readdir(dir
))) {
229 if(*de
->d_name
== '.') continue;
230 for(entry
= hd_data
->manual
; entry
; entry
= entry
->next
) {
231 if(entry
->unique_id
&& !strcmp(entry
->unique_id
, de
->d_name
)) break;
234 PROGRESS(2, ++i
, "read");
235 if((entry
= hd_manual_read_entry(hd_data
, de
->d_name
))) {
236 ADD2LOG(" got %s\n", entry
->unique_id
);
238 entry_next
= &entry
->next
;
244 if(hd_data
->debug
) dump_manual(hd_data
);
246 /* initialize some useful status value */
247 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
249 !hd
->status
.configured
&&
250 !hd
->status
.available
&&
251 !hd
->status
.needed
&&
252 !hd
->status
.active
&&
255 hd
->status
.configured
= status_new
;
256 hd
->status
.available
= hd
->module
== mod_manual
? status_unknown
: status_yes
;
257 hd
->status
.needed
= status_no
;
258 hd
->status
.active
= status_unknown
;
262 hd_data
->flags
.keep_kmods
= 1;
263 for(entry
= hd_data
->manual
; entry
; entry
= entry
->next
) {
265 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
266 if(hd
->unique_id
&& !strcmp(hd
->unique_id
, entry
->unique_id
)) break;
270 /* just update config status */
271 hd
->status
= entry
->status
;
272 hd
->status
.available
= status_yes
;
274 hd
->config_string
= new_str(entry
->config_string
);
278 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
280 manual2hd(hd_data
, entry
, hd
);
282 if(hd
->status
.available
!= status_unknown
) hd
->status
.available
= status_no
;
285 for(hd1
= hd_data
->hd
; hd1
; hd1
= hd1
->next
) {
286 if(hd1
->unique_id
&& !strcmp(hd1
->unique_id
, hd
->parent_id
)) {
287 hd
->attached_to
= hd1
->idx
;
294 hd_data
->flags
.keep_kmods
= 0;
299 void hd_scan_manual2(hd_data_t
*hd_data
)
303 /* check if it's necessary to reconfigure this hardware */
304 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
305 hd
->status
.reconfig
= status_no
;
307 if(hd
->status
.needed
!= status_yes
) continue;
309 if(hd
->status
.available
== status_no
) {
310 hd
->status
.reconfig
= status_yes
;
314 if(hd
->status
.available
!= status_unknown
) continue;
316 for(hd1
= hd_data
->hd
; hd1
; hd1
= hd1
->next
) {
317 if(hd1
== hd
) continue;
320 hd1
->hw_class
== hd
->hw_class
&&
321 hd1
->status
.configured
== status_new
&&
322 hd1
->status
.available
== status_yes
326 if(hd1
) hd
->status
.reconfig
= status_yes
;
331 int value2key(hash_t
*hash
, char *str
)
333 for(; hash
->value
; hash
++) {
334 if(!strcmp(hash
->value
, str
)) break;
342 char *key2value(hash_t
*hash
, int id
)
344 for(; hash
->value
; hash
++) {
345 if(hash
->key
== id
) break;
351 char *hd_hw_item_name(hd_hw_item_t item
)
353 return key2value(hw_items
, item
);
359 char *hd_status_value_name(hd_status_value_t status
)
361 return key2value(status_names
, status
);
367 hd_manual_t
*hd_manual_read_entry(hd_data_t
*hd_data
, const char *id
)
371 str_list_t
*sl
, *sl0
;
377 snprintf(path
, sizeof path
, "%s/%s", HARDWARE_UNIQUE_KEYS
, id
);
379 if(!(sl0
= read_file(path
, 0, 0))) {
380 /* try old location, too */
381 snprintf(path
, sizeof path
, "%s/%s", HARDWARE_DIR
, id
);
382 if(!(sl0
= read_file(path
, 0, 0))) return NULL
;
385 entry
= new_mem(sizeof *entry
);
387 // default list: no valid entries
388 sect
= hw_ids_general
+ sizeof hw_ids_general
/ sizeof *hw_ids_general
- 1;
390 for(line
= 1, sl
= sl0
; sl
; sl
= sl
->next
, line
++) {
392 while(isspace(*s
)) s
++;
393 if(!*s
|| *s
== '#' || *s
== ';') continue; /* empty lines & comments */
396 s1
= strsep(&s2
, "=");
398 if(!s2
&& *s
== '[') {
400 s1
= strsep(&s2
, "]");
402 if(!strcmp(s1
, MAN_SECT_GENERAL
)) {
403 sect
= hw_ids_general
;
406 if(!strcmp(s1
, MAN_SECT_STATUS
)) {
407 sect
= hw_ids_status
;
410 if(!strcmp(s1
, MAN_SECT_HARDWARE
)) {
419 ADD2LOG(" %s: invalid line %d\n", id
, line
);
425 i
= value2key(sect
, s1
);
427 ADD2LOG(" %s: invalid line %d\n", id
, line
);
431 s
= canon_str(s2
, strlen(s2
));
434 entry
->unique_id
= s
;
439 entry
->parent_id
= s
;
444 entry
->child_ids
= s
;
449 j
= value2key(hw_items
, s
);
459 case hw_id_configured
:
460 j
= value2key(status_names
, s
);
461 entry
->status
.configured
= j
;
465 case hw_id_available
:
466 j
= value2key(status_names
, s
);
467 entry
->status
.available_orig
=
468 entry
->status
.available
= j
;
473 j
= value2key(status_names
, s
);
474 entry
->status
.needed
= j
;
479 j
= value2key(status_names
, s
);
480 entry
->status
.active
= j
;
484 case hw_id_cfgstring
:
485 entry
->config_string
= s
;
496 ADD2LOG(" %s: invalid line %d\n", id
, line
);
501 add_str_list(&entry
->key
, s1
);
502 s
= canon_str(s2
, strlen(s2
));
503 add_str_list(&entry
->value
, s
);
511 * do some basic consistency checks
514 if(!entry
->unique_id
|| strcmp(entry
->unique_id
, id
)) {
515 ADD2LOG(" %s: unique id does not match file name\n", id
);
520 * if the status info is completely missing, fake some:
521 * new hardware, not autodetectable, not needed
524 !entry
->status
.configured
&&
525 !entry
->status
.available
&&
526 !entry
->status
.needed
&&
527 !entry
->status
.invalid
529 entry
->status
.configured
= status_new
;
530 entry
->status
.available
= status_unknown
;
531 entry
->status
.needed
= status_no
;
534 if(!entry
->status
.active
) entry
->status
.active
= status_unknown
;
537 !entry
->status
.configured
||
538 !entry
->status
.available
||
539 !entry
->status
.needed
||
540 !entry
->status
.active
542 ADD2LOG(" %s: incomplete status\n", id
);
546 if(!entry
->hw_class
) {
547 ADD2LOG(" %s: no class\n", id
);
552 ADD2LOG(" %s: no model\n", id
);
557 entry
= hd_free_manual(entry
);
568 int hd_manual_write_entry(hd_data_t
*hd_data
, hd_manual_t
*entry
)
574 str_list_t
*sl1
, *sl2
;
577 if(!entry
->unique_id
|| entry
->status
.invalid
) return 1;
579 snprintf(path
, sizeof path
, "%s/%s", HARDWARE_UNIQUE_KEYS
, entry
->unique_id
);
581 if(!(f
= fopen(path
, "w"))) {
582 /* maybe we have to create the HARDWARE_UNIQUE_KEYS directory first... */
584 if(lstat(HARDWARE_DIR
, &sbuf
)) {
585 mkdir(HARDWARE_DIR
, 0755);
588 if(lstat(HARDWARE_UNIQUE_KEYS
, &sbuf
)) {
589 mkdir(HARDWARE_UNIQUE_KEYS
, 0755);
592 if(!(f
= fopen(path
, "w"))) return 2;
595 fprintf(f
, "[%s]\n", MAN_SECT_GENERAL
);
598 !fprintf(f
, "%s=%s\n",
599 key2value(hw_ids_general
, hw_id_unique
),
606 !fprintf(f
, "%s=%s\n",
607 key2value(hw_ids_general
, hw_id_parent
),
614 !fprintf(f
, "%s=%s\n",
615 key2value(hw_ids_general
, hw_id_child
),
621 (entry
->hw_class
&& key2value(hw_items
, entry
->hw_class
)) &&
622 !fprintf(f
, "%s=%s\n",
623 key2value(hw_ids_general
, hw_id_hwclass
),
624 key2value(hw_items
, entry
->hw_class
)
630 !fprintf(f
, "%s=%s\n",
631 key2value(hw_ids_general
, hw_id_model
),
636 fprintf(f
, "\n[%s]\n", MAN_SECT_STATUS
);
639 (entry
->status
.configured
&& key2value(status_names
, entry
->status
.configured
)) &&
640 !fprintf(f
, "%s=%s\n",
641 key2value(hw_ids_status
, hw_id_configured
),
642 key2value(status_names
, entry
->status
.configured
)
647 (entry
->status
.available
&& key2value(status_names
, entry
->status
.available
)) &&
648 !fprintf(f
, "%s=%s\n",
649 key2value(hw_ids_status
, hw_id_available
),
650 key2value(status_names
, entry
->status
.available
)
655 (entry
->status
.needed
&& key2value(status_names
, entry
->status
.needed
)) &&
656 !fprintf(f
, "%s=%s\n",
657 key2value(hw_ids_status
, hw_id_needed
),
658 key2value(status_names
, entry
->status
.needed
)
663 (entry
->status
.active
&& key2value(status_names
, entry
->status
.active
)) &&
664 !fprintf(f
, "%s=%s\n",
665 key2value(hw_ids_status
, hw_id_active
),
666 key2value(status_names
, entry
->status
.active
)
671 entry
->config_string
&&
672 !fprintf(f
, "%s=%s\n",
673 key2value(hw_ids_status
, hw_id_cfgstring
),
678 fprintf(f
, "\n[%s]\n", MAN_SECT_HARDWARE
);
681 sl1
= entry
->key
, sl2
= entry
->value
;
683 sl1
= sl1
->next
, sl2
= sl2
->next
685 if(!fprintf(f
, "%s=%s\n", sl1
->str
, sl2
->str
)) {
695 /* remove old file */
697 snprintf(path
, sizeof path
, "%s/%s", HARDWARE_DIR
, entry
->unique_id
);
705 void dump_manual(hd_data_t
*hd_data
)
708 static const char *txt
= "manually configured hardware";
709 str_list_t
*sl1
, *sl2
;
711 if(!hd_data
->manual
) return;
713 ADD2LOG("----- %s -----\n", txt
);
714 for(entry
= hd_data
->manual
; entry
; entry
= entry
->next
) {
716 key2value(hw_ids_general
, hw_id_unique
),
721 key2value(hw_ids_general
, hw_id_parent
),
726 key2value(hw_ids_general
, hw_id_child
),
730 key2value(hw_ids_general
, hw_id_hwclass
),
731 key2value(hw_items
, entry
->hw_class
)
734 key2value(hw_ids_general
, hw_id_model
),
738 key2value(hw_ids_status
, hw_id_configured
),
739 key2value(status_names
, entry
->status
.configured
)
742 key2value(hw_ids_status
, hw_id_available
),
743 key2value(status_names
, entry
->status
.available
)
746 key2value(hw_ids_status
, hw_id_needed
),
747 key2value(status_names
, entry
->status
.needed
)
750 key2value(hw_ids_status
, hw_id_active
),
751 key2value(status_names
, entry
->status
.active
)
753 if(entry
->config_string
)
755 key2value(hw_ids_status
, hw_id_cfgstring
),
759 sl1
= entry
->key
, sl2
= entry
->value
;
761 sl1
= sl1
->next
, sl2
= sl2
->next
763 ADD2LOG(" %s=%s\n", sl1
->str
, sl2
->str
);
766 ADD2LOG("----- %s end -----\n", txt
);
770 unsigned str2id(char *str
)
775 if(strlen(str
) == 3) return name2eisa_id(str
);
779 tag
= TAG_PCI
; str
++; break;
785 tag
= TAG_USB
; str
++; break;
788 tag
= TAG_SPECIAL
; str
++; break;
791 tag
= TAG_PCMCIA
; str
++; break;
795 id
= strtoul(str
, &str
, 16);
798 return MAKE_ID(tag
, ID_VALUE(id
));
803 * move info from hd_manual_t to hd_t
805 void manual2hd(hd_data_t
*hd_data
, hd_manual_t
*entry
, hd_t
*hd
)
807 str_list_t
*sl1
, *sl2
;
809 unsigned tag
, u0
, u1
, u2
, u3
, u4
;
811 uint64_t u64_0
, u64_1
;
815 if(!hd
|| !entry
) return;
817 hd
->unique_id
= new_str(entry
->unique_id
);
818 hd
->parent_id
= new_str(entry
->parent_id
);
819 hd
->child_ids
= hd_split(',', entry
->child_ids
);
820 hd
->model
= new_str(entry
->model
);
821 hd
->hw_class
= entry
->hw_class
;
823 hd
->config_string
= new_str(entry
->config_string
);
825 hd
->status
= entry
->status
;
828 sl1
= entry
->key
, sl2
= entry
->value
;
830 sl1
= sl1
->next
, sl2
= sl2
->next
832 switch(item
= value2key(hw_ids_hd_items
, sl1
->str
)) {
834 hd
->bus
.id
= strtoul(sl2
->str
, NULL
, 0);
838 hd
->slot
= strtoul(sl2
->str
, NULL
, 0);
842 hd
->func
= strtoul(sl2
->str
, NULL
, 0);
845 case hwdi_base_class
:
846 hd
->base_class
.id
= strtoul(sl2
->str
, NULL
, 0);
850 hd
->sub_class
.id
= strtoul(sl2
->str
, NULL
, 0);
854 hd
->prog_if
.id
= strtoul(sl2
->str
, NULL
, 0);
858 hd
->device
.id
= str2id(sl2
->str
);
862 hd
->vendor
.id
= str2id(sl2
->str
);
866 hd
->sub_device
.id
= str2id(sl2
->str
);
870 hd
->sub_vendor
.id
= str2id(sl2
->str
);
874 hd
->revision
.id
= strtoul(sl2
->str
, NULL
, 0);
877 case hwdi_compat_dev
:
878 hd
->compat_device
.id
= str2id(sl2
->str
);
881 case hwdi_compat_vend
:
882 hd
->compat_vendor
.id
= str2id(sl2
->str
);
886 hd
->device
.name
= new_str(sl2
->str
);
890 hd
->vendor
.name
= new_str(sl2
->str
);
893 case hwdi_sub_dev_name
:
894 hd
->sub_device
.name
= new_str(sl2
->str
);
897 case hwdi_sub_vend_name
:
898 hd
->sub_vendor
.name
= new_str(sl2
->str
);
902 hd
->revision
.name
= new_str(sl2
->str
);
906 hd
->serial
= new_str(sl2
->str
);
909 case hwdi_unix_dev_name
:
910 hd
->unix_dev_name
= new_str(sl2
->str
);
913 case hwdi_unix_dev_name2
:
914 hd
->unix_dev_name2
= new_str(sl2
->str
);
917 case hwdi_unix_dev_names
:
918 hd
->unix_dev_names
= hd_split(' ', sl2
->str
);
922 hd
->drivers
= hd_split('|', sl2
->str
);
926 hd
->sysfs_id
= new_str(sl2
->str
);
929 case hwdi_sysfs_busid
:
930 hd
->sysfs_bus_id
= new_str(sl2
->str
);
933 case hwdi_sysfs_link
:
934 hd
->sysfs_device_link
= new_str(sl2
->str
);
938 hd
->rom_id
= new_str(sl2
->str
);
942 hd
->broken
= strtoul(sl2
->str
, NULL
, 0);
946 hd
->usb_guid
= new_str(sl2
->str
);
950 hd
->hotplug
= strtol(sl2
->str
, NULL
, 0);
953 case hwdi_class_list
:
955 u0
= 0, s
= sl2
->str
;
956 u0
< sizeof hd
->hw_class_list
/ sizeof *hd
->hw_class_list
;
959 if(*s
&& s
[1] && (i
= hex(s
, 2)) >= 0) {
960 hd
->hw_class_list
[u0
] = i
;
970 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
971 res
->any
.type
= res_mem
;
972 if(sscanf(sl2
->str
, "0x%"SCNx64
",0x%"SCNx64
",%u,%u,%u", &u64_0
, &u64_1
, &u0
, &u1
, &u2
) == 5) {
973 res
->mem
.base
= u64_0
;
974 res
->mem
.range
= u64_1
;
975 res
->mem
.enabled
= u0
;
976 res
->mem
.access
= u1
;
977 res
->mem
.prefetch
= u2
;
981 case hwdi_res_phys_mem
:
982 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
983 res
->any
.type
= res_phys_mem
;
984 if(sscanf(sl2
->str
, "0x%"SCNx64
"", &u64_0
) == 1) {
985 res
->phys_mem
.range
= u64_0
;
990 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
991 res
->any
.type
= res_io
;
992 if(sscanf(sl2
->str
, "0x%"SCNx64
",0x%"SCNx64
",%u,%u", &u64_0
, &u64_1
, &u0
, &u1
) == 4) {
993 res
->io
.base
= u64_0
;
994 res
->io
.range
= u64_1
;
995 res
->io
.enabled
= u0
;
1001 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
1002 res
->any
.type
= res_irq
;
1003 if(sscanf(sl2
->str
, "%u,%u,%u", &u0
, &u1
, &u2
) == 3) {
1005 res
->irq
.triggered
= u1
;
1006 res
->irq
.enabled
= u2
;
1011 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
1012 res
->any
.type
= res_dma
;
1013 if(sscanf(sl2
->str
, "%u,%u", &u0
, &u1
) == 2) {
1015 res
->dma
.enabled
= u1
;
1020 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
1021 res
->any
.type
= res_size
;
1022 if(sscanf(sl2
->str
, "%u,%u,%u", &u0
, &u1
, &u2
) == 3) {
1023 res
->size
.unit
= u0
;
1024 res
->size
.val1
= u1
;
1025 res
->size
.val2
= u2
;
1030 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
1031 res
->any
.type
= res_baud
;
1032 if(sscanf(sl2
->str
, "%u,%u,%u,%u,%u", &u0
, &u1
, &u2
, &u3
, &u4
) == 5) {
1033 res
->baud
.speed
= u0
;
1034 res
->baud
.bits
= u1
;
1035 res
->baud
.stopbits
= u2
;
1036 res
->baud
.parity
= (char) u3
;
1037 res
->baud
.handshake
= (char) u4
;
1041 case hwdi_res_cache
:
1042 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
1043 res
->any
.type
= res_cache
;
1044 if(sscanf(sl2
->str
, "%u", &u0
) == 1) {
1045 res
->cache
.size
= u0
;
1049 case hwdi_res_disk_geo
:
1050 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
1051 res
->any
.type
= res_disk_geo
;
1052 if(sscanf(sl2
->str
, "%u,%u,%u,%u", &u0
, &u1
, &u2
, &u3
) == 4) {
1053 res
->disk_geo
.cyls
= u0
;
1054 res
->disk_geo
.heads
= u1
;
1055 res
->disk_geo
.sectors
= u2
;
1056 res
->disk_geo
.geotype
= u3
;
1060 case hwdi_res_monitor
:
1061 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
1062 res
->any
.type
= res_monitor
;
1063 if(sscanf(sl2
->str
, "%u,%u,%u,%u", &u0
, &u1
, &u2
, &u3
) == 4) {
1064 res
->monitor
.width
= u0
;
1065 res
->monitor
.height
= u1
;
1066 res
->monitor
.vfreq
= u2
;
1067 res
->monitor
.interlaced
= u3
;
1071 case hwdi_res_framebuffer
:
1072 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
1073 res
->any
.type
= res_framebuffer
;
1074 if(sscanf(sl2
->str
, "%u,%u,%u,%u,%u", &u0
, &u1
, &u2
, &u3
, &u4
) == 5) {
1075 res
->framebuffer
.width
= u0
;
1076 res
->framebuffer
.height
= u1
;
1077 res
->framebuffer
.bytes_p_line
= u2
;
1078 res
->framebuffer
.colorbits
= u3
;
1079 res
->framebuffer
.mode
= u4
;
1084 u0
= strtoul(sl2
->str
, NULL
, 0);
1085 if(u0
& (1 << 0)) hd
->is
.agp
= 1;
1086 if(u0
& (1 << 1)) hd
->is
.isapnp
= 1;
1087 if(u0
& (1 << 2)) hd
->is
.softraiddisk
= 1;
1088 if(u0
& (1 << 3)) hd
->is
.zip
= 1;
1089 if(u0
& (1 << 4)) hd
->is
.cdr
= 1;
1090 if(u0
& (1 << 5)) hd
->is
.cdrw
= 1;
1091 if(u0
& (1 << 6)) hd
->is
.dvd
= 1;
1092 if(u0
& (1 << 7)) hd
->is
.dvdr
= 1;
1093 if(u0
& (1 << 8)) hd
->is
.dvdram
= 1;
1094 if(u0
& (1 << 9)) hd
->is
.pppoe
= 1;
1095 if(u0
& (1 << 10)) hd
->is
.wlan
= 1;
1100 if(hd
->device
.id
|| hd
->vendor
.id
) {
1101 tag
= ID_TAG(hd
->device
.id
);
1102 tag
= tag
? tag
: ID_TAG(hd
->vendor
.id
);
1103 tag
= tag
? tag
: TAG_PCI
;
1104 hd
->device
.id
= MAKE_ID(tag
, ID_VALUE(hd
->device
.id
));
1105 hd
->vendor
.id
= MAKE_ID(tag
, ID_VALUE(hd
->vendor
.id
));
1108 if(hd
->sub_device
.id
|| hd
->sub_vendor
.id
) {
1109 tag
= ID_TAG(hd
->sub_device
.id
);
1110 tag
= tag
? tag
: ID_TAG(hd
->sub_vendor
.id
);
1111 tag
= tag
? tag
: TAG_PCI
;
1112 hd
->sub_device
.id
= MAKE_ID(tag
, ID_VALUE(hd
->sub_device
.id
));
1113 hd
->sub_vendor
.id
= MAKE_ID(tag
, ID_VALUE(hd
->sub_vendor
.id
));
1116 if(hd
->compat_device
.id
|| hd
->compat_vendor
.id
) {
1117 tag
= ID_TAG(hd
->compat_device
.id
);
1118 tag
= tag
? tag
: ID_TAG(hd
->compat_vendor
.id
);
1119 tag
= tag
? tag
: TAG_PCI
;
1120 hd
->compat_device
.id
= MAKE_ID(tag
, ID_VALUE(hd
->compat_device
.id
));
1121 hd
->compat_vendor
.id
= MAKE_ID(tag
, ID_VALUE(hd
->compat_vendor
.id
));
1124 if(hd
->status
.available
== status_unknown
) hd
->is
.manual
= 1;
1126 /* create some entries, if missing */
1128 if(!hd
->device
.id
&& !hd
->vendor
.id
&& !hd
->device
.name
) {
1129 hd
->device
.name
= new_str(hd
->model
);
1132 if(hd
->hw_class
&& !hd
->base_class
.id
) {
1133 switch(hd
->hw_class
) {
1135 hd
->base_class
.id
= bc_storage_device
;
1136 hd
->sub_class
.id
= sc_sdev_cdrom
;
1140 hd
->base_class
.id
= bc_mouse
;
1141 hd
->sub_class
.id
= sc_mou_other
;
1149 hddb_add_info(hd_data
, hd
);
1153 void hd2manual(hd_t
*hd
, hd_manual_t
*entry
)
1160 if(!hd
|| !entry
) return;
1162 entry
->unique_id
= new_str(hd
->unique_id
);
1163 entry
->parent_id
= new_str(hd
->parent_id
);
1164 entry
->child_ids
= hd_join(",", hd
->child_ids
);
1165 entry
->model
= new_str(hd
->model
);
1166 entry
->hw_class
= hd
->hw_class
;
1168 entry
->config_string
= new_str(hd
->config_string
);
1170 entry
->status
= hd
->status
;
1173 !entry
->status
.configured
&&
1174 !entry
->status
.available
&&
1175 !entry
->status
.needed
&&
1176 !entry
->status
.active
&&
1177 !entry
->status
.invalid
1179 entry
->status
.configured
= status_new
;
1180 entry
->status
.available
= hd
->module
== mod_manual
? status_unknown
: status_yes
;
1181 entry
->status
.needed
= status_no
;
1182 entry
->status
.active
= status_unknown
;
1188 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_broken
));
1189 str_printf(&s
, 0, "0x%x", hd
->broken
);
1190 add_str_list(&entry
->value
, s
);
1194 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_bus
));
1195 str_printf(&s
, 0, "0x%x", hd
->bus
.id
);
1196 add_str_list(&entry
->value
, s
);
1200 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_slot
));
1201 str_printf(&s
, 0, "0x%x", hd
->slot
);
1202 add_str_list(&entry
->value
, s
);
1206 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_func
));
1207 str_printf(&s
, 0, "0x%x", hd
->func
);
1208 add_str_list(&entry
->value
, s
);
1211 if(hd
->base_class
.id
) {
1212 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_base_class
));
1213 str_printf(&s
, 0, "0x%x", hd
->base_class
.id
);
1214 add_str_list(&entry
->value
, s
);
1217 if(hd
->sub_class
.id
) {
1218 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_sub_class
));
1219 str_printf(&s
, 0, "0x%x", hd
->sub_class
.id
);
1220 add_str_list(&entry
->value
, s
);
1223 if(hd
->prog_if
.id
) {
1224 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_prog_if
));
1225 str_printf(&s
, 0, "0x%x", hd
->prog_if
.id
);
1226 add_str_list(&entry
->value
, s
);
1229 if(hd
->device
.id
|| hd
->vendor
.id
) {
1230 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_vend
));
1231 add_str_list(&entry
->value
, vend_id2str(hd
->vendor
.id
));
1232 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_dev
));
1233 str_printf(&s
, 0, "%04x", ID_VALUE(hd
->device
.id
));
1234 add_str_list(&entry
->value
, s
);
1237 if(hd
->sub_device
.id
|| hd
->sub_vendor
.id
) {
1238 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_sub_vend
));
1239 add_str_list(&entry
->value
, vend_id2str(hd
->sub_vendor
.id
));
1240 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_sub_dev
));
1241 str_printf(&s
, 0, "%04x", ID_VALUE(hd
->sub_device
.id
));
1242 add_str_list(&entry
->value
, s
);
1245 if(hd
->revision
.id
) {
1246 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_rev
));
1247 str_printf(&s
, 0, "0x%x", hd
->revision
.id
);
1248 add_str_list(&entry
->value
, s
);
1251 if(hd
->compat_device
.id
|| hd
->compat_vendor
.id
) {
1252 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_compat_vend
));
1253 add_str_list(&entry
->value
, vend_id2str(hd
->compat_vendor
.id
));
1254 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_compat_dev
));
1255 str_printf(&s
, 0, "%04x", ID_VALUE(hd
->compat_device
.id
));
1256 add_str_list(&entry
->value
, s
);
1259 if(hd
->device
.name
) {
1260 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_dev_name
));
1261 add_str_list(&entry
->value
, hd
->device
.name
);
1264 if(hd
->vendor
.name
) {
1265 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_vend_name
));
1266 add_str_list(&entry
->value
, hd
->vendor
.name
);
1269 if(hd
->sub_device
.name
) {
1270 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_sub_dev_name
));
1271 add_str_list(&entry
->value
, hd
->sub_device
.name
);
1274 if(hd
->sub_vendor
.name
) {
1275 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_sub_vend_name
));
1276 add_str_list(&entry
->value
, hd
->sub_vendor
.name
);
1279 if(hd
->revision
.name
) {
1280 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_rev_name
));
1281 add_str_list(&entry
->value
, hd
->revision
.name
);
1285 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_serial
));
1286 add_str_list(&entry
->value
, hd
->serial
);
1289 if(hd
->unix_dev_name
) {
1290 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_unix_dev_name
));
1291 add_str_list(&entry
->value
, hd
->unix_dev_name
);
1294 if(hd
->unix_dev_name2
) {
1295 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_unix_dev_name2
));
1296 add_str_list(&entry
->value
, hd
->unix_dev_name2
);
1299 if(hd
->unix_dev_names
) {
1300 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_unix_dev_names
));
1302 s
= hd_join(" ", hd
->unix_dev_names
);
1303 add_str_list(&entry
->value
, s
);
1307 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_drivers
));
1309 s
= hd_join("|", hd
->drivers
);
1310 add_str_list(&entry
->value
, s
);
1314 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_sysfs_id
));
1315 add_str_list(&entry
->value
, hd
->sysfs_id
);
1318 if(hd
->sysfs_bus_id
) {
1319 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_sysfs_busid
));
1320 add_str_list(&entry
->value
, hd
->sysfs_bus_id
);
1323 if(hd
->sysfs_device_link
) {
1324 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_sysfs_link
));
1325 add_str_list(&entry
->value
, hd
->sysfs_device_link
);
1329 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_rom_id
));
1330 add_str_list(&entry
->value
, hd
->rom_id
);
1334 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_usb_guid
));
1335 add_str_list(&entry
->value
, hd
->usb_guid
);
1339 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_hotplug
));
1340 str_printf(&s
, 0, "%d", hd
->hotplug
);
1341 add_str_list(&entry
->value
, s
);
1345 for(u
= 0; u
< sizeof hd
->hw_class_list
/ sizeof *hd
->hw_class_list
; u
++) {
1346 str_printf(&s
, -1, "%02x", hd
->hw_class_list
[u
]);
1348 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_class_list
));
1349 add_str_list(&entry
->value
, s
);
1352 if(hd
->is
.agp
) u
|= 1 << 0;
1353 if(hd
->is
.isapnp
) u
|= 1 << 1;
1354 if(hd
->is
.softraiddisk
) u
|= 1 << 2;
1355 if(hd
->is
.zip
) u
|= 1 << 3;
1356 if(hd
->is
.cdr
) u
|= 1 << 4;
1357 if(hd
->is
.cdrw
) u
|= 1 << 5;
1358 if(hd
->is
.dvd
) u
|= 1 << 6;
1359 if(hd
->is
.dvdr
) u
|= 1 << 7;
1360 if(hd
->is
.dvdram
) u
|= 1 << 8;
1361 if(hd
->is
.pppoe
) u
|= 1 << 9;
1362 if(hd
->is
.wlan
) u
|= 1 << 10;
1365 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_features
));
1366 str_printf(&s
, 0, "0x%x", u
);
1367 add_str_list(&entry
->value
, s
);
1370 for(res
= hd
->res
; res
; res
= res
->next
) {
1372 switch(res
->any
.type
) {
1374 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_mem
));
1375 str_printf(&s
, 0, "0x%"PRIx64
"", res
->mem
.base
);
1376 add_str_list(&sl
, s
);
1377 str_printf(&s
, 0, "0x%"PRIx64
"", res
->mem
.range
);
1378 add_str_list(&sl
, s
);
1379 str_printf(&s
, 0, "%u", res
->mem
.enabled
);
1380 add_str_list(&sl
, s
);
1381 str_printf(&s
, 0, "%u", res
->mem
.access
);
1382 add_str_list(&sl
, s
);
1383 str_printf(&s
, 0, "%u", res
->mem
.prefetch
);
1384 add_str_list(&sl
, s
);
1388 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_phys_mem
));
1389 str_printf(&s
, 0, "0x%"PRIx64
"", res
->phys_mem
.range
);
1390 add_str_list(&sl
, s
);
1394 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_io
));
1395 str_printf(&s
, 0, "0x%"PRIx64
"", res
->io
.base
);
1396 add_str_list(&sl
, s
);
1397 str_printf(&s
, 0, "0x%"PRIx64
"", res
->io
.range
);
1398 add_str_list(&sl
, s
);
1399 str_printf(&s
, 0, "%u", res
->io
.enabled
);
1400 add_str_list(&sl
, s
);
1401 str_printf(&s
, 0, "%u", res
->io
.access
);
1402 add_str_list(&sl
, s
);
1406 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_irq
));
1407 str_printf(&s
, 0, "%u", res
->irq
.base
);
1408 add_str_list(&sl
, s
);
1409 str_printf(&s
, 0, "%u", res
->irq
.triggered
);
1410 add_str_list(&sl
, s
);
1411 str_printf(&s
, 0, "%u", res
->irq
.enabled
);
1412 add_str_list(&sl
, s
);
1416 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_dma
));
1417 str_printf(&s
, 0, "%u", res
->dma
.base
);
1418 add_str_list(&sl
, s
);
1419 str_printf(&s
, 0, "%u", res
->dma
.enabled
);
1420 add_str_list(&sl
, s
);
1424 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_size
));
1425 str_printf(&s
, 0, "%u", res
->size
.unit
);
1426 add_str_list(&sl
, s
);
1427 str_printf(&s
, 0, "%"PRIu64
, res
->size
.val1
);
1428 add_str_list(&sl
, s
);
1429 str_printf(&s
, 0, "%"PRIu64
, res
->size
.val2
);
1430 add_str_list(&sl
, s
);
1434 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_baud
));
1435 str_printf(&s
, 0, "%u", res
->baud
.speed
);
1436 add_str_list(&sl
, s
);
1437 str_printf(&s
, 0, "%u", res
->baud
.bits
);
1438 add_str_list(&sl
, s
);
1439 str_printf(&s
, 0, "%u", res
->baud
.stopbits
);
1440 add_str_list(&sl
, s
);
1441 str_printf(&s
, 0, "0x%02x", (unsigned) res
->baud
.parity
);
1442 add_str_list(&sl
, s
);
1443 str_printf(&s
, 0, "0x%02x", (unsigned) res
->baud
.handshake
);
1444 add_str_list(&sl
, s
);
1448 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_cache
));
1449 str_printf(&s
, 0, "%u", res
->cache
.size
);
1450 add_str_list(&sl
, s
);
1454 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_disk_geo
));
1455 str_printf(&s
, 0, "%u", res
->disk_geo
.cyls
);
1456 add_str_list(&sl
, s
);
1457 str_printf(&s
, 0, "%u", res
->disk_geo
.heads
);
1458 add_str_list(&sl
, s
);
1459 str_printf(&s
, 0, "%u", res
->disk_geo
.sectors
);
1460 add_str_list(&sl
, s
);
1461 str_printf(&s
, 0, "%u", res
->disk_geo
.geotype
);
1462 add_str_list(&sl
, s
);
1466 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_monitor
));
1467 str_printf(&s
, 0, "%u", res
->monitor
.width
);
1468 add_str_list(&sl
, s
);
1469 str_printf(&s
, 0, "%u", res
->monitor
.height
);
1470 add_str_list(&sl
, s
);
1471 str_printf(&s
, 0, "%u", res
->monitor
.vfreq
);
1472 add_str_list(&sl
, s
);
1473 str_printf(&s
, 0, "%u", res
->monitor
.interlaced
);
1474 add_str_list(&sl
, s
);
1477 case res_framebuffer
:
1478 add_str_list(&entry
->key
, key2value(hw_ids_hd_items
, hwdi_res_framebuffer
));
1479 str_printf(&s
, 0, "%u", res
->framebuffer
.width
);
1480 add_str_list(&sl
, s
);
1481 str_printf(&s
, 0, "%u", res
->framebuffer
.height
);
1482 add_str_list(&sl
, s
);
1483 str_printf(&s
, 0, "%u", res
->framebuffer
.bytes_p_line
);
1484 add_str_list(&sl
, s
);
1485 str_printf(&s
, 0, "%u", res
->framebuffer
.colorbits
);
1486 add_str_list(&sl
, s
);
1487 str_printf(&s
, 0, "%u", res
->framebuffer
.mode
);
1488 add_str_list(&sl
, s
);
1494 /* keep entry->key & entry->value symmetrical! */
1496 t
= hd_join(",", sl
);
1497 add_str_list(&entry
->value
, t
);
1507 hd_t
*hd_read_config(hd_data_t
*hd_data
, const char *id
)
1514 entry
= hd_manual_read_entry(hd_data
, id
);
1517 hd
= new_mem(sizeof *hd
);
1518 hd
->module
= hd_data
->module
;
1519 hd
->line
= __LINE__
;
1520 hd
->tag
.freeit
= 1; /* make it a 'stand alone' entry */
1521 manual2hd(hd_data
, entry
, hd
);
1522 hd_free_manual(entry
);
1529 int hd_write_config(hd_data_t
*hd_data
, hd_t
*hd
)
1534 if(!hd_report_this(hd_data
, hd
)) return 0;
1536 entry
= new_mem(sizeof *entry
);
1538 hd2manual(hd
, entry
);
1540 err
= entry
->unique_id
? hd_manual_write_entry(hd_data
, entry
) : 5;
1542 hd_free_manual(entry
);
1548 #endif /* LIBHD_TINY */