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 + -
显示快捷键?