summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/adb/adb.h2
-rw-r--r--sys/dev/adb/adb_bus.c71
-rw-r--r--sys/dev/adb/adb_kbd.c14
-rw-r--r--sys/dev/adb/adb_mouse.c2
-rw-r--r--sys/dev/adb/adbvar.h1
-rw-r--r--sys/powerpc/powermac/cuda.c229
-rw-r--r--sys/powerpc/powermac/cudavar.h36
7 files changed, 214 insertions, 141 deletions
diff --git a/sys/dev/adb/adb.h b/sys/dev/adb/adb.h
index 8d68a87..10c3db2 100644
--- a/sys/dev/adb/adb.h
+++ b/sys/dev/adb/adb.h
@@ -68,7 +68,7 @@ uint8_t adb_get_device_type(device_t dev);
uint8_t adb_get_device_handler(device_t dev);
uint8_t adb_set_device_handler(device_t dev, uint8_t newhandler);
-uint8_t adb_read_register(device_t dev, u_char reg, size_t *len, void *data);
+size_t adb_read_register(device_t dev, u_char reg, void *data);
/* Bits for implementing ADB host bus adapters */
extern devclass_t adb_devclass;
diff --git a/sys/dev/adb/adb_bus.c b/sys/dev/adb/adb_bus.c
index 9c00144..faab048 100644
--- a/sys/dev/adb/adb_bus.c
+++ b/sys/dev/adb/adb_bus.c
@@ -48,7 +48,7 @@ static void adb_bus_enumerate(void *xdev);
static void adb_probe_nomatch(device_t dev, device_t child);
static int adb_print_child(device_t dev, device_t child);
-static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data);
+static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data, u_char *reply);
static char *adb_device_string[] = {
"HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
@@ -118,8 +118,7 @@ adb_bus_enumerate(void *xdev)
sc->packet_reply = 0;
sc->autopoll_mask = 0;
-
- mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE);
+ sc->sync_packet = 0xffff;
/* Initialize devinfo */
for (i = 0; i < 16; i++) {
@@ -128,7 +127,7 @@ adb_bus_enumerate(void *xdev)
}
/* Reset ADB bus */
- adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL);
+ adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL);
DELAY(1500);
/* Enumerate bus */
@@ -140,7 +139,7 @@ adb_bus_enumerate(void *xdev)
do {
reply = adb_send_raw_packet_sync(dev,i,
- ADB_COMMAND_TALK,3,0,NULL);
+ ADB_COMMAND_TALK,3,0,NULL,NULL);
if (reply) {
/* If we got a response, relocate to next_free */
@@ -150,10 +149,10 @@ adb_bus_enumerate(void *xdev)
r3 |= 0x00fe;
adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
- sizeof(uint16_t),(u_char *)(&r3));
+ sizeof(uint16_t),(u_char *)(&r3),NULL);
adb_send_raw_packet_sync(dev,next_free,
- ADB_COMMAND_TALK,3,0,NULL);
+ ADB_COMMAND_TALK,3,0,NULL,NULL);
sc->devinfo[next_free].default_address = i;
if (first_relocated < 0)
@@ -169,9 +168,9 @@ adb_bus_enumerate(void *xdev)
adb_send_raw_packet_sync(dev,first_relocated,
ADB_COMMAND_LISTEN,3,
- sizeof(uint16_t),(u_char *)(&r3));
+ sizeof(uint16_t),(u_char *)(&r3),NULL);
adb_send_raw_packet_sync(dev,i,
- ADB_COMMAND_TALK,3,0,NULL);
+ ADB_COMMAND_TALK,3,0,NULL,NULL);
sc->devinfo[i].default_address = i;
sc->devinfo[(int)(first_relocated)].default_address = 0;
@@ -194,10 +193,6 @@ adb_bus_enumerate(void *xdev)
static int adb_bus_detach(device_t dev)
{
- struct adb_softc *sc = device_get_softc(dev);
-
- mtx_destroy(&sc->sc_sync_mtx);
-
return (bus_generic_detach(dev));
}
@@ -230,6 +225,7 @@ adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len,
if (sc->sync_packet == command) {
memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
atomic_store_rel_int(&sc->packet_reply,len + 1);
+ wakeup(sc);
}
if (sc->children[addr] != NULL) {
@@ -317,12 +313,12 @@ adb_get_device_handler(device_t dev)
static int
adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
- uint8_t reg, int len, u_char *data)
+ uint8_t reg, int len, u_char *data, u_char *reply)
{
u_char command_byte = 0;
struct adb_softc *sc;
int result = -1;
- int i = 0;
+ int i = 1;
sc = device_get_softc(dev);
@@ -331,7 +327,8 @@ adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
command_byte |= reg;
/* Wait if someone else has a synchronous request pending */
- mtx_lock(&sc->sc_sync_mtx);
+ while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte))
+ tsleep(sc, 0, "ADB sync", hz/10);
sc->packet_reply = 0;
sc->sync_packet = command_byte;
@@ -343,21 +340,27 @@ adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
* Maybe the command got lost? Try resending and polling the
* controller.
*/
- if (i > 40)
+ if (i % 40 == 0)
ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte,
len, data, 1);
- DELAY(100);
+ tsleep(sc, 0, "ADB sync", hz/10);
i++;
}
result = sc->packet_reply - 1;
+ if (reply != NULL && result > 0)
+ memcpy(reply,sc->syncreg,result);
+
/* Clear packet sync */
sc->packet_reply = 0;
- sc->sync_packet = 0xffff; /* We can't match a 16 bit value */
- mtx_unlock(&sc->sc_sync_mtx);
+ /*
+ * We can't match a value beyond 8 bits, so set sync_packet to
+ * 0xffff to avoid collisions.
+ */
+ atomic_set_int(&sc->sync_packet, 0xffff);
return (result);
}
@@ -375,37 +378,27 @@ adb_set_device_handler(device_t dev, uint8_t newhandler)
newr3 = dinfo->register3 & 0xff00;
newr3 |= (uint16_t)(newhandler);
+ adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN,
+ 3, sizeof(uint16_t), (u_char *)(&newr3), NULL);
adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
- ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3));
- adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
- ADB_COMMAND_TALK, 3, 0, NULL);
+ ADB_COMMAND_TALK, 3, 0, NULL, NULL);
return (dinfo->handler_id);
}
-uint8_t
-adb_read_register(device_t dev, u_char reg,
- size_t *len, void *data)
+size_t
+adb_read_register(device_t dev, u_char reg, void *data)
{
struct adb_softc *sc;
struct adb_devinfo *dinfo;
- size_t orig_len;
+ size_t result;
dinfo = device_get_ivars(dev);
sc = device_get_softc(device_get_parent(dev));
- orig_len = *len;
-
- mtx_lock(&sc->sc_sync_mtx);
-
- *len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
- ADB_COMMAND_TALK, reg, 0, NULL);
+ result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
+ ADB_COMMAND_TALK, reg, 0, NULL, data);
- if (*len > 0)
- memcpy(data,sc->syncreg,*len);
-
- mtx_unlock(&sc->sc_sync_mtx);
-
- return ((*len > 0) ? 0 : -1);
+ return (result);
}
diff --git a/sys/dev/adb/adb_kbd.c b/sys/dev/adb/adb_kbd.c
index db95cfe..115b35d 100644
--- a/sys/dev/adb/adb_kbd.c
+++ b/sys/dev/adb/adb_kbd.c
@@ -271,11 +271,12 @@ adb_kbd_attach(device_t dev)
}
#endif
- adb_set_autopoll(dev,1);
-
- /* Check (asynchronously) if we can read out the LED state from
+ /* Check if we can read out the LED state from
this keyboard by reading the key state register */
- adb_send_packet(dev,ADB_COMMAND_TALK,2,0,NULL);
+ if (adb_read_register(dev, 2, NULL) == 2)
+ sc->have_led_control = 1;
+
+ adb_set_autopoll(dev,1);
return (0);
}
@@ -323,11 +324,6 @@ adb_kbd_receive_packet(device_t dev, u_char status,
if (command != ADB_COMMAND_TALK)
return 0;
- if (reg == 2 && len == 2) {
- sc->have_led_control = 1;
- return 0;
- }
-
if (reg != 0 || len != 2)
return (0);
diff --git a/sys/dev/adb/adb_mouse.c b/sys/dev/adb/adb_mouse.c
index 26edbc5..bba38c2 100644
--- a/sys/dev/adb/adb_mouse.c
+++ b/sys/dev/adb/adb_mouse.c
@@ -181,7 +181,7 @@ adb_mouse_attach(device_t dev)
sc->mode.resolution = 200;
break;
case 4:
- adb_read_register(dev,1,&r1_len,r1);
+ r1_len = adb_read_register(dev,1,r1);
if (r1_len < 8)
break;
diff --git a/sys/dev/adb/adbvar.h b/sys/dev/adb/adbvar.h
index e70aa75..47afb35 100644
--- a/sys/dev/adb/adbvar.h
+++ b/sys/dev/adb/adbvar.h
@@ -40,7 +40,6 @@ struct adb_softc {
device_t parent;
struct intr_config_hook enum_hook;
- struct mtx sc_sync_mtx;
volatile int sync_packet;
volatile int packet_reply;
diff --git a/sys/powerpc/powermac/cuda.c b/sys/powerpc/powermac/cuda.c
index c17ca82..274bb98 100644
--- a/sys/powerpc/powermac/cuda.c
+++ b/sys/powerpc/powermac/cuda.c
@@ -65,10 +65,12 @@ static int cuda_probe(device_t);
static int cuda_attach(device_t);
static int cuda_detach(device_t);
-static u_int cuda_adb_send(device_t dev, u_char command_byte, int len,
+static u_int cuda_adb_send(device_t dev, u_char command_byte, int len,
u_char *data, u_char poll);
-static u_int cuda_adb_autopoll(device_t dev, uint16_t mask);
-static void cuda_poll(device_t dev);
+static u_int cuda_adb_autopoll(device_t dev, uint16_t mask);
+static void cuda_poll(device_t dev);
+static void cuda_send_inbound(struct cuda_softc *sc);
+static void cuda_send_outbound(struct cuda_softc *sc);
static device_method_t cuda_methods[] = {
/* Device interface */
@@ -102,6 +104,8 @@ static devclass_t cuda_devclass;
DRIVER_MODULE(cuda, macio, cuda_driver, cuda_devclass, 0, 0);
DRIVER_MODULE(adb, cuda, adb_driver, adb_devclass, 0, 0);
+MALLOC_DEFINE(M_CUDA, "cuda", "CUDA packet queue");
+
static void cuda_intr(void *arg);
static uint8_t cuda_read_reg(struct cuda_softc *sc, u_int offset);
static void cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value);
@@ -170,9 +174,11 @@ cuda_attach(device_t dev)
sc->sc_waiting = 0;
sc->sc_polling = 0;
sc->sc_state = CUDA_NOTREADY;
- sc->sc_error = 0;
sc->sc_autopoll = 0;
+ STAILQ_INIT(&sc->sc_inq);
+ STAILQ_INIT(&sc->sc_outq);
+
/* Init CUDA */
reg = cuda_read_reg(sc, vDirB);
@@ -335,42 +341,126 @@ cuda_send(void *cookie, int poll, int length, uint8_t *msg)
{
struct cuda_softc *sc = cookie;
device_t dev = sc->sc_dev;
+ struct cuda_packet *pkt;
if (sc->sc_state == CUDA_NOTREADY)
- return -1;
+ return (-1);
mtx_lock(&sc->sc_mutex);
- if (sc->sc_state != CUDA_IDLE) {
- if (sc->sc_waiting == 0) {
- sc->sc_waiting = 1;
- } else {
- mtx_unlock(&sc->sc_mutex);
- return -1;
- }
+ pkt = malloc(sizeof(struct cuda_packet), M_CUDA, M_WAITOK);
+ pkt->len = length - 1;
+ pkt->type = msg[0];
+ memcpy(pkt->data, &msg[1], pkt->len);
+
+ STAILQ_INSERT_TAIL(&sc->sc_outq, pkt, pkt_q);
+
+ /*
+ * If we already are sending a packet, we should bail now that this
+ * one has been added to the queue.
+ */
+
+ if (sc->sc_waiting) {
+ mtx_unlock(&sc->sc_mutex);
+ return (0);
}
- sc->sc_error = 0;
- memcpy(sc->sc_out, msg, length);
- sc->sc_out_length = length;
+ cuda_send_outbound(sc);
+ mtx_unlock(&sc->sc_mutex);
+
+ if (sc->sc_polling || poll || cold)
+ cuda_poll(dev);
+
+ return (0);
+}
+
+static void
+cuda_send_outbound(struct cuda_softc *sc)
+{
+ struct cuda_packet *pkt;
+
+ mtx_assert(&sc->sc_mutex, MA_OWNED);
+
+ pkt = STAILQ_FIRST(&sc->sc_outq);
+ if (pkt == NULL)
+ return;
+
+ sc->sc_out_length = pkt->len + 1;
+ memcpy(sc->sc_out, &pkt->type, pkt->len + 1);
sc->sc_sent = 0;
- if (sc->sc_waiting != 1) {
- DELAY(150);
+ free(pkt, M_CUDA);
+ STAILQ_REMOVE_HEAD(&sc->sc_outq, pkt_q);
+
+ sc->sc_waiting = 1;
+
+ cuda_poll(sc->sc_dev);
+
+ DELAY(150);
+
+ if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc)) {
sc->sc_state = CUDA_OUT;
cuda_out(sc);
cuda_write_reg(sc, vSR, sc->sc_out[0]);
cuda_ack_off(sc);
cuda_tip(sc);
}
- sc->sc_waiting = 1;
- mtx_unlock(&sc->sc_mutex);
+}
- if (sc->sc_polling || poll || cold) {
- cuda_poll(dev);
+static void
+cuda_send_inbound(struct cuda_softc *sc)
+{
+ device_t dev;
+ struct cuda_packet *pkt;
+
+ dev = sc->sc_dev;
+
+ mtx_lock(&sc->sc_mutex);
+
+ while ((pkt = STAILQ_FIRST(&sc->sc_inq)) != NULL) {
+ STAILQ_REMOVE_HEAD(&sc->sc_inq, pkt_q);
+
+ mtx_unlock(&sc->sc_mutex);
+
+ /* check if we have a handler for this message */
+ switch (pkt->type) {
+ case CUDA_ADB:
+ if (pkt->len > 2) {
+ adb_receive_raw_packet(sc->adb_bus,
+ pkt->data[0],pkt->data[1],
+ pkt->len - 2,&pkt->data[2]);
+ } else {
+ adb_receive_raw_packet(sc->adb_bus,
+ pkt->data[0],pkt->data[1],0,NULL);
+ }
+ break;
+ case CUDA_PSEUDO:
+ mtx_lock(&sc->sc_mutex);
+ if (pkt->data[0] == CMD_AUTOPOLL)
+ sc->sc_autopoll = 1;
+ mtx_unlock(&sc->sc_mutex);
+ break;
+ case CUDA_ERROR:
+ /*
+ * CUDA will throw errors if we miss a race between
+ * sending and receiving packets. This is already
+ * handled when we abort packet output to handle
+ * this packet in cuda_intr(). Thus, we ignore
+ * these messages.
+ */
+ break;
+ default:
+ device_printf(dev,"unknown CUDA command %d\n",
+ pkt->type);
+ break;
+ }
+
+ free(pkt,M_CUDA);
+
+ mtx_lock(&sc->sc_mutex);
}
- return 0;
+ mtx_unlock(&sc->sc_mutex);
}
static void
@@ -382,8 +472,7 @@ cuda_poll(device_t dev)
!sc->sc_waiting)
return;
- if ((cuda_read_reg(sc, vIFR) & vSR_INT) == vSR_INT)
- cuda_intr(dev);
+ cuda_intr(dev);
}
static void
@@ -392,7 +481,7 @@ cuda_intr(void *arg)
device_t dev;
struct cuda_softc *sc;
- int i, ending, type, restart_send;
+ int i, ending, restart_send, process_inbound;
uint8_t reg;
dev = (device_t)arg;
@@ -401,7 +490,13 @@ cuda_intr(void *arg)
mtx_lock(&sc->sc_mutex);
restart_send = 0;
+ process_inbound = 0;
reg = cuda_read_reg(sc, vIFR);
+ if ((reg & vSR_INT) != vSR_INT) {
+ mtx_unlock(&sc->sc_mutex);
+ return;
+ }
+
cuda_write_reg(sc, vIFR, 0x7f); /* Clear interrupt */
switch_start:
@@ -450,13 +545,6 @@ switch_start:
} else
sc->sc_received++;
- if (sc->sc_received > 3) {
- if ((sc->sc_in[3] == CMD_IIC) &&
- (sc->sc_received > (sc->sc_i2c_read_len + 4))) {
- ending = 1;
- }
- }
-
/* intr off means this is the last byte (end of frame) */
if (cuda_intr_state(sc) == 0) {
ending = 1;
@@ -465,42 +553,24 @@ switch_start:
}
if (ending == 1) { /* end of message? */
- sc->sc_in[0] = sc->sc_received - 1;
+ struct cuda_packet *pkt;
/* reset vars and signal the end of this frame */
cuda_idle(sc);
- /* check if we have a handler for this message */
- type = sc->sc_in[1];
-
- switch (type) {
- case CUDA_ADB:
- if (sc->sc_received > 4) {
- adb_receive_raw_packet(sc->adb_bus,
- sc->sc_in[2],sc->sc_in[3],
- sc->sc_received - 4,&sc->sc_in[4]);
- } else {
- adb_receive_raw_packet(sc->adb_bus,
- sc->sc_in[2],sc->sc_in[3],0,NULL);
- }
- break;
- case CUDA_PSEUDO:
- if (sc->sc_in[3] == CMD_AUTOPOLL)
- sc->sc_autopoll = 1;
- break;
- case CUDA_ERROR:
- device_printf(dev,"CUDA Error\n");
- sc->sc_error = 1;
- break;
- default:
- device_printf(dev,"unknown CUDA command %d\n",
- type);
- break;
- }
+ /* Queue up the packet */
+ pkt = malloc(sizeof(struct cuda_packet), M_CUDA,
+ M_WAITOK);
+
+ pkt->len = sc->sc_received - 2;
+ pkt->type = sc->sc_in[1];
+ memcpy(pkt->data, &sc->sc_in[2], pkt->len);
+
+ STAILQ_INSERT_TAIL(&sc->sc_inq, pkt, pkt_q);
sc->sc_state = CUDA_IDLE;
-
sc->sc_received = 0;
+ process_inbound = 1;
/*
* If there is something waiting to be sent out,
@@ -526,6 +596,7 @@ switch_start:
DELAY(150);
goto switch_start;
}
+
/*
* If we got here, it's ok to start sending
* so load the first byte and tell the chip
@@ -558,7 +629,6 @@ switch_start:
break;
}
if (sc->sc_out_length == sc->sc_sent) { /* check for done */
-
sc->sc_waiting = 0; /* done writing */
sc->sc_state = CUDA_IDLE; /* signal bus is idle */
cuda_in(sc);
@@ -579,14 +649,26 @@ switch_start:
}
mtx_unlock(&sc->sc_mutex);
+
+ if (process_inbound)
+ cuda_send_inbound(sc);
+
+ mtx_lock(&sc->sc_mutex);
+ /* If we have another packet waiting, set it up */
+ if (!sc->sc_waiting && sc->sc_state == CUDA_IDLE)
+ cuda_send_outbound(sc);
+
+ mtx_unlock(&sc->sc_mutex);
+
}
static u_int
-cuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data, u_char poll)
+cuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data,
+ u_char poll)
{
struct cuda_softc *sc = device_get_softc(dev);
- int i;
uint8_t packet[16];
+ int i;
/* construct an ADB command packet and send it */
packet[0] = CUDA_ADB;
@@ -594,15 +676,9 @@ cuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data, u_char p
for (i = 0; i < len; i++)
packet[i + 2] = data[i];
- if (poll)
- cuda_poll(dev);
-
cuda_send(sc, poll, len + 2, packet);
- if (poll)
- cuda_poll(dev);
-
- return 0;
+ return (0);
}
static u_int
@@ -615,17 +691,14 @@ cuda_adb_autopoll(device_t dev, uint16_t mask) {
if (cmd[2] == sc->sc_autopoll) {
mtx_unlock(&sc->sc_mutex);
- return 0;
+ return (0);
}
- while (sc->sc_state != CUDA_IDLE)
- mtx_sleep(dev,&sc->sc_mutex,0,"cuda",1);
-
sc->sc_autopoll = -1;
- cuda_send(sc, 0, 3, cmd);
+ cuda_send(sc, 1, 3, cmd);
mtx_unlock(&sc->sc_mutex);
-
- return 0;
+
+ return (0);
}
diff --git a/sys/powerpc/powermac/cudavar.h b/sys/powerpc/powermac/cudavar.h
index 90f0eae..b6f25fe 100644
--- a/sys/powerpc/powermac/cudavar.h
+++ b/sys/powerpc/powermac/cudavar.h
@@ -61,6 +61,16 @@
#define CUDA_IN 0x4 /* receiving data */
#define CUDA_POLLING 0x5 /* polling - II only */
+struct cuda_packet {
+ uint8_t len;
+ uint8_t type;
+
+ uint8_t data[253];
+ STAILQ_ENTRY(cuda_packet) pkt_q;
+};
+
+STAILQ_HEAD(cuda_pktq, cuda_packet);
+
struct cuda_softc {
device_t sc_dev;
int sc_memrid;
@@ -73,22 +83,24 @@ struct cuda_softc {
device_t adb_bus;
- int sc_node;
- volatile int sc_state;
- int sc_waiting;
- int sc_polling;
- int sc_sent;
- int sc_out_length;
- int sc_received;
- int sc_iic_done;
- int sc_error;
- volatile int sc_autopoll;
+ int sc_node;
+ volatile int sc_state;
+ int sc_waiting;
+ int sc_polling;
+ int sc_iic_done;
+ volatile int sc_autopoll;
int sc_i2c_read_len;
/* internal buffers */
- uint8_t sc_in[256];
- uint8_t sc_out[256];
+ uint8_t sc_in[256];
+ uint8_t sc_out[256];
+ int sc_sent;
+ int sc_out_length;
+ int sc_received;
+
+ struct cuda_pktq sc_inq;
+ struct cuda_pktq sc_outq;
};
#endif /* _POWERPC_CUDAVAR_H_ */
OpenPOWER on IntegriCloud