#include "openbios/config.h" #include "openbios/bindings.h" #include "adb.h" #include "cuda.h" #define DEBUG_CUDA #ifdef DEBUG_CUDA #define CUDA_DPRINTF(fmt, args...) \ do { printk("CUDA - %s: " fmt, __func__ , ##args); } while (0) #else #define CUDA_DPRINTF(fmt, args...) do { } while (0) #endif #define ADB_DPRINTF CUDA_DPRINTF /* VIA registers - spaced 0x200 bytes apart */ #define RS 0x200 /* skip between registers */ #define B 0 /* B-side data */ #define A RS /* A-side data */ #define DIRB (2*RS) /* B-side direction (1=output) */ #define DIRA (3*RS) /* A-side direction (1=output) */ #define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ #define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ #define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ #define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ #define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ #define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ #define SR (10*RS) /* Shift register */ #define ACR (11*RS) /* Auxiliary control register */ #define PCR (12*RS) /* Peripheral control register */ #define IFR (13*RS) /* Interrupt flag register */ #define IER (14*RS) /* Interrupt enable register */ #define ANH (15*RS) /* A-side data, no handshake */ /* Bits in B data register: all active low */ #define TREQ 0x08 /* Transfer request (input) */ #define TACK 0x10 /* Transfer acknowledge (output) */ #define TIP 0x20 /* Transfer in progress (output) */ /* Bits in ACR */ #define SR_CTRL 0x1c /* Shift register control bits */ #define SR_EXT 0x0c /* Shift on external clock */ #define SR_OUT 0x10 /* Shift out if 1 */ /* Bits in IFR and IER */ #define IER_SET 0x80 /* set bits in IER */ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ #define CUDA_BUF_SIZE 16 #define ADB_PACKET 0 #define CUDA_PACKET 1 static uint8_t cuda_readb (cuda_t *dev, int reg) { return *(volatile uint8_t *)(dev->base + reg); } static void cuda_writeb (cuda_t *dev, int reg, uint8_t val) { *(volatile uint8_t *)(dev->base + reg) = val; } static void cuda_wait_irq (cuda_t *dev) { int val; // CUDA_DPRINTF("\n"); for(;;) { val = cuda_readb(dev, IFR); cuda_writeb(dev, IFR, val & 0x7f); if (val & SR_INT) break; } } static int cuda_request (cuda_t *dev, uint8_t pkt_type, const uint8_t *buf, int buf_len, uint8_t *obuf) { int i, obuf_len, val; cuda_writeb(dev, ACR, cuda_readb(dev, ACR) | SR_OUT); cuda_writeb(dev, SR, pkt_type); cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP); if (buf) { //CUDA_DPRINTF("Send buf len: %d\n", buf_len); /* send 'buf' */ for(i = 0; i < buf_len; i++) { cuda_wait_irq(dev); cuda_writeb(dev, SR, buf[i]); cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK); } } cuda_wait_irq(dev); cuda_writeb(dev, ACR, cuda_readb(dev, ACR) & ~SR_OUT); cuda_readb(dev, SR); cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK); obuf_len = 0; if (obuf) { cuda_wait_irq(dev); cuda_readb(dev, SR); cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP); for(;;) { cuda_wait_irq(dev); val = cuda_readb(dev, SR); if (obuf_len < CUDA_BUF_SIZE) obuf[obuf_len++] = val; if (cuda_readb(dev, B) & TREQ) break; cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK); } cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK); cuda_wait_irq(dev); cuda_readb(dev, SR); } // CUDA_DPRINTF("Got len: %d\n", obuf_len); return obuf_len; } static int cuda_adb_req (void *host, const uint8_t *snd_buf, int len, uint8_t *rcv_buf) { uint8_t buffer[CUDA_BUF_SIZE], *pos; // CUDA_DPRINTF("len: %d %02x\n", len, snd_buf[0]); len = cuda_request(host, ADB_PACKET, snd_buf, len, buffer); if (len > 1 && buffer[0] == ADB_PACKET) { pos = buffer + 2; len -= 2; } else { pos = buffer + 1; len = -1; } memcpy(rcv_buf, pos, len); return len; } cuda_t *cuda_init (uint32_t base) { cuda_t *cuda; //CUDA_DPRINTF(" base=%08x\n", base); cuda = malloc(sizeof(cuda_t)); if (cuda == NULL) return NULL; cuda->base = base; cuda_writeb(cuda, B, cuda_readb(cuda, B) | TREQ | TIP); cuda->adb_bus = adb_bus_new(cuda, &cuda_adb_req); if (cuda->adb_bus == NULL) { free(cuda); return NULL; } adb_bus_init(cuda->adb_bus); return cuda; } adb_bus_t *adb_bus_new (void *host, int (*req)(void *host, const uint8_t *snd_buf, int len, uint8_t *rcv_buf)) { adb_bus_t *new; new = malloc(sizeof(adb_bus_t)); if (new == NULL) return NULL; new->host = host; new->req = req; return new; } /* Check and relocate all ADB devices as suggested in * * ADB_manager Apple documentation * */ int adb_bus_init (adb_bus_t *bus) { uint8_t buffer[ADB_BUF_SIZE]; uint8_t adb_addresses[16] = { 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, 0, }; adb_dev_t tmp_device, **cur; int address; int reloc = 0, next_free = 7; int keep; /* Reset the bus */ // ADB_DPRINTF("\n"); adb_reset(bus); cur = &bus->devices; memset(&tmp_device, 0, sizeof(adb_dev_t)); tmp_device.bus = bus; for (address = 1; address < 8 && adb_addresses[reloc] > 0;) { if (address == ADB_RES) { /* Reserved */ address++; continue; } //ADB_DPRINTF("Check device on ADB address %d\n", address); tmp_device.addr = address; switch (adb_reg_get(&tmp_device, 3, buffer)) { case 0: //ADB_DPRINTF("No device on ADB address %d\n", address); /* Register this address as free */ if (adb_addresses[next_free] != 0) adb_addresses[next_free++] = address; /* Check next ADB address */ address++; break; case 2: /* One device answered : * make it available and relocate it to a free address */ if (buffer[0] == ADB_CHADDR) { /* device self test failed */ ADB_DPRINTF("device on ADB address %d self-test failed " "%02x %02x %02x\n", address, buffer[0], buffer[1], buffer[2]); keep = 0; } else { //ADB_DPRINTF("device on ADB address %d self-test OK\n", // address); keep = 1; } ADB_DPRINTF("Relocate device on ADB address %d to %d (%d)\n", address, adb_addresses[reloc], reloc); buffer[0] = ((buffer[0] & 0x40) & ~0x90) | adb_addresses[reloc]; if (keep == 1) buffer[0] |= 0x20; buffer[1] = ADB_CHADDR_NOCOLL; if (adb_reg_set(&tmp_device, 3, buffer, 2) < 0) { ADB_DPRINTF("ADB device relocation failed\n"); return -1; } if (keep == 1) { *cur = malloc(sizeof(adb_dev_t)); if (*cur == NULL) { return -1; } (*cur)->type = address; (*cur)->bus = bus; (*cur)->addr = adb_addresses[reloc++]; /* Flush buffers */ adb_flush(*cur); switch ((*cur)->type) { case ADB_PROTECT: ADB_DPRINTF("Found one protected device\n"); break; case ADB_KEYBD: ADB_DPRINTF("Found one keyboard on address %d\n", address); adb_kbd_new(*cur); break; case ADB_MOUSE: ADB_DPRINTF("Found one mouse on address %d\n", address); //chardev_register(CHARDEV_MOUSE, &adb_mouse_ops, *cur); break; case ADB_ABS: ADB_DPRINTF("Found one absolute positioning device\n"); break; case ADB_MODEM: ADB_DPRINTF("Found one modem\n"); break; case ADB_RES: ADB_DPRINTF("Found one ADB res device\n"); break; case ADB_MISC: ADB_DPRINTF("Found one ADB misc device\n"); break; } cur = &((*cur)->next); } break; case 1: case 3 ... 7: /* SHOULD NOT HAPPEN : register 3 is always two bytes long */ ADB_DPRINTF("Invalid returned len for ADB register 3\n"); return -1; case -1: /* ADB ERROR */ ADB_DPRINTF("error gettting ADB register 3\n"); return -1; } } return 0; }