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

📄 psi240i.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*+M************************************************************************* * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux. * * Copyright (c) 1997 Perceptive Solutions, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING.  If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * *	File Name:		psi240i.c * *	Description:	SCSI driver for the PSI240I EIDE interface card. * *-M*************************************************************************/#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/spinlock.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include <linux/blk.h>#include "scsi.h"#include "hosts.h"#include "psi240i.h"#include "psi_chip.h"#include<linux/stat.h>//#define DEBUG 1#ifdef DEBUG#define DEB(x) x#else#define DEB(x)#endif#define MAXBOARDS 2	/* Increase this and the sizes of the arrays below, if you need more. */#define	PORT_DATA				0#define	PORT_ERROR				1#define	PORT_SECTOR_COUNT		2#define	PORT_LBA_0				3#define	PORT_LBA_8				4#define	PORT_LBA_16				5#define	PORT_LBA_24				6#define	PORT_STAT_CMD			7#define	PORT_SEL_FAIL			8#define	PORT_IRQ_STATUS			9#define	PORT_ADDRESS			10#define	PORT_FAIL				11#define	PORT_ALT_STAT		   	12typedef struct	{	UCHAR		   	device;				// device code	UCHAR			byte6;				// device select register image	UCHAR			spigot;				// spigot number	UCHAR			expectingIRQ;		// flag for expecting and interrupt	USHORT			sectors;			// number of sectors per track	USHORT			heads;				// number of heads	USHORT			cylinders;			// number of cylinders for this device	USHORT			spareword;			// placeholder	ULONG			blocks;				// number of blocks on device	}	OUR_DEVICE, *POUR_DEVICE;typedef struct	{	USHORT		 ports[13];	OUR_DEVICE	 device[8];	Scsi_Cmnd	*pSCmnd;	IDE_STRUCT	 ide;	ULONG		 startSector;	USHORT		 sectorCount;	Scsi_Cmnd	*SCpnt;	VOID		*buffer;	USHORT		 expectingIRQ;	}	ADAPTER240I, *PADAPTER240I;#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)static struct	Scsi_Host *PsiHost[6] = {NULL,};  /* One for each IRQ level (10-15) */static			IDENTIFY_DATA	identifyData;static			SETUP			ChipSetup;static	USHORT	portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};/**************************************************************** *	Name:	WriteData	:LOCAL * *	Description:	Write data to device. * *	Parameters:		padapter - Pointer adapter data structure. * *	Returns:		TRUE if drive does not assert DRQ in time. * ****************************************************************/static int WriteData (PADAPTER240I padapter)	{	ULONG	timer;	USHORT *pports = padapter->ports;	timer = jiffies + TIMEOUT_DRQ;								// calculate the timeout value	do  {		if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )			{			outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);			return 0;			}		}	while ( time_after(timer, jiffies) );									// test for timeout	padapter->ide.ide.ides.cmd = 0;									// null out the command byte	return 1;	}/**************************************************************** *	Name:	IdeCmd	:LOCAL * *	Description:	Process a queued command from the SCSI manager. * *	Parameters:		padapter - Pointer adapter data structure. * *	Returns:		Zero if no error or status register contents on error. * ****************************************************************/static UCHAR IdeCmd (PADAPTER240I padapter)	{	ULONG	timer;	USHORT *pports = padapter->ports;	UCHAR	status;	outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]);	// select the spigot	outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]);			// select the drive	timer = jiffies + TIMEOUT_READY;							// calculate the timeout value	do  {		status = inb_p (padapter->ports[PORT_STAT_CMD]);		if ( status & IDE_STATUS_DRDY )			{			outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);			outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);			outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);			outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);			padapter->expectingIRQ = 1;			outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);			if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )				return (WriteData (padapter));			return 0;			}		}	while ( time_after(timer, jiffies) );									// test for timeout	padapter->ide.ide.ides.cmd = 0;									// null out the command byte	return status;	}/**************************************************************** *	Name:	SetupTransfer	:LOCAL * *	Description:	Setup a data transfer command. * *	Parameters:		padapter - Pointer adapter data structure. *					drive	 - Drive/head register upper nibble only. * *	Returns:		TRUE if no data to transfer. * ****************************************************************/static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)	{	if ( padapter->sectorCount )		{		*(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;		padapter->ide.ide.ide[6] |= drive;		padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;		padapter->sectorCount -= padapter->ide.ide.ides.sectors;	// bump the start and count for next xfer		padapter->startSector += padapter->ide.ide.ides.sectors;		return 0;		}	else		{		padapter->ide.ide.ides.cmd = 0;								// null out the command byte		padapter->SCpnt = NULL;		return 1;		}	}/**************************************************************** *	Name:	DecodeError	:LOCAL * *	Description:	Decode and process device errors. * *	Parameters:		pshost - Pointer to host data block. *					status - Status register code. * *	Returns:		The driver status code. * ****************************************************************/static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)	{	PADAPTER240I	padapter = HOSTDATA(pshost);	UCHAR			error;	padapter->expectingIRQ = 0;	padapter->SCpnt = NULL;	if ( status & IDE_STATUS_WRITE_FAULT )		{		return DID_PARITY << 16;		}	if ( status & IDE_STATUS_BUSY )		return DID_BUS_BUSY << 16;	error = inb_p (padapter->ports[PORT_ERROR]);	DEB(printk ("\npsi240i error register: %x", error));	switch ( error )		{		case IDE_ERROR_AMNF:		case IDE_ERROR_TKONF:		case IDE_ERROR_ABRT:		case IDE_ERROR_IDFN:		case IDE_ERROR_UNC:		case IDE_ERROR_BBK:		default:			return DID_ERROR << 16;		}	return DID_ERROR << 16;	}/**************************************************************** *	Name:	Irq_Handler	:LOCAL * *	Description:	Interrupt handler. * *	Parameters:		irq		- Hardware IRQ number. *					dev_id	- *					regs	- * *	Returns:		TRUE if drive is not ready in time. * ****************************************************************/static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)	{	struct Scsi_Host   *shost;			// Pointer to host data block	PADAPTER240I		padapter;		// Pointer to adapter control structure	USHORT		 	   *pports;			// I/O port array	Scsi_Cmnd		   *SCpnt;	UCHAR				status;	int					z;	DEB(printk ("\npsi240i received interrupt\n"));	shost = PsiHost[irq - 10];	if ( !shost )		panic ("Splunge!");	padapter = HOSTDATA(shost);	pports = padapter->ports;	SCpnt = padapter->SCpnt;	if ( !padapter->expectingIRQ )		{		DEB(printk ("\npsi240i Unsolicited interrupt\n"));		return;		}	padapter->expectingIRQ = 0;	status = inb_p (padapter->ports[PORT_STAT_CMD]);			// read the device status	if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )		goto irqerror;	DEB(printk ("\npsi240i processing interrupt"));	switch ( padapter->ide.ide.ides.cmd )							// decide how to handle the interrupt		{		case IDE_CMD_READ_MULTIPLE:			if ( status & IDE_STATUS_DRQ )				{				insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);				padapter->buffer += padapter->ide.ide.ides.sectors * 512;				if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )					{					SCpnt->result = DID_OK << 16;					padapter->SCpnt = NULL;					SCpnt->scsi_done (SCpnt);					return;					}				if ( !(status = IdeCmd (padapter)) )					return;				}			break;		case IDE_CMD_WRITE_MULTIPLE:			padapter->buffer += padapter->ide.ide.ides.sectors * 512;			if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )				{				SCpnt->result = DID_OK << 16;				padapter->SCpnt = NULL;				SCpnt->scsi_done (SCpnt);				return;				}			if ( !(status = IdeCmd (padapter)) )				return;			break;		case IDE_COMMAND_IDENTIFY:			{			PINQUIRYDATA	pinquiryData  = SCpnt->request_buffer;			if ( status & IDE_STATUS_DRQ )				{				insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);				memset (pinquiryData, 0, SCpnt->request_bufflen);		// Zero INQUIRY data structure.				pinquiryData->DeviceType = 0;				pinquiryData->Versions = 2;				pinquiryData->AdditionalLength = 35 - 4;				// Fill in vendor identification fields.				for ( z = 0;  z < 20;  z += 2 )					{					pinquiryData->VendorId[z]	  = ((UCHAR *)identifyData.ModelNumber)[z + 1];					pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];					}				// Initialize unused portion of product id.				for ( z = 0;  z < 4;  z++ )					pinquiryData->ProductId[12 + z] = ' ';				// Move firmware revision from IDENTIFY data to				// product revision in INQUIRY data.				for ( z = 0;  z < 4;  z += 2 )					{					pinquiryData->ProductRevisionLevel[z]	 = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];					pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];					}				SCpnt->result = DID_OK << 16;				padapter->SCpnt = NULL;				SCpnt->scsi_done (SCpnt);				return;				}			break;			}		default:			SCpnt->result = DID_OK << 16;			padapter->SCpnt = NULL;			SCpnt->scsi_done (SCpnt);			return;

⌨️ 快捷键说明

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