Ignore:
File:
1 edited

Legend:

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

    r75751db6 ra1a101d  
    22 * Copyright (c) 2001-2004 Jakub Jermar
    33 * Copyright (c) 2006 Josef Cejka
    4  * Copyright (c) 2014 Jiri Svoboda
     4 * Copyright (c) 2009 Jiri Svoboda
    55 * Copyright (c) 2011 Jan Vesely
    66 * All rights reserved.
     
    3939 */
    4040
    41 #include <ddf/log.h>
    42 #include <ddf/interrupt.h>
     41#include <device/hw_res.h>
    4342#include <ddi.h>
    44 #include <device/hw_res.h>
     43#include <libarch/ddi.h>
    4544#include <errno.h>
    4645#include <str_error.h>
    4746#include <inttypes.h>
    48 #include <io/chardev_srv.h>
    49 
     47#include <ddf/log.h>
     48#include <ddf/interrupt.h>
    5049#include "i8042.h"
    5150
     
    6665#define i8042_KBD_TRANSLATE  0x40  /* Use this to switch to XT scancodes */
    6766
    68 static void i8042_char_conn(ipc_callid_t, ipc_call_t *, void *);
    69 static int i8042_read(chardev_srv_t *, void *, size_t);
    70 static int i8042_write(chardev_srv_t *, const void *, size_t);
    71 
    72 static chardev_ops_t i8042_chardev_ops = {
    73         .read = i8042_read,
    74         .write = i8042_write
     67#define CHECK_RET_DESTROY(ret, msg...) \
     68        do { \
     69                if (ret != EOK) { \
     70                        ddf_msg(LVL_ERROR, msg); \
     71                        if (dev->kbd_fun) { \
     72                                dev->kbd_fun->driver_data = NULL; \
     73                                ddf_fun_destroy(dev->kbd_fun); \
     74                        } \
     75                        if (dev->aux_fun) { \
     76                                dev->aux_fun->driver_data = NULL; \
     77                                ddf_fun_destroy(dev->aux_fun); \
     78                        } \
     79                } \
     80        } while (0)
     81
     82#define CHECK_RET_UNBIND_DESTROY(ret, msg...) \
     83        do { \
     84                if (ret != EOK) { \
     85                        ddf_msg(LVL_ERROR, msg); \
     86                        if (dev->kbd_fun) { \
     87                                ddf_fun_unbind(dev->kbd_fun); \
     88                                dev->kbd_fun->driver_data = NULL; \
     89                                ddf_fun_destroy(dev->kbd_fun); \
     90                        } \
     91                        if (dev->aux_fun) { \
     92                                ddf_fun_unbind(dev->aux_fun); \
     93                                dev->aux_fun->driver_data = NULL; \
     94                                ddf_fun_destroy(dev->aux_fun); \
     95                        } \
     96                } \
     97        } while (0)
     98
     99void default_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
     100
     101/** Port function operations. */
     102static ddf_dev_ops_t ops = {
     103        .default_handler = default_handler,
    75104};
    76105
     
    110139};
    111140
     141/** Get i8042 soft state from device node. */
     142static i8042_t *dev_i8042(ddf_dev_t *dev)
     143{
     144        return ddf_dev_data_get(dev);
     145}
     146
    112147/** Wait until it is safe to write to the device. */
    113148static void wait_ready(i8042_t *dev)
     
    121156 * Write new data to the corresponding buffer.
    122157 *
     158 * @param dev  Device that caued the interrupt.
    123159 * @param iid  Call id.
    124160 * @param call pointerr to call data.
    125  * @param dev  Device that caued the interrupt.
    126  *
    127  */
    128 static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call,
    129     ddf_dev_t *dev)
    130 {
    131         i8042_t *controller = ddf_dev_data_get(dev);
     161 *
     162 */
     163static void i8042_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
     164    ipc_call_t *call)
     165{
     166        i8042_t *controller = dev_i8042(dev);
    132167       
    133168        const uint8_t status = IPC_GET_ARG1(*call);
     
    143178 *
    144179 * @param dev       Driver structure to initialize.
    145  * @param regs      I/O range  of registers.
     180 * @param regs      I/O address of registers.
     181 * @param reg_size  size of the reserved I/O address space.
    146182 * @param irq_kbd   IRQ for primary port.
    147183 * @param irq_mouse IRQ for aux port.
     
    151187 *
    152188 */
    153 int i8042_init(i8042_t *dev, addr_range_t *regs, int irq_kbd,
     189int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd,
    154190    int irq_mouse, ddf_dev_t *ddf_dev)
    155191{
     
    159195        const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
    160196        irq_cmd_t cmds[cmd_count];
    161         i8042_regs_t *ar;
    162197
    163198        int rc;
     
    168203        dev->aux_fun = NULL;
    169204       
    170         if (regs->size < sizeof(i8042_regs_t)) {
     205        if (reg_size < sizeof(i8042_regs_t)) {
    171206                rc = EINVAL;
    172207                goto error;
    173208        }
    174209       
    175         if (pio_enable_range(regs, (void **) &dev->regs) != 0) {
     210        if (pio_enable(regs, sizeof(i8042_regs_t), (void **) &dev->regs) != 0) {
    176211                rc = EIO;
    177212                goto error;
     
    184219        };
    185220       
    186         dev->kbd = ddf_fun_data_alloc(dev->kbd_fun, sizeof(i8042_port_t));
    187         if (dev->kbd == NULL) {
    188                 rc = ENOMEM;
    189                 goto error;
    190         }
    191        
    192         dev->kbd->ctl = dev;
    193         chardev_srvs_init(&dev->kbd->cds);
    194         dev->kbd->cds.ops = &i8042_chardev_ops;
    195         dev->kbd->cds.sarg = dev->kbd;
    196        
    197221        rc = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90);
    198222        if (rc != EOK)
     
    205229        }
    206230       
    207         dev->aux = ddf_fun_data_alloc(dev->aux_fun, sizeof(i8042_port_t));
    208         if (dev->aux == NULL) {
    209                 rc = ENOMEM;
    210                 goto error;
    211         }
    212        
    213         dev->aux->ctl = dev;
    214         chardev_srvs_init(&dev->aux->cds);
    215         dev->aux->cds.ops = &i8042_chardev_ops;
    216         dev->aux->cds.sarg = dev->aux;
    217        
    218231        rc = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90);
    219232        if (rc != EOK)
    220233                goto error;
    221234       
    222         ddf_fun_set_conn_handler(dev->kbd_fun, i8042_char_conn);
    223         ddf_fun_set_conn_handler(dev->aux_fun, i8042_char_conn);
     235        ddf_fun_set_ops(dev->kbd_fun, &ops);
     236        ddf_fun_set_ops(dev->aux_fun, &ops);
    224237       
    225238        buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE);
     
    254267
    255268        memcpy(ranges, i8042_ranges, sizeof(i8042_ranges));
    256         ranges[0].base = RNGABS(*regs);
    257 
    258 
    259         ar = RNGABSPTR(*regs);
     269        ranges[0].base = (uintptr_t) regs;
     270
    260271        memcpy(cmds, i8042_cmds, sizeof(i8042_cmds));
    261         cmds[0].addr = (void *) &ar->status;
    262         cmds[3].addr = (void *) &ar->data;
     272        cmds[0].addr = (void *) &(((i8042_regs_t *) regs)->status);
     273        cmds[3].addr = (void *) &(((i8042_regs_t *) regs)->data);
    263274
    264275        irq_code_t irq_code = {
     
    318329}
    319330
     331// FIXME TODO use shared instead this
     332enum {
     333        IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
     334        IPC_CHAR_WRITE,
     335};
     336
    320337/** Write data to i8042 port.
    321338 *
    322  * @param srv    Connection-specific data
    323  * @param buffer Data source
    324  * @param size   Data size
     339 * @param fun    DDF function.
     340 * @param buffer Data source.
     341 * @param size   Data size.
    325342 *
    326343 * @return Bytes written.
    327344 *
    328345 */
    329 static int i8042_write(chardev_srv_t *srv, const void *data, size_t size)
    330 {
    331         i8042_port_t *port = (i8042_port_t *)srv->srvs->sarg;
    332         i8042_t *i8042 = port->ctl;
    333         const char *dp = (const char *)data;
    334        
    335         fibril_mutex_lock(&i8042->write_guard);
     346static int i8042_write(ddf_fun_t *fun, char *buffer, size_t size)
     347{
     348        i8042_t *controller = dev_i8042(ddf_fun_get_dev(fun));
     349        fibril_mutex_lock(&controller->write_guard);
    336350       
    337351        for (size_t i = 0; i < size; ++i) {
    338                 if (port == i8042->aux) {
    339                         wait_ready(i8042);
    340                         pio_write_8(&i8042->regs->status,
     352                if (controller->aux_fun == fun) {
     353                        wait_ready(controller);
     354                        pio_write_8(&controller->regs->status,
    341355                            i8042_CMD_WRITE_AUX);
    342356                }
    343357               
    344                 wait_ready(i8042);
    345                 pio_write_8(&i8042->regs->data, dp[i]);
    346         }
    347        
    348         fibril_mutex_unlock(&i8042->write_guard);
     358                wait_ready(controller);
     359                pio_write_8(&controller->regs->data, buffer[i]);
     360        }
     361       
     362        fibril_mutex_unlock(&controller->write_guard);
    349363        return size;
    350364}
     
    352366/** Read data from i8042 port.
    353367 *
    354  * @param srv    Connection-specific data
    355  * @param buffer Data place
    356  * @param size   Data place size
     368 * @param fun    DDF function.
     369 * @param buffer Data place.
     370 * @param size   Data place size.
    357371 *
    358372 * @return Bytes read.
    359373 *
    360374 */
    361 static int i8042_read(chardev_srv_t *srv, void *dest, size_t size)
    362 {
    363         i8042_port_t *port = (i8042_port_t *)srv->srvs->sarg;
    364         i8042_t *i8042 = port->ctl;
    365         uint8_t *destp = (uint8_t *)dest;
    366        
    367         buffer_t *buffer = (port == i8042->aux) ?
    368             &i8042->aux_buffer : &i8042->kbd_buffer;
     375static int i8042_read(ddf_fun_t *fun, char *data, size_t size)
     376{
     377        i8042_t *controller = dev_i8042(ddf_fun_get_dev(fun));
     378        buffer_t *buffer = (fun == controller->aux_fun) ?
     379            &controller->aux_buffer : &controller->kbd_buffer;
    369380       
    370381        for (size_t i = 0; i < size; ++i)
    371                 *destp++ = buffer_read(buffer);
     382                *data++ = buffer_read(buffer);
    372383       
    373384        return size;
     
    376387/** Handle data requests.
    377388 *
     389 * @param fun  ddf_fun_t function.
    378390 * @param id   callid
    379391 * @param call IPC request.
    380  * @param arg  ddf_fun_t function.
    381  */
    382 void i8042_char_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    383 {
    384         i8042_port_t *port = ddf_fun_data_get((ddf_fun_t *)arg);
    385 
    386         chardev_conn(iid, icall, &port->cds);
     392 *
     393 */
     394void default_handler(ddf_fun_t *fun, ipc_callid_t id, ipc_call_t *call)
     395{
     396        const sysarg_t method = IPC_GET_IMETHOD(*call);
     397        const size_t size = IPC_GET_ARG1(*call);
     398       
     399        switch (method) {
     400        case IPC_CHAR_READ:
     401                if (size <= 4 * sizeof(sysarg_t)) {
     402                        sysarg_t message[4] = {};
     403                       
     404                        i8042_read(fun, (char *) message, size);
     405                        async_answer_4(id, size, message[0], message[1],
     406                            message[2], message[3]);
     407                } else
     408                        async_answer_0(id, ELIMIT);
     409                break;
     410       
     411        case IPC_CHAR_WRITE:
     412                if (size <= 3 * sizeof(sysarg_t)) {
     413                        const sysarg_t message[3] = {
     414                                IPC_GET_ARG2(*call),
     415                                IPC_GET_ARG3(*call),
     416                                IPC_GET_ARG4(*call)
     417                        };
     418                       
     419                        i8042_write(fun, (char *) message, size);
     420                        async_answer_0(id, size);
     421                } else
     422                        async_answer_0(id, ELIMIT);
     423       
     424        default:
     425                async_answer_0(id, EINVAL);
     426        }
    387427}
    388428
Note: See TracChangeset for help on using the changeset viewer.