1 | #include <unistd.h>
|
---|
2 | #include <ddi.h>
|
---|
3 | #include <libarch/ddi.h>
|
---|
4 | #include <ipc/ipc.h>
|
---|
5 | #include <ipc/services.h>
|
---|
6 | #include <ipc/serial.h>
|
---|
7 | #include <ipc/devmap.h>
|
---|
8 | #include <ipc/ns.h>
|
---|
9 | #include <bool.h>
|
---|
10 | #include <errno.h>
|
---|
11 | #include <async.h>
|
---|
12 | #include <stdio.h>
|
---|
13 | #include <futex.h>
|
---|
14 | #include <assert.h>
|
---|
15 | #include <adt/list.h>
|
---|
16 | #include <string.h>
|
---|
17 |
|
---|
18 | #include "isa.h"
|
---|
19 | #include "serial.h"
|
---|
20 | #include "pic.h"
|
---|
21 |
|
---|
22 | #define NAME "serial"
|
---|
23 |
|
---|
24 | #define REG_COUNT 7
|
---|
25 |
|
---|
26 | #define MAX_NAME_LEN 8
|
---|
27 | #define BUF_LEN 256 // the length of the input buffer
|
---|
28 |
|
---|
29 | struct cyclic_buffer {
|
---|
30 | uint8_t buf[BUF_LEN]; // cyclic buffer
|
---|
31 | int start;
|
---|
32 | int cnt;
|
---|
33 | };
|
---|
34 |
|
---|
35 | typedef struct cyclic_buffer cyclic_buffer_t;
|
---|
36 |
|
---|
37 | // returns false if the buffer is full
|
---|
38 | static bool buf_push_back(cyclic_buffer_t *buf, uint8_t item)
|
---|
39 | {
|
---|
40 | if (buf->cnt >= BUF_LEN) {
|
---|
41 | return false;
|
---|
42 | }
|
---|
43 |
|
---|
44 | int pos = (buf->start + buf->cnt) % BUF_LEN;
|
---|
45 | buf->buf[pos] = item;
|
---|
46 | buf->cnt++;
|
---|
47 | return true;
|
---|
48 | }
|
---|
49 |
|
---|
50 | static bool buf_is_empty(cyclic_buffer_t *buf)
|
---|
51 | {
|
---|
52 | return buf->cnt == 0;
|
---|
53 | }
|
---|
54 |
|
---|
55 | // call it on non empty buffer!
|
---|
56 | static uint8_t buf_pop_front(cyclic_buffer_t *buf)
|
---|
57 | {
|
---|
58 | assert(!buf_is_empty(buf));
|
---|
59 |
|
---|
60 | uint8_t res = buf->buf[buf->start];
|
---|
61 | buf->start = (buf->start + 1) % BUF_LEN;
|
---|
62 | buf->cnt--;
|
---|
63 | return res;
|
---|
64 | }
|
---|
65 |
|
---|
66 | static void buf_clear(cyclic_buffer_t *buf)
|
---|
67 | {
|
---|
68 | buf->cnt = 0;
|
---|
69 | }
|
---|
70 |
|
---|
71 | struct serial_dev {
|
---|
72 | link_t link;
|
---|
73 | char name[MAX_NAME_LEN];
|
---|
74 | int handle; // devmapper device handle
|
---|
75 | int devno; // unique device number; used in irq registration (cannot be handle used instead of it?)
|
---|
76 | bool client_connected;
|
---|
77 | ioport8_t *port;
|
---|
78 | void *phys_addr;
|
---|
79 | int irq;
|
---|
80 | bridge_to_isa_t *parent;
|
---|
81 | cyclic_buffer_t input_buffer;
|
---|
82 | futex_t futex;
|
---|
83 | };
|
---|
84 |
|
---|
85 | typedef struct serial_dev serial_dev_t;
|
---|
86 |
|
---|
87 | static irq_cmd_t serial_cmds[] = {
|
---|
88 | {
|
---|
89 | .cmd = CMD_ACCEPT
|
---|
90 | }
|
---|
91 | };
|
---|
92 |
|
---|
93 | static irq_code_t serial_pseudocode = {
|
---|
94 | sizeof(serial_cmds) / sizeof(irq_cmd_t),
|
---|
95 | serial_cmds
|
---|
96 | };
|
---|
97 |
|
---|
98 | static void * serial_phys_addresses[] = { (void *)0x3F8, (void *)0x2F8 };
|
---|
99 | static int serial_irqs[] = { 4, 3 }; // TODO - what about if there were more than two serial ports?
|
---|
100 | static int serial_phys_addr_cnt = sizeof(serial_phys_addresses)/sizeof(void *);
|
---|
101 | static int serial_irq_cnt = sizeof(serial_irqs)/sizeof(int);
|
---|
102 |
|
---|
103 | // number, which should be assigned to a newly found serial device - increment first, then assign to the device
|
---|
104 | static int serial_idx = 0;
|
---|
105 |
|
---|
106 | static int serial_driver_phone = -1;
|
---|
107 |
|
---|
108 | LIST_INITIALIZE(serial_devices_list);
|
---|
109 |
|
---|
110 | static atomic_t serial_futex = FUTEX_INITIALIZER;
|
---|
111 |
|
---|
112 |
|
---|
113 | static void serial_init_port(ioport8_t *port);
|
---|
114 | static void serial_write_8(ioport8_t *port, uint8_t c);
|
---|
115 | static bool is_transmit_empty(ioport8_t *port);
|
---|
116 | static uint8_t serial_read_8(ioport8_t *port);
|
---|
117 | static bool serial_received(ioport8_t *port);
|
---|
118 | static void serial_probe(bridge_to_isa_t *parent);
|
---|
119 | static ioport8_t * serial_probe_port(void *phys_addr);
|
---|
120 | static int serial_device_register(int driver_phone, char *name, int *handle);
|
---|
121 | static int serial_driver_register(char *name);
|
---|
122 | static void serial_putchar(serial_dev_t *dev, ipc_callid_t rid, ipc_call_t *request);
|
---|
123 | static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid);
|
---|
124 | static void serial_client_conn(ipc_callid_t iid, ipc_call_t *icall);
|
---|
125 | static void serial_irq_handler(ipc_callid_t iid, ipc_call_t *icall);
|
---|
126 | static serial_dev_t * serial_devno_to_dev(int devno);
|
---|
127 | static serial_dev_t * serial_handle_to_dev(int handle);
|
---|
128 | static void serial_enable_interrupt(serial_dev_t *dev);
|
---|
129 |
|
---|
130 | static isa_drv_ops_t serial_isa_ops = {
|
---|
131 | .probe = serial_probe
|
---|
132 | };
|
---|
133 |
|
---|
134 | static isa_drv_t serial_isa_drv = {
|
---|
135 | .name = NAME,
|
---|
136 | .ops = &serial_isa_ops
|
---|
137 | };
|
---|
138 |
|
---|
139 | int serial_init()
|
---|
140 | {
|
---|
141 | // register driver by devmapper
|
---|
142 | serial_driver_phone = serial_driver_register(NAME);
|
---|
143 | if (serial_driver_phone < 0) {
|
---|
144 | printf(NAME ": Unable to register driver\n");
|
---|
145 | return 0;
|
---|
146 | }
|
---|
147 |
|
---|
148 | // register irq handler
|
---|
149 | printf(NAME ": Registering interrup notification callback function.\n");
|
---|
150 | async_set_interrupt_received(serial_irq_handler);
|
---|
151 |
|
---|
152 | // register this driver by generic isa bus driver
|
---|
153 | isa_register_driver(&serial_isa_drv);
|
---|
154 | return 1;
|
---|
155 | }
|
---|
156 |
|
---|
157 | static bool serial_received(ioport8_t *port)
|
---|
158 | {
|
---|
159 | return (pio_read_8(port + 5) & 1) != 0;
|
---|
160 | }
|
---|
161 |
|
---|
162 | static uint8_t serial_read_8(ioport8_t *port)
|
---|
163 | {
|
---|
164 | return pio_read_8(port);
|
---|
165 | }
|
---|
166 |
|
---|
167 | static bool is_transmit_empty(ioport8_t *port)
|
---|
168 | {
|
---|
169 | return (pio_read_8(port + 5) & 0x20) != 0;
|
---|
170 | }
|
---|
171 |
|
---|
172 | static void serial_write_8(ioport8_t *port, uint8_t c)
|
---|
173 | {
|
---|
174 | while (!is_transmit_empty(port))
|
---|
175 | ;
|
---|
176 |
|
---|
177 | pio_write_8(port, c);
|
---|
178 | }
|
---|
179 |
|
---|
180 | static void serial_init_port(ioport8_t *port)
|
---|
181 | {
|
---|
182 | pio_write_8(port + 1, 0x00); // Disable all interrupts
|
---|
183 | pio_write_8(port + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
---|
184 | pio_write_8(port + 0, 0x60); // Set divisor to 96 (lo byte) 1200 baud
|
---|
185 | pio_write_8(port + 1, 0x00); // (hi byte)
|
---|
186 | pio_write_8(port + 3, 0x07); // 8 bits, no parity, two stop bits
|
---|
187 | pio_write_8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
---|
188 | pio_write_8(port + 4, 0x0B); // RTS/DSR set (Request to Send and Data Terminal Ready lines enabled),
|
---|
189 | // Aux Output2 set - needed for interrupts
|
---|
190 |
|
---|
191 | }
|
---|
192 |
|
---|
193 | static void serial_enable_interrupt(serial_dev_t *dev)
|
---|
194 | {
|
---|
195 | futex_down(&(dev->futex));
|
---|
196 | // TODO do not call pic directly, do it more generally
|
---|
197 | pic_enable_interrupt(dev->irq);
|
---|
198 | pio_write_8(dev->port + 1 , 0x01); // Interrupt when data received
|
---|
199 | pio_write_8(dev->port + 4, 0x0B);
|
---|
200 | futex_up(&(dev->futex));
|
---|
201 | }
|
---|
202 |
|
---|
203 | static serial_dev_t * serial_alloc_dev()
|
---|
204 | {
|
---|
205 | serial_dev_t *dev = (serial_dev_t *)malloc(sizeof(serial_dev_t));
|
---|
206 | memset(dev, 0, sizeof(serial_dev_t));
|
---|
207 | return dev;
|
---|
208 | }
|
---|
209 |
|
---|
210 | static void serial_init_dev(serial_dev_t *dev, bridge_to_isa_t *parent, int idx)
|
---|
211 | {
|
---|
212 | assert(dev != NULL);
|
---|
213 |
|
---|
214 | memset(dev, 0, sizeof(serial_dev_t));
|
---|
215 | dev->parent = parent;
|
---|
216 | dev->phys_addr = dev->parent->ops->absolutize(serial_phys_addresses[idx % serial_phys_addr_cnt]);
|
---|
217 | dev->irq = serial_irqs[idx % serial_irq_cnt];
|
---|
218 | snprintf(dev->name, MAX_NAME_LEN, "com%d", idx + 1);
|
---|
219 | dev->devno = -1;
|
---|
220 | dev->client_connected = false;
|
---|
221 | futex_initialize(&(dev->futex), 1);
|
---|
222 | }
|
---|
223 |
|
---|
224 | static bool serial_probe_dev(serial_dev_t *dev)
|
---|
225 | {
|
---|
226 | assert(dev != NULL);
|
---|
227 |
|
---|
228 | return (dev->port = (ioport8_t *)serial_probe_port(dev->phys_addr)) != NULL;
|
---|
229 | }
|
---|
230 |
|
---|
231 | static void serial_delete_dev(serial_dev_t *dev) {
|
---|
232 | free(dev);
|
---|
233 | }
|
---|
234 |
|
---|
235 | static void serial_probe(bridge_to_isa_t *parent)
|
---|
236 | {
|
---|
237 | printf(NAME " driver: probe()\n");
|
---|
238 |
|
---|
239 | serial_dev_t *dev = serial_alloc_dev();
|
---|
240 |
|
---|
241 | int i;
|
---|
242 | for (i = 0; i < serial_phys_addr_cnt; i++) {
|
---|
243 | serial_init_dev(dev, parent, serial_idx);
|
---|
244 | printf(NAME ": probing %s. \n", dev->name);
|
---|
245 | if (serial_probe_dev(dev)) {
|
---|
246 | printf(NAME " driver: initializing %s.\n", dev->name);
|
---|
247 | serial_init_port(dev->port);
|
---|
248 | if (EOK != serial_device_register(serial_driver_phone, dev->name, &(dev->handle))) {
|
---|
249 | printf(NAME ": unable to register device %s\n", dev->name);
|
---|
250 | } else {
|
---|
251 | dev->devno = device_assign_devno();
|
---|
252 |
|
---|
253 | // 3rd argument called method is equal devno,this enables us to identify the device
|
---|
254 | // which caused the interrupt in the irq notification callback function
|
---|
255 | printf(NAME ": registering irq = %d for %s.\n", dev->irq, dev->name);
|
---|
256 | ipc_register_irq(dev->irq, dev->devno, dev->devno, &serial_pseudocode);
|
---|
257 | list_append(&(dev->link), &serial_devices_list);
|
---|
258 | printf(NAME ": enabling irq = %d for %s.\n", dev->irq, dev->name);
|
---|
259 | serial_enable_interrupt(dev);
|
---|
260 | dev = serial_alloc_dev();
|
---|
261 | }
|
---|
262 | } else {
|
---|
263 | printf(NAME " driver: %s is not present \n", dev->name);
|
---|
264 | }
|
---|
265 | serial_idx++;
|
---|
266 | }
|
---|
267 |
|
---|
268 | serial_delete_dev(dev);
|
---|
269 | }
|
---|
270 |
|
---|
271 | // returns virtual address of the serial port, if the serial port is present at this physical address, NULL otherwise
|
---|
272 | static ioport8_t * serial_probe_port(void *phys_addr)
|
---|
273 | {
|
---|
274 | ioport8_t *port_addr = NULL;
|
---|
275 |
|
---|
276 | if (pio_enable(phys_addr, REG_COUNT, (void **)(&port_addr))) { // Gain control over port's registers.
|
---|
277 | printf(NAME ": Error - cannot gain the port %lx.\n", phys_addr);
|
---|
278 | return NULL;
|
---|
279 | }
|
---|
280 |
|
---|
281 | uint8_t olddata;
|
---|
282 |
|
---|
283 | olddata = pio_read_8(port_addr + 4);
|
---|
284 | pio_write_8(port_addr + 4, 0x10);
|
---|
285 | if ((pio_read_8(port_addr + 6) & 0xf0)) {
|
---|
286 | return NULL;
|
---|
287 | }
|
---|
288 |
|
---|
289 | pio_write_8(port_addr + 4, 0x1f);
|
---|
290 | if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0) {
|
---|
291 | return NULL;
|
---|
292 | }
|
---|
293 | pio_write_8(port_addr + 4, olddata);
|
---|
294 |
|
---|
295 | return port_addr;
|
---|
296 | }
|
---|
297 |
|
---|
298 |
|
---|
299 | static void serial_putchar(serial_dev_t *dev, ipc_callid_t rid, ipc_call_t *request)
|
---|
300 | {
|
---|
301 | int c = IPC_GET_ARG1(*request);
|
---|
302 | futex_down(&(dev->futex));
|
---|
303 | serial_write_8(dev->port, (uint8_t)c);
|
---|
304 | futex_up(&(dev->futex));
|
---|
305 | ipc_answer_0(rid, EOK);
|
---|
306 | }
|
---|
307 |
|
---|
308 | static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid)
|
---|
309 | {
|
---|
310 | uint8_t c;
|
---|
311 | printf(NAME ": trying to read from serial port %s\n", dev->name);
|
---|
312 | while (true) { // TODO: fix it - the queue of requests to read ?
|
---|
313 | futex_down(&(dev->futex));
|
---|
314 | if (!buf_is_empty(&(dev->input_buffer))) {
|
---|
315 | c = buf_pop_front(&(dev->input_buffer));
|
---|
316 | futex_up(&(dev->futex));
|
---|
317 | break;
|
---|
318 | }
|
---|
319 | //printf(NAME "no data ready, trying to read again after some while.\n", dev->name);
|
---|
320 | futex_up(&(dev->futex));
|
---|
321 | async_usleep(10000);
|
---|
322 | }
|
---|
323 | printf(NAME ": serial_getchar: sending characer %c read from %s to client.\n", c, dev->name);
|
---|
324 | ipc_answer_1(rid, EOK, c);
|
---|
325 | }
|
---|
326 |
|
---|
327 | static serial_dev_t * serial_handle_to_dev(int handle)
|
---|
328 | {
|
---|
329 | futex_down(&serial_futex);
|
---|
330 |
|
---|
331 | link_t *item = serial_devices_list.next;
|
---|
332 | serial_dev_t *dev = NULL;
|
---|
333 |
|
---|
334 | while (item != &serial_devices_list) {
|
---|
335 | dev = list_get_instance(item, serial_dev_t, link);
|
---|
336 | if (dev->handle == handle) {
|
---|
337 | futex_up(&serial_futex);
|
---|
338 | return dev;
|
---|
339 | }
|
---|
340 | item = item->next;
|
---|
341 | }
|
---|
342 |
|
---|
343 | futex_up(&serial_futex);
|
---|
344 | return NULL;
|
---|
345 | }
|
---|
346 |
|
---|
347 | static serial_dev_t * serial_devno_to_dev(int devno)
|
---|
348 | {
|
---|
349 | futex_down(&serial_futex);
|
---|
350 |
|
---|
351 | link_t *item = serial_devices_list.next;
|
---|
352 | serial_dev_t *dev = NULL;
|
---|
353 |
|
---|
354 | while (item != &serial_devices_list) {
|
---|
355 | dev = list_get_instance(item, serial_dev_t, link);
|
---|
356 | if (dev->devno == devno) {
|
---|
357 | futex_up(&serial_futex);
|
---|
358 | return dev;
|
---|
359 | }
|
---|
360 | item = item->next;
|
---|
361 | }
|
---|
362 |
|
---|
363 | futex_up(&serial_futex);
|
---|
364 | return NULL;
|
---|
365 | }
|
---|
366 |
|
---|
367 |
|
---|
368 | /** Handle one connection to the driver.
|
---|
369 | *
|
---|
370 | * @param iid Hash of the request that opened the connection.
|
---|
371 | * @param icall Call data of the request that opened the connection.
|
---|
372 | */
|
---|
373 | static void serial_client_conn(ipc_callid_t iid, ipc_call_t *icall)
|
---|
374 | {
|
---|
375 | /*
|
---|
376 | * Answer the first IPC_M_CONNECT_ME_TO call and remember the handle of the device to which the client connected.
|
---|
377 | */
|
---|
378 | int handle = IPC_GET_ARG1(*icall);
|
---|
379 | serial_dev_t *dev = serial_handle_to_dev(handle);
|
---|
380 |
|
---|
381 | if (dev == NULL) {
|
---|
382 | ipc_answer_0(iid, ENOENT);
|
---|
383 | return;
|
---|
384 | }
|
---|
385 | if (dev->client_connected) {
|
---|
386 | ipc_answer_0(iid, ELIMIT);
|
---|
387 | return;
|
---|
388 | }
|
---|
389 |
|
---|
390 | buf_clear(&(dev->input_buffer)); // synchronization with interrupt service routine ?
|
---|
391 | dev->client_connected = true;
|
---|
392 | ipc_answer_0(iid, EOK);
|
---|
393 |
|
---|
394 | while (1) {
|
---|
395 | ipc_callid_t callid;
|
---|
396 | ipc_call_t call;
|
---|
397 |
|
---|
398 | callid = async_get_call(&call);
|
---|
399 | switch (IPC_GET_METHOD(call)) {
|
---|
400 | case IPC_M_PHONE_HUNGUP:
|
---|
401 | /*
|
---|
402 | * The other side has hung up.
|
---|
403 | * Answer the message and exit the fibril.
|
---|
404 | */
|
---|
405 | ipc_answer_0(callid, EOK);
|
---|
406 | dev->client_connected = false;
|
---|
407 | return;
|
---|
408 | break;
|
---|
409 | case SERIAL_GETCHAR:
|
---|
410 | serial_getchar(dev, callid);
|
---|
411 | break;
|
---|
412 | case SERIAL_PUTCHAR:
|
---|
413 | serial_putchar(dev, callid, &call);
|
---|
414 | break;
|
---|
415 | default:
|
---|
416 | ipc_answer_0(callid, ENOTSUP);
|
---|
417 | break;
|
---|
418 | }
|
---|
419 | }
|
---|
420 | }
|
---|
421 |
|
---|
422 |
|
---|
423 | /**
|
---|
424 | * Register the driver with the given name and return its newly created phone.
|
---|
425 | */
|
---|
426 | static int serial_driver_register(char *name)
|
---|
427 | {
|
---|
428 | ipcarg_t retval;
|
---|
429 | aid_t req;
|
---|
430 | ipc_call_t answer;
|
---|
431 | int phone;
|
---|
432 | ipcarg_t callback_phonehash;
|
---|
433 |
|
---|
434 | phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
|
---|
435 |
|
---|
436 | while (phone < 0) {
|
---|
437 | usleep(10000);
|
---|
438 | phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
|
---|
439 | }
|
---|
440 |
|
---|
441 | req = async_send_2(phone, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
|
---|
442 |
|
---|
443 | retval = ipc_data_write_start(phone, (char *) name, str_length(name) + 1);
|
---|
444 |
|
---|
445 | if (retval != EOK) {
|
---|
446 | async_wait_for(req, NULL);
|
---|
447 | return -1;
|
---|
448 | }
|
---|
449 |
|
---|
450 | async_set_client_connection(serial_client_conn); // set callback function which will serve client connections
|
---|
451 |
|
---|
452 | ipc_connect_to_me(phone, 0, 0, 0, &callback_phonehash);
|
---|
453 | async_wait_for(req, &retval);
|
---|
454 |
|
---|
455 | return phone;
|
---|
456 | }
|
---|
457 |
|
---|
458 | static int serial_device_register(int driver_phone, char *name, int *handle)
|
---|
459 | {
|
---|
460 | ipcarg_t retval;
|
---|
461 | aid_t req;
|
---|
462 | ipc_call_t answer;
|
---|
463 |
|
---|
464 | if (handle != NULL) {
|
---|
465 | *handle = -1;
|
---|
466 | }
|
---|
467 |
|
---|
468 | req = async_send_2(driver_phone, DEVMAP_DEVICE_REGISTER, 0, 0, &answer);
|
---|
469 |
|
---|
470 | retval = ipc_data_write_start(driver_phone, (char *) name, str_length(name) + 1);
|
---|
471 |
|
---|
472 | if (retval != EOK) {
|
---|
473 | async_wait_for(req, NULL);
|
---|
474 | return retval;
|
---|
475 | }
|
---|
476 |
|
---|
477 | async_wait_for(req, &retval);
|
---|
478 |
|
---|
479 | if (EOK == retval) {
|
---|
480 | if (NULL != handle)
|
---|
481 | *handle = (int) IPC_GET_ARG1(answer);
|
---|
482 | }
|
---|
483 |
|
---|
484 | return retval;
|
---|
485 | }
|
---|
486 |
|
---|
487 | static void serial_read_from_device(serial_dev_t *dev)
|
---|
488 | {
|
---|
489 | bool cont = true;
|
---|
490 |
|
---|
491 | while (cont) {
|
---|
492 | futex_down(&(dev->futex));
|
---|
493 | if (cont = serial_received(dev->port)) {
|
---|
494 | uint8_t val = serial_read_8(dev->port);
|
---|
495 | printf(NAME ": character %c read from %s.\n", val, dev->name);
|
---|
496 | if (dev->client_connected) {
|
---|
497 | if (!buf_push_back(&(dev->input_buffer), val)) {
|
---|
498 | printf(NAME ": buffer overflow on %s.\n", dev->name);
|
---|
499 | } else {
|
---|
500 | printf(NAME ": the character %c saved to the buffer of %s.\n", val, dev->name);
|
---|
501 | }
|
---|
502 | } else {
|
---|
503 | printf(NAME ": no client is connected to %s, discarding the character which was read.\n", dev->name);
|
---|
504 | }
|
---|
505 | }
|
---|
506 | futex_up(&(dev->futex));
|
---|
507 | usleep(10000);
|
---|
508 | }
|
---|
509 | }
|
---|
510 |
|
---|
511 | // TODO - this is the only irq handling function registered by this task.
|
---|
512 | // (A task can register only one such function.)
|
---|
513 | // If more drivers within the task needed to handle interrupts,
|
---|
514 | // there will have to be one generic handler redistributing
|
---|
515 | // irq notification messages among them.
|
---|
516 | // Or the change of ansync framework will be needed.
|
---|
517 | static void serial_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
|
---|
518 | {
|
---|
519 | printf(NAME ": irq handler\n");
|
---|
520 | int devno = IPC_GET_METHOD(*icall);
|
---|
521 | serial_dev_t *dev = serial_devno_to_dev(devno);
|
---|
522 | serial_read_from_device(dev);
|
---|
523 | }
|
---|
524 |
|
---|