source: mainline/uspace/drv/char/grlib_uart/grlib_uart.c@ 208b5f5

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

cherrypick important fixes and updates from lp:~jceel/helenos/leon3

  • 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 EXCHANGE_SERIALIZE);
385 if (parent_sess == NULL) {
386 ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
387 "device %s.", ddf_dev_get_name(ns->dev));
388 ret = ENOENT;
389 goto failed;
390 }
391
392 /* Get hw resources. */
393 ret = hw_res_get_resource_list(parent_sess, &hw_resources);
394 if (ret != EOK) {
395 ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
396 "%s.", ddf_dev_get_name(ns->dev));
397 goto failed;
398 }
399
400 bool irq = false;
401 bool ioport = false;
402
403 for (size_t i = 0; i < hw_resources.count; i++) {
404 hw_resource_t *res = &hw_resources.resources[i];
405 switch (res->type) {
406 case INTERRUPT:
407 ns->irq = res->res.interrupt.irq;
408 irq = true;
409 ddf_msg(LVL_NOTE, "Device %s was assigned irq = 0x%x.",
410 ddf_dev_get_name(ns->dev), ns->irq);
411 break;
412
413 case MEM_RANGE:
414 ns->regs_addr = res->res.mem_range.address;
415 if (res->res.mem_range.size < REG_COUNT) {
416 ddf_msg(LVL_ERROR, "I/O range assigned to "
417 "device %s is too small.", ddf_dev_get_name(ns->dev));
418 ret = ELIMIT;
419 goto failed;
420 }
421 ioport = true;
422 ddf_msg(LVL_NOTE, "Device %s was assigned I/O address = "
423 "0x%x.", ddf_dev_get_name(ns->dev), ns->regs_addr);
424 break;
425
426 default:
427 break;
428 }
429 }
430
431 if ((!irq) || (!ioport)) {
432 ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
433 ddf_dev_get_name(ns->dev));
434 ret = ENOENT;
435 goto failed;
436 }
437
438 hw_res_clean_resource_list(&hw_resources);
439 return ret;
440
441failed:
442 grlib_uart_dev_cleanup(ns);
443 hw_res_clean_resource_list(&hw_resources);
444 return ret;
445}
446
447/** Enable interrupts on the serial port device.
448 *
449 * Interrupt when data is received
450 *
451 * @param port The base address of the serial port device's ports.
452 *
453 */
454static inline void grlib_uart_port_interrupts_enable(grlib_uart_regs_t *regs)
455{
456 /* Interrupt when data received. */
457 uint32_t control = pio_read_32(&regs->control);
458 pio_write_32(&regs->control, control | GRLIB_UART_CONTROL_RE);
459}
460
461/** Disable interrupts on the serial port device.
462 *
463 * @param port The base address of the serial port device's ports.
464 *
465 */
466static inline void grlib_uart_port_interrupts_disable(grlib_uart_regs_t *regs)
467{
468 uint32_t control = pio_read_32(&regs->control);
469 pio_write_32(&regs->control, control & (~GRLIB_UART_CONTROL_RE));
470}
471
472/** Enable interrupts for the serial port device.
473 *
474 * @param ns Serial port device
475 *
476 * @return Zero on success, negative error number otherwise
477 *
478 */
479static int grlib_uart_interrupt_enable(grlib_uart_t *ns)
480{
481 /* Enable interrupt on the serial port. */
482 grlib_uart_port_interrupts_enable(ns->regs);
483
484 return EOK;
485}
486
487static int grlib_uart_port_set_baud_rate(grlib_uart_regs_t *regs,
488 unsigned int baud_rate)
489{
490 if ((baud_rate < 50) || (MAX_BAUD_RATE % baud_rate != 0)) {
491 ddf_msg(LVL_ERROR, "Invalid baud rate %d requested.",
492 baud_rate);
493 return EINVAL;
494 }
495
496 /* XXX: Set baud rate */
497
498 return EOK;
499}
500
501/** Set the parameters of the serial communication on the serial port device.
502 *
503 * @param parity The parity to be used.
504 * @param word_length The length of one data unit in bits.
505 * @param stop_bits The number of stop bits used (one or two).
506 *
507 * @return Zero on success.
508 * @return EINVAL if some of the specified values is invalid.
509 *
510 */
511static int grlib_uart_port_set_com_props(grlib_uart_regs_t *regs,
512 unsigned int parity, unsigned int word_length, unsigned int stop_bits)
513{
514 uint32_t val = pio_read_32(&regs->control);
515
516 switch (parity) {
517 case SERIAL_NO_PARITY:
518 case SERIAL_ODD_PARITY:
519 case SERIAL_EVEN_PARITY:
520 case SERIAL_MARK_PARITY:
521 case SERIAL_SPACE_PARITY:
522 val |= GRLIB_UART_CONTROL_PE;
523 break;
524 default:
525 return EINVAL;
526 }
527
528 pio_write_32(&regs->control, val);
529
530 return EOK;
531}
532
533/** Initialize the serial port device.
534 *
535 * Set the default parameters of the serial communication.
536 *
537 * @param ns Serial port device
538 *
539 */
540static void grlib_uart_initialize_port(grlib_uart_t *ns)
541{
542 /* Disable interrupts. */
543 grlib_uart_port_interrupts_disable(ns->regs);
544
545 /* Set baud rate. */
546 grlib_uart_port_set_baud_rate(ns->regs, 38400);
547
548 /* 8 bits, no parity, two stop bits. */
549 grlib_uart_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
550
551 /*
552 * Enable FIFO, clear them, with 4-byte threshold for greater
553 * reliability.
554 */
555 pio_write_32(&ns->regs->control, GRLIB_UART_CONTROL_RE |
556 GRLIB_UART_CONTROL_TE | GRLIB_UART_CONTROL_RF |
557 GRLIB_UART_CONTROL_TF | GRLIB_UART_CONTROL_RI |
558 GRLIB_UART_CONTROL_FA);
559}
560
561/** Deinitialize the serial port device.
562 *
563 * @param ns Serial port device
564 *
565 */
566static void grlib_uart_port_cleanup(grlib_uart_t *ns)
567{
568 grlib_uart_port_interrupts_disable(ns->regs);
569}
570
571/** Read the data from the serial port device and store them to the input
572 * buffer.
573 *
574 * @param ns Serial port device
575 *
576 */
577static void grlib_uart_read_from_device(grlib_uart_t *ns)
578{
579 grlib_uart_regs_t *regs = ns->regs;
580 bool cont = true;
581
582 fibril_mutex_lock(&ns->mutex);
583
584 while (cont) {
585 cont = grlib_uart_received(regs);
586 if (cont) {
587 uint8_t val = grlib_uart_read_8(regs);
588
589 if (ns->client_connections > 0) {
590 bool buf_was_empty = buf_is_empty(&ns->input_buffer);
591 if (!buf_push_back(&ns->input_buffer, val)) {
592 ddf_msg(LVL_WARN, "Buffer overflow on "
593 "%s.", ddf_dev_get_name(ns->dev));
594 break;
595 } else {
596 ddf_msg(LVL_DEBUG2, "Character %c saved "
597 "to the buffer of %s.",
598 val, ddf_dev_get_name(ns->dev));
599 if (buf_was_empty)
600 fibril_condvar_broadcast(&ns->input_buffer_available);
601 }
602 }
603 }
604 }
605
606 fibril_mutex_unlock(&ns->mutex);
607 fibril_yield();
608}
609
610/** The interrupt handler.
611 *
612 * The serial port is initialized to interrupt when some data come or line
613 * status register changes, so the interrupt is handled by reading the incoming
614 * data and reading the line status register.
615 *
616 * @param dev The serial port device.
617 *
618 */
619static inline void grlib_uart_interrupt_handler(ddf_dev_t *dev,
620 ipc_callid_t iid, ipc_call_t *icall)
621{
622 grlib_uart_t *ns = dev_grlib_uart(dev);
623
624 uint32_t status = pio_read_32(&ns->regs->status);
625
626 if (status & GRLIB_UART_STATUS_RF) {
627 if (status & GRLIB_UART_STATUS_OV)
628 ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev));
629 }
630
631 grlib_uart_read_from_device(ns);
632}
633
634/** Register the interrupt handler for the device.
635 *
636 * @param ns Serial port device
637 *
638 */
639static inline int grlib_uart_register_interrupt_handler(grlib_uart_t *ns)
640{
641 return register_interrupt_handler(ns->dev, ns->irq,
642 grlib_uart_interrupt_handler, NULL);
643}
644
645/** Unregister the interrupt handler for the device.
646 *
647 * @param ns Serial port device
648 *
649 */
650static inline int grlib_uart_unregister_interrupt_handler(grlib_uart_t *ns)
651{
652 return unregister_interrupt_handler(ns->dev, ns->irq);
653}
654
655/** The dev_add callback method of the serial port driver.
656 *
657 * Probe and initialize the newly added device.
658 *
659 * @param dev The serial port device.
660 *
661 */
662static int grlib_uart_dev_add(ddf_dev_t *dev)
663{
664 grlib_uart_t *ns = NULL;
665 ddf_fun_t *fun = NULL;
666 bool need_cleanup = false;
667 bool need_unreg_intr_handler = false;
668 int rc;
669
670 ddf_msg(LVL_DEBUG, "grlib_uart_dev_add %s (handle = %d)",
671 ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
672
673 /* Allocate soft-state for the device */
674 ns = ddf_dev_data_alloc(dev, sizeof(grlib_uart_t));
675 if (ns == NULL) {
676 rc = ENOMEM;
677 goto fail;
678 }
679
680 fibril_mutex_initialize(&ns->mutex);
681 fibril_condvar_initialize(&ns->input_buffer_available);
682 ns->dev = dev;
683
684 rc = grlib_uart_dev_initialize(ns);
685 if (rc != EOK)
686 goto fail;
687
688 need_cleanup = true;
689
690 if (!grlib_uart_pio_enable(ns)) {
691 rc = EADDRNOTAVAIL;
692 goto fail;
693 }
694
695 /* Find out whether the device is present. */
696 if (!grlib_uart_dev_probe(ns)) {
697 rc = ENOENT;
698 goto fail;
699 }
700
701 /* Serial port initialization (baud rate etc.). */
702 grlib_uart_initialize_port(ns);
703
704 /* Register interrupt handler. */
705 if (grlib_uart_register_interrupt_handler(ns) != EOK) {
706 ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
707 rc = EADDRNOTAVAIL;
708 goto fail;
709 }
710 need_unreg_intr_handler = true;
711
712 /* Enable interrupt. */
713 rc = grlib_uart_interrupt_enable(ns);
714 if (rc != EOK) {
715 ddf_msg(LVL_ERROR, "Failed to enable the interrupt. Error code = "
716 "%d.", rc);
717 goto fail;
718 }
719
720 fun = ddf_fun_create(dev, fun_exposed, "a");
721 if (fun == NULL) {
722 ddf_msg(LVL_ERROR, "Failed creating function.");
723 goto fail;
724 }
725
726 /* Set device operations. */
727 ddf_fun_set_ops(fun, &grlib_uart_dev_ops);
728 rc = ddf_fun_bind(fun);
729 if (rc != EOK) {
730 ddf_msg(LVL_ERROR, "Failed binding function.");
731 goto fail;
732 }
733
734 ns->fun = fun;
735
736 ddf_fun_add_to_category(fun, "serial");
737
738 ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
739 ddf_dev_get_name(dev));
740
741 return EOK;
742
743fail:
744 if (fun != NULL)
745 ddf_fun_destroy(fun);
746
747 if (need_unreg_intr_handler)
748 grlib_uart_unregister_interrupt_handler(ns);
749
750 if (need_cleanup)
751 grlib_uart_dev_cleanup(ns);
752
753 return rc;
754}
755
756static int grlib_uart_dev_remove(ddf_dev_t *dev)
757{
758 grlib_uart_t *ns = dev_grlib_uart(dev);
759
760 fibril_mutex_lock(&ns->mutex);
761 if (ns->client_connections > 0) {
762 fibril_mutex_unlock(&ns->mutex);
763 return EBUSY;
764 }
765 ns->removed = true;
766 fibril_mutex_unlock(&ns->mutex);
767
768 int rc = ddf_fun_unbind(ns->fun);
769 if (rc != EOK) {
770 ddf_msg(LVL_ERROR, "Failed to unbind function.");
771 return rc;
772 }
773
774 ddf_fun_destroy(ns->fun);
775
776 grlib_uart_port_cleanup(ns);
777 grlib_uart_unregister_interrupt_handler(ns);
778 grlib_uart_dev_cleanup(ns);
779 return EOK;
780}
781
782/** Open the device.
783 *
784 * This is a callback function called when a client tries to connect to the
785 * device.
786 *
787 * @param dev The device.
788 *
789 */
790static int grlib_uart_open(ddf_fun_t *fun)
791{
792 grlib_uart_t *ns = fun_grlib_uart(fun);
793 int res;
794
795 fibril_mutex_lock(&ns->mutex);
796 if (ns->removed) {
797 res = ENXIO;
798 } else {
799 res = EOK;
800 ns->client_connections++;
801 }
802 fibril_mutex_unlock(&ns->mutex);
803
804 return res;
805}
806
807/** Close the device.
808 *
809 * This is a callback function called when a client tries to disconnect from
810 * the device.
811 *
812 * @param dev The device.
813 *
814 */
815static void grlib_uart_close(ddf_fun_t *fun)
816{
817 grlib_uart_t *data = fun_grlib_uart(fun);
818
819 fibril_mutex_lock(&data->mutex);
820
821 assert(data->client_connections > 0);
822
823 if (!(--data->client_connections))
824 buf_clear(&data->input_buffer);
825
826 fibril_mutex_unlock(&data->mutex);
827}
828
829/** Default handler for client requests which are not handled by the standard
830 * interfaces.
831 *
832 * Configure the parameters of the serial communication.
833 *
834 */
835static void grlib_uart_default_handler(ddf_fun_t *fun, ipc_callid_t callid,
836 ipc_call_t *call)
837{
838 sysarg_t method = IPC_GET_IMETHOD(*call);
839
840 switch (method) {
841 default:
842 async_answer_0(callid, ENOTSUP);
843 }
844}
845
846/** Initialize the serial port driver.
847 *
848 * Initialize device operations structures with callback methods for handling
849 * client requests to the serial port devices.
850 *
851 */
852static void grlib_uart_init(void)
853{
854 ddf_log_init(NAME);
855
856 grlib_uart_dev_ops.open = &grlib_uart_open;
857 grlib_uart_dev_ops.close = &grlib_uart_close;
858
859 grlib_uart_dev_ops.interfaces[CHAR_DEV_IFACE] = &grlib_uart_char_dev_ops;
860 grlib_uart_dev_ops.default_handler = &grlib_uart_default_handler;
861}
862
863int main(int argc, char *argv[])
864{
865 printf("%s: HelenOS serial port driver\n", NAME);
866 grlib_uart_init();
867 return ddf_driver_main(&grlib_uart_driver);
868}
869
870/**
871 * @}
872 */
Note: See TracBrowser for help on using the repository browser.