vpoio.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 842 行 · 第 1/2 页

C
842
字号
	ppb_MS_exec(&vpo->vpo_dev, MS_OP_PUT, buffer, size, MS_UNKNOWN, &error);#if 0		/* XXX EPP 1.9 not implemented with microsequences */		else {			ppb_reset_epp_timeout(&vpo->vpo_dev);			ppb_wctr(&vpo->vpo_dev,				H_AUTO | H_SELIN | H_INIT | H_STROBE);			if (((long) buffer | size) & 0x03)				ppb_outsb_epp(&vpo->vpo_dev,						buffer, size);			else				ppb_outsl_epp(&vpo->vpo_dev,						buffer, size/4);			if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {				error = VP0_EPPDATA_TIMEOUT;				goto error;			}			ppb_wctr(&vpo->vpo_dev,				H_AUTO | H_nSELIN | H_INIT | H_STROBE);		}#endif	ppb_ecp_sync(&vpo->vpo_dev);	return (error);}/* * vpoio_instr() */static intvpoio_instr(struct vpoio_data *vpo, char *buffer, int size){	int error = 0;	ppb_MS_exec(&vpo->vpo_dev, MS_OP_GET, buffer, size, MS_UNKNOWN, &error);#if 0		/* XXX EPP 1.9 not implemented with microsequences */		else {			ppb_reset_epp_timeout(&vpo->vpo_dev);			ppb_wctr(&vpo->vpo_dev, PCD |				H_AUTO | H_SELIN | H_INIT | H_STROBE);			if (((long) buffer | size) & 0x03)				ppb_insb_epp(&vpo->vpo_dev,						buffer, size);			else				ppb_insl_epp(&vpo->vpo_dev,						buffer, size/4);			if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {				error = VP0_EPPDATA_TIMEOUT;				goto error;			}			ppb_wctr(&vpo->vpo_dev, PCD |				H_AUTO | H_nSELIN | H_INIT | H_STROBE);		}#endif	ppb_ecp_sync(&vpo->vpo_dev);	return (error);}static charvpoio_select(struct vpoio_data *vpo, int initiator, int target){	int ret;	struct ppb_microseq select_microseq[] = {		/* parameter list		 */		#define SELECT_TARGET		MS_PARAM(0, 1, MS_TYP_INT)		#define SELECT_INITIATOR	MS_PARAM(3, 1, MS_TYP_INT)		/* send the select command to the drive */		MS_DASS(MS_UNKNOWN),		MS_CASS(H_nAUTO | H_nSELIN |  H_INIT | H_STROBE),		MS_CASS( H_AUTO | H_nSELIN |  H_INIT | H_STROBE),		MS_DASS(MS_UNKNOWN),		MS_CASS( H_AUTO | H_nSELIN | H_nINIT | H_STROBE),		/* now, wait until the drive is ready */		MS_SET(VP0_SELTMO),/* loop: */	MS_BRSET(H_ACK, 3 /* ready */),		MS_DBRA(-1 /* loop */),/* error: */	MS_RET(1),/* ready: */	MS_RET(0)	};	/* initialize the select microsequence */	ppb_MS_init_msq(select_microseq, 2,			SELECT_TARGET, 1 << target,			SELECT_INITIATOR, 1 << initiator);					ppb_MS_microseq(&vpo->vpo_dev, select_microseq, &ret);	if (ret)		return (VP0_ESELECT_TIMEOUT);	return (0);}/* * vpoio_wait() * * H_SELIN must be low. * * XXX should be ported to microseq */static charvpoio_wait(struct vpoio_data *vpo, int tmo){	register int	k;	register char	r;#if 0	/* broken */	if (ppb_poll_device(&vpo->vpo_dev, 150, nBUSY, nBUSY, PPB_INTR))		return (0);	return (ppb_rstr(&vpo->vpo_dev) & 0xf0);#endif	/* XXX should be ported to microseq */	k = 0;	while (!((r = ppb_rstr(&vpo->vpo_dev)) & nBUSY) && (k++ < tmo))		;	/*	 * Return some status information.	 * Semantics :	0xc0 = ZIP wants more data	 *		0xd0 = ZIP wants to send more data	 *		0xe0 = ZIP wants command	 *		0xf0 = end of transfer, ZIP is sending status	 */	if (k < tmo)	  return (r & 0xf0);	return (0);			   /* command timed out */	}/* * vpoio_probe() * * Low level probe of vpo device * */struct ppb_device *vpoio_probe(struct ppb_data *ppb, struct vpoio_data *vpo){	/* ppbus dependent initialisation */	vpo->vpo_dev.id_unit = vpo->vpo_unit;	vpo->vpo_dev.name = "vpo";	vpo->vpo_dev.ppb = ppb;	/*	 * Initialize microsequence code	 */	INIT_TRIG_MICROSEQ;	/* now, try to initialise the drive */	if (vpoio_detect(vpo)) {		return (NULL);	}	return (&vpo->vpo_dev);}/* * vpoio_attach() * * Low level attachment of vpo device * */intvpoio_attach(struct vpoio_data *vpo){	int epp;	/*	 * Report ourselves	 */	printf("vpo%d: <Iomega VPI0 Parallel to SCSI interface> on ppbus %d\n",		vpo->vpo_dev.id_unit, vpo->vpo_dev.ppb->ppb_link->adapter_unit);	vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc(		sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT);	if (!vpo->vpo_nibble_inbyte_msq)		return (0);	bcopy((void *)nibble_inbyte_submicroseq,		(void *)vpo->vpo_nibble_inbyte_msq,		sizeof(nibble_inbyte_submicroseq));	INIT_NIBBLE_INBYTE_SUBMICROSEQ(vpo);	/*	 * Initialize mode dependent in/out microsequences	 */	ppb_request_bus(&vpo->vpo_dev, PPB_WAIT);	/* enter NIBBLE mode to configure submsq */	if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1) {		ppb_MS_GET_init(&vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);		ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq);	}	/* enter PS2 mode to configure submsq */	if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1) {		ppb_MS_GET_init(&vpo->vpo_dev, ps2_inbyte_submicroseq);		ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq);	}	epp = ppb_get_epp_protocol(&vpo->vpo_dev);	/* enter EPP mode to configure submsq */	if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) {		switch (epp) {		case EPP_1_9:			/* XXX EPP 1.9 support should be improved */		case EPP_1_7:			ppb_MS_GET_init(&vpo->vpo_dev, epp17_instr_body);			ppb_MS_PUT_init(&vpo->vpo_dev, epp17_outstr_body);			break;		default:			panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,				epp);		}	}	/* try to enter EPP or PS/2 mode, NIBBLE otherwise */	if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) {		switch (epp) {		case EPP_1_9:			printf("vpo%d: EPP 1.9 mode\n", vpo->vpo_unit);			break;		case EPP_1_7:			printf("vpo%d: EPP 1.7 mode\n", vpo->vpo_unit);			break;		default:			panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,				epp);		}	} else if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1)		printf("vpo%d: PS2 mode\n", vpo->vpo_unit);	else if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1)		printf("vpo%d: NIBBLE mode\n", vpo->vpo_unit);	else {		printf("vpo%d: can't enter NIBBLE, PS2 or EPP mode\n",			vpo->vpo_unit);		ppb_release_bus(&vpo->vpo_dev);		free(vpo->vpo_nibble_inbyte_msq, M_DEVBUF);		return (0);	}	ppb_release_bus(&vpo->vpo_dev);	return (1);}/* * vpoio_reset_bus() * */intvpoio_reset_bus(struct vpoio_data *vpo){	/* first, connect to the drive */	if (vpoio_connect(vpo, PPB_WAIT|PPB_INTR) || !vpoio_in_disk_mode(vpo)) {#ifdef VP0_DEBUG		printf("%s: not in disk mode!\n", __FUNCTION__);#endif		/* release ppbus */		vpoio_disconnect(vpo);		return (1);	}	/* reset the SCSI bus */	vpoio_reset(vpo);	/* then disconnect */	vpoio_disconnect(vpo);	return (0);}/* * vpoio_do_scsi() * * Send an SCSI command * */int vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,		int clen, char *buffer, int blen, int *result, int *count,		int *ret){	register char r;	char l, h = 0;	int len, error = 0;	register int k;	/*	 * enter disk state, allocate the ppbus	 *	 * XXX	 * Should we allow this call to be interruptible?	 * The only way to report the interruption is to return	 * EIO do upper SCSI code :^(	 */	if ((error = vpoio_connect(vpo, PPB_WAIT|PPB_INTR)))		return (error);	if (!vpoio_in_disk_mode(vpo)) {		*ret = VP0_ECONNECT; goto error;	}	if ((*ret = vpoio_select(vpo,host,target)))		goto error;	/*	 * Send the command ...	 *	 * set H_SELIN low for vpoio_wait().	 */	ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);	for (k = 0; k < clen; k++) {		if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) {			*ret = VP0_ECMD_TIMEOUT;			goto error;		}		if (vpoio_outstr(vpo, &command[k], 1)) {			*ret = VP0_EPPDATA_TIMEOUT;			goto error;		}	}	/* 	 * Completion ... 	 */	*count = 0;	for (;;) {		if (!(r = vpoio_wait(vpo, VP0_LOW_SPINTMO))) {			*ret = VP0_ESTATUS_TIMEOUT; goto error;		}		/* stop when the ZIP wants to send status */		if (r == (char)0xf0)			break;		if (*count >= blen) {			*ret = VP0_EDATA_OVERFLOW;			goto error;		}		/* if in EPP mode or writing bytes, try to transfer a sector		 * otherwise, just send one byte		 */		if (PPB_IN_EPP_MODE(&vpo->vpo_dev) || r == (char)0xc0)			len = (((blen - *count) >= VP0_SECTOR_SIZE)) ?				VP0_SECTOR_SIZE : 1;		else			len = 1;		/* ZIP wants to send data? */		if (r == (char)0xc0)			error = vpoio_outstr(vpo, &buffer[*count], len);		else			error = vpoio_instr(vpo, &buffer[*count], len);		if (error) {			*ret = error;			goto error;		}		*count += len;	}	if (vpoio_instr(vpo, &l, 1)) {		*ret = VP0_EOTHER; goto error;	}	/* check if the ZIP wants to send more status */	if (vpoio_wait(vpo, VP0_FAST_SPINTMO) == (char)0xf0)		if (vpoio_instr(vpo, &h, 1)) {			*ret = VP0_EOTHER+2; goto error;		}	*result = ((int) h << 8) | ((int) l & 0xff);error:	/* return to printer state, release the ppbus */	vpoio_disconnect(vpo);	return (0);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?