00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
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
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
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);
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);
00424 }
00425
00431 static int ns8250_interrupt_enable(ns8250_t *ns)
00432 {
00433
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
00485 enable_dlab(port);
00486
00487
00488 pio_write_8(port + 0, div_low);
00489
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
00508 enable_dlab(port);
00509
00510
00511 div_low = pio_read_8(port + 0);
00512
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
00626 ns8250_port_interrupts_disable(port);
00627
00628 ns8250_port_set_baud_rate(port, 38400);
00629
00630 ns8250_port_set_com_props(port, SERIAL_NO_PARITY, 8, 2);
00631
00632 pio_write_8(port + 2, 0xC7);
00633
00634
00635
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
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
00744 if (!ns8250_dev_probe(ns)) {
00745 rc = ENOENT;
00746 goto fail;
00747 }
00748
00749
00750 ns8250_initialize_port(ns);
00751
00752
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
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
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