Changeset 013c4d6 in mainline


Ignore:
Timestamp:
2009-02-19T23:55:23Z (16 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
Location:
kernel
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/ia64/src/ia64.c

    rd1eece6 r013c4d6  
    6666/* NS16550 as a COM 1 */
    6767#define NS16550_IRQ     (4 + LEGACY_INTERRUPT_BASE)
    68 #define NS16550_PORT    0x3f8
    6968
    7069bootinfo_t *bootinfo;
     
    165164
    166165#ifdef CONFIG_NS16550
    167         ns16550_init(kbd, NS16550_PORT, NS16550_IRQ, NULL, NULL);
     166        (void) ns16550_init((ns16550_t *)NS16550_BASE, kbd, NS16550_IRQ, NULL,
     167             NULL);
    168168#else
    169169        devno_t mouse = device_assign_devno();
     
    250250void arch_reboot(void)
    251251{
    252         pio_write_8(0x64, 0xfe);
     252        pio_write_8((ioport8_t *)0x64, 0xfe);
    253253        while (1)
    254254                ;
  • kernel/arch/ia64/src/smp/smp.c

    rd1eece6 r013c4d6  
    5252#include <ddi/irq.h>
    5353#include <ddi/device.h>
    54 #include <arch/drivers/ega.h>
    5554#include <arch/bootinfo.h>
    5655#include <genarch/kbd/i8042.h>
  • kernel/genarch/include/drivers/legacy/ia32/io.h

    rd1eece6 r013c4d6  
    4040#include <arch/types.h>
    4141
    42 #define i8042_BASE      ((ioport8_t *)0x60)
     42#define I8042_BASE      ((ioport8_t *)0x60)
    4343
    4444#define EGA_VIDEORAM    0xb8000
    4545#define EGA_BASE        ((ioport8_t *)0x3d4)
     46
     47#define NS16550_BASE    ((ioport8_t *)0x3f8)
    4648
    4749#endif
  • kernel/genarch/include/kbd/i8042.h

    rd1eece6 r013c4d6  
    3737
    3838#include <arch/types.h>
    39 #include <console/chardev.h>
     39#include <typedefs.h>
    4040
    4141struct i8042 {
     
    5353extern void i8042_grab(void);
    5454extern void i8042_release(void);
    55 extern char i8042_key_read(chardev_t *d);
    5655
    5756#endif
  • kernel/genarch/include/kbd/ns16550.h

    rd1eece6 r013c4d6  
    3838#define KERN_NS16550_H_
    3939
    40 #include <console/chardev.h>
    4140#include <ddi/irq.h>
    42 #include <ipc/irq.h>
    43 
    44 extern void ns16550_init(devno_t, uintptr_t, inr_t, cir_t, void *);
    45 extern void ns16550_poll(void);
    46 extern void ns16550_grab(void);
    47 extern void ns16550_release(void);
    48 extern char ns16550_key_read(chardev_t *);
    49 extern irq_ownership_t ns16550_claim(void *);
    50 extern void ns16550_irq_handler(irq_t *);
    51 
    5241#include <arch/types.h>
    5342#include <arch/drivers/kbd.h>
    54 
    55 /* NS16550 registers */
    56 #define RBR_REG         0       /** Receiver Buffer Register. */
    57 #define IER_REG         1       /** Interrupt Enable Register. */
    58 #define IIR_REG         2       /** Interrupt Ident Register (read). */
    59 #define FCR_REG         2       /** FIFO control register (write). */
    60 #define LCR_REG         3       /** Line Control register. */
    61 #define MCR_REG         4       /** Modem Control Register. */
    62 #define LSR_REG         5       /** Line Status Register. */
    6343
    6444#define IER_ERBFI       0x01    /** Enable Receive Buffer Full Interrupt. */
     
    6848#define MCR_OUT2        0x08    /** OUT2. */
    6949
     50/** NS16550 registers. */
     51struct ns16550 {
     52        ioport8_t rbr;  /**< Receiver Buffer Register. */
     53        ioport8_t ier;  /**< Interrupt Enable Register. */
     54        union {
     55                ioport8_t iir;  /**< Interrupt Ident Register (read). */
     56                ioport8_t fcr;  /**< FIFO control register (write). */
     57        } __attribute__ ((packed));
     58        ioport8_t lcr;  /**< Line Control register. */
     59        ioport8_t mcr;  /**< Modem Control Register. */
     60        ioport8_t lsr;  /**< Line Status Register. */
     61} __attribute__ ((packed));
     62typedef struct ns16550 ns16550_t;
     63
    7064/** Structure representing the ns16550 device. */
    71 typedef struct {
     65typedef struct ns16550_instance {
    7266        devno_t devno;
    73         /** Memory mapped registers of the ns16550. */
    74         volatile ioport_t io_port;
    75 } ns16550_t;
     67        ns16550_t *ns16550;
     68        irq_t *irq;
     69} ns16550_instance_t;
    7670
    77 static inline uint8_t ns16550_rbr_read(ns16550_t *dev)
    78 {
    79         return pio_read_8(dev->io_port + RBR_REG);
    80 }
    81 static inline void ns16550_rbr_write(ns16550_t *dev, uint8_t v)
    82 {
    83         pio_write_8(dev->io_port + RBR_REG, v);
    84 }
    85 
    86 static inline uint8_t ns16550_ier_read(ns16550_t *dev)
    87 {
    88         return pio_read_8(dev->io_port + IER_REG);
    89 }
    90 
    91 static inline void ns16550_ier_write(ns16550_t *dev, uint8_t v)
    92 {
    93         pio_write_8(dev->io_port + IER_REG, v);
    94 }
    95 
    96 static inline uint8_t ns16550_iir_read(ns16550_t *dev)
    97 {
    98         return pio_read_8(dev->io_port + IIR_REG);
    99 }
    100 
    101 static inline void ns16550_fcr_write(ns16550_t *dev, uint8_t v)
    102 {
    103         pio_write_8(dev->io_port + FCR_REG, v);
    104 }
    105 
    106 static inline uint8_t ns16550_lcr_read(ns16550_t *dev)
    107 {
    108         return pio_read_8(dev->io_port + LCR_REG);
    109 }
    110 
    111 static inline void ns16550_lcr_write(ns16550_t *dev, uint8_t v)
    112 {
    113         pio_write_8(dev->io_port + LCR_REG, v);
    114 }
    115 
    116 static inline uint8_t ns16550_lsr_read(ns16550_t *dev)
    117 {
    118         return pio_read_8(dev->io_port + LSR_REG);
    119 }
    120 
    121 static inline uint8_t ns16550_mcr_read(ns16550_t *dev)
    122 {
    123         return pio_read_8(dev->io_port + MCR_REG);
    124 }
    125 
    126 static inline void ns16550_mcr_write(ns16550_t *dev, uint8_t v)
    127 {
    128         pio_write_8(dev->io_port + MCR_REG, v);
    129 }
     71extern bool ns16550_init(ns16550_t *, devno_t, inr_t, cir_t, void *);
     72extern void ns16550_grab(void);
     73extern void ns16550_release(void);
     74extern irq_ownership_t ns16550_claim(void *);
     75extern void ns16550_irq_handler(irq_t *);
    13076
    13177#endif
  • kernel/genarch/src/kbd/i8042.c

    rd1eece6 r013c4d6  
    5353
    5454i8042_instance_t lgcy_i8042_instance = {
    55         .i8042 = (i8042_t *) i8042_BASE,
     55        .i8042 = (i8042_t *) I8042_BASE,
    5656};
    5757
     
    8989        .suspend = i8042_suspend,
    9090        .resume = i8042_resume,
    91         .read = i8042_key_read
    9291};
    9392
     
    229228}
    230229
    231 char i8042_key_read(chardev_t *d)
    232 {
    233         i8042_t *dev = lgcy_i8042_instance.i8042;
    234         char ch;
    235        
    236         while (!(ch = active_read_buff_read())) {
    237                 uint8_t x;
    238                
    239                 while (!(pio_read_8(&dev->status) & i8042_BUFFER_FULL_MASK))
    240                         ;
    241                
    242                 x = pio_read_8(&dev->data);
    243                 if (x & KEY_RELEASE)
    244                         key_released(x ^ KEY_RELEASE);
    245                 else
    246                         active_read_key_pressed(x);
    247         }
    248         return ch;
    249 }
    250 
    251230/** @}
    252231 */
  • 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.