macintosh/adb-iop: Implement SRQ autopolling
authorFinn Thain <fthain@telegraphics.com.au>
Sat, 30 May 2020 23:17:03 +0000 (09:17 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Sun, 26 Jul 2020 13:34:24 +0000 (23:34 +1000)
The adb_driver.autopoll method is needed during ADB bus scan and device
address assignment. Implement this method so that the IOP's list of
device addresses can be updated. When the list is empty, disable SRQ
autopolling.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Tested-by: Stan Johnson <userm57@yahoo.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/0fb7fdcd99d7820bb27faf1f27f7f6f1923914ef.1590880623.git.fthain@telegraphics.com.au
arch/m68k/include/asm/adb_iop.h
drivers/macintosh/adb-iop.c

index 195d7fb..6aecd02 100644 (file)
@@ -29,6 +29,7 @@
 
 #define ADB_IOP_EXPLICIT       0x80    /* nonzero if explicit command */
 #define ADB_IOP_AUTOPOLL       0x40    /* auto/SRQ polling enabled    */
+#define ADB_IOP_SET_AUTOPOLL   0x20    /* set autopoll device list    */
 #define ADB_IOP_SRQ            0x04    /* SRQ detected                */
 #define ADB_IOP_TIMEOUT                0x02    /* nonzero if timeout          */
 
index 8594e4f..f3d1a46 100644 (file)
@@ -7,10 +7,6 @@
  * 1999-07-01 (jmt) - First implementation for new driver architecture.
  *
  * 1999-07-31 (jmt) - First working version.
- *
- * TODO:
- *
- * o Implement SRQ handling.
  */
 
 #include <linux/types.h>
@@ -28,6 +24,7 @@
 
 static struct adb_request *current_req;
 static struct adb_request *last_req;
+static unsigned int autopoll_devs;
 
 static enum adb_iop_state {
        idle,
@@ -123,7 +120,7 @@ static void adb_iop_listen(struct iop_msg *msg)
                          amsg->flags & ADB_IOP_AUTOPOLL);
        }
 
-       msg->reply[0] = ADB_IOP_AUTOPOLL;
+       msg->reply[0] = autopoll_devs ? ADB_IOP_AUTOPOLL : 0;
        iop_complete_message(msg);
 
        if (req_done)
@@ -231,9 +228,32 @@ static int adb_iop_write(struct adb_request *req)
        return 0;
 }
 
+static void adb_iop_set_ap_complete(struct iop_msg *msg)
+{
+       struct adb_iopmsg *amsg = (struct adb_iopmsg *)msg->message;
+
+       autopoll_devs = (amsg->data[1] << 8) | amsg->data[0];
+}
+
 static int adb_iop_autopoll(int devs)
 {
-       /* TODO: how do we enable/disable autopoll? */
+       struct adb_iopmsg amsg;
+       unsigned long flags;
+       unsigned int mask = (unsigned int)devs & 0xFFFE;
+
+       local_irq_save(flags);
+
+       amsg.flags = ADB_IOP_SET_AUTOPOLL | (mask ? ADB_IOP_AUTOPOLL : 0);
+       amsg.count = 2;
+       amsg.cmd = 0;
+       amsg.data[0] = mask & 0xFF;
+       amsg.data[1] = (mask >> 8) & 0xFF;
+
+       iop_send_message(ADB_IOP, ADB_CHAN, NULL, sizeof(amsg), (__u8 *)&amsg,
+                        adb_iop_set_ap_complete);
+
+       local_irq_restore(flags);
+
        return 0;
 }