hdt: Adding Silent mode
[profile/ivi/syslinux.git] / com32 / hdt / hdt-common.c
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2009 Erwan Velu - All Rights Reserved
4  *
5  *   Permission is hereby granted, free of charge, to any person
6  *   obtaining a copy of this software and associated documentation
7  *   files (the "Software"), to deal in the Software without
8  *   restriction, including without limitation the rights to use,
9  *   copy, modify, merge, publish, distribute, sublicense, and/or
10  *   sell copies of the Software, and to permit persons to whom
11  *   the Software is furnished to do so, subject to the following
12  *   conditions:
13  *
14  *   The above copyright notice and this permission notice shall
15  *   be included in all copies or substantial portions of the Software.
16  *
17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  *   OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * -----------------------------------------------------------------------
27 */
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <getkey.h>
33 #include "syslinux/config.h"
34 #include "../lib/sys/vesa/vesa.h"
35 #include "hdt-common.h"
36 #include <disk/util.h>
37 #include <disk/mbrs.h>
38 #include <memory.h>
39
40 /* ISOlinux requires a 8.3 format */
41 void convert_isolinux_filename(char *filename, struct s_hardware *hardware)
42 {
43     /* Exit if we are not running ISOLINUX */
44     if (hardware->sv->filesystem != SYSLINUX_FS_ISOLINUX)
45         return;
46     /* Searching the dot */
47     char *dot = strchr(filename, '.');
48     /* Exiting if no dot exists in that string */
49     if (dot == NULL)
50         return;
51     /* Exiting if the extension is 3 char or less */
52     if (strlen(dot) <= 4)
53         return;
54
55     /* We have an extension bigger than .blah
56      * so we have to shorten it to 3*/
57     dot[4] = '\0';
58 }
59
60 void detect_parameters(const int argc, const char *argv[],
61                        struct s_hardware *hardware)
62 {
63     /* Quiet mode - make the output more quiet */
64     quiet = true;
65
66     /* Silent mode - make not output at all */
67     silent = false;
68
69     /* Vesa mode isn't set until we explictly call it */
70     vesamode = false;
71
72     /* Automode isn't the default*/
73     automode = false;
74
75     /* Menu mode is the default*/
76     menumode = true;
77
78     for (int i = 1; i < argc; i++) {
79         if (!strncmp(argv[i], "quiet", 5)) {
80             quiet = true;
81         } else if (!strncmp(argv[i], "silent", 6)) {
82             silent = true;
83         } else  if (!strncmp(argv[i], "verbose", 7)) {
84             quiet = false;
85         } else if (!strncmp(argv[i], "modules_pcimap=", 15)) {
86             strlcpy(hardware->modules_pcimap_path, argv[i] + 15,
87                     sizeof(hardware->modules_pcimap_path));
88             convert_isolinux_filename(hardware->modules_pcimap_path, hardware);
89         } else if (!strncmp(argv[i], "pciids=", 7)) {
90             strlcpy(hardware->pciids_path, argv[i] + 7,
91                     sizeof(hardware->pciids_path));
92             convert_isolinux_filename(hardware->pciids_path, hardware);
93         } else if (!strncmp(argv[i], "modules_alias=", 14)) {
94             strlcpy(hardware->modules_alias_path, argv[i] + 14,
95                     sizeof(hardware->modules_alias_path));
96             convert_isolinux_filename(hardware->modules_alias_path, hardware);
97         } else if (!strncmp(argv[i], "memtest=", 8)) {
98             strlcpy(hardware->memtest_label, argv[i] + 8,
99                     sizeof(hardware->memtest_label));
100             convert_isolinux_filename(hardware->memtest_label, hardware);
101         } else if (!strncmp(argv[i], "vesa", 4)) {
102             vesamode = true;
103             max_console_lines = MAX_VESA_CLI_LINES;
104             /* If the user defines a background image */
105             if (!strncmp(argv[i], "vesa=", 5)) {
106                 strlcpy(hardware->vesa_background, argv[i] + 5,
107                         sizeof(hardware->vesa_background));
108             }
109         } else if (!strncmp(argv[i], "novesa", 6)) {
110             vesamode = false;
111             max_console_lines = MAX_CLI_LINES;
112         } else if (!strncmp(argv[i], "nomenu", 6)) {
113             menumode = false;
114         } else if (!strncmp(argv[i], "dump_filename=", 14)) {
115             strlcpy(hardware->dump_filename, argv[i] + 14,
116                     sizeof(hardware->dump_filename));
117         } else if (!strncmp(argv[i], "dump_path=", 10)) {
118             strlcpy(hardware->dump_path, argv[i] + 10,
119                     sizeof(hardware->dump_path));
120         } else if (!strncmp(argv[i], "tftp_ip=", 8)) {
121             strlcpy(hardware->tftp_ip, argv[i] + 8,
122                     sizeof(hardware->tftp_ip));
123         } else if (!strncmp(argv[i], "postexec=", 9)) {
124             /* The postexec= parameter is separated in several argv[]
125              * as it can contains spaces.
126              * We use the AUTO_DELIMITER char to define the limits
127              * of this parameter.
128              * i.e postexec='linux memtest.bin'
129              */
130
131             char *argument = (char*)argv[i]+10;
132             /* Extracting the first parameter */
133             strcpy(hardware->postexec, argument);
134
135             /* While we can't find the other AUTO_DELIMITER, let's process the argv[] */
136             while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) {
137                 i++;
138                 argument = (char *)argv[i];
139                 strcat(hardware->postexec, " ");
140                 strcat(hardware->postexec, argument);
141             } 
142         
143              hardware->postexec[strlen(hardware->postexec) - 1] = 0;
144         } else if (!strncmp(argv[i], "auto=", 5)) {
145             /* The auto= parameter is separated in several argv[]
146              * as it can contains spaces.
147              * We use the AUTO_DELIMITER char to define the limits
148              * of this parameter.
149              * i.e auto='show dmi; show pci'
150              */
151
152             automode=true;
153             char *argument = (char*)argv[i]+6;
154             /* Extracting the first parameter */
155             strcpy(hardware->auto_label, argument);
156
157             /* While we can't find the other AUTO_DELIMITER, let's process the argv[] */
158             while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) {
159                 i++;
160                 argument = (char *)argv[i];
161                 strcat(hardware->auto_label, " ");
162                 strcat(hardware->auto_label, argument);
163             } 
164
165              hardware->auto_label[strlen(hardware->auto_label) - 1] = 0;
166         }
167     }
168 }
169
170 void detect_syslinux(struct s_hardware *hardware)
171 {
172     hardware->sv = syslinux_version();
173     switch (hardware->sv->filesystem) {
174     case SYSLINUX_FS_SYSLINUX:
175         strlcpy(hardware->syslinux_fs, "SYSlinux", 9);
176         break;
177     case SYSLINUX_FS_PXELINUX:
178         strlcpy(hardware->syslinux_fs, "PXElinux", 9);
179         break;
180     case SYSLINUX_FS_ISOLINUX:
181         strlcpy(hardware->syslinux_fs, "ISOlinux", 9);
182         break;
183     case SYSLINUX_FS_EXTLINUX:
184         strlcpy(hardware->syslinux_fs, "EXTlinux", 9);
185         break;
186     case SYSLINUX_FS_UNKNOWN:
187     default:
188         strlcpy(hardware->syslinux_fs, "Unknown Bootloader",
189                 sizeof hardware->syslinux_fs);
190         break;
191     }
192 }
193
194 void init_hardware(struct s_hardware *hardware)
195 {
196     hardware->pci_ids_return_code = 0;
197     hardware->modules_pcimap_return_code = 0;
198     hardware->modules_alias_return_code = 0;
199     hardware->cpu_detection = false;
200     hardware->pci_detection = false;
201     hardware->disk_detection = false;
202     hardware->disks_count = 0;
203     hardware->dmi_detection = false;
204     hardware->pxe_detection = false;
205     hardware->vesa_detection = false;
206     hardware->vpd_detection = false;
207     hardware->memory_detection = false;
208     hardware->acpi_detection = false;
209     hardware->nb_pci_devices = 0;
210     hardware->is_dmi_valid = false;
211     hardware->is_pxe_valid = false;
212     hardware->is_vpd_valid = false;
213     hardware->is_acpi_valid = false;
214     hardware->pci_domain = NULL;
215     hardware->detected_memory_size = 0;
216     hardware->physical_cpu_count =1; /* we have at least one cpu */
217
218     /* Cleaning structures */
219     memset(hardware->disk_info, 0, sizeof(hardware->disk_info));
220     memset(hardware->mbr_ids, 0, sizeof(hardware->mbr_ids));
221     memset(&hardware->dmi, 0, sizeof(s_dmi));
222     memset(&hardware->cpu, 0, sizeof(s_cpu));
223     memset(&hardware->pxe, 0, sizeof(struct s_pxe));
224     memset(&hardware->vesa, 0, sizeof(struct s_vesa));
225     memset(&hardware->vpd, 0, sizeof(s_vpd));
226     memset(&hardware->acpi, 0, sizeof(s_acpi));
227     memset(hardware->syslinux_fs, 0, sizeof hardware->syslinux_fs);
228     memset(hardware->pciids_path, 0, sizeof hardware->pciids_path);
229     memset(hardware->modules_pcimap_path, 0,
230            sizeof hardware->modules_pcimap_path);
231     memset(hardware->modules_alias_path, 0,
232            sizeof hardware->modules_alias_path);
233     memset(hardware->memtest_label, 0, sizeof hardware->memtest_label);
234     memset(hardware->auto_label, 0, sizeof hardware->auto_label);
235     memset(hardware->dump_path, 0, sizeof hardware->dump_path);
236     memset(hardware->dump_filename, 0, sizeof hardware->dump_filename);
237     memset(hardware->vesa_background, 0, sizeof hardware->vesa_background);
238     memset(hardware->tftp_ip, 0, sizeof hardware->tftp_ip);
239     memset(hardware->postexec, 0, sizeof hardware->postexec);
240     strcat(hardware->dump_path, "hdt");
241     strcat(hardware->dump_filename, "%{m}+%{p}+%{v}");
242     strcat(hardware->pciids_path, "pci.ids");
243     strcat(hardware->modules_pcimap_path, "modules.pcimap");
244     strcat(hardware->modules_alias_path, "modules.alias");
245     strcat(hardware->memtest_label, "memtest");
246     strlcpy(hardware->vesa_background, CLI_DEFAULT_BACKGROUND,
247             sizeof(hardware->vesa_background));
248 }
249
250 /*
251  * Detecting if a DMI table exist
252  * if yes, let's parse it
253  */
254 int detect_dmi(struct s_hardware *hardware)
255 {
256     if (hardware->dmi_detection == true)
257         return -1;
258     hardware->dmi_detection = true;
259     if (dmi_iterate(&hardware->dmi) == -ENODMITABLE) {
260         hardware->is_dmi_valid = false;
261         return -ENODMITABLE;
262     }
263
264     parse_dmitable(&hardware->dmi);
265     hardware->is_dmi_valid = true;
266     return 0;
267 }
268
269 /*
270  * Detecting ACPI
271  * if yes, let's parse it
272  */
273 int detect_acpi(struct s_hardware *hardware)
274 {
275     int retval;
276     if (hardware->acpi_detection == true)
277         return -1;
278     hardware->acpi_detection = true;
279     if ((retval=parse_acpi(&hardware->acpi)) != ACPI_FOUND) {
280         hardware->is_acpi_valid = false;
281         return retval;
282     }
283
284     hardware->is_acpi_valid = true;
285     return retval;
286 }
287
288 /**
289  * vpd_detection - populate the VPD structure
290  *
291  * VPD is a structure available on IBM machines.
292  * It is documented at:
293  *    http://www.pc.ibm.com/qtechinfo/MIGR-45120.html
294  * (XXX the page seems to be gone)
295  **/
296 int detect_vpd(struct s_hardware *hardware)
297 {
298     if (hardware->vpd_detection)
299         return -1;
300     else
301         hardware->vpd_detection = true;
302
303     if (vpd_decode(&hardware->vpd) == -ENOVPDTABLE) {
304         hardware->is_vpd_valid = false;
305         return -ENOVPDTABLE;
306     } else {
307         hardware->is_vpd_valid = true;
308         return 0;
309     }
310 }
311
312 /* Detection vesa stuff*/
313 int detect_vesa(struct s_hardware *hardware)
314 {
315     static com32sys_t rm;
316     struct vesa_general_info *gi;
317     struct vesa_mode_info *mi;
318     uint16_t mode, *mode_ptr;
319     char *oem_ptr;
320
321     if (hardware->vesa_detection == true)
322         return -1;
323
324     hardware->vesa_detection = true;
325     hardware->is_vesa_valid = false;
326
327     /* Allocate space in the bounce buffer for these structures */
328     gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
329     mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
330
331     gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
332     rm.eax.w[0] = 0x4F00;       /* Get SVGA general information */
333     rm.edi.w[0] = OFFS(gi);
334     rm.es = SEG(gi);
335     __intcall(0x10, &rm, &rm);
336
337     if (rm.eax.w[0] != 0x004F) {
338         return -1;
339     };
340
341     mode_ptr = GET_PTR(gi->video_mode_ptr);
342     oem_ptr = GET_PTR(gi->oem_vendor_name_ptr);
343     strlcpy(hardware->vesa.vendor, oem_ptr, sizeof(hardware->vesa.vendor));
344     oem_ptr = GET_PTR(gi->oem_product_name_ptr);
345     strlcpy(hardware->vesa.product, oem_ptr, sizeof(hardware->vesa.product));
346     oem_ptr = GET_PTR(gi->oem_product_rev_ptr);
347     strlcpy(hardware->vesa.product_revision, oem_ptr,
348             sizeof(hardware->vesa.product_revision));
349
350     hardware->vesa.major_version = (gi->version >> 8) & 0xff;
351     hardware->vesa.minor_version = gi->version & 0xff;
352     hardware->vesa.total_memory = gi->total_memory;
353     hardware->vesa.software_rev = gi->oem_software_rev;
354
355     hardware->vesa.vmi_count = 0;
356
357     while ((mode = *mode_ptr++) != 0xFFFF) {
358
359         rm.eax.w[0] = 0x4F01;   /* Get SVGA mode information */
360         rm.ecx.w[0] = mode;
361         rm.edi.w[0] = OFFS(mi);
362         rm.es = SEG(mi);
363         __intcall(0x10, &rm, &rm);
364
365         /* Must be a supported mode */
366         if (rm.eax.w[0] != 0x004f)
367             continue;
368
369         /* Saving detected values */
370         memcpy(&hardware->vesa.vmi[hardware->vesa.vmi_count].mi, mi,
371                sizeof(struct vesa_mode_info));
372         hardware->vesa.vmi[hardware->vesa.vmi_count].mode = mode;
373
374         hardware->vesa.vmi_count++;
375     }
376     hardware->is_vesa_valid = true;
377     return 0;
378 }
379
380 /* Try to detect disks from port 0x80 to 0xff */
381 void detect_disks(struct s_hardware *hardware)
382 {
383     int i = -1;
384     int err;
385
386     if (hardware->disk_detection)
387         return;
388
389     hardware->disk_detection = true;
390     for (int drive = 0x80; drive < 0xff; drive++) {
391         i++;
392         hardware->disk_info[i].disk = drive;
393         err = get_drive_parameters(&hardware->disk_info[i]);
394
395         /*
396          * Do not print output when drive does not exist or
397          * doesn't support int13 (cdrom, ...)
398          */
399         if (err == -1 || !hardware->disk_info[i].cbios)
400             continue;
401
402         /* Detect MBR */
403         hardware->mbr_ids[i] = get_mbr_id(&hardware->disk_info[i]);
404
405         hardware->disks_count++;
406     }
407 }
408
409 int detect_pxe(struct s_hardware *hardware)
410 {
411     void *dhcpdata;
412
413     size_t dhcplen;
414     t_PXENV_UNDI_GET_NIC_TYPE gnt;
415
416     if (hardware->pxe_detection == true)
417         return -1;
418     hardware->pxe_detection = true;
419     hardware->is_pxe_valid = false;
420     memset(&gnt, 0, sizeof(t_PXENV_UNDI_GET_NIC_TYPE));
421     memset(&hardware->pxe, 0, sizeof(struct s_pxe));
422
423     /* This code can only work if pxelinux is loaded */
424     if (hardware->sv->filesystem != SYSLINUX_FS_PXELINUX) {
425         return -1;
426     }
427 // printf("PXE: PXElinux detected\n");
428     if (!pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) {
429         pxe_bootp_t *dhcp = &hardware->pxe.dhcpdata;
430         memcpy(&hardware->pxe.dhcpdata, dhcpdata,
431                sizeof(hardware->pxe.dhcpdata));
432         snprintf(hardware->pxe.mac_addr, sizeof(hardware->pxe.mac_addr),
433                  "%02x:%02x:%02x:%02x:%02x:%02x", dhcp->CAddr[0],
434                  dhcp->CAddr[1], dhcp->CAddr[2], dhcp->CAddr[3],
435                  dhcp->CAddr[4], dhcp->CAddr[5]);
436
437         /* Saving our IP address in a easy format */
438         hardware->pxe.ip_addr[0] = hardware->pxe.dhcpdata.yip & 0xff;
439         hardware->pxe.ip_addr[1] = hardware->pxe.dhcpdata.yip >> 8 & 0xff;
440         hardware->pxe.ip_addr[2] = hardware->pxe.dhcpdata.yip >> 16 & 0xff;
441         hardware->pxe.ip_addr[3] = hardware->pxe.dhcpdata.yip >> 24 & 0xff;
442
443         if (!pxe_get_nic_type(&gnt)) {
444             switch (gnt.NicType) {
445             case PCI_NIC:
446                 hardware->is_pxe_valid = true;
447                 hardware->pxe.vendor_id = gnt.info.pci.Vendor_ID;
448                 hardware->pxe.product_id = gnt.info.pci.Dev_ID;
449                 hardware->pxe.subvendor_id = gnt.info.pci.SubVendor_ID;
450                 hardware->pxe.subproduct_id =
451                     gnt.info.pci.SubDevice_ID,
452                     hardware->pxe.rev = gnt.info.pci.Rev;
453                 hardware->pxe.pci_bus = (gnt.info.pci.BusDevFunc >> 8) & 0xff;
454                 hardware->pxe.pci_dev = (gnt.info.pci.BusDevFunc >> 3) & 0x7;
455                 hardware->pxe.pci_func = gnt.info.pci.BusDevFunc & 0x03;
456                 hardware->pxe.base_class = gnt.info.pci.Base_Class;
457                 hardware->pxe.sub_class = gnt.info.pci.Sub_Class;
458                 hardware->pxe.prog_intf = gnt.info.pci.Prog_Intf;
459                 hardware->pxe.nictype = gnt.NicType;
460                 break;
461             case CardBus_NIC:
462                 hardware->is_pxe_valid = true;
463                 hardware->pxe.vendor_id = gnt.info.cardbus.Vendor_ID;
464                 hardware->pxe.product_id = gnt.info.cardbus.Dev_ID;
465                 hardware->pxe.subvendor_id = gnt.info.cardbus.SubVendor_ID;
466                 hardware->pxe.subproduct_id =
467                     gnt.info.cardbus.SubDevice_ID,
468                     hardware->pxe.rev = gnt.info.cardbus.Rev;
469                 hardware->pxe.pci_bus =
470                     (gnt.info.cardbus.BusDevFunc >> 8) & 0xff;
471                 hardware->pxe.pci_dev =
472                     (gnt.info.cardbus.BusDevFunc >> 3) & 0x7;
473                 hardware->pxe.pci_func = gnt.info.cardbus.BusDevFunc & 0x03;
474                 hardware->pxe.base_class = gnt.info.cardbus.Base_Class;
475                 hardware->pxe.sub_class = gnt.info.cardbus.Sub_Class;
476                 hardware->pxe.prog_intf = gnt.info.cardbus.Prog_Intf;
477                 hardware->pxe.nictype = gnt.NicType;
478                 break;
479             case PnP_NIC:
480             default:
481                 return -1;
482                 break;
483             }
484
485             /* The firt pass try to find the exact pci device */
486             hardware->pxe.pci_device = NULL;
487             hardware->pxe.pci_device_pos = 0;
488             struct pci_device *pci_device;
489             int pci_number = 0;
490             for_each_pci_func(pci_device, hardware->pci_domain) {
491                 pci_number++;
492                 if ((__pci_bus == hardware->pxe.pci_bus) &&
493                     (__pci_slot == hardware->pxe.pci_dev) &&
494                     (__pci_func == hardware->pxe.pci_func) &&
495                     (pci_device->vendor == hardware->pxe.vendor_id)
496                     && (pci_device->product == hardware->pxe.product_id)) {
497                     hardware->pxe.pci_device = pci_device;
498                     hardware->pxe.pci_device_pos = pci_number;
499                     return 0;
500                 }
501             }
502
503             /* If we reach that part, it means the pci device pointed by
504              * the pxe rom wasn't found in our list.
505              * Let's try to find the device only by its pci ids.
506              * The pci device we'll match is maybe not exactly the good one
507              * as we can have the same pci id several times.
508              * At least, the pci id, the vendor/product will be right.
509              * That's clearly a workaround for some weird cases.
510              * This should happend very unlikely */
511             hardware->pxe.pci_device = NULL;
512             hardware->pxe.pci_device_pos = 0;
513             pci_number = 0;
514             for_each_pci_func(pci_device, hardware->pci_domain) {
515                 pci_number++;
516                 if ((pci_device->vendor == hardware->pxe.vendor_id)
517                     && (pci_device->product == hardware->pxe.product_id)) {
518                     hardware->pxe.pci_device = pci_device;
519                     hardware->pxe.pci_device_pos = pci_number;
520                     return 0;
521                 }
522             }
523
524         }
525     }
526     return 0;
527 }
528
529 void detect_memory(struct s_hardware *hardware) {
530      if (hardware->memory_detection == false) {
531              hardware->memory_detection = true;
532      hardware->detected_memory_size = detect_memsize();
533      }
534 }
535
536 void detect_pci(struct s_hardware *hardware)
537 {
538     if (hardware->pci_detection == true)
539         return;
540     hardware->pci_detection = true;
541
542     hardware->nb_pci_devices = 0;
543
544     /* Scanning to detect pci buses and devices */
545     hardware->pci_domain = pci_scan();
546
547     if (!hardware->pci_domain)
548         return;
549
550     /* Gathering addtional information */
551     gather_additional_pci_config(hardware->pci_domain);
552
553     struct pci_device *pci_device;
554     for_each_pci_func(pci_device, hardware->pci_domain) {
555         hardware->nb_pci_devices++;
556     }
557
558     if (!quiet) {
559         more_printf("PCI: %d devices detected\n", hardware->nb_pci_devices);
560         more_printf("PCI: Resolving names\n");
561     }
562     /* Assigning product & vendor name for each device */
563     hardware->pci_ids_return_code =
564         get_name_from_pci_ids(hardware->pci_domain, hardware->pciids_path);
565
566     if (!quiet)
567         more_printf("PCI: Resolving class names\n");
568     /* Assigning class name for each device */
569     hardware->pci_ids_return_code =
570         get_class_name_from_pci_ids(hardware->pci_domain,
571                                     hardware->pciids_path);
572
573     if (!quiet)
574         more_printf("PCI: Resolving module names\n");
575     /* Detecting which kernel module should match each device using modules.pcimap */
576     hardware->modules_pcimap_return_code =
577         get_module_name_from_pcimap(hardware->pci_domain,
578                                     hardware->modules_pcimap_path);
579
580     /* Detecting which kernel module should match each device using modules.alias */
581     hardware->modules_alias_return_code =
582         get_module_name_from_alias(hardware->pci_domain,
583                                    hardware->modules_alias_path);
584
585 }
586
587 void cpu_detect(struct s_hardware *hardware)
588 {
589     if (hardware->cpu_detection == true)
590         return;
591     detect_cpu(&hardware->cpu);
592     /* Old processors doesn't manage the identify commands 
593      * Let's use the dmi value in that case */
594     if (strlen(remove_spaces(hardware->cpu.model)) == 0)
595         strlcpy(hardware->cpu.model, hardware->dmi.processor.version,
596                 sizeof(hardware->cpu.model));
597
598     /* Some CPUs like to put many spaces in the model name
599      * That makes some weird display in console/menu
600      * Let's remove that mulitple spaces */
601     strlcpy(hardware->cpu.model,del_multi_spaces(hardware->cpu.model),sizeof(hardware->cpu.model));
602
603     if ((hardware->is_acpi_valid) && (hardware->acpi.madt.valid)) {
604         hardware->physical_cpu_count=hardware->acpi.madt.processor_local_apic_count / hardware->cpu.num_cores;
605     }
606     hardware->cpu_detection = true;
607 }
608
609 /*
610  * Find the last instance of a particular command line argument
611  * (which should include the final =; do not use for boolean arguments)
612  */
613 const char *find_argument(const char **argv, const char *argument)
614 {
615     int la = strlen(argument);
616     const char **arg;
617     const char *ptr = NULL;
618
619     for (arg = argv; *arg; arg++) {
620         if (!memcmp(*arg, argument, la))
621             ptr = *arg + la;
622     }
623
624     return ptr;
625 }
626
627 void clear_screen(void)
628 {
629     move_cursor_to_next_line();
630     disable_utf8();
631     set_g1_special_char();
632     set_us_g0_charset();
633     display_cursor(false);
634     clear_entire_screen();
635     gotoxy(0,0);
636     reset_more_printf();
637 }
638
639 /* remove begining spaces */
640 char *skip_spaces(char *p)
641 {
642     while (*p && *p <= ' ') {
643         p++;
644     }
645
646     return p;
647 }
648
649 /* remove trailing & begining spaces */
650 char *remove_spaces(char *p)
651 {
652     char *save = p;
653     p += strlen(p) - 1;
654     while (*p && *p <= ' ') {
655         *p = '\0';
656         p--;
657     }
658     p = save;
659     while (*p && *p <= ' ') {
660         p++;
661     }
662
663     return p;
664 }
665
666 /* remove trailing LF */
667 char *remove_trailing_lf(char *p)
668 {
669     char *save = p;
670     p += strlen(p) - 1;
671     while (*p && *p == 10) {
672         *p = '\0';
673         p--;
674     }
675     p = save;
676
677     return p;
678 }
679
680 /* delete multiple spaces, one is enough */
681 char *del_multi_spaces(char *p)
682 {
683     /* Saving the original pointer */
684     char *save = p;
685
686     /* Let's parse the complete string
687      * As we search for a double spacing
688      * we have to be sure then string is
689      * long enough to be processed */
690     while (*p && *(p + 1)) {
691
692         /* If we have two consecutive spaces */
693         if ((*p == ' ') && (*(p + 1) == ' ')) {
694
695             /* Let's copy to the current position
696              * the content from the second space*/
697             strlcpy(p, p + 1, strlen(p + 1));
698
699             /* Don't increment the pointer as we
700              * changed the content of the current position*/
701             continue;
702         }
703
704         /* Nothing as been found, let's see on the next char */
705         p++;
706     }
707     /* Returning the original pointer */
708     return save;
709 }
710
711 /* Reset the more_printf counter */
712 void reset_more_printf(void)
713 {
714     display_line_nb = 0;
715 }
716
717 int draw_background(const char *what)
718 {
719     if (!what)
720         return vesacon_default_background();
721     else
722         return vesacon_load_background(what);
723 }
724
725 void init_console(struct s_hardware *hardware)
726 {
727     if (vesamode) {
728         openconsole(&dev_rawcon_r, &dev_vesaserial_w);
729         draw_background(hardware->vesa_background);
730     } else
731         console_ansi_raw();
732 }
733
734 void detect_hardware(struct s_hardware *hardware)
735 {
736     if (!quiet)
737         more_printf("ACPI: Detecting\n");
738     detect_acpi(hardware);
739
740     if (!quiet)
741         more_printf("MEMORY: Detecting\n");
742     detect_memory(hardware);
743
744     if (!quiet)
745         more_printf("DMI: Detecting Table\n");
746     if (detect_dmi(hardware) == -ENODMITABLE) {
747         more_printf("DMI: ERROR ! Table not found ! \n");
748         more_printf("DMI: Many hardware components will not be detected ! \n");
749     } else {
750         if (!quiet)
751             more_printf("DMI: Table found ! (version %u.%u)\n",
752                         hardware->dmi.dmitable.major_version,
753                         hardware->dmi.dmitable.minor_version);
754     }
755
756     if (!quiet)
757         more_printf("CPU: Detecting\n");
758     cpu_detect(hardware);
759
760     if (!quiet)
761         more_printf("DISKS: Detecting\n");
762     detect_disks(hardware);
763
764     if (!quiet)
765         more_printf("VPD: Detecting\n");
766     detect_vpd(hardware);
767
768     detect_pci(hardware);
769     if (!quiet)
770         more_printf("PCI: %d Devices Found\n", hardware->nb_pci_devices);
771  
772    if (!quiet)
773         more_printf("PXE: Detecting\n");
774     detect_pxe(hardware);
775
776     if (!quiet)
777         more_printf("VESA: Detecting\n");
778     detect_vesa(hardware);
779 }
780