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; STAILQ_REMOVE_HEAD(&sc->sc_outq, pkt_q); STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, 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); } }
static int cuda_send(void *cookie, int poll, int length, uint8_t *msg) { struct cuda_softc *sc = cookie; int s; DPRINTF("cuda_send %08x\n", (uint32_t)cookie); if (sc->sc_state == CUDA_NOTREADY) return -1; s = splhigh(); if ((sc->sc_state == CUDA_IDLE) /*&& ((cuda_read_reg(sc, vBufB) & vPB3) == vPB3)*/) { /* fine */ DPRINTF("chip is idle\n"); } else { DPRINTF("cuda state is %d\n", sc->sc_state); if (sc->sc_waiting == 0) { sc->sc_waiting = 1; } else { splx(s); return -1; } } sc->sc_error = 0; memcpy(sc->sc_out, msg, length); sc->sc_out_length = length; sc->sc_sent = 0; if (sc->sc_waiting != 1) { delay(150); 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; if (sc->sc_polling || poll || cold) { cuda_poll(sc); } splx(s); return 0; }
static void cuda_intr(void *arg) { device_t dev; struct cuda_softc *sc; int i, ending, restart_send, process_inbound; uint8_t reg; dev = (device_t)arg; sc = device_get_softc(dev); 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: switch (sc->sc_state) { case CUDA_IDLE: /* * This is an unexpected packet, so grab the first (dummy) * byte, set up the proper vars, and tell the chip we are * starting to receive the packet by setting the TIP bit. */ sc->sc_in[1] = cuda_read_reg(sc, vSR); if (cuda_intr_state(sc) == 0) { /* must have been a fake start */ if (sc->sc_waiting) { /* start over */ DELAY(150); sc->sc_state = CUDA_OUT; sc->sc_sent = 0; cuda_out(sc); cuda_write_reg(sc, vSR, sc->sc_out[1]); cuda_ack_off(sc); cuda_tip(sc); } break; } cuda_in(sc); cuda_tip(sc); sc->sc_received = 1; sc->sc_state = CUDA_IN; break; case CUDA_IN: sc->sc_in[sc->sc_received] = cuda_read_reg(sc, vSR); ending = 0; if (sc->sc_received > 255) { /* bitch only once */ if (sc->sc_received == 256) { device_printf(dev,"input overflow\n"); ending = 1; } } else sc->sc_received++; /* intr off means this is the last byte (end of frame) */ if (cuda_intr_state(sc) == 0) { ending = 1; } else { cuda_toggle_ack(sc); } if (ending == 1) { /* end of message? */ struct cuda_packet *pkt; /* reset vars and signal the end of this frame */ cuda_idle(sc); /* Queue up the packet */ pkt = STAILQ_FIRST(&sc->sc_freeq); if (pkt != NULL) { /* If we have a free packet, process it */ pkt->len = sc->sc_received - 2; pkt->type = sc->sc_in[1]; memcpy(pkt->data, &sc->sc_in[2], pkt->len); STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q); STAILQ_INSERT_TAIL(&sc->sc_inq, pkt, pkt_q); process_inbound = 1; } sc->sc_state = CUDA_IDLE; sc->sc_received = 0; /* * If there is something waiting to be sent out, * set everything up and send the first byte. */ if (sc->sc_waiting == 1) { DELAY(1500); /* required */ sc->sc_sent = 0; sc->sc_state = CUDA_OUT; /* * If the interrupt is on, we were too slow * and the chip has already started to send * something to us, so back out of the write * and start a read cycle. */ if (cuda_intr_state(sc)) { cuda_in(sc); cuda_idle(sc); sc->sc_sent = 0; sc->sc_state = CUDA_IDLE; sc->sc_received = 0; DELAY(150); goto switch_start; } /* * If we got here, it's ok to start sending * so load the first byte and tell the chip * we want to send. */ cuda_out(sc); cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]); cuda_ack_off(sc); cuda_tip(sc); } } break; case CUDA_OUT: i = cuda_read_reg(sc, vSR); /* reset SR-intr in IFR */ sc->sc_sent++; if (cuda_intr_state(sc)) { /* ADB intr low during write */ cuda_in(sc); /* make sure SR is set to IN */ cuda_idle(sc); sc->sc_sent = 0; /* must start all over */ sc->sc_state = CUDA_IDLE; /* new state */ sc->sc_received = 0; sc->sc_waiting = 1; /* must retry when done with * read */ DELAY(150); goto switch_start; /* process next state right * now */ 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); cuda_idle(sc); } else { /* send next byte */ cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]); cuda_toggle_ack(sc); /* signal byte ready to * shift */ } break; case CUDA_NOTREADY: break; default: break; } 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 int cuda_intr(void *arg) { struct cuda_softc *sc = arg; int i, ending, type; uint8_t reg; reg = cuda_read_reg(sc, vIFR); /* Read the interrupts */ DPRINTF("["); if ((reg & 0x80) == 0) { DPRINTF("irq %02x]", reg); return 0; /* No interrupts to process */ } DPRINTF(":"); cuda_write_reg(sc, vIFR, 0x7f); /* Clear 'em */ switch_start: switch (sc->sc_state) { case CUDA_IDLE: /* * This is an unexpected packet, so grab the first (dummy) * byte, set up the proper vars, and tell the chip we are * starting to receive the packet by setting the TIP bit. */ sc->sc_in[1] = cuda_read_reg(sc, vSR); DPRINTF("start: %02x", sc->sc_in[1]); if (cuda_intr_state(sc) == 0) { /* must have been a fake start */ DPRINTF(" ... fake start\n"); if (sc->sc_waiting) { /* start over */ delay(150); sc->sc_state = CUDA_OUT; sc->sc_sent = 0; cuda_out(sc); cuda_write_reg(sc, vSR, sc->sc_out[1]); cuda_ack_off(sc); cuda_tip(sc); } break; } cuda_in(sc); cuda_tip(sc); sc->sc_received = 1; sc->sc_state = CUDA_IN; DPRINTF(" CUDA_IN"); break; case CUDA_IN: sc->sc_in[sc->sc_received] = cuda_read_reg(sc, vSR); DPRINTF(" %02x", sc->sc_in[sc->sc_received]); ending = 0; if (sc->sc_received > 255) { /* bitch only once */ if (sc->sc_received == 256) { printf("%s: input overflow\n", device_xname(sc->sc_dev)); ending = 1; } } 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; DPRINTF(".\n"); } else { cuda_toggle_ack(sc); } if (ending == 1) { /* end of message? */ sc->sc_in[0] = sc->sc_received - 1; /* 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]; if ((type >= 0) && (type < 16)) { CudaHandler *me = &sc->sc_handlers[type]; if (me->handler != NULL) { me->handler(me->cookie, sc->sc_received - 1, &sc->sc_in[1]); } else { printf("no handler for type %02x\n", type); panic("barf"); } } DPRINTF("CUDA_IDLE"); sc->sc_state = CUDA_IDLE; sc->sc_received = 0; /* * If there is something waiting to be sent out, * set everything up and send the first byte. */ if (sc->sc_waiting == 1) { DPRINTF("pending write\n"); delay(1500); /* required */ sc->sc_sent = 0; sc->sc_state = CUDA_OUT; /* * If the interrupt is on, we were too slow * and the chip has already started to send * something to us, so back out of the write * and start a read cycle. */ if (cuda_intr_state(sc)) { cuda_in(sc); cuda_idle(sc); sc->sc_sent = 0; sc->sc_state = CUDA_IDLE; sc->sc_received = 0; delay(150); DPRINTF("too slow - incoming message\n"); goto switch_start; } /* * If we got here, it's ok to start sending * so load the first byte and tell the chip * we want to send. */ DPRINTF("sending "); cuda_out(sc); cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]); cuda_ack_off(sc); cuda_tip(sc); } } break; case CUDA_OUT: i = cuda_read_reg(sc, vSR); /* reset SR-intr in IFR */ sc->sc_sent++; if (cuda_intr_state(sc)) { /* ADB intr low during write */ DPRINTF("incoming msg during send\n"); cuda_in(sc); /* make sure SR is set to IN */ cuda_idle(sc); sc->sc_sent = 0; /* must start all over */ sc->sc_state = CUDA_IDLE; /* new state */ sc->sc_received = 0; sc->sc_waiting = 1; /* must retry when done with * read */ delay(150); goto switch_start; /* process next state right * now */ 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); cuda_idle(sc); DPRINTF("done sending\n"); } else { /* send next byte */ cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]); cuda_toggle_ack(sc); /* signal byte ready to * shift */ } break; case CUDA_NOTREADY: DPRINTF("adb: not yet initialized\n"); break; default: DPRINTF("intr: unknown ADB state\n"); break; } DPRINTF("]"); return 1; }