Initial revision
[opensuse:hwinfo.git] / src / hd / bios.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8
9 #include "hd.h"
10 #include "hd_int.h"
11 #include "bios.h"
12
13 #define BIOS_START      0xc0000
14 #define BIOS_SIZE       0x40000
15
16 #define BIOS_VARS_START 0x400
17 #define BIOS_VARS_SIZE  0x100
18
19 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
20  * bios info
21  *
22  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23  */
24
25 #if defined(__i386__)
26
27 static void get_pnp_support_status(unsigned char *, bios_info_t *);
28
29 void hd_scan_bios(hd_data_t *hd_data)
30 {
31   hd_t *hd;
32   char *s = NULL /* gcc -Wall */, *t;
33   char c_str[] = "SuSE=";
34   unsigned char bios_vars[BIOS_VARS_SIZE];
35   unsigned char bios[BIOS_SIZE];
36   int fd, ok = 0;
37   bios_info_t *bt;
38   str_list_t *sl;
39
40   if(!(hd_data->probe & (1 << pr_bios))) return;
41
42   hd_data->module = mod_bios;
43
44   /* some clean-up */
45   remove_hd_entries(hd_data);
46
47   PROGRESS(1, 0, "cmdline");
48
49   hd = add_hd_entry(hd_data, __LINE__, 0);
50   hd->base_class = bc_internal;
51   hd->sub_class = sc_int_bios;
52   hd->detail = new_mem(sizeof *hd->detail);
53   hd->detail->type = hd_detail_bios;
54   hd->detail->bios.data = bt = new_mem(sizeof *bt);
55
56   /*
57    * first, look for APM support
58    */
59   if((sl = read_file(PROC_CMDLINE, 0, 1))) {
60     t = sl->str;
61     while((s = strsep(&t, " "))) {
62       if(!*s) continue;
63       if(!strncmp(s, c_str, sizeof c_str - 1)) {
64         s += sizeof c_str - 1;
65
66         /* ok, now strip off the monitor info (separated by',') */
67         for(t = s; *s; s++) if(*s == ',') break;
68         if(*s++ == ',')
69           if(strlen(s) == 10) ok = 1;
70
71         break;
72       }
73     }
74
75     if(ok) {
76       bt->apm_supported = 1;
77       bt->apm_ver = hex(s, 1);
78       bt->apm_subver = hex(s + 1, 1);
79       bt->apm_bios_flags = hex(s + 2, 2);
80       /*
81        * Bitfields for APM flags (from Ralf Brown's list):
82        * Bit(s)  Description
83        *  0      16-bit protected mode interface supported
84        *  1      32-bit protected mode interface supported
85        *  2      CPU idle call reduces processor speed
86        *  3      BIOS power management disabled
87        *  4      BIOS power management disengaged (APM v1.1)
88        *  5-7    reserved
89        */
90       bt->apm_enabled = (bt->apm_bios_flags & 8) ? 0 : 1;
91
92       bt->vbe_ver = hex(s + 4, 2);
93       bt->vbe_video_mem = hex(s + 6, 4) << 16;
94     }
95   }
96
97   sl = free_str_list(sl);
98
99   /*
100    * get the i/o ports for the parallel & serial interfaces from the BIOS
101    * memory area starting at 0x40:0
102    */
103   PROGRESS(2, 0, "ram");
104
105   fd = -1;
106   if(
107     (fd = open(DEV_MEM, O_RDWR)) >= 0 && 
108     lseek(fd, BIOS_VARS_START, SEEK_SET) >= 0 &&
109     read(fd, bios_vars, sizeof bios_vars) == sizeof bios_vars
110   ) {
111     bt->ser_port0 = (bios_vars[1] << 8) + bios_vars[0];
112     bt->ser_port1 = (bios_vars[3] << 8) + bios_vars[2];
113     bt->ser_port2 = (bios_vars[5] << 8) + bios_vars[4];
114     bt->ser_port3 = (bios_vars[7] << 8) + bios_vars[6];
115
116     bt->par_port0 = (bios_vars[  9] << 8) + bios_vars[  8];
117     bt->par_port1 = (bios_vars[0xb] << 8) + bios_vars[0xa];
118     bt->par_port2 = (bios_vars[0xd] << 8) + bios_vars[0xc];
119
120   }
121   if(fd >= 0) close(fd);
122
123
124   /*
125    * read the bios rom and look for useful things there...
126    */
127   PROGRESS(2, 0, "rom");
128
129   fd = -1;
130   if(
131     (fd = open(DEV_MEM, O_RDWR)) >= 0 && 
132     lseek(fd, BIOS_START, SEEK_SET) >= 0 &&
133     read(fd, bios, sizeof bios) == sizeof bios
134   ) {
135     get_pnp_support_status(bios, bt);
136
137
138
139   }
140   if(fd >= 0) close(fd);
141 }
142
143
144 void get_pnp_support_status(unsigned char *bios, bios_info_t *bt)
145 {
146   int i;
147   unsigned char pnp[4] = { '$', 'P', 'n', 'P' };
148   unsigned char *t;
149   unsigned l, cs;
150
151   for(i = 0xf0000 - BIOS_START; i < BIOS_SIZE; i += 0x10) {
152     t = bios + i;
153     if(t[0] == pnp[0] && t[1] == pnp[1] && t[2] == pnp[2] && t[3] == pnp[3]) {
154       for(l = cs = 0; l < t[5]; l++) { cs += t[l]; }
155       if((cs & 0xff) == 0) {            // checksum ok
156         bt->is_pnp_bios = 1;
157 //        printf("0x%x bytes at 0x%x, cs = 0x%x\n", t[5], i, cs);
158         bt->pnp_id = t[0x17] + (t[0x18] << 8) + (t[0x19] << 16) + (t[0x20] << 24);
159       }
160     }
161   }
162 }
163
164 #endif /* defined(__i386__) */
165