Changeset 86554e7 in mainline for uspace/srv/pci/serial.c


Ignore:
Timestamp:
2009-11-16T15:21:44Z (14 years ago)
Author:
Lenka Trochtova <trochtova.lenka@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f052c57
Parents:
8344d0a
Message:

serial port now uses interrupts for receiving data

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/pci/serial.c

    r8344d0a r86554e7  
    1818#include "isa.h"
    1919#include "serial.h"
     20#include "pic.h"
    2021
    2122#define NAME "serial"
     
    2425
    2526#define MAX_NAME_LEN 8
     27#define BUF_LEN 256  // the length of the input buffer
     28
     29struct cyclic_buffer {
     30        uint8_t buf[BUF_LEN];  // cyclic buffer
     31        int start;
     32        int cnt;
     33};
     34
     35typedef struct cyclic_buffer cyclic_buffer_t;
     36
     37// returns false if the buffer is full
     38static bool buf_push_back(cyclic_buffer_t *buf, uint8_t item)
     39{
     40        if (buf->cnt >= BUF_LEN) {
     41                return false;
     42        }
     43       
     44        int pos = (buf->start + buf->cnt) % BUF_LEN;
     45        buf->buf[pos] = item;
     46        buf->cnt++;
     47        return true;
     48}
     49
     50static bool buf_is_empty(cyclic_buffer_t *buf)
     51{
     52        return buf->cnt == 0;
     53}
     54
     55// call it on non empty buffer!
     56static uint8_t buf_pop_front(cyclic_buffer_t *buf)
     57{
     58        assert(!buf_is_empty(buf));
     59       
     60        uint8_t res = buf->buf[buf->start];
     61        buf->start = (buf->start + 1) % BUF_LEN;       
     62        buf->cnt--;
     63        return res;
     64}
     65
     66static void buf_clear(cyclic_buffer_t *buf)
     67{
     68        buf->cnt = 0;
     69}
    2670
    2771struct serial_dev {
    2872        link_t link;
    2973        char name[MAX_NAME_LEN];
    30         int handle;
     74        int handle; // devmapper device handle
     75        int devno; // unique device number; used in irq registration (cannot be handle used instead of it?)
    3176        bool client_connected;
    3277        ioport8_t *port;
    3378        void *phys_addr;
     79        int irq;
    3480        bridge_to_isa_t *parent;
     81        cyclic_buffer_t input_buffer;
     82        futex_t futex;
    3583};
    3684
    3785typedef struct serial_dev serial_dev_t;
    3886
     87static irq_cmd_t serial_cmds[] = {
     88        {
     89                .cmd = CMD_ACCEPT
     90        }
     91};
     92
     93static irq_code_t serial_pseudocode = {
     94        sizeof(serial_cmds) / sizeof(irq_cmd_t),
     95        serial_cmds
     96};
     97
    3998static void * serial_phys_addresses[] = { (void *)0x3F8, (void *)0x2F8 };
     99static int serial_irqs[] = { 4, 3 }; // TODO - what about if there were more than two serial ports?
    40100static int serial_phys_addr_cnt = sizeof(serial_phys_addresses)/sizeof(void *);
     101static int serial_irq_cnt = sizeof(serial_irqs)/sizeof(int);
     102
    41103// number, which should be assigned to a newly found serial device - increment first, then assign to the device
    42104static int serial_idx = 0;
     
    61123static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid);
    62124static void serial_client_conn(ipc_callid_t iid, ipc_call_t *icall);
     125static void serial_irq_handler(ipc_callid_t iid, ipc_call_t *icall);
     126static serial_dev_t * serial_devno_to_dev(int devno);
     127static serial_dev_t * serial_handle_to_dev(int handle);
     128static void serial_enable_interrupt(serial_dev_t *dev);
    63129
    64130static isa_drv_ops_t serial_isa_ops = {
     
    77143    if (serial_driver_phone < 0) {
    78144                printf(NAME ": Unable to register driver\n");
    79                 return false;
    80         }
     145                return 0;
     146        }
     147       
     148        // register irq handler
     149        printf(NAME ": Registering interrup notification callback function.\n");
     150        async_set_interrupt_received(serial_irq_handler);
    81151           
    82152        // register this driver by generic isa bus driver       
     
    92162static uint8_t serial_read_8(ioport8_t *port)
    93163{
    94         while (!serial_received(port))
    95                 ;
    96 
    97         uint8_t c = pio_read_8(port);
    98         return c;
     164        return pio_read_8(port);
    99165}
    100166
     
    120186        pio_write_8(port + 3, 0x07);    // 8 bits, no parity, two stop bits
    121187        pio_write_8(port + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
    122         pio_write_8(port + 4, 0x0B);    // RTS/DSR set (Request to Send and Data Terminal Ready lines enabled), Aux Output2 set
     188        pio_write_8(port + 4, 0x0B);    // RTS/DSR set (Request to Send and Data Terminal Ready lines enabled),
     189                                                                        // Aux Output2 set - needed for interrupts
     190         
     191}
     192
     193static void serial_enable_interrupt(serial_dev_t *dev)
     194{
     195        futex_down(&(dev->futex));
     196        // TODO do not call pic directly, do it more generally
     197        pic_enable_interrupt(dev->irq);
     198        pio_write_8(dev->port + 1 , 0x01);   // Interrupt when data received
     199        pio_write_8(dev->port + 4, 0x0B);
     200        futex_up(&(dev->futex));
    123201}
    124202
     
    137215        dev->parent = parent;
    138216        dev->phys_addr = dev->parent->ops->absolutize(serial_phys_addresses[idx % serial_phys_addr_cnt]);
     217        dev->irq = serial_irqs[idx % serial_irq_cnt];
    139218        snprintf(dev->name, MAX_NAME_LEN, "com%d", idx + 1);
    140         dev->client_connected = false; 
     219        dev->devno = -1;
     220        dev->client_connected = false;
     221        futex_initialize(&(dev->futex), 1);
    141222}
    142223
     
    145226        assert(dev != NULL);
    146227       
    147         printf(NAME " driver: probing %s \n", dev->name);
    148228        return (dev->port = (ioport8_t *)serial_probe_port(dev->phys_addr)) != NULL;   
    149229}
     
    160240       
    161241        int i;
    162         for (i = 0; i < serial_phys_addr_cnt; i++) {           
     242        for (i = 0; i < serial_phys_addr_cnt; i++) {                   
    163243                serial_init_dev(dev, parent, serial_idx);
     244                printf(NAME ": probing %s. \n", dev->name);
    164245                if (serial_probe_dev(dev)) {
    165246                        printf(NAME " driver: initializing %s.\n", dev->name);
    166247                        serial_init_port(dev->port);
    167248                        if (EOK != serial_device_register(serial_driver_phone, dev->name, &(dev->handle))) {
    168                                 printf(NAME ": Unable to register device %s\n", dev->name);
    169                         }       
    170                         list_append(&(dev->link), &serial_devices_list);
    171                         dev = serial_alloc_dev();
     249                                printf(NAME ": unable to register device %s\n", dev->name);
     250                        } else {
     251                                dev->devno = device_assign_devno();
     252                               
     253                                // 3rd argument called method is equal devno,this enables us to identify the device
     254                                // which caused the interrupt in the irq notification callback function
     255                                printf(NAME ": registering irq = %d for %s.\n", dev->irq, dev->name);
     256                                ipc_register_irq(dev->irq, dev->devno, dev->devno, &serial_pseudocode); 
     257                                list_append(&(dev->link), &serial_devices_list);
     258                                printf(NAME ": enabling irq = %d for %s.\n", dev->irq, dev->name);
     259                                serial_enable_interrupt(dev);
     260                                dev = serial_alloc_dev();
     261                        }
    172262                } else {
    173263                        printf(NAME " driver: %s is not present \n", dev->name);
     
    210300{
    211301        int c = IPC_GET_ARG1(*request);
     302        futex_down(&(dev->futex));
    212303        serial_write_8(dev->port, (uint8_t)c); 
     304        futex_up(&(dev->futex));
    213305        ipc_answer_0(rid, EOK);
    214306}
     
    216308static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid)
    217309{
    218         uint8_t c = serial_read_8(dev->port);   
     310        uint8_t c;
     311        printf(NAME ": trying to read from serial port %s\n", dev->name);
     312        while (true) {  // TODO: fix it - the queue of requests to read ?
     313                futex_down(&(dev->futex));
     314                if (!buf_is_empty(&(dev->input_buffer))) {
     315                        c = buf_pop_front(&(dev->input_buffer));
     316                        futex_up(&(dev->futex));
     317                        break;
     318                }
     319                //printf(NAME "no data ready, trying to read again after some while.\n", dev->name);
     320                futex_up(&(dev->futex));
     321                async_usleep(10000);
     322        }
     323        printf(NAME ": serial_getchar: sending characer %c read from %s to client.\n", c, dev->name);
    219324        ipc_answer_1(rid, EOK, c);             
    220325}
    221326
    222 static serial_dev_t * serial_handle_to_dev(int handle) {
    223        
     327static serial_dev_t * serial_handle_to_dev(int handle)
     328{       
    224329        futex_down(&serial_futex);     
    225330       
     
    230335                dev = list_get_instance(item, serial_dev_t, link);
    231336                if (dev->handle == handle) {
     337                        futex_up(&serial_futex);
     338                        return dev;
     339                }
     340                item = item->next;
     341        }
     342       
     343        futex_up(&serial_futex);
     344        return NULL;
     345}
     346
     347static serial_dev_t * serial_devno_to_dev(int devno)
     348{               
     349        futex_down(&serial_futex);     
     350       
     351        link_t *item = serial_devices_list.next;
     352        serial_dev_t *dev = NULL;
     353       
     354        while (item != &serial_devices_list) {
     355                dev = list_get_instance(item, serial_dev_t, link);
     356                if (dev->devno == devno) {
    232357                        futex_up(&serial_futex);
    233358                        return dev;
     
    262387                return;
    263388        }
    264        
     389               
     390        buf_clear(&(dev->input_buffer));  // synchronization with interrupt service routine ?
    265391        dev->client_connected = true;
    266392        ipc_answer_0(iid, EOK);
     
    310436        while (phone < 0) {
    311437                usleep(10000);
    312                 phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
    313                     DEVMAP_DRIVER, 0);
     438                phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
    314439        }
    315440       
     
    336461        aid_t req;
    337462        ipc_call_t answer;
     463       
     464        if (handle != NULL) {
     465                *handle = -1;
     466        }
    338467
    339468        req = async_send_2(driver_phone, DEVMAP_DEVICE_REGISTER, 0, 0, &answer);
     
    347476
    348477        async_wait_for(req, &retval);
    349 
    350         if (handle != NULL)
    351                 *handle = -1;
    352478       
    353479        if (EOK == retval) {
     
    358484        return retval;
    359485}
     486
     487static void serial_read_from_device(serial_dev_t *dev)
     488{       
     489        bool cont = true;
     490       
     491        while (cont) { 
     492                futex_down(&(dev->futex));
     493                if (cont = serial_received(dev->port)) {
     494                        uint8_t val = serial_read_8(dev->port);
     495                        printf(NAME ": character %c read from %s.\n", val, dev->name);
     496                        if (dev->client_connected) {
     497                                if (!buf_push_back(&(dev->input_buffer), val)) {
     498                                        printf(NAME ": buffer overflow on %s.\n", dev->name);
     499                                } else {
     500                                        printf(NAME ": the character %c saved to the buffer of %s.\n", val, dev->name);
     501                                }
     502                        } else {
     503                                printf(NAME ": no client is connected to %s, discarding the character which was read.\n", dev->name);
     504                        }
     505                }
     506                futex_up(&(dev->futex));
     507                usleep(10000);
     508        }       
     509}
     510
     511// TODO - this is the only irq handling function registered by this task.
     512// (A task can register only one such function.)
     513// If more drivers within the task needed to handle interrupts,
     514// there will have to be one generic handler redistributing
     515// irq notification messages among them.
     516// Or the change of ansync framework will be needed.
     517static void serial_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
     518{
     519        printf(NAME ": irq handler\n");
     520        int devno = IPC_GET_METHOD(*icall);
     521        serial_dev_t *dev = serial_devno_to_dev(devno);
     522        serial_read_from_device(dev);   
     523}
     524
Note: See TracChangeset for help on using the changeset viewer.