source: mainline/uspace/drv/bus/adb/cuda_adb/cuda_adb.c@ 6769005

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6769005 was 6769005, checked in by Jakub Jermar <jakub@…>, 7 years ago

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

  • Property mode set to 100644
File size: 11.4 KB
Line 
1/*
2 * Copyright (c) 2010 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup uspace_drv_cuda_adb
30 * @{
31 */
32/** @file VIA-CUDA Apple Desktop Bus driver
33 *
34 * Note: We should really do a full bus scan at the beginning and resolve
35 * address conflicts. Also we should consider the handler ID in r3. Instead
36 * we just assume a keyboard at address 2 or 8 and a mouse at address 9.
37 */
38
39#include <assert.h>
40#include <ddf/driver.h>
41#include <ddf/log.h>
42#include <ddi.h>
43#include <errno.h>
44#include <ipc/adb.h>
45#include <libarch/ddi.h>
46#include <stdbool.h>
47#include <stddef.h>
48#include <stdint.h>
49#include <stdio.h>
50#include <stdlib.h>
51
52#include "cuda_adb.h"
53#include "cuda_hw.h"
54
55#define NAME "cuda_adb"
56
57static void cuda_dev_connection(ipc_call_t *, void *);
58static errno_t cuda_init(cuda_t *);
59static void cuda_irq_handler(ipc_call_t *, void *);
60
61static void cuda_irq_listen(cuda_t *);
62static void cuda_irq_receive(cuda_t *);
63static void cuda_irq_rcv_end(cuda_t *, void *, size_t *);
64static void cuda_irq_send_start(cuda_t *);
65static void cuda_irq_send(cuda_t *);
66
67static void cuda_packet_handle(cuda_t *, uint8_t *, size_t);
68static void cuda_send_start(cuda_t *);
69static void cuda_autopoll_set(cuda_t *, bool);
70
71static void adb_packet_handle(cuda_t *, uint8_t *, size_t, bool);
72
73static irq_pio_range_t cuda_ranges[] = {
74 {
75 .base = 0,
76 .size = sizeof(cuda_regs_t)
77 }
78};
79
80static irq_cmd_t cuda_cmds[] = {
81 {
82 .cmd = CMD_PIO_READ_8,
83 .addr = NULL,
84 .dstarg = 1
85 },
86 {
87 .cmd = CMD_AND,
88 .value = SR_INT,
89 .srcarg = 1,
90 .dstarg = 2
91 },
92 {
93 .cmd = CMD_PREDICATE,
94 .value = 1,
95 .srcarg = 2
96 },
97 {
98 .cmd = CMD_ACCEPT
99 }
100};
101
102static irq_code_t cuda_irq_code = {
103 sizeof(cuda_ranges) / sizeof(irq_pio_range_t),
104 cuda_ranges,
105 sizeof(cuda_cmds) / sizeof(irq_cmd_t),
106 cuda_cmds
107};
108
109static errno_t cuda_dev_create(cuda_t *cuda, const char *name, const char *id,
110 adb_dev_t **rdev)
111{
112 adb_dev_t *dev = NULL;
113 ddf_fun_t *fun;
114 errno_t rc;
115
116 fun = ddf_fun_create(cuda->dev, fun_inner, name);
117 if (fun == NULL) {
118 ddf_msg(LVL_ERROR, "Failed creating function '%s'.", name);
119 rc = ENOMEM;
120 goto error;
121 }
122
123 rc = ddf_fun_add_match_id(fun, id, 10);
124 if (rc != EOK) {
125 ddf_msg(LVL_ERROR, "Failed adding match ID.");
126 rc = ENOMEM;
127 goto error;
128 }
129
130 dev = ddf_fun_data_alloc(fun, sizeof(adb_dev_t));
131 if (dev == NULL) {
132 ddf_msg(LVL_ERROR, "Failed allocating memory for '%s'.", name);
133 rc = ENOMEM;
134 goto error;
135 }
136
137 dev->fun = fun;
138 list_append(&dev->lcuda, &cuda->devs);
139
140 ddf_fun_set_conn_handler(fun, cuda_dev_connection);
141
142 rc = ddf_fun_bind(fun);
143 if (rc != EOK) {
144 ddf_msg(LVL_ERROR, "Failed binding function '%s'.", name);
145 goto error;
146 }
147
148 *rdev = dev;
149 return EOK;
150error:
151 if (fun != NULL)
152 ddf_fun_destroy(fun);
153 return rc;
154}
155
156errno_t cuda_add(cuda_t *cuda, cuda_res_t *res)
157{
158 adb_dev_t *kbd = NULL;
159 adb_dev_t *mouse = NULL;
160 errno_t rc;
161
162 cuda->phys_base = res->base;
163
164 rc = cuda_dev_create(cuda, "kbd", "adb/keyboard", &kbd);
165 if (rc != EOK)
166 goto error;
167
168 rc = cuda_dev_create(cuda, "mouse", "adb/mouse", &mouse);
169 if (rc != EOK)
170 goto error;
171
172 cuda->addr_dev[2] = kbd;
173 cuda->addr_dev[8] = kbd;
174
175 cuda->addr_dev[9] = mouse;
176
177 rc = cuda_init(cuda);
178 if (rc != EOK) {
179 ddf_msg(LVL_ERROR, "Failed initializing CUDA hardware.");
180 return rc;
181 }
182
183 return EOK;
184error:
185 return rc;
186}
187
188errno_t cuda_remove(cuda_t *cuda)
189{
190 return ENOTSUP;
191}
192
193errno_t cuda_gone(cuda_t *cuda)
194{
195 return ENOTSUP;
196}
197
198/** Device connection handler */
199static void cuda_dev_connection(ipc_call_t *icall, void *arg)
200{
201 adb_dev_t *dev = (adb_dev_t *) ddf_fun_data_get((ddf_fun_t *) arg);
202 ipc_call_t call;
203 sysarg_t method;
204
205 /* Answer the IPC_M_CONNECT_ME_TO call. */
206 async_answer_5(icall, EOK, 0, 0, 0, 0, async_get_label());
207
208 while (true) {
209 async_get_call(&call);
210 method = IPC_GET_IMETHOD(call);
211
212 if (!method) {
213 /* The other side has hung up. */
214 async_answer_0(&call, EOK);
215 return;
216 }
217
218 async_sess_t *sess =
219 async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
220 if (sess != NULL) {
221 dev->client_sess = sess;
222 async_answer_0(&call, EOK);
223 } else {
224 async_answer_0(&call, EINVAL);
225 }
226 }
227}
228
229static errno_t cuda_init(cuda_t *cuda)
230{
231 errno_t rc;
232
233 void *vaddr;
234 rc = pio_enable((void *) cuda->phys_base, sizeof(cuda_regs_t),
235 &vaddr);
236 if (rc != EOK)
237 return rc;
238
239 cuda->regs = vaddr;
240 cuda->xstate = cx_listen;
241 cuda->bidx = 0;
242 cuda->snd_bytes = 0;
243
244 fibril_mutex_initialize(&cuda->dev_lock);
245
246 /* Disable all interrupts from CUDA. */
247 pio_write_8(&cuda->regs->ier, IER_CLR | ALL_INT);
248
249 cuda_irq_code.ranges[0].base = (uintptr_t) cuda->phys_base;
250 cuda_irq_code.cmds[0].addr = (void *) &((cuda_regs_t *)
251 cuda->phys_base)->ifr;
252 async_irq_subscribe(10, cuda_irq_handler, cuda, &cuda_irq_code, NULL);
253
254 /* Enable SR interrupt. */
255 pio_write_8(&cuda->regs->ier, TIP | TREQ);
256 pio_write_8(&cuda->regs->ier, IER_SET | SR_INT);
257
258 /* Enable ADB autopolling. */
259 cuda_autopoll_set(cuda, true);
260
261 return EOK;
262}
263
264static void cuda_irq_handler(ipc_call_t *call, void *arg)
265{
266 uint8_t rbuf[CUDA_RCV_BUF_SIZE];
267 cuda_t *cuda = (cuda_t *)arg;
268 size_t len;
269 bool handle;
270
271 handle = false;
272 len = 0;
273
274 fibril_mutex_lock(&cuda->dev_lock);
275
276 switch (cuda->xstate) {
277 case cx_listen:
278 cuda_irq_listen(cuda);
279 break;
280 case cx_receive:
281 cuda_irq_receive(cuda);
282 break;
283 case cx_rcv_end:
284 cuda_irq_rcv_end(cuda, rbuf, &len);
285 handle = true;
286 break;
287 case cx_send_start:
288 cuda_irq_send_start(cuda);
289 break;
290 case cx_send:
291 cuda_irq_send(cuda);
292 break;
293 }
294
295 /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */
296 pio_write_8(&cuda->regs->ifr, SR_INT);
297
298 fibril_mutex_unlock(&cuda->dev_lock);
299
300 /* Handle an incoming packet. */
301 if (handle)
302 cuda_packet_handle(cuda, rbuf, len);
303}
304
305/** Interrupt in listen state.
306 *
307 * Start packet reception.
308 *
309 * @param cuda CUDA instance
310 */
311static void cuda_irq_listen(cuda_t *cuda)
312{
313 uint8_t b = pio_read_8(&cuda->regs->b);
314
315 if ((b & TREQ) != 0) {
316 ddf_msg(LVL_WARN, "cuda_irq_listen: no TREQ?!");
317 return;
318 }
319
320 pio_write_8(&cuda->regs->b, b & ~TIP);
321 cuda->xstate = cx_receive;
322}
323
324/** Interrupt in receive state.
325 *
326 * Receive next byte of packet.
327 *
328 * @param cuda CUDA instance
329 */
330static void cuda_irq_receive(cuda_t *cuda)
331{
332 uint8_t data = pio_read_8(&cuda->regs->sr);
333 if (cuda->bidx < CUDA_RCV_BUF_SIZE)
334 cuda->rcv_buf[cuda->bidx++] = data;
335
336 uint8_t b = pio_read_8(&cuda->regs->b);
337
338 if ((b & TREQ) == 0) {
339 pio_write_8(&cuda->regs->b, b ^ TACK);
340 } else {
341 pio_write_8(&cuda->regs->b, b | TACK | TIP);
342 cuda->xstate = cx_rcv_end;
343 }
344}
345
346/** Interrupt in rcv_end state.
347 *
348 * Terminate packet reception. Either go back to listen state or start
349 * receiving another packet if CUDA has one for us.
350 *
351 * @param cuda CUDA instance
352 * @param buf Buffer for storing received packet
353 * @param len Place to store length of received packet
354 */
355static void cuda_irq_rcv_end(cuda_t *cuda, void *buf, size_t *len)
356{
357 uint8_t b = pio_read_8(&cuda->regs->b);
358
359 if ((b & TREQ) == 0) {
360 cuda->xstate = cx_receive;
361 pio_write_8(&cuda->regs->b, b & ~TIP);
362 } else {
363 cuda->xstate = cx_listen;
364 cuda_send_start(cuda);
365 }
366
367 memcpy(buf, cuda->rcv_buf, cuda->bidx);
368 *len = cuda->bidx;
369 cuda->bidx = 0;
370}
371
372/** Interrupt in send_start state.
373 *
374 * Process result of sending first byte (and send second on success).
375 *
376 * @param cuda CUDA instance
377 */
378static void cuda_irq_send_start(cuda_t *cuda)
379{
380 uint8_t b;
381
382 b = pio_read_8(&cuda->regs->b);
383
384 if ((b & TREQ) == 0) {
385 /* Collision */
386 pio_write_8(&cuda->regs->acr, pio_read_8(&cuda->regs->acr) &
387 ~SR_OUT);
388 pio_read_8(&cuda->regs->sr);
389 pio_write_8(&cuda->regs->b, pio_read_8(&cuda->regs->b) |
390 TIP | TACK);
391 cuda->xstate = cx_listen;
392 return;
393 }
394
395 pio_write_8(&cuda->regs->sr, cuda->snd_buf[1]);
396 pio_write_8(&cuda->regs->b, pio_read_8(&cuda->regs->b) ^ TACK);
397 cuda->bidx = 2;
398
399 cuda->xstate = cx_send;
400}
401
402/** Interrupt in send state.
403 *
404 * Send next byte or terminate transmission.
405 *
406 * @param cuda CUDA instance
407 */
408static void cuda_irq_send(cuda_t *cuda)
409{
410 if (cuda->bidx < cuda->snd_bytes) {
411 /* Send next byte. */
412 pio_write_8(&cuda->regs->sr,
413 cuda->snd_buf[cuda->bidx++]);
414 pio_write_8(&cuda->regs->b, pio_read_8(&cuda->regs->b) ^ TACK);
415 return;
416 }
417
418 /* End transfer. */
419 cuda->snd_bytes = 0;
420 cuda->bidx = 0;
421
422 pio_write_8(&cuda->regs->acr, pio_read_8(&cuda->regs->acr) & ~SR_OUT);
423 pio_read_8(&cuda->regs->sr);
424 pio_write_8(&cuda->regs->b, pio_read_8(&cuda->regs->b) | TACK | TIP);
425
426 cuda->xstate = cx_listen;
427 /* TODO: Match reply with request. */
428}
429
430static void cuda_packet_handle(cuda_t *cuda, uint8_t *data, size_t len)
431{
432 if (data[0] != PT_ADB)
433 return;
434 if (len < 2)
435 return;
436
437 adb_packet_handle(cuda, data + 2, len - 2, (data[1] & 0x40) != 0);
438}
439
440static void adb_packet_handle(cuda_t *cuda, uint8_t *data, size_t size,
441 bool autopoll)
442{
443 uint8_t dev_addr;
444 uint8_t reg_no;
445 uint16_t reg_val;
446 adb_dev_t *dev;
447 unsigned i;
448
449 dev_addr = data[0] >> 4;
450 reg_no = data[0] & 0x03;
451
452 if (size != 3) {
453 ddf_msg(LVL_WARN, "Unrecognized packet, size=%zu", size);
454 for (i = 0; i < size; ++i) {
455 ddf_msg(LVL_WARN, " 0x%02x", data[i]);
456 }
457 return;
458 }
459
460 if (reg_no != 0) {
461 ddf_msg(LVL_WARN, "Unrecognized packet, size=%zu", size);
462 for (i = 0; i < size; ++i) {
463 ddf_msg(LVL_WARN, " 0x%02x", data[i]);
464 }
465 return;
466 }
467
468 reg_val = ((uint16_t) data[1] << 8) | (uint16_t) data[2];
469
470 ddf_msg(LVL_DEBUG, "Received ADB packet for device address %d",
471 dev_addr);
472 dev = cuda->addr_dev[dev_addr];
473 if (dev == NULL)
474 return;
475
476 async_exch_t *exch = async_exchange_begin(dev->client_sess);
477 async_msg_1(exch, ADB_REG_NOTIF, reg_val);
478 async_exchange_end(exch);
479}
480
481static void cuda_autopoll_set(cuda_t *cuda, bool enable)
482{
483 cuda->snd_buf[0] = PT_CUDA;
484 cuda->snd_buf[1] = CPT_AUTOPOLL;
485 cuda->snd_buf[2] = enable ? 0x01 : 0x00;
486 cuda->snd_bytes = 3;
487 cuda->bidx = 0;
488
489 cuda_send_start(cuda);
490}
491
492static void cuda_send_start(cuda_t *cuda)
493{
494 assert(cuda->xstate == cx_listen);
495
496 if (cuda->snd_bytes == 0)
497 return;
498
499 /* Check for incoming data. */
500 if ((pio_read_8(&cuda->regs->b) & TREQ) == 0)
501 return;
502
503 pio_write_8(&cuda->regs->acr, pio_read_8(&cuda->regs->acr) | SR_OUT);
504 pio_write_8(&cuda->regs->sr, cuda->snd_buf[0]);
505 pio_write_8(&cuda->regs->b, pio_read_8(&cuda->regs->b) & ~TIP);
506
507 cuda->xstate = cx_send_start;
508}
509
510/** @}
511 */
Note: See TracBrowser for help on using the repository browser.