Changes in uspace/drv/char/i8042/i8042.c [75751db6:a1a101d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/char/i8042/i8042.c
r75751db6 ra1a101d 2 2 * Copyright (c) 2001-2004 Jakub Jermar 3 3 * Copyright (c) 2006 Josef Cejka 4 * Copyright (c) 20 14Jiri Svoboda4 * Copyright (c) 2009 Jiri Svoboda 5 5 * Copyright (c) 2011 Jan Vesely 6 6 * All rights reserved. … … 39 39 */ 40 40 41 #include <ddf/log.h> 42 #include <ddf/interrupt.h> 41 #include <device/hw_res.h> 43 42 #include <ddi.h> 44 #include < device/hw_res.h>43 #include <libarch/ddi.h> 45 44 #include <errno.h> 46 45 #include <str_error.h> 47 46 #include <inttypes.h> 48 #include < io/chardev_srv.h>49 47 #include <ddf/log.h> 48 #include <ddf/interrupt.h> 50 49 #include "i8042.h" 51 50 … … 66 65 #define i8042_KBD_TRANSLATE 0x40 /* Use this to switch to XT scancodes */ 67 66 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 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, 75 104 }; 76 105 … … 110 139 }; 111 140 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 112 147 /** Wait until it is safe to write to the device. */ 113 148 static void wait_ready(i8042_t *dev) … … 121 156 * Write new data to the corresponding buffer. 122 157 * 158 * @param dev Device that caued the interrupt. 123 159 * @param iid Call id. 124 160 * @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 */ 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); 132 167 133 168 const uint8_t status = IPC_GET_ARG1(*call); … … 143 178 * 144 179 * @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. 146 182 * @param irq_kbd IRQ for primary port. 147 183 * @param irq_mouse IRQ for aux port. … … 151 187 * 152 188 */ 153 int i8042_init(i8042_t *dev, addr_range_t *regs, int irq_kbd,189 int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd, 154 190 int irq_mouse, ddf_dev_t *ddf_dev) 155 191 { … … 159 195 const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t); 160 196 irq_cmd_t cmds[cmd_count]; 161 i8042_regs_t *ar;162 197 163 198 int rc; … … 168 203 dev->aux_fun = NULL; 169 204 170 if (reg s->size < sizeof(i8042_regs_t)) {205 if (reg_size < sizeof(i8042_regs_t)) { 171 206 rc = EINVAL; 172 207 goto error; 173 208 } 174 209 175 if (pio_enable _range(regs, (void **) &dev->regs) != 0) {210 if (pio_enable(regs, sizeof(i8042_regs_t), (void **) &dev->regs) != 0) { 176 211 rc = EIO; 177 212 goto error; … … 184 219 }; 185 220 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 197 221 rc = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90); 198 222 if (rc != EOK) … … 205 229 } 206 230 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 218 231 rc = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90); 219 232 if (rc != EOK) 220 233 goto error; 221 234 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); 224 237 225 238 buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE); … … 254 267 255 268 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 260 271 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); 263 274 264 275 irq_code_t irq_code = { … … 318 329 } 319 330 331 // FIXME TODO use shared instead this 332 enum { 333 IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD, 334 IPC_CHAR_WRITE, 335 }; 336 320 337 /** Write data to i8042 port. 321 338 * 322 * @param srv Connection-specific data323 * @param buffer Data source 324 * @param size Data size 339 * @param fun DDF function. 340 * @param buffer Data source. 341 * @param size Data size. 325 342 * 326 343 * @return Bytes written. 327 344 * 328 345 */ 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); 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); 336 350 337 351 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, 341 355 i8042_CMD_WRITE_AUX); 342 356 } 343 357 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); 349 363 return size; 350 364 } … … 352 366 /** Read data from i8042 port. 353 367 * 354 * @param srv Connection-specific data355 * @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. 357 371 * 358 372 * @return Bytes read. 359 373 * 360 374 */ 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; 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; 369 380 370 381 for (size_t i = 0; i < size; ++i) 371 *d estp++ = buffer_read(buffer);382 *data++ = buffer_read(buffer); 372 383 373 384 return size; … … 376 387 /** Handle data requests. 377 388 * 389 * @param fun ddf_fun_t function. 378 390 * @param id callid 379 391 * @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 */ 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 } 387 427 } 388 428
Note:
See TracChangeset
for help on using the changeset viewer.