Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

macintosh/adb-iop: Send correct poll command

The behaviour of the IOP firmware is not well documented but we do know
that IOP message reply data can be used to issue new ADB commands.
Use the message reply to better control autopoll behaviour by sending
a Talk Register 0 command after every ADB response, not unlike the
algorithm in the via-macii driver. This poll command is addressed to
that device which last received a Talk command (explicit or otherwise).

Cc: Joshua Thompson <funaho@jurai.org>
Fixes: 32226e817043 ("macintosh/adb-iop: Implement idle -> sending state transition")
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Link: https://lore.kernel.org/r/58bba4310da4c29b068345a4b36af8a531397ff7.1605847196.git.fthain@telegraphics.com.au
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>

authored by

Finn Thain and committed by
Geert Uytterhoeven
10199e90 2c9cfbad

+29 -9
+29 -9
drivers/macintosh/adb-iop.c
··· 25 25 static struct adb_request *current_req; 26 26 static struct adb_request *last_req; 27 27 static unsigned int autopoll_devs; 28 + static u8 autopoll_addr; 28 29 29 30 static enum adb_iop_state { 30 31 idle, ··· 41 40 static int adb_iop_autopoll(int); 42 41 static void adb_iop_poll(void); 43 42 static int adb_iop_reset_bus(void); 43 + 44 + /* ADB command byte structure */ 45 + #define ADDR_MASK 0xF0 46 + #define OP_MASK 0x0C 47 + #define TALK 0x0C 44 48 45 49 struct adb_driver adb_iop_driver = { 46 50 .name = "ISM IOP", ··· 100 94 static void adb_iop_listen(struct iop_msg *msg) 101 95 { 102 96 struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message; 97 + u8 addr = (amsg->cmd & ADDR_MASK) >> 4; 98 + u8 op = amsg->cmd & OP_MASK; 103 99 unsigned long flags; 104 100 bool req_done = false; 105 101 106 102 local_irq_save(flags); 107 103 108 - /* Handle a timeout. Timeout packets seem to occur even after 109 - * we've gotten a valid reply to a TALK, presumably because of 110 - * autopolling. 104 + /* Responses to Talk commands may be unsolicited as they are 105 + * produced when the IOP polls devices. They are mostly timeouts. 111 106 */ 107 + if (op == TALK && ((1 << addr) & autopoll_devs)) 108 + autopoll_addr = addr; 112 109 113 - if (amsg->flags & ADB_IOP_EXPLICIT) { 110 + switch (amsg->flags & (ADB_IOP_EXPLICIT | 111 + ADB_IOP_AUTOPOLL | 112 + ADB_IOP_TIMEOUT)) { 113 + case ADB_IOP_EXPLICIT: 114 + case ADB_IOP_EXPLICIT | ADB_IOP_TIMEOUT: 114 115 if (adb_iop_state == awaiting_reply) { 115 116 struct adb_request *req = current_req; 116 117 ··· 128 115 129 116 req_done = true; 130 117 } 131 - } else if (!(amsg->flags & ADB_IOP_TIMEOUT)) { 132 - adb_input(&amsg->cmd, amsg->count + 1, 133 - amsg->flags & ADB_IOP_AUTOPOLL); 118 + break; 119 + case ADB_IOP_AUTOPOLL: 120 + if (((1 << addr) & autopoll_devs) && 121 + amsg->cmd == ADB_READREG(addr, 0)) 122 + adb_input(&amsg->cmd, amsg->count + 1, 1); 123 + break; 134 124 } 135 - 136 - msg->reply[0] = autopoll_devs ? ADB_IOP_AUTOPOLL : 0; 125 + msg->reply[0] = autopoll_addr ? ADB_IOP_AUTOPOLL : 0; 126 + msg->reply[1] = 0; 127 + msg->reply[2] = autopoll_addr ? ADB_READREG(autopoll_addr, 0) : 0; 137 128 iop_complete_message(msg); 138 129 139 130 if (req_done) ··· 250 233 struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message; 251 234 252 235 autopoll_devs = (amsg->data[1] << 8) | amsg->data[0]; 236 + if (autopoll_devs & (1 << autopoll_addr)) 237 + return; 238 + autopoll_addr = autopoll_devs ? (ffs(autopoll_devs) - 1) : 0; 253 239 } 254 240 255 241 static int adb_iop_autopoll(int devs)