source: mainline/uspace/drv/char/ns8250/ns8250.c@ 516e780

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 516e780 was 4122410, checked in by Jakub Jermar <jakub@…>, 7 years ago

Improve Doxygen documentaion

This is stil WiP. A number of libraries, drivers and services were
converted to using a more hierarchical and decentralized scheme when it
comes to specifying to which doxygen group they belong.

  • Property mode set to 100644
File size: 28.4 KB
RevLine 
[68414f4a]1/*
[5fe1c32]2 * Copyright (c) 2010 Lenka Trochtova
[74017ce]3 * Copyright (c) 2017 Jiri Svoboda
[5fe1c32]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/**
[4122410]31 * @addtogroup ns8250
[5fe1c32]32 * @{
33 */
34
35/** @file
36 */
37
38#include <assert.h>
39#include <stdio.h>
40#include <errno.h>
[dd8ab1c]41#include <str_error.h>
[3e6a98c5]42#include <stdbool.h>
[5fe1c32]43#include <fibril_synch.h>
44#include <stdlib.h>
[c47e1a8]45#include <str.h>
[5fe1c32]46#include <ctype.h>
47#include <macros.h>
[38d150e]48#include <stdlib.h>
[5fe1c32]49#include <dirent.h>
[1f8657b]50#include <ddi.h>
[5fe1c32]51
[af6b5157]52#include <ddf/driver.h>
53#include <ddf/interrupt.h>
[fc51296]54#include <ddf/log.h>
[74017ce]55#include <io/chardev_srv.h>
[5fe1c32]56
57#include <device/hw_res.h>
[f4ef3c2]58#include <ipc/serial_ctl.h>
[5fe1c32]59
[1f8657b]60#include "cyclic_buffer.h"
61
[04c7003f]62#define NAME "ns8250"
[5fe1c32]63
[1f8657b]64#define REG_COUNT 7
[f4ef3c2]65#define MAX_BAUD_RATE 115200
[cf8cc36]66#define DLAB_MASK (1 << 7)
67
[c7235d40]68/** Interrupt Enable Register definition. */
69#define NS8250_IER_RXREADY (1 << 0)
70#define NS8250_IER_THRE (1 << 1)
71#define NS8250_IER_RXSTATUS (1 << 2)
72#define NS8250_IER_MODEM_STATUS (1 << 3)
73
74/** Interrupt ID Register definition. */
75#define NS8250_IID_ACTIVE (1 << 0)
[e0cd9042]76#define NS8250_IID_CAUSE_MASK 0x0e
77#define NS8250_IID_CAUSE_RXSTATUS 0x06
[c7235d40]78
79/** FIFO Control Register definition. */
80#define NS8250_FCR_FIFOENABLE (1 << 0)
81#define NS8250_FCR_RXFIFORESET (1 << 1)
82#define NS8250_FCR_TXFIFORESET (1 << 2)
83#define NS8250_FCR_DMAMODE (1 << 3)
84#define NS8250_FCR_RXTRIGGERLOW (1 << 6)
85#define NS8250_FCR_RXTRIGGERHI (1 << 7)
86
87/** Line Control Register definition. */
88#define NS8250_LCR_STOPBITS (1 << 2)
89#define NS8250_LCR_PARITY (1 << 3)
90#define NS8250_LCR_SENDBREAK (1 << 6)
91#define NS8250_LCR_DLAB (1 << 7)
92
93/** Modem Control Register definition. */
94#define NS8250_MCR_DTR (1 << 0)
95#define NS8250_MCR_RTS (1 << 1)
96#define NS8250_MCR_OUT1 (1 << 2)
97#define NS8250_MCR_OUT2 (1 << 3)
98#define NS8250_MCR_LOOPBACK (1 << 4)
99#define NS8250_MCR_ALL (0x1f)
100
101/** Line Status Register definition. */
102#define NS8250_LSR_RXREADY (1 << 0)
103#define NS8250_LSR_OE (1 << 1)
104#define NS8250_LSR_PE (1 << 2)
105#define NS8250_LSR_FE (1 << 3)
106#define NS8250_LSR_BREAK (1 << 4)
107#define NS8250_LSR_THRE (1 << 5)
108#define NS8250_LSR_TSE (1 << 6)
109
110/** Modem Status Register definition. */
111#define NS8250_MSR_DELTACTS (1 << 0)
112#define NS8250_MSR_DELTADSR (1 << 1)
113#define NS8250_MSR_RITRAILING (1 << 2)
114#define NS8250_MSR_DELTADCD (1 << 3)
115#define NS8250_MSR_CTS (1 << 4)
116#define NS8250_MSR_DSR (1 << 5)
117#define NS8250_MSR_RI (1 << 6)
118#define NS8250_MSR_DCD (1 << 7)
119#define NS8250_MSR_SIGNALS (NS8250_MSR_CTS | NS8250_MSR_DSR \
120 | NS8250_MSR_RI | NS8250_MSR_DCD)
121
[49698fa]122/** The number of bits of one data unit send by the serial port. */
[cf8cc36]123typedef enum {
124 WORD_LENGTH_5,
125 WORD_LENGTH_6,
126 WORD_LENGTH_7,
[49698fa]127 WORD_LENGTH_8
[cf8cc36]128} word_length_t;
129
130/** The number of stop bits used by the serial port. */
131typedef enum {
132 /** Use one stop bit. */
133 ONE_STOP_BIT,
134 /** 1.5 stop bits for word length 5, 2 stop bits otherwise. */
[49698fa]135 TWO_STOP_BITS
[cf8cc36]136} stop_bit_t;
137
[c7235d40]138/** 8250 UART registers layout. */
139typedef struct {
140 ioport8_t data; /**< Data register. */
141 ioport8_t ier; /**< Interrupt Enable Reg. */
142 ioport8_t iid; /**< Interrupt ID Reg. */
143 ioport8_t lcr; /**< Line Control Reg. */
144 ioport8_t mcr; /**< Modem Control Reg. */
145 ioport8_t lsr; /**< Line Status Reg. */
146 ioport8_t msr; /**< Modem Status Reg. */
147} ns8250_regs_t;
148
[49698fa]149/** The driver data for the serial port devices. */
[68414f4a]150typedef struct ns8250 {
151 /** DDF device node */
[83a2f43]152 ddf_dev_t *dev;
[68414f4a]153 /** DDF function node */
[83a2f43]154 ddf_fun_t *fun;
[74017ce]155 /** Character device service */
156 chardev_srvs_t cds;
[d51838f]157 /** Parent session */
158 async_sess_t *parent_sess;
[c7235d40]159 /** I/O registers **/
160 ns8250_regs_t *regs;
[4510e06]161 /** Are there any clients connected to the device? */
162 unsigned client_connections;
[cf8cc36]163 /** The irq assigned to this device. */
[1f8657b]164 int irq;
[3f74275]165 /** IRQ capability handle */
[eadaeae8]166 cap_irq_handle_t irq_handle;
[cf8cc36]167 /** The base i/o address of the devices registers. */
[340513c]168 uintptr_t io_addr;
[cf8cc36]169 /** The i/o port used to access the serial ports registers. */
[1f8657b]170 ioport8_t *port;
[381ff2f]171 /** The buffer for incoming data. */
[1f8657b]172 cyclic_buffer_t input_buffer;
[49698fa]173 /** The fibril mutex for synchronizing the access to the device. */
174 fibril_mutex_t mutex;
[91ecaa10]175 /** Indicates that some data has become available */
176 fibril_condvar_t input_buffer_available;
[5b68e0c]177 /** True if device is removed. */
178 bool removed;
[68414f4a]179} ns8250_t;
[5fe1c32]180
[56fd7cf]181/** Obtain soft-state structure from device node */
182static ns8250_t *dev_ns8250(ddf_dev_t *dev)
183{
184 return ddf_dev_data_get(dev);
185}
186
187/** Obtain soft-state structure from function node */
188static ns8250_t *fun_ns8250(ddf_fun_t *fun)
189{
190 return dev_ns8250(ddf_fun_get_dev(fun));
191}
192
[74017ce]193/** Obtain soft-state structure from chardev srv */
194static ns8250_t *srv_ns8250(chardev_srv_t *srv)
195{
196 return (ns8250_t *)srv->srvs->sarg;
197}
198
199
[381ff2f]200/** Find out if there is some incoming data available on the serial port.
[49698fa]201 *
202 * @param port The base address of the serial port device's ports.
203 * @return True if there are data waiting to be read, false
204 * otherwise.
[cf8cc36]205 */
[c7235d40]206static bool ns8250_received(ns8250_regs_t *regs)
[ca97cad]207{
[c7235d40]208 return (pio_read_8(&regs->lsr) & NS8250_LSR_RXREADY) != 0;
[ca97cad]209}
210
[cf8cc36]211/** Read one byte from the serial port.
[49698fa]212 *
213 * @param port The base address of the serial port device's ports.
214 * @return The data read.
[cf8cc36]215 */
[c7235d40]216static uint8_t ns8250_read_8(ns8250_regs_t *regs)
[ca97cad]217{
[c7235d40]218 return pio_read_8(&regs->data);
[ca97cad]219}
220
[cf8cc36]221/** Find out wheter it is possible to send data.
[49698fa]222 *
223 * @param port The base address of the serial port device's ports.
[cf8cc36]224 */
[c7235d40]225static bool is_transmit_empty(ns8250_regs_t *regs)
[ca97cad]226{
[c7235d40]227 return (pio_read_8(&regs->lsr) & NS8250_LSR_THRE) != 0;
[ca97cad]228}
229
[cf8cc36]230/** Write one character on the serial port.
[49698fa]231 *
232 * @param port The base address of the serial port device's ports.
233 * @param c The character to be written to the serial port device.
[cf8cc36]234 */
[c7235d40]235static void ns8250_write_8(ns8250_regs_t *regs, uint8_t c)
[ca97cad]236{
[c7235d40]237 while (!is_transmit_empty(regs))
[ca97cad]238 ;
[a35b458]239
[c7235d40]240 pio_write_8(&regs->data, c);
[ca97cad]241}
242
[cf8cc36]243/** Read data from the serial port device.
[49698fa]244 *
[74017ce]245 * @param srv Server-side connection data
[956d4281]246 * @param buf The output buffer for read data.
[49698fa]247 * @param count The number of bytes to be read.
[74017ce]248 * @param nread Place to store number of bytes actually read
[49698fa]249 *
[74017ce]250 * @return EOK on success or non-zero error code
[cf8cc36]251 */
[b7fd2a0]252static errno_t ns8250_read(chardev_srv_t *srv, void *buf, size_t count, size_t *nread)
[f658458]253{
[74017ce]254 ns8250_t *ns = srv_ns8250(srv);
255 char *bp = (char *) buf;
256 size_t pos = 0;
[a35b458]257
[74017ce]258 if (count == 0) {
259 *nread = 0;
260 return EOK;
261 }
[a35b458]262
[68414f4a]263 fibril_mutex_lock(&ns->mutex);
[91ecaa10]264 while (buf_is_empty(&ns->input_buffer))
265 fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
[74017ce]266 while (!buf_is_empty(&ns->input_buffer) && pos < count) {
267 bp[pos] = (char)buf_pop_front(&ns->input_buffer);
268 pos++;
[bb864a0]269 }
[68414f4a]270 fibril_mutex_unlock(&ns->mutex);
[a35b458]271
[74017ce]272 *nread = pos;
273 return EOK;
[f658458]274}
275
[cf8cc36]276/** Write a character to the serial port.
[49698fa]277 *
[68414f4a]278 * @param ns Serial port device
279 * @param c The character to be written
[cf8cc36]280 */
[68414f4a]281static inline void ns8250_putchar(ns8250_t *ns, uint8_t c)
[49698fa]282{
[68414f4a]283 fibril_mutex_lock(&ns->mutex);
[c7235d40]284 ns8250_write_8(ns->regs, c);
[68414f4a]285 fibril_mutex_unlock(&ns->mutex);
[ca97cad]286}
287
[cf8cc36]288/** Write data to the serial port.
[49698fa]289 *
[74017ce]290 * @param srv Server-side connection data
[68414f4a]291 * @param buf The data to be written
292 * @param count The number of bytes to be written
[74017ce]293 * @param nwritten Place to store number of bytes successfully written
294 * @return EOK on success or non-zero error code
[cf8cc36]295 */
[b7fd2a0]296static errno_t ns8250_write(chardev_srv_t *srv, const void *buf, size_t count,
[74017ce]297 size_t *nwritten)
[f658458]298{
[74017ce]299 ns8250_t *ns = srv_ns8250(srv);
[ca97cad]300 size_t idx;
[74017ce]301 uint8_t *bp = (uint8_t *) buf;
[a35b458]302
[49698fa]303 for (idx = 0; idx < count; idx++)
[74017ce]304 ns8250_putchar(ns, bp[idx]);
[a35b458]305
[74017ce]306 *nwritten = count;
307 return EOK;
[f658458]308}
309
[b7fd2a0]310static errno_t ns8250_open(chardev_srvs_t *, chardev_srv_t *);
311static errno_t ns8250_close(chardev_srv_t *);
[984a9ba]312static void ns8250_default_handler(chardev_srv_t *, ipc_call_t *);
[5fe1c32]313
[49698fa]314/** The character interface's callbacks. */
[74017ce]315static chardev_ops_t ns8250_chardev_ops = {
316 .open = ns8250_open,
317 .close = ns8250_close,
318 .read = ns8250_read,
319 .write = ns8250_write,
320 .def_handler = ns8250_default_handler
[f658458]321};
322
[984a9ba]323static void ns8250_char_conn(ipc_call_t *, void *);
[74017ce]324
[b7fd2a0]325static errno_t ns8250_dev_add(ddf_dev_t *dev);
326static errno_t ns8250_dev_remove(ddf_dev_t *dev);
[5fe1c32]327
[49698fa]328/** The serial port device driver's standard operations. */
[04c7003f]329static driver_ops_t ns8250_ops = {
[0c0f823b]330 .dev_add = &ns8250_dev_add,
[5b68e0c]331 .dev_remove = &ns8250_dev_remove
[5fe1c32]332};
333
[49698fa]334/** The serial port device driver structure. */
[04c7003f]335static driver_t ns8250_driver = {
[5fe1c32]336 .name = NAME,
[04c7003f]337 .driver_ops = &ns8250_ops
[5fe1c32]338};
339
[68414f4a]340/** Clean up the serial port soft-state
[49698fa]341 *
[68414f4a]342 * @param ns Serial port device
[cf8cc36]343 */
[68414f4a]344static void ns8250_dev_cleanup(ns8250_t *ns)
[1f8657b]345{
346}
347
[cf8cc36]348/** Enable the i/o ports of the device.
[49698fa]349 *
[68414f4a]350 * @param ns Serial port device
351 * @return True on success, false otherwise
[cf8cc36]352 */
[68414f4a]353static bool ns8250_pio_enable(ns8250_t *ns)
[1f8657b]354{
[56fd7cf]355 ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ddf_dev_get_name(ns->dev));
[a35b458]356
[49698fa]357 /* Gain control over port's registers. */
[340513c]358 if (pio_enable((void *) ns->io_addr, REG_COUNT,
[68414f4a]359 (void **) &ns->port)) {
[340513c]360 ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIxn
[56fd7cf]361 " for device %s.", ns->io_addr, ddf_dev_get_name(ns->dev));
[1f8657b]362 return false;
363 }
[c7235d40]364
365 ns->regs = (ns8250_regs_t *)ns->port;
[a35b458]366
[1f8657b]367 return true;
368}
369
[cf8cc36]370/** Probe the serial port device for its presence.
[49698fa]371 *
[68414f4a]372 * @param ns Serial port device
373 * @return True if the device is present, false otherwise
[cf8cc36]374 */
[68414f4a]375static bool ns8250_dev_probe(ns8250_t *ns)
[1f8657b]376{
[56fd7cf]377 ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ddf_dev_get_name(ns->dev));
[a35b458]378
[1f8657b]379 bool res = true;
380 uint8_t olddata;
[a35b458]381
[c7235d40]382 olddata = pio_read_8(&ns->regs->mcr);
[a35b458]383
[c7235d40]384 pio_write_8(&ns->regs->mcr, NS8250_MCR_LOOPBACK);
385 if (pio_read_8(&ns->regs->msr) & NS8250_MSR_SIGNALS)
[1f8657b]386 res = false;
[a35b458]387
[c7235d40]388 pio_write_8(&ns->regs->mcr, NS8250_MCR_ALL);
[3bacee1]389 if ((pio_read_8(&ns->regs->msr) & NS8250_MSR_SIGNALS) !=
390 NS8250_MSR_SIGNALS)
[1f8657b]391 res = false;
[a35b458]392
[c7235d40]393 pio_write_8(&ns->regs->mcr, olddata);
[a35b458]394
[fc51296]395 if (!res) {
[ebcb05a]396 ddf_msg(LVL_DEBUG, "Device %s is not present.",
[56fd7cf]397 ddf_dev_get_name(ns->dev));
[fc51296]398 }
[a35b458]399
[49698fa]400 return res;
[1f8657b]401}
402
[cf8cc36]403/** Initialize serial port device.
[49698fa]404 *
[68414f4a]405 * @param ns Serial port device
[cde999a]406 * @return Zero on success, error number otherwise
[cf8cc36]407 */
[b7fd2a0]408static errno_t ns8250_dev_initialize(ns8250_t *ns)
[1f8657b]409{
[b7fd2a0]410 errno_t ret = EOK;
[a35b458]411
[56fd7cf]412 ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ddf_dev_get_name(ns->dev));
[a35b458]413
[1f8657b]414 hw_resource_list_t hw_resources;
415 memset(&hw_resources, 0, sizeof(hw_resource_list_t));
[a35b458]416
[49698fa]417 /* Get hw resources. */
[d51838f]418 ret = hw_res_get_resource_list(ns->parent_sess, &hw_resources);
[be942bc]419 if (ret != EOK) {
[fc51296]420 ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
[56fd7cf]421 "%s.", ddf_dev_get_name(ns->dev));
[1f8657b]422 goto failed;
[49698fa]423 }
[a35b458]424
[1f8657b]425 size_t i;
426 hw_resource_t *res;
427 bool irq = false;
428 bool ioport = false;
[a35b458]429
[1f8657b]430 for (i = 0; i < hw_resources.count; i++) {
431 res = &hw_resources.resources[i];
432 switch (res->type) {
433 case INTERRUPT:
[68414f4a]434 ns->irq = res->res.interrupt.irq;
[1f8657b]435 irq = true;
[3a67d63]436 ddf_msg(LVL_NOTE, "Device %s was assigned irq = 0x%x.",
[56fd7cf]437 ddf_dev_get_name(ns->dev), ns->irq);
[1f8657b]438 break;
[a35b458]439
[1f8657b]440 case IO_RANGE:
[68414f4a]441 ns->io_addr = res->res.io_range.address;
[1f8657b]442 if (res->res.io_range.size < REG_COUNT) {
[fc51296]443 ddf_msg(LVL_ERROR, "I/O range assigned to "
[56fd7cf]444 "device %s is too small.", ddf_dev_get_name(ns->dev));
[be942bc]445 ret = ELIMIT;
[1f8657b]446 goto failed;
447 }
448 ioport = true;
[3a67d63]449 ddf_msg(LVL_NOTE, "Device %s was assigned I/O address = "
[340513c]450 "0x%#" PRIxn ".", ddf_dev_get_name(ns->dev), ns->io_addr);
[3bacee1]451 break;
[a35b458]452
[dafe675]453 default:
454 break;
[1f8657b]455 }
456 }
[a35b458]457
[1f8657b]458 if (!irq || !ioport) {
[ebcb05a]459 ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
[56fd7cf]460 ddf_dev_get_name(ns->dev));
[be942bc]461 ret = ENOENT;
[1f8657b]462 goto failed;
[49698fa]463 }
[a35b458]464
[f724e82]465 hw_res_clean_resource_list(&hw_resources);
[df747b9c]466 return ret;
[a35b458]467
[1f8657b]468failed:
[68414f4a]469 ns8250_dev_cleanup(ns);
[f724e82]470 hw_res_clean_resource_list(&hw_resources);
[49698fa]471 return ret;
[1f8657b]472}
473
[cf8cc36]474/** Enable interrupts on the serial port device.
[49698fa]475 *
[68414f4a]476 * Interrupt when data is received
[49698fa]477 *
478 * @param port The base address of the serial port device's ports.
[cf8cc36]479 */
[c7235d40]480static inline void ns8250_port_interrupts_enable(ns8250_regs_t *regs)
[bab6388]481{
[c7235d40]482 /* Interrupt when data received. */
[e0cd9042]483 pio_write_8(&regs->ier, NS8250_IER_RXREADY | NS8250_IER_RXSTATUS);
[3bacee1]484 pio_write_8(&regs->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS |
485 NS8250_MCR_OUT2);
[f4ef3c2]486}
487
[cf8cc36]488/** Disable interrupts on the serial port device.
[49698fa]489 *
[68414f4a]490 * @param port The base address of the serial port device's ports
[cf8cc36]491 */
[c7235d40]492static inline void ns8250_port_interrupts_disable(ns8250_regs_t *regs)
[f4ef3c2]493{
[c7235d40]494 pio_write_8(&regs->ier, 0x0); /* Disable all interrupts. */
[f4ef3c2]495}
496
[cf8cc36]497/** Enable interrupts for the serial port device.
[49698fa]498 *
[68414f4a]499 * @param ns Serial port device
[cde999a]500 * @return Zero on success, error number otherwise
[cf8cc36]501 */
[b7fd2a0]502static errno_t ns8250_interrupt_enable(ns8250_t *ns)
[cfe7716]503{
[ebc9c2c]504 /* Enable interrupt using IRC service. */
[b7fd2a0]505 errno_t rc = hw_res_enable_interrupt(ns->parent_sess, ns->irq);
[ebc9c2c]506 if (rc != EOK)
[128c78b]507 return EIO;
[a35b458]508
[e0cd9042]509 /* Read LSR to clear possible previous LSR interrupt */
510 pio_read_8(&ns->regs->lsr);
[a35b458]511
[49698fa]512 /* Enable interrupt on the serial port. */
[c7235d40]513 ns8250_port_interrupts_enable(ns->regs);
[a35b458]514
[cfe7716]515 return EOK;
516}
517
[cf8cc36]518/** Set Divisor Latch Access Bit.
[49698fa]519 *
520 * When the Divisor Latch Access Bit is set, it is possible to set baud rate of
521 * the serial port device.
522 *
523 * @param port The base address of the serial port device's ports.
[cf8cc36]524 */
[c7235d40]525static inline void enable_dlab(ns8250_regs_t *regs)
[cf8cc36]526{
[c7235d40]527 uint8_t val = pio_read_8(&regs->lcr);
528 pio_write_8(&regs->lcr, val | NS8250_LCR_DLAB);
[cf8cc36]529}
530
531/** Clear Divisor Latch Access Bit.
[49698fa]532 *
533 * @param port The base address of the serial port device's ports.
[cf8cc36]534 */
[c7235d40]535static inline void clear_dlab(ns8250_regs_t *regs)
[cf8cc36]536{
[c7235d40]537 uint8_t val = pio_read_8(&regs->lcr);
538 pio_write_8(&regs->lcr, val & (~NS8250_LCR_DLAB));
[cf8cc36]539}
540
541/** Set baud rate of the serial communication on the serial device.
[49698fa]542 *
543 * @param port The base address of the serial port device's ports.
544 * @param baud_rate The baud rate to be used by the device.
[cde999a]545 * @return Zero on success, error number otherwise (EINVAL
[49698fa]546 * if the specified baud_rate is not valid).
[cf8cc36]547 */
[b7fd2a0]548static errno_t ns8250_port_set_baud_rate(ns8250_regs_t *regs, unsigned int baud_rate)
[f4ef3c2]549{
550 uint16_t divisor;
551 uint8_t div_low, div_high;
[a35b458]552
[33dbbd2]553 if (baud_rate < 50 || MAX_BAUD_RATE % baud_rate != 0) {
[ebcb05a]554 ddf_msg(LVL_ERROR, "Invalid baud rate %d requested.",
[fc51296]555 baud_rate);
[49698fa]556 return EINVAL;
[f4ef3c2]557 }
[a35b458]558
[f4ef3c2]559 divisor = MAX_BAUD_RATE / baud_rate;
560 div_low = (uint8_t)divisor;
[49698fa]561 div_high = (uint8_t)(divisor >> 8);
[a35b458]562
[49698fa]563 /* Enable DLAB to be able to access baud rate divisor. */
[c7235d40]564 enable_dlab(regs);
[a35b458]565
[49698fa]566 /* Set divisor low byte. */
[c7235d40]567 pio_write_8(&regs->data, div_low);
[49698fa]568 /* Set divisor high byte. */
[c7235d40]569 pio_write_8(&regs->ier, div_high);
[a35b458]570
[c7235d40]571 clear_dlab(regs);
[a35b458]572
[49698fa]573 return EOK;
[f4ef3c2]574}
575
[cf8cc36]576/** Get baud rate used by the serial port device.
[49698fa]577 *
578 * @param port The base address of the serial port device's ports.
579 * @param baud_rate The ouput parameter to which the baud rate is stored.
[cf8cc36]580 */
[c7235d40]581static unsigned int ns8250_port_get_baud_rate(ns8250_regs_t *regs)
[f4ef3c2]582{
[cf8cc36]583 uint16_t divisor;
584 uint8_t div_low, div_high;
[a35b458]585
[49698fa]586 /* Enable DLAB to be able to access baud rate divisor. */
[c7235d40]587 enable_dlab(regs);
[a35b458]588
[49698fa]589 /* Get divisor low byte. */
[c7235d40]590 div_low = pio_read_8(&regs->data);
[49698fa]591 /* Get divisor high byte. */
[c7235d40]592 div_high = pio_read_8(&regs->ier);
[a35b458]593
[c7235d40]594 clear_dlab(regs);
[a35b458]595
[cf8cc36]596 divisor = (div_high << 8) | div_low;
597 return MAX_BAUD_RATE / divisor;
598}
599
[49698fa]600/** Get the parameters of the serial communication set on the serial port
601 * device.
602 *
603 * @param parity The parity used.
604 * @param word_length The length of one data unit in bits.
605 * @param stop_bits The number of stop bits used (one or two).
[cf8cc36]606 */
[c7235d40]607static void ns8250_port_get_com_props(ns8250_regs_t *regs, unsigned int *parity,
[49698fa]608 unsigned int *word_length, unsigned int *stop_bits)
[cf8cc36]609{
610 uint8_t val;
[a35b458]611
[c7235d40]612 val = pio_read_8(&regs->lcr);
613 *parity = ((val >> NS8250_LCR_PARITY) & 7);
[a35b458]614
[56fd7cf]615 /* Silence warnings */
616 *word_length = 0;
617
[cf8cc36]618 switch (val & 3) {
[49698fa]619 case WORD_LENGTH_5:
620 *word_length = 5;
621 break;
622 case WORD_LENGTH_6:
623 *word_length = 6;
624 break;
625 case WORD_LENGTH_7:
626 *word_length = 7;
627 break;
628 case WORD_LENGTH_8:
629 *word_length = 8;
630 break;
[cf8cc36]631 }
[a35b458]632
[c7235d40]633 if ((val >> NS8250_LCR_STOPBITS) & 1)
[cf8cc36]634 *stop_bits = 2;
[49698fa]635 else
[cf8cc36]636 *stop_bits = 1;
[f4ef3c2]637}
638
[cf8cc36]639/** Set the parameters of the serial communication on the serial port device.
[49698fa]640 *
641 * @param parity The parity to be used.
642 * @param word_length The length of one data unit in bits.
643 * @param stop_bits The number of stop bits used (one or two).
644 * @return Zero on success, EINVAL if some of the specified values
645 * is invalid.
[cf8cc36]646 */
[b7fd2a0]647static errno_t ns8250_port_set_com_props(ns8250_regs_t *regs, unsigned int parity,
[49698fa]648 unsigned int word_length, unsigned int stop_bits)
[cf8cc36]649{
650 uint8_t val;
[a35b458]651
[cf8cc36]652 switch (word_length) {
[49698fa]653 case 5:
654 val = WORD_LENGTH_5;
655 break;
656 case 6:
657 val = WORD_LENGTH_6;
658 break;
659 case 7:
660 val = WORD_LENGTH_7;
661 break;
662 case 8:
663 val = WORD_LENGTH_8;
664 break;
665 default:
666 return EINVAL;
[cf8cc36]667 }
[a35b458]668
[cf8cc36]669 switch (stop_bits) {
[49698fa]670 case 1:
[c7235d40]671 val |= ONE_STOP_BIT << NS8250_LCR_STOPBITS;
[49698fa]672 break;
673 case 2:
[c7235d40]674 val |= TWO_STOP_BITS << NS8250_LCR_STOPBITS;
[49698fa]675 break;
676 default:
677 return EINVAL;
[cf8cc36]678 }
[a35b458]679
[cf8cc36]680 switch (parity) {
[49698fa]681 case SERIAL_NO_PARITY:
682 case SERIAL_ODD_PARITY:
683 case SERIAL_EVEN_PARITY:
684 case SERIAL_MARK_PARITY:
685 case SERIAL_SPACE_PARITY:
[c7235d40]686 val |= parity << NS8250_LCR_PARITY;
[49698fa]687 break;
688 default:
689 return EINVAL;
[cf8cc36]690 }
[a35b458]691
[c7235d40]692 pio_write_8(&regs->lcr, val);
[a35b458]693
[cf8cc36]694 return EOK;
695}
696
697/** Initialize the serial port device.
[49698fa]698 *
[cf8cc36]699 * Set the default parameters of the serial communication.
[49698fa]700 *
[68414f4a]701 * @param ns Serial port device
[cf8cc36]702 */
[68414f4a]703static void ns8250_initialize_port(ns8250_t *ns)
[cfe7716]704{
[49698fa]705 /* Disable interrupts. */
[c7235d40]706 ns8250_port_interrupts_disable(ns->regs);
[49698fa]707 /* Set baud rate. */
[c7235d40]708 ns8250_port_set_baud_rate(ns->regs, 38400);
[49698fa]709 /* 8 bits, no parity, two stop bits. */
[c7235d40]710 ns8250_port_set_com_props(ns->regs, SERIAL_NO_PARITY, 8, 2);
[188c76c]711 /*
712 * Enable FIFO, clear them, with 4-byte threshold for greater
713 * reliability.
714 */
[3bacee1]715 pio_write_8(&ns->regs->iid, NS8250_FCR_FIFOENABLE |
716 NS8250_FCR_RXFIFORESET | NS8250_FCR_TXFIFORESET |
717 NS8250_FCR_RXTRIGGERLOW);
[49698fa]718 /*
719 * RTS/DSR set (Request to Send and Data Terminal Ready lines enabled),
720 * Aux Output2 set - needed for interrupts.
721 */
[3bacee1]722 pio_write_8(&ns->regs->mcr, NS8250_MCR_DTR | NS8250_MCR_RTS |
723 NS8250_MCR_OUT2);
[49698fa]724}
725
[5b68e0c]726/** Deinitialize the serial port device.
727 *
728 * @param ns Serial port device
729 */
730static void ns8250_port_cleanup(ns8250_t *ns)
731{
732 /* Disable FIFO */
[c7235d40]733 pio_write_8(&ns->regs->iid, 0x00);
[5b68e0c]734 /* Disable DTR, RTS, OUT1, OUT2 (int. enable) */
[c7235d40]735 pio_write_8(&ns->regs->mcr, 0x00);
[5b68e0c]736 /* Disable all interrupts from the port */
[c7235d40]737 ns8250_port_interrupts_disable(ns->regs);
[5b68e0c]738}
739
[49698fa]740/** Read the data from the serial port device and store them to the input
741 * buffer.
742 *
[68414f4a]743 * @param ns Serial port device
[cf8cc36]744 */
[68414f4a]745static void ns8250_read_from_device(ns8250_t *ns)
[7f8b581]746{
[c7235d40]747 ns8250_regs_t *regs = ns->regs;
[dafe675]748 bool cont = true;
[a35b458]749
[c92e30f]750 fibril_mutex_lock(&ns->mutex);
[49698fa]751 while (cont) {
[c7235d40]752 cont = ns8250_received(regs);
[cf8cc36]753 if (cont) {
[c7235d40]754 uint8_t val = ns8250_read_8(regs);
[a35b458]755
[4510e06]756 if (ns->client_connections > 0) {
[91ecaa10]757 bool buf_was_empty = buf_is_empty(&ns->input_buffer);
[68414f4a]758 if (!buf_push_back(&ns->input_buffer, val)) {
[fc51296]759 ddf_msg(LVL_WARN, "Buffer overflow on "
[56fd7cf]760 "%s.", ddf_dev_get_name(ns->dev));
[c92e30f]761 break;
[dafe675]762 } else {
[fc51296]763 ddf_msg(LVL_DEBUG2, "Character %c saved "
[ebcb05a]764 "to the buffer of %s.",
[56fd7cf]765 val, ddf_dev_get_name(ns->dev));
[91ecaa10]766 if (buf_was_empty)
767 fibril_condvar_broadcast(&ns->input_buffer_available);
[dafe675]768 }
[49698fa]769 }
[dafe675]770 }
[49698fa]771 }
[c92e30f]772 fibril_mutex_unlock(&ns->mutex);
773 fibril_yield();
[2300b9d]774}
775
[cf8cc36]776/** The interrupt handler.
[49698fa]777 *
[e0cd9042]778 * The serial port is initialized to interrupt when some data come or line
779 * status register changes, so the interrupt is handled by reading the incoming
780 * data and reading the line status register.
[49698fa]781 *
[8820544]782 * @param dev The serial port device.
783 *
[cf8cc36]784 */
[01c3bb4]785static inline void ns8250_interrupt_handler(ipc_call_t *icall, ddf_dev_t *dev)
[2300b9d]786{
[56fd7cf]787 ns8250_t *ns = dev_ns8250(dev);
[e0cd9042]788 uint8_t iir = pio_read_8(&ns->regs->iid);
789 if ((iir & NS8250_IID_CAUSE_MASK) == NS8250_IID_CAUSE_RXSTATUS) {
790 uint8_t lsr = pio_read_8(&ns->regs->lsr);
791 if (lsr & NS8250_LSR_OE) {
[56fd7cf]792 ddf_msg(LVL_WARN, "Overrun error on %s", ddf_dev_get_name(ns->dev));
[e0cd9042]793 }
794 }
[a35b458]795
[e0cd9042]796 ns8250_read_from_device(ns);
[d51838f]797 hw_res_clear_interrupt(ns->parent_sess, ns->irq);
[7f8b581]798}
799
[cf8cc36]800/** Register the interrupt handler for the device.
[49698fa]801 *
[68414f4a]802 * @param ns Serial port device
[cf8cc36]803 */
[b7fd2a0]804static inline errno_t ns8250_register_interrupt_handler(ns8250_t *ns,
[eadaeae8]805 cap_irq_handle_t *ihandle)
[7f8b581]806{
[68414f4a]807 return register_interrupt_handler(ns->dev, ns->irq,
[eadaeae8]808 ns8250_interrupt_handler, NULL, ihandle);
[2300b9d]809}
810
[cf8cc36]811/** Unregister the interrupt handler for the device.
[49698fa]812 *
[68414f4a]813 * @param ns Serial port device
[cf8cc36]814 */
[b7fd2a0]815static inline errno_t ns8250_unregister_interrupt_handler(ns8250_t *ns)
[2300b9d]816{
[eadaeae8]817 return unregister_interrupt_handler(ns->dev, ns->irq_handle);
[7f8b581]818}
819
[0c0f823b]820/** The dev_add callback method of the serial port driver.
[49698fa]821 *
[cf8cc36]822 * Probe and initialize the newly added device.
[49698fa]823 *
824 * @param dev The serial port device.
[cf8cc36]825 */
[b7fd2a0]826static errno_t ns8250_dev_add(ddf_dev_t *dev)
[5fe1c32]827{
[68414f4a]828 ns8250_t *ns = NULL;
[83a2f43]829 ddf_fun_t *fun = NULL;
[68414f4a]830 bool need_cleanup = false;
[dad0d2f]831 bool need_unreg_intr_handler = false;
[b7fd2a0]832 errno_t rc;
[a35b458]833
[0c0f823b]834 ddf_msg(LVL_DEBUG, "ns8250_dev_add %s (handle = %d)",
[56fd7cf]835 ddf_dev_get_name(dev), (int) ddf_dev_get_handle(dev));
[a35b458]836
[68414f4a]837 /* Allocate soft-state for the device */
[5f6e25e]838 ns = ddf_dev_data_alloc(dev, sizeof(ns8250_t));
[68414f4a]839 if (ns == NULL) {
840 rc = ENOMEM;
841 goto fail;
842 }
[a35b458]843
[5f6e25e]844 fibril_mutex_initialize(&ns->mutex);
[91ecaa10]845 fibril_condvar_initialize(&ns->input_buffer_available);
[68414f4a]846 ns->dev = dev;
[a35b458]847
[d51838f]848 ns->parent_sess = ddf_dev_parent_sess_get(ns->dev);
849 if (ns->parent_sess == NULL) {
850 ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
851 "device %s.", ddf_dev_get_name(ns->dev));
852 rc = EIO;
853 goto fail;
854 }
[a35b458]855
[68414f4a]856 rc = ns8250_dev_initialize(ns);
857 if (rc != EOK)
858 goto fail;
[a35b458]859
[68414f4a]860 need_cleanup = true;
[a35b458]861
[68414f4a]862 if (!ns8250_pio_enable(ns)) {
863 rc = EADDRNOTAVAIL;
864 goto fail;
[49698fa]865 }
[a35b458]866
[49698fa]867 /* Find out whether the device is present. */
[68414f4a]868 if (!ns8250_dev_probe(ns)) {
869 rc = ENOENT;
870 goto fail;
[49698fa]871 }
[a35b458]872
[49698fa]873 /* Serial port initialization (baud rate etc.). */
[68414f4a]874 ns8250_initialize_port(ns);
[a35b458]875
[49698fa]876 /* Register interrupt handler. */
[eadaeae8]877 ns->irq_handle = CAP_NIL;
878 rc = ns8250_register_interrupt_handler(ns, &ns->irq_handle);
[071a1ddb]879 if (rc != EOK) {
[ebcb05a]880 ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
[68414f4a]881 rc = EADDRNOTAVAIL;
882 goto fail;
[7f8b581]883 }
[dad0d2f]884 need_unreg_intr_handler = true;
[c4e30607]885
[49698fa]886 /* Enable interrupt. */
[68414f4a]887 rc = ns8250_interrupt_enable(ns);
888 if (rc != EOK) {
[fc51296]889 ddf_msg(LVL_ERROR, "Failed to enable the interrupt. Error code = "
[dd8ab1c]890 "%s.", str_error_name(rc));
[68414f4a]891 goto fail;
[49698fa]892 }
[a35b458]893
[97a62fe]894 fun = ddf_fun_create(dev, fun_exposed, "a");
895 if (fun == NULL) {
[ebcb05a]896 ddf_msg(LVL_ERROR, "Failed creating function.");
[97a62fe]897 goto fail;
898 }
[a35b458]899
[74017ce]900 ddf_fun_set_conn_handler(fun, ns8250_char_conn);
[a35b458]901
[74017ce]902 chardev_srvs_init(&ns->cds);
903 ns->cds.ops = &ns8250_chardev_ops;
904 ns->cds.sarg = ns;
[a35b458]905
[97a62fe]906 rc = ddf_fun_bind(fun);
907 if (rc != EOK) {
[ebcb05a]908 ddf_msg(LVL_ERROR, "Failed binding function.");
[97a62fe]909 goto fail;
910 }
911
[68414f4a]912 ns->fun = fun;
[a35b458]913
[1dc4a5e]914 ddf_fun_add_to_category(fun, "serial");
[a35b458]915
[ebcb05a]916 ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
[56fd7cf]917 ddf_dev_get_name(dev));
[a35b458]918
[df747b9c]919 return EOK;
[68414f4a]920fail:
[97a62fe]921 if (fun != NULL)
922 ddf_fun_destroy(fun);
[dad0d2f]923 if (need_unreg_intr_handler)
924 ns8250_unregister_interrupt_handler(ns);
[68414f4a]925 if (need_cleanup)
926 ns8250_dev_cleanup(ns);
927 return rc;
[5fe1c32]928}
929
[b7fd2a0]930static errno_t ns8250_dev_remove(ddf_dev_t *dev)
[5b68e0c]931{
[56fd7cf]932 ns8250_t *ns = dev_ns8250(dev);
[b7fd2a0]933 errno_t rc;
[a35b458]934
[5b68e0c]935 fibril_mutex_lock(&ns->mutex);
[956d4281]936 if (ns->client_connections > 0) {
[5b68e0c]937 fibril_mutex_unlock(&ns->mutex);
938 return EBUSY;
939 }
940 ns->removed = true;
941 fibril_mutex_unlock(&ns->mutex);
[a35b458]942
[5b68e0c]943 rc = ddf_fun_unbind(ns->fun);
944 if (rc != EOK) {
945 ddf_msg(LVL_ERROR, "Failed to unbind function.");
946 return rc;
947 }
[a35b458]948
[5b68e0c]949 ddf_fun_destroy(ns->fun);
[a35b458]950
[5b68e0c]951 ns8250_port_cleanup(ns);
952 ns8250_unregister_interrupt_handler(ns);
953 ns8250_dev_cleanup(ns);
954 return EOK;
955}
956
[25a7e11d]957/** Open the device.
[49698fa]958 *
959 * This is a callback function called when a client tries to connect to the
960 * device.
961 *
[74017ce]962 * @param srvs Service structure
963 * @param srv Server-side connection structure
[25a7e11d]964 */
[b7fd2a0]965static errno_t ns8250_open(chardev_srvs_t *srvs, chardev_srv_t *srv)
[25a7e11d]966{
[74017ce]967 ns8250_t *ns = srv_ns8250(srv);
[b7fd2a0]968 errno_t res;
[a35b458]969
[5b68e0c]970 fibril_mutex_lock(&ns->mutex);
[4510e06]971 if (ns->removed) {
[5b68e0c]972 res = ENXIO;
[25a7e11d]973 } else {
974 res = EOK;
[4510e06]975 ns->client_connections++;
[25a7e11d]976 }
[5b68e0c]977 fibril_mutex_unlock(&ns->mutex);
[a35b458]978
[25a7e11d]979 return res;
980}
981
982/** Close the device.
[49698fa]983 *
984 * This is a callback function called when a client tries to disconnect from
985 * the device.
986 *
[74017ce]987 * @param srv Server-side connection structure
[25a7e11d]988 */
[b7fd2a0]989static errno_t ns8250_close(chardev_srv_t *srv)
[25a7e11d]990{
[74017ce]991 ns8250_t *data = srv_ns8250(srv);
[a35b458]992
[25a7e11d]993 fibril_mutex_lock(&data->mutex);
[a35b458]994
[4510e06]995 assert(data->client_connections > 0);
[a35b458]996
[4510e06]997 if (!(--data->client_connections))
998 buf_clear(&data->input_buffer);
[a35b458]999
[49698fa]1000 fibril_mutex_unlock(&data->mutex);
[a35b458]1001
[74017ce]1002 return EOK;
[25a7e11d]1003}
1004
[49698fa]1005/** Get parameters of the serial communication which are set to the specified
1006 * device.
1007 *
1008 * @param dev The serial port device.
1009 * @param baud_rate The baud rate used by the device.
1010 * @param parity The type of parity used by the device.
1011 * @param word_length The size of one data unit in bits.
1012 * @param stop_bits The number of stop bits used.
[cf8cc36]1013 */
[18b6a88]1014static void ns8250_get_props(ddf_dev_t *dev, unsigned int *baud_rate,
1015 unsigned int *parity, unsigned int *word_length, unsigned int *stop_bits)
[49698fa]1016{
[56fd7cf]1017 ns8250_t *data = dev_ns8250(dev);
[c7235d40]1018 ns8250_regs_t *regs = data->regs;
[a35b458]1019
[49698fa]1020 fibril_mutex_lock(&data->mutex);
[c7235d40]1021 ns8250_port_interrupts_disable(regs);
1022 *baud_rate = ns8250_port_get_baud_rate(regs);
1023 ns8250_port_get_com_props(regs, parity, word_length, stop_bits);
1024 ns8250_port_interrupts_enable(regs);
[49698fa]1025 fibril_mutex_unlock(&data->mutex);
[a35b458]1026
[fc51296]1027 ddf_msg(LVL_DEBUG, "ns8250_get_props: baud rate %d, parity 0x%x, word "
[ebcb05a]1028 "length %d, stop bits %d", *baud_rate, *parity, *word_length,
[49698fa]1029 *stop_bits);
[cf8cc36]1030}
1031
[49698fa]1032/** Set parameters of the serial communication to the specified serial port
1033 * device.
1034 *
1035 * @param dev The serial port device.
1036 * @param baud_rate The baud rate to be used by the device.
1037 * @param parity The type of parity to be used by the device.
1038 * @param word_length The size of one data unit in bits.
1039 * @param stop_bits The number of stop bits to be used.
[cf8cc36]1040 */
[b7fd2a0]1041static errno_t ns8250_set_props(ddf_dev_t *dev, unsigned int baud_rate,
[33dbbd2]1042 unsigned int parity, unsigned int word_length, unsigned int stop_bits)
[cf8cc36]1043{
[fc51296]1044 ddf_msg(LVL_DEBUG, "ns8250_set_props: baud rate %d, parity 0x%x, word "
[ebcb05a]1045 "length %d, stop bits %d", baud_rate, parity, word_length,
[49698fa]1046 stop_bits);
[a35b458]1047
[56fd7cf]1048 ns8250_t *data = dev_ns8250(dev);
[c7235d40]1049 ns8250_regs_t *regs = data->regs;
[b7fd2a0]1050 errno_t ret;
[a35b458]1051
[49698fa]1052 fibril_mutex_lock(&data->mutex);
[c7235d40]1053 ns8250_port_interrupts_disable(regs);
1054 ret = ns8250_port_set_baud_rate(regs, baud_rate);
[33dbbd2]1055 if (ret == EOK)
[c7235d40]1056 ret = ns8250_port_set_com_props(regs, parity, word_length, stop_bits);
1057 ns8250_port_interrupts_enable(regs);
[49698fa]1058 fibril_mutex_unlock(&data->mutex);
[a35b458]1059
[49698fa]1060 return ret;
[cf8cc36]1061}
1062
[49698fa]1063/** Default handler for client requests which are not handled by the standard
1064 * interfaces.
1065 *
[f4ef3c2]1066 * Configure the parameters of the serial communication.
1067 */
[984a9ba]1068static void ns8250_default_handler(chardev_srv_t *srv, ipc_call_t *call)
[f4ef3c2]1069{
[74017ce]1070 ns8250_t *ns8250 = srv_ns8250(srv);
[228e490]1071 sysarg_t method = IPC_GET_IMETHOD(*call);
[b7fd2a0]1072 errno_t ret;
[49698fa]1073 unsigned int baud_rate, parity, word_length, stop_bits;
[a35b458]1074
[49698fa]1075 switch (method) {
1076 case SERIAL_GET_COM_PROPS:
[74017ce]1077 ns8250_get_props(ns8250->dev, &baud_rate, &parity, &word_length,
[49698fa]1078 &stop_bits);
[984a9ba]1079 async_answer_4(call, EOK, baud_rate, parity, word_length,
[49698fa]1080 stop_bits);
1081 break;
[a35b458]1082
[49698fa]1083 case SERIAL_SET_COM_PROPS:
[3bacee1]1084 baud_rate = IPC_GET_ARG1(*call);
[49698fa]1085 parity = IPC_GET_ARG2(*call);
1086 word_length = IPC_GET_ARG3(*call);
1087 stop_bits = IPC_GET_ARG4(*call);
[74017ce]1088 ret = ns8250_set_props(ns8250->dev, baud_rate, parity, word_length,
[49698fa]1089 stop_bits);
[984a9ba]1090 async_answer_0(call, ret);
[49698fa]1091 break;
[a35b458]1092
[49698fa]1093 default:
[984a9ba]1094 async_answer_0(call, ENOTSUP);
[49698fa]1095 }
[f4ef3c2]1096}
1097
[984a9ba]1098void ns8250_char_conn(ipc_call_t *icall, void *arg)
[74017ce]1099{
1100 ns8250_t *ns8250 = fun_ns8250((ddf_fun_t *)arg);
1101
[984a9ba]1102 chardev_conn(icall, &ns8250->cds);
[74017ce]1103}
1104
[25a7e11d]1105/** Initialize the serial port driver.
[49698fa]1106 *
1107 * Initialize device operations structures with callback methods for handling
[25a7e11d]1108 * client requests to the serial port devices.
1109 */
[49698fa]1110static void ns8250_init(void)
[5fe1c32]1111{
[267f235]1112 ddf_log_init(NAME);
[5fe1c32]1113}
1114
1115int main(int argc, char *argv[])
1116{
[49698fa]1117 printf(NAME ": HelenOS serial port driver\n");
[04c7003f]1118 ns8250_init();
[83a2f43]1119 return ddf_driver_main(&ns8250_driver);
[5fe1c32]1120}
1121
1122/**
1123 * @}
[49698fa]1124 */
Note: See TracBrowser for help on using the repository browser.