Ignore:
File:
1 edited

Legend:

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

    rbd87ae0 r876f6463  
    2929 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    3030 */
     31
    3132/** @addtogroup kbd_port
    3233 * @ingroup kbd
    3334 * @{
    3435 */
     36
    3537/** @file
    3638 * @brief i8042 PS/2 port driver.
     
    4446#include <str_error.h>
    4547#include <inttypes.h>
    46 
    4748#include <ddf/log.h>
    4849#include <ddf/interrupt.h>
    49 
    5050#include "i8042.h"
    5151
    52 #define NAME       "i8042"
     52/* Interesting bits for status register */
     53#define i8042_OUTPUT_FULL  0x01
     54#define i8042_INPUT_FULL   0x02
     55#define i8042_AUX_DATA     0x20
     56
     57/* Command constants */
     58#define i8042_CMD_WRITE_CMDB  0x60  /**< Write command byte */
     59#define i8042_CMD_WRITE_AUX   0xd4  /**< Write aux device */
     60
     61/* Command byte fields */
     62#define i8042_KBD_IE         0x01
     63#define i8042_AUX_IE         0x02
     64#define i8042_KBD_DISABLE    0x10
     65#define i8042_AUX_DISABLE    0x20
     66#define i8042_KBD_TRANSLATE  0x40  /* Use this to switch to XT scancodes */
     67
     68#define CHECK_RET_DESTROY(ret, msg...) \
     69        do { \
     70                if (ret != EOK) { \
     71                        ddf_msg(LVL_ERROR, msg); \
     72                        if (dev->kbd_fun) { \
     73                                dev->kbd_fun->driver_data = NULL; \
     74                                ddf_fun_destroy(dev->kbd_fun); \
     75                        } \
     76                        if (dev->aux_fun) { \
     77                                dev->aux_fun->driver_data = NULL; \
     78                                ddf_fun_destroy(dev->aux_fun); \
     79                        } \
     80                } \
     81        } while (0)
     82
     83#define CHECK_RET_UNBIND_DESTROY(ret, msg...) \
     84        do { \
     85                if (ret != EOK) { \
     86                        ddf_msg(LVL_ERROR, msg); \
     87                        if (dev->kbd_fun) { \
     88                                ddf_fun_unbind(dev->kbd_fun); \
     89                                dev->kbd_fun->driver_data = NULL; \
     90                                ddf_fun_destroy(dev->kbd_fun); \
     91                        } \
     92                        if (dev->aux_fun) { \
     93                                ddf_fun_unbind(dev->aux_fun); \
     94                                dev->aux_fun->driver_data = NULL; \
     95                                ddf_fun_destroy(dev->aux_fun); \
     96                        } \
     97                } \
     98        } while (0)
    5399
    54100void default_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
     
    59105};
    60106
    61 /* Interesting bits for status register */
    62 #define i8042_OUTPUT_FULL       0x01
    63 #define i8042_INPUT_FULL        0x02
    64 #define i8042_AUX_DATA          0x20
    65 
    66 /* Command constants */
    67 #define i8042_CMD_WRITE_CMDB    0x60    /**< write command byte */
    68 #define i8042_CMD_WRITE_AUX     0xd4    /**< write aux device */
    69 
    70 /* Command byte fields */
    71 #define i8042_KBD_IE            0x01
    72 #define i8042_AUX_IE            0x02
    73 #define i8042_KBD_DISABLE       0x10
    74 #define i8042_AUX_DISABLE       0x20
    75 #define i8042_KBD_TRANSLATE     0x40 /* Use this to switch to XT scancodes */
    76 
    77107/** i8042 Interrupt pseudo-code. */
    78108static const irq_cmd_t i8042_cmds[] = {
    79109        {
    80110                .cmd = CMD_PIO_READ_8,
    81                 .addr = NULL,   /* will be patched in run-time */
     111                .addr = NULL,  /* will be patched in run-time */
    82112                .dstarg = 1
    83113        },
     
    95125        {
    96126                .cmd = CMD_PIO_READ_8,
    97                 .addr = NULL,   /* will be patched in run-time */
     127                .addr = NULL,  /* will be patched in run-time */
    98128                .dstarg = 2
    99129        },
     
    111141
    112142/** Interrupt handler routine.
    113  * Writes new data to the corresponding buffer.
    114  * @param dev Device that caued the interrupt.
    115  * @param iid Call id.
     143 *
     144 * Write new data to the corresponding buffer.
     145 *
     146 * @param dev  Device that caued the interrupt.
     147 * @param iid  Call id.
    116148 * @param call pointerr to call data.
    117  */
    118 static void i8042_irq_handler(
    119     ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
    120 {
    121         if (!dev || !dev->driver_data)
     149 *
     150 */
     151static void i8042_irq_handler(ddf_dev_t *dev, ipc_callid_t iid,
     152    ipc_call_t *call)
     153{
     154        if ((!dev) || (!dev->driver_data))
    122155                return;
     156       
    123157        i8042_t *controller = dev->driver_data;
    124 
     158       
    125159        const uint8_t status = IPC_GET_ARG1(*call);
    126160        const uint8_t data = IPC_GET_ARG2(*call);
     161       
    127162        buffer_t *buffer = (status & i8042_AUX_DATA) ?
    128163            &controller->aux_buffer : &controller->kbd_buffer;
     164       
    129165        buffer_write(buffer, data);
    130166}
    131167
    132168/** Initialize i8042 driver structure.
    133  * @param dev Driver structure to initialize.
    134  * @param regs I/O address of registers.
    135  * @param reg_size size of the reserved I/O address space.
    136  * @param irq_kbd IRQ for primary port.
     169 *
     170 * @param dev       Driver structure to initialize.
     171 * @param regs      I/O address of registers.
     172 * @param reg_size  size of the reserved I/O address space.
     173 * @param irq_kbd   IRQ for primary port.
    137174 * @param irq_mouse IRQ for aux port.
    138  * @param ddf_dev DDF device structure of the device.
     175 * @param ddf_dev   DDF device structure of the device.
     176 *
    139177 * @return Error code.
     178 *
    140179 */
    141180int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd,
     
    144183        assert(ddf_dev);
    145184        assert(dev);
    146 
     185       
    147186        if (reg_size < sizeof(i8042_regs_t))
    148187                return EINVAL;
    149 
    150         if (pio_enable(regs, sizeof(i8042_regs_t), (void**)&dev->regs) != 0)
     188       
     189        if (pio_enable(regs, sizeof(i8042_regs_t), (void **) &dev->regs) != 0)
    151190                return -1;
    152 
     191       
    153192        dev->kbd_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2a");
    154193        if (!dev->kbd_fun)
    155194                return ENOMEM;
     195       
    156196        int ret = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90);
    157197        if (ret != EOK) {
     
    159199                return ret;
    160200        }
    161 
     201       
    162202        dev->aux_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2b");
    163203        if (!dev->aux_fun) {
     
    165205                return ENOMEM;
    166206        }
    167 
     207       
    168208        ret = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90);
    169209        if (ret != EOK) {
     
    172212                return ret;
    173213        }
    174 
     214       
    175215        dev->kbd_fun->ops = &ops;
    176216        dev->aux_fun->ops = &ops;
    177217        dev->kbd_fun->driver_data = dev;
    178218        dev->aux_fun->driver_data = dev;
    179 
     219       
    180220        buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE);
    181221        buffer_init(&dev->aux_buffer, dev->aux_data, BUFFER_SIZE);
    182222        fibril_mutex_initialize(&dev->write_guard);
    183 
    184 #define CHECK_RET_DESTROY(ret, msg...) \
    185 if  (ret != EOK) { \
    186         ddf_msg(LVL_ERROR, msg); \
    187         if (dev->kbd_fun) { \
    188                 dev->kbd_fun->driver_data = NULL; \
    189                 ddf_fun_destroy(dev->kbd_fun); \
    190         } \
    191         if (dev->aux_fun) { \
    192                 dev->aux_fun->driver_data = NULL; \
    193                 ddf_fun_destroy(dev->aux_fun); \
    194         } \
    195 } else (void)0
    196 
     223       
    197224        ret = ddf_fun_bind(dev->kbd_fun);
    198         CHECK_RET_DESTROY(ret,
    199             "Failed to bind keyboard function: %s.", str_error(ret));
    200 
     225        CHECK_RET_DESTROY(ret, "Failed to bind keyboard function: %s.",
     226            str_error(ret));
     227       
    201228        ret = ddf_fun_bind(dev->aux_fun);
    202         CHECK_RET_DESTROY(ret,
    203             "Failed to bind mouse function: %s.", str_error(ret));
    204 
     229        CHECK_RET_DESTROY(ret, "Failed to bind mouse function: %s.",
     230            str_error(ret));
     231       
    205232        /* Disable kbd and aux */
    206233        wait_ready(dev);
     
    208235        wait_ready(dev);
    209236        pio_write_8(&dev->regs->data, i8042_KBD_DISABLE | i8042_AUX_DISABLE);
    210 
     237       
    211238        /* Flush all current IO */
    212239        while (pio_read_8(&dev->regs->status) & i8042_OUTPUT_FULL)
    213240                (void) pio_read_8(&dev->regs->data);
    214 
    215 #define CHECK_RET_UNBIND_DESTROY(ret, msg...) \
    216 if  (ret != EOK) { \
    217         ddf_msg(LVL_ERROR, msg); \
    218         if (dev->kbd_fun) { \
    219                 ddf_fun_unbind(dev->kbd_fun); \
    220                 dev->kbd_fun->driver_data = NULL; \
    221                 ddf_fun_destroy(dev->kbd_fun); \
    222         } \
    223         if (dev->aux_fun) { \
    224                 ddf_fun_unbind(dev->aux_fun); \
    225                 dev->aux_fun->driver_data = NULL; \
    226                 ddf_fun_destroy(dev->aux_fun); \
    227         } \
    228 } else (void)0
    229 
     241       
    230242        const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
    231243        irq_cmd_t cmds[cmd_count];
     
    233245        cmds[0].addr = (void *) &dev->regs->status;
    234246        cmds[3].addr = (void *) &dev->regs->data;
    235 
    236         irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = cmds };
     247       
     248        irq_code_t irq_code = {
     249                .cmdcount = cmd_count,
     250                .cmds = cmds
     251        };
     252       
    237253        ret = register_interrupt_handler(ddf_dev, irq_kbd, i8042_irq_handler,
    238254            &irq_code);
    239         CHECK_RET_UNBIND_DESTROY(ret,
    240             "Failed set handler for kbd: %s.", str_error(ret));
    241 
     255        CHECK_RET_UNBIND_DESTROY(ret, "Failed set handler for kbd: %s.",
     256            str_error(ret));
     257       
    242258        ret = register_interrupt_handler(ddf_dev, irq_mouse, i8042_irq_handler,
    243259            &irq_code);
    244         CHECK_RET_UNBIND_DESTROY(ret,
    245             "Failed set handler for mouse: %s.", str_error(ret));
    246 
     260        CHECK_RET_UNBIND_DESTROY(ret, "Failed set handler for mouse: %s.",
     261            str_error(ret));
     262       
    247263        /* Enable interrupts */
    248264        async_sess_t *parent_sess =
     
    251267        ret = parent_sess ? EOK : ENOMEM;
    252268        CHECK_RET_UNBIND_DESTROY(ret, "Failed to create parent connection.");
    253 
     269       
    254270        const bool enabled = hw_res_enable_interrupt(parent_sess);
    255271        async_hangup(parent_sess);
    256272        ret = enabled ? EOK : EIO;
    257273        CHECK_RET_UNBIND_DESTROY(ret, "Failed to enable interrupts: %s.");
    258 
     274       
    259275        /* Enable port interrupts. */
    260276        wait_ready(dev);
     
    263279        pio_write_8(&dev->regs->data, i8042_KBD_IE | i8042_KBD_TRANSLATE |
    264280            i8042_AUX_IE);
    265 
     281       
    266282        return EOK;
    267283}
    268284
    269 // TODO use shared instead this
     285// FIXME TODO use shared instead this
    270286enum {
    271287        IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
     
    274290
    275291/** Write data to i8042 port.
    276  * @param fun DDF function.
     292 *
     293 * @param fun    DDF function.
    277294 * @param buffer Data source.
    278  * @param size Data size.
     295 * @param size   Data size.
     296 *
    279297 * @return Bytes written.
     298 *
    280299 */
    281300static int i8042_write(ddf_fun_t *fun, char *buffer, size_t size)
     
    283302        assert(fun);
    284303        assert(fun->driver_data);
     304       
    285305        i8042_t *controller = fun->driver_data;
    286306        fibril_mutex_lock(&controller->write_guard);
     307       
    287308        for (size_t i = 0; i < size; ++i) {
     309                if (controller->aux_fun == fun) {
     310                        wait_ready(controller);
     311                        pio_write_8(&controller->regs->status,
     312                            i8042_CMD_WRITE_AUX);
     313                }
     314               
    288315                wait_ready(controller);
    289                 if (controller->aux_fun == fun)
    290                         pio_write_8(
    291                             &controller->regs->status, i8042_CMD_WRITE_AUX);
    292316                pio_write_8(&controller->regs->data, buffer[i]);
    293317        }
     318       
    294319        fibril_mutex_unlock(&controller->write_guard);
    295320        return size;
     
    297322
    298323/** Read data from i8042 port.
    299  * @param fun DDF function.
     324 *
     325 * @param fun    DDF function.
    300326 * @param buffer Data place.
    301  * @param size Data place size.
     327 * @param size   Data place size.
     328 *
    302329 * @return Bytes read.
     330 *
    303331 */
    304332static int i8042_read(ddf_fun_t *fun, char *data, size_t size)
     
    306334        assert(fun);
    307335        assert(fun->driver_data);
    308 
     336       
    309337        i8042_t *controller = fun->driver_data;
    310338        buffer_t *buffer = (fun == controller->aux_fun) ?
    311339            &controller->aux_buffer : &controller->kbd_buffer;
    312         for (size_t i = 0; i < size; ++i) {
     340       
     341        for (size_t i = 0; i < size; ++i)
    313342                *data++ = buffer_read(buffer);
    314         }
     343       
    315344        return size;
    316345}
    317346
    318347/** Handle data requests.
    319  * @param fun ddf_fun_t function.
    320  * @param id callid
     348 *
     349 * @param fun  ddf_fun_t function.
     350 * @param id   callid
    321351 * @param call IPC request.
     352 *
    322353 */
    323354void default_handler(ddf_fun_t *fun, ipc_callid_t id, ipc_call_t *call)
     
    325356        const sysarg_t method = IPC_GET_IMETHOD(*call);
    326357        const size_t size = IPC_GET_ARG1(*call);
     358       
    327359        switch (method) {
    328360        case IPC_CHAR_READ:
    329361                if (size <= 4 * sizeof(sysarg_t)) {
    330362                        sysarg_t message[4] = {};
    331                         i8042_read(fun, (char*)message, size);
     363                       
     364                        i8042_read(fun, (char *) message, size);
    332365                        async_answer_4(id, size, message[0], message[1],
    333366                            message[2], message[3]);
    334                 } else {
     367                } else
    335368                        async_answer_0(id, ELIMIT);
    336                 }
    337369                break;
    338 
     370       
    339371        case IPC_CHAR_WRITE:
    340372                if (size <= 3 * sizeof(sysarg_t)) {
    341373                        const sysarg_t message[3] = {
    342                                 IPC_GET_ARG2(*call), IPC_GET_ARG3(*call),
    343                                 IPC_GET_ARG4(*call) };
    344                         i8042_write(fun, (char*)message, size);
     374                                IPC_GET_ARG2(*call),
     375                                IPC_GET_ARG3(*call),
     376                                IPC_GET_ARG4(*call)
     377                        };
     378                       
     379                        i8042_write(fun, (char *) message, size);
    345380                        async_answer_0(id, size);
    346                 } else {
     381                } else
    347382                        async_answer_0(id, ELIMIT);
    348                 }
    349 
     383       
    350384        default:
    351385                async_answer_0(id, EINVAL);
    352386        }
    353387}
     388
    354389/**
    355390 * @}
Note: See TracChangeset for help on using the changeset viewer.