static int ppc_check_epp_timeout(struct ppc_data *ppc) { ppc_reset_epp_timeout(ppc); return (!(r_str(ppc) & TIMEOUT)); }
String<CharType> GenerateRandomString(ULONG seed, size_t str_length) { String<CharType> r_str(str_length); FOR(i, str_length) { CharType c = CharType('A') + CharType(RtlRandomEx(&seed) % 26); r_str << c; }
/* * EPP timeout, according to the PC87332 manual * Semantics of clearing EPP timeout bit. * PC87332 - reading SPP_STR does it... * SMC - write 1 to EPP timeout bit XXX * Others - (?) write 0 to EPP timeout bit */ static void ppc_reset_epp_timeout(struct ppc_data *ppc) { register char r; r = r_str(ppc); w_str(ppc, r | 0x1); w_str(ppc, r & 0xfe); return; }
u_char ppc_io(device_t ppcdev, int iop, u_char *addr, int cnt, u_char byte) { struct ppc_data *ppc = DEVTOSOFTC(ppcdev); switch (iop) { case PPB_OUTSB_EPP: bus_space_write_multi_1(ppc->bst, ppc->bsh, PPC_EPP_DATA, addr, cnt); break; case PPB_OUTSW_EPP: bus_space_write_multi_2(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int16_t *)addr, cnt); break; case PPB_OUTSL_EPP: bus_space_write_multi_4(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int32_t *)addr, cnt); break; case PPB_INSB_EPP: bus_space_read_multi_1(ppc->bst, ppc->bsh, PPC_EPP_DATA, addr, cnt); break; case PPB_INSW_EPP: bus_space_read_multi_2(ppc->bst, ppc->bsh, PPC_EPP_DATA, (u_int16_t *)addr, cnt); break; case PPB_INSL_EPP: bus_space_read_multi_4(ppc->bst, ppc->bsh, 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 */ }
static void ppcintr(void *arg) { device_t dev = (device_t)arg; struct ppc_data *ppc = (struct ppc_data *)device_get_softc(dev); u_char ctr, ecr, str; str = r_str(ppc); ctr = r_ctr(ppc); ecr = r_ecr(ppc); #if PPC_DEBUG > 1 printf("![%x/%x/%x]", ctr, ecr, str); #endif /* don't use ecp mode with IRQENABLE set */ if (ctr & IRQENABLE) { return; } /* interrupts are generated by nFault signal * only in ECP mode */ if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { /* check if ppc driver has programmed the * nFault interrupt */ if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { w_ecr(ppc, ecr | PPC_nFAULT_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; } else { /* shall be handled by underlying layers XXX */ return; } } if (ppc->ppc_irqstat & PPC_IRQ_DMA) { /* disable interrupts (should be done by hardware though) */ w_ecr(ppc, ecr | PPC_SERVICE_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_DMA; ecr = r_ecr(ppc); /* check if DMA completed */ if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { #ifdef PPC_DEBUG printf("a"); #endif /* stop DMA */ w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); ecr = r_ecr(ppc); if (ppc->ppc_dmastat == PPC_DMA_STARTED) { #ifdef PPC_DEBUG printf("d"); #endif isa_dmadone( ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt, ppc->ppc_dmachan); ppc->ppc_dmastat = PPC_DMA_COMPLETE; /* wakeup the waiting process */ wakeup(ppc); } } } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { /* classic interrupt I/O */ ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; } return; }
/* * 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(register,ppc) (bus_space_read_1((ppc)->bst, (ppc)->bsh, register)) #define w_reg(register, ppc, byte) (bus_space_write_1((ppc)->bst, (ppc)->bsh, register, byte)) #define INCR_PC (mi ++) /* increment program counter */ 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) tsleep(NULL, PPBPRI, "ppbdelay", mi->arg[0].i * (hz/1000)); 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 void ppcintr(void *arg) { struct ppc_data *ppc = arg; u_char ctr, ecr, str; /* * If we have any child interrupt handlers registered, let * them handle this interrupt. * * XXX: If DMA is in progress should we just complete that w/o * doing this? */ PPC_LOCK(ppc); if (ppc->ppc_intr_hook != NULL && ppc->ppc_intr_hook(ppc->ppc_intr_arg) == 0) { PPC_UNLOCK(ppc); return; } str = r_str(ppc); ctr = r_ctr(ppc); ecr = r_ecr(ppc); #if defined(PPC_DEBUG) && PPC_DEBUG > 1 printf("![%x/%x/%x]", ctr, ecr, str); #endif /* don't use ecp mode with IRQENABLE set */ if (ctr & IRQENABLE) { PPC_UNLOCK(ppc); return; } /* interrupts are generated by nFault signal * only in ECP mode */ if ((str & nFAULT) && (ppc->ppc_mode & PPB_ECP)) { /* check if ppc driver has programmed the * nFault interrupt */ if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { w_ecr(ppc, ecr | PPC_nFAULT_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; } else { /* shall be handled by underlying layers XXX */ PPC_UNLOCK(ppc); return; } } if (ppc->ppc_irqstat & PPC_IRQ_DMA) { /* disable interrupts (should be done by hardware though) */ w_ecr(ppc, ecr | PPC_SERVICE_INTR); ppc->ppc_irqstat &= ~PPC_IRQ_DMA; ecr = r_ecr(ppc); /* check if DMA completed */ if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { #ifdef PPC_DEBUG printf("a"); #endif /* stop DMA */ w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); ecr = r_ecr(ppc); if (ppc->ppc_dmastat == PPC_DMA_STARTED) { #ifdef PPC_DEBUG printf("d"); #endif ppc->ppc_dmadone(ppc); ppc->ppc_dmastat = PPC_DMA_COMPLETE; /* wakeup the waiting process */ wakeup(ppc); } } } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { /* classic interrupt I/O */ ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; } PPC_UNLOCK(ppc); return; }