⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wdc.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*      $OpenBSD: wdc.c,v 1.16 2000/04/10 07:06:14 csapuntz Exp $     *//*	$NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ *//* * Copyright (c) 1998 Manuel Bouyer.  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. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *  This product includes software developed by Manuel Bouyer. * 4. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. *//*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum, by Onno van der Linden and by Manuel Bouyer. * * 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. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *        This product includes software developed by the NetBSD *        Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its *    contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. *//* * CODE UNTESTED IN THE CURRENT REVISION: *    */#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/conf.h>#include <sys/buf.h>#include <sys/device.h>#include <sys/malloc.h>#include <sys/syslog.h>#include <sys/proc.h>#include <vm/vm.h>#include <machine/intr.h>#include <machine/bus.h>#include <dev/ata/atavar.h>#include <dev/ata/atareg.h>#include <dev/ic/wdcreg.h>#include <dev/ic/wdcvar.h>#ifndef PMON#include "atapiscsi.h"#endif#define WDCDELAY  100 /* 100 microseconds */#define WDCNDELAY_RST (WDC_RESET_WAIT * 1000 / WDCDELAY)#if 0/* If you enable this, it will report any delays more than WDCDELAY * N long. */#define WDCNDELAY_DEBUG	50#endifLIST_HEAD(xfer_free_list, wdc_xfer) xfer_free_list;#ifndef PMONstatic void  __wdcerror	  __P((struct channel_softc*, char *));#endifstatic int   __wdcwait_reset  __P((struct channel_softc *, int));void  __wdccommand_done __P((struct channel_softc *, struct wdc_xfer *));void  __wdccommand_start __P((struct channel_softc *, struct wdc_xfer *));	int   __wdccommand_intr __P((struct channel_softc *, struct wdc_xfer *, int));int   wdprint __P((void *, const char *));void  wdc_kill_pending __P((struct channel_softc *));#define DEBUG_INTR   0x01#define DEBUG_XFERS  0x02#define DEBUG_STATUS 0x04#define DEBUG_FUNCS  0x08#define DEBUG_PROBE  0x10#define DEBUG_STATUSX 0x20#define DEBUG_SDRIVE 0x40#define DEBUG_DETACH 0x80#ifdef WDCDEBUGint wdcdebug_mask = 0;int wdc_nxfer = 0;#define WDCDEBUG_PRINT(args, level)  if (wdcdebug_mask & (level)) printf args#else#define WDCDEBUG_PRINT(args, level)#endifint at_poll = AT_POLL;u_int8_t wdc_default_read_reg __P((struct channel_softc *, enum wdc_regs));void wdc_default_write_reg __P((struct channel_softc *, enum wdc_regs, u_int8_t));void wdc_default_read_raw_multi_2 __P((struct channel_softc *,     void *, unsigned int));void wdc_default_write_raw_multi_2 __P((struct channel_softc *,     void *, unsigned int));void wdc_default_read_raw_multi_4 __P((struct channel_softc *,     void *, unsigned int));void wdc_default_write_raw_multi_4 __P((struct channel_softc *,     void *, unsigned int));struct channel_softc_vtbl wdc_default_vtbl = {	wdc_default_read_reg,	wdc_default_write_reg,	wdc_default_read_raw_multi_2,	wdc_default_write_raw_multi_2,	wdc_default_read_raw_multi_4,	wdc_default_write_raw_multi_4};u_int8_twdc_default_read_reg(chp, reg)	struct channel_softc *chp;	enum wdc_regs reg;{	u_int8_t rv;#ifdef DIAGNOSTIC		if (reg & _WDC_WRONLY) {		printf ("wdc_default_read_reg: reading from a write-only register %d\n", reg);	}#endif	if (reg & _WDC_AUX) 		rv = bus_space_read_1(chp->ctl_iot, chp->ctl_ioh,		    reg & _WDC_REGMASK);	else		rv = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,		    reg & _WDC_REGMASK);	return(rv);}voidwdc_default_write_reg(chp, reg, val)	struct channel_softc *chp;	enum wdc_regs reg;	u_int8_t val;{#ifdef DIAGNOSTIC		if (reg & _WDC_RDONLY) {		printf ("wdc_default_write_reg: writing to a read-only register %d\n", reg);	}#endif	if (reg & _WDC_AUX) 		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh,		    reg & _WDC_REGMASK, val);	else		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,		    reg & _WDC_REGMASK, val);}voidwdc_default_read_raw_multi_2(chp, data, nbytes)	struct channel_softc *chp;	void *data;	unsigned int nbytes;{	if (data == NULL) {		int i;		for (i = 0; i < nbytes; i += 2) {			bus_space_read_2(chp->cmd_iot, chp->cmd_ioh, 0);		}		return;	}	bus_space_read_raw_multi_2(chp->cmd_iot, chp->cmd_ioh, 0, 	    data, nbytes);	return;}voidwdc_default_write_raw_multi_2(chp, data, nbytes)	struct channel_softc *chp;	void *data;	unsigned int nbytes;{	if (data == NULL) {		int i;		for (i = 0; i < nbytes; i += 2) {			bus_space_write_2(chp->cmd_iot, chp->cmd_ioh, 0, 0);		}		return;	}	bus_space_write_raw_multi_2(chp->cmd_iot, chp->cmd_ioh, 0, 	    data, nbytes);	return;}voidwdc_default_write_raw_multi_4(chp, data, nbytes)	struct channel_softc *chp;	void *data;	unsigned int nbytes;{	if (data == NULL) {		int i;		for (i = 0; i < nbytes; i += 4) {			bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, 0, 0);		}		return;	}	bus_space_write_raw_multi_4(chp->cmd_iot, chp->cmd_ioh, 0, 	    data, nbytes);	return;}voidwdc_default_read_raw_multi_4(chp, data, nbytes)	struct channel_softc *chp;	void *data;	unsigned int nbytes;{	if (data == NULL) {		int i;		for (i = 0; i < nbytes; i += 4) {			bus_space_read_4(chp->cmd_iot, chp->cmd_ioh, 0);		}		return;	}	bus_space_read_raw_multi_4(chp->cmd_iot, chp->cmd_ioh, 0, 	    data, nbytes);	return;}intwdprint(aux, pnp)	void *aux;	const char *pnp;{	struct ata_atapi_attach *aa_link = aux;	if (pnp)		printf("drive at %s", pnp);	printf(" channel %d drive %d", aa_link->aa_channel,	    aa_link->aa_drv_data->drive);	return (UNCONF);}intatapi_print(aux, pnp)	void *aux;	const char *pnp;{	struct ata_atapi_attach *aa_link = aux;	if (pnp)		printf("atapibus at %s", pnp);	printf(" channel %d", aa_link->aa_channel);	return (UNCONF);}voidwdc_disable_intr(chp)	struct channel_softc *chp;{	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS);}voidwdc_enable_intr(chp)	struct channel_softc *chp;{	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT);}intwdc_select_drive(chp, drive, howlong)	struct channel_softc *chp;	int drive;	int howlong;{	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4));		delay(1);	if (wdcwait(chp, WDCS_DRQ, 0, howlong)) {		WDCDEBUG_PRINT(("wdc_select_drive %s:%d:%d waiting for %d"				"after\n",				chp->wdc->sc_dev.dv_xname, chp->channel, drive,				howlong),			       DEBUG_SDRIVE);						return -1;	}	return 0;}/* Test to see controller with at last one attached drive is there. * Returns a bit for each possible drive found (0x01 for drive 0, * 0x02 for drive 1). * Logic: * - If a status register is at 0xff, assume there is no drive here *   (ISA has pull-up resistors). If no drive at all -> return. * - reset the controller, wait for it to complete (may take up to 31s !). *   If timeout -> return. * - test ATA/ATAPI signatures. If at last one drive found -> return. * - try an ATA command on the master. */intwdcprobe(chp)	struct channel_softc *chp;{	u_int8_t st0, st1, sc, sn, cl, ch;	u_int8_t ret_value = 0x03;	u_int8_t drive;	if (!chp->_vtbl)		chp->_vtbl = &wdc_default_vtbl;	/*	 * Sanity check to see if the wdc channel responds at all.	 */	if (chp->wdc == NULL ||	    (chp->wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) {		CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM);		delay(10);		st0 = CHP_READ_REG(chp, wdr_status);		CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | 0x10);		delay(10);		st1 = CHP_READ_REG(chp, wdr_status);		WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%x, st1=0x%x\n",		    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",		    chp->channel, st0, st1), DEBUG_PROBE);		if (st0 == 0xff)			ret_value &= ~0x01;		if (st1 == 0xff)			ret_value &= ~0x02;		if (ret_value == 0) 			return 0;	}	/* assert SRST, wait for reset to complete */	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM);	delay(10);	CHP_WRITE_REG(chp,wdr_ctlr, WDCTL_RST | WDCTL_IDS); 	DELAY(1000);	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS);	delay(1000);	(void) CHP_READ_REG(chp, wdr_error);	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT);	delay(10);	ret_value = __wdcwait_reset(chp, ret_value);	WDCDEBUG_PRINT(("%s:%d: after reset, ret_value=0x%d\n",	    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,	    ret_value), DEBUG_PROBE);	/* if reset failed, there's nothing here */	if (ret_value == 0)		return 0;	/*	 * Test presence of drives. First test register signatures looking for	 * ATAPI devices. If it's not an ATAPI and reset said there may be	 * something here assume it's ATA or OLD. Ghost will be killed later in	 * attach routine.	 */	for (drive = 0; drive < 2; drive++) {		if ((ret_value & (0x01 << drive)) == 0)			continue;		CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4));		delay(10);		/* Save registers contents */		sc = CHP_READ_REG(chp, wdr_seccnt);		sn = CHP_READ_REG(chp, wdr_sector);		cl = CHP_READ_REG(chp, wdr_cyl_lo);		ch = CHP_READ_REG(chp, wdr_cyl_hi);		WDCDEBUG_PRINT(("%s:%d:%d: after reset, sc=0x%x sn=0x%x "		    "cl=0x%x ch=0x%x\n",		    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",	    	    chp->channel, drive, sc, sn, cl, ch), DEBUG_PROBE);		/*		 * This is a simplification of the test in the ATAPI		 * spec since not all drives seem to set the other regs		 * correctly.		 */		if (cl == 0x14 && ch == 0xeb) {			chp->ch_drive[drive].drive_flags |= DRIVE_ATAPI;		} else {			chp->ch_drive[drive].drive_flags |= DRIVE_ATA;			if (chp->wdc == NULL ||			    (chp->wdc->cap & WDC_CAPABILITY_PREATA) != 0)				chp->ch_drive[drive].drive_flags |= DRIVE_OLD;		}	}	return (ret_value);	}#ifndef PMON/* * Call activate routine of underlying devices. */intwdcactivate(self, act)	struct device *self;	enum devact act;{	int error = 0;	int s;	s = splbio();	config_activate_children(self, act);	splx(s);	return (error);}#endifvoidwdcattach(chp)	struct channel_softc *chp;{	int channel_flags, ctrl_flags, i;#ifndef __OpenBSD__	int error;#endif	struct ata_atapi_attach aa_link;	struct ataparams params;	static int inited = 0;#ifndef PMON	extern int cold;	if (!cold)		at_poll = AT_WAIT;#endif#ifndef __OpenBSD__	if ((error = wdc_addref(chp)) != 0) {		printf("%s: unable to enable controller\n",		    chp->wdc->sc_dev.dv_xname);		return;	}#endif	if (!chp->_vtbl)		chp->_vtbl = &wdc_default_vtbl;	if (wdcprobe(chp) == 0) {		/* If no drives, abort attach here. */#ifndef __OpenBSD__		wdc_delref(chp);#endif		return;	}	/* init list only once */	if (inited == 0) {		LIST_INIT(&xfer_free_list);		inited++;	}	TAILQ_INIT(&chp->ch_queue->sc_xfer);		for (i = 0; i < 2; i++) {		chp->ch_drive[i].chnl_softc = chp;		chp->ch_drive[i].drive = i;		/* If controller can't do 16bit flag the drives as 32bit */		if ((chp->wdc->cap &		    (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) ==		    WDC_CAPABILITY_DATA32)			chp->ch_drive[i].drive_flags |= DRIVE_CAP32;		if ((chp->ch_drive[i].drive_flags & DRIVE) == 0)			continue;		if (i == 1 && ((chp->ch_drive[0].drive_flags & DRIVE) == 0))			chp->ch_flags |= WDCF_ONESLAVE;		/* Issue a IDENTIFY command, to try to detect slave ghost */		if (ata_get_params(&chp->ch_drive[i], at_poll, &params) ==		    CMD_OK) {			/* If IDENTIFY succeded, this is not an OLD ctrl */			chp->ch_drive[0].drive_flags &= ~DRIVE_OLD;			chp->ch_drive[1].drive_flags &= ~DRIVE_OLD;		} else {			chp->ch_drive[i].drive_flags &=			    ~(DRIVE_ATA | DRIVE_ATAPI);			WDCDEBUG_PRINT(("%s:%d:%d: IDENTIFY failed\n",			    chp->wdc->sc_dev.dv_xname,			    chp->channel, i), DEBUG_PROBE);			if ((chp->ch_drive[i].drive_flags & DRIVE_OLD) == 0)				continue;			/*			 * Pre-ATA drive ?			 * Test registers writability (Error register not			 * writable, but cyllo is), then try an ATA command.			 */			CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (i << 4));			delay(10);			CHP_WRITE_REG(chp, wdr_features, 0x58);			CHP_WRITE_REG(chp, wdr_cyl_lo, 0xa5);			if ((CHP_READ_REG(chp, wdr_error) == 0x58) ||			    (CHP_READ_REG(chp, wdr_cyl_lo) != 0xa5)) {				WDCDEBUG_PRINT(("%s:%d:%d: register "				    "writability failed\n",				    chp->wdc->sc_dev.dv_xname,				    chp->channel, i), DEBUG_PROBE);				    chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;			}			CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (i << 4));			delay(100);			if (wait_for_ready(chp, 10000) != 0) {				WDCDEBUG_PRINT(("%s:%d:%d: not ready\n",				    chp->wdc->sc_dev.dv_xname,				    chp->channel, i), DEBUG_PROBE);				chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;				continue;			}			CHP_WRITE_REG(chp, wdr_command, WDCC_RECAL);			if (wait_for_ready(chp, 10000) != 0) {				WDCDEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n",				    chp->wdc->sc_dev.dv_xname,				    chp->channel, i), DEBUG_PROBE);				chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;			}		}	}

⌨️ 快捷键说明

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