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; }
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; }