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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a0a9cc2 was 5a6cc679, checked in by Jenda <jenda.jzqk73@…>, 8 years ago

Merge commit '50f19b7ee8e94570b5c63896736c4eb49cfa18db' into forwardport

Not all ints are converted to errno_t in xhci tree yet, however it compiles and works :)

  • Property mode set to 100644
File size: 28.6 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 */
[e9d15d9]167 int irq_cap;
[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 ;
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 */
[5a6cc679]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;
[91ecaa10]258
[74017ce]259 if (count == 0) {
260 *nread = 0;
261 return EOK;
262 }
[bb864a0]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);
[bb864a0]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 */
[5a6cc679]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;
[49698fa]303
304 for (idx = 0; idx < count; idx++)
[74017ce]305 ns8250_putchar(ns, bp[idx]);
[ca97cad]306
[74017ce]307 *nwritten = count;
308 return EOK;
[f658458]309}
310
[5a6cc679]311static errno_t ns8250_open(chardev_srvs_t *, chardev_srv_t *);
312static errno_t ns8250_close(chardev_srv_t *);
[74017ce]313static void ns8250_default_handler(chardev_srv_t *, ipc_callid_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
[74017ce]324static void ns8250_char_conn(ipc_callid_t, ipc_call_t *, void *);
325
[5a6cc679]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));
[1f8657b]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;
[1f8657b]367
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));
[1f8657b]379
380 bool res = true;
381 uint8_t olddata;
382
[c7235d40]383 olddata = pio_read_8(&ns->regs->mcr);
[1f8657b]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;
388
[c7235d40]389 pio_write_8(&ns->regs->mcr, NS8250_MCR_ALL);
390 if ((pio_read_8(&ns->regs->msr) & NS8250_MSR_SIGNALS)
391 != NS8250_MSR_SIGNALS)
[1f8657b]392 res = false;
393
[c7235d40]394 pio_write_8(&ns->regs->mcr, olddata);
[1f8657b]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 }
[1f8657b]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 */
[5a6cc679]409static errno_t ns8250_dev_initialize(ns8250_t *ns)
[1f8657b]410{
[5a6cc679]411 errno_t ret = EOK;
[49698fa]412
[56fd7cf]413 ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ddf_dev_get_name(ns->dev));
414
[1f8657b]415 hw_resource_list_t hw_resources;
416 memset(&hw_resources, 0, sizeof(hw_resource_list_t));
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 }
[1f8657b]425
426 size_t i;
427 hw_resource_t *res;
428 bool irq = false;
429 bool ioport = false;
430
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;
[49698fa]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);
[ebcb05a]452 break;
[49698fa]453
[dafe675]454 default:
455 break;
[1f8657b]456 }
457 }
458
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 }
[1f8657b]465
[f724e82]466 hw_res_clean_resource_list(&hw_resources);
[df747b9c]467 return ret;
[1f8657b]468
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);
[c7235d40]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 */
[5a6cc679]503static errno_t ns8250_interrupt_enable(ns8250_t *ns)
[cfe7716]504{
[ebc9c2c]505 /* Enable interrupt using IRC service. */
[5a6cc679]506 errno_t rc = hw_res_enable_interrupt(ns->parent_sess, ns->irq);
[ebc9c2c]507 if (rc != EOK)
[128c78b]508 return EIO;
[ebc9c2c]509
[e0cd9042]510 /* Read LSR to clear possible previous LSR interrupt */
511 pio_read_8(&ns->regs->lsr);
[ebc9c2c]512
[49698fa]513 /* Enable interrupt on the serial port. */
[c7235d40]514 ns8250_port_interrupts_enable(ns->regs);
[cfe7716]515
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 */
[5a6cc679]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;
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 }
559
560 divisor = MAX_BAUD_RATE / baud_rate;
561 div_low = (uint8_t)divisor;
[49698fa]562 div_high = (uint8_t)(divisor >> 8);
[f4ef3c2]563
[49698fa]564 /* Enable DLAB to be able to access baud rate divisor. */
[c7235d40]565 enable_dlab(regs);
[f4ef3c2]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);
[f4ef3c2]571
[c7235d40]572 clear_dlab(regs);
[f4ef3c2]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;
[f4ef3c2]586
[49698fa]587 /* Enable DLAB to be able to access baud rate divisor. */
[c7235d40]588 enable_dlab(regs);
[f619943a]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);
[f4ef3c2]594
[c7235d40]595 clear_dlab(regs);
[cf8cc36]596
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;
612
[c7235d40]613 val = pio_read_8(&regs->lcr);
614 *parity = ((val >> NS8250_LCR_PARITY) & 7);
[cf8cc36]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 }
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 */
[5a6cc679]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;
652
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 }
669
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 }
680
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 }
692
[c7235d40]693 pio_write_8(&regs->lcr, val);
[cf8cc36]694
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 */
[c7235d40]716 pio_write_8(&ns->regs->iid, NS8250_FCR_FIFOENABLE
[188c76c]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 */
[c7235d40]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;
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);
[ca97cad]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 }
796
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 */
[5a6cc679]805static inline errno_t ns8250_register_interrupt_handler(ns8250_t *ns,
[071a1ddb]806 cap_handle_t *handle)
[7f8b581]807{
[68414f4a]808 return register_interrupt_handler(ns->dev, ns->irq,
[071a1ddb]809 ns8250_interrupt_handler, NULL, handle);
[2300b9d]810}
811
[cf8cc36]812/** Unregister the interrupt handler for the device.
[49698fa]813 *
[68414f4a]814 * @param ns Serial port device
[cf8cc36]815 */
[5a6cc679]816static inline errno_t ns8250_unregister_interrupt_handler(ns8250_t *ns)
[2300b9d]817{
[e9d15d9]818 return unregister_interrupt_handler(ns->dev, ns->irq_cap);
[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 */
[5a6cc679]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;
[5a6cc679]833 errno_t rc;
[68414f4a]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));
[5fe1c32]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 }
844
[5f6e25e]845 fibril_mutex_initialize(&ns->mutex);
[91ecaa10]846 fibril_condvar_initialize(&ns->input_buffer_available);
[68414f4a]847 ns->dev = dev;
[1f8657b]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 }
856
[68414f4a]857 rc = ns8250_dev_initialize(ns);
858 if (rc != EOK)
859 goto fail;
860
861 need_cleanup = true;
862
863 if (!ns8250_pio_enable(ns)) {
864 rc = EADDRNOTAVAIL;
865 goto fail;
[49698fa]866 }
[df747b9c]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 }
[1f8657b]873
[49698fa]874 /* Serial port initialization (baud rate etc.). */
[68414f4a]875 ns8250_initialize_port(ns);
[cfe7716]876
[49698fa]877 /* Register interrupt handler. */
[071a1ddb]878 rc = ns8250_register_interrupt_handler(ns, &ns->irq_cap);
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 }
[68414f4a]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 }
[f658458]899
[74017ce]900 ddf_fun_set_conn_handler(fun, ns8250_char_conn);
901
902 chardev_srvs_init(&ns->cds);
903 ns->cds.ops = &ns8250_chardev_ops;
904 ns->cds.sarg = ns;
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;
[5fe1c32]913
[1dc4a5e]914 ddf_fun_add_to_category(fun, "serial");
[692c40cb]915
[ebcb05a]916 ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
[56fd7cf]917 ddf_dev_get_name(dev));
[2300b9d]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
[5a6cc679]930static errno_t ns8250_dev_remove(ddf_dev_t *dev)
[5b68e0c]931{
[56fd7cf]932 ns8250_t *ns = dev_ns8250(dev);
[5a6cc679]933 errno_t rc;
[5b68e0c]934
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);
942
943 rc = ddf_fun_unbind(ns->fun);
944 if (rc != EOK) {
945 ddf_msg(LVL_ERROR, "Failed to unbind function.");
946 return rc;
947 }
948
949 ddf_fun_destroy(ns->fun);
950
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 */
[5a6cc679]965static errno_t ns8250_open(chardev_srvs_t *srvs, chardev_srv_t *srv)
[25a7e11d]966{
[74017ce]967 ns8250_t *ns = srv_ns8250(srv);
[5a6cc679]968 errno_t res;
[25a7e11d]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);
[bab6388]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 */
[5a6cc679]989static errno_t ns8250_close(chardev_srv_t *srv)
[25a7e11d]990{
[74017ce]991 ns8250_t *data = srv_ns8250(srv);
[25a7e11d]992
993 fibril_mutex_lock(&data->mutex);
994
[4510e06]995 assert(data->client_connections > 0);
[25a7e11d]996
[4510e06]997 if (!(--data->client_connections))
998 buf_clear(&data->input_buffer);
[25a7e11d]999
[49698fa]1000 fibril_mutex_unlock(&data->mutex);
[74017ce]1001
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 */
[49698fa]1014static void
[83a2f43]1015ns8250_get_props(ddf_dev_t *dev, unsigned int *baud_rate, unsigned int *parity,
[49698fa]1016 unsigned int *word_length, unsigned int* stop_bits)
1017{
[56fd7cf]1018 ns8250_t *data = dev_ns8250(dev);
[c7235d40]1019 ns8250_regs_t *regs = data->regs;
[cf8cc36]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);
[cf8cc36]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 */
[5a6cc679]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);
[cf8cc36]1048
[56fd7cf]1049 ns8250_t *data = dev_ns8250(dev);
[c7235d40]1050 ns8250_regs_t *regs = data->regs;
[5a6cc679]1051 errno_t ret;
[cf8cc36]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);
[cf8cc36]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 */
[74017ce]1069static void ns8250_default_handler(chardev_srv_t *srv, ipc_callid_t callid,
[33dbbd2]1070 ipc_call_t *call)
[f4ef3c2]1071{
[74017ce]1072 ns8250_t *ns8250 = srv_ns8250(srv);
[228e490]1073 sysarg_t method = IPC_GET_IMETHOD(*call);
[5a6cc679]1074 errno_t ret;
[49698fa]1075 unsigned int baud_rate, parity, word_length, stop_bits;
1076
1077 switch (method) {
1078 case SERIAL_GET_COM_PROPS:
[74017ce]1079 ns8250_get_props(ns8250->dev, &baud_rate, &parity, &word_length,
[49698fa]1080 &stop_bits);
[ffa2c8ef]1081 async_answer_4(callid, EOK, baud_rate, parity, word_length,
[49698fa]1082 stop_bits);
1083 break;
[cf8cc36]1084
[49698fa]1085 case SERIAL_SET_COM_PROPS:
1086 baud_rate = IPC_GET_ARG1(*call);
1087 parity = IPC_GET_ARG2(*call);
1088 word_length = IPC_GET_ARG3(*call);
1089 stop_bits = IPC_GET_ARG4(*call);
[74017ce]1090 ret = ns8250_set_props(ns8250->dev, baud_rate, parity, word_length,
[49698fa]1091 stop_bits);
[ffa2c8ef]1092 async_answer_0(callid, ret);
[49698fa]1093 break;
1094
1095 default:
[ffa2c8ef]1096 async_answer_0(callid, ENOTSUP);
[49698fa]1097 }
[f4ef3c2]1098}
1099
[74017ce]1100void ns8250_char_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
1101{
1102 ns8250_t *ns8250 = fun_ns8250((ddf_fun_t *)arg);
1103
1104 chardev_conn(iid, icall, &ns8250->cds);
1105}
1106
[25a7e11d]1107/** Initialize the serial port driver.
[49698fa]1108 *
1109 * Initialize device operations structures with callback methods for handling
[25a7e11d]1110 * client requests to the serial port devices.
1111 */
[49698fa]1112static void ns8250_init(void)
[5fe1c32]1113{
[267f235]1114 ddf_log_init(NAME);
[5fe1c32]1115}
1116
1117int main(int argc, char *argv[])
1118{
[49698fa]1119 printf(NAME ": HelenOS serial port driver\n");
[04c7003f]1120 ns8250_init();
[83a2f43]1121 return ddf_driver_main(&ns8250_driver);
[5fe1c32]1122}
1123
1124/**
1125 * @}
[49698fa]1126 */
Note: See TracBrowser for help on using the repository browser.