Changeset 013c4d6 in mainline for kernel/genarch/src/kbd/ns16550.c


Ignore:
Timestamp:
2009-02-19T23:55:23Z (15 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f32d90b
Parents:
d1eece6
Message:

Improve the ns16550 driver.

  • The driver support multiple instances.
  • It still remembers the last registered IRQ in a global structure (cannot be easily fixed now)
  • Was converted to use PIO directly
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/genarch/src/kbd/ns16550.c

    rd1eece6 r013c4d6  
    5151#include <sysinfo/sysinfo.h>
    5252#include <synch/spinlock.h>
     53#include <mm/slab.h>
    5354
    5455#define LSR_DATA_READY  0x01
    5556
    56 /** Structure representing the ns16550. */
    57 static ns16550_t ns16550;
    58 
    59 /** Structure for ns16550's IRQ. */
    60 static irq_t ns16550_irq;
     57static irq_t *ns16550_irq;
    6158
    6259/*
     
    7168        .suspend = ns16550_suspend,
    7269        .resume = ns16550_resume,
    73         .read = ns16550_key_read
    7470};
    75 
    76 void ns16550_interrupt(void);
    7771
    7872/** Initialize keyboard and service interrupts using kernel routine */
     
    8074{
    8175        ipl_t ipl = interrupts_disable();
    82 
    83         ns16550_ier_write(&ns16550, IER_ERBFI);         /* enable receiver interrupt */
    84        
    85         while (ns16550_lsr_read(&ns16550) & LSR_DATA_READY)
    86                 (void) ns16550_rbr_read(&ns16550);
    87 
    88         spinlock_lock(&ns16550_irq.lock);
    89         ns16550_irq.notif_cfg.notify = false;
    90         spinlock_unlock(&ns16550_irq.lock);
     76        spinlock_lock(&ns16550_irq->lock);
     77        ns16550_irq->notif_cfg.notify = false;
     78        spinlock_unlock(&ns16550_irq->lock);
    9179        interrupts_restore(ipl);
    9280}
     
    9684{
    9785        ipl_t ipl = interrupts_disable();
    98         spinlock_lock(&ns16550_irq.lock);
    99         if (ns16550_irq.notif_cfg.answerbox)
    100                 ns16550_irq.notif_cfg.notify = true;
    101         spinlock_unlock(&ns16550_irq.lock);
     86        spinlock_lock(&ns16550_irq->lock);
     87        if (ns16550_irq->notif_cfg.answerbox)
     88                ns16550_irq->notif_cfg.notify = true;
     89        spinlock_unlock(&ns16550_irq->lock);
    10290        interrupts_restore(ipl);
    10391}
     
    10593/** Initialize ns16550.
    10694 *
     95 * @param dev           Addrress of the beginning of the device in I/O space.
    10796 * @param devno         Device number.
    108  * @param port          Virtual/IO address of device's registers.
    10997 * @param inr           Interrupt number.
    11098 * @param cir           Clear interrupt function.
    11199 * @param cir_arg       First argument to cir.
    112  */
    113 void
    114 ns16550_init(devno_t devno, ioport_t port, inr_t inr, cir_t cir, void *cir_arg)
    115 {
     100 *
     101 * @return              True on success, false on failure.
     102 */
     103bool
     104ns16550_init(ns16550_t *dev, devno_t devno, inr_t inr, cir_t cir, void *cir_arg)
     105{
     106        ns16550_instance_t *instance;
     107        irq_t *irq;
     108
    116109        chardev_initialize("ns16550_kbd", &kbrd, &ops);
    117110        stdin = &kbrd;
    118111       
    119         ns16550.devno = devno;
    120         ns16550.io_port = port;
    121        
    122         irq_initialize(&ns16550_irq);
    123         ns16550_irq.devno = devno;
    124         ns16550_irq.inr = inr;
    125         ns16550_irq.claim = ns16550_claim;
    126         ns16550_irq.handler = ns16550_irq_handler;
    127         ns16550_irq.cir = cir;
    128         ns16550_irq.cir_arg = cir_arg;
    129         irq_register(&ns16550_irq);
    130        
    131         while ((ns16550_lsr_read(&ns16550) & LSR_DATA_READY))
    132                 ns16550_rbr_read(&ns16550);
     112        instance = malloc(sizeof(ns16550_instance_t), FRAME_ATOMIC);
     113        if (!instance)
     114                return false;
     115
     116        irq = malloc(sizeof(irq_t), FRAME_ATOMIC);
     117        if (!irq) {
     118                free(instance);
     119                return false;
     120        }
     121
     122        instance->devno = devno;
     123        instance->ns16550 = dev;
     124        instance->irq = irq;
     125       
     126        irq_initialize(irq);
     127        irq->devno = devno;
     128        irq->inr = inr;
     129        irq->claim = ns16550_claim;
     130        irq->handler = ns16550_irq_handler;
     131        irq->instance = instance;
     132        irq->cir = cir;
     133        irq->cir_arg = cir_arg;
     134        irq_register(irq);
     135
     136        ns16550_irq = irq;      /* TODO: remove me soon */
     137       
     138        while ((pio_read_8(&dev->lsr) & LSR_DATA_READY))
     139                (void) pio_read_8(&dev->rbr);
    133140       
    134141        sysinfo_set_item_val("kbd", NULL, true);
     
    136143        sysinfo_set_item_val("kbd.devno", NULL, devno);
    137144        sysinfo_set_item_val("kbd.inr", NULL, inr);
    138         sysinfo_set_item_val("kbd.address.virtual", NULL, port);
    139         sysinfo_set_item_val("kbd.port", NULL, port);
     145        sysinfo_set_item_val("kbd.address.virtual", NULL, (uintptr_t) dev);
     146        sysinfo_set_item_val("kbd.port", NULL, (uintptr_t) dev);
    140147       
    141148        /* Enable interrupts */
    142         ns16550_ier_write(&ns16550, IER_ERBFI);
    143         ns16550_mcr_write(&ns16550, MCR_OUT2);
    144        
    145         uint8_t c;
    146         // This switches rbr & ier to mode when accept baudrate constant
    147         c = ns16550_lcr_read(&ns16550);
    148         ns16550_lcr_write(&ns16550, 0x80 | c);
    149         ns16550_rbr_write(&ns16550, 0x0c);
    150         ns16550_ier_write(&ns16550, 0x00);
    151         ns16550_lcr_write(&ns16550, c);
     149        pio_write_8(&dev->ier, IER_ERBFI);
     150        pio_write_8(&dev->mcr, MCR_OUT2);
    152151       
    153152        ns16550_grab();
    154 }
    155 
    156 /** Process ns16550 interrupt. */
    157 void ns16550_interrupt(void)
    158 {
    159         ns16550_poll();
     153       
     154        return true;
    160155}
    161156
     
    170165}
    171166
    172 
    173 char ns16550_key_read(chardev_t *d)
    174 {
    175         char ch;       
    176 
    177         while(!(ch = active_read_buff_read())) {
    178                 uint8_t x;
    179                 while (!(ns16550_lsr_read(&ns16550) & LSR_DATA_READY));
    180                
    181                 x = ns16550_rbr_read(&ns16550);
    182                
    183                 if (x != IGNORE_CODE) {
    184                         if (x & KEY_RELEASE)
    185                                 key_released(x ^ KEY_RELEASE);
    186                         else
    187                                 active_read_key_pressed(x);
    188                 }
     167irq_ownership_t ns16550_claim(void *instance)
     168{
     169        ns16550_instance_t *ns16550_instance = instance;
     170        ns16550_t *dev = ns16550_instance->ns16550;
     171
     172        if (pio_read_8(&dev->lsr) & LSR_DATA_READY)
     173                return IRQ_ACCEPT;
     174        else
     175                return IRQ_DECLINE;
     176}
     177
     178void ns16550_irq_handler(irq_t *irq)
     179{
     180        if (irq->notif_cfg.notify && irq->notif_cfg.answerbox) {
     181                /*
     182                 * This will hopefully go to the IRQ dispatch code soon.
     183                 */
     184                ipc_irq_send_notif(irq);
     185                return;
    189186        }
    190         return ch;
    191 }
    192 
    193 /** Poll for key press and release events.
    194  *
    195  * This function can be used to implement keyboard polling.
    196  */
    197 void ns16550_poll(void)
    198 {
    199         while (ns16550_lsr_read(&ns16550) & LSR_DATA_READY) {
     187
     188        ns16550_instance_t *ns16550_instance = irq->instance;
     189        ns16550_t *dev = ns16550_instance->ns16550;
     190
     191        if (pio_read_8(&dev->lsr) & LSR_DATA_READY) {
    200192                uint8_t x;
    201193               
    202                 x = ns16550_rbr_read(&ns16550);
     194                x = pio_read_8(&dev->rbr);
    203195               
    204196                if (x != IGNORE_CODE) {
     
    209201                }
    210202        }
    211 }
    212 
    213 irq_ownership_t ns16550_claim(void *instance)
    214 {
    215         return (ns16550_lsr_read(&ns16550) & LSR_DATA_READY);
    216 }
    217 
    218 void ns16550_irq_handler(irq_t *irq)
    219 {
    220         if (irq->notif_cfg.notify && irq->notif_cfg.answerbox)
    221                 ipc_irq_send_notif(irq);
    222         else
    223                 ns16550_interrupt();
     203
    224204}
    225205
Note: See TracChangeset for help on using the changeset viewer.