immio.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 805 行 · 第 1/2 页
C
805 行
/*- * 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: immio.c,v 1.5 1999/01/10 12:04:54 nsouch Exp $ * *//* * Iomega ZIP+ Matchmaker Parallel Port Interface driver * * Thanks to David Campbell work on the Linux driver and the Iomega specs * Thanks to Thiebault Moeglin for the drive */#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>#include <dev/ppbus/ppb_1284.h>#define VP0_SELTMO 5000 /* select timeout */#define VP0_FAST_SPINTMO 500000 /* wait status timeout */#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */#define VP0_SECTOR_SIZE 512/* * Microcode to execute very fast I/O sequences at the lowest bus level. */#define SELECT_TARGET MS_PARAM(6, 1, MS_TYP_CHA)#define DECLARE_SELECT_MICROSEQUENCE \struct ppb_microseq select_microseq[] = { \ MS_CASS(0xc), \ /* first, check there is nothing holding onto the bus */ \ MS_SET(VP0_SELTMO), \/* _loop: */ \ MS_BRCLEAR(0x8, 3 /* _ready */), \ MS_DBRA(-1 /* _loop */), \ MS_RET(2), /* bus busy */ \/* _ready: */ \ MS_CASS(0x4), \ MS_DASS(MS_UNKNOWN /* 0x80 | 1 << target */), \ MS_DELAY(1), \ MS_CASS(0xc), \ MS_CASS(0xd), \ /* now, wait until the drive is ready */ \ MS_SET(VP0_SELTMO), \/* loop: */ \ MS_BRSET(0x8, 4 /* ready */), \ MS_DBRA(-1 /* loop */), \/* error: */ \ MS_CASS(0xc), \ MS_RET(VP0_ESELECT_TIMEOUT), \/* ready: */ \ MS_CASS(0xc), \ MS_RET(0) \}static struct ppb_microseq transfer_epilog[] = { MS_CASS(0x4), MS_CASS(0xc), MS_CASS(0xe), MS_CASS(0x4), MS_RET(0)};#define CPP_S1 MS_PARAM(10, 2, MS_TYP_PTR)#define CPP_S2 MS_PARAM(13, 2, MS_TYP_PTR)#define CPP_S3 MS_PARAM(16, 2, MS_TYP_PTR)#define CPP_PARAM MS_PARAM(17, 1, MS_TYP_CHA)#define DECLARE_CPP_MICROSEQ \struct ppb_microseq cpp_microseq[] = { \ MS_CASS(0x0c), MS_DELAY(2), \ MS_DASS(0xaa), MS_DELAY(10), \ MS_DASS(0x55), MS_DELAY(10), \ MS_DASS(0x00), MS_DELAY(10), \ MS_DASS(0xff), MS_DELAY(10), \ MS_RFETCH(MS_REG_STR, 0xb8, MS_UNKNOWN /* &s1 */), \ MS_DASS(0x87), MS_DELAY(10), \ MS_RFETCH(MS_REG_STR, 0xb8, MS_UNKNOWN /* &s2 */), \ MS_DASS(0x78), MS_DELAY(10), \ MS_RFETCH(MS_REG_STR, 0x38, MS_UNKNOWN /* &s3 */), \ MS_DASS(MS_UNKNOWN /* param */), \ MS_DELAY(2), \ MS_CASS(0x0c), MS_DELAY(10), \ MS_CASS(0x0d), MS_DELAY(2), \ MS_CASS(0x0c), MS_DELAY(10), \ MS_DASS(0xff), MS_DELAY(10), \ MS_RET(0) \}#define NEGOCIATED_MODE MS_PARAM(2, 1, MS_TYP_CHA)#define DECLARE_NEGOCIATE_MICROSEQ \static struct ppb_microseq negociate_microseq[] = { \ MS_CASS(0x4), \ MS_DELAY(5), \ MS_DASS(MS_UNKNOWN /* mode */), \ MS_DELAY(100), \ MS_CASS(0x6), \ MS_DELAY(5), \ MS_BRSET(0x20, 6 /* continue */), \ MS_DELAY(5), \ MS_CASS(0x7), \ MS_DELAY(5), \ MS_CASS(0x6), \ MS_RET(VP0_ENEGOCIATE), \/* continue: */ \ MS_DELAY(5), \ MS_CASS(0x7), \ MS_DELAY(5), \ MS_CASS(0x6), \ MS_RET(0) \}static struct ppb_microseq reset_microseq[] = { MS_CASS(0x04), MS_DASS(0x40), MS_DELAY(1), MS_CASS(0x0c), MS_CASS(0x0d), MS_DELAY(50), MS_CASS(0x0c), MS_CASS(0x04), 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[6].arg[2].p = \ (void *)&(vpo)->vpo_nibble.h; \ (vpo)->vpo_nibble_inbyte_msq[3].arg[2].p = \ (void *)&(vpo)->vpo_nibble.l; \ (vpo)->vpo_nibble_inbyte_msq[9].arg[0].f = \ nibble_inbyte_hook; \ (vpo)->vpo_nibble_inbyte_msq[9].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[] = { MS_CASS(0x4),/* loop: */ MS_CASS(0x6), MS_DELAY(1), MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* low nibble */), MS_CASS(0x5), MS_DELAY(1), MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* high nibble */), MS_CASS(0x4), MS_DELAY(1), /* do a C call to format the received nibbles */ MS_C_CALL(MS_UNKNOWN /* C hook */, MS_UNKNOWN /* param */), MS_DBRA(-6 /* loop */), MS_RET(0)};/* * This is the sub-microseqence for MS_GET in PS2 mode */static struct ppb_microseq ps2_inbyte_submicroseq[] = { MS_CASS(0x4),/* loop: */ MS_CASS(PCD | 0x6), MS_RFETCH_P(1, MS_REG_DTR, MS_FETCH_ALL), MS_CASS(PCD | 0x5), MS_DBRA(-3 /* loop */), MS_RET(0)};/* * This is the sub-microsequence for MS_PUT in both NIBBLE and PS2 modes */static struct ppb_microseq spp_outbyte_submicroseq[] = { MS_CASS(0x4),/* loop: */ MS_RASSERT_P(1, MS_REG_DTR), MS_CASS(0x5), MS_DBRA(1), /* decrement counter */ MS_RASSERT_P(1, MS_REG_DTR), MS_CASS(0x0), MS_DBRA(-5 /* loop */), /* return from the put call */ MS_CASS(0x4), MS_RET(0)};/* EPP 1.7 microsequences, ptr and len set at runtime */static struct ppb_microseq epp17_outstr[] = { MS_CASS(0x4), MS_RASSERT_P(MS_ACCUM, MS_REG_EPP), MS_CASS(0xc), MS_RET(0),};static struct ppb_microseq epp17_instr[] = { MS_CASS(PCD | 0x4), MS_RFETCH_P(MS_ACCUM, MS_REG_EPP, MS_FETCH_ALL), MS_CASS(PCD | 0xc), MS_RET(0),};static intimm_disconnect(struct vpoio_data *vpo, int *connected, int release_bus){ DECLARE_CPP_MICROSEQ; char s1, s2, s3; int ret; /* all should be ok */ if (connected) *connected = 0; ppb_MS_init_msq(cpp_microseq, 4, CPP_S1, (void *)&s1, CPP_S2, (void *)&s2, CPP_S3, (void *)&s3, CPP_PARAM, 0x30); ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x38)) { if (bootverbose) printf("imm%d: (disconnect) s1=0x%x s2=0x%x, s3=0x%x\n", vpo->vpo_unit, s1 & 0xff, s2 & 0xff, s3 & 0xff); if (connected) *connected = VP0_ECONNECT; } if (release_bus) return (ppb_release_bus(&vpo->vpo_dev)); else return (0);}/* * how : PPB_WAIT or PPB_DONTWAIT */static intimm_connect(struct vpoio_data *vpo, int how, int *disconnected, int request_bus){ DECLARE_CPP_MICROSEQ; char s1, s2, s3; int error; int ret; /* all should be ok */ if (disconnected) *disconnected = 0; if (request_bus) if ((error = ppb_request_bus(&vpo->vpo_dev, how))) return (error); ppb_MS_init_msq(cpp_microseq, 3, CPP_S1, (void *)&s1, CPP_S2, (void *)&s2, CPP_S3, (void *)&s3); /* select device 0 in compatible mode */ ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0xe0); ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); /* disconnect all devices */ ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0x30); ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0x28); else ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0xe0); ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret); if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x30)) { if (bootverbose) printf("imm%d: (connect) s1=0x%x s2=0x%x, s3=0x%x\n", vpo->vpo_unit, s1 & 0xff, s2 & 0xff, s3 & 0xff); if (disconnected) *disconnected = VP0_ECONNECT; } return (0);}/* * imm_detect() * * Detect and initialise the VP0 adapter. */static intimm_detect(struct vpoio_data *vpo){ int error; if ((error = ppb_request_bus(&vpo->vpo_dev, PPB_DONTWAIT))) return (error); /* disconnect the drive, keep the bus */ imm_disconnect(vpo, NULL, 0); /* we already have the bus, just connect */ imm_connect(vpo, PPB_DONTWAIT, &error, 0); if (error) { if (bootverbose) printf("imm%d: can't connect to the drive\n", vpo->vpo_unit); goto error; } /* send SCSI reset signal */ ppb_MS_microseq(&vpo->vpo_dev, reset_microseq, NULL); /* release the bus now */ imm_disconnect(vpo, &error, 1); /* ensure we are disconnected or daisy chained peripheral * may cause serious problem to the disk */ if (error) { if (bootverbose) printf("imm%d: can't disconnect from the drive\n", vpo->vpo_unit); goto error; } return (0);error: ppb_release_bus(&vpo->vpo_dev); return (VP0_EINITFAILED);}/*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?