diff options
-rw-r--r-- | sys/dev/adb/adb.h | 2 | ||||
-rw-r--r-- | sys/dev/adb/adb_bus.c | 71 | ||||
-rw-r--r-- | sys/dev/adb/adb_kbd.c | 14 | ||||
-rw-r--r-- | sys/dev/adb/adb_mouse.c | 2 | ||||
-rw-r--r-- | sys/dev/adb/adbvar.h | 1 | ||||
-rw-r--r-- | sys/powerpc/powermac/cuda.c | 229 | ||||
-rw-r--r-- | sys/powerpc/powermac/cudavar.h | 36 |
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_ */ |