vpoio.c

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

C
842
字号
/*- * Copyright (c) 1998 Nicolas Souchu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	$Id: vpoio.c,v 1.5 1999/01/10 12:04:55 nsouch Exp $ * */#ifdef KERNEL#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <sys/buf.h>#include <machine/clock.h>#endif	/* KERNEL */#ifdef	KERNEL#include <sys/kernel.h>#endif /*KERNEL */#include "opt_vpo.h"#include <dev/ppbus/ppbconf.h>#include <dev/ppbus/ppb_msq.h>#include <dev/ppbus/vpoio.h>/* * The driver pools the drive. We may add a timeout queue to avoid * active polling on nACK. I've tried this but it leads to unreliable * transfers */#define VP0_SELTMO		5000	/* select timeout */#define VP0_FAST_SPINTMO	500000	/* wait status timeout */#define VP0_LOW_SPINTMO		5000000	/* wait status timeout *//* * Actually, VP0 timings are more accurate (about few 16MHZ cycles), * but succeeding in respecting such timings leads to architecture * dependent considerations. */#define VP0_PULSE		1#define VP0_SECTOR_SIZE	512#define VP0_BUFFER_SIZE	0x12000#define n(flags) (~(flags) & (flags))/* * VP0 connections. */#define H_AUTO		n(AUTOFEED)#define H_nAUTO		AUTOFEED#define H_STROBE	n(STROBE)#define H_nSTROBE	STROBE#define H_BSY		n(nBUSY)#define H_nBSY		nBUSY#define H_SEL		SELECT#define H_nSEL		n(SELECT)#define H_ERR		PERROR#define H_nERR		n(PERROR)#define H_ACK		nACK#define H_nACK		n(nACK)#define H_FLT		nFAULT#define H_nFLT		n(nFAULT)#define H_SELIN		n(SELECTIN)#define H_nSELIN	SELECTIN#define H_INIT		nINIT#define H_nINIT		n(nINIT)/* * Microcode to execute very fast I/O sequences at the lowest bus level. *//* call this macro to initialize connect/disconnect microsequences */#define INIT_TRIG_MICROSEQ {						\	int i;								\	for (i=1; i <= 7; i+=2) {					\		disconnect_microseq[i].arg[2] = (void *)d_pulse;	\		connect_epp_microseq[i].arg[2] = 			\		connect_spp_microseq[i].arg[2] = (void *)c_pulse;	\	}								\}#define trig_d_pulse MS_TRIG(MS_REG_CTR,5,MS_UNKNOWN /* d_pulse */)static char d_pulse[] = {	 H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,	H_nAUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE,	 H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,	 H_AUTO |  H_SELIN | H_INIT | H_STROBE, VP0_PULSE,	 H_AUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE};#define trig_c_pulse MS_TRIG(MS_REG_CTR,5,MS_UNKNOWN /* c_pulse */)static char c_pulse[] = {	 H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,	 H_AUTO |  H_SELIN | H_INIT | H_STROBE, 0,	H_nAUTO |  H_SELIN | H_INIT | H_STROBE, VP0_PULSE,	 H_AUTO |  H_SELIN | H_INIT | H_STROBE, 0,	 H_AUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE};static struct ppb_microseq disconnect_microseq[] = {	  MS_DASS(0x0), trig_d_pulse, MS_DASS(0x3c), trig_d_pulse,	  MS_DASS(0x20), trig_d_pulse, MS_DASS(0xf), trig_d_pulse, MS_RET(0)};static struct ppb_microseq connect_epp_microseq[] = {	  MS_DASS(0x0), trig_c_pulse, MS_DASS(0x3c), trig_c_pulse,	  MS_DASS(0x20), trig_c_pulse, MS_DASS(0xcf), trig_c_pulse, MS_RET(0)};static struct ppb_microseq connect_spp_microseq[] = {	  MS_DASS(0x0), trig_c_pulse, MS_DASS(0x3c), trig_c_pulse,	  MS_DASS(0x20), trig_c_pulse, MS_DASS(0x8f), trig_c_pulse, MS_RET(0)};/* * nibble_inbyte_hook() * * Formats high and low nibble into a character */static intnibble_inbyte_hook (void *p, char *ptr){	struct vpo_nibble *s = (struct vpo_nibble *)p;	/* increment the buffer pointer */	*ptr++ = ((s->l >> 4) & 0x0f) + (s->h & 0xf0);	return (0);}/* * Macro used to initialize each vpoio_data structure during * low level attachment * * XXX should be converted to ppb_MS_init_msq() */#define INIT_NIBBLE_INBYTE_SUBMICROSEQ(vpo) {		    	\	(vpo)->vpo_nibble_inbyte_msq[2].arg[2].p =		\			(void *)&(vpo)->vpo_nibble.h;		\	(vpo)->vpo_nibble_inbyte_msq[4].arg[2].p =		\			(void *)&(vpo)->vpo_nibble.l;		\	(vpo)->vpo_nibble_inbyte_msq[5].arg[0].f =		\			nibble_inbyte_hook;			\	(vpo)->vpo_nibble_inbyte_msq[5].arg[1].p =		\			(void *)&(vpo)->vpo_nibble;		\}/* * This is the sub-microseqence for MS_GET in NIBBLE mode * Retrieve the two nibbles and call the C function to generate the character * and store it in the buffer (see nibble_inbyte_hook()) */static struct ppb_microseq nibble_inbyte_submicroseq[] = {/* loop: */	  MS_CASS( H_AUTO | H_SELIN | H_INIT | H_STROBE),	  MS_DELAY(VP0_PULSE),	  MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* high nibble */),	  MS_CASS(H_nAUTO | H_SELIN | H_INIT | H_STROBE),	  MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* low nibble */),	  /* do a C call to format the received nibbles */	  MS_C_CALL(MS_UNKNOWN /* C hook */, MS_UNKNOWN /* param */),	  MS_DBRA(-6 /* loop */),	  MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_RET(0)};/* * This is the sub-microseqence for MS_GET in PS2 mode */static struct ppb_microseq ps2_inbyte_submicroseq[] = {	  MS_CASS(PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE),/* loop: */	  MS_RFETCH_P(1, MS_REG_DTR, MS_FETCH_ALL),	  MS_CASS(PCD | H_nAUTO | H_SELIN | H_INIT | H_nSTROBE),	  MS_CASS(PCD |  H_AUTO | H_SELIN | H_INIT | H_nSTROBE),	  MS_DBRA(-3 /* loop */),	  MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_RET(0)};/* * This is the sub-microsequence for MS_PUT in both NIBBLE and PS2 modes */static struct ppb_microseq spp_outbyte_submicroseq[] = {/* loop: */	  MS_RASSERT_P(1, MS_REG_DTR), 	  MS_CASS(H_nAUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_DELAY(VP0_PULSE),	  MS_DBRA(-4 /* loop */),	  /* return from the put call */	  MS_RET(0)};/* EPP 1.7 microsequences, ptr and len set at runtime */static struct ppb_microseq epp17_outstr_body[] = {	  MS_CASS(H_AUTO | H_SELIN | H_INIT | H_STROBE),/* loop: */	  MS_RASSERT_P(1, MS_REG_EPP), 	  MS_BRSET(TIMEOUT, 4 /* error */),	/* EPP timeout? */	  MS_DBRA(-2 /* loop */),	  MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_RET(0),/* error: */	  MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_RET(1)};static struct ppb_microseq epp17_instr_body[] = {	  MS_CASS(PCD | H_AUTO | H_SELIN | H_INIT | H_STROBE),/* loop: */	  MS_RFETCH_P(1, MS_REG_EPP, MS_FETCH_ALL), 	  MS_BRSET(TIMEOUT, 4 /* error */),	/* EPP timeout? */	  MS_DBRA(-2 /* loop */),	  MS_CASS(PCD | H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_RET(0),/* error: */	  MS_CASS(PCD | H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_RET(1)};static struct ppb_microseq in_disk_mode[] = {	  MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_CASS(H_nAUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_BRCLEAR(H_FLT, 4 /* error */),	  MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),	  MS_BRSET(H_FLT, 2 /* error */),	  MS_RET(1),/* error: */	  MS_RET(0)};static intvpoio_disconnect(struct vpoio_data *vpo){	int ret;	ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq, &ret);	return (ppb_release_bus(&vpo->vpo_dev));}/* * how	: PPB_WAIT or PPB_DONTWAIT */static intvpoio_connect(struct vpoio_data *vpo, int how){	int error;	int ret;	if ((error = ppb_request_bus(&vpo->vpo_dev, how))) {#ifdef VP0_DEBUG		printf("%s: can't request bus!\n", __FUNCTION__);#endif		return error;	}	if (PPB_IN_EPP_MODE(&vpo->vpo_dev))		ppb_MS_microseq(&vpo->vpo_dev, connect_epp_microseq, &ret);	else		ppb_MS_microseq(&vpo->vpo_dev, connect_spp_microseq, &ret);	return (0);}/* * vpoio_reset() * * SCSI reset signal, the drive must be in disk mode */static voidvpoio_reset (struct vpoio_data *vpo){	int ret;	struct ppb_microseq reset_microseq[] = {		#define INITIATOR	MS_PARAM(0, 1, MS_TYP_INT)		MS_DASS(MS_UNKNOWN),		MS_CASS(H_AUTO | H_nSELIN | H_nINIT | H_STROBE),		MS_DELAY(25),		MS_CASS(H_AUTO | H_nSELIN |  H_INIT | H_STROBE),		MS_RET(0)	};	ppb_MS_init_msq(reset_microseq, 1, INITIATOR, 1 << VP0_INITIATOR);	ppb_MS_microseq(&vpo->vpo_dev, reset_microseq, &ret);	return;}/* * vpoio_in_disk_mode() */static intvpoio_in_disk_mode(struct vpoio_data *vpo){	int ret;	ppb_MS_microseq(&vpo->vpo_dev, in_disk_mode, &ret);	return (ret);}/* * vpoio_detect() * * Detect and initialise the VP0 adapter. */static intvpoio_detect(struct vpoio_data *vpo){	int error, ret;	/* allocate the bus, then apply microsequences */	if ((error = ppb_request_bus(&vpo->vpo_dev, PPB_DONTWAIT)))                return (error);	ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq, &ret);	if (PPB_IN_EPP_MODE(&vpo->vpo_dev))		ppb_MS_microseq(&vpo->vpo_dev, connect_epp_microseq, &ret);	else		ppb_MS_microseq(&vpo->vpo_dev, connect_spp_microseq, &ret);	ppb_MS_microseq(&vpo->vpo_dev, in_disk_mode, &ret);	if (!ret) {		/* try spp mode (maybe twice or because previous mode was PS2)		 * NIBBLE mode will be restored on next transfers if detection		 * succeed		 */		ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE);		ppb_MS_microseq(&vpo->vpo_dev, connect_spp_microseq, &ret);		ppb_MS_microseq(&vpo->vpo_dev, in_disk_mode, &ret);		if (!ret) {			if (bootverbose)				printf("vpo%d: can't connect to the drive\n",					vpo->vpo_unit);			/* disconnect and release the bus */			ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq,					&ret);			goto error;		}	}	/* send SCSI reset signal */	vpoio_reset(vpo);	ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq, &ret);	/* ensure we are disconnected or daisy chained peripheral 	 * may cause serious problem to the disk */	ppb_MS_microseq(&vpo->vpo_dev, in_disk_mode, &ret);	if (ret) {		if (bootverbose)			printf("vpo%d: can't disconnect from the drive\n",				vpo->vpo_unit);		goto error;	}	ppb_release_bus(&vpo->vpo_dev);	return (0);error:	ppb_release_bus(&vpo->vpo_dev);	return (VP0_EINITFAILED);}/* * vpoio_outstr() */static intvpoio_outstr(struct vpoio_data *vpo, char *buffer, int size){	int error = 0;

⌨️ 快捷键说明

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