Changeset cecb0789 in mainline


Ignore:
Timestamp:
2009-02-21T17:27:59Z (15 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9688513
Parents:
0cb9fa0
Message:

This is the evil commit. In particular, it does:

  • introduces more powerful pseudo code for userspace IRQ top-half handlers
  • changes the internals of IRQ dispatching
  • simplifies the kernel's i8042 driver
  • adapts the uspace i8042 driver to make use of the new pseudocode
  • breaks all other architectures except ia32
  • breaks almost all existing drivers
  • breaks switching between uspace and kernel drivers
Files:
7 edited

Legend:

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

    r0cb9fa0 rcecb0789  
    167167#endif
    168168       
    169         i8042_grab();
    170169}
    171170
     
    175174void arch_release_console(void)
    176175{
    177         i8042_release();
    178176}
    179177
  • kernel/genarch/src/kbd/i8042.c

    r0cb9fa0 rcecb0789  
    9595static irq_t i8042_mouse_irq;
    9696
    97 void i8042_grab(void)
    98 {
    99         ipl_t ipl = interrupts_disable();
    100        
    101         spinlock_lock(&i8042_kbd_irq.lock);
    102         i8042_kbd_irq.notif_cfg.notify = false;
    103         spinlock_unlock(&i8042_kbd_irq.lock);
    104        
    105         spinlock_lock(&i8042_mouse_irq.lock);
    106         i8042_mouse_irq.notif_cfg.notify = false;
    107         spinlock_unlock(&i8042_mouse_irq.lock);
    108        
    109         interrupts_restore(ipl);
    110 }
    111 
    112 void i8042_release(void)
    113 {
    114         ipl_t ipl = interrupts_disable();
    115        
    116         spinlock_lock(&i8042_kbd_irq.lock);
    117         if (i8042_kbd_irq.notif_cfg.answerbox)
    118                 i8042_kbd_irq.notif_cfg.notify = true;
    119         spinlock_unlock(&i8042_kbd_irq.lock);
    120        
    121         spinlock_lock(&i8042_mouse_irq.lock);
    122         if (i8042_mouse_irq.notif_cfg.answerbox)
    123                 i8042_mouse_irq.notif_cfg.notify = true;
    124         spinlock_unlock(&i8042_mouse_irq.lock);
    125        
    126         interrupts_restore(ipl);
    127 }
    128 
    12997static irq_ownership_t i8042_claim(irq_t *irq)
    13098{
     
    139107static void i8042_irq_handler(irq_t *irq)
    140108{
    141         if (irq->notif_cfg.notify && irq->notif_cfg.answerbox) {
    142                 /*
    143                  * This will hopefully go to the IRQ dispatcher code soon.
    144                  */
    145                 ipc_irq_send_notif(irq);
    146                 return;
    147         }
    148 
    149109        i8042_instance_t *instance = irq->instance;
    150110        i8042_t *dev = instance->i8042;
     
    214174        sysinfo_set_item_val("mouse.devno", NULL, mouse_devno);
    215175        sysinfo_set_item_val("mouse.inr", NULL, mouse_inr);
    216        
    217         i8042_grab();
    218176}
    219177
  • kernel/generic/include/ddi/irq.h

    r0cb9fa0 rcecb0789  
    3737
    3838typedef enum {
    39         CMD_MEM_READ_1 = 0,
    40         CMD_MEM_READ_2,
    41         CMD_MEM_READ_4,
    42         CMD_MEM_READ_8,
    43         CMD_MEM_WRITE_1,
    44         CMD_MEM_WRITE_2,
    45         CMD_MEM_WRITE_4,
    46         CMD_MEM_WRITE_8,
    47         CMD_PORT_READ_1,
    48         CMD_PORT_WRITE_1,
     39        CMD_PIO_READ_8 = 1,
     40        CMD_PIO_READ_16,
     41        CMD_PIO_READ_32,
     42        CMD_PIO_WRITE_8,
     43        CMD_PIO_WRITE_16,
     44        CMD_PIO_WRITE_32,
     45        CMD_BTEST,
     46        CMD_PREDICATE,
     47        CMD_ACCEPT,
     48        CMD_DECLINE,
    4949        CMD_LAST
    5050} irq_cmd_type;
     
    5353        irq_cmd_type cmd;
    5454        void *addr;
    55         unsigned long long value;
    56         int dstarg;
     55        unsigned long long value;
     56        unsigned int srcarg;
     57        unsigned int dstarg;
    5758} irq_cmd_t;
    5859
     
    6667#include <arch/types.h>
    6768#include <adt/list.h>
     69#include <adt/hash_table.h>
    6870#include <synch/spinlock.h>
    6971#include <proc/task.h>
     72#include <ipc/ipc.h>
    7073
    7174typedef enum {
     
    97100        /** Method to be used for the notification. */
    98101        unative_t method;
     102        /** Arguments that will be sent if the IRQ is claimed. */
     103        unative_t scratch[IPC_CALL_LEN];
    99104        /** Top-half pseudocode. */
    100105        irq_code_t *code;
     
    155160} irq_t;
    156161
     162SPINLOCK_EXTERN(irq_uspace_hash_table_lock);
     163extern hash_table_t irq_uspace_hash_table;
     164
    157165extern void irq_init(count_t, count_t);
    158166extern void irq_initialize(irq_t *);
    159167extern void irq_register(irq_t *);
    160168extern irq_t *irq_dispatch_and_lock(inr_t);
    161 extern irq_t *irq_find_and_lock(inr_t, devno_t);
    162169
    163170#endif
  • kernel/generic/include/ipc/irq.h

    r0cb9fa0 rcecb0789  
    3737
    3838/** Maximum length of IPC IRQ program */
    39 #define IRQ_MAX_PROG_SIZE       10
     39#define IRQ_MAX_PROG_SIZE       20
    4040
    4141#include <ipc/ipc.h>
     
    4444#include <adt/list.h>
    4545
    46 extern int ipc_irq_register(answerbox_t *box, inr_t inr, devno_t devno,
    47     unative_t method, irq_code_t *ucode);
    48 extern void ipc_irq_send_notif(irq_t *irq);
    49 extern void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno);
    50 extern void ipc_irq_cleanup(answerbox_t *box);
     46extern int ipc_irq_register(answerbox_t *, inr_t, devno_t, unative_t,
     47    irq_code_t *);
     48
     49extern irq_ownership_t ipc_irq_top_half_claim(irq_t *);
     50extern void ipc_irq_top_half_handler(irq_t *);
     51
     52extern int ipc_irq_unregister(answerbox_t *, inr_t, devno_t);
     53extern void ipc_irq_cleanup(answerbox_t *);
    5154
    5255/*
     
    6770    ipc_irq_send_msg((irq), (a1), (a2), (a3), (a4), (a5))
    6871
    69 extern void ipc_irq_send_msg(irq_t *irq, unative_t a1, unative_t a2,
    70     unative_t a3, unative_t a4, unative_t a5);
     72extern void ipc_irq_send_msg(irq_t *, unative_t, unative_t, unative_t, unative_t,
     73    unative_t);
    7174
    7275#endif
  • kernel/generic/src/ddi/irq.c

    r0cb9fa0 rcecb0789  
    7070#include <ddi/irq.h>
    7171#include <adt/hash_table.h>
     72#include <mm/slab.h>
    7273#include <arch/types.h>
    7374#include <synch/spinlock.h>
     75#include <memstr.h>
    7476#include <arch.h>
    7577
     
    7880
    7981/**
    80  * Spinlock protecting the hash table.
     82 * Spinlock protecting the kernel IRQ hash table.
    8183 * This lock must be taken only when interrupts are disabled.
    8284 */
    83 SPINLOCK_INITIALIZE(irq_hash_table_lock);
    84 static hash_table_t irq_hash_table;
     85static SPINLOCK_INITIALIZE(irq_kernel_hash_table_lock);
     86/** The kernel IRQ hash table. */
     87static hash_table_t irq_kernel_hash_table;
     88
     89/**
     90 * Spinlock protecting the uspace IRQ hash table.
     91 * This lock must be taken only when interrupts are disabled.
     92 */
     93SPINLOCK_INITIALIZE(irq_uspace_hash_table_lock);
     94/** The uspace IRQ hash table. */
     95hash_table_t irq_uspace_hash_table;
    8596
    8697/**
     
    112123};
    113124
     125/** Number of buckets in either of the hash tables. */
     126static count_t buckets;
     127
    114128/** Initialize IRQ subsystem.
    115129 *
     
    119133void irq_init(count_t inrs, count_t chains)
    120134{
     135        buckets = chains;
    121136        /*
    122137         * Be smart about the choice of the hash table operations.
     
    125140         * different keys), we can use optimized set of operations.
    126141         */
    127         if (inrs == chains)
    128                 hash_table_create(&irq_hash_table, chains, 2, &irq_lin_ops);
    129         else
    130                 hash_table_create(&irq_hash_table, chains, 2, &irq_ht_ops);
     142        if (inrs == chains) {
     143                hash_table_create(&irq_uspace_hash_table, chains, 2,
     144                    &irq_lin_ops);
     145                hash_table_create(&irq_kernel_hash_table, chains, 2,
     146                    &irq_lin_ops);
     147        } else {
     148                hash_table_create(&irq_uspace_hash_table, chains, 2,
     149                    &irq_ht_ops);
     150                hash_table_create(&irq_kernel_hash_table, chains, 2,
     151                    &irq_ht_ops);
     152        }
    131153}
    132154
     
    138160void irq_initialize(irq_t *irq)
    139161{
     162        memsetb(irq, 0, sizeof(irq_t));
    140163        link_initialize(&irq->link);
    141164        spinlock_initialize(&irq->lock, "irq.lock");
    142         irq->preack = false;
     165        link_initialize(&irq->notif_cfg.link);
    143166        irq->inr = -1;
    144167        irq->devno = -1;
    145         irq->trigger = (irq_trigger_t) 0;
    146         irq->claim = NULL;
    147         irq->handler = NULL;
    148         irq->instance = NULL;
    149         irq->cir = NULL;
    150         irq->cir_arg = NULL;
    151         irq->notif_cfg.notify = false;
    152         irq->notif_cfg.answerbox = NULL;
    153         irq->notif_cfg.code = NULL;
    154         irq->notif_cfg.method = 0;
    155         irq->notif_cfg.counter = 0;
    156         link_initialize(&irq->notif_cfg.link);
    157168}
    158169
     
    161172 * The irq structure must be filled with information
    162173 * about the interrupt source and with the claim()
    163  * function pointer and irq_handler() function pointer.
    164  *
    165  * @param irq IRQ structure belonging to a device.
     174 * function pointer and handler() function pointer.
     175 *
     176 * @param irq           IRQ structure belonging to a device.
     177 * @return              True on success, false on failure.
    166178 */
    167179void irq_register(irq_t *irq)
    168180{
     181        spinlock_t *lock = &irq_kernel_hash_table_lock;
     182        hash_table_t *table = &irq_kernel_hash_table;
    169183        ipl_t ipl;
    170184        unative_t key[] = {
     
    174188       
    175189        ipl = interrupts_disable();
    176         spinlock_lock(&irq_hash_table_lock);
    177         hash_table_insert(&irq_hash_table, key, &irq->link);
    178         spinlock_unlock(&irq_hash_table_lock);
     190        spinlock_lock(lock);
     191        spinlock_lock(&irq->lock);
     192        hash_table_insert(table, key, &irq->link);
     193        spinlock_unlock(&irq->lock);   
     194        spinlock_unlock(lock);
    179195        interrupts_restore(ipl);
    180196}
     
    202218        };
    203219       
    204         spinlock_lock(&irq_hash_table_lock);
    205 
    206         lnk = hash_table_find(&irq_hash_table, key);
     220        /*
     221         * Try uspace handlers first.
     222         */
     223        spinlock_lock(&irq_uspace_hash_table_lock);
     224        lnk = hash_table_find(&irq_uspace_hash_table, key);
    207225        if (lnk) {
    208226                irq_t *irq;
    209227               
    210228                irq = hash_table_get_instance(lnk, irq_t, link);
    211 
    212                 spinlock_unlock(&irq_hash_table_lock);
     229                spinlock_unlock(&irq_uspace_hash_table_lock);
    213230                return irq;
    214231        }
    215        
    216         spinlock_unlock(&irq_hash_table_lock);
    217 
    218         return NULL;   
    219 }
    220 
    221 /** Find the IRQ structure corresponding to inr and devno.
    222  *
    223  * This functions attempts to lookup the IRQ structure
    224  * corresponding to its arguments. On success, this
    225  * function returns with interrups disabled, holding
    226  * the lock of the respective IRQ structure.
    227  *
    228  * This function assumes interrupts are already disabled.
    229  *
    230  * @param inr INR being looked up.
    231  * @param devno Devno being looked up.
    232  *
    233  * @return Locked IRQ structure on success or NULL on failure.
    234  */
    235 irq_t *irq_find_and_lock(inr_t inr, devno_t devno)
    236 {
    237         link_t *lnk;
    238         unative_t keys[] = {
    239                 (unative_t) inr,
    240                 (unative_t) devno
    241         };
    242        
    243         spinlock_lock(&irq_hash_table_lock);
    244 
    245         lnk = hash_table_find(&irq_hash_table, keys);
     232        spinlock_unlock(&irq_uspace_hash_table_lock);
     233
     234        /*
     235         * Fallback to kernel handlers.
     236         */
     237        spinlock_lock(&irq_kernel_hash_table_lock);
     238        lnk = hash_table_find(&irq_kernel_hash_table, key);
    246239        if (lnk) {
    247240                irq_t *irq;
    248241               
    249242                irq = hash_table_get_instance(lnk, irq_t, link);
    250 
    251                 spinlock_unlock(&irq_hash_table_lock);
     243                spinlock_unlock(&irq_kernel_hash_table_lock);
    252244                return irq;
    253245        }
    254        
    255         spinlock_unlock(&irq_hash_table_lock);
     246        spinlock_unlock(&irq_kernel_hash_table_lock);
    256247
    257248        return NULL;   
     
    274265{
    275266        inr_t inr = (inr_t) key[KEY_INR];
    276         return inr % irq_hash_table.entries;
     267        return inr % buckets;
    277268}
    278269
     
    309300                /* Invoked by irq_dispatch_and_lock(). */
    310301                rv = ((irq->inr == inr) &&
    311                     (irq->claim(irq->instance) == IRQ_ACCEPT));
     302                    (irq->claim(irq) == IRQ_ACCEPT));
    312303        } else {
    313304                /* Invoked by irq_find_and_lock(). */
     
    368359        if (devno == -1) {
    369360                /* Invoked by irq_dispatch_and_lock() */
    370                 rv = (irq->claim(irq->instance) == IRQ_ACCEPT);
     361                rv = (irq->claim(irq) == IRQ_ACCEPT);
    371362        } else {
    372363                /* Invoked by irq_find_and_lock() */
  • kernel/generic/src/ipc/irq.c

    r0cb9fa0 rcecb0789  
    4545 * - ARG2: payload modified by a 'top-half' handler
    4646 * - ARG3: payload modified by a 'top-half' handler
     47 * - ARG4: payload modified by a 'top-half' handler
     48 * - ARG5: payload modified by a 'top-half' handler
    4749 * - in_phone_hash: interrupt counter (may be needed to assure correct order
    4850 *         in multithreaded drivers)
     51 *
     52 * Note on synchronization for ipc_irq_register(), ipc_irq_unregister(),
     53 * ipc_irq_cleanup() and IRQ handlers:
     54 *
     55 *   By always taking all of the uspace IRQ hash table lock, IRQ structure lock
     56 *   and answerbox lock, we can rule out race conditions between the
     57 *   registration functions and also the cleanup function. Thus the observer can
     58 *   either see the IRQ structure present in both the hash table and the
     59 *   answerbox list or absent in both. Views in which the IRQ structure would be
     60 *   linked in the hash table but not in the answerbox list, or vice versa, are
     61 *   not possible.
     62 *
     63 *   By always taking the hash table lock and the IRQ structure lock, we can
     64 *   rule out a scenario in which we would free up an IRQ structure, which is
     65 *   still referenced by, for example, an IRQ handler. The locking scheme forces
     66 *   us to lock the IRQ structure only after any progressing IRQs on that
     67 *   structure are finished. Because we hold the hash table lock, we prevent new
     68 *   IRQs from taking new references to the IRQ structure.
    4969 */
    5070
     
    5979#include <print.h>
    6080
    61 /** Execute code associated with IRQ notification.
    62  *
    63  * @param call          Notification call.
    64  * @param code          Top-half pseudocode.
    65  */
    66 static void code_execute(call_t *call, irq_code_t *code)
    67 {
    68         unsigned int i;
    69         unative_t dstval = 0;
    70        
    71         if (!code)
    72                 return;
    73        
    74         for (i = 0; i < code->cmdcount; i++) {
    75                 switch (code->cmds[i].cmd) {
    76                 case CMD_MEM_READ_1:
    77                         dstval = *((uint8_t *) code->cmds[i].addr);
    78                         break;
    79                 case CMD_MEM_READ_2:
    80                         dstval = *((uint16_t *) code->cmds[i].addr);
    81                         break;
    82                 case CMD_MEM_READ_4:
    83                         dstval = *((uint32_t *) code->cmds[i].addr);
    84                         break;
    85                 case CMD_MEM_READ_8:
    86                         dstval = *((uint64_t *) code->cmds[i].addr);
    87                         break;
    88                 case CMD_MEM_WRITE_1:
    89                         *((uint8_t *) code->cmds[i].addr) = code->cmds[i].value;
    90                         break;
    91                 case CMD_MEM_WRITE_2:
    92                         *((uint16_t *) code->cmds[i].addr) =
    93                             code->cmds[i].value;
    94                         break;
    95                 case CMD_MEM_WRITE_4:
    96                         *((uint32_t *) code->cmds[i].addr) =
    97                             code->cmds[i].value;
    98                         break;
    99                 case CMD_MEM_WRITE_8:
    100                         *((uint64_t *) code->cmds[i].addr) =
    101                             code->cmds[i].value;
    102                         break;
    103                 case CMD_PORT_READ_1:
    104                         dstval = pio_read_8((ioport8_t *) code->cmds[i].addr);
    105                         break;
    106                 case CMD_PORT_WRITE_1:
    107                         pio_write_8((ioport8_t *) code->cmds[i].addr, code->cmds[i].value);
    108                         break;
    109                 default:
    110                         break;
    111                 }
    112                 if (code->cmds[i].dstarg && code->cmds[i].dstarg <
    113                     IPC_CALL_LEN) {
    114                         call->data.args[code->cmds[i].dstarg] = dstval;
    115                 }
    116         }
    117 }
    118 
    119 /** Free top-half pseudocode.
     81/** Free the top-half pseudocode.
    12082 *
    12183 * @param code          Pointer to the top-half pseudocode.
     
    12991}
    13092
    131 /** Copy top-half pseudocode from userspace into the kernel.
     93/** Copy the top-half pseudocode from userspace into the kernel.
    13294 *
    13395 * @param ucode         Userspace address of the top-half pseudocode.
     
    165127}
    166128
    167 /** Unregister task from IRQ notification.
    168  *
    169  * @param box           Answerbox associated with the notification.
    170  * @param inr           IRQ number.
    171  * @param devno         Device number.
    172  */
    173 void ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
    174 {
    175         ipl_t ipl;
    176         irq_t *irq;
    177 
    178         ipl = interrupts_disable();
    179         irq = irq_find_and_lock(inr, devno);
    180         if (irq) {
    181                 if (irq->notif_cfg.answerbox == box) {
    182                         code_free(irq->notif_cfg.code);
    183                         irq->notif_cfg.notify = false;
    184                         irq->notif_cfg.answerbox = NULL;
    185                         irq->notif_cfg.code = NULL;
    186                         irq->notif_cfg.method = 0;
    187                         irq->notif_cfg.counter = 0;
    188 
    189                         spinlock_lock(&box->irq_lock);
    190                         list_remove(&irq->notif_cfg.link);
    191                         spinlock_unlock(&box->irq_lock);
    192                        
    193                         spinlock_unlock(&irq->lock);
    194                 }
    195         }
    196         interrupts_restore(ipl);
    197 }
    198 
    199129/** Register an answerbox as a receiving end for IRQ notifications.
    200130 *
     
    213143        irq_code_t *code;
    214144        irq_t *irq;
     145        unative_t key[] = {
     146                (unative_t) inr,
     147                (unative_t) devno
     148        };
    215149
    216150        if (ucode) {
     
    222156        }
    223157
    224         ipl = interrupts_disable();
    225         irq = irq_find_and_lock(inr, devno);
    226         if (!irq) {
    227                 interrupts_restore(ipl);
    228                 code_free(code);
    229                 return ENOENT;
    230         }
    231        
    232         if (irq->notif_cfg.answerbox) {
    233                 spinlock_unlock(&irq->lock);
    234                 interrupts_restore(ipl);
    235                 code_free(code);
    236                 return EEXISTS;
    237         }
    238        
     158        /*
     159         * Allocate and populate the IRQ structure.
     160         */
     161        irq = malloc(sizeof(irq_t), 0);
     162        irq_initialize(irq);
     163        irq->devno = devno;
     164        irq->inr = inr;
     165        irq->claim = ipc_irq_top_half_claim;
     166        irq->handler = ipc_irq_top_half_handler;       
    239167        irq->notif_cfg.notify = true;
    240168        irq->notif_cfg.answerbox = box;
     
    243171        irq->notif_cfg.counter = 0;
    244172
     173        /*
     174         * Enlist the IRQ structure in the uspace IRQ hash table and the
     175         * answerbox's list.
     176         */
     177        ipl = interrupts_disable();
     178        spinlock_lock(&irq_uspace_hash_table_lock);
     179        spinlock_lock(&irq->lock);
    245180        spinlock_lock(&box->irq_lock);
     181        if (hash_table_find(&irq_uspace_hash_table, key)) {
     182                code_free(code);
     183                spinlock_unlock(&box->irq_lock);
     184                spinlock_unlock(&irq->lock);
     185                spinlock_unlock(&irq_uspace_hash_table_lock);
     186                free(irq);
     187                interrupts_restore(ipl);
     188                return EEXISTS;
     189        }
     190        hash_table_insert(&irq_uspace_hash_table, key, &irq->link);
    246191        list_append(&irq->notif_cfg.link, &box->irq_head);
    247192        spinlock_unlock(&box->irq_lock);
    248 
    249193        spinlock_unlock(&irq->lock);
     194        spinlock_unlock(&irq_uspace_hash_table_lock);
     195
    250196        interrupts_restore(ipl);
    251 
    252         return 0;
     197        return EOK;
     198}
     199
     200/** Unregister task from IRQ notification.
     201 *
     202 * @param box           Answerbox associated with the notification.
     203 * @param inr           IRQ number.
     204 * @param devno         Device number.
     205 */
     206int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
     207{
     208        ipl_t ipl;
     209        unative_t key[] = {
     210                (unative_t) inr,
     211                (unative_t) devno
     212        };
     213        link_t *lnk;
     214        irq_t *irq;
     215
     216        ipl = interrupts_disable();
     217        spinlock_lock(&irq_uspace_hash_table_lock);
     218        lnk = hash_table_find(&irq_uspace_hash_table, key);
     219        if (!lnk) {
     220                spinlock_unlock(&irq_uspace_hash_table_lock);
     221                interrupts_restore(ipl);
     222                return ENOENT;
     223        }
     224        irq = hash_table_get_instance(lnk, irq_t, link);
     225        spinlock_lock(&irq->lock);
     226        spinlock_lock(&box->irq_lock);
     227       
     228        ASSERT(irq->notif_cfg.answerbox == box);
     229       
     230        /* Free up the pseudo code and associated structures. */
     231        code_free(irq->notif_cfg.code);
     232
     233        /* Remove the IRQ from the answerbox's list. */
     234        list_remove(&irq->notif_cfg.link);
     235
     236        /* Remove the IRQ from the uspace IRQ hash table. */
     237        hash_table_remove(&irq_uspace_hash_table, key, 2);
     238       
     239        spinlock_unlock(&irq_uspace_hash_table_lock);
     240        spinlock_unlock(&irq->lock);
     241        spinlock_unlock(&box->irq_lock);
     242       
     243        /* Free up the IRQ structure. */
     244        free(irq);
     245       
     246        interrupts_restore(ipl);
     247        return EOK;
     248}
     249
     250
     251/** Disconnect all IRQ notifications from an answerbox.
     252 *
     253 * This function is effective because the answerbox contains
     254 * list of all irq_t structures that are registered to
     255 * send notifications to it.
     256 *
     257 * @param box           Answerbox for which we want to carry out the cleanup.
     258 */
     259void ipc_irq_cleanup(answerbox_t *box)
     260{
     261        ipl_t ipl;
     262       
     263loop:
     264        ipl = interrupts_disable();
     265        spinlock_lock(&irq_uspace_hash_table_lock);
     266        spinlock_lock(&box->irq_lock);
     267       
     268        while (box->irq_head.next != &box->irq_head) {
     269                link_t *cur = box->irq_head.next;
     270                irq_t *irq;
     271                DEADLOCK_PROBE_INIT(p_irqlock);
     272                unative_t key[2];
     273               
     274                irq = list_get_instance(cur, irq_t, notif_cfg.link);
     275                if (!spinlock_trylock(&irq->lock)) {
     276                        /*
     277                         * Avoid deadlock by trying again.
     278                         */
     279                        spinlock_unlock(&box->irq_lock);
     280                        spinlock_unlock(&irq_uspace_hash_table_lock);
     281                        interrupts_restore(ipl);
     282                        DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD);
     283                        goto loop;
     284                }
     285                key[0] = irq->inr;
     286                key[1] = irq->devno;
     287               
     288               
     289                ASSERT(irq->notif_cfg.answerbox == box);
     290               
     291                /* Unlist from the answerbox. */
     292                list_remove(&irq->notif_cfg.link);
     293               
     294                /* Remove from the hash table. */
     295                hash_table_remove(&irq_uspace_hash_table, key, 2);
     296               
     297                /* Free up the pseudo code and associated structures. */
     298                code_free(irq->notif_cfg.code);
     299               
     300                spinlock_unlock(&irq->lock);
     301                free(irq);
     302        }
     303       
     304        spinlock_unlock(&box->irq_lock);
     305        spinlock_unlock(&irq_uspace_hash_table_lock);
     306        interrupts_restore(ipl);
    253307}
    254308
     
    267321               
    268322        waitq_wakeup(&irq->notif_cfg.answerbox->wq, WAKEUP_FIRST);
     323}
     324
     325/** Apply the top-half pseudo code to find out whether to accept the IRQ or not.
     326 *
     327 * @param irq           IRQ structure.
     328 *
     329 * @return              IRQ_ACCEPT if the interrupt is accepted by the
     330 *                      pseudocode. IRQ_DECLINE otherwise.
     331 */
     332irq_ownership_t ipc_irq_top_half_claim(irq_t *irq)
     333{
     334        unsigned int i;
     335        unative_t dstval;
     336        irq_code_t *code = irq->notif_cfg.code;
     337        unative_t *scratch = irq->notif_cfg.scratch;
     338
     339       
     340        if (!irq->notif_cfg.notify)
     341                return IRQ_DECLINE;
     342       
     343        if (!code)
     344                return IRQ_DECLINE;
     345       
     346        for (i = 0; i < code->cmdcount; i++) {
     347                unsigned int srcarg = code->cmds[i].srcarg;
     348                unsigned int dstarg = code->cmds[i].dstarg;
     349               
     350                if (srcarg >= IPC_CALL_LEN)
     351                        break;
     352                if (dstarg >= IPC_CALL_LEN)
     353                        break;
     354       
     355                switch (code->cmds[i].cmd) {
     356                case CMD_PIO_READ_8:
     357                        dstval = pio_read_8((ioport8_t *) code->cmds[i].addr);
     358                        if (dstarg)
     359                                scratch[dstarg] = dstval;
     360                        break;
     361                case CMD_PIO_READ_16:
     362                        dstval = pio_read_16((ioport16_t *) code->cmds[i].addr);
     363                        if (dstarg)
     364                                scratch[dstarg] = dstval;
     365                        break;
     366                case CMD_PIO_READ_32:
     367                        dstval = pio_read_32((ioport32_t *) code->cmds[i].addr);
     368                        if (dstarg)
     369                                scratch[dstarg] = dstval;
     370                        break;
     371                case CMD_PIO_WRITE_8:
     372                        pio_write_8((ioport8_t *) code->cmds[i].addr,
     373                            (uint8_t) code->cmds[i].value);
     374                        break;
     375                case CMD_PIO_WRITE_16:
     376                        pio_write_16((ioport16_t *) code->cmds[i].addr,
     377                            (uint16_t) code->cmds[i].value);
     378                        break;
     379                case CMD_PIO_WRITE_32:
     380                        pio_write_32((ioport32_t *) code->cmds[i].addr,
     381                            (uint32_t) code->cmds[i].value);
     382                        break;
     383                case CMD_BTEST:
     384                        if (srcarg && dstarg) {
     385                                dstval = scratch[srcarg] & code->cmds[i].value;
     386                                scratch[dstarg] = dstval;
     387                        }
     388                        break;
     389                case CMD_PREDICATE:
     390                        if (srcarg && !scratch[srcarg]) {
     391                                i += code->cmds[i].value;
     392                                continue;
     393                        }
     394                        break;
     395                case CMD_ACCEPT:
     396                        return IRQ_ACCEPT;
     397                        break;
     398                case CMD_DECLINE:
     399                default:
     400                        return IRQ_DECLINE;
     401                }
     402        }
     403       
     404        return IRQ_DECLINE;
     405}
     406
     407
     408/* IRQ top-half handler.
     409 *
     410 * We expect interrupts to be disabled and the irq->lock already held.
     411 *
     412 * @param irq           IRQ structure.
     413 */
     414void ipc_irq_top_half_handler(irq_t *irq)
     415{
     416        ASSERT(irq);
     417
     418        if (irq->notif_cfg.answerbox) {
     419                call_t *call;
     420
     421                call = ipc_call_alloc(FRAME_ATOMIC);
     422                if (!call)
     423                        return;
     424               
     425                call->flags |= IPC_CALL_NOTIF;
     426                /* Put a counter to the message */
     427                call->priv = ++irq->notif_cfg.counter;
     428
     429                /* Set up args */
     430                IPC_SET_METHOD(call->data, irq->notif_cfg.method);
     431                IPC_SET_ARG1(call->data, irq->notif_cfg.scratch[1]);
     432                IPC_SET_ARG2(call->data, irq->notif_cfg.scratch[2]);
     433                IPC_SET_ARG3(call->data, irq->notif_cfg.scratch[3]);
     434                IPC_SET_ARG4(call->data, irq->notif_cfg.scratch[4]);
     435                IPC_SET_ARG5(call->data, irq->notif_cfg.scratch[5]);
     436
     437                send_call(irq, call);
     438        }
    269439}
    270440
     
    292462                }
    293463                call->flags |= IPC_CALL_NOTIF;
     464                /* Put a counter to the message */
     465                call->priv = ++irq->notif_cfg.counter;
     466
    294467                IPC_SET_METHOD(call->data, irq->notif_cfg.method);
    295468                IPC_SET_ARG1(call->data, a1);
     
    298471                IPC_SET_ARG4(call->data, a4);
    299472                IPC_SET_ARG5(call->data, a5);
    300                 /* Put a counter to the message */
    301                 call->priv = ++irq->notif_cfg.counter;
    302473               
    303474                send_call(irq, call);
     
    306477}
    307478
    308 /** Notify a task that an IRQ had occurred.
    309  *
    310  * We expect interrupts to be disabled and the irq->lock already held.
    311  *
    312  * @param irq           IRQ structure.
    313  */
    314 void ipc_irq_send_notif(irq_t *irq)
    315 {
    316         call_t *call;
    317 
    318         ASSERT(irq);
    319 
    320         if (irq->notif_cfg.answerbox) {
    321                 call = ipc_call_alloc(FRAME_ATOMIC);
    322                 if (!call) {
    323                         return;
    324                 }
    325                 call->flags |= IPC_CALL_NOTIF;
    326                 /* Put a counter to the message */
    327                 call->priv = ++irq->notif_cfg.counter;
    328                 /* Set up args */
    329                 IPC_SET_METHOD(call->data, irq->notif_cfg.method);
    330 
    331                 /* Execute code to handle irq */
    332                 code_execute(call, irq->notif_cfg.code);
    333                
    334                 send_call(irq, call);
    335         }
    336 }
    337 
    338 /** Disconnect all IRQ notifications from an answerbox.
    339  *
    340  * This function is effective because the answerbox contains
    341  * list of all irq_t structures that are registered to
    342  * send notifications to it.
    343  *
    344  * @param box           Answerbox for which we want to carry out the cleanup.
    345  */
    346 void ipc_irq_cleanup(answerbox_t *box)
    347 {
    348         ipl_t ipl;
    349        
    350 loop:
    351         ipl = interrupts_disable();
    352         spinlock_lock(&box->irq_lock);
    353        
    354         while (box->irq_head.next != &box->irq_head) {
    355                 link_t *cur = box->irq_head.next;
    356                 irq_t *irq;
    357                 DEADLOCK_PROBE_INIT(p_irqlock);
    358                
    359                 irq = list_get_instance(cur, irq_t, notif_cfg.link);
    360                 if (!spinlock_trylock(&irq->lock)) {
    361                         /*
    362                          * Avoid deadlock by trying again.
    363                          */
    364                         spinlock_unlock(&box->irq_lock);
    365                         interrupts_restore(ipl);
    366                         DEADLOCK_PROBE(p_irqlock, DEADLOCK_THRESHOLD);
    367                         goto loop;
    368                 }
    369                
    370                 ASSERT(irq->notif_cfg.answerbox == box);
    371                
    372                 list_remove(&irq->notif_cfg.link);
    373                
    374                 /*
    375                  * Don't forget to free any top-half pseudocode.
    376                  */
    377                 code_free(irq->notif_cfg.code);
    378                
    379                 irq->notif_cfg.notify = false;
    380                 irq->notif_cfg.answerbox = NULL;
    381                 irq->notif_cfg.code = NULL;
    382                 irq->notif_cfg.method = 0;
    383                 irq->notif_cfg.counter = 0;
    384 
    385                 spinlock_unlock(&irq->lock);
    386         }
    387        
    388         spinlock_unlock(&box->irq_lock);
    389         interrupts_restore(ipl);
    390 }
    391 
    392479/** @}
    393480 */
  • uspace/srv/kbd/port/i8042.c

    r0cb9fa0 rcecb0789  
    6464#define MOUSE_ACK       0xfa
    6565
    66 static irq_cmd_t i8042_cmds[2] = {
    67         { CMD_PORT_READ_1, (void *) 0x64, 0, 1 },
    68         { CMD_PORT_READ_1, (void *) 0x60, 0, 2 }
     66static irq_cmd_t i8042_cmds[] = {
     67        {
     68                .cmd = CMD_PIO_READ_8,
     69                .addr = (void *) 0x64,
     70                .dstarg = 1
     71        },
     72        {
     73                .cmd = CMD_BTEST,
     74                .value = i8042_OUTPUT_FULL,
     75                .srcarg = 1,
     76                .dstarg = 3
     77        },
     78        {
     79                .cmd = CMD_PREDICATE,
     80                .value = 2,
     81                .srcarg = 3
     82        },
     83        {
     84                .cmd = CMD_PIO_READ_8,
     85                .addr = (void *) 0x60,
     86                .dstarg = 2
     87        },
     88        {
     89                .cmd = CMD_ACCEPT
     90        }
    6991};
    7092
    7193static irq_code_t i8042_kbd = {
    72         2,
     94        sizeof(i8042_cmds) / sizeof(irq_cmd_t),
    7395        i8042_cmds
    7496};
Note: See TracChangeset for help on using the changeset viewer.