Ignore:
File:
1 edited

Legend:

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

    ra1a101d r75751db6  
    22 * Copyright (c) 2001-2004 Jakub Jermar
    33 * Copyright (c) 2006 Josef Cejka
    4  * Copyright (c) 2009 Jiri Svoboda
     4 * Copyright (c) 2014 Jiri Svoboda
    55 * Copyright (c) 2011 Jan Vesely
    66 * All rights reserved.
     
    3939 */
    4040
     41#include <ddf/log.h>
     42#include <ddf/interrupt.h>
     43#include <ddi.h>
    4144#include <device/hw_res.h>
    42 #include <ddi.h>
    43 #include <libarch/ddi.h>
    4445#include <errno.h>
    4546#include <str_error.h>
    4647#include <inttypes.h>
    47 #include <ddf/log.h>
    48 #include <ddf/interrupt.h>
     48#include <io/chardev_srv.h>
     49
    4950#include "i8042.h"
    5051
     
    6566#define i8042_KBD_TRANSLATE  0x40  /* Use this to switch to XT scancodes */
    6667
    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 
    99 void default_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
    100 
    101 /** Port function operations. */
    102 static ddf_dev_ops_t ops = {
    103         .default_handler = default_handler,
     68static void i8042_char_conn(ipc_callid_t, ipc_call_t *, void *);
     69static int i8042_read(chardev_srv_t *, void *, size_t);
     70static int i8042_write(chardev_srv_t *, const void *, size_t);
     71
     72static chardev_ops_t i8042_chardev_ops = {
     73        .read = i8042_read,
     74        .write = i8042_write
    10475};
    10576
     
    139110};
    140111
    141 /** Get i8042 soft state from device node. */
    142 static i8042_t *dev_i8042(ddf_dev_t *dev)
    143 {
    144         return ddf_dev_data_get(dev);
    145 }
    146 
    147112/** Wait until it is safe to write to the device. */
    148113static void wait_ready(i8042_t *dev)
     
    156121 * Write new data to the corresponding buffer.
    157122 *
    158  * @param dev  Device that caued the interrupt.
    159123 * @param iid  Call id.
    160124 * @param call pointerr to call data.
    161  *
    162  */
    163 static 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);
     125 * @param dev  Device that caued the interrupt.
     126 *
     127 */
     128static 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);
    167132       
    168133        const uint8_t status = IPC_GET_ARG1(*call);
     
    178143 *
    179144 * @param dev       Driver structure to initialize.
    180  * @param regs      I/O address of registers.
    181  * @param reg_size  size of the reserved I/O address space.
     145 * @param regs      I/O range  of registers.
    182146 * @param irq_kbd   IRQ for primary port.
    183147 * @param irq_mouse IRQ for aux port.
     
    187151 *
    188152 */
    189 int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd,
     153int i8042_init(i8042_t *dev, addr_range_t *regs, int irq_kbd,
    190154    int irq_mouse, ddf_dev_t *ddf_dev)
    191155{
     
    195159        const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
    196160        irq_cmd_t cmds[cmd_count];
     161        i8042_regs_t *ar;
    197162
    198163        int rc;
     
    203168        dev->aux_fun = NULL;
    204169       
    205         if (reg_size < sizeof(i8042_regs_t)) {
     170        if (regs->size < sizeof(i8042_regs_t)) {
    206171                rc = EINVAL;
    207172                goto error;
    208173        }
    209174       
    210         if (pio_enable(regs, sizeof(i8042_regs_t), (void **) &dev->regs) != 0) {
     175        if (pio_enable_range(regs, (void **) &dev->regs) != 0) {
    211176                rc = EIO;
    212177                goto error;
     
    219184        };
    220185       
     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       
    221197        rc = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90);
    222198        if (rc != EOK)
     
    229205        }
    230206       
     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       
    231218        rc = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90);
    232219        if (rc != EOK)
    233220                goto error;
    234221       
    235         ddf_fun_set_ops(dev->kbd_fun, &ops);
    236         ddf_fun_set_ops(dev->aux_fun, &ops);
     222        ddf_fun_set_conn_handler(dev->kbd_fun, i8042_char_conn);
     223        ddf_fun_set_conn_handler(dev->aux_fun, i8042_char_conn);
    237224       
    238225        buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE);
     
    267254
    268255        memcpy(ranges, i8042_ranges, sizeof(i8042_ranges));
    269         ranges[0].base = (uintptr_t) regs;
    270 
     256        ranges[0].base = RNGABS(*regs);
     257
     258
     259        ar = RNGABSPTR(*regs);
    271260        memcpy(cmds, i8042_cmds, sizeof(i8042_cmds));
    272         cmds[0].addr = (void *) &(((i8042_regs_t *) regs)->status);
    273         cmds[3].addr = (void *) &(((i8042_regs_t *) regs)->data);
     261        cmds[0].addr = (void *) &ar->status;
     262        cmds[3].addr = (void *) &ar->data;
    274263
    275264        irq_code_t irq_code = {
     
    329318}
    330319
    331 // FIXME TODO use shared instead this
    332 enum {
    333         IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
    334         IPC_CHAR_WRITE,
    335 };
    336 
    337320/** Write data to i8042 port.
    338321 *
    339  * @param fun    DDF function.
    340  * @param buffer Data source.
    341  * @param size   Data size.
     322 * @param srv    Connection-specific data
     323 * @param buffer Data source
     324 * @param size   Data size
    342325 *
    343326 * @return Bytes written.
    344327 *
    345328 */
    346 static 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);
     329static 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);
    350336       
    351337        for (size_t i = 0; i < size; ++i) {
    352                 if (controller->aux_fun == fun) {
    353                         wait_ready(controller);
    354                         pio_write_8(&controller->regs->status,
     338                if (port == i8042->aux) {
     339                        wait_ready(i8042);
     340                        pio_write_8(&i8042->regs->status,
    355341                            i8042_CMD_WRITE_AUX);
    356342                }
    357343               
    358                 wait_ready(controller);
    359                 pio_write_8(&controller->regs->data, buffer[i]);
    360         }
    361        
    362         fibril_mutex_unlock(&controller->write_guard);
     344                wait_ready(i8042);
     345                pio_write_8(&i8042->regs->data, dp[i]);
     346        }
     347       
     348        fibril_mutex_unlock(&i8042->write_guard);
    363349        return size;
    364350}
     
    366352/** Read data from i8042 port.
    367353 *
    368  * @param fun    DDF function.
    369  * @param buffer Data place.
    370  * @param size   Data place size.
     354 * @param srv    Connection-specific data
     355 * @param buffer Data place
     356 * @param size   Data place size
    371357 *
    372358 * @return Bytes read.
    373359 *
    374360 */
    375 static 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;
     361static 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;
    380369       
    381370        for (size_t i = 0; i < size; ++i)
    382                 *data++ = buffer_read(buffer);
     371                *destp++ = buffer_read(buffer);
    383372       
    384373        return size;
     
    387376/** Handle data requests.
    388377 *
    389  * @param fun  ddf_fun_t function.
    390378 * @param id   callid
    391379 * @param call IPC request.
    392  *
    393  */
    394 void 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         }
     380 * @param arg  ddf_fun_t function.
     381 */
     382void 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);
    427387}
    428388
Note: See TracChangeset for help on using the changeset viewer.