Ejemplo n.º 1
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;

	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);
	}
}
Ejemplo n.º 2
0
static u_int
cuda_poll(device_t dev)
{
	struct cuda_softc *sc = device_get_softc(dev);

	if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc) && 
	    !sc->sc_waiting)
		return (0);

	cuda_intr(dev);
	return (0);
}
Ejemplo n.º 3
0
static void
cuda_poll(void *cookie)
{
	struct cuda_softc *sc = cookie;
	int s;

	DPRINTF("polling\n");
	while ((sc->sc_state != CUDA_IDLE) ||
	       (cuda_intr_state(sc)) ||
	       (sc->sc_waiting == 1)) {
		if ((cuda_read_reg(sc, vIFR) & vSR_INT) == vSR_INT) {
			s = splhigh();
			cuda_intr(sc);
			splx(s);
		}
	}
}
Ejemplo n.º 4
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);

}
Ejemplo n.º 5
0
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;
}