source: mainline/uspace/drv/char/grlib_uart/grlib_uart.c@ 659ebd86

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 659ebd86 was f9b2cb4c, checked in by Martin Decky <martin@…>, 10 years ago

unify interface API

  • introduce new interfaces
  • unify location service clients to always expect service ID as the second argument
  • remove obsolete methods that take explicit exchange management arguments (first phase)
  • use interfaces in device drivers, devman, location service, logger, inet
  • Property mode set to 100644
File size: 21.0 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * Copyright (c) 2011 Jiri Svoboda
4 * Copyright (c) 2013 Jakub Klama
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @defgroup grlib_uart Serial port driver.
33 * @brief HelenOS serial port driver.
34 * @{
35 */
36
37/** @file
38 */
39
40#include <assert.h>
41#include <stdio.h>
42#include <errno.h>
43#include <stdbool.h>
44#include <fibril_synch.h>
45#include <stdlib.h>
46#include <str.h>
47#include <ctype.h>
48#include <macros.h>
49#include <malloc.h>
50#include <dirent.h>
51#include <fcntl.h>
52#include <sys/stat.h>
53#include <ddi.h>
54
55#include <ddf/driver.h>
56#include <ddf/interrupt.h>
57#include <ddf/log.h>
58#include <ops/char_dev.h>
59
60#include <ns.h>
61#include <ipc/services.h>
62#include <ipc/irc.h>
63#include <device/hw_res.h>
64#include <ipc/serial_ctl.h>
65
66#include "cyclic_buffer.h"
67
68#define NAME "grlib_uart"
69
70#define REG_COUNT 5
71#define MAX_BAUD_RATE 115200
72
73#define LVL_DEBUG LVL_ERROR
74
75#define GRLIB_UART_STATUS_DR (1 << 0)
76#define GRLIB_UART_STATUS_TS (1 << 1)
77#define GRLIB_UART_STATUS_TE (1 << 2)
78#define GRLIB_UART_STATUS_BR (1 << 3)
79#define GRLIB_UART_STATUS_OV (1 << 4)
80#define GRLIB_UART_STATUS_PE (1 << 5)
81#define GRLIB_UART_STATUS_FE (1 << 6)
82#define GRLIB_UART_STATUS_TH (1 << 7)
83#define GRLIB_UART_STATUS_RH (1 << 8)
84#define GRLIB_UART_STATUS_TF (1 << 9)
85#define GRLIB_UART_STATUS_RF (1 << 10)
86
87#define GRLIB_UART_CONTROL_RE (1 << 0)
88#define GRLIB_UART_CONTROL_TE (1 << 1)
89#define GRLIB_UART_CONTROL_RI (1 << 2)
90#define GRLIB_UART_CONTROL_TI (1 << 3)
91#define GRLIB_UART_CONTROL_PS (1 << 4)
92#define GRLIB_UART_CONTROL_PE (1 << 5)
93#define GRLIB_UART_CONTROL_FL (1 << 6)
94#define GRLIB_UART_CONTROL_LB (1 << 7)
95#define GRLIB_UART_CONTROL_EC (1 << 8)
96#define GRLIB_UART_CONTROL_TF (1 << 9)
97#define GRLIB_UART_CONTROL_RF (1 << 10)
98#define GRLIB_UART_CONTROL_DB (1 << 11)
99#define GRLIB_UART_CONTROL_BI (1 << 12)
100#define GRLIB_UART_CONTROL_DI (1 << 13)
101#define GRLIB_UART_CONTROL_SI (1 << 14)
102#define GRLIB_UART_CONTROL_FA (1 << 31)
103
104typedef struct {
105 unsigned int fa : 1;
106 unsigned int : 16;
107 unsigned int si : 1;
108 unsigned int di : 1;
109 unsigned int bi : 1;
110 unsigned int db : 1;
111 unsigned int rf : 1;
112 unsigned int tf : 1;
113 unsigned int ec : 1;
114 unsigned int lb : 1;
115 unsigned int fl : 1;
116 unsigned int pe : 1;
117 unsigned int ps : 1;
118 unsigned int ti : 1;
119 unsigned int ri : 1;
120 unsigned int te : 1;
121 unsigned int re : 1;
122} grlib_uart_control_t;
123
124/** GRLIB UART registers */
125typedef struct {
126 ioport32_t data;
127 ioport32_t status;
128 ioport32_t control;
129 ioport32_t scaler;
130 ioport32_t debug;
131} grlib_uart_regs_t;
132
133/** The number of bits of one data unit send by the serial port. */
134typedef enum {
135 WORD_LENGTH_5,
136 WORD_LENGTH_6,
137 WORD_LENGTH_7,
138 WORD_LENGTH_8
139} word_length_t;
140
141/** The number of stop bits used by the serial port. */
142typedef enum {
143 /** Use one stop bit. */
144 ONE_STOP_BIT,
145 /** 1.5 stop bits for word length 5, 2 stop bits otherwise. */
146 TWO_STOP_BITS
147} stop_bit_t;
148
149/** The driver data for the serial port devices. */
150typedef struct grlib_uart {
151 /** DDF device node */
152 ddf_dev_t *dev;
153 /** DDF function node */
154 ddf_fun_t *fun;
155 /** I/O registers **/
156 grlib_uart_regs_t *regs;
157 /** Are there any clients connected to the device? */
158 unsigned client_connections;
159 /** The irq assigned to this device. */
160 int irq;
161 /** The base i/o address of the devices registers. */
162 uintptr_t regs_addr;
163 /** The buffer for incoming data. */
164 cyclic_buffer_t input_buffer;
165 /** The fibril mutex for synchronizing the access to the device. */
166 fibril_mutex_t mutex;
167 /** Indicates that some data has become available */
168 fibril_condvar_t input_buffer_available;
169 /** True if device is removed. */
170 bool removed;
171} grlib_uart_t;
172
173/** Obtain soft-state structure from device node */
174static grlib_uart_t *dev_grlib_uart(ddf_dev_t *dev)
175{
176 return ddf_dev_data_get(dev);
177}
178
179/** Obtain soft-state structure from function node */
180static grlib_uart_t *fun_grlib_uart(ddf_fun_t *fun)
181{
182 return dev_grlib_uart(ddf_fun_get_dev(fun));
183}
184
185/** Find out if there is some incoming data available on the serial port.
186 *
187 * @param port The base address of the serial port device's ports.
188 *
189 * @return True if there are data waiting to be read.
190 * @return False otherwise.
191 *
192 */
193static bool grlib_uart_received(grlib_uart_regs_t *regs)
194{
195 return ((pio_read_32(&regs->status) & GRLIB_UART_STATUS_DR) != 0);
196}
197
198/** Read one byte from the serial port.
199 *
200 * @param port The base address of the serial port device's ports.
201 *
202 * @return The data read.
203 *
204 */
205static uint8_t grlib_uart_read_8(grlib_uart_regs_t *regs)
206{
207 return (uint8_t) pio_read_32(&regs->data);
208}
209
210/** Find out wheter it is possible to send data.
211 *
212 * @param port The base address of the serial port device's ports.
213 *
214 */
215static bool is_transmit_empty(grlib_uart_regs_t *regs)
216{
217 return ((pio_read_32(&regs->status) & GRLIB_UART_STATUS_TS) != 0);
218}
219
220/** Write one character on the serial port.
221 *
222 * @param port The base address of the serial port device's ports.
223 * @param c The character to be written to the serial port device.
224 *
225 */
226static void grlib_uart_write_8(grlib_uart_regs_t *regs, uint8_t c)
227{
228 while (!is_transmit_empty(regs));
229
230 pio_write_32(&regs->data, (uint32_t) c);
231}
232
233/** Read data from the serial port device.
234 *
235 * @param fun The serial port function
236 * @param buf The output buffer for read data.
237 * @param count The number of bytes to be read.
238 *
239 * @return The number of bytes actually read on success,
240 * @return Negative error number otherwise.
241 *
242 */
243static int grlib_uart_read(ddf_fun_t *fun, char *buf, size_t count)
244{
245 if (count == 0)
246 return 0;
247
248 grlib_uart_t *ns = fun_grlib_uart(fun);
249
250 fibril_mutex_lock(&ns->mutex);
251
252 while (buf_is_empty(&ns->input_buffer))
253 fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
254
255 int ret = 0;
256 while ((!buf_is_empty(&ns->input_buffer)) && ((size_t) ret < count)) {
257 buf[ret] = (char) buf_pop_front(&ns->input_buffer);
258 ret++;
259 }
260
261 fibril_mutex_unlock(&ns->mutex);
262
263 return ret;
264}
265
266/** Write a character to the serial port.
267 *
268 * @param ns Serial port device
269 * @param c The character to be written
270 *
271 */
272static inline void grlib_uart_putchar(grlib_uart_t *ns, uint8_t c)
273{
274 fibril_mutex_lock(&ns->mutex);
275 grlib_uart_write_8(ns->regs, c);
276 fibril_mutex_unlock(&ns->mutex);
277}
278
279/** Write data to the serial port.
280 *
281 * @param fun The serial port function
282 * @param buf The data to be written
283 * @param count The number of bytes to be written
284 *
285 * @return Zero on success
286 *
287 */
288static int grlib_uart_write(ddf_fun_t *fun, char *buf, size_t count)
289{
290 grlib_uart_t *ns = fun_grlib_uart(fun);
291
292 for (size_t idx = 0; idx < count; idx++)
293 grlib_uart_putchar(ns, (uint8_t) buf[idx]);
294
295 return count;
296}
297
298static ddf_dev_ops_t grlib_uart_dev_ops;
299
300/** The character interface's callbacks. */
301static char_dev_ops_t grlib_uart_char_dev_ops = {
302 .read = &grlib_uart_read,
303 .write = &grlib_uart_write
304};
305
306static int grlib_uart_dev_add(ddf_dev_t *);
307static int grlib_uart_dev_remove(ddf_dev_t *);
308
309/** The serial port device driver's standard operations. */
310static driver_ops_t grlib_uart_ops = {
311 .dev_add = &grlib_uart_dev_add,
312 .dev_remove = &grlib_uart_dev_remove
313};
314
315/** The serial port device driver structure. */
316static driver_t grlib_uart_driver = {
317 .name = NAME,
318 .driver_ops = &grlib_uart_ops
319};
320
321/** Clean up the serial port soft-state
322 *
323 * @param ns Serial port device
324 *
325 */
326static void grlib_uart_dev_cleanup(grlib_uart_t *ns)
327{
328}
329
330/** Enable the i/o ports of the device.
331 *
332 * @param ns Serial port device
333 *
334 * @return True on success, false otherwise
335 *
336 */
337static bool grlib_uart_pio_enable(grlib_uart_t *ns)
338{
339 ddf_msg(LVL_DEBUG, "grlib_uart_pio_enable %s", ddf_dev_get_name(ns->dev));
340
341 /* Gain control over port's registers. */
342 if (pio_enable((void *) ns->regs_addr, REG_COUNT,
343 (void **) &ns->regs)) {
344 ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32
345 " for device %s.", ns->regs_addr, ddf_dev_get_name(ns->dev));
346 return false;
347 }
348
349 return true;
350}
351
352/** Probe the serial port device for its presence.
353 *
354 * @param ns Serial port device
355 *
356 * @return True if the device is present, false otherwise
357 *
358 */
359static bool grlib_uart_dev_probe(grlib_uart_t *ns)
360{
361 ddf_msg(LVL_DEBUG, "grlib_uart_dev_probe %s", ddf_dev_get_name(ns->dev));
362
363 return true;
364}
365
366/** Initialize serial port device.
367 *
368 * @param ns Serial port device
369 *
370 * @return Zero on success, negative error number otherwise
371 *
372 */
373static int grlib_uart_dev_initialize(grlib_uart_t *ns)
374{
375 ddf_msg(LVL_DEBUG, "grlib_uart_dev_initialize %s", ddf_dev_get_name(ns->dev));
376
377 hw_resource_list_t hw_resources;
378 memset(&hw_resources, 0, sizeof(hw_resource_list_t));
379
380 int ret = EOK;
381
382 /* Connect to the parent's driver. */
383 async_sess_t *parent_sess = ddf_dev_parent_sess_create(ns->dev);
384 if (parent_sess == NULL) {
385 ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
386 "device %s.", ddf_dev_get_name(ns->dev));
387 ret = ENOENT;
388 goto failed;
389 }
390
391 /* Get hw resources. */
392 ret = hw_res_get_resource_list(parent_sess, &hw_resources);
393 if (ret != EOK) {
394 ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
395 "%s.", ddf_dev_get_name(ns->dev));
396 goto failed;
397 }
398
399 bool irq = false;
400 bool ioport = false;
401
402 for (size_t i = 0; i < hw_resources.count; i++) {
403 hw_resource_t *res = &hw_resources.resources[i];
404 switch (res->type) {
405 case INTERRUPT:
406 ns->irq = res->res.interrupt.irq;
407 irq = true;
408 ddf_msg(LVL_NOTE, "Device %s was assigned irq = 0x%x.",
409 ddf_dev_get_name(ns->dev), ns->irq);
410 break;
411
412 case MEM_RANGE:
413 ns->regs_addr = res->res.mem_range.address;
414 if (res->res.mem_range.size < REG_COUNT) {
415 ddf_msg(LVL_ERROR, "I/O range assigned to "
416 "device %s is too small.", ddf_dev_get_name(ns->dev));
417 ret = ELIMIT;
418 goto failed;
419 }
420 ioport = true;
421 ddf_msg(LVL_NOTE, "Device %s was assigned I/O address = "
422 "0x%x.", ddf_dev_get_name(ns->dev), ns->regs_addr);
423 break;
424
425 default:
426 break;
427 }
428 }
429
430 if ((!irq) || (!ioport)) {
431 ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
432 ddf_dev_get_name(ns->dev));
433 ret = ENOENT;
434 goto failed;
435 }
436
437 hw_res_clean_resource_list(&hw_resources);
438 return ret;
439
440failed:
441 grlib_uart_dev_cleanup(ns);
442 hw_res_clean_resource_list(&hw_resources);
443 return ret;
444}
445
446/** Enable interrupts on the serial port device.
447 *
448 * Interrupt when data is received
449 *
450 * @param port The base address of the serial port device's ports.
451 *
452 */
453static inline void grlib_uart_port_interrupts_enable(grlib_uart_regs_t *regs)
454{
455 /* Interrupt when data received. */
456 uint32_t control = pio_read_32(&regs->control);
457 pio_write_32(&regs->control, control | GRLIB_UART_CONTROL_RE);
458}
459
460/** Disable interrupts on the serial port device.
461 *
462 * @param port The base address of the serial port device's ports.
463 *
464 */
465static inline void grlib_uart_port_interrupts_disable(grlib_uart_regs_t *regs)
466{
467 uint32_t control = pio_read_32(&regs->control);
468 pio_write_32(&regs->control, control & (~GRLIB_UART_CONTROL_RE));
469}
470
471/** Enable interrupts for the serial port device.
472 *
473 * @param ns Serial port device
474 *
475 * @return Zero on success, negative error number otherwise
476 *
477 */
478static int grlib_uart_interrupt_enable(grlib_uart_t *ns)
479{
480 /* Enable interrupt on the serial port. */
481 grlib_uart_port_interrupts_enable(ns->regs);
482
483 return EOK;
484}
485
486static int grlib_uart_port_set_baud_rate(grlib_uart_regs_t *regs,
487 unsigned int baud_rate)
488{
489 if ((baud_rate < 50) || (MAX_BAUD_RATE % baud_rate != 0)) {
490 ddf_msg(LVL_ERROR, "Invalid baud rate %d requested.",
491 baud_rate);
492 return EINVAL;
493 }
494
495 /* XXX: Set baud rate */
496
497 return EOK;
498}
499
500/** Set the parameters of the serial communication on the serial port device.
501 *
502 * @param parity The parity to be used.
503 * @param word_length The length of one data unit in bits.
504 * @param stop_bits The number of stop bits used (one or two).
505 *
506 * @return Zero on success.
507 * @return EINVAL if some of the specified values is invalid.
508 *
509 */
510static int grlib_uart_port_set_com_props(grlib_uart_regs_t *regs,
511 unsigned int parity, unsigned int word_length, unsigned int stop_bits)
512{
513 uint32_t val = pio_read_32(&regs->control);
514
515 switch (parity) {
516 case SERIAL_NO_PARITY:
517 case SERIAL_ODD_PARITY:
518 case SERIAL_EVEN_PARITY:
519 case SERIAL_MARK_PARITY:
520 case SERIAL_SPACE_PARITY:
521 val |= GRLIB_UART_CONTROL_PE;
522 break;
523 default:
524 return EINVAL;
525 }
526
527 pio_write_32(&regs->control, val);
528
529 return EOK;
530}
531
532/** Initialize the serial port device.
533 *
534 * Set the default parameters of the serial communication.
535 *
536 * @param ns Serial port device
537 *
538 */
539static void grlib_uart_initialize_port(grlib_uart_t *ns)
540{
541 /* Disable interrupts. */
542 grlib_uart_port_interrupts_disable(ns->regs);
543
544 /* Set baud rate. */
545 grlib_uart_port_set_baud_rate(ns->regs, 38400);
546
547 /* 8 bits, no parity, two stop bits. */
548 grlib_uart_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
549
550 /*
551 * Enable FIFO, clear them, with 4-byte threshold for greater
552 * reliability.
553 */
554 pio_write_32(&ns->regs->control, GRLIB_UART_CONTROL_RE |
555 GRLIB_UART_CONTROL_TE | GRLIB_UART_CONTROL_RF |
556 GRLIB_UART_CONTROL_TF | GRLIB_UART_CONTROL_RI |
557 GRLIB_UART_CONTROL_FA);
558}
559
560/** Deinitialize the serial port device.
561 *
562 * @param ns Serial port device
563 *
564 */
565static void grlib_uart_port_cleanup(grlib_uart_t *ns)
566{
567 grlib_uart_port_interrupts_disable(ns->regs);
568}
569
570/** Read the data from the serial port device and store them to the input
571 * buffer.
572 *
573 * @param ns Serial port device
574 *
575 */
576static void grlib_uart_read_from_device(grlib_uart_t *ns)
577{
578 grlib_uart_regs_t *regs = ns->regs;
579 bool cont = true;
580
581 fibril_mutex_lock(&ns->mutex);
582
583 while (cont) {
584 cont = grlib_uart_received(regs);
585 if (cont) {
586 uint8_t val = grlib_uart_read_8(regs);
587
588 if (ns->client_connections > 0) {
589 bool buf_was_empty = buf_is_empty(&ns->input_buffer);
590 if (!buf_push_back(&ns->input_buffer, val)) {
591 ddf_msg(LVL_WARN, "Buffer overflow on "
592 "%s.", ddf_dev_get_name(ns->dev));
593 break;
594 } else {
595 ddf_msg(LVL_DEBUG2, "Character %c saved "
596 "to the buffer of %s.",
597 val, ddf_dev_get_name(ns->dev));
598 if (buf_was_empty)
599 fibril_condvar_broadcast(&ns->input_buffer_available);
600 }
601 }
602 }
603 }
604
605 fibril_mutex_unlock(&ns->mutex);
606 fibril_yield();
607}
608
609/** The interrupt handler.
610 *
611 * The serial port is initialized to interrupt when some data come or line
612 * status register changes, so the interrupt is handled by reading the incoming
613 * data and reading the line status register.
614 *
615 * @param dev The serial port device.
616 *
617 */
618static inline void grlib_uart_interrupt_handler(ddf_dev_t *dev,
619 ipc_callid_t iid, ipc_call_t *icall)
620{
621 grlib_uart_t *ns = dev_grlib_uart(dev);
622
623 uint32_t status = pio_read_32(&ns->regs->status);
624
625 if (status & GRLIB_UART_STATUS_RF) {
626 if (status & GRLIB_UART_STATUS_OV)
627 ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev));
628 }
629
630 grlib_uart_read_from_device(ns);
631}
632
633/** Register the interrupt handler for the device.
634 *
635 * @param ns Serial port device
636 *
637 */
638static inline int grlib_uart_register_interrupt_handler(grlib_uart_t *ns)
639{
640 return register_interrupt_handler(ns->dev, ns->irq,
641 grlib_uart_interrupt_handler, NULL);
642}
643
644/** Unregister the interrupt handler for the device.
645 *
646 * @param ns Serial port device
647 *
648 */
649static inline int grlib_uart_unregister_interrupt_handler(grlib_uart_t *ns)
650{
651 return unregister_interrupt_handler(ns->dev, ns->irq);
652}
653
654/** The dev_add callback method of the serial port driver.
655 *
656 * Probe and initialize the newly added device.
657 *
658 * @param dev The serial port device.
659 *
660 */
661static int grlib_uart_dev_add(ddf_dev_t *dev)
662{
663 grlib_uart_t *ns = NULL;
664 ddf_fun_t *fun = NULL;
665 bool need_cleanup = false;
666 bool need_unreg_intr_handler = false;
667 int rc;
668
669 ddf_msg(LVL_DEBUG, "grlib_uart_dev_add %s (handle = %d)",
670 ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
671
672 /* Allocate soft-state for the device */
673 ns = ddf_dev_data_alloc(dev, sizeof(grlib_uart_t));
674 if (ns == NULL) {
675 rc = ENOMEM;
676 goto fail;
677 }
678
679 fibril_mutex_initialize(&ns->mutex);
680 fibril_condvar_initialize(&ns->input_buffer_available);
681 ns->dev = dev;
682
683 rc = grlib_uart_dev_initialize(ns);
684 if (rc != EOK)
685 goto fail;
686
687 need_cleanup = true;
688
689 if (!grlib_uart_pio_enable(ns)) {
690 rc = EADDRNOTAVAIL;
691 goto fail;
692 }
693
694 /* Find out whether the device is present. */
695 if (!grlib_uart_dev_probe(ns)) {
696 rc = ENOENT;
697 goto fail;
698 }
699
700 /* Serial port initialization (baud rate etc.). */
701 grlib_uart_initialize_port(ns);
702
703 /* Register interrupt handler. */
704 if (grlib_uart_register_interrupt_handler(ns) != EOK) {
705 ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
706 rc = EADDRNOTAVAIL;
707 goto fail;
708 }
709 need_unreg_intr_handler = true;
710
711 /* Enable interrupt. */
712 rc = grlib_uart_interrupt_enable(ns);
713 if (rc != EOK) {
714 ddf_msg(LVL_ERROR, "Failed to enable the interrupt. Error code = "
715 "%d.", rc);
716 goto fail;
717 }
718
719 fun = ddf_fun_create(dev, fun_exposed, "a");
720 if (fun == NULL) {
721 ddf_msg(LVL_ERROR, "Failed creating function.");
722 goto fail;
723 }
724
725 /* Set device operations. */
726 ddf_fun_set_ops(fun, &grlib_uart_dev_ops);
727 rc = ddf_fun_bind(fun);
728 if (rc != EOK) {
729 ddf_msg(LVL_ERROR, "Failed binding function.");
730 goto fail;
731 }
732
733 ns->fun = fun;
734
735 ddf_fun_add_to_category(fun, "serial");
736
737 ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
738 ddf_dev_get_name(dev));
739
740 return EOK;
741
742fail:
743 if (fun != NULL)
744 ddf_fun_destroy(fun);
745
746 if (need_unreg_intr_handler)
747 grlib_uart_unregister_interrupt_handler(ns);
748
749 if (need_cleanup)
750 grlib_uart_dev_cleanup(ns);
751
752 return rc;
753}
754
755static int grlib_uart_dev_remove(ddf_dev_t *dev)
756{
757 grlib_uart_t *ns = dev_grlib_uart(dev);
758
759 fibril_mutex_lock(&ns->mutex);
760 if (ns->client_connections > 0) {
761 fibril_mutex_unlock(&ns->mutex);
762 return EBUSY;
763 }
764 ns->removed = true;
765 fibril_mutex_unlock(&ns->mutex);
766
767 int rc = ddf_fun_unbind(ns->fun);
768 if (rc != EOK) {
769 ddf_msg(LVL_ERROR, "Failed to unbind function.");
770 return rc;
771 }
772
773 ddf_fun_destroy(ns->fun);
774
775 grlib_uart_port_cleanup(ns);
776 grlib_uart_unregister_interrupt_handler(ns);
777 grlib_uart_dev_cleanup(ns);
778 return EOK;
779}
780
781/** Open the device.
782 *
783 * This is a callback function called when a client tries to connect to the
784 * device.
785 *
786 * @param dev The device.
787 *
788 */
789static int grlib_uart_open(ddf_fun_t *fun)
790{
791 grlib_uart_t *ns = fun_grlib_uart(fun);
792 int res;
793
794 fibril_mutex_lock(&ns->mutex);
795 if (ns->removed) {
796 res = ENXIO;
797 } else {
798 res = EOK;
799 ns->client_connections++;
800 }
801 fibril_mutex_unlock(&ns->mutex);
802
803 return res;
804}
805
806/** Close the device.
807 *
808 * This is a callback function called when a client tries to disconnect from
809 * the device.
810 *
811 * @param dev The device.
812 *
813 */
814static void grlib_uart_close(ddf_fun_t *fun)
815{
816 grlib_uart_t *data = fun_grlib_uart(fun);
817
818 fibril_mutex_lock(&data->mutex);
819
820 assert(data->client_connections > 0);
821
822 if (!(--data->client_connections))
823 buf_clear(&data->input_buffer);
824
825 fibril_mutex_unlock(&data->mutex);
826}
827
828/** Default handler for client requests which are not handled by the standard
829 * interfaces.
830 *
831 * Configure the parameters of the serial communication.
832 *
833 */
834static void grlib_uart_default_handler(ddf_fun_t *fun, ipc_callid_t callid,
835 ipc_call_t *call)
836{
837 sysarg_t method = IPC_GET_IMETHOD(*call);
838
839 switch (method) {
840 default:
841 async_answer_0(callid, ENOTSUP);
842 }
843}
844
845/** Initialize the serial port driver.
846 *
847 * Initialize device operations structures with callback methods for handling
848 * client requests to the serial port devices.
849 *
850 */
851static void grlib_uart_init(void)
852{
853 ddf_log_init(NAME);
854
855 grlib_uart_dev_ops.open = &grlib_uart_open;
856 grlib_uart_dev_ops.close = &grlib_uart_close;
857
858 grlib_uart_dev_ops.interfaces[CHAR_DEV_IFACE] = &grlib_uart_char_dev_ops;
859 grlib_uart_dev_ops.default_handler = &grlib_uart_default_handler;
860}
861
862int main(int argc, char *argv[])
863{
864 printf("%s: HelenOS serial port driver\n", NAME);
865 grlib_uart_init();
866 return ddf_driver_main(&grlib_uart_driver);
867}
868
869/**
870 * @}
871 */
Note: See TracBrowser for help on using the repository browser.