📄 via-macii.c
字号:
/* * Device driver for the via ADB on (many) Mac II-class machines * * Based on the original ADB keyboard handler Copyright (c) 1997 Alan Cox * Also derived from code Copyright (C) 1996 Paul Mackerras. * * With various updates provided over the years by Michael Schmitz, * Guideo Koerber and others. * * Rewrite for Unified ADB by Joshua M. Thompson (funaho@jurai.org) * * 1999-08-02 (jmt) - Initial rewrite for Unified ADB. */ #include <stdarg.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/adb.h>#include <asm/macintosh.h>#include <asm/macints.h>#include <asm/machw.h>#include <asm/mac_via.h>#include <asm/io.h>#include <asm/system.h>#include <asm/init.h>static volatile unsigned char *via;/* 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) */#define ST_MASK 0x30 /* mask for selecting ADB state bits *//* 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 SR_DATA 0x08 /* Shift register data */#define SR_CLOCK 0x10 /* Shift register clock *//* ADB transaction states according to GMHW */#define ST_CMD 0x00 /* ADB state: command byte */#define ST_EVEN 0x10 /* ADB state: even data byte */#define ST_ODD 0x20 /* ADB state: odd data byte */#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */static int macii_init_via(void);static void macii_start(void);static void macii_interrupt(int irq, void *arg, struct pt_regs *regs);static void macii_retransmit(int);static void macii_queue_poll(void);static int macii_probe(void);static int macii_init(void);static int macii_send_request(struct adb_request *req, int sync);static int macii_write(struct adb_request *req);static int macii_autopoll(int devs);static void macii_poll(void);static int macii_reset_bus(void);struct adb_driver via_macii_driver = { "Mac II", macii_probe, macii_init, macii_send_request, macii_autopoll, macii_poll, macii_reset_bus};static enum macii_state { idle, sent_first_byte, sending, reading, read_done, awaiting_reply} macii_state;static int need_poll = 0;static int command_byte = 0;static int last_reply = 0;static int last_active = 0;static struct adb_request *current_req;static struct adb_request *last_req;static struct adb_request *retry_req;static unsigned char reply_buf[16];static unsigned char *reply_ptr;static int reply_len;static int reading_reply;static int data_index;static int first_byte;static int prefix_len;static int status = ST_IDLE|TREQ;static int last_status;static int driver_running = 0;/* debug level 10 required for ADB logging (should be && debug_adb, ideally) *//* Check for MacII style ADB */static int macii_probe(void){ if (macintosh_config->adb_type != MAC_ADB_II) return -ENODEV; via = via1; printk("adb: Mac II ADB Driver v0.4 for Unified ADB\n"); return 0;}/* Initialize the driver */int macii_init(void){ unsigned long flags; int err; save_flags(flags); cli(); err = macii_init_via(); if (err) return err; err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB", macii_interrupt); if (err) return err; macii_state = idle; restore_flags(flags); return 0;}/* initialize the hardware */ static int macii_init_via(void){ unsigned char x; /* Set the lines up. We want TREQ as input TACK|TIP as output */ via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; /* Set up state: idle */ via[B] |= ST_IDLE; last_status = via[B] & (ST_MASK|TREQ); /* Shift register on input */ via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; /* Wipe any pending data and int */ x = via[SR]; return 0;}/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */static void macii_queue_poll(void){ static int device = 0; static int in_poll=0; static struct adb_request req; unsigned long flags; if (in_poll) printk("macii_queue_poll: double poll!\n"); in_poll++; if (++device > 15) device = 1; adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, ADB_READREG(device, 0)); save_flags(flags); cli(); req.next = current_req; current_req = &req; restore_flags(flags); macii_start(); in_poll--;}/* Send an ADB retransmit (Talk, appended to the request queue) */static void macii_retransmit(int device){ static int in_retransmit = 0; static struct adb_request rt; unsigned long flags; if (in_retransmit) printk("macii_retransmit: double retransmit!\n"); in_retransmit++; adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, ADB_READREG(device, 0)); save_flags(flags); cli(); if (current_req != NULL) { last_req->next = &rt; last_req = &rt; } else { current_req = &rt; last_req = &rt; } if (macii_state == idle) macii_start(); restore_flags(flags); in_retransmit--;}/* Send an ADB request; if sync, poll out the reply 'till it's done */static int macii_send_request(struct adb_request *req, int sync){ int i; i = macii_write(req); if (i) return i; if (sync) { while (!req->complete) macii_poll(); } return 0;}/* Send an ADB request */static int macii_write(struct adb_request *req){ unsigned long flags; if (req->nbytes < 2 || req->data[0] != ADB_PACKET) { req->complete = 1; return -EINVAL; } req->next = 0; req->sent = 0; req->complete = 0; req->reply_len = 0; save_flags(flags); cli(); if (current_req != NULL) { last_req->next = req; last_req = req; } else { current_req = req; last_req = req; if (macii_state == idle) macii_start(); } restore_flags(flags); return 0;}/* Start auto-polling */static int macii_autopoll(int devs){ /* Just ping a random default address */ if (!(current_req || retry_req)) macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3); return 0;}/* Prod the chip without interrupts */static void macii_poll(void){ unsigned long flags; save_flags(flags); cli(); if (via[IFR] & SR_INT) macii_interrupt(0, 0, 0); restore_flags(flags);}/* Reset the bus */static int macii_reset_bus(void){ static struct adb_request req; /* Command = 0, Address = ignored */ adb_request(&req, NULL, 0, 1, ADB_BUSRESET); return 0;}/* Start sending ADB packet */static void macii_start(void){ unsigned long flags; struct adb_request *req; req = current_req; if (!req) return; /* assert macii_state == idle */ if (macii_state != idle) { printk("macii_start: called while driver busy (%p %x %x)!\n", req, macii_state, (uint) via1[B] & (ST_MASK|TREQ)); return; } save_flags(flags); cli(); /* * IRQ signaled ?? (means ADB controller wants to send, or might * be end of packet if we were reading) */ if ((via[B] & TREQ) == 0) { /* * FIXME - we need to restart this on a timer * or a collision at boot hangs us. * Never set macii_state to idle here, or macii_start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -