/* * ppb_1284_get_state() * * Get IEEE1284 state */ int ppb_1284_get_state(device_t bus) { return (DEVTOSOFTC(bus)->state); }
void _ppb_assert_locked(device_t bus, const char *file, int line) { mtx_assert_(DEVTOSOFTC(bus)->ppc_lock, MA_OWNED, file, line); }
static int pcf_ebus_attach(device_t dev) { struct pcf_softc *sc; int rv = ENXIO; phandle_t node; uint64_t own_addr; sc = DEVTOSOFTC(dev); mtx_init(&sc->pcf_lock, device_get_nameunit(dev), "pcf", MTX_DEF); /* get OFW node of the pcf */ if ((node = ofw_bus_get_node(dev)) == -1) { device_printf(dev, "cannot get OFW node\n"); goto error; } /* IO port is mandatory */ sc->res_ioport = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid_ioport, RF_ACTIVE); if (sc->res_ioport == 0) { device_printf(dev, "cannot reserve I/O port range\n"); goto error; } sc->pcf_flags = device_get_flags(dev); /* * XXX use poll-mode property? */ if (!(sc->pcf_flags & IIC_POLLED)) { sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid_irq, RF_ACTIVE); if (sc->res_irq == 0) { device_printf(dev, "can't reserve irq, polled mode.\n"); sc->pcf_flags |= IIC_POLLED; } } /* * XXX on AXmp there's probably a second IRQ which is the fan fail * interrupt genererated by the PCF8574 at 0x78. */ /* get address of the pcf */ if (OF_getprop(node, "own-address", &own_addr, sizeof(own_addr)) == -1) { device_printf(dev, "cannot get own address\n"); goto error; } if (bootverbose) device_printf(dev, "PCF8584 address: 0x%08llx\n", (unsigned long long)own_addr); /* reset the chip */ pcf_rst_card(dev, IIC_FASTEST, own_addr, NULL); if (sc->res_irq) { rv = bus_setup_intr(dev, sc->res_irq, INTR_TYPE_NET /* | INTR_ENTROPY */, NULL, pcf_intr, sc, &sc->intr_cookie); if (rv) { device_printf(dev, "could not setup IRQ\n"); goto error; } } if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) device_printf(dev, "could not allocate iicbus instance\n"); /* probe and attach the iicbus */ bus_generic_attach(dev); return (0); error: if (sc->res_irq != 0) { bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq); } if (sc->res_ioport != 0) { bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ioport, sc->res_ioport); } mtx_destroy(&sc->pcf_lock); return (rv); }
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; }
static int pcf_isa_attach(device_t dev) { struct pcf_softc *sc; int rv = ENXIO; sc = DEVTOSOFTC(dev); mtx_init(&sc->pcf_lock, device_get_nameunit(dev), "pcf", MTX_DEF); /* IO port is mandatory */ sc->res_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->rid_ioport, RF_ACTIVE); if (sc->res_ioport == 0) { device_printf(dev, "cannot reserve I/O port range\n"); goto error; } sc->pcf_flags = device_get_flags(dev); if (!(sc->pcf_flags & IIC_POLLED)) { sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid_irq, RF_ACTIVE); if (sc->res_irq == 0) { device_printf(dev, "can't reserve irq, polled mode.\n"); sc->pcf_flags |= IIC_POLLED; } } /* reset the chip */ pcf_rst_card(dev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); if (sc->res_irq) { rv = bus_setup_intr(dev, sc->res_irq, INTR_TYPE_NET /* | INTR_ENTROPY */, NULL, pcf_intr, sc, &sc->intr_cookie); if (rv) { device_printf(dev, "could not setup IRQ\n"); goto error; } } if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) device_printf(dev, "could not allocate iicbus instance\n"); /* probe and attach the iicbus */ bus_generic_attach(dev); return (0); error: if (sc->res_irq != 0) { bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq); } if (sc->res_ioport != 0) { bus_release_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, sc->res_ioport); } mtx_destroy(&sc->pcf_lock); return (rv); }
u_char ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) { struct ppc_data *ppc = DEVTOSOFTC(ppcdev); PPC_ASSERT_LOCKED(ppc); switch (iop) { case PPB_OUTSB_EPP: bus_write_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); break; case PPB_OUTSW_EPP: bus_write_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt); break; case PPB_OUTSL_EPP: bus_write_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt); break; case PPB_INSB_EPP: bus_read_multi_1(ppc->res_ioport, PPC_EPP_DATA, addr, cnt); break; case PPB_INSW_EPP: bus_read_multi_2(ppc->res_ioport, PPC_EPP_DATA, (u_int16_t *)addr, cnt); break; case PPB_INSL_EPP: bus_read_multi_4(ppc->res_ioport, PPC_EPP_DATA, (u_int32_t *)addr, cnt); break; case PPB_RDTR: return (r_dtr(ppc)); case PPB_RSTR: return (r_str(ppc)); case PPB_RCTR: return (r_ctr(ppc)); case PPB_REPP_A: return (r_epp_A(ppc)); case PPB_REPP_D: return (r_epp_D(ppc)); case PPB_RECR: return (r_ecr(ppc)); case PPB_RFIFO: return (r_fifo(ppc)); case PPB_WDTR: w_dtr(ppc, byte); break; case PPB_WSTR: w_str(ppc, byte); break; case PPB_WCTR: w_ctr(ppc, byte); break; case PPB_WEPP_A: w_epp_A(ppc, byte); break; case PPB_WEPP_D: w_epp_D(ppc, byte); break; case PPB_WECR: w_ecr(ppc, byte); break; case PPB_WFIFO: w_fifo(ppc, byte); break; default: panic("%s: unknown I/O operation", __func__); break; } return (0); /* not significative */ }
int ppc_probe(device_t dev, int rid) { #ifdef __i386__ static short next_bios_ppc = 0; #ifdef PC98 unsigned int pc98_ieee_mode = 0x00; unsigned int tmp; #endif #endif struct ppc_data *ppc; int error; rman_res_t port; /* * Allocate the ppc_data structure. */ ppc = DEVTOSOFTC(dev); bzero(ppc, sizeof(struct ppc_data)); ppc->rid_ioport = rid; /* retrieve ISA parameters */ error = bus_get_resource(dev, SYS_RES_IOPORT, rid, &port, NULL); #ifdef __i386__ /* * If port not specified, use bios list. */ if (error) { #ifdef PC98 if (next_bios_ppc == 0) { /* Use default IEEE-1284 port of NEC PC-98x1 */ port = PC98_IEEE_1284_PORT; next_bios_ppc += 1; if (bootverbose) device_printf(dev, "parallel port found at 0x%lx\n", port); } #else if ((next_bios_ppc < BIOS_MAX_PPC) && (*(BIOS_PORTS + next_bios_ppc) != 0)) { port = *(BIOS_PORTS + next_bios_ppc++); if (bootverbose) device_printf(dev, "parallel port found at 0x%lx\n", port); } else { device_printf(dev, "parallel port not found.\n"); return (ENXIO); } #endif /* PC98 */ bus_set_resource(dev, SYS_RES_IOPORT, rid, port, IO_LPTSIZE_EXTENDED); } #endif /* IO port is mandatory */ /* Try "extended" IO port range...*/ ppc->res_ioport = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &ppc->rid_ioport, IO_LPTSIZE_EXTENDED, RF_ACTIVE); if (ppc->res_ioport != 0) { if (bootverbose) device_printf(dev, "using extended I/O port range\n"); } else { /* Failed? If so, then try the "normal" IO port range... */ ppc->res_ioport = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &ppc->rid_ioport, IO_LPTSIZE_NORMAL, RF_ACTIVE); if (ppc->res_ioport != 0) { if (bootverbose) device_printf(dev, "using normal I/O port range\n"); } else { device_printf(dev, "cannot reserve I/O port range\n"); goto error; } } ppc->ppc_base = rman_get_start(ppc->res_ioport); ppc->ppc_flags = device_get_flags(dev); if (!(ppc->ppc_flags & 0x20)) { ppc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &ppc->rid_irq, RF_SHAREABLE); ppc->res_drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &ppc->rid_drq, RF_ACTIVE); } if (ppc->res_irq) ppc->ppc_irq = rman_get_start(ppc->res_irq); if (ppc->res_drq) ppc->ppc_dmachan = rman_get_start(ppc->res_drq); ppc->ppc_dev = dev; ppc->ppc_model = GENERIC; ppc->ppc_mode = PPB_COMPATIBLE; ppc->ppc_epp = (ppc->ppc_flags & 0x10) >> 4; ppc->ppc_type = PPC_TYPE_GENERIC; #if defined(__i386__) && defined(PC98) /* * IEEE STD 1284 Function Check and Enable * for default IEEE-1284 port of NEC PC-98x1 */ if (ppc->ppc_base == PC98_IEEE_1284_PORT && !(ppc->ppc_flags & PC98_IEEE_1284_DISABLE)) { tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); pc98_ieee_mode = tmp; if ((tmp & 0x10) == 0x10) { outb(ppc->ppc_base + PPC_1284_ENABLE, tmp & ~0x10); tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); if ((tmp & 0x10) == 0x10) goto error; } else { outb(ppc->ppc_base + PPC_1284_ENABLE, tmp | 0x10); tmp = inb(ppc->ppc_base + PPC_1284_ENABLE); if ((tmp & 0x10) != 0x10) goto error; } outb(ppc->ppc_base + PPC_1284_ENABLE, pc98_ieee_mode | 0x10); } #endif /* * Try to detect the chipset and its mode. */ if (ppc_detect(ppc, ppc->ppc_flags & 0xf)) goto error; return (0); error: #if defined(__i386__) && defined(PC98) if (ppc->ppc_base == PC98_IEEE_1284_PORT && !(ppc->ppc_flags & PC98_IEEE_1284_DISABLE)) { outb(ppc->ppc_base + PPC_1284_ENABLE, pc98_ieee_mode); } #endif if (ppc->res_irq != 0) { bus_release_resource(dev, SYS_RES_IRQ, ppc->rid_irq, ppc->res_irq); } if (ppc->res_ioport != 0) { bus_release_resource(dev, SYS_RES_IOPORT, ppc->rid_ioport, ppc->res_ioport); } if (ppc->res_drq != 0) { bus_release_resource(dev, SYS_RES_DRQ, ppc->rid_drq, ppc->res_drq); } return (ENXIO); }
/* * ppc_exec_microseq() * * Execute a microsequence. * Microsequence mechanism is supposed to handle fast I/O operations. */ int ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq) { struct ppc_data *ppc = DEVTOSOFTC(dev); struct ppb_microseq *mi; char cc, *p; int i, iter, len; int error; register int reg; register char mask; register int accum = 0; register char *ptr = 0; struct ppb_microseq *stack = 0; /* microsequence registers are equivalent to PC-like port registers */ #define r_reg(reg,ppc) (bus_read_1((ppc)->res_ioport, reg)) #define w_reg(reg, ppc, byte) (bus_write_1((ppc)->res_ioport, reg, byte)) #define INCR_PC (mi ++) /* increment program counter */ PPC_ASSERT_LOCKED(ppc); mi = *p_msq; for (;;) { switch (mi->opcode) { case MS_OP_RSET: cc = r_reg(mi->arg[0].i, ppc); cc &= (char)mi->arg[2].i; /* clear mask */ cc |= (char)mi->arg[1].i; /* assert mask */ w_reg(mi->arg[0].i, ppc, cc); INCR_PC; break; case MS_OP_RASSERT_P: reg = mi->arg[1].i; ptr = ppc->ppc_ptr; if ((len = mi->arg[0].i) == MS_ACCUM) { accum = ppc->ppc_accum; for (; accum; accum--) w_reg(reg, ppc, *ptr++); ppc->ppc_accum = accum; } else for (i=0; i<len; i++) w_reg(reg, ppc, *ptr++); ppc->ppc_ptr = ptr; INCR_PC; break; case MS_OP_RFETCH_P: reg = mi->arg[1].i; mask = (char)mi->arg[2].i; ptr = ppc->ppc_ptr; if ((len = mi->arg[0].i) == MS_ACCUM) { accum = ppc->ppc_accum; for (; accum; accum--) *ptr++ = r_reg(reg, ppc) & mask; ppc->ppc_accum = accum; } else for (i=0; i<len; i++) *ptr++ = r_reg(reg, ppc) & mask; ppc->ppc_ptr = ptr; INCR_PC; break; case MS_OP_RFETCH: *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & (char)mi->arg[1].i; INCR_PC; break; case MS_OP_RASSERT: case MS_OP_DELAY: /* let's suppose the next instr. is the same */ prefetch: for (;mi->opcode == MS_OP_RASSERT; INCR_PC) w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); if (mi->opcode == MS_OP_DELAY) { DELAY(mi->arg[0].i); INCR_PC; goto prefetch; } break; case MS_OP_ADELAY: if (mi->arg[0].i) { PPC_UNLOCK(ppc); pause("ppbdelay", mi->arg[0].i * (hz/1000)); PPC_LOCK(ppc); } INCR_PC; break; case MS_OP_TRIG: reg = mi->arg[0].i; iter = mi->arg[1].i; p = (char *)mi->arg[2].p; /* XXX delay limited to 255 us */ for (i=0; i<iter; i++) { w_reg(reg, ppc, *p++); DELAY((unsigned char)*p++); } INCR_PC; break; case MS_OP_SET: ppc->ppc_accum = mi->arg[0].i; INCR_PC; break; case MS_OP_DBRA: if (--ppc->ppc_accum > 0) mi += mi->arg[0].i; INCR_PC; break; case MS_OP_BRSET: cc = r_str(ppc); if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) mi += mi->arg[1].i; INCR_PC; break; case MS_OP_BRCLEAR: cc = r_str(ppc); if ((cc & (char)mi->arg[0].i) == 0) mi += mi->arg[1].i; INCR_PC; break; case MS_OP_BRSTAT: cc = r_str(ppc); if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == (char)mi->arg[0].i) mi += mi->arg[2].i; INCR_PC; break; case MS_OP_C_CALL: /* * If the C call returns !0 then end the microseq. * The current state of ptr is passed to the C function */ if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) return (error); INCR_PC; break; case MS_OP_PTR: ppc->ppc_ptr = (char *)mi->arg[0].p; INCR_PC; break; case MS_OP_CALL: if (stack) panic("%s: too much calls", __func__); if (mi->arg[0].p) { /* store the state of the actual * microsequence */ stack = mi; /* jump to the new microsequence */ mi = (struct ppb_microseq *)mi->arg[0].p; } else INCR_PC; break; case MS_OP_SUBRET: /* retrieve microseq and pc state before the call */ mi = stack; /* reset the stack */ stack = 0; /* XXX return code */ INCR_PC; break; case MS_OP_PUT: case MS_OP_GET: case MS_OP_RET: /* can't return to ppb level during the execution * of a submicrosequence */ if (stack) panic("%s: can't return to ppb level", __func__); /* update pc for ppb level of execution */ *p_msq = mi; /* return to ppb level of execution */ return (0); default: panic("%s: unknown microsequence opcode 0x%x", __func__, mi->opcode); } } /* unreached */ }
static int envctrl_attach(device_t dev) { struct pcf_softc *sc; int rv = ENXIO; sc = DEVTOSOFTC(dev); bzero(sc, sizeof(struct pcf_softc)); /* IO port is mandatory */ sc->res_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->rid_ioport, RF_ACTIVE); if (sc->res_ioport == 0) { device_printf(dev, "cannot reserve I/O port range\n"); goto error; } sc->bt_ioport = rman_get_bustag(sc->res_ioport); sc->bh_ioport = rman_get_bushandle(sc->res_ioport); sc->pcf_flags = device_get_flags(dev); if (!(sc->pcf_flags & IIC_POLLED)) { sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid_irq, RF_ACTIVE); if (sc->res_irq == 0) { device_printf(dev, "can't reserve irq, polled mode.\n"); sc->pcf_flags |= IIC_POLLED; } } /* reset the chip */ pcf_rst_card(dev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); rv = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->res_irq, INTR_TYPE_NET /* | INTR_ENTROPY */, pcf_intr, sc, &sc->intr_cookie); if (rv) { device_printf(dev, "could not setup IRQ\n"); goto error; } if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) device_printf(dev, "could not allocate iicbus instance\n"); /* probe and attach the iicbus */ bus_generic_attach(dev); return (0); error: if (sc->res_irq != 0) { bus_deactivate_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq); bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq); } if (sc->res_ioport != 0) { bus_deactivate_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, sc->res_ioport); bus_release_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, sc->res_ioport); } return (rv); }