Beispiel #1
0
/*
 * ppc_ecp_sync()		XXX
 */
int
ppc_ecp_sync(device_t dev)
{
	int i, r;
	struct ppc_data *ppc = DEVTOSOFTC(dev);

	PPC_ASSERT_LOCKED(ppc);
	if (!(ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_dtm & PPB_ECP))
		return 0;

	r = r_ecr(ppc);
	if ((r & 0xe0) != PPC_ECR_EPP)
		return 0;

	for (i = 0; i < 100; i++) {
		r = r_ecr(ppc);
		if (r & 0x1)
			return 0;
		DELAY(100);
	}

	device_printf(dev, "ECP sync failed as data still present in FIFO.\n");

	return 0;
}
Beispiel #2
0
int
ppc_write_ivar(device_t bus, device_t dev, int index, uintptr_t val)
{
	struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus);

	switch (index) {
	case PPC_IVAR_INTR_HANDLER:
		PPC_ASSERT_LOCKED(ppc);
		if (dev != ppc->ppbus)
			return (EINVAL);
		if (val == 0) {
			ppc->ppc_intr_hook = NULL;
			break;
		}
		if (ppc->ppc_intr_hook != NULL)
			return (EBUSY);
		ppc->ppc_intr_hook = (void *)val;
		ppc->ppc_intr_arg = device_get_softc(dev);
		break;
	default:
		return (ENOENT);
	}

	return (0);
}
Beispiel #3
0
int
ppc_reset_epp(device_t dev)
{
	struct ppc_data *ppc = DEVTOSOFTC(dev);

	PPC_ASSERT_LOCKED(ppc);
	ppc_reset_epp_timeout(ppc);

	return 0;
}
Beispiel #4
0
int
ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val)
{
	struct ppc_data *ppc = (struct ppc_data *)device_get_softc(bus);

	switch (index) {
	case PPC_IVAR_EPP_PROTO:
		PPC_ASSERT_LOCKED(ppc);
		*val = (u_long)ppc->ppc_epp;
		break;
	case PPC_IVAR_LOCK:
		*val = (uintptr_t)&ppc->ppc_lock;
		break;
	default:
		return (ENOENT);
	}

	return (0);
}
Beispiel #5
0
int
ppc_setmode(device_t dev, int mode)
{
	struct ppc_data *ppc = DEVTOSOFTC(dev);

	PPC_ASSERT_LOCKED(ppc);
	switch (ppc->ppc_type) {
	case PPC_TYPE_SMCLIKE:
		return (ppc_smclike_setmode(ppc, mode));
		break;

	case PPC_TYPE_GENERIC:
	default:
		return (ppc_generic_setmode(ppc, mode));
		break;
	}

	/* not reached */
	return (ENXIO);
}
Beispiel #6
0
/*
 * Call this function if you want to send data in any advanced mode
 * of your parallel port: FIFO, DMA
 *
 * If what you want is not possible (no ECP, no DMA...),
 * EINVAL is returned
 */
int
ppc_isa_write(device_t dev, char *buf, int len, int how)
{
	struct ppc_data *ppc = device_get_softc(dev);
	char ecr, ecr_sav, ctr, ctr_sav;
	int error = 0;
	int spin;

	PPC_ASSERT_LOCKED(ppc);
	if (!(ppc->ppc_avm & PPB_ECP))
		return (EINVAL);
	if (ppc->ppc_dmachan == 0)
		return (EINVAL);

#ifdef PPC_DEBUG
	printf("w");
#endif

	ecr_sav = r_ecr(ppc);
	ctr_sav = r_ctr(ppc);

	/*
	 * Send buffer with DMA, FIFO and interrupts
	 */

	/* byte mode, no intr, no DMA, dir=0, flush fifo */
	ecr = PPC_ECR_STD | PPC_DISABLE_INTR;
	w_ecr(ppc, ecr);

	/* disable nAck interrupts */
	ctr = r_ctr(ppc);
	ctr &= ~IRQENABLE;
	w_ctr(ppc, ctr);

	ppc->ppc_dmaflags = 0;
	ppc->ppc_dmaddr = (caddr_t)buf;
	ppc->ppc_dmacnt = (u_int)len;

	switch (ppc->ppc_mode) {
	case PPB_COMPATIBLE:
		/* compatible mode with FIFO, no intr, DMA, dir=0 */
		ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
		break;
	case PPB_ECP:
		ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
		break;
	default:
		error = EINVAL;
		goto error;
	}

	w_ecr(ppc, ecr);
	ecr = r_ecr(ppc);

	ppc->ppc_dmastat = PPC_DMA_INIT;

	/* enable interrupts */
	ecr &= ~PPC_SERVICE_INTR;
	ppc->ppc_irqstat = PPC_IRQ_DMA;
	w_ecr(ppc, ecr);

	isa_dmastart(ppc->ppc_dmaflags, ppc->ppc_dmaddr, ppc->ppc_dmacnt,
		     ppc->ppc_dmachan);
	ppc->ppc_dmastat = PPC_DMA_STARTED;

#ifdef PPC_DEBUG
	printf("s%d", ppc->ppc_dmacnt);
#endif

	/* Wait for the DMA completed interrupt. We hope we won't
	 * miss it, otherwise a signal will be necessary to unlock the
	 * process.
	 */
	do {
		/* release CPU */
		error = mtx_sleep(ppc, &ppc->ppc_lock, PPBPRI | PCATCH,
		    "ppcdma", 0);
	} while (error == EWOULDBLOCK);

	if (error) {
#ifdef PPC_DEBUG
		printf("i");
#endif
		/* stop DMA */
		isa_dmadone(ppc->ppc_dmaflags, ppc->ppc_dmaddr,
			    ppc->ppc_dmacnt, ppc->ppc_dmachan);

		/* no dma, no interrupt, flush the fifo */
		w_ecr(ppc, PPC_ECR_RESET);

		ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
		goto error;
	}

	/* wait for an empty fifo */
	while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {

		for (spin=100; spin; spin--)
			if (r_ecr(ppc) & PPC_FIFO_EMPTY)
				goto fifo_empty;
#ifdef PPC_DEBUG
		printf("Z");
#endif
		error = mtx_sleep(ppc, &ppc->ppc_lock, PPBPRI | PCATCH,
		    "ppcfifo", hz / 100);
		if (error != EWOULDBLOCK) {
#ifdef PPC_DEBUG
			printf("I");
#endif
			/* no dma, no interrupt, flush the fifo */
			w_ecr(ppc, PPC_ECR_RESET);

			ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
			error = EINTR;
			goto error;
		}
	}

fifo_empty:
	/* no dma, no interrupt, flush the fifo */
	w_ecr(ppc, PPC_ECR_RESET);

error:
	/* PDRQ must be kept unasserted until nPDACK is
	 * deasserted for a minimum of 350ns (SMC datasheet)
	 *
	 * Consequence may be a FIFO that never empty
	 */
	DELAY(1);

	w_ecr(ppc, ecr_sav);
	w_ctr(ppc, ctr_sav);
	return (error);
}
Beispiel #7
0
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 */
}
Beispiel #8
0
/*
 * 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 */
}