This commit was manufactured by cvs2svn to create tag
[opensuse:hwinfo.git] / src / hd / kbd.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <termios.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <sys/time.h>
11 #include <sys/ioctl.h>
12 #include <linux/serial.h>
13
14 #ifdef __sparc__
15
16 struct serial_struct {
17   int     type;
18   int     line;
19   unsigned long   port;
20   int     irq;
21   int     flags;
22   int     xmit_fifo_size;
23   int     custom_divisor;
24   int     baud_base;
25   unsigned short  close_delay;
26   char    io_type;
27   char    reserved_char[1];
28   int     hub6;
29   unsigned short  closing_wait; /* time to wait before closing */
30   unsigned short  closing_wait2; /* no longer used... */
31   unsigned char   *iomem_base;
32   unsigned short  iomem_reg_shift;
33   int     reserved[2];
34 };
35
36 #ifdef DIET
37 typedef unsigned int u_int;
38 #endif
39
40 #include <asm/kbio.h>
41 #include <asm/openpromio.h>
42 #endif
43
44 #include "hd.h"
45 #include "hd_int.h"
46 #include "kbd.h"
47
48 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
49  *
50  * Look for keyboards not covered by kernel input device driver, mainly
51  * some sort of serial consoles.
52  *
53  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54  */
55
56 #ifdef __sparc__
57 static void add_sun_console(hd_data_t *hd_data);
58 #else
59 static void add_serial_console(hd_data_t *hd_data);
60 #endif
61
62
63 void hd_scan_kbd(hd_data_t *hd_data)
64 {
65   hd_t *hd;
66
67   if(!hd_probe_feature(hd_data, pr_kbd)) return;
68
69   hd_data->module = mod_kbd;
70
71   /* some clean-up */
72   remove_hd_entries(hd_data);
73
74   PROGRESS(2, 0, "uml");
75
76   if(hd_is_uml(hd_data)) {
77     hd = add_hd_entry(hd_data, __LINE__, 0);
78     hd->base_class.id = bc_keyboard;
79     hd->sub_class.id = sc_keyboard_kbd;
80     hd->bus.id = bus_none;
81     hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0201);
82     hd->device.id = MAKE_ID(TAG_SPECIAL, 2);
83   }
84
85   PROGRESS(3, 0, "serial console");
86
87 #ifdef __sparc__
88   add_sun_console(hd_data);
89 #else
90   add_serial_console(hd_data);
91 #endif
92 }
93
94
95 #ifndef __sparc__
96
97 void add_serial_console(hd_data_t *hd_data)
98 {
99   hd_t *hd;
100   hd_res_t *res = NULL;
101   int fd, i;
102   str_list_t *cmd, *sl;
103   unsigned u, u1;
104   struct serial_struct ser_info;
105   unsigned tty_major = 0, tty_minor = 0;
106   char c, *dev = NULL, *s;
107
108   /* first, try console= option */
109   cmd = get_cmdline(hd_data, "console");
110   if(
111     cmd &&
112     (
113       /* everything != "ttyN" */
114       strncmp(cmd->str, "tty", 3) ||
115       !(cmd->str[3] == 0 || (cmd->str[3] >= '0' && cmd->str[3] <= '9'))
116     )
117   ) {
118     sl = hd_split(',', cmd->str);
119     s = sl->str;
120     if(!strncmp(s, "/dev/", sizeof "/dev/" - 1)) s += sizeof "/dev/" - 1;
121     dev = new_str(s);
122     if(sl->next && (i = sscanf(sl->next->str, "%u%c%u", &u, &c, &u1)) >= 1) {
123       res = add_res_entry(&res, new_mem(sizeof *res));
124       res->baud.type = res_baud;
125       res->baud.speed = u;
126       if(i >= 2) res->baud.parity = c;
127       if(i >= 3) res->baud.bits = u1;
128     }
129     free_str_list(sl);
130   }
131
132   if(!dev && (fd = open(DEV_CONSOLE, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0) {
133     if(ioctl(fd, TIOCGDEV, &u) != -1) {
134       tty_major = (u >> 8) & 0xfff;
135       tty_minor = (u & 0xff) | ((u >> 12) & 0xfff00);
136       ADD2LOG(DEV_CONSOLE ": major %u, minor %u\n", tty_major, tty_minor);
137     }
138
139     if(tty_major == 229 /* iseries hvc */) {
140       str_printf(&dev, 0, "hvc%u", tty_minor);
141     }
142     else if(!ioctl(fd, TIOCGSERIAL, &ser_info)) {
143       ADD2LOG("serial console at line %d\n", ser_info.line);
144       str_printf(&dev, 0, "ttyS%d", ser_info.line);
145     }
146     close(fd);
147   }
148
149   if(dev) {
150
151     hd = add_hd_entry(hd_data, __LINE__, 0);
152     hd->base_class.id = bc_keyboard;
153     hd->sub_class.id = sc_keyboard_console;
154     hd->bus.id = bus_serial;
155     hd->device.name = new_str("serial console");
156
157     if(*dev) str_printf(&hd->unix_dev_name, 0, "/dev/%s", dev);
158
159     hd->res = res;
160
161     free_mem(dev);
162   }
163
164   free_str_list(cmd);
165 }
166
167
168 #else   /* defined(__sparc__) */
169
170
171 void add_sun_console(hd_data_t *hd_data)
172 {
173   int fd, kid, kid2, klay, ser_cons, i;
174   unsigned u, u1, u2;
175   char c1, c2;
176   struct serial_struct ser_info;
177   unsigned char buf[OPROMMAXPARAM];
178   struct openpromio *opio = (struct openpromio *) buf;
179   hd_t *hd;
180   hd_res_t *res;
181
182   if((fd = open(DEV_CONSOLE, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0)
183     {
184       if(ioctl(fd, TIOCGSERIAL, &ser_info))
185         {
186           ser_cons = -1;
187         }
188       else
189         {
190           ser_cons = ser_info.line;
191           ADD2LOG("serial console at line %d\n", ser_cons);
192         }
193       close(fd);
194
195       if(ser_cons >= 0 && (fd = open(DEV_OPENPROM, O_RDWR | O_NONBLOCK)) >= 0)
196         {
197           sprintf(opio->oprom_array, "tty%c-mode", (ser_cons & 1) + 'a');
198           opio->oprom_size = sizeof buf - 0x100;
199           if(!ioctl(fd, OPROMGETOPT, opio))
200             {
201               if(opio->oprom_size < 0x100)
202                 {
203                   opio->oprom_array[opio->oprom_size] = 0;
204                   ADD2LOG(
205                           "prom(tty%c-mode) = \"%s\" (%d bytes)\n",
206                           (ser_cons & 1) + 'a', opio->oprom_array,
207                           opio->oprom_size
208                           );
209                   hd = add_hd_entry(hd_data, __LINE__, 0);
210                   hd->base_class.id = bc_keyboard;
211                   hd->sub_class.id = sc_keyboard_console;
212                   hd->bus.id = bus_serial;
213                   hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0203);
214                   hd->device.id = MAKE_ID(TAG_SPECIAL, 0x0000);
215                   str_printf(&hd->unix_dev_name, 0, "/dev/ttyS%d", ser_cons);
216                   if((i = sscanf(opio->oprom_array, "%u,%u,%c,%u,%c",
217                                  &u, &u1, &c1, &u2, &c2)) >= 1)
218                     {
219                       res = add_res_entry(&hd->res, new_mem(sizeof *res));
220                       res->baud.type = res_baud;
221                       res->baud.speed = u;
222                       if(i >= 2) res->baud.bits = u1;
223                       if(i >= 3) res->baud.parity = c1;
224                       if(i >= 4) res->baud.stopbits = u2;
225                       if(i >= 5) res->baud.handshake = c2;
226                     }
227                 }
228             }
229           close(fd);
230           /* We have a serial console, so don't test for keyboard. Else
231              we will always find a PS/2 keyboard */
232           return;
233         }
234     }
235
236   PROGRESS(1, 0, "sun kbd");
237
238   if((fd = open(DEV_KBD, O_RDWR | O_NONBLOCK | O_NOCTTY)) >= 0)
239     {
240       if(ioctl(fd, KIOCTYPE, &kid)) kid = -1;
241       if(ioctl(fd, KIOCLAYOUT, &klay)) klay = -1;
242       close(fd);
243
244       if(kid != -1)
245         {
246           ADD2LOG("sun keyboard: type %d, layout %d\n", kid, klay);
247
248           hd = add_hd_entry(hd_data, __LINE__, 0);
249           hd->base_class.id = bc_keyboard;
250           hd->sub_class.id = sc_keyboard_kbd;
251           hd->bus.id = bus_serial;
252           if(kid == 4 && klay >= 0)
253             hd->prog_if.id = klay;
254
255           hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0202);
256           kid2 = kid;
257           if(kid == 4 && klay > 0x20)
258             kid2 = 5;
259           hd->device.id = MAKE_ID(TAG_SPECIAL, kid2);
260           if(kid2 == 5) {
261             if(klay == 0x22 || klay == 0x51)
262               {
263                 hd->sub_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0202);
264                 hd->sub_device.id = MAKE_ID(TAG_SPECIAL, 0x0001);
265               }
266             else if(!(
267                       klay == 0x21 || (klay >= 0x2f && klay <= 0x31) ||
268                       klay == 0x50 || (klay >= 0x5e && klay <= 0x60)
269                       ))
270               {
271                 hd->sub_vendor.id = MAKE_ID(TAG_SPECIAL, 0x0202);
272                 hd->sub_device.id = MAKE_ID(TAG_SPECIAL, 0x0002);
273               }
274           }
275         }
276     }
277   else
278     {
279       for(hd = hd_data->hd; hd; hd = hd->next) {
280         if(hd->base_class.id == bc_keyboard) break;
281       }
282       if(!hd) {
283         /* We must have a PS/2 Keyboard */
284         hd = add_hd_entry(hd_data, __LINE__, 0);
285         hd->base_class.id = bc_keyboard;
286         hd->sub_class.id = sc_keyboard_kbd;
287         hd->bus.id = bus_ps2;
288         hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0x0201);
289         hd->device.id = MAKE_ID(TAG_SPECIAL, 1);
290       }
291     }
292 }
293
294 #endif  /* __sparc__ */
295
296