Changeset ee163b3 in mainline for uspace/drv/char/i8042/i8042.c


Ignore:
Timestamp:
2011-12-10T01:32:05Z (12 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5960b48
Parents:
f44ba92
Message:

i8042: Add tons of DDF stuff, matchid.

Still missing:

  • enable interrupts (didn't kernel do this for us?)
  • handle callback connections
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/char/i8042/i8042.c

    rf44ba92 ree163b3  
    4242#include <async.h>
    4343#include <unistd.h>
    44 #include <sysinfo.h>
    4544#include <stdio.h>
    4645#include <errno.h>
     46#include <str_error.h>
    4747#include <inttypes.h>
     48#include <ddf/log.h>
     49#include <ddf/interrupt.h>
     50
    4851#include "i8042.h"
    4952
     
    6770#define i8042_KBD_TRANSLATE     0x40
    6871
    69 
    70 static irq_cmd_t i8042_cmds[] = {
     72static const irq_cmd_t i8042_cmds[] = {
    7173        {
    7274                .cmd = CMD_PIO_READ_8,
     
    9597};
    9698
    97 static irq_code_t i8042_kbd = {
    98         sizeof(i8042_cmds) / sizeof(irq_cmd_t),
    99         i8042_cmds
    100 };
    101 
    102 static i8042_dev_t device;
    103 
    104 static void wait_ready(i8042_dev_t *dev)
     99static i8042_t device;
     100
     101static void wait_ready(i8042_t *dev)
    105102{
    106103        assert(dev);
     
    108105}
    109106
    110 static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call);
     107static void i8042_irq_handler(ddf_dev_t *dev,
     108    ipc_callid_t iid, ipc_call_t *call);
    111109static void i8042_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
    112 static int i8042_init(i8042_dev_t *dev);
    113 static void i8042_port_write(i8042_dev_t *dev, int devid, uint8_t data);
    114 
    115 
    116 int main(int argc, char *argv[])
    117 {
    118         printf(NAME ": i8042 PS/2 port driver\n");
    119 
    120         int rc = loc_server_register(NAME, i8042_connection);
    121         if (rc < 0) {
    122                 printf(NAME ": Unable to register server.\n");
    123                 return rc;
    124         }
    125 
    126         if (i8042_init(&device) != EOK)
     110static void i8042_port_write(i8042_t *dev, int devid, uint8_t data);
     111
     112int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd,
     113    int irq_mouse, ddf_dev_t *ddf_dev)
     114{
     115        assert(ddf_dev);
     116        assert(dev);
     117
     118        if (reg_size < sizeof(i8042_regs_t))
     119                return EINVAL;
     120
     121        if (pio_enable(regs, sizeof(i8042_regs_t), (void**)&dev->regs) != 0)
    127122                return -1;
    128123
    129         for (int i = 0; i < MAX_DEVS; i++) {
    130                 device.port[i].client_sess = NULL;
    131 
    132                 static const char *names[MAX_DEVS] = {
    133                     NAMESPACE "/ps2a", NAMESPACE "/ps2b"};
    134                 rc = loc_service_register(names[i], &device.port[i].service_id);
    135                 if (rc != EOK) {
    136                         printf(NAME ": Unable to register device %s.\n",
    137                             names[i]);
    138                         return rc;
    139                 }
    140                 printf(NAME ": Registered device %s\n", names[i]);
    141         }
    142 
    143         printf(NAME ": Accepting connections\n");
    144         task_retval(0);
    145         async_manager();
    146 
    147         /* Not reached */
    148         return 0;
    149 }
    150 
    151 static int i8042_init(i8042_dev_t *dev)
    152 {
    153         static uintptr_t i8042_physical;
    154         static uintptr_t i8042_kernel;
    155         assert(dev);
    156         if (sysinfo_get_value("i8042.address.physical", &i8042_physical) != EOK)
    157                 return -1;
    158        
    159         if (sysinfo_get_value("i8042.address.kernel", &i8042_kernel) != EOK)
    160                 return -1;
    161        
    162         void *vaddr;
    163         if (pio_enable((void *) i8042_physical, sizeof(i8042_regs_t), &vaddr) != 0)
    164                 return -1;
    165        
    166         dev->regs = vaddr;
    167        
    168         sysarg_t inr_a;
    169         sysarg_t inr_b;
    170        
    171         if (sysinfo_get_value("i8042.inr_a", &inr_a) != EOK)
    172                 return -1;
    173        
    174         if (sysinfo_get_value("i8042.inr_b", &inr_b) != EOK)
    175                 return -1;
    176        
    177         async_set_interrupt_received(i8042_irq_handler);
    178        
     124        dev->kbd_fun = ddf_fun_create(ddf_dev, fun_exposed, "ps2a");
     125        if (!dev->kbd_fun)
     126                return ENOMEM;
     127
     128        dev->mouse_fun = ddf_fun_create(ddf_dev, fun_exposed, "ps2b");
     129        if (!dev->mouse_fun) {
     130                ddf_fun_destroy(dev->kbd_fun);
     131                return ENOMEM;
     132        }
     133
     134#define CHECK_RET_DESTROY(ret, msg...) \
     135if  (ret != EOK) { \
     136        ddf_msg(LVL_ERROR, msg); \
     137        if (dev->kbd_fun) { \
     138                dev->kbd_fun->driver_data = NULL; \
     139                ddf_fun_destroy(dev->kbd_fun); \
     140        } \
     141        if (dev->mouse_fun) { \
     142                dev->mouse_fun->driver_data = NULL; \
     143                ddf_fun_destroy(dev->mouse_fun); \
     144        } \
     145} else (void)0
     146
     147        int ret = ddf_fun_bind(dev->kbd_fun);
     148        CHECK_RET_DESTROY(ret,
     149            "Failed to bind keyboard function: %s.\n", str_error(ret));
     150
     151        ret = ddf_fun_bind(dev->mouse_fun);
     152        CHECK_RET_DESTROY(ret,
     153            "Failed to bind mouse function: %s.\n", str_error(ret));
     154
    179155        /* Disable kbd and aux */
    180156        wait_ready(dev);
     
    187163                (void) pio_read_8(&dev->regs->data);
    188164
    189         i8042_kbd.cmds[0].addr = (void *) &((i8042_regs_t *) i8042_kernel)->status;
    190         i8042_kbd.cmds[3].addr = (void *) &((i8042_regs_t *) i8042_kernel)->data;
    191         register_irq(inr_a, device_assign_devno(), 0, &i8042_kbd);
    192         register_irq(inr_b, device_assign_devno(), 0, &i8042_kbd);
    193         printf("%s: registered for interrupts %" PRIun " and %" PRIun "\n",
    194             NAME, inr_a, inr_b);
     165#define CHECK_RET_UNBIND_DESTROY(ret, msg...) \
     166if  (ret != EOK) { \
     167        ddf_msg(LVL_ERROR, msg); \
     168        if (dev->kbd_fun) { \
     169                ddf_fun_unbind(dev->kbd_fun); \
     170                dev->kbd_fun->driver_data = NULL; \
     171                ddf_fun_destroy(dev->kbd_fun); \
     172        } \
     173        if (dev->mouse_fun) { \
     174                ddf_fun_unbind(dev->mouse_fun); \
     175                dev->mouse_fun->driver_data = NULL; \
     176                ddf_fun_destroy(dev->mouse_fun); \
     177        } \
     178} else (void)0
     179        const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
     180        irq_cmd_t cmds[cmd_count];
     181        memcpy(cmds, i8042_cmds, sizeof(i8042_cmds));
     182        cmds[0].addr = (void *) &dev->regs->status;
     183        cmds[3].addr = (void *) &dev->regs->data;
     184
     185        irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = cmds };
     186        ddf_msg(LVL_DEBUG,
     187            "Registering interrupt handler for device %s on irq %d.\n",
     188            ddf_dev->name, irq_kbd);
     189        ret = register_interrupt_handler(ddf_dev, irq_kbd, i8042_irq_handler,
     190            &irq_code);
     191        CHECK_RET_UNBIND_DESTROY(ret,
     192            "Failed set handler for kbd: %s.\n", str_error(ret));
     193
     194        ddf_msg(LVL_DEBUG,
     195            "Registering interrupt handler for device %s on irq %d.\n",
     196            ddf_dev->name, irq_mouse);
     197        ret = register_interrupt_handler(ddf_dev, irq_mouse, i8042_irq_handler,
     198            &irq_code);
     199        CHECK_RET_UNBIND_DESTROY(ret,
     200            "Failed set handler for mouse: %s.\n", str_error(ret));
     201
     202        ret = ddf_fun_add_to_category(dev->kbd_fun, "keyboard");
     203        if (ret != EOK)
     204                ddf_msg(LVL_WARN, "Failed to register kbd fun to category.\n");
     205        ret = ddf_fun_add_to_category(dev->mouse_fun, "mouse");
     206        if (ret != EOK)
     207                ddf_msg(LVL_WARN, "Failed to register mouse fun to category.\n");
     208
     209        // TODO: Don't rely on kernel enabling interrupts do it yourself.
    195210
    196211        wait_ready(dev);
     
    200215            i8042_AUX_IE);
    201216
    202         return 0;
     217        // TODO: Plug in connection.
     218
     219        return ret;
     220        (void)i8042_connection;
    203221}
    204222
     
    271289}
    272290
    273 void i8042_port_write(i8042_dev_t *dev, int devid, uint8_t data)
    274 {
     291void i8042_port_write(i8042_t *dev, int devid, uint8_t data)
     292{
     293
    275294        assert(dev);
    276295        if (devid == DEVID_AUX) {
     
    282301}
    283302
    284 static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call)
    285 {
    286         int status, data;
    287         int devid;
    288 
    289         status = IPC_GET_ARG1(*call);
    290         data = IPC_GET_ARG2(*call);
    291 
    292         if ((status & i8042_AUX_DATA)) {
    293                 devid = DEVID_AUX;
    294         } else {
    295                 devid = DEVID_PRI;
    296         }
     303void i8042_irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
     304{
     305        ddf_msg(LVL_FATAL, "IRQ!!!.\n");
     306        if (!dev || !dev->driver_data)
     307                return;
     308
     309        const int status = IPC_GET_ARG1(*call);
     310        const int data = IPC_GET_ARG2(*call);
     311        const int devid = (status & i8042_AUX_DATA) ? DEVID_AUX : DEVID_PRI;
    297312
    298313        if (device.port[devid].client_sess != NULL) {
    299314                async_exch_t *exch =
    300315                    async_exchange_begin(device.port[devid].client_sess);
    301                 async_msg_1(exch, IPC_FIRST_USER_METHOD, data);
    302                 async_exchange_end(exch);
     316                if (exch) {
     317                        async_msg_1(exch, IPC_FIRST_USER_METHOD, data);
     318                        async_exchange_end(exch);
     319                }
     320        } else {
     321                ddf_msg(LVL_WARN, "No client session.\n");
    303322        }
    304323}
Note: See TracChangeset for help on using the changeset viewer.