Beispiel #1
0
void
pcf_intr(void *arg)
{
	struct pcf_softc *sc = arg;
	char data, status, addr;
	char error = 0;

	PCF_LOCK(sc);
	status = pcf_get_S1(sc);

	if (status & PIN) {
		printf("pcf: spurious interrupt, status=0x%x\n",
		       status & 0xff);

		goto error;
	}

	if (status & LAB)
		printf("pcf: bus arbitration lost!\n");

	if (status & BER) {
		error = IIC_EBUSERR;
		iicbus_intr(sc->iicbus, INTR_ERROR, &error);

		goto error;
	}

	do {
		status = pcf_get_S1(sc);

		switch(sc->pcf_slave_mode) {

		case SLAVE_TRANSMITTER:
			if (status & LRB) {
				/* ack interrupt line */
				dummy_write(sc);

				/* no ack, don't send anymore */
				sc->pcf_slave_mode = SLAVE_RECEIVER;

				iicbus_intr(sc->iicbus, INTR_NOACK, NULL);
				break;
			}

			/* get data from upper code */
			iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);

			pcf_set_S0(sc, data);
			break;

		case SLAVE_RECEIVER:
			if (status & AAS) {
				addr = pcf_get_S0(sc);

				if (status & AD0)
					iicbus_intr(sc->iicbus, INTR_GENERAL, &addr);
				else
					iicbus_intr(sc->iicbus, INTR_START, &addr);

				if (addr & LSB) {
					sc->pcf_slave_mode = SLAVE_TRANSMITTER;

					/* get the first char from upper code */
					iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);

					/* send first data byte */
					pcf_set_S0(sc, data);
				}

				break;
			}

			/* stop condition received? */
			if (status & STS) {
				/* ack interrupt line */
				dummy_read(sc);

				/* emulate intr stop condition */
				iicbus_intr(sc->iicbus, INTR_STOP, NULL);

			} else {
				/* get data, ack interrupt line */
				data = pcf_get_S0(sc);

				/* deliver the character */
				iicbus_intr(sc->iicbus, INTR_RECEIVE, &data);
			}
			break;

		    default:
			panic("%s: unknown slave mode (%d)!", __func__,
				sc->pcf_slave_mode);
		    }

	} while ((pcf_get_S1(sc) & PIN) == 0);
	PCF_UNLOCK(sc);

	return;

error:
	/* unknown event on bus...reset PCF */
	pcf_set_S1(sc, PIN|ESO|ENI|ACK);

	sc->pcf_slave_mode = SLAVE_RECEIVER;
	PCF_UNLOCK(sc);

	return;
}
Beispiel #2
0
static void
pcfintr(void *arg)
{
	device_t pcfdev = (device_t)arg;
	struct pcf_softc *pcf = DEVTOSOFTC(pcfdev);

	char data, status, addr;
	char error = 0;

	status = PCF_GET_S1(pcf);

	if (status & PIN) {
		device_printf(pcfdev, "spurious interrupt, status=0x%x\n", status & 0xff);

		goto error;
	}

	if (status & LAB)
		device_printf(pcfdev, "bus arbitration lost!\n");

	if (status & BER) {
		error = IIC_EBUSERR;
		iicbus_intr(pcf->iicbus, INTR_ERROR, &error);

		goto error;
	}

	do {
		status = PCF_GET_S1(pcf);

		switch(pcf->pcf_slave_mode) {

		case SLAVE_TRANSMITTER:
			if (status & LRB) {
				/* ack interrupt line */
				dummy_write(pcf);

				/* no ack, don't send anymore */
				pcf->pcf_slave_mode = SLAVE_RECEIVER;

				iicbus_intr(pcf->iicbus, INTR_NOACK, NULL);
				break;
			}

			/* get data from upper code */
			iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data);

			PCF_SET_S0(pcf, data);
			break;

		case SLAVE_RECEIVER:
			if (status & AAS) {
				addr = PCF_GET_S0(pcf);

				if (status & AD0)
					iicbus_intr(pcf->iicbus, INTR_GENERAL, &addr);
				else
					iicbus_intr(pcf->iicbus, INTR_START, &addr);

				if (addr & LSB) {
					pcf->pcf_slave_mode = SLAVE_TRANSMITTER;

					/* get the first char from upper code */
					iicbus_intr(pcf->iicbus, INTR_TRANSMIT, &data);

					/* send first data byte */
					PCF_SET_S0(pcf, data);
				}

				break;
			}

			/* stop condition received? */
			if (status & STS) {
				/* ack interrupt line */
				dummy_read(pcf);

				/* emulate intr stop condition */
				iicbus_intr(pcf->iicbus, INTR_STOP, NULL);

			} else {
				/* get data, ack interrupt line */
				data = PCF_GET_S0(pcf);

				/* deliver the character */
				iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data);
			}
			break;

		    default:
			panic("%s: unknown slave mode (%d)!", __func__,
				pcf->pcf_slave_mode);
		    }

	} while ((PCF_GET_S1(pcf) & PIN) == 0);

	return;

error:
	/* unknown event on bus...reset PCF */
	PCF_SET_S1(pcf, PIN|ES0|ENI|ACK);

	pcf->pcf_slave_mode = SLAVE_RECEIVER;

	return;
}