ns8250.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 Lenka Trochtova
00003  * Copyright (c) 2011 Jiri Svoboda
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00039 #include <assert.h>
00040 #include <stdio.h>
00041 #include <errno.h>
00042 #include <bool.h>
00043 #include <fibril_synch.h>
00044 #include <stdlib.h>
00045 #include <str.h>
00046 #include <ctype.h>
00047 #include <macros.h>
00048 #include <malloc.h>
00049 #include <dirent.h>
00050 #include <fcntl.h>
00051 #include <sys/stat.h>
00052 #include <ddi.h>
00053 #include <libarch/ddi.h>
00054 
00055 #include <ddf/driver.h>
00056 #include <ddf/interrupt.h>
00057 #include <ddf/log.h>
00058 #include <ops/char_dev.h>
00059 
00060 #include <devman.h>
00061 #include <ipc/devman.h>
00062 #include <device/hw_res.h>
00063 #include <ipc/serial_ctl.h>
00064 
00065 #include "cyclic_buffer.h"
00066 
00067 #define NAME "ns8250"
00068 
00069 #define REG_COUNT 7
00070 #define MAX_BAUD_RATE 115200
00071 #define DLAB_MASK (1 << 7)
00072 
00074 #define NS8250(fnode) ((ns8250_t *) ((fnode)->dev->driver_data))
00075 
00077 #define NS8250_FROM_DEV(dnode) ((ns8250_t *) ((dnode)->driver_data))
00078 
00080 typedef enum {
00081         WORD_LENGTH_5,
00082         WORD_LENGTH_6,
00083         WORD_LENGTH_7,
00084         WORD_LENGTH_8
00085 } word_length_t;
00086 
00088 typedef enum {
00090         ONE_STOP_BIT,
00092         TWO_STOP_BITS
00093 } stop_bit_t;
00094 
00096 typedef struct ns8250 {
00098         ddf_dev_t *dev;
00100         ddf_fun_t *fun;
00102         bool client_connected;
00104         int irq;
00106         uint32_t io_addr;
00108         ioport8_t *port;
00110         cyclic_buffer_t input_buffer;
00112         fibril_mutex_t mutex;
00113 } ns8250_t;
00114 
00119 static ns8250_t *ns8250_new(void)
00120 {
00121         ns8250_t *ns;
00122         
00123         ns = (ns8250_t *) calloc(1, sizeof(ns8250_t));
00124         if (ns == NULL)
00125                 return NULL;
00126         
00127         fibril_mutex_initialize(&ns->mutex);
00128         return ns;
00129 }
00130 
00135 static void ns8250_delete(ns8250_t *ns)
00136 {
00137         assert(ns != NULL);
00138         free(ns);
00139 }
00140 
00147 static bool ns8250_received(ioport8_t *port)
00148 {
00149         return (pio_read_8(port + 5) & 1) != 0;
00150 }
00151 
00157 static uint8_t ns8250_read_8(ioport8_t *port)
00158 {
00159         return pio_read_8(port);
00160 }
00161 
00166 static bool is_transmit_empty(ioport8_t *port)
00167 {
00168         return (pio_read_8(port + 5) & 0x20) != 0;
00169 }
00170 
00176 static void ns8250_write_8(ioport8_t *port, uint8_t c)
00177 {
00178         while (!is_transmit_empty(port))
00179                 ;
00180         
00181         pio_write_8(port, c);
00182 }
00183 
00193 static int ns8250_read(ddf_fun_t *fun, char *buf, size_t count)
00194 {
00195         ns8250_t *ns = NS8250(fun);
00196         int ret = EOK;
00197         
00198         fibril_mutex_lock(&ns->mutex);
00199         while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) {
00200                 buf[ret] = (char)buf_pop_front(&ns->input_buffer);
00201                 ret++;
00202         }
00203         fibril_mutex_unlock(&ns->mutex);
00204         
00205         return ret;
00206 }
00207 
00213 static inline void ns8250_putchar(ns8250_t *ns, uint8_t c)
00214 {
00215         fibril_mutex_lock(&ns->mutex);
00216         ns8250_write_8(ns->port, c);
00217         fibril_mutex_unlock(&ns->mutex);
00218 }
00219 
00227 static int ns8250_write(ddf_fun_t *fun, char *buf, size_t count)
00228 {
00229         ns8250_t *ns = NS8250(fun);
00230         size_t idx;
00231         
00232         for (idx = 0; idx < count; idx++)
00233                 ns8250_putchar(ns, (uint8_t) buf[idx]);
00234         
00235         return 0;
00236 }
00237 
00238 static ddf_dev_ops_t ns8250_dev_ops;
00239 
00241 static char_dev_ops_t ns8250_char_dev_ops = {
00242         .read = &ns8250_read,
00243         .write = &ns8250_write
00244 };
00245 
00246 static int ns8250_add_device(ddf_dev_t *dev);
00247 
00249 static driver_ops_t ns8250_ops = {
00250         .add_device = &ns8250_add_device
00251 };
00252 
00254 static driver_t ns8250_driver = {
00255         .name = NAME,
00256         .driver_ops = &ns8250_ops
00257 };
00258 
00263 static void ns8250_dev_cleanup(ns8250_t *ns)
00264 {
00265         if (ns->dev->parent_phone > 0) {
00266                 async_hangup(ns->dev->parent_phone);
00267                 ns->dev->parent_phone = 0;
00268         }
00269 }
00270 
00276 static bool ns8250_pio_enable(ns8250_t *ns)
00277 {
00278         ddf_msg(LVL_DEBUG, "ns8250_pio_enable %s", ns->dev->name);
00279         
00280         /* Gain control over port's registers. */
00281         if (pio_enable((void *)(uintptr_t) ns->io_addr, REG_COUNT,
00282             (void **) &ns->port)) {
00283                 ddf_msg(LVL_ERROR, "Cannot map the port %#" PRIx32
00284                     " for device %s.", ns->io_addr, ns->dev->name);
00285                 return false;
00286         }
00287         
00288         return true;
00289 }
00290 
00296 static bool ns8250_dev_probe(ns8250_t *ns)
00297 {
00298         ddf_msg(LVL_DEBUG, "ns8250_dev_probe %s", ns->dev->name);
00299         
00300         ioport8_t *port_addr = ns->port;
00301         bool res = true;
00302         uint8_t olddata;
00303         
00304         olddata = pio_read_8(port_addr + 4);
00305         
00306         pio_write_8(port_addr + 4, 0x10);
00307         if (pio_read_8(port_addr + 6) & 0xf0)
00308                 res = false;
00309         
00310         pio_write_8(port_addr + 4, 0x1f);
00311         if ((pio_read_8(port_addr + 6) & 0xf0) != 0xf0)
00312                 res = false;
00313         
00314         pio_write_8(port_addr + 4, olddata);
00315         
00316         if (!res) {
00317                 ddf_msg(LVL_DEBUG, "Device %s is not present.",
00318                     ns->dev->name);
00319         }
00320         
00321         return res;
00322 }
00323 
00329 static int ns8250_dev_initialize(ns8250_t *ns)
00330 {
00331         ddf_msg(LVL_DEBUG, "ns8250_dev_initialize %s", ns->dev->name);
00332         
00333         int ret = EOK;
00334         
00335         hw_resource_list_t hw_resources;
00336         memset(&hw_resources, 0, sizeof(hw_resource_list_t));
00337         
00338         /* Connect to the parent's driver. */
00339         ns->dev->parent_phone = devman_parent_device_connect(ns->dev->handle,
00340             IPC_FLAG_BLOCKING);
00341         if (ns->dev->parent_phone < 0) {
00342                 ddf_msg(LVL_ERROR, "Failed to connect to parent driver of "
00343                     "device %s.", ns->dev->name);
00344                 ret = ns->dev->parent_phone;
00345                 goto failed;
00346         }
00347         
00348         /* Get hw resources. */
00349         ret = hw_res_get_resource_list(ns->dev->parent_phone, &hw_resources);
00350         if (ret != EOK) {
00351                 ddf_msg(LVL_ERROR, "Failed to get HW resources for device "
00352                     "%s.", ns->dev->name);
00353                 goto failed;
00354         }
00355         
00356         size_t i;
00357         hw_resource_t *res;
00358         bool irq = false;
00359         bool ioport = false;
00360         
00361         for (i = 0; i < hw_resources.count; i++) {
00362                 res = &hw_resources.resources[i];
00363                 switch (res->type) {
00364                 case INTERRUPT:
00365                         ns->irq = res->res.interrupt.irq;
00366                         irq = true;
00367                         ddf_msg(LVL_NOTE, "Device %s was asigned irq = 0x%x.",
00368                             ns->dev->name, ns->irq);
00369                         break;
00370                         
00371                 case IO_RANGE:
00372                         ns->io_addr = res->res.io_range.address;
00373                         if (res->res.io_range.size < REG_COUNT) {
00374                                 ddf_msg(LVL_ERROR, "I/O range assigned to "
00375                                     "device %s is too small.", ns->dev->name);
00376                                 ret = ELIMIT;
00377                                 goto failed;
00378                         }
00379                         ioport = true;
00380                         ddf_msg(LVL_NOTE, "Device %s was asigned I/O address = "
00381                             "0x%x.", ns->dev->name, ns->io_addr);
00382                         break;
00383                         
00384                 default:
00385                         break;
00386                 }
00387         }
00388         
00389         if (!irq || !ioport) {
00390                 ddf_msg(LVL_ERROR, "Missing HW resource(s) for device %s.",
00391                     ns->dev->name);
00392                 ret = ENOENT;
00393                 goto failed;
00394         }
00395         
00396         hw_res_clean_resource_list(&hw_resources);
00397         return ret;
00398         
00399 failed:
00400         ns8250_dev_cleanup(ns);
00401         hw_res_clean_resource_list(&hw_resources);
00402         return ret;
00403 }
00404 
00411 static inline void ns8250_port_interrupts_enable(ioport8_t *port)
00412 {
00413         pio_write_8(port + 1, 0x1);     /* Interrupt when data received. */
00414         pio_write_8(port + 4, 0xB);
00415 }
00416 
00421 static inline void ns8250_port_interrupts_disable(ioport8_t *port)
00422 {
00423         pio_write_8(port + 1, 0x0);     /* Disable all interrupts. */
00424 }
00425 
00431 static int ns8250_interrupt_enable(ns8250_t *ns)
00432 {
00433         /* Enable interrupt on the serial port. */
00434         ns8250_port_interrupts_enable(ns->port);
00435         
00436         return EOK;
00437 }
00438 
00446 static inline void enable_dlab(ioport8_t *port)
00447 {
00448         uint8_t val = pio_read_8(port + 3);
00449         pio_write_8(port + 3, val | DLAB_MASK);
00450 }
00451 
00456 static inline void clear_dlab(ioport8_t *port)
00457 {
00458         uint8_t val = pio_read_8(port + 3);
00459         pio_write_8(port + 3, val & (~DLAB_MASK));
00460 }
00461 
00469 static int ns8250_port_set_baud_rate(ioport8_t *port, unsigned int baud_rate)
00470 {
00471         uint16_t divisor;
00472         uint8_t div_low, div_high;
00473         
00474         if (baud_rate < 50 || MAX_BAUD_RATE % baud_rate != 0) {
00475                 ddf_msg(LVL_ERROR, "Invalid baud rate %d requested.",
00476                     baud_rate);
00477                 return EINVAL;
00478         }
00479         
00480         divisor = MAX_BAUD_RATE / baud_rate;
00481         div_low = (uint8_t)divisor;
00482         div_high = (uint8_t)(divisor >> 8);
00483         
00484         /* Enable DLAB to be able to access baud rate divisor. */
00485         enable_dlab(port);
00486         
00487         /* Set divisor low byte. */
00488         pio_write_8(port + 0, div_low);
00489         /* Set divisor high byte. */
00490         pio_write_8(port + 1, div_high);
00491         
00492         clear_dlab(port);
00493         
00494         return EOK;
00495 }
00496 
00502 static unsigned int ns8250_port_get_baud_rate(ioport8_t *port)
00503 {
00504         uint16_t divisor;
00505         uint8_t div_low, div_high;
00506         
00507         /* Enable DLAB to be able to access baud rate divisor. */
00508         enable_dlab(port);
00509         
00510         /* Get divisor low byte. */
00511         div_low = pio_read_8(port + 0);
00512         /* Get divisor high byte. */
00513         div_high = pio_read_8(port + 1);
00514         
00515         clear_dlab(port);
00516         
00517         divisor = (div_high << 8) | div_low;
00518         return MAX_BAUD_RATE / divisor;
00519 }
00520 
00528 static void ns8250_port_get_com_props(ioport8_t *port, unsigned int *parity,
00529     unsigned int *word_length, unsigned int *stop_bits)
00530 {
00531         uint8_t val;
00532         
00533         val = pio_read_8(port + 3);
00534         *parity = ((val >> 3) & 7);
00535         
00536         switch (val & 3) {
00537         case WORD_LENGTH_5:
00538                 *word_length = 5;
00539                 break;
00540         case WORD_LENGTH_6:
00541                 *word_length = 6;
00542                 break;
00543         case WORD_LENGTH_7:
00544                 *word_length = 7;
00545                 break;
00546         case WORD_LENGTH_8:
00547                 *word_length = 8;
00548                 break;
00549         }
00550         
00551         if ((val >> 2) & 1)
00552                 *stop_bits = 2;
00553         else
00554                 *stop_bits = 1;
00555 }
00556 
00565 static int ns8250_port_set_com_props(ioport8_t *port, unsigned int parity,
00566     unsigned int word_length, unsigned int stop_bits)
00567 {
00568         uint8_t val;
00569         
00570         switch (word_length) {
00571         case 5:
00572                 val = WORD_LENGTH_5;
00573                 break;
00574         case 6:
00575                 val = WORD_LENGTH_6;
00576                 break;
00577         case 7:
00578                 val = WORD_LENGTH_7;
00579                 break;
00580         case 8:
00581                 val = WORD_LENGTH_8;
00582                 break;
00583         default:
00584                 return EINVAL;
00585         }
00586         
00587         switch (stop_bits) {
00588         case 1:
00589                 val |= ONE_STOP_BIT << 2;
00590                 break;
00591         case 2:
00592                 val |= TWO_STOP_BITS << 2;
00593                 break;
00594         default:
00595                 return EINVAL;
00596         }
00597         
00598         switch (parity) {
00599         case SERIAL_NO_PARITY:
00600         case SERIAL_ODD_PARITY:
00601         case SERIAL_EVEN_PARITY:
00602         case SERIAL_MARK_PARITY:
00603         case SERIAL_SPACE_PARITY:
00604                 val |= parity << 3;
00605                 break;
00606         default:
00607                 return EINVAL;
00608         }
00609         
00610         pio_write_8(port + 3, val);
00611         
00612         return EOK;
00613 }
00614 
00621 static void ns8250_initialize_port(ns8250_t *ns)
00622 {
00623         ioport8_t *port = ns->port;
00624         
00625         /* Disable interrupts. */
00626         ns8250_port_interrupts_disable(port);
00627         /* Set baud rate. */
00628         ns8250_port_set_baud_rate(port, 38400);
00629         /* 8 bits, no parity, two stop bits. */
00630         ns8250_port_set_com_props(port, SERIAL_NO_PARITY, 8, 2);
00631         /* Enable FIFO, clear them, with 14-byte threshold. */
00632         pio_write_8(port + 2, 0xC7);
00633         /*
00634          * RTS/DSR set (Request to Send and Data Terminal Ready lines enabled),
00635          * Aux Output2 set - needed for interrupts.
00636          */
00637         pio_write_8(port + 4, 0x0B);
00638 }
00639 
00645 static void ns8250_read_from_device(ns8250_t *ns)
00646 {
00647         ioport8_t *port = ns->port;
00648         bool cont = true;
00649         
00650         while (cont) {
00651                 fibril_mutex_lock(&ns->mutex);
00652                 
00653                 cont = ns8250_received(port);
00654                 if (cont) {
00655                         uint8_t val = ns8250_read_8(port);
00656                         
00657                         if (ns->client_connected) {
00658                                 if (!buf_push_back(&ns->input_buffer, val)) {
00659                                         ddf_msg(LVL_WARN, "Buffer overflow on "
00660                                             "%s.", ns->dev->name);
00661                                 } else {
00662                                         ddf_msg(LVL_DEBUG2, "Character %c saved "
00663                                             "to the buffer of %s.",
00664                                             val, ns->dev->name);
00665                                 }
00666                         }
00667                 }
00668                 
00669                 fibril_mutex_unlock(&ns->mutex);
00670                 fibril_yield();
00671         }
00672 }
00673 
00681 static inline void ns8250_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid,
00682     ipc_call_t *icall)
00683 {
00684         ns8250_read_from_device(NS8250_FROM_DEV(dev));
00685 }
00686 
00691 static inline int ns8250_register_interrupt_handler(ns8250_t *ns)
00692 {
00693         return register_interrupt_handler(ns->dev, ns->irq,
00694             ns8250_interrupt_handler, NULL);
00695 }
00696 
00701 static inline int ns8250_unregister_interrupt_handler(ns8250_t *ns)
00702 {
00703         return unregister_interrupt_handler(ns->dev, ns->irq);
00704 }
00705 
00712 static int ns8250_add_device(ddf_dev_t *dev)
00713 {
00714         ns8250_t *ns = NULL;
00715         ddf_fun_t *fun = NULL;
00716         bool need_cleanup = false;
00717         int rc;
00718         
00719         ddf_msg(LVL_DEBUG, "ns8250_add_device %s (handle = %d)",
00720             dev->name, (int) dev->handle);
00721         
00722         /* Allocate soft-state for the device */
00723         ns = ns8250_new();
00724         if (ns == NULL) {
00725                 rc = ENOMEM;
00726                 goto fail;
00727         }
00728         
00729         ns->dev = dev;
00730         dev->driver_data = ns;
00731         
00732         rc = ns8250_dev_initialize(ns);
00733         if (rc != EOK)
00734                 goto fail;
00735         
00736         need_cleanup = true;
00737         
00738         if (!ns8250_pio_enable(ns)) {
00739                 rc = EADDRNOTAVAIL;
00740                 goto fail;
00741         }
00742         
00743         /* Find out whether the device is present. */
00744         if (!ns8250_dev_probe(ns)) {
00745                 rc = ENOENT;
00746                 goto fail;
00747         }
00748         
00749         /* Serial port initialization (baud rate etc.). */
00750         ns8250_initialize_port(ns);
00751         
00752         /* Register interrupt handler. */
00753         if (ns8250_register_interrupt_handler(ns) != EOK) {
00754                 ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
00755                 rc = EADDRNOTAVAIL;
00756                 goto fail;
00757         }
00758         
00759         /* Enable interrupt. */
00760         rc = ns8250_interrupt_enable(ns);
00761         if (rc != EOK) {
00762                 ddf_msg(LVL_ERROR, "Failed to enable the interrupt. Error code = "
00763                     "%d.", rc);
00764                 goto fail;
00765         }
00766         
00767         fun = ddf_fun_create(dev, fun_exposed, "a");
00768         if (fun == NULL) {
00769                 ddf_msg(LVL_ERROR, "Failed creating function.");
00770                 goto fail;
00771         }
00772         
00773         /* Set device operations. */
00774         fun->ops = &ns8250_dev_ops;
00775         rc = ddf_fun_bind(fun);
00776         if (rc != EOK) {
00777                 ddf_msg(LVL_ERROR, "Failed binding function.");
00778                 goto fail;
00779         }
00780 
00781         ns->fun = fun;
00782         
00783         ddf_fun_add_to_class(fun, "serial");
00784         
00785         ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
00786             dev->name);
00787         
00788         return EOK;
00789 fail:
00790         if (fun != NULL)
00791                 ddf_fun_destroy(fun);
00792         if (need_cleanup)
00793                 ns8250_dev_cleanup(ns);
00794         if (ns != NULL)
00795                 ns8250_delete(ns);
00796         return rc;
00797 }
00798 
00806 static int ns8250_open(ddf_fun_t *fun)
00807 {
00808         ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
00809         int res;
00810         
00811         fibril_mutex_lock(&data->mutex);
00812         if (data->client_connected) {
00813                 res = ELIMIT;
00814         } else {
00815                 res = EOK;
00816                 data->client_connected = true;
00817         }
00818         fibril_mutex_unlock(&data->mutex);
00819         
00820         return res;
00821 }
00822 
00830 static void ns8250_close(ddf_fun_t *fun)
00831 {
00832         ns8250_t *data = (ns8250_t *) fun->dev->driver_data;
00833         
00834         fibril_mutex_lock(&data->mutex);
00835         
00836         assert(data->client_connected);
00837         
00838         data->client_connected = false;
00839         buf_clear(&data->input_buffer);
00840         
00841         fibril_mutex_unlock(&data->mutex);
00842 }
00843 
00853 static void
00854 ns8250_get_props(ddf_dev_t *dev, unsigned int *baud_rate, unsigned int *parity,
00855     unsigned int *word_length, unsigned int* stop_bits)
00856 {
00857         ns8250_t *data = (ns8250_t *) dev->driver_data;
00858         ioport8_t *port = data->port;
00859         
00860         fibril_mutex_lock(&data->mutex);
00861         ns8250_port_interrupts_disable(port);
00862         *baud_rate = ns8250_port_get_baud_rate(port);
00863         ns8250_port_get_com_props(port, parity, word_length, stop_bits);
00864         ns8250_port_interrupts_enable(port);
00865         fibril_mutex_unlock(&data->mutex);
00866         
00867         ddf_msg(LVL_DEBUG, "ns8250_get_props: baud rate %d, parity 0x%x, word "
00868             "length %d, stop bits %d", *baud_rate, *parity, *word_length,
00869             *stop_bits);
00870 }
00871 
00881 static int ns8250_set_props(ddf_dev_t *dev, unsigned int baud_rate,
00882     unsigned int parity, unsigned int word_length, unsigned int stop_bits)
00883 {
00884         ddf_msg(LVL_DEBUG, "ns8250_set_props: baud rate %d, parity 0x%x, word "
00885             "length %d, stop bits %d", baud_rate, parity, word_length,
00886             stop_bits);
00887         
00888         ns8250_t *data = (ns8250_t *) dev->driver_data;
00889         ioport8_t *port = data->port;
00890         int ret;
00891         
00892         fibril_mutex_lock(&data->mutex);
00893         ns8250_port_interrupts_disable(port);
00894         ret = ns8250_port_set_baud_rate(port, baud_rate);
00895         if (ret == EOK)
00896                 ret = ns8250_port_set_com_props(port, parity, word_length, stop_bits);
00897         ns8250_port_interrupts_enable(port);
00898         fibril_mutex_unlock(&data->mutex);
00899         
00900         return ret;
00901 }
00902 
00908 static void ns8250_default_handler(ddf_fun_t *fun, ipc_callid_t callid,
00909     ipc_call_t *call)
00910 {
00911         sysarg_t method = IPC_GET_IMETHOD(*call);
00912         int ret;
00913         unsigned int baud_rate, parity, word_length, stop_bits;
00914         
00915         switch (method) {
00916         case SERIAL_GET_COM_PROPS:
00917                 ns8250_get_props(fun->dev, &baud_rate, &parity, &word_length,
00918                     &stop_bits);
00919                 async_answer_4(callid, EOK, baud_rate, parity, word_length,
00920                     stop_bits);
00921                 break;
00922                 
00923         case SERIAL_SET_COM_PROPS:
00924                 baud_rate = IPC_GET_ARG1(*call);
00925                 parity = IPC_GET_ARG2(*call);
00926                 word_length = IPC_GET_ARG3(*call);
00927                 stop_bits = IPC_GET_ARG4(*call);
00928                 ret = ns8250_set_props(fun->dev, baud_rate, parity, word_length,
00929                     stop_bits);
00930                 async_answer_0(callid, ret);
00931                 break;
00932                 
00933         default:
00934                 async_answer_0(callid, ENOTSUP);
00935         }
00936 }
00937 
00943 static void ns8250_init(void)
00944 {
00945         ddf_log_init(NAME, LVL_ERROR);
00946         
00947         ns8250_dev_ops.open = &ns8250_open;
00948         ns8250_dev_ops.close = &ns8250_close;
00949         
00950         ns8250_dev_ops.interfaces[CHAR_DEV_IFACE] = &ns8250_char_dev_ops;
00951         ns8250_dev_ops.default_handler = &ns8250_default_handler;
00952 }
00953 
00954 int main(int argc, char *argv[])
00955 {
00956         printf(NAME ": HelenOS serial port driver\n");
00957         ns8250_init();
00958         return ddf_driver_main(&ns8250_driver);
00959 }
00960 

Generated on Thu Jun 2 07:45:44 2011 for HelenOS/USB by  doxygen 1.4.7