00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00039 #include <ddi.h>
00040 #include <libarch/ddi.h>
00041 #include <devmap.h>
00042 #include <async.h>
00043 #include <unistd.h>
00044 #include <sysinfo.h>
00045 #include <stdio.h>
00046 #include <errno.h>
00047 #include <inttypes.h>
00048
00049 #include "i8042.h"
00050
00051 #define NAME "i8042"
00052 #define NAMESPACE "char"
00053
00054
00055 #define i8042_OUTPUT_FULL 0x01
00056 #define i8042_INPUT_FULL 0x02
00057 #define i8042_AUX_DATA 0x20
00058
00059
00060 #define i8042_CMD_WRITE_CMDB 0x60
00061 #define i8042_CMD_WRITE_AUX 0xd4
00063
00064 #define i8042_KBD_IE 0x01
00065 #define i8042_AUX_IE 0x02
00066 #define i8042_KBD_DISABLE 0x10
00067 #define i8042_AUX_DISABLE 0x20
00068 #define i8042_KBD_TRANSLATE 0x40
00069
00070
00071 enum {
00072 DEVID_PRI = 0,
00073 DEVID_AUX = 1,
00074 MAX_DEVS = 2
00075 };
00076
00077 static irq_cmd_t i8042_cmds[] = {
00078 {
00079 .cmd = CMD_PIO_READ_8,
00080 .addr = NULL,
00081 .dstarg = 1
00082 },
00083 {
00084 .cmd = CMD_BTEST,
00085 .value = i8042_OUTPUT_FULL,
00086 .srcarg = 1,
00087 .dstarg = 3
00088 },
00089 {
00090 .cmd = CMD_PREDICATE,
00091 .value = 2,
00092 .srcarg = 3
00093 },
00094 {
00095 .cmd = CMD_PIO_READ_8,
00096 .addr = NULL,
00097 .dstarg = 2
00098 },
00099 {
00100 .cmd = CMD_ACCEPT
00101 }
00102 };
00103
00104 static irq_code_t i8042_kbd = {
00105 sizeof(i8042_cmds) / sizeof(irq_cmd_t),
00106 i8042_cmds
00107 };
00108
00109 static uintptr_t i8042_physical;
00110 static uintptr_t i8042_kernel;
00111 static i8042_t * i8042;
00112
00113 static i8042_port_t i8042_port[MAX_DEVS];
00114
00115 static void wait_ready(void)
00116 {
00117 while (pio_read_8(&i8042->status) & i8042_INPUT_FULL);
00118 }
00119
00120 static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call);
00121 static void i8042_connection(ipc_callid_t iid, ipc_call_t *icall);
00122 static int i8042_init(void);
00123 static void i8042_port_write(int devid, uint8_t data);
00124
00125
00126 int main(int argc, char *argv[])
00127 {
00128 char name[16];
00129 int i, rc;
00130 char dchar[MAX_DEVS] = { 'a', 'b' };
00131
00132 printf(NAME ": i8042 PS/2 port driver\n");
00133
00134 rc = devmap_driver_register(NAME, i8042_connection);
00135 if (rc < 0) {
00136 printf(NAME ": Unable to register driver.\n");
00137 return rc;
00138 }
00139
00140 if (i8042_init() != EOK)
00141 return -1;
00142
00143 for (i = 0; i < MAX_DEVS; i++) {
00144 i8042_port[i].client_phone = -1;
00145
00146 snprintf(name, 16, "%s/ps2%c", NAMESPACE, dchar[i]);
00147 rc = devmap_device_register(name, &i8042_port[i].devmap_handle);
00148 if (rc != EOK) {
00149 printf(NAME ": Unable to register device %s.\n", name);
00150 return rc;
00151 }
00152 printf(NAME ": Registered device %s\n", name);
00153 }
00154
00155 printf(NAME ": Accepting connections\n");
00156 task_retval(0);
00157 async_manager();
00158
00159
00160 return 0;
00161 }
00162
00163 static int i8042_init(void)
00164 {
00165 if (sysinfo_get_value("i8042.address.physical", &i8042_physical) != EOK)
00166 return -1;
00167
00168 if (sysinfo_get_value("i8042.address.kernel", &i8042_kernel) != EOK)
00169 return -1;
00170
00171 void *vaddr;
00172 if (pio_enable((void *) i8042_physical, sizeof(i8042_t), &vaddr) != 0)
00173 return -1;
00174
00175 i8042 = vaddr;
00176
00177 sysarg_t inr_a;
00178 sysarg_t inr_b;
00179
00180 if (sysinfo_get_value("i8042.inr_a", &inr_a) != EOK)
00181 return -1;
00182
00183 if (sysinfo_get_value("i8042.inr_b", &inr_b) != EOK)
00184 return -1;
00185
00186 async_set_interrupt_received(i8042_irq_handler);
00187
00188
00189 wait_ready();
00190 pio_write_8(&i8042->status, i8042_CMD_WRITE_CMDB);
00191 wait_ready();
00192 pio_write_8(&i8042->data, i8042_KBD_DISABLE | i8042_AUX_DISABLE);
00193
00194
00195 while (pio_read_8(&i8042->status) & i8042_OUTPUT_FULL)
00196 (void) pio_read_8(&i8042->data);
00197
00198 i8042_kbd.cmds[0].addr = (void *) &((i8042_t *) i8042_kernel)->status;
00199 i8042_kbd.cmds[3].addr = (void *) &((i8042_t *) i8042_kernel)->data;
00200 register_irq(inr_a, device_assign_devno(), 0, &i8042_kbd);
00201 register_irq(inr_b, device_assign_devno(), 0, &i8042_kbd);
00202 printf("%s: registered for interrupts %" PRIun " and %" PRIun "\n",
00203 NAME, inr_a, inr_b);
00204
00205 wait_ready();
00206 pio_write_8(&i8042->status, i8042_CMD_WRITE_CMDB);
00207 wait_ready();
00208 pio_write_8(&i8042->data, i8042_KBD_IE | i8042_KBD_TRANSLATE |
00209 i8042_AUX_IE);
00210
00211 return 0;
00212 }
00213
00215 static void i8042_connection(ipc_callid_t iid, ipc_call_t *icall)
00216 {
00217 ipc_callid_t callid;
00218 ipc_call_t call;
00219 sysarg_t method;
00220 devmap_handle_t dh;
00221 int retval;
00222 int dev_id, i;
00223
00224 printf(NAME ": connection handler\n");
00225
00226
00227 dh = IPC_GET_ARG1(*icall);
00228
00229
00230 dev_id = -1;
00231 for (i = 0; i < MAX_DEVS; i++) {
00232 if (i8042_port[i].devmap_handle == dh)
00233 dev_id = i;
00234 }
00235
00236 if (dev_id < 0) {
00237 async_answer_0(iid, EINVAL);
00238 return;
00239 }
00240
00241
00242 async_answer_0(iid, EOK);
00243
00244 printf(NAME ": accepted connection\n");
00245
00246 while (1) {
00247 callid = async_get_call(&call);
00248 method = IPC_GET_IMETHOD(call);
00249 switch (method) {
00250 case IPC_M_PHONE_HUNGUP:
00251
00252 async_answer_0(callid, EOK);
00253 return;
00254 case IPC_M_CONNECT_TO_ME:
00255 printf(NAME ": creating callback connection\n");
00256 if (i8042_port[dev_id].client_phone != -1) {
00257 retval = ELIMIT;
00258 break;
00259 }
00260 i8042_port[dev_id].client_phone = IPC_GET_ARG5(call);
00261 retval = 0;
00262 break;
00263 case IPC_FIRST_USER_METHOD:
00264 printf(NAME ": write %" PRIun " to devid %d\n",
00265 IPC_GET_ARG1(call), dev_id);
00266 i8042_port_write(dev_id, IPC_GET_ARG1(call));
00267 retval = 0;
00268 break;
00269 default:
00270 retval = EINVAL;
00271 break;
00272 }
00273 async_answer_0(callid, retval);
00274 }
00275 }
00276
00277 void i8042_port_write(int devid, uint8_t data)
00278 {
00279 if (devid == DEVID_AUX) {
00280 wait_ready();
00281 pio_write_8(&i8042->status, i8042_CMD_WRITE_AUX);
00282 }
00283 wait_ready();
00284 pio_write_8(&i8042->data, data);
00285 }
00286
00287 static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call)
00288 {
00289 int status, data;
00290 int devid;
00291
00292 status = IPC_GET_ARG1(*call);
00293 data = IPC_GET_ARG2(*call);
00294
00295 if ((status & i8042_AUX_DATA)) {
00296 devid = DEVID_AUX;
00297 } else {
00298 devid = DEVID_PRI;
00299 }
00300
00301 if (i8042_port[devid].client_phone != -1) {
00302 async_msg_1(i8042_port[devid].client_phone,
00303 IPC_FIRST_USER_METHOD, data);
00304 }
00305 }
00306