source: mainline/uspace/drv/char/ns8250/ns8250.c@ ceb2512

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

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

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