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
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <sys/types.h>
00042 #include <bool.h>
00043 #include <ddi.h>
00044 #include <libarch/ddi.h>
00045 #include <devmap.h>
00046 #include <sysinfo.h>
00047 #include <errno.h>
00048 #include <ipc/adb.h>
00049 #include <async.h>
00050 #include <assert.h>
00051 #include "cuda_adb.h"
00052
00053 #define NAME "cuda_adb"
00054
00055 static void cuda_connection(ipc_callid_t iid, ipc_call_t *icall);
00056 static int cuda_init(void);
00057 static void cuda_irq_handler(ipc_callid_t iid, ipc_call_t *call);
00058
00059 static void cuda_irq_listen(void);
00060 static void cuda_irq_receive(void);
00061 static void cuda_irq_rcv_end(void *buf, size_t *len);
00062 static void cuda_irq_send_start(void);
00063 static void cuda_irq_send(void);
00064
00065 static void cuda_packet_handle(uint8_t *buf, size_t len);
00066 static void cuda_send_start(void);
00067 static void cuda_autopoll_set(bool enable);
00068
00069 static void adb_packet_handle(uint8_t *data, size_t size, bool autopoll);
00070
00071
00073 enum {
00074 TREQ = 0x08,
00075 TACK = 0x10,
00076 TIP = 0x20
00077 };
00078
00080 enum {
00081 IER_CLR = 0x00,
00082 IER_SET = 0x80,
00083
00084 SR_INT = 0x04,
00085 ALL_INT = 0x7f
00086 };
00087
00089 enum {
00090 SR_OUT = 0x10
00091 };
00092
00094 enum {
00095 PT_ADB = 0x00,
00096 PT_CUDA = 0x01
00097 };
00098
00100 enum {
00101 CPT_AUTOPOLL = 0x01
00102 };
00103
00104 enum {
00105 ADB_MAX_ADDR = 16
00106 };
00107
00108 static irq_cmd_t cuda_cmds[] = {
00109 {
00110 .cmd = CMD_PIO_READ_8,
00111 .addr = NULL,
00112 .dstarg = 1
00113 },
00114 {
00115 .cmd = CMD_BTEST,
00116 .value = SR_INT,
00117 .srcarg = 1,
00118 .dstarg = 2
00119 },
00120 {
00121 .cmd = CMD_PREDICATE,
00122 .value = 1,
00123 .srcarg = 2
00124 },
00125 {
00126 .cmd = CMD_ACCEPT
00127 }
00128 };
00129
00130
00131 static irq_code_t cuda_irq_code = {
00132 sizeof(cuda_cmds) / sizeof(irq_cmd_t),
00133 cuda_cmds
00134 };
00135
00136 static cuda_instance_t cinst;
00137
00138 static cuda_instance_t *instance = &cinst;
00139 static cuda_t *dev;
00140
00141 static adb_dev_t adb_dev[ADB_MAX_ADDR];
00142
00143 int main(int argc, char *argv[])
00144 {
00145 devmap_handle_t devmap_handle;
00146 int rc;
00147 int i;
00148
00149 printf(NAME ": VIA-CUDA Apple Desktop Bus driver\n");
00150
00151 for (i = 0; i < ADB_MAX_ADDR; ++i) {
00152 adb_dev[i].client_phone = -1;
00153 adb_dev[i].devmap_handle = 0;
00154 }
00155
00156 rc = devmap_driver_register(NAME, cuda_connection);
00157 if (rc < 0) {
00158 printf(NAME ": Unable to register driver.\n");
00159 return rc;
00160 }
00161
00162 rc = devmap_device_register("adb/kbd", &devmap_handle);
00163 if (rc != EOK) {
00164 printf(NAME ": Unable to register device %s.\n", "adb/kdb");
00165 return rc;
00166 }
00167
00168 adb_dev[2].devmap_handle = devmap_handle;
00169 adb_dev[8].devmap_handle = devmap_handle;
00170
00171 rc = devmap_device_register("adb/mouse", &devmap_handle);
00172 if (rc != EOK) {
00173 printf(NAME ": Unable to register device %s.\n", "adb/mouse");
00174 return rc;
00175 }
00176
00177 adb_dev[9].devmap_handle = devmap_handle;
00178
00179 if (cuda_init() < 0) {
00180 printf("cuda_init() failed\n");
00181 return 1;
00182 }
00183
00184 task_retval(0);
00185 async_manager();
00186
00187 return 0;
00188 }
00189
00191 static void cuda_connection(ipc_callid_t iid, ipc_call_t *icall)
00192 {
00193 ipc_callid_t callid;
00194 ipc_call_t call;
00195 sysarg_t method;
00196 devmap_handle_t dh;
00197 int retval;
00198 int dev_addr, i;
00199
00200
00201 dh = IPC_GET_ARG1(*icall);
00202
00203
00204 dev_addr = -1;
00205 for (i = 0; i < ADB_MAX_ADDR; i++) {
00206 if (adb_dev[i].devmap_handle == dh)
00207 dev_addr = i;
00208 }
00209
00210 if (dev_addr < 0) {
00211 async_answer_0(iid, EINVAL);
00212 return;
00213 }
00214
00215
00216 async_answer_0(iid, EOK);
00217
00218 while (1) {
00219 callid = async_get_call(&call);
00220 method = IPC_GET_IMETHOD(call);
00221 switch (method) {
00222 case IPC_M_PHONE_HUNGUP:
00223
00224 async_answer_0(callid, EOK);
00225 return;
00226 case IPC_M_CONNECT_TO_ME:
00227 if (adb_dev[dev_addr].client_phone != -1) {
00228 retval = ELIMIT;
00229 break;
00230 }
00231 adb_dev[dev_addr].client_phone = IPC_GET_ARG5(call);
00232
00233
00234
00235
00236 for (i = 0; i < ADB_MAX_ADDR; ++i) {
00237 if (adb_dev[i].devmap_handle == dh) {
00238 adb_dev[i].client_phone = IPC_GET_ARG5(call);
00239 }
00240 }
00241 retval = 0;
00242 break;
00243 default:
00244 retval = EINVAL;
00245 break;
00246 }
00247 async_answer_0(callid, retval);
00248 }
00249 }
00250
00251
00252 static int cuda_init(void)
00253 {
00254 if (sysinfo_get_value("cuda.address.physical", &(instance->cuda_physical)) != EOK)
00255 return -1;
00256
00257 if (sysinfo_get_value("cuda.address.kernel", &(instance->cuda_kernel)) != EOK)
00258 return -1;
00259
00260 void *vaddr;
00261 if (pio_enable((void *) instance->cuda_physical, sizeof(cuda_t), &vaddr) != 0)
00262 return -1;
00263
00264 dev = vaddr;
00265
00266 instance->cuda = dev;
00267 instance->xstate = cx_listen;
00268 instance->bidx = 0;
00269 instance->snd_bytes = 0;
00270
00271 fibril_mutex_initialize(&instance->dev_lock);
00272
00273
00274 pio_write_8(&dev->ier, IER_CLR | ALL_INT);
00275
00276 cuda_irq_code.cmds[0].addr = (void *) &((cuda_t *) instance->cuda_kernel)->ifr;
00277 async_set_interrupt_received(cuda_irq_handler);
00278 register_irq(10, device_assign_devno(), 0, &cuda_irq_code);
00279
00280
00281 pio_write_8(&dev->ier, TIP | TREQ);
00282 pio_write_8(&dev->ier, IER_SET | SR_INT);
00283
00284
00285 cuda_autopoll_set(true);
00286
00287 return 0;
00288 }
00289
00290 static void cuda_irq_handler(ipc_callid_t iid, ipc_call_t *call)
00291 {
00292 uint8_t rbuf[CUDA_RCV_BUF_SIZE];
00293 size_t len;
00294 bool handle;
00295
00296 handle = false;
00297 len = 0;
00298
00299 fibril_mutex_lock(&instance->dev_lock);
00300
00301
00302 pio_write_8(&instance->cuda->ifr, SR_INT);
00303
00304 switch (instance->xstate) {
00305 case cx_listen: cuda_irq_listen(); break;
00306 case cx_receive: cuda_irq_receive(); break;
00307 case cx_rcv_end: cuda_irq_rcv_end(rbuf, &len);
00308 handle = true; break;
00309 case cx_send_start: cuda_irq_send_start(); break;
00310 case cx_send: cuda_irq_send(); break;
00311 }
00312
00313 fibril_mutex_unlock(&instance->dev_lock);
00314
00315
00316 if (handle)
00317 cuda_packet_handle(rbuf, len);
00318 }
00319
00324 static void cuda_irq_listen(void)
00325 {
00326 uint8_t b;
00327
00328 b = pio_read_8(&dev->b);
00329
00330 if ((b & TREQ) != 0) {
00331 printf("cuda_irq_listen: no TREQ?!\n");
00332 return;
00333 }
00334
00335 pio_read_8(&dev->sr);
00336 pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
00337 instance->xstate = cx_receive;
00338 }
00339
00344 static void cuda_irq_receive(void)
00345 {
00346 uint8_t b, data;
00347
00348 data = pio_read_8(&dev->sr);
00349 if (instance->bidx < CUDA_RCV_BUF_SIZE)
00350 instance->rcv_buf[instance->bidx++] = data;
00351
00352 b = pio_read_8(&dev->b);
00353
00354 if ((b & TREQ) == 0) {
00355 pio_write_8(&dev->b, b ^ TACK);
00356 } else {
00357 pio_write_8(&dev->b, b | TACK | TIP);
00358 instance->xstate = cx_rcv_end;
00359 }
00360 }
00361
00367 static void cuda_irq_rcv_end(void *buf, size_t *len)
00368 {
00369 uint8_t b;
00370
00371 b = pio_read_8(&dev->b);
00372 pio_read_8(&dev->sr);
00373
00374 if ((b & TREQ) == 0) {
00375 instance->xstate = cx_receive;
00376 pio_write_8(&dev->b, b & ~TIP);
00377 } else {
00378 instance->xstate = cx_listen;
00379 cuda_send_start();
00380 }
00381
00382 memcpy(buf, instance->rcv_buf, instance->bidx);
00383 *len = instance->bidx;
00384 instance->bidx = 0;
00385 }
00386
00391 static void cuda_irq_send_start(void)
00392 {
00393 uint8_t b;
00394
00395 b = pio_read_8(&dev->b);
00396
00397 if ((b & TREQ) == 0) {
00398
00399 pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT);
00400 pio_read_8(&dev->sr);
00401 pio_write_8(&dev->b, pio_read_8(&dev->b) | TIP | TACK);
00402 instance->xstate = cx_listen;
00403 return;
00404 }
00405
00406 pio_write_8(&dev->sr, instance->snd_buf[1]);
00407 pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK);
00408 instance->bidx = 2;
00409
00410 instance->xstate = cx_send;
00411 }
00412
00417 static void cuda_irq_send(void)
00418 {
00419 if (instance->bidx < instance->snd_bytes) {
00420
00421 pio_write_8(&dev->sr, instance->snd_buf[instance->bidx++]);
00422 pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK);
00423 return;
00424 }
00425
00426
00427 instance->snd_bytes = 0;
00428 instance->bidx = 0;
00429
00430 pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT);
00431 pio_read_8(&dev->sr);
00432 pio_write_8(&dev->b, pio_read_8(&dev->b) | TACK | TIP);
00433
00434 instance->xstate = cx_listen;
00435
00436 }
00437
00438 static void cuda_packet_handle(uint8_t *data, size_t len)
00439 {
00440 if (data[0] != PT_ADB)
00441 return;
00442 if (len < 2)
00443 return;
00444
00445 adb_packet_handle(data + 2, len - 2, (data[1] & 0x40) != 0);
00446 }
00447
00448 static void adb_packet_handle(uint8_t *data, size_t size, bool autopoll)
00449 {
00450 uint8_t dev_addr;
00451 uint8_t reg_no;
00452 uint16_t reg_val;
00453 unsigned i;
00454
00455 dev_addr = data[0] >> 4;
00456 reg_no = data[0] & 0x03;
00457
00458 if (size != 3) {
00459 printf("unrecognized packet, size=%d\n", size);
00460 for (i = 0; i < size; ++i) {
00461 printf(" 0x%02x", data[i]);
00462 }
00463 putchar('\n');
00464 return;
00465 }
00466
00467 if (reg_no != 0) {
00468 printf("unrecognized packet, size=%d\n", size);
00469 for (i = 0; i < size; ++i) {
00470 printf(" 0x%02x", data[i]);
00471 }
00472 putchar('\n');
00473 return;
00474 }
00475
00476 reg_val = ((uint16_t) data[1] << 8) | (uint16_t) data[2];
00477
00478 if (adb_dev[dev_addr].client_phone == -1)
00479 return;
00480
00481 async_msg_1(adb_dev[dev_addr].client_phone, ADB_REG_NOTIF, reg_val);
00482 }
00483
00484 static void cuda_autopoll_set(bool enable)
00485 {
00486 instance->snd_buf[0] = PT_CUDA;
00487 instance->snd_buf[1] = CPT_AUTOPOLL;
00488 instance->snd_buf[2] = enable ? 0x01 : 0x00;
00489 instance->snd_bytes = 3;
00490 instance->bidx = 0;
00491
00492 cuda_send_start();
00493 }
00494
00495 static void cuda_send_start(void)
00496 {
00497 cuda_t *dev = instance->cuda;
00498
00499 assert(instance->xstate == cx_listen);
00500
00501 if (instance->snd_bytes == 0)
00502 return;
00503
00504
00505 if ((pio_read_8(&dev->b) & TREQ) == 0)
00506 return;
00507
00508 pio_write_8(&dev->acr, pio_read_8(&dev->acr) | SR_OUT);
00509 pio_write_8(&dev->sr, instance->snd_buf[0]);
00510 pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
00511
00512 instance->xstate = cx_send_start;
00513 }
00514
00515