162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Device driver for the via ADB on (many) Mac II-class machines 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on the original ADB keyboard handler Copyright (c) 1997 Alan Cox 662306a36Sopenharmony_ci * Also derived from code Copyright (C) 1996 Paul Mackerras. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * With various updates provided over the years by Michael Schmitz, 962306a36Sopenharmony_ci * Guideo Koerber and others. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Rewrite for Unified ADB by Joshua M. Thompson (funaho@jurai.org) 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * 1999-08-02 (jmt) - Initial rewrite for Unified ADB. 1462306a36Sopenharmony_ci * 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org> 1562306a36Sopenharmony_ci * - Big overhaul, should actually work now. 1662306a36Sopenharmony_ci * 2006-12-31 Finn Thain - Another overhaul. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Suggested reading: 1962306a36Sopenharmony_ci * Inside Macintosh, ch. 5 ADB Manager 2062306a36Sopenharmony_ci * Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus 2162306a36Sopenharmony_ci * Rockwell R6522 VIA datasheet 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Apple's "ADB Analyzer" bus sniffer is invaluable: 2462306a36Sopenharmony_ci * ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/ 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci#include <linux/types.h> 2762306a36Sopenharmony_ci#include <linux/errno.h> 2862306a36Sopenharmony_ci#include <linux/kernel.h> 2962306a36Sopenharmony_ci#include <linux/delay.h> 3062306a36Sopenharmony_ci#include <linux/adb.h> 3162306a36Sopenharmony_ci#include <linux/interrupt.h> 3262306a36Sopenharmony_ci#include <linux/init.h> 3362306a36Sopenharmony_ci#include <asm/macintosh.h> 3462306a36Sopenharmony_ci#include <asm/macints.h> 3562306a36Sopenharmony_ci#include <asm/mac_via.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic volatile unsigned char *via; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* VIA registers - spaced 0x200 bytes apart */ 4062306a36Sopenharmony_ci#define RS 0x200 /* skip between registers */ 4162306a36Sopenharmony_ci#define B 0 /* B-side data */ 4262306a36Sopenharmony_ci#define A RS /* A-side data */ 4362306a36Sopenharmony_ci#define DIRB (2*RS) /* B-side direction (1=output) */ 4462306a36Sopenharmony_ci#define DIRA (3*RS) /* A-side direction (1=output) */ 4562306a36Sopenharmony_ci#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ 4662306a36Sopenharmony_ci#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ 4762306a36Sopenharmony_ci#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ 4862306a36Sopenharmony_ci#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ 4962306a36Sopenharmony_ci#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ 5062306a36Sopenharmony_ci#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ 5162306a36Sopenharmony_ci#define SR (10*RS) /* Shift register */ 5262306a36Sopenharmony_ci#define ACR (11*RS) /* Auxiliary control register */ 5362306a36Sopenharmony_ci#define PCR (12*RS) /* Peripheral control register */ 5462306a36Sopenharmony_ci#define IFR (13*RS) /* Interrupt flag register */ 5562306a36Sopenharmony_ci#define IER (14*RS) /* Interrupt enable register */ 5662306a36Sopenharmony_ci#define ANH (15*RS) /* A-side data, no handshake */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* Bits in B data register: all active low */ 5962306a36Sopenharmony_ci#define CTLR_IRQ 0x08 /* Controller rcv status (input) */ 6062306a36Sopenharmony_ci#define ST_MASK 0x30 /* mask for selecting ADB state bits */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Bits in ACR */ 6362306a36Sopenharmony_ci#define SR_CTRL 0x1c /* Shift register control bits */ 6462306a36Sopenharmony_ci#define SR_EXT 0x0c /* Shift on external clock */ 6562306a36Sopenharmony_ci#define SR_OUT 0x10 /* Shift out if 1 */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* Bits in IFR and IER */ 6862306a36Sopenharmony_ci#define IER_SET 0x80 /* set bits in IER */ 6962306a36Sopenharmony_ci#define IER_CLR 0 /* clear bits in IER */ 7062306a36Sopenharmony_ci#define SR_INT 0x04 /* Shift register full/empty */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* ADB transaction states according to GMHW */ 7362306a36Sopenharmony_ci#define ST_CMD 0x00 /* ADB state: command byte */ 7462306a36Sopenharmony_ci#define ST_EVEN 0x10 /* ADB state: even data byte */ 7562306a36Sopenharmony_ci#define ST_ODD 0x20 /* ADB state: odd data byte */ 7662306a36Sopenharmony_ci#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* ADB command byte structure */ 7962306a36Sopenharmony_ci#define ADDR_MASK 0xF0 8062306a36Sopenharmony_ci#define CMD_MASK 0x0F 8162306a36Sopenharmony_ci#define OP_MASK 0x0C 8262306a36Sopenharmony_ci#define TALK 0x0C 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int macii_init_via(void); 8562306a36Sopenharmony_cistatic void macii_start(void); 8662306a36Sopenharmony_cistatic irqreturn_t macii_interrupt(int irq, void *arg); 8762306a36Sopenharmony_cistatic void macii_queue_poll(void); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int macii_probe(void); 9062306a36Sopenharmony_cistatic int macii_init(void); 9162306a36Sopenharmony_cistatic int macii_send_request(struct adb_request *req, int sync); 9262306a36Sopenharmony_cistatic int macii_write(struct adb_request *req); 9362306a36Sopenharmony_cistatic int macii_autopoll(int devs); 9462306a36Sopenharmony_cistatic void macii_poll(void); 9562306a36Sopenharmony_cistatic int macii_reset_bus(void); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistruct adb_driver via_macii_driver = { 9862306a36Sopenharmony_ci .name = "Mac II", 9962306a36Sopenharmony_ci .probe = macii_probe, 10062306a36Sopenharmony_ci .init = macii_init, 10162306a36Sopenharmony_ci .send_request = macii_send_request, 10262306a36Sopenharmony_ci .autopoll = macii_autopoll, 10362306a36Sopenharmony_ci .poll = macii_poll, 10462306a36Sopenharmony_ci .reset_bus = macii_reset_bus, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic enum macii_state { 10862306a36Sopenharmony_ci idle, 10962306a36Sopenharmony_ci sending, 11062306a36Sopenharmony_ci reading, 11162306a36Sopenharmony_ci} macii_state; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic struct adb_request *current_req; /* first request struct in the queue */ 11462306a36Sopenharmony_cistatic struct adb_request *last_req; /* last request struct in the queue */ 11562306a36Sopenharmony_cistatic unsigned char reply_buf[16]; /* storage for autopolled replies */ 11662306a36Sopenharmony_cistatic unsigned char *reply_ptr; /* next byte in reply_buf or req->reply */ 11762306a36Sopenharmony_cistatic bool reading_reply; /* store reply in reply_buf else req->reply */ 11862306a36Sopenharmony_cistatic int data_index; /* index of the next byte to send from req->data */ 11962306a36Sopenharmony_cistatic int reply_len; /* number of bytes received in reply_buf or req->reply */ 12062306a36Sopenharmony_cistatic int status; /* VIA's ADB status bits captured upon interrupt */ 12162306a36Sopenharmony_cistatic bool bus_timeout; /* no data was sent by the device */ 12262306a36Sopenharmony_cistatic bool srq_asserted; /* have to poll for the device that asserted it */ 12362306a36Sopenharmony_cistatic u8 last_cmd; /* the most recent command byte transmitted */ 12462306a36Sopenharmony_cistatic u8 last_talk_cmd; /* the most recent Talk command byte transmitted */ 12562306a36Sopenharmony_cistatic u8 last_poll_cmd; /* the most recent Talk R0 command byte transmitted */ 12662306a36Sopenharmony_cistatic unsigned int autopoll_devs; /* bits set are device addresses to poll */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* Check for MacII style ADB */ 12962306a36Sopenharmony_cistatic int macii_probe(void) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci if (macintosh_config->adb_type != MAC_ADB_II) 13262306a36Sopenharmony_ci return -ENODEV; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci via = via1; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci pr_info("adb: Mac II ADB Driver v1.0 for Unified ADB\n"); 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* Initialize the driver */ 14162306a36Sopenharmony_cistatic int macii_init(void) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci unsigned long flags; 14462306a36Sopenharmony_ci int err; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci local_irq_save(flags); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci err = macii_init_via(); 14962306a36Sopenharmony_ci if (err) 15062306a36Sopenharmony_ci goto out; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB", 15362306a36Sopenharmony_ci macii_interrupt); 15462306a36Sopenharmony_ci if (err) 15562306a36Sopenharmony_ci goto out; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci macii_state = idle; 15862306a36Sopenharmony_ciout: 15962306a36Sopenharmony_ci local_irq_restore(flags); 16062306a36Sopenharmony_ci return err; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* initialize the hardware */ 16462306a36Sopenharmony_cistatic int macii_init_via(void) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci unsigned char x; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */ 16962306a36Sopenharmony_ci via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Set up state: idle */ 17262306a36Sopenharmony_ci via[B] |= ST_IDLE; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Shift register on input */ 17562306a36Sopenharmony_ci via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Wipe any pending data and int */ 17862306a36Sopenharmony_ci x = via[SR]; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* Send an ADB poll (Talk Register 0 command prepended to the request queue) */ 18462306a36Sopenharmony_cistatic void macii_queue_poll(void) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci static struct adb_request req; 18762306a36Sopenharmony_ci unsigned char poll_command; 18862306a36Sopenharmony_ci unsigned int poll_addr; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* This only polls devices in the autopoll list, which assumes that 19162306a36Sopenharmony_ci * unprobed devices never assert SRQ. That could happen if a device was 19262306a36Sopenharmony_ci * plugged in after the adb bus scan. Unplugging it again will resolve 19362306a36Sopenharmony_ci * the problem. This behaviour is similar to MacOS. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci if (!autopoll_devs) 19662306a36Sopenharmony_ci return; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* The device most recently polled may not be the best device to poll 19962306a36Sopenharmony_ci * right now. Some other device(s) may have signalled SRQ (the active 20062306a36Sopenharmony_ci * device won't do that). Or the autopoll list may have been changed. 20162306a36Sopenharmony_ci * Try polling the next higher address. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci poll_addr = (last_poll_cmd & ADDR_MASK) >> 4; 20462306a36Sopenharmony_ci if ((srq_asserted && last_cmd == last_poll_cmd) || 20562306a36Sopenharmony_ci !(autopoll_devs & (1 << poll_addr))) { 20662306a36Sopenharmony_ci unsigned int higher_devs; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci higher_devs = autopoll_devs & -(1 << (poll_addr + 1)); 20962306a36Sopenharmony_ci poll_addr = ffs(higher_devs ? higher_devs : autopoll_devs) - 1; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Send a Talk Register 0 command */ 21362306a36Sopenharmony_ci poll_command = ADB_READREG(poll_addr, 0); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* No need to repeat this Talk command. The transceiver will do that 21662306a36Sopenharmony_ci * as long as it is idle. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci if (poll_command == last_cmd) 21962306a36Sopenharmony_ci return; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci adb_request(&req, NULL, ADBREQ_NOSEND, 1, poll_command); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci req.sent = 0; 22462306a36Sopenharmony_ci req.complete = 0; 22562306a36Sopenharmony_ci req.reply_len = 0; 22662306a36Sopenharmony_ci req.next = current_req; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (WARN_ON(current_req)) { 22962306a36Sopenharmony_ci current_req = &req; 23062306a36Sopenharmony_ci } else { 23162306a36Sopenharmony_ci current_req = &req; 23262306a36Sopenharmony_ci last_req = &req; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* Send an ADB request; if sync, poll out the reply 'till it's done */ 23762306a36Sopenharmony_cistatic int macii_send_request(struct adb_request *req, int sync) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int err; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci err = macii_write(req); 24262306a36Sopenharmony_ci if (err) 24362306a36Sopenharmony_ci return err; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (sync) 24662306a36Sopenharmony_ci while (!req->complete) 24762306a36Sopenharmony_ci macii_poll(); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* Send an ADB request (append to request queue) */ 25362306a36Sopenharmony_cistatic int macii_write(struct adb_request *req) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci unsigned long flags; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) { 25862306a36Sopenharmony_ci req->complete = 1; 25962306a36Sopenharmony_ci return -EINVAL; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci req->next = NULL; 26362306a36Sopenharmony_ci req->sent = 0; 26462306a36Sopenharmony_ci req->complete = 0; 26562306a36Sopenharmony_ci req->reply_len = 0; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci local_irq_save(flags); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (current_req != NULL) { 27062306a36Sopenharmony_ci last_req->next = req; 27162306a36Sopenharmony_ci last_req = req; 27262306a36Sopenharmony_ci } else { 27362306a36Sopenharmony_ci current_req = req; 27462306a36Sopenharmony_ci last_req = req; 27562306a36Sopenharmony_ci if (macii_state == idle) 27662306a36Sopenharmony_ci macii_start(); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci local_irq_restore(flags); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* Start auto-polling */ 28562306a36Sopenharmony_cistatic int macii_autopoll(int devs) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci unsigned long flags; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci local_irq_save(flags); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* bit 1 == device 1, and so on. */ 29262306a36Sopenharmony_ci autopoll_devs = (unsigned int)devs & 0xFFFE; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (!current_req) { 29562306a36Sopenharmony_ci macii_queue_poll(); 29662306a36Sopenharmony_ci if (current_req && macii_state == idle) 29762306a36Sopenharmony_ci macii_start(); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci local_irq_restore(flags); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* Prod the chip without interrupts */ 30662306a36Sopenharmony_cistatic void macii_poll(void) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci macii_interrupt(0, NULL); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* Reset the bus */ 31262306a36Sopenharmony_cistatic int macii_reset_bus(void) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct adb_request req; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Command = 0, Address = ignored */ 31762306a36Sopenharmony_ci adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET); 31862306a36Sopenharmony_ci macii_send_request(&req, 1); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Don't want any more requests during the Global Reset low time. */ 32162306a36Sopenharmony_ci udelay(3000); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/* Start sending ADB packet */ 32762306a36Sopenharmony_cistatic void macii_start(void) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct adb_request *req; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci req = current_req; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Now send it. Be careful though, that first byte of the request 33462306a36Sopenharmony_ci * is actually ADB_PACKET; the real data begins at index 1! 33562306a36Sopenharmony_ci * And req->nbytes is the number of bytes of real data plus one. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Output mode */ 33962306a36Sopenharmony_ci via[ACR] |= SR_OUT; 34062306a36Sopenharmony_ci /* Load data */ 34162306a36Sopenharmony_ci via[SR] = req->data[1]; 34262306a36Sopenharmony_ci /* set ADB state to 'command' */ 34362306a36Sopenharmony_ci via[B] = (via[B] & ~ST_MASK) | ST_CMD; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci macii_state = sending; 34662306a36Sopenharmony_ci data_index = 2; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci bus_timeout = false; 34962306a36Sopenharmony_ci srq_asserted = false; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/* 35362306a36Sopenharmony_ci * The notorious ADB interrupt handler - does all of the protocol handling. 35462306a36Sopenharmony_ci * Relies on the ADB controller sending and receiving data, thereby 35562306a36Sopenharmony_ci * generating shift register interrupts (SR_INT) for us. This means there has 35662306a36Sopenharmony_ci * to be activity on the ADB bus. The chip will poll to achieve this. 35762306a36Sopenharmony_ci * 35862306a36Sopenharmony_ci * The VIA Port B output signalling works as follows. After the ADB transceiver 35962306a36Sopenharmony_ci * sees a transition on the PB4 and PB5 lines it will crank over the VIA shift 36062306a36Sopenharmony_ci * register which eventually raises the SR_INT interrupt. The PB4/PB5 outputs 36162306a36Sopenharmony_ci * are toggled with each byte as the ADB transaction progresses. 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * Request with no reply expected (and empty transceiver buffer): 36462306a36Sopenharmony_ci * CMD -> IDLE 36562306a36Sopenharmony_ci * Request with expected reply packet (or with buffered autopoll packet): 36662306a36Sopenharmony_ci * CMD -> EVEN -> ODD -> EVEN -> ... -> IDLE 36762306a36Sopenharmony_ci * Unsolicited packet: 36862306a36Sopenharmony_ci * IDLE -> EVEN -> ODD -> EVEN -> ... -> IDLE 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_cistatic irqreturn_t macii_interrupt(int irq, void *arg) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci int x; 37362306a36Sopenharmony_ci struct adb_request *req; 37462306a36Sopenharmony_ci unsigned long flags; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci local_irq_save(flags); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!arg) { 37962306a36Sopenharmony_ci /* Clear the SR IRQ flag when polling. */ 38062306a36Sopenharmony_ci if (via[IFR] & SR_INT) 38162306a36Sopenharmony_ci via[IFR] = SR_INT; 38262306a36Sopenharmony_ci else { 38362306a36Sopenharmony_ci local_irq_restore(flags); 38462306a36Sopenharmony_ci return IRQ_NONE; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci status = via[B] & (ST_MASK | CTLR_IRQ); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci switch (macii_state) { 39162306a36Sopenharmony_ci case idle: 39262306a36Sopenharmony_ci WARN_ON((status & ST_MASK) != ST_IDLE); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci reply_ptr = reply_buf; 39562306a36Sopenharmony_ci reading_reply = false; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci bus_timeout = false; 39862306a36Sopenharmony_ci srq_asserted = false; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci x = via[SR]; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (!(status & CTLR_IRQ)) { 40362306a36Sopenharmony_ci /* /CTLR_IRQ asserted in idle state means we must 40462306a36Sopenharmony_ci * read an autopoll reply from the transceiver buffer. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci macii_state = reading; 40762306a36Sopenharmony_ci *reply_ptr = x; 40862306a36Sopenharmony_ci reply_len = 1; 40962306a36Sopenharmony_ci } else { 41062306a36Sopenharmony_ci /* bus timeout */ 41162306a36Sopenharmony_ci reply_len = 0; 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* set ADB state = even for first data byte */ 41662306a36Sopenharmony_ci via[B] = (via[B] & ~ST_MASK) | ST_EVEN; 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci case sending: 42062306a36Sopenharmony_ci req = current_req; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (status == (ST_CMD | CTLR_IRQ)) { 42362306a36Sopenharmony_ci /* /CTLR_IRQ de-asserted after the command byte means 42462306a36Sopenharmony_ci * the host can continue with the transaction. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Store command byte */ 42862306a36Sopenharmony_ci last_cmd = req->data[1]; 42962306a36Sopenharmony_ci if ((last_cmd & OP_MASK) == TALK) { 43062306a36Sopenharmony_ci last_talk_cmd = last_cmd; 43162306a36Sopenharmony_ci if ((last_cmd & CMD_MASK) == ADB_READREG(0, 0)) 43262306a36Sopenharmony_ci last_poll_cmd = last_cmd; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (status == ST_CMD) { 43762306a36Sopenharmony_ci /* /CTLR_IRQ asserted after the command byte means we 43862306a36Sopenharmony_ci * must read an autopoll reply. The first byte was 43962306a36Sopenharmony_ci * lost because the shift register was an output. 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_ci macii_state = reading; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci reading_reply = false; 44462306a36Sopenharmony_ci reply_ptr = reply_buf; 44562306a36Sopenharmony_ci *reply_ptr = last_talk_cmd; 44662306a36Sopenharmony_ci reply_len = 1; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* reset to shift in */ 44962306a36Sopenharmony_ci via[ACR] &= ~SR_OUT; 45062306a36Sopenharmony_ci x = via[SR]; 45162306a36Sopenharmony_ci } else if (data_index >= req->nbytes) { 45262306a36Sopenharmony_ci req->sent = 1; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (req->reply_expected) { 45562306a36Sopenharmony_ci macii_state = reading; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci reading_reply = true; 45862306a36Sopenharmony_ci reply_ptr = req->reply; 45962306a36Sopenharmony_ci *reply_ptr = req->data[1]; 46062306a36Sopenharmony_ci reply_len = 1; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci via[ACR] &= ~SR_OUT; 46362306a36Sopenharmony_ci x = via[SR]; 46462306a36Sopenharmony_ci } else if ((req->data[1] & OP_MASK) == TALK) { 46562306a36Sopenharmony_ci macii_state = reading; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci reading_reply = false; 46862306a36Sopenharmony_ci reply_ptr = reply_buf; 46962306a36Sopenharmony_ci *reply_ptr = req->data[1]; 47062306a36Sopenharmony_ci reply_len = 1; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci via[ACR] &= ~SR_OUT; 47362306a36Sopenharmony_ci x = via[SR]; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci req->complete = 1; 47662306a36Sopenharmony_ci current_req = req->next; 47762306a36Sopenharmony_ci if (req->done) 47862306a36Sopenharmony_ci (*req->done)(req); 47962306a36Sopenharmony_ci } else { 48062306a36Sopenharmony_ci macii_state = idle; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci req->complete = 1; 48362306a36Sopenharmony_ci current_req = req->next; 48462306a36Sopenharmony_ci if (req->done) 48562306a36Sopenharmony_ci (*req->done)(req); 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci } else { 48962306a36Sopenharmony_ci via[SR] = req->data[data_index++]; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if ((via[B] & ST_MASK) == ST_CMD) { 49362306a36Sopenharmony_ci /* just sent the command byte, set to EVEN */ 49462306a36Sopenharmony_ci via[B] = (via[B] & ~ST_MASK) | ST_EVEN; 49562306a36Sopenharmony_ci } else { 49662306a36Sopenharmony_ci /* invert state bits, toggle ODD/EVEN */ 49762306a36Sopenharmony_ci via[B] ^= ST_MASK; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci case reading: 50262306a36Sopenharmony_ci x = via[SR]; 50362306a36Sopenharmony_ci WARN_ON((status & ST_MASK) == ST_CMD || 50462306a36Sopenharmony_ci (status & ST_MASK) == ST_IDLE); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (!(status & CTLR_IRQ)) { 50762306a36Sopenharmony_ci if (status == ST_EVEN && reply_len == 1) { 50862306a36Sopenharmony_ci bus_timeout = true; 50962306a36Sopenharmony_ci } else if (status == ST_ODD && reply_len == 2) { 51062306a36Sopenharmony_ci srq_asserted = true; 51162306a36Sopenharmony_ci } else { 51262306a36Sopenharmony_ci macii_state = idle; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (bus_timeout) 51562306a36Sopenharmony_ci reply_len = 0; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (reading_reply) { 51862306a36Sopenharmony_ci struct adb_request *req = current_req; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci req->reply_len = reply_len; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci req->complete = 1; 52362306a36Sopenharmony_ci current_req = req->next; 52462306a36Sopenharmony_ci if (req->done) 52562306a36Sopenharmony_ci (*req->done)(req); 52662306a36Sopenharmony_ci } else if (reply_len && autopoll_devs && 52762306a36Sopenharmony_ci reply_buf[0] == last_poll_cmd) { 52862306a36Sopenharmony_ci adb_input(reply_buf, reply_len, 1); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci break; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (reply_len < ARRAY_SIZE(reply_buf)) { 53562306a36Sopenharmony_ci reply_ptr++; 53662306a36Sopenharmony_ci *reply_ptr = x; 53762306a36Sopenharmony_ci reply_len++; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* invert state bits, toggle ODD/EVEN */ 54162306a36Sopenharmony_ci via[B] ^= ST_MASK; 54262306a36Sopenharmony_ci break; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci default: 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (macii_state == idle) { 54962306a36Sopenharmony_ci if (!current_req) 55062306a36Sopenharmony_ci macii_queue_poll(); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (current_req) 55362306a36Sopenharmony_ci macii_start(); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (macii_state == idle) { 55662306a36Sopenharmony_ci via[ACR] &= ~SR_OUT; 55762306a36Sopenharmony_ci x = via[SR]; 55862306a36Sopenharmony_ci via[B] = (via[B] & ~ST_MASK) | ST_IDLE; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci local_irq_restore(flags); 56362306a36Sopenharmony_ci return IRQ_HANDLED; 56462306a36Sopenharmony_ci} 565