Import of openhackware-0.4.1
[openhackware.git] / src / char.c
blob4e74ac6affdacff919000c4f8211bc2cbb4a9ce3
1 /*
2 * <char.c>
4 * Open Hack'Ware BIOS character devices drivers.
5 *
6 * Copyright (c) 2004-2005 Jocelyn Mayer
8 * cuda driver: Copyright (c) 2004-2005 Fabrice Bellard
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License V2
12 * as published by the Free Software Foundation
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include "bios.h"
27 #include "adb.h"
29 //#define DEBUG_CHARDEV
30 //#define DEBUG_CUDA
31 //#define DEBUG_ADB
33 #ifdef DEBUG_CHARDEV
34 #define CHARDEV_DPRINTF(fmt, args...) \
35 do { dprintf("CHARDEV - %s: " fmt, __func__ , ##args); } while (0)
36 #else
37 #define CHARDEV_DPRINTF(fmt, args...) do { } while (0)
38 #endif
40 /* Generic character device API */
41 struct chardev_t {
42 chardev_t *next;
43 int type;
44 cops_t *ops;
45 void *private;
48 static chardev_t *char_devices;
50 int chardev_register (int type, cops_t *ops, void *private)
52 chardev_t *dev, **cur;
54 CHARDEV_DPRINTF("Register char device of type %d\n", type);
55 if (type > CHARDEV_LAST)
56 return -1;
57 dev = malloc(sizeof(chardev_t));
58 if (dev == NULL)
59 return -1;
60 dev->type = type;
61 dev->ops = ops;
62 dev->private = private;
63 for (cur = &char_devices; *cur != NULL; cur = &((*cur)->next))
64 continue;
65 *cur = dev;
67 return 0;
70 int chardev_open (chardev_t *dev)
72 if (dev->ops == NULL)
73 return -1;
74 if (dev->ops->open == NULL)
75 return 0;
77 return (*dev->ops->open)(dev->private);
80 int chardev_close (chardev_t *dev)
82 if (dev->ops == NULL)
83 return -1;
84 if (dev->ops->close == NULL)
85 return 0;
87 return (*dev->ops->close)(dev->private);
90 int chardev_read (chardev_t *dev, void *buffer, int maxlen)
92 unsigned char *p;
93 int len;
94 int c;
96 if (dev->ops == NULL || dev->ops->read == NULL)
97 return -1;
99 p = buffer;
100 for (len = 0; len < maxlen; len++) {
101 c = (*dev->ops->read)(dev->private);
102 if (c < 0)
103 break;
104 *p++ = c;
107 return len;
110 int chardev_write (chardev_t *dev, const void *buffer, int maxlen)
112 const unsigned char *p;
113 int len;
114 int c;
116 if (dev->ops == NULL || dev->ops->write == NULL)
117 return -1;
119 p = buffer;
120 for (len = 0; len < maxlen; len++) {
121 c = *p++;
122 if ((*dev->ops->write)(dev->private, c) < 0)
123 break;
126 return len;
129 int chardev_type (chardev_t *dev)
131 return dev->type;
134 /* Console driver */
135 static chardev_t *console_in_devs[17], *console_out_devs[17];
136 static int console_last_in;
138 int console_open (void)
140 chardev_t *cur;
141 int i, j, n, register_outd;
143 i = 0;
144 j = 0;
145 n = 0;
146 /* Check all character devices and register those which are usable
147 * as IO for the console
149 CHARDEV_DPRINTF("enter\n");
150 for (cur = char_devices; cur != NULL; cur = cur->next, n++) {
151 register_outd = 0;
152 switch (cur->type) {
153 case CHARDEV_SERIAL:
154 CHARDEV_DPRINTF("one serial port\n");
155 register_outd = 1;
156 /* No break here */
157 case CHARDEV_KBD:
158 CHARDEV_DPRINTF("one input port %d %d\n", n, i);
159 if (i < 16 && chardev_open(cur) == 0) {
160 console_in_devs[i++] = cur;
162 if (!register_outd)
163 break;
164 /* No break here */
165 case CHARDEV_DISPLAY:
166 CHARDEV_DPRINTF("one output port %d %d\n", n, j);
167 if (j < 16 && chardev_open(cur) == 0) {
168 console_out_devs[j++] = cur;
170 break;
171 default:
172 CHARDEV_DPRINTF("Skip device %d\n", n);
173 break;
177 return 0;
180 int console_read (void *buffer, int maxlen)
182 chardev_t *cur;
183 int i, in;
185 CHARDEV_DPRINTF("enter\n");
186 /* Get data from the first in device responding to us */
187 cur = console_in_devs[console_last_in];
188 for (i = console_last_in;;) {
189 CHARDEV_DPRINTF("read from device %d\n", i);
190 in = chardev_read(cur, buffer, maxlen);
191 if (in > 0) {
192 console_last_in = i;
193 #if 0
194 printf("Read %d chars '%c'...\n", in, *((char *)buffer));
195 #endif
196 return in;
198 cur = console_in_devs[++i];
199 if (cur == NULL) {
200 i = 0;
201 cur = console_in_devs[0];
203 if (i == console_last_in || cur == NULL)
204 break;
206 console_last_in = i;
207 CHARDEV_DPRINTF("out\n");
209 return 0;
212 int console_write (const void *buffer, int len)
214 chardev_t *cur;
215 int i, out, max;
217 /* Write data to all devices */
218 max = 0;
219 for (i = 0; i < 16; i++) {
220 cur = console_out_devs[i];
221 if (cur == NULL)
222 break;
223 out = chardev_write(cur, buffer, len);
224 if (out > max)
225 max = out;
228 return max;
231 void console_close (void)
233 chardev_t *cur;
234 int i;
236 for (i = 0; i < 16; i++) {
237 cur = console_out_devs[i];
238 if (cur == NULL)
239 break;
240 chardev_close(cur);
241 console_out_devs[i] = NULL;
245 /* PC serial port "driver" */
246 #define PC_SERIAL_LSR_OFFSET (5)
247 typedef struct pc_serial_t {
248 uint16_t base;
249 } pc_serial_t;
251 static int pc_serial_open (unused void *private)
253 return 0;
256 static int pc_serial_writeb (void *private, int data)
258 pc_serial_t *serial = private;
260 /* Wait for the FIFO to be ready to accept more chars.
261 * Note: this is completely buggy and would never work on real hardware,
262 * as the serial port (especialy the FIFO) has not been programmed
263 * anywhere before !
265 if (!(inb(serial->base + PC_SERIAL_LSR_OFFSET) & 0x20))
266 usleep(100);
267 outb(serial->base, data);
269 return 0;
272 static int pc_serial_readb (void *private)
274 pc_serial_t *serial = private;
276 if (!(inb(serial->base + PC_SERIAL_LSR_OFFSET) & 0x01))
277 return -1;
279 return inb(serial->base);
282 static int pc_serial_close (unused void *private)
284 return 0;
287 static cops_t pc_serial_ops = {
288 .open = &pc_serial_open,
289 .read = &pc_serial_readb,
290 .write = &pc_serial_writeb,
291 .close = &pc_serial_close,
294 /* XXX: debug stuff only ! (TOFIX with a generic debug console) */
295 int serial_write (const void *buffer, int len)
297 const char *p;
299 for (p = buffer; len > 0; len--) {
300 if (!(inb(0x3F8 + PC_SERIAL_LSR_OFFSET) & 0x20))
301 usleep(100);
302 outb(0x3F8, *p++);
305 return 0;
308 int pc_serial_register (uint16_t base)
310 pc_serial_t *serial;
312 serial = malloc(sizeof(pc_serial_t));
313 if (serial == NULL)
314 return -1;
315 serial->base = base;
316 /* XXX: TODO: initialize the serial port (FIFO, speed, ...) */
318 return chardev_register(CHARDEV_SERIAL, &pc_serial_ops, serial);
321 /* VGA console device */
322 static int vga_cons_open (unused void *private)
324 return 0;
327 static int vga_cons_writeb (unused void *private, int data)
329 vga_putchar(data);
331 return 0;
334 static int vga_cons_close (unused void *private)
336 return 0;
339 static cops_t vga_cons_ops = {
340 .open = &vga_cons_open,
341 .read = NULL,
342 .write = &vga_cons_writeb,
343 .close = &vga_cons_close,
346 int vga_console_register (void)
348 return chardev_register(CHARDEV_DISPLAY, &vga_cons_ops, NULL);
351 /* Macintosh via-cuda driver */
352 #ifdef DEBUG_CUDA
353 #define CUDA_DPRINTF(fmt, args...) \
354 do { dprintf("CUDA - %s: " fmt, __func__ , ##args); } while (0)
355 #else
356 #define CUDA_DPRINTF(fmt, args...) do { } while (0)
357 #endif
359 /* VIA registers - spaced 0x200 bytes apart */
360 #define RS 0x200 /* skip between registers */
361 #define B 0 /* B-side data */
362 #define A RS /* A-side data */
363 #define DIRB (2*RS) /* B-side direction (1=output) */
364 #define DIRA (3*RS) /* A-side direction (1=output) */
365 #define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
366 #define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
367 #define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
368 #define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
369 #define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
370 #define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
371 #define SR (10*RS) /* Shift register */
372 #define ACR (11*RS) /* Auxiliary control register */
373 #define PCR (12*RS) /* Peripheral control register */
374 #define IFR (13*RS) /* Interrupt flag register */
375 #define IER (14*RS) /* Interrupt enable register */
376 #define ANH (15*RS) /* A-side data, no handshake */
378 /* Bits in B data register: all active low */
379 #define TREQ 0x08 /* Transfer request (input) */
380 #define TACK 0x10 /* Transfer acknowledge (output) */
381 #define TIP 0x20 /* Transfer in progress (output) */
383 /* Bits in ACR */
384 #define SR_CTRL 0x1c /* Shift register control bits */
385 #define SR_EXT 0x0c /* Shift on external clock */
386 #define SR_OUT 0x10 /* Shift out if 1 */
388 /* Bits in IFR and IER */
389 #define IER_SET 0x80 /* set bits in IER */
390 #define IER_CLR 0 /* clear bits in IER */
391 #define SR_INT 0x04 /* Shift register full/empty */
393 #define CUDA_BUF_SIZE 16
395 #define ADB_PACKET 0
396 #define CUDA_PACKET 1
398 struct cuda_t {
399 uint32_t base;
400 adb_bus_t *adb_bus;
403 static uint8_t cuda_readb (cuda_t *dev, int reg)
405 return *(volatile uint8_t *)(dev->base + reg);
408 static void cuda_writeb (cuda_t *dev, int reg, uint8_t val)
410 *(volatile uint8_t *)(dev->base + reg) = val;
413 static void cuda_wait_irq (cuda_t *dev)
415 int val;
417 CUDA_DPRINTF("\n");
418 for(;;) {
419 val = cuda_readb(dev, IFR);
420 cuda_writeb(dev, IFR, val & 0x7f);
421 if (val & SR_INT)
422 break;
426 static int cuda_request (cuda_t *dev, uint8_t pkt_type, const uint8_t *buf,
427 int buf_len, uint8_t *obuf)
429 int i, obuf_len, val;
431 cuda_writeb(dev, ACR, cuda_readb(dev, ACR) | SR_OUT);
432 cuda_writeb(dev, SR, pkt_type);
433 cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP);
434 if (buf) {
435 CUDA_DPRINTF("Send buf len: %d\n", buf_len);
436 /* send 'buf' */
437 for(i = 0; i < buf_len; i++) {
438 cuda_wait_irq(dev);
439 cuda_writeb(dev, SR, buf[i]);
440 cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK);
443 cuda_wait_irq(dev);
444 cuda_writeb(dev, ACR, cuda_readb(dev, ACR) & ~SR_OUT);
445 cuda_readb(dev, SR);
446 cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK);
448 obuf_len = 0;
449 if (obuf) {
450 cuda_wait_irq(dev);
451 cuda_readb(dev, SR);
452 cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP);
453 for(;;) {
454 cuda_wait_irq(dev);
455 val = cuda_readb(dev, SR);
456 if (obuf_len < CUDA_BUF_SIZE)
457 obuf[obuf_len++] = val;
458 if (cuda_readb(dev, B) & TREQ)
459 break;
460 cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK);
462 cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK);
464 cuda_wait_irq(dev);
465 cuda_readb(dev, SR);
467 CUDA_DPRINTF("Got len: %d\n", obuf_len);
469 return obuf_len;
472 #if 0
473 void cuda_test(void)
475 int keycode;
476 printf("cuda test:\n");
477 cuda_init(0x80400000 + 0x16000);
478 for(;;) {
479 keycode = adb_read_key();
480 if (keycode >= 0)
481 printf("keycode=%x\n", keycode);
484 #endif
486 /* Cuda ADB glue */
487 static int cuda_adb_req (void *host, const uint8_t *snd_buf, int len,
488 uint8_t *rcv_buf)
490 uint8_t buffer[CUDA_BUF_SIZE], *pos;
492 CUDA_DPRINTF("len: %d %02x\n", len, snd_buf[0]);
493 len = cuda_request(host, ADB_PACKET, snd_buf, len, buffer);
494 if (len > 1 && buffer[0] == ADB_PACKET) {
495 pos = buffer + 2;
496 len -= 2;
497 } else {
498 pos = buffer + 1;
499 len = -1;
501 memcpy(rcv_buf, pos, len);
503 return len;
506 cuda_t *cuda_init (uint32_t base)
508 cuda_t *cuda;
510 CUDA_DPRINTF(" base=%08x\n", base);
511 cuda = malloc(sizeof(cuda_t));
512 if (cuda == NULL)
513 return NULL;
514 cuda->base = base;
515 cuda_writeb(cuda, B, cuda_readb(cuda, B) | TREQ | TIP);
516 #if 0
518 int len;
520 /* enable auto poll */
521 buf[0] = 0x01;
522 buf[1] = 1;
523 len = cuda_request(cuda, CUDA_PACKET, buf, 2, obuf);
524 if (len != 2 || obuf[0] != CUDA_PACKET || obuf[1] != 1) {
525 printf("cuda: invalid reply for auto poll request");
526 free(cuda);
527 return NULL;
530 #endif
531 cuda->adb_bus = adb_bus_new(cuda, &cuda_adb_req);
532 if (cuda->adb_bus == NULL) {
533 free(cuda);
534 return NULL;
536 adb_bus_init(cuda->adb_bus);
538 return cuda;
541 void cuda_reset (cuda_t *cuda)
543 adb_bus_reset(cuda->adb_bus);
546 /* ADB generic driver */
547 #ifdef DEBUG_ADB
548 #define ADB_DPRINTF(fmt, args...) \
549 do { dprintf("ADB - %s: " fmt, __func__ , ##args); } while (0)
550 #else
551 #define ADB_DPRINTF(fmt, args...) do { } while (0)
552 #endif
554 int adb_cmd (adb_dev_t *dev, uint8_t cmd, uint8_t reg,
555 uint8_t *buf, int len)
557 uint8_t adb_send[ADB_BUF_SIZE], adb_rcv[ADB_BUF_SIZE];
559 ADB_DPRINTF("cmd: %d reg: %d len: %d\n", cmd, reg, len);
560 if (dev->bus == NULL || dev->bus->req == NULL) {
561 ADB_DPRINTF("ERROR: invalid bus !\n");
562 bug();
564 /* Sanity checks */
565 if (cmd != ADB_LISTEN && len != 0) {
566 /* No buffer transmitted but for LISTEN command */
567 ADB_DPRINTF("in buffer for cmd %d\n", cmd);
568 return -1;
570 if (cmd == ADB_LISTEN && ((len < 2 || len > 8) || buf == NULL)) {
571 /* Need a buffer with a regular register size for LISTEN command */
572 ADB_DPRINTF("no/invalid buffer for ADB_LISTEN (%d)\n", len);
573 return -1;
575 if ((cmd == ADB_TALK || cmd == ADB_LISTEN) && reg > 3) {
576 /* Need a valid register number for LISTEN and TALK commands */
577 ADB_DPRINTF("invalid reg for TALK/LISTEN command (%d %d)\n", cmd, reg);
578 return -1;
580 switch (cmd) {
581 case ADB_SEND_RESET:
582 adb_send[0] = ADB_SEND_RESET;
583 break;
584 case ADB_FLUSH:
585 adb_send[0] = (dev->addr << 4) | ADB_FLUSH;
586 break;
587 case ADB_LISTEN:
588 memcpy(adb_send + 1, buf, len);
589 /* No break here */
590 case ADB_TALK:
591 adb_send[0] = (dev->addr << 4) | cmd | reg;
592 break;
594 memset(adb_rcv, 0, ADB_BUF_SIZE);
595 len = (*dev->bus->req)(dev->bus->host, adb_send, len + 1, adb_rcv);
596 #ifdef DEBUG_ADB
597 printf("%x %x %x %x\n", adb_rcv[0], adb_rcv[1], adb_rcv[2], adb_rcv[3]);
598 #endif
599 switch (len) {
600 case 0:
601 /* No data */
602 break;
603 case 2 ... 8:
604 /* Register transmitted */
605 if (buf != NULL)
606 memcpy(buf, adb_rcv, len);
607 break;
608 default:
609 /* Should never happen */
610 ADB_DPRINTF("Cmd %d returned %d bytes !\n", cmd, len);
611 return -1;
613 ADB_DPRINTF("retlen: %d\n", len);
615 return len;
618 void adb_bus_reset (adb_bus_t *bus)
620 adb_reset(bus);
623 adb_bus_t *adb_bus_new (void *host,
624 int (*req)(void *host, const uint8_t *snd_buf,
625 int len, uint8_t *rcv_buf))
627 adb_bus_t *new;
629 new = malloc(sizeof(adb_bus_t));
630 if (new == NULL)
631 return NULL;
632 new->host = host;
633 new->req = req;
635 return new;
638 /* ADB */
639 void *adb_kbd_new (void *private);
641 static int adb_mouse_open (void *private);
642 static int adb_mouse_close (void *private);
643 static int adb_mouse_read (void *private);
645 static cops_t adb_mouse_ops = {
646 &adb_mouse_open,
647 &adb_mouse_close,
648 &adb_mouse_read,
649 NULL,
652 /* Check and relocate all ADB devices as suggested in
653 * ADB_manager Apple documentation
655 int adb_bus_init (adb_bus_t *bus)
657 uint8_t buffer[ADB_BUF_SIZE];
658 uint8_t adb_addresses[16] =
659 { 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, 0, };
660 adb_dev_t tmp_device, **cur;
661 int address;
662 int reloc = 0, next_free = 7;
663 int keep;
665 /* Reset the bus */
666 ADB_DPRINTF("\n");
667 adb_reset(bus);
668 cur = &bus->devices;
669 memset(&tmp_device, 0, sizeof(adb_dev_t));
670 tmp_device.bus = bus;
671 for (address = 1; address < 8 && adb_addresses[reloc] > 0;) {
672 if (address == ADB_RES) {
673 /* Reserved */
674 address++;
675 continue;
677 ADB_DPRINTF("Check device on ADB address %d\n", address);
678 tmp_device.addr = address;
679 switch (adb_reg_get(&tmp_device, 3, buffer)) {
680 case 0:
681 ADB_DPRINTF("No device on ADB address %d\n", address);
682 /* Register this address as free */
683 if (adb_addresses[next_free] != 0)
684 adb_addresses[next_free++] = address;
685 /* Check next ADB address */
686 address++;
687 break;
688 case 2:
689 /* One device answered :
690 * make it available and relocate it to a free address
692 if (buffer[0] == ADB_CHADDR) {
693 /* device self test failed */
694 ADB_DPRINTF("device on ADB address %d self-test failed "
695 "%02x %02x %02x\n", address,
696 buffer[0], buffer[1], buffer[2]);
697 keep = 0;
698 } else {
699 ADB_DPRINTF("device on ADB address %d self-test OK\n",
700 address);
701 keep = 1;
703 ADB_DPRINTF("Relocate device on ADB address %d to %d (%d)\n",
704 address, adb_addresses[reloc], reloc);
705 buffer[0] = ((buffer[0] & 0x40) & ~0x90) | adb_addresses[reloc];
706 if (keep == 1)
707 buffer[0] |= 0x20;
708 buffer[1] = ADB_CHADDR_NOCOLL;
709 if (adb_reg_set(&tmp_device, 3, buffer, 2) < 0) {
710 ADB_DPRINTF("ADB device relocation failed\n");
711 return -1;
713 if (keep == 1) {
714 *cur = malloc(sizeof(adb_dev_t));
715 if (*cur == NULL) {
716 return -1;
718 (*cur)->type = address;
719 (*cur)->bus = bus;
720 (*cur)->addr = adb_addresses[reloc++];
721 /* Flush buffers */
722 adb_flush(*cur);
723 switch ((*cur)->type) {
724 case ADB_PROTECT:
725 ADB_DPRINTF("Found one protected device\n");
726 break;
727 case ADB_KEYBD:
728 ADB_DPRINTF("Found one keyboard\n");
729 adb_kbd_new(*cur);
730 break;
731 case ADB_MOUSE:
732 ADB_DPRINTF("Found one mouse\n");
733 chardev_register(CHARDEV_MOUSE, &adb_mouse_ops, *cur);
734 break;
735 case ADB_ABS:
736 ADB_DPRINTF("Found one absolute positioning device\n");
737 break;
738 case ADB_MODEM:
739 ADB_DPRINTF("Found one modem\n");
740 break;
741 case ADB_RES:
742 ADB_DPRINTF("Found one ADB res device\n");
743 break;
744 case ADB_MISC:
745 ADB_DPRINTF("Found one ADB misc device\n");
746 break;
748 cur = &((*cur)->next);
750 break;
751 case 1:
752 case 3 ... 7:
753 /* SHOULD NOT HAPPEN : register 3 is always two bytes long */
754 ADB_DPRINTF("Invalid returned len for ADB register 3\n");
755 return -1;
756 case -1:
757 /* ADB ERROR */
758 ADB_DPRINTF("error gettting ADB register 3\n");
759 return -1;
763 return 0;
766 /* ADB mouse chardev interface (TODO) */
767 static int adb_mouse_open (unused void *private)
769 return 0;
772 static int adb_mouse_close (unused void *private)
774 return 0;
777 static int adb_mouse_read (unused void *private)
779 return -1;