Initial revision
[opensuse:hwinfo.git] / src / hd / serial.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <sys/stat.h>
7 #include <sys/types.h>
8
9 #include "hd.h"
10 #include "hd_int.h"
11 #include "serial.h"
12
13 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
14  * serial interface
15  *
16  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
17  */
18
19
20 static void get_serial_info(hd_data_t *hd_data);
21 static serial_t *add_serial_entry(serial_t **ser, serial_t *new_ser);
22 static void dump_serial_data(hd_data_t *hd_data);
23
24 void hd_scan_serial(hd_data_t *hd_data)
25 {
26   hd_t *hd;
27   serial_t *ser;
28   hd_res_t *res;
29
30   if(!(hd_data->probe & (1 << pr_serial))) return;
31
32   hd_data->module = mod_serial;
33
34   /* some clean-up */
35   remove_hd_entries(hd_data);
36   hd_data->serial = NULL;
37
38   PROGRESS(1, 0, "read info");
39
40   get_serial_info(hd_data);
41   if((hd_data->debug & HD_DEB_SERIAL)) dump_serial_data(hd_data);
42
43   PROGRESS(2, 0, "build list");
44
45   for(ser = hd_data->serial; ser; ser = ser->next) {
46     hd = add_hd_entry(hd_data, __LINE__, 0);
47     hd->base_class = bc_comm;
48     hd->sub_class = sc_com_ser;
49     hd->dev_name = new_str(ser->name);
50     hd->func = ser->line;
51     str_printf(&hd->unix_dev_name, 0, "/dev/ttyS%u", ser->line);
52     if(ser->baud) {
53       res = add_res_entry(&hd->res, new_mem(sizeof *res));
54       res->baud.type = res_baud;
55       res->baud.speed = ser->baud;
56     }
57     res = add_res_entry(&hd->res, new_mem(sizeof *res));
58     res->io.type = res_io;
59     res->io.enabled = 1;
60     res->io.base = ser->port;
61     res->io.access = acc_rw;
62
63     res = add_res_entry(&hd->res, new_mem(sizeof *res));
64     res->irq.type = res_irq;
65     res->irq.enabled = 1;
66     res->irq.base = ser->irq;
67   }  
68 }
69
70 void get_serial_info(hd_data_t *hd_data)
71 {
72   char buf[32];
73   unsigned u0, u1, u2, u3;
74   int i;
75   str_list_t *sl, *sl0;
76   serial_t *ser;
77
78   /*
79    * Max. 44 serial lines at the moment; the serial proc interface is
80    * somewhat buggy at the moment (2.2.13), hence the explicit 44 lines
81    * limit. That may be dropped later.
82    */
83   if(!(sl0 = read_file(PROC_DRIVER_SERIAL, 1, 44))) return;
84
85   for(sl = sl0; sl; sl = sl->next) {
86     i = 0;
87     if(
88       sscanf(sl->str, "%u: uart:%31s port:%x irq:%u baud:%u", &u0, buf, &u1, &u2, &u3) == 5 ||
89       (i = 1, sscanf(sl->str, "%u: uart:%31s port:%x irq:%u tx:%*u", &u0, buf, &u1, &u2) == 5)
90     ) {
91       /*
92        * The 'baud' or 'tx' entries are only present for real interfaces.
93        */
94       ser = add_serial_entry(&hd_data->serial, new_mem(sizeof *ser));
95       ser->line = u0;
96       ser->port = u1;
97       ser->irq = u2;
98       if(!i) ser->baud = u3;
99       ser->name = new_str(buf);
100     }
101   }
102
103   if((hd_data->debug & HD_DEB_SERIAL)) {
104     /* log just the first 16 entries */
105     ADD2LOG("----- /proc/tty/driver/serial -----\n");
106     for(sl = sl0, i = 16; sl && i--; sl = sl->next) {
107       ADD2LOG("  %s", sl->str);
108     }
109     ADD2LOG("----- /proc/tty/driver/serial end -----\n");
110   }
111
112   free_str_list(sl0);
113 }
114
115 serial_t *add_serial_entry(serial_t **ser, serial_t *new_ser)
116 {
117   while(*ser) ser = &(*ser)->next;
118   return *ser = new_ser;
119 }
120
121 void dump_serial_data(hd_data_t *hd_data)
122 {
123   serial_t *ser;
124
125   ADD2LOG("----- serial info -----\n");
126   for(ser = hd_data->serial; ser; ser = ser->next) {
127     ADD2LOG(
128       "  uart %s, line %d, port 0x%03x, irq %d, baud %d\n",
129       ser->name, ser->line, ser->port, ser->irq, ser->baud
130     );
131   }
132   ADD2LOG("----- serial info end -----\n");
133 }
134