Example #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);
	}
}
Example #2
0
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;
}
Example #3
0
static void
cuda_init(struct cuda_softc *sc)
{
	volatile int i;
	uint8_t reg;

	reg = cuda_read_reg(sc, vDirB);
	reg |= 0x30;	/* register B bits 4 and 5: outputs */
	cuda_write_reg(sc, vDirB, reg);

	reg = cuda_read_reg(sc, vDirB);
	reg &= 0xf7;	/* register B bit 3: input */
	cuda_write_reg(sc, vDirB, reg);
	
	reg = cuda_read_reg(sc, vACR);
	reg &= ~vSR_OUT;	/* make sure SR is set to IN */
	cuda_write_reg(sc, vACR, reg);

	cuda_write_reg(sc, vACR, (cuda_read_reg(sc, vACR) | 0x0c) & ~0x10);

	sc->sc_state = CUDA_IDLE;	/* used by all types of hardware */

	cuda_write_reg(sc, vIER, 0x84); /* make sure VIA interrupts are on */
	cuda_idle(sc);	/* set ADB bus state to idle */

	/* sort of a device reset */
	i = cuda_read_reg(sc, vSR);	/* clear interrupt */
	cuda_write_reg(sc, vIER, 0x04); /* no interrupts while clearing */
	cuda_idle(sc);	/* reset state to idle */
	delay(150);
	cuda_tip(sc);	/* signal start of frame */
	delay(150);
	cuda_toggle_ack(sc);
	delay(150);
	cuda_clear_tip(sc);
	delay(150);
	cuda_idle(sc);	/* back to idle state */
	i = cuda_read_reg(sc, vSR);	/* clear interrupt */
	cuda_write_reg(sc, vIER, 0x84);	/* ints ok now */
}
Example #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);

}
Example #5
0
static int
cuda_attach(device_t dev)
{
	struct cuda_softc *sc;

	volatile int i;
	uint8_t reg;
	phandle_t node,child;
	
	sc = device_get_softc(dev);
	sc->sc_dev = dev;
	
	sc->sc_memrid = 0;
	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 
	    &sc->sc_memrid, RF_ACTIVE);

	if (sc->sc_memr == NULL) {
		device_printf(dev, "Could not alloc mem resource!\n");
		return (ENXIO);
	}

	sc->sc_irqrid = 0;
	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid,
            	RF_ACTIVE);
        if (sc->sc_irq == NULL) {
                device_printf(dev, "could not allocate interrupt\n");
                return (ENXIO);
        }

	if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE 
	    | INTR_ENTROPY, NULL, cuda_intr, dev, &sc->sc_ih) != 0) {
                device_printf(dev, "could not setup interrupt\n");
                bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid,
                    sc->sc_irq);
                return (ENXIO);
        }

	mtx_init(&sc->sc_mutex,"cuda",NULL,MTX_DEF | MTX_RECURSE);

	sc->sc_sent = 0;
	sc->sc_received = 0;
	sc->sc_waiting = 0;
	sc->sc_polling = 0;
	sc->sc_state = CUDA_NOTREADY;
	sc->sc_autopoll = 0;
	sc->sc_rtc = -1;

	STAILQ_INIT(&sc->sc_inq);
	STAILQ_INIT(&sc->sc_outq);
	STAILQ_INIT(&sc->sc_freeq);

	for (i = 0; i < CUDA_MAXPACKETS; i++)
		STAILQ_INSERT_TAIL(&sc->sc_freeq, &sc->sc_pkts[i], pkt_q);

	/* Init CUDA */

	reg = cuda_read_reg(sc, vDirB);
	reg |= 0x30;	/* register B bits 4 and 5: outputs */
	cuda_write_reg(sc, vDirB, reg);

	reg = cuda_read_reg(sc, vDirB);
	reg &= 0xf7;	/* register B bit 3: input */
	cuda_write_reg(sc, vDirB, reg);

	reg = cuda_read_reg(sc, vACR);
	reg &= ~vSR_OUT;	/* make sure SR is set to IN */
	cuda_write_reg(sc, vACR, reg);

	cuda_write_reg(sc, vACR, (cuda_read_reg(sc, vACR) | 0x0c) & ~0x10);

	sc->sc_state = CUDA_IDLE;	/* used by all types of hardware */

	cuda_write_reg(sc, vIER, 0x84); /* make sure VIA interrupts are on */

	cuda_idle(sc);	/* reset ADB */

	/* Reset CUDA */

	i = cuda_read_reg(sc, vSR);	/* clear interrupt */
	cuda_write_reg(sc, vIER, 0x04); /* no interrupts while clearing */
	cuda_idle(sc);	/* reset state to idle */
	DELAY(150);
	cuda_tip(sc);	/* signal start of frame */
	DELAY(150);
	cuda_toggle_ack(sc);
	DELAY(150);
	cuda_clear_tip(sc);
	DELAY(150);
	cuda_idle(sc);	/* back to idle state */
	i = cuda_read_reg(sc, vSR);	/* clear interrupt */
	cuda_write_reg(sc, vIER, 0x84);	/* ints ok now */

	/* Initialize child buses (ADB) */
	node = ofw_bus_get_node(dev);

	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
		char name[32];

		memset(name, 0, sizeof(name));
		OF_getprop(child, "name", name, sizeof(name));

		if (bootverbose)
			device_printf(dev, "CUDA child <%s>\n",name);

		if (strncmp(name, "adb", 4) == 0) {
			sc->adb_bus = device_add_child(dev,"adb",-1);
		}
	}

	clock_register(dev, 1000);
	EVENTHANDLER_REGISTER(shutdown_final, cuda_shutdown, sc,
	    SHUTDOWN_PRI_LAST);

	return (bus_generic_attach(dev));
}
Example #6
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;
}