hdt: Improving PCI menu display
[profile/ivi/syslinux.git] / sample / hdt.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 /*
30  * hdt.c
31  *
32  * An Hardware Detection Tool
33  */
34
35 #include <string.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <console.h>
39 #include "com32io.h"
40 #include "menu.h"
41 #include "help.h"
42 #include "passwords.h"
43 #include "cpuid.h"
44 #include "dmi/dmi.h"
45 #include "sys/pci.h"
46
47 #define INFLINE 22
48 #define PWDLINE 3
49 #define PWDPROMPT 21
50 #define PWDCOLUMN 60
51 #define PWDATTR 0x74
52 #define EDITPROMPT 21
53
54 #define WITH_PCI 1
55 #define WITH_MENU_DISPLAY 1
56
57 #define SECTOR 512              /* bytes/sector */
58
59 enum {
60         ATA_ID_FW_REV           = 23,
61         ATA_ID_PROD             = 27,
62         ATA_ID_FW_REV_LEN       = 8,
63         ATA_ID_PROD_LEN         = 40,
64 };
65
66 unsigned char MAIN_MENU, CPU_MENU, MOBO_MENU, CHASSIS_MENU, BIOS_MENU, SYSTEM_MENU, PCI_MENU, KERNEL_MENU;
67 unsigned char MEMORY_MENU,  MEMORY_SUBMENU[32], DISK_MENU, DISK_SUBMENU[32], PCI_SUBMENU[255],BATTERY_MENU;
68 int nb_sub_disk_menu=0;
69 bool is_dmi_valid=false;
70
71 #define ATTR_PACKED __attribute__((packed))
72
73 struct ata_identify_device {
74   unsigned short words000_009[10];
75   unsigned char  serial_no[20];
76   unsigned short words020_022[3];
77   unsigned char  fw_rev[8];
78   unsigned char  model[40];
79   unsigned short words047_079[33];
80   unsigned short major_rev_num;
81   unsigned short minor_rev_num;
82   unsigned short command_set_1;
83   unsigned short command_set_2;
84   unsigned short command_set_extension;
85   unsigned short cfs_enable_1;
86   unsigned short word086;
87   unsigned short csf_default;
88   unsigned short words088_255[168];
89 } ATTR_PACKED;
90
91 struct diskinfo {
92   int disk;
93   int ebios;                    /* EBIOS supported on this disk */
94   int cbios;                    /* CHS geometry is valid */
95   int heads;
96   int sectors_per_track;
97   int sectors;
98   int cylinders;
99   char edd_version[4];
100   struct ata_identify_device aid; /* IDENTIFY xxx DEVICE data */
101   char host_bus_type[5];
102   char interface_type[9];
103   char interface_port;
104 } ATTR_PACKED;
105
106 /*
107  * Get a disk block and return a malloc'd buffer.
108  * Uses the disk number and information from disk_info.
109  */
110 struct ebios_dapa {
111   uint16_t len;
112   uint16_t count;
113   uint16_t off;
114   uint16_t seg;
115   uint64_t lba;
116 };
117
118
119
120 // BYTE=8
121 // WORD=16
122 // DWORD=32
123 // QWORD=64
124 struct device_parameter {
125  uint16_t len;
126  uint16_t info;
127  uint32_t cylinders;
128  uint32_t heads;
129  uint32_t sectors_per_track;
130  uint64_t sectors;
131  uint16_t bytes_per_sector;
132  uint32_t dpte_pointer;
133  uint16_t device_path_information;
134  uint8_t  device_path_lenght;
135  uint8_t  device_path_reserved;
136  uint16_t device_path_reserved_2;
137  uint8_t  host_bus_type[4];
138  uint8_t  interface_type[8];
139  uint64_t interace_path;
140  uint64_t device_path[2];
141  uint8_t  reserved;
142  uint8_t  cheksum;
143 } ATTR_PACKED;
144
145 /**
146  *      ata_id_string - Convert IDENTIFY DEVICE page into string
147  *      @id: IDENTIFY DEVICE results we will examine
148  *      @s: string into which data is output
149  *      @ofs: offset into identify device page
150  *      @len: length of string to return. must be an even number.
151  *
152  *      The strings in the IDENTIFY DEVICE page are broken up into
153  *      16-bit chunks.  Run through the string, and output each
154  *      8-bit chunk linearly, regardless of platform.
155  *
156  *      LOCKING:
157  *      caller.
158  */
159
160 void ata_id_string(const uint16_t *id, unsigned char *s,
161                    unsigned int ofs, unsigned int len)
162 {
163         unsigned int c;
164
165         while (len > 0) {
166                 c = id[ofs] >> 8;
167                 *s = c;
168                 s++;
169
170                 c = id[ofs] & 0xff;
171                 *s = c;
172                 s++;
173
174                 ofs++;
175                 len -= 2;
176         }
177 }
178
179 /**
180  *      ata_id_c_string - Convert IDENTIFY DEVICE page into C string
181  *      @id: IDENTIFY DEVICE results we will examine
182  *      @s: string into which data is output
183  *      @ofs: offset into identify device page
184  *      @len: length of string to return. must be an odd number.
185  *
186  *      This function is identical to ata_id_string except that it
187  *      trims trailing spaces and terminates the resulting string with
188  *      null.  @len must be actual maximum length (even number) + 1.
189  *
190  *      LOCKING:
191  *      caller.
192  */
193 void ata_id_c_string(const uint16_t *id, unsigned char *s,
194                      unsigned int ofs, unsigned int len)
195 {
196         unsigned char *p;
197
198         //WARN_ON(!(len & 1));
199
200         ata_id_string(id, s, ofs, len - 1);
201
202         p = s + strnlen(s, len - 1);
203         while (p > s && p[-1] == ' ')
204                 p--;
205         *p = '\0';
206 }
207
208
209 static void printregs(const com32sys_t *r)
210 {
211   printf("eflags = %08x  ds = %04x  es = %04x  fs = %04x  gs = %04x\n"
212          "eax = %08x  ebx = %08x  ecx = %08x  edx = %08x\n"
213          "ebp = %08x  esi = %08x  edi = %08x  esp = %08x\n",
214          r->eflags.l, r->ds, r->es, r->fs, r->gs,
215          r->eax.l, r->ebx.l, r->ecx.l, r->edx.l,
216          r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l);
217 }
218
219
220 /*
221  * Call int 13h, but with retry on failure.  Especially floppies need this.
222  */
223 static int int13_retry(const com32sys_t *inreg, com32sys_t *outreg)
224 {
225   int retry = 6;                /* Number of retries */
226   com32sys_t tmpregs;
227
228   if ( !outreg ) outreg = &tmpregs;
229
230   while ( retry-- ) {
231     __intcall(0x13, inreg, outreg);
232     if ( !(outreg->eflags.l & EFLAGS_CF) )
233       return 0;                 /* CF=0, OK */
234   }
235
236   return -1;                    /* Error */
237 }
238
239 TIMEOUTCODE ontimeout()
240 {
241          // beep();
242             return CODE_WAIT;
243 }
244
245 void keys_handler(t_menusystem *ms, t_menuitem *mi,unsigned int scancode)
246 {
247    char nc;
248
249    if ((scancode >> 8) == F1) { // If scancode of F1
250       runhelpsystem(mi->helpid);
251    }
252    // If user hit TAB, and item is an "executable" item
253    // and user has privileges to edit it, edit it in place.
254    if (((scancode & 0xFF) == 0x09) && (mi->action == OPT_RUN)) {
255 //(isallowed(username,"editcmd") || isallowed(username,"root"))) {
256      nc = getnumcols();
257      // User typed TAB and has permissions to edit command line
258      gotoxy(EDITPROMPT,1,ms->menupage);
259      csprint("Command line:",0x07);
260      editstring(mi->data,ACTIONLEN);
261      gotoxy(EDITPROMPT,1,ms->menupage);
262      cprint(' ',0x07,nc-1,ms->menupage);
263    }
264 }
265
266
267 static int get_disk_params(int disk, struct diskinfo *disk_info)
268 {
269   static com32sys_t getparm, parm, getebios, ebios, inreg,outreg;
270   //char buffer[255];
271   struct device_parameter dp;
272 //  struct ata_identify_device aid;
273
274   disk_info[disk].disk = disk;
275   disk_info[disk].ebios = disk_info[disk].cbios = 0;
276
277    memset(&getebios, 0, sizeof (com32sys_t));
278    memset(&ebios, 0, sizeof (com32sys_t));
279   /* Get EBIOS support */
280   getebios.eax.w[0] = 0x4100;
281   getebios.ebx.w[0] = 0x55aa;
282   getebios.edx.b[0] = disk;
283   getebios.eflags.b[0] = 0x3;   /* CF set */
284
285   __intcall(0x13, &getebios, &ebios);
286
287   if ( !(ebios.eflags.l & EFLAGS_CF) &&
288        ebios.ebx.w[0] == 0xaa55 &&
289        (ebios.ecx.b[0] & 1) ) {
290     disk_info[disk].ebios = 1;
291     switch(ebios.eax.b[1]) {
292             case 32:  strcpy(disk_info[disk].edd_version,"1.0"); break;
293             case 33:  strcpy(disk_info[disk].edd_version,"1.1"); break;
294             case 48:  strcpy(disk_info[disk].edd_version,"3.0"); break;
295             default:  strcpy(disk_info[disk].edd_version,"0"); break;
296     }
297   }
298
299   /* Get disk parameters -- really only useful for
300      hard disks, but if we have a partitioned floppy
301      it's actually our best chance... */
302   memset(&getparm, 0, sizeof (com32sys_t));
303   memset(&parm, 0, sizeof (com32sys_t));
304   getparm.eax.b[1] = 0x08;
305   getparm.edx.b[0] = disk;
306
307   __intcall(0x13, &getparm, &parm);
308
309   if ( parm.eflags.l & EFLAGS_CF )
310     return disk_info[disk].ebios ? 0 : -1;
311
312   disk_info[disk].heads = parm.edx.b[1]+1;
313   disk_info[disk].sectors_per_track = parm.ecx.b[0] & 0x3f;
314   if ( disk_info[disk].sectors_per_track == 0 ) {
315     disk_info[disk].sectors_per_track = 1;
316   } else {
317    disk_info[disk].cbios = 1;        /* Valid geometry */
318      }
319
320    memset(&dp, 0, sizeof(struct device_parameter));
321    //FIXME: memset to 0 make it fails
322 //   memset(__com32.cs_bounce, 0, sizeof(struct device_parameter));
323    memset(&inreg, 0, sizeof(com32sys_t));
324
325    inreg.esi.w[0] = OFFS(__com32.cs_bounce);
326    inreg.ds       = SEG(__com32.cs_bounce);
327    inreg.eax.w[0] = 0x4800;
328    inreg.edx.b[0] = disk;
329
330    __intcall(0x13, &inreg, &outreg);
331
332   memcpy(&dp, __com32.cs_bounce, sizeof (struct device_parameter));
333
334    if ( outreg.eflags.l & EFLAGS_CF) {
335            printf("Disk 0x%X doesn't supports EDD 3.0\n",disk);
336 //         return -1;
337   }
338
339    sprintf(disk_info[disk].host_bus_type,"%c%c%c%c",dp.host_bus_type[0],dp.host_bus_type[1],dp.host_bus_type[2],dp.host_bus_type[3]);
340    sprintf(disk_info[disk].interface_type,"%c%c%c%c%c%c%c%c",dp.interface_type[0],dp.interface_type[1],dp.interface_type[2],dp.interface_type[3],dp.interface_type[4],dp.interface_type[5],dp.interface_type[6],dp.interface_type[7]);
341    disk_info[disk].sectors=dp.sectors;
342    disk_info[disk].cylinders=dp.cylinders;
343    //FIXME: we have to find a way to grab the model & fw
344    sprintf(disk_info[disk].aid.model,"0x%X",disk);
345    sprintf(disk_info[disk].aid.fw_rev,"%s","N/A");
346    sprintf(disk_info[disk].aid.serial_no,"%s","N/A");
347
348   /*
349    memset(__com32.cs_bounce, 0, sizeof(struct device_parameter));
350    memset(&aid, 0, sizeof(struct ata_identify_device));
351    memset(&inreg, 0, sizeof inreg);
352    inreg.ebx.w[0] = OFFS(__com32.cs_bounce+1024);
353    inreg.es       = SEG(__com32.cs_bounce+1024);
354    inreg.eax.w[0] = 0x2500;
355    inreg.edx.b[0] = disk;
356
357   __intcall(0x13,&inreg, &outreg);
358
359   memcpy(&aid, __com32.cs_bounce, sizeof (struct ata_identify_device));
360
361   if ( outreg.eflags.l & EFLAGS_CF) {
362            printf("Disk 0x%X: Failed to Identify Device\n",disk);
363            //FIXME
364            return 0;
365   }
366
367 //   ata_id_c_string(aid, disk_info[disk].fwrev, ATA_ID_FW_REV, sizeof(disk_info[disk].fwrev));
368 //   ata_id_c_string(aid, disk_info[disk].model, ATA_ID_PROD,  sizeof(disk_info[disk].model));
369
370   char buff[sizeof(struct ata_identify_device)];
371   memcpy(buff,&aid, sizeof (struct ata_identify_device));
372   for (int j=0;j<sizeof(struct ata_identify_device);j++)
373      printf ("model=|%c|\n",buff[j]);
374     printf ("Disk 0x%X : %s %s %s\n",disk, aid.model, aid.fw_rev,aid.serial_no);
375 */
376 return 0;
377 }
378
379 int detect_dmi(s_dmi *dmi) {
380   if ( ! dmi_iterate() ) {
381              printf("No DMI Structure found\n");
382              return -1;
383   }
384
385   parse_dmitable(dmi);
386  return 0;
387 }
388
389 void detect_disks(struct diskinfo *disk_info) {
390  for (int drive = 0x80; drive <= 0xff; drive++) {
391     if (get_disk_params(drive,disk_info))
392           continue;
393     struct diskinfo d=disk_info[drive];
394     printf("  DISK 0x%X: %s %s: sectors=%d, sector/track=%d head=%d : EDD=%s\n",drive,d.host_bus_type,d.interface_type, d.sectors, d.sectors_per_track,d.heads,d.edd_version);
395  }
396 }
397
398
399 void compute_pci_device(unsigned char *menu,struct pci_device *pci_device,int pci_bus, int pci_slot, int pci_func) {
400   char buffer[MENULEN];
401   char infobar[STATLEN];
402
403   *menu = add_menu(" PCI Devices ",-1);
404    set_menu_pos(7,17);
405    add_item(buffer,"Class Name",OPT_INACTIVE,NULL,0);
406    snprintf(buffer,59,"Class    :%s",pci_device->dev_info->class_name);
407    add_item(buffer,"Class Name",OPT_INACTIVE,NULL,0);
408    snprintf(buffer,59,"Location: %02x:%02x.%01x",pci_bus, pci_slot, pci_func);
409    add_item(buffer,"Location on the PCI Bus",OPT_INACTIVE,NULL,0);
410    snprintf(buffer,59,"PCI ID  : %04x:%04x[%04x:%04x]",pci_device->vendor, pci_device->product,pci_device->sub_vendor, pci_device->sub_product);
411    add_item(buffer,"PCI ID: vendor:product[sub_vendor:sub_product]",OPT_INACTIVE,NULL,0);
412    snprintf(buffer,59,"Module  : %s",pci_device->dev_info->linux_kernel_module);
413    add_item(buffer,"Related kernel module",OPT_INACTIVE,NULL,0);
414
415 }
416
417 void compute_PCI(unsigned char *menu, struct pci_domain **pci_domain) {
418  char buffer[MENULEN];
419  char menuname[255][MENULEN];
420  char infobar[255][STATLEN];
421  int i=0;
422  struct pci_device *pci_device;
423
424  for_each_pci_func(pci_device, *pci_domain) {
425    compute_pci_device(&PCI_SUBMENU[i],pci_device,__pci_bus,__pci_slot,__pci_func);
426    snprintf(menuname[i],59,"%s|%s",pci_device->dev_info->vendor_name,pci_device->dev_info->product_name);
427    snprintf(infobar[i], STATLEN,"%02x:%02x.%01x # %s # ID:%04x:%04x[%04x:%04x] # Kmod:%s\n",
428                __pci_bus, __pci_slot, __pci_func,pci_device->dev_info->class_name,
429                pci_device->vendor, pci_device->product,
430                pci_device->sub_vendor, pci_device->sub_product,pci_device->dev_info->linux_kernel_module);
431    i++;
432  }
433
434 *menu = add_menu(" PCI Devices ",-1);
435
436 for (int j=0;j<i;j++) {
437 //  sprintf(buffer," PCI <%d> ",j);
438   add_item(menuname[j],infobar[j],OPT_SUBMENU,NULL,PCI_SUBMENU[j]);
439 }
440 }
441
442 void compute_KERNEL(unsigned char *menu,struct pci_domain **pci_domain) {
443   char buffer[MENULEN];
444   char infobar[MENULEN];
445
446   *menu = add_menu(" Kernel Modules ",-1);
447   struct pci_device *pci_device;
448   for_each_pci_func(pci_device, *pci_domain) {
449         if (strcmp("unknown",pci_device->dev_info->linux_kernel_module)!=0) {
450          snprintf(buffer,MENULEN,"%s",pci_device->dev_info->linux_kernel_module);
451          snprintf(infobar, MENULEN,"%04x:%04x %s : %s\n",
452                pci_device->vendor, pci_device->product,
453                 pci_device->dev_info->vendor_name,
454                 pci_device->dev_info->product_name);
455
456          add_item(buffer,infobar,OPT_INACTIVE,NULL,0);
457         }
458   }
459 }
460
461 void compute_battery(unsigned char *menu, s_dmi *dmi) {
462   char buffer[MENULEN];
463   *menu = add_menu(" Battery ",-1);
464
465   snprintf(buffer,MENULEN,"Vendor          : %s",dmi->battery.manufacturer);
466   add_item(buffer,"Vendor",OPT_INACTIVE,NULL,0);
467   snprintf(buffer,MENULEN,"Manufacture Date: %s",dmi->battery.manufacture_date);
468   add_item(buffer,"Manufacture Date",OPT_INACTIVE,NULL,0);
469   snprintf(buffer,MENULEN,"Serial          : %s",dmi->battery.serial);
470   add_item(buffer,"Serial",OPT_INACTIVE,NULL,0);
471   snprintf(buffer,MENULEN,"Name            : %s",dmi->battery.name);
472   add_item(buffer,"Name",OPT_INACTIVE,NULL,0);
473   snprintf(buffer,MENULEN,"Chemistry       : %s",dmi->battery.chemistry);
474   add_item(buffer,"Chemistry",OPT_INACTIVE,NULL,0);
475   snprintf(buffer,MENULEN,"Design Capacity : %s",dmi->battery.design_capacity);
476   add_item(buffer,"Design Capacity",OPT_INACTIVE,NULL,0);
477   snprintf(buffer,MENULEN,"Design Voltage  : %s",dmi->battery.design_voltage);
478   add_item(buffer,"Design Voltage",OPT_INACTIVE,NULL,0);
479   snprintf(buffer,MENULEN,"SBDS            : %s",dmi->battery.sbds);
480   add_item(buffer,"SBDS",OPT_INACTIVE,NULL,0);
481   snprintf(buffer,MENULEN,"SBDS Manuf. Date: %s",dmi->battery.sbds_manufacture_date);
482   add_item(buffer,"SBDS Manufacture Date",OPT_INACTIVE,NULL,0);
483   snprintf(buffer,MENULEN,"SBDS Chemistry  : %s",dmi->battery.sbds_chemistry);
484   add_item(buffer,"SBDS Chemistry",OPT_INACTIVE,NULL,0);
485   snprintf(buffer,MENULEN,"Maximum Error   : %s",dmi->battery.maximum_error);
486   add_item(buffer,"Maximum Error (%)",OPT_INACTIVE,NULL,0);
487   snprintf(buffer,MENULEN,"OEM Info        : %s",dmi->battery.oem_info);
488   add_item(buffer,"OEM Info",OPT_INACTIVE,NULL,0);
489 }
490
491
492 void compute_disk_module(unsigned char *menu, struct diskinfo *disk_info, int disk_number) {
493   char buffer[MENULEN];
494   struct diskinfo d = disk_info[disk_number];
495   if (strlen(d.aid.model)<=0) return;
496
497    sprintf(buffer," Disk <%d> ",nb_sub_disk_menu);
498   *menu = add_menu(buffer,-1);
499
500   sprintf(buffer,"Model        : %s",d.aid.model);
501   add_item(buffer,"Model",OPT_INACTIVE,NULL,0);
502
503   // Compute device size
504   char previous_unit[3],unit[3]; //GB
505   int previous_size,size = d.sectors/2; // Converting to bytes
506   strcpy(unit,"KB");
507   strcpy(previous_unit,unit);
508   previous_size=size;
509   if (size>1000) {
510      size=size/1000;
511      strcpy(unit,"MB");
512      if (size>1000) {
513        previous_size=size;
514        size=size/1000;
515        strcpy(previous_unit,unit);
516        strcpy(unit,"GB");
517        if (size>1000) {
518         previous_size=size;
519         size=size/1000;
520         strcpy(previous_unit,unit);
521         strcpy(unit,"TB");
522        }
523      }
524   }
525
526   sprintf(buffer,"Size         : %d %s (%d %s)",size,unit,previous_size,previous_unit);
527   add_item(buffer,"Size",OPT_INACTIVE,NULL,0);
528
529   sprintf(buffer,"Firmware Rev.: %s",d.aid.fw_rev);
530   add_item(buffer,"Firmware Revision",OPT_INACTIVE,NULL,0);
531
532   sprintf(buffer,"Serial Number: %s",d.aid.serial_no);
533   add_item(buffer,"Serial Number",OPT_INACTIVE,NULL,0);
534
535   sprintf(buffer,"Interface    : %s",d.interface_type);
536   add_item(buffer,"Interface Type",OPT_INACTIVE,NULL,0);
537
538   sprintf(buffer,"Host Bus     : %s",d.host_bus_type);
539   add_item(buffer,"Host Bus Type",OPT_INACTIVE,NULL,0);
540
541   sprintf(buffer,"Sectors      : %d",d.sectors);
542   add_item(buffer,"Sectors",OPT_INACTIVE,NULL,0);
543
544   sprintf(buffer,"Heads        : %d",d.heads);
545   add_item(buffer,"Heads",OPT_INACTIVE,NULL,0);
546
547   sprintf(buffer,"Cylinders    : %d",d.cylinders);
548   add_item(buffer,"Cylinders",OPT_INACTIVE,NULL,0);
549
550   sprintf(buffer,"Sectors/Track: %d",d.sectors_per_track);
551   add_item(buffer,"Sectors per Track",OPT_INACTIVE,NULL,0);
552
553   sprintf(buffer,"Port         : 0x%X",disk_number);
554   add_item(buffer,"Port",OPT_INACTIVE,NULL,0);
555
556   sprintf(buffer,"EDD Version  : %s",d.edd_version);
557   add_item(buffer,"EDD Version",OPT_INACTIVE,NULL,0);
558
559   nb_sub_disk_menu++;
560 }
561
562 void compute_memory_module(unsigned char *menu, s_dmi *dmi, int slot_number) {
563   int i=slot_number;
564   char buffer[MENULEN];
565   sprintf(buffer," Module <%d> ",i);
566   *menu = add_menu(buffer,-1);
567
568   sprintf(buffer,"Form Factor  : %s",dmi->memory[i].form_factor);
569   add_item(buffer,"Form Factor",OPT_INACTIVE,NULL,0);
570
571   sprintf(buffer,"Type         : %s",dmi->memory[i].type);
572   add_item(buffer,"Memory Type",OPT_INACTIVE,NULL,0);
573
574   sprintf(buffer,"Type Details : %s",dmi->memory[i].type_detail);
575   add_item(buffer,"Memory Ty^e Details",OPT_INACTIVE,NULL,0);
576
577   sprintf(buffer,"Speed        : %s",dmi->memory[i].speed);
578   add_item(buffer,"Speed (MHz)",OPT_INACTIVE,NULL,0);
579
580   sprintf(buffer,"Size         : %s",dmi->memory[i].size);
581   add_item(buffer,"Size",OPT_INACTIVE,NULL,0);
582
583   sprintf(buffer,"Device Set   : %s",dmi->memory[i].device_set);
584   add_item(buffer,"Device Set",OPT_INACTIVE,NULL,0);
585
586   sprintf(buffer,"Device Loc.  : %s",dmi->memory[i].device_locator);
587   add_item(buffer,"Device Location",OPT_INACTIVE,NULL,0);
588
589   sprintf(buffer,"Bank Locator : %s",dmi->memory[i].bank_locator);
590   add_item(buffer,"Bank Location",OPT_INACTIVE,NULL,0);
591
592   sprintf(buffer,"Total Width  : %s",dmi->memory[i].total_width);
593   add_item(buffer,"Total bit Width",OPT_INACTIVE,NULL,0);
594
595   sprintf(buffer,"Data Width   : %s",dmi->memory[i].data_width);
596   add_item(buffer,"Data bit Width",OPT_INACTIVE,NULL,0);
597
598   sprintf(buffer,"Error        : %s",dmi->memory[i].error);
599   add_item(buffer,"Error",OPT_INACTIVE,NULL,0);
600
601   sprintf(buffer,"Vendor       : %s",dmi->memory[i].manufacturer);
602   add_item(buffer,"Vendor",OPT_INACTIVE,NULL,0);
603
604   sprintf(buffer,"Serial       : %s",dmi->memory[i].serial);
605   add_item(buffer,"Serial Number",OPT_INACTIVE,NULL,0);
606
607   sprintf(buffer,"Asset Tag    : %s",dmi->memory[i].asset_tag);
608   add_item(buffer,"Asset Tag",OPT_INACTIVE,NULL,0);
609
610   sprintf(buffer,"Part Number  : %s",dmi->memory[i].part_number);
611   add_item(buffer,"Part Number",OPT_INACTIVE,NULL,0);
612
613 }
614
615 void compute_motherboard(unsigned char *menu,s_dmi *dmi) {
616   char buffer[MENULEN];
617   *menu = add_menu(" Motherboard ",-1);
618   snprintf(buffer,MENULEN,"Vendor    : %s",dmi->base_board.manufacturer);
619   add_item(buffer,"Vendor",OPT_INACTIVE,NULL,0);
620   snprintf(buffer,MENULEN,"Product   : %s",dmi->base_board.product_name);
621   add_item(buffer,"Product Name",OPT_INACTIVE,NULL,0);
622   snprintf(buffer,MENULEN,"Version   : %s",dmi->base_board.version);
623   add_item(buffer,"Version",OPT_INACTIVE,NULL,0);
624   snprintf(buffer,MENULEN,"Serial    : %s",dmi->base_board.serial);
625   add_item(buffer,"Serial Number",OPT_INACTIVE,NULL,0);
626   snprintf(buffer,MENULEN,"Asset Tag : %s",dmi->base_board.asset_tag);
627   add_item(buffer,"Asset Tag",OPT_INACTIVE,NULL,0);
628   snprintf(buffer,MENULEN,"Location  : %s",dmi->base_board.location);
629   add_item(buffer,"Location",OPT_INACTIVE,NULL,0);
630   snprintf(buffer,MENULEN,"Type      : %s",dmi->base_board.type);
631   add_item(buffer,"Type",OPT_INACTIVE,NULL,0);
632 }
633
634 void compute_system(unsigned char *menu,s_dmi *dmi) {
635   char buffer[MENULEN];
636   *menu = add_menu(" System ",-1);
637   snprintf(buffer,MENULEN,"Vendor    : %s",dmi->system.manufacturer);
638   add_item(buffer,"Vendor",OPT_INACTIVE,NULL,0);
639   snprintf(buffer,MENULEN,"Product   : %s",dmi->system.product_name);
640   add_item(buffer,"Product Name",OPT_INACTIVE,NULL,0);
641   snprintf(buffer,MENULEN,"Version   : %s",dmi->system.version);
642   add_item(buffer,"Version",OPT_INACTIVE,NULL,0);
643   snprintf(buffer,MENULEN,"Serial    : %s",dmi->system.serial);
644   add_item(buffer,"Serial Number",OPT_INACTIVE,NULL,0);
645   snprintf(buffer,MENULEN,"UUID      : %s",dmi->system.uuid);
646   add_item(buffer,"UUID",OPT_INACTIVE,NULL,0);
647   snprintf(buffer,MENULEN,"Wakeup    : %s",dmi->system.wakeup_type);
648   add_item(buffer,"Wakeup Type",OPT_INACTIVE,NULL,0);
649   snprintf(buffer,MENULEN,"SKU Number: %s",dmi->system.sku_number);
650   add_item(buffer,"SKU Number",OPT_INACTIVE,NULL,0);
651   snprintf(buffer,MENULEN,"Family    : %s",dmi->system.family);
652   add_item(buffer,"Family",OPT_INACTIVE,NULL,0);
653 }
654
655 void compute_chassis(unsigned char *menu,s_dmi *dmi) {
656   char buffer[MENULEN];
657   *menu = add_menu(" Chassis ",-1);
658   snprintf(buffer,MENULEN,"Vendor    : %s",dmi->chassis.manufacturer);
659   add_item(buffer,"Vendor",OPT_INACTIVE,NULL,0);
660   snprintf(buffer,MENULEN,"Type      : %s",dmi->chassis.type);
661   add_item(buffer,"Type",OPT_INACTIVE,NULL,0);
662   snprintf(buffer,MENULEN,"Version   : %s",dmi->chassis.version);
663   add_item(buffer,"Version",OPT_INACTIVE,NULL,0);
664   snprintf(buffer,MENULEN,"Serial    : %s",dmi->chassis.serial);
665   add_item(buffer,"Serial Number",OPT_INACTIVE,NULL,0);
666   snprintf(buffer,MENULEN,"Asset Tag : %s",dmi->chassis.asset_tag);
667   add_item(buffer,"Asset Tag",OPT_INACTIVE,NULL,0);
668   snprintf(buffer,MENULEN,"Lock      : %s",dmi->chassis.lock);
669   add_item(buffer,"Lock",OPT_INACTIVE,NULL,0);
670 }
671
672 void compute_bios(unsigned char *menu,s_dmi *dmi) {
673   char buffer[MENULEN];
674   *menu = add_menu(" BIOS ",-1);
675   snprintf(buffer,MENULEN,"Vendor    : %s",dmi->bios.vendor);
676   add_item(buffer,"Vendor",OPT_INACTIVE,NULL,0);
677   snprintf(buffer,MENULEN,"Version   : %s",dmi->bios.version);
678   add_item(buffer,"Version",OPT_INACTIVE,NULL,0);
679   snprintf(buffer,MENULEN,"Release   : %s",dmi->bios.release_date);
680   add_item(buffer,"Release Date",OPT_INACTIVE,NULL,0);
681   snprintf(buffer,MENULEN,"Bios Rev. : %s",dmi->bios.bios_revision);
682   add_item(buffer,"Bios Revision",OPT_INACTIVE,NULL,0);
683   snprintf(buffer,MENULEN,"Fw.  Rev. : %s",dmi->bios.firmware_revision);
684   add_item(buffer,"Firmware Revision",OPT_INACTIVE,NULL,0);
685 }
686
687 void compute_processor(unsigned char *menu,s_cpu *cpu, s_dmi *dmi) {
688   char buffer[MENULEN];
689   char buffer1[MENULEN];
690   *menu = add_menu(" Main Processor ",-1);
691   snprintf(buffer,MENULEN,"Vendor    : %s",cpu->vendor);
692   add_item(buffer,"Vendor",OPT_INACTIVE,NULL,0);
693   snprintf(buffer,MENULEN,"Model     : %s",cpu->model);
694   add_item(buffer,"Model",OPT_INACTIVE,NULL,0);
695   snprintf(buffer,MENULEN,"Vendor ID : %d",cpu->vendor_id);
696   add_item(buffer,"Vendor ID",OPT_INACTIVE,NULL,0);
697   snprintf(buffer,MENULEN,"Family ID : %d",cpu->family);
698   add_item(buffer,"Family ID",OPT_INACTIVE,NULL,0);
699   snprintf(buffer,MENULEN,"Model  ID : %d",cpu->model_id);
700   add_item(buffer,"Model ID",OPT_INACTIVE,NULL,0);
701   snprintf(buffer,MENULEN,"Stepping  : %d",cpu->stepping);
702   add_item(buffer,"Stepping",OPT_INACTIVE,NULL,0);
703   if (is_dmi_valid) {
704    snprintf(buffer,MENULEN,"FSB       : %d",dmi->processor.external_clock);
705    add_item(buffer,"Front Side Bus (MHz)",OPT_INACTIVE,NULL,0);
706    snprintf(buffer,MENULEN,"Cur. Speed: %d",dmi->processor.current_speed);
707    add_item(buffer,"Current Speed (MHz)",OPT_INACTIVE,NULL,0);
708    snprintf(buffer,MENULEN,"Max Speed : %d",dmi->processor.max_speed);
709    add_item(buffer,"Max Speed (MHz)",OPT_INACTIVE,NULL,0);
710    snprintf(buffer,MENULEN,"Upgrade   : %s",dmi->processor.upgrade);
711    add_item(buffer,"Upgrade",OPT_INACTIVE,NULL,0);
712   }
713
714   if (cpu->flags.smp)  snprintf(buffer,MENULEN,"SMP       : Yes");
715   else snprintf(buffer,MENULEN,"SMP       : No");
716   add_item(buffer,"SMP system",OPT_INACTIVE,NULL,0);
717
718   if (cpu->flags.lm)  snprintf(buffer,MENULEN,"x86_64    : Yes");
719   else snprintf(buffer,MENULEN,"X86_64    : No");
720   add_item(buffer,"x86_64 compatible processor",OPT_INACTIVE,NULL,0);
721
722   buffer1[0]='\0';
723   if (cpu->flags.fpu) strcat(buffer1,"fpu ");
724   if (cpu->flags.vme) strcat(buffer1,"vme ");
725   if (cpu->flags.de)  strcat(buffer1,"de ");
726   if (cpu->flags.pse) strcat(buffer1,"pse ");
727   if (cpu->flags.tsc) strcat(buffer1,"tsc ");
728   if (cpu->flags.msr) strcat(buffer1,"msr ");
729   if (cpu->flags.pae) strcat(buffer1,"pae ");
730   snprintf(buffer,MENULEN,"Flags     : %s",buffer1);
731   add_item(buffer,"Flags",OPT_INACTIVE,NULL,0);
732
733   buffer1[0]='\0';
734   if (cpu->flags.mce) strcat(buffer1,"mce ");
735   if (cpu->flags.cx8) strcat(buffer1,"cx8 ");
736   if (cpu->flags.apic) strcat(buffer1,"apic ");
737   if (cpu->flags.sep) strcat(buffer1,"sep ");
738   if (cpu->flags.mtrr) strcat(buffer1,"mtrr ");
739   if (cpu->flags.pge) strcat(buffer1,"pge ");
740   if (cpu->flags.mca) strcat(buffer1,"mca ");
741   snprintf(buffer,MENULEN,"Flags     : %s",buffer1);
742   add_item(buffer,"Flags",OPT_INACTIVE,NULL,0);
743
744   buffer1[0]='\0';
745   if (cpu->flags.cmov) strcat(buffer1,"cmov ");
746   if (cpu->flags.pat)  strcat(buffer1,"pat ");
747   if (cpu->flags.pse_36) strcat(buffer1,"pse_36 ");
748   if (cpu->flags.psn)  strcat(buffer1,"psn ");
749   if (cpu->flags.clflsh) strcat(buffer1,"clflsh ");
750   snprintf(buffer,MENULEN,"Flags     : %s",buffer1);
751   add_item(buffer,"Flags",OPT_INACTIVE,NULL,0);
752
753   buffer1[0]='\0';
754   if (cpu->flags.dts)  strcat(buffer1,"dts ");
755   if (cpu->flags.acpi) strcat(buffer1,"acpi ");
756   if (cpu->flags.mmx)  strcat(buffer1,"mmx ");
757   if (cpu->flags.sse)  strcat(buffer1,"sse ");
758   snprintf(buffer,MENULEN,"Flags     : %s",buffer1);
759   add_item(buffer,"Flags",OPT_INACTIVE,NULL,0);
760
761   buffer1[0]='\0';
762   if (cpu->flags.sse2) strcat(buffer1,"sse2 ");
763   if (cpu->flags.ss)   strcat(buffer1,"ss ");
764   if (cpu->flags.htt)  strcat(buffer1,"ht ");
765   if (cpu->flags.acc)  strcat(buffer1,"acc ");
766   if (cpu->flags.syscall) strcat(buffer1,"syscall ");
767   if (cpu->flags.mp)   strcat(buffer1,"mp ");
768   snprintf(buffer,MENULEN,"Flags     : %s",buffer1);
769   add_item(buffer,"Flags",OPT_INACTIVE,NULL,0);
770
771   buffer1[0]='\0';
772   if (cpu->flags.nx)    strcat(buffer1,"nx ");
773   if (cpu->flags.mmxext) strcat(buffer1,"mmxext ");
774   if (cpu->flags.lm)     strcat(buffer1,"lm ");
775   if (cpu->flags.nowext) strcat(buffer1,"3dnowext ");
776   if (cpu->flags.now)    strcat(buffer1,"3dnow! ");
777   snprintf(buffer,MENULEN,"Flags     : %s",buffer1);
778   add_item(buffer,"Flags",OPT_INACTIVE,NULL,0);
779
780 }
781
782 void setup_env() {
783   openconsole(&dev_stdcon_r, &dev_stdcon_w);
784   init_menusystem("Hardware Detection Tool Version 0.1.1 by Erwan Velu");
785   set_window_size(1,1,23,78); // Leave some space around
786
787  // Register the menusystem handler
788  // reg_handler(HDLR_SCREEN,&msys_handler);
789   reg_handler(HDLR_KEYS,&keys_handler);
790
791   // Register the ontimeout handler, with a time out of 10 seconds
792   reg_ontimeout(ontimeout,1000,0);
793 }
794
795 void detect_hardware(s_dmi *dmi, s_cpu *cpu, struct pci_domain **pci_domain, struct diskinfo *disk_info) {
796   printf("CPU: Detecting\n");
797   detect_cpu(cpu);
798
799   printf("DISKS: Detecting\n");
800   detect_disks(disk_info);
801
802   printf("DMI: Detecting Table\n");
803   if (detect_dmi(dmi) == 0)
804                 is_dmi_valid=true;
805
806 #ifdef WITH_PCI
807   printf("PCI: Detecting Devices\n");
808   /* Scanning to detect pci buses and devices */
809   *pci_domain = pci_scan();
810
811
812   printf("PCI: Resolving names\n");
813   /* Assigning product & vendor name for each device*/
814   get_name_from_pci_ids(*pci_domain);
815
816   printf("PCI: Resolving class names\n");
817   /* Assigning class name for each device*/
818   get_class_name_from_pci_ids(*pci_domain);
819
820
821   printf("PCI: Resolving module names\n");
822   /* Detecting which kernel module should match each device */
823   get_module_name_from_pci_ids(*pci_domain);
824 #endif
825 }
826
827 void compute_memory(unsigned char *menu, s_dmi *dmi) {
828 char buffer[MENULEN];
829 for (int i=0;i<dmi->memory_count;i++) {
830   compute_memory_module(&MEMORY_SUBMENU[i],dmi,i);
831 }
832
833 *menu = add_menu(" Modules ",-1);
834
835 for (int i=0;i<dmi->memory_count;i++) {
836   sprintf(buffer," Module <%d> ",i);
837   add_item(buffer,"Memory Module",OPT_SUBMENU,NULL,MEMORY_SUBMENU[i]);
838 }
839 add_item("Run Test","Run Test",OPT_RUN,"memtest",0);
840 }
841
842 void compute_disks(unsigned char *menu, struct diskinfo *disk_info) {
843 char buffer[MENULEN];
844 nb_sub_disk_menu=0;
845
846 for (int i=0;i<0xff;i++) {
847   compute_disk_module(&DISK_SUBMENU[nb_sub_disk_menu],disk_info,i);
848 }
849
850 *menu = add_menu(" Disks ",-1);
851
852 for (int i=0;i<nb_sub_disk_menu;i++) {
853   sprintf(buffer," Disk <%d> ",i);
854   add_item(buffer,"Disk",OPT_SUBMENU,NULL,DISK_SUBMENU[i]);
855 }
856 }
857
858 void compute_submenus(s_dmi *dmi, s_cpu *cpu, struct pci_domain **pci_domain, struct diskinfo *disk_info) {
859 if (is_dmi_valid) {
860   compute_motherboard(&MOBO_MENU,dmi);
861   compute_chassis(&CHASSIS_MENU,dmi);
862   compute_system(&SYSTEM_MENU,dmi);
863   compute_memory(&MEMORY_MENU,dmi);
864   compute_bios(&BIOS_MENU,dmi);
865   compute_battery(&BATTERY_MENU,dmi);
866 }
867   compute_processor(&CPU_MENU,cpu,dmi);
868   compute_disks(&DISK_MENU,disk_info);
869 #ifdef WITH_PCI
870   compute_PCI(&PCI_MENU,pci_domain);
871   compute_KERNEL(&KERNEL_MENU,pci_domain);
872 #endif
873 }
874
875 void compute_main_menu() {
876   MAIN_MENU = add_menu(" Main Menu ",-1);
877   set_item_options(-1,24);
878
879  if (nb_sub_disk_menu>0)
880 #ifdef WITH_PCI
881   add_item("PCI <D>evices","PCI Devices",OPT_SUBMENU,NULL,PCI_MENU);
882 #endif
883  add_item("<D>isks","Disks",OPT_SUBMENU,NULL,DISK_MENU);
884  add_item("<M>emory Modules","Memory Modules",OPT_SUBMENU,NULL,MEMORY_MENU);
885  add_item("<P>rocessor","Main Processor",OPT_SUBMENU,NULL,CPU_MENU);
886
887 if (is_dmi_valid) {
888   add_item("<M>otherboard","Motherboard",OPT_SUBMENU,NULL,MOBO_MENU);
889   add_item("<B>ios","Bios",OPT_SUBMENU,NULL,BIOS_MENU);
890   add_item("<C>hassis","Chassis",OPT_SUBMENU,NULL,CHASSIS_MENU);
891   add_item("<S>ystem","System",OPT_SUBMENU,NULL,SYSTEM_MENU);
892   add_item("Ba<t>tery","Battery",OPT_SUBMENU,NULL,BATTERY_MENU);
893 }
894 #ifdef WITH_PCI
895   add_item("","",OPT_SEP,"",0);
896   add_item("<K>ernel modules","Kernel Modules",OPT_SUBMENU,NULL,KERNEL_MENU);
897 #endif
898 }
899
900 int main(void)
901 {
902   s_dmi dmi;
903   s_cpu cpu;
904   struct pci_domain *pci_domain=NULL;
905   struct diskinfo disk_info[255];
906
907   setup_env();
908
909   detect_hardware(&dmi,&cpu,&pci_domain,disk_info);
910
911   compute_submenus(&dmi,&cpu,&pci_domain,disk_info);
912
913   compute_main_menu();
914
915 #ifdef WITH_MENU_DISPLAY
916   t_menuitem * curr;
917   char cmd[160];
918
919   printf("Starting Menu\n");
920   curr=showmenus(MAIN_MENU);
921   if (curr) {
922         if (curr->action == OPT_RUN)
923         {
924             strcpy(cmd,curr->data);
925
926              if (issyslinux())
927                runsyslinuxcmd(cmd);
928             else csprint(cmd,0x07);
929             return 1; // Should not happen when run from SYSLINUX
930         }
931   }
932 #endif
933
934   return 0;
935 }