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

📄 atp870u.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $ *  linux/kernel/atp870u.c * *  Copyright (C) 1997	Wu Ching Chen *  2.1.x update (C) 1998  Krzysztof G. Baranowski * * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes * * Wu Ching Chen : NULL pointer fixes  2000/06/02 *		   support atp876 chip *		   enable 32 bit fifo transfer *		   support cdrom & remove device run ultra speed *		   fix disconnect bug  2000/12/21 *		   support atp880 chip lvd u160 2001/05/15 (7.1) */#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/system.h>#include <asm/io.h>#include <linux/pci.h>#include <linux/blk.h>#include "scsi.h"#include "hosts.h"#include "atp870u.h"#include<linux/stat.h>void mydlyu(unsigned int);/* *   static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $"; */static unsigned char admaxu = 1;static unsigned short int sync_idu;static unsigned int irqnumu[2] = {0, 0};struct atp_unit{	unsigned long ioport;	unsigned long irq;	unsigned long pciport;	unsigned char last_cmd;	unsigned char in_snd;	unsigned char in_int;	unsigned char quhdu;	unsigned char quendu;	unsigned char scam_on;	unsigned char global_map;	unsigned char chip_veru;	unsigned char host_idu;	int working;	unsigned short wide_idu;	unsigned short active_idu;	unsigned short ultra_map;	unsigned short async;	unsigned short deviceid;	unsigned char ata_cdbu[16];	unsigned char sp[16];	Scsi_Cmnd *querequ[qcnt];	struct atp_id	{		unsigned char dirctu;		unsigned char devspu;		unsigned char devtypeu;		unsigned long prdaddru;		unsigned long tran_lenu;		unsigned long last_lenu;		unsigned char *prd_posu;		unsigned char *prd_tableu;		Scsi_Cmnd *curr_req;	} id[16];};static struct Scsi_Host *atp_host[2] = {NULL, NULL};static struct atp_unit atp_unit[2];static void atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs){	unsigned long flags;	unsigned short int tmpcip, id;	unsigned char i, j, h, target_id, lun;	unsigned char *prd;	Scsi_Cmnd *workrequ;	unsigned int workportu, tmport;	unsigned long adrcntu, k;	int errstus;	struct atp_unit *dev = dev_id;	for (h = 0; h < 2; h++) {		if (irq == irqnumu[h]) {			goto irq_numok;		}	}	return;irq_numok:	dev->in_int = 1;	workportu = dev->ioport;	tmport = workportu;	if (dev->working != 0)	{		tmport += 0x1f;		j = inb(tmport);		if ((j & 0x80) == 0)		{			dev->in_int = 0;			return;		}		tmpcip = dev->pciport;		if ((inb(tmpcip) & 0x08) != 0)		{			tmpcip += 0x2;			for (k=0; k < 1000; k++)			{				if ((inb(tmpcip) & 0x08) == 0)				{					goto stop_dma;				}				if ((inb(tmpcip) & 0x01) == 0)				{					goto stop_dma;				}			}		}stop_dma:		tmpcip = dev->pciport;		outb(0x00, tmpcip);		tmport -= 0x08;		i = inb(tmport);		tmport -= 0x02;		target_id = inb(tmport);		tmport += 0x02;		/*		 *	Remap wide devices onto id numbers		 */		if ((target_id & 0x40) != 0) {			target_id = (target_id & 0x07) | 0x08;		} else {			target_id &= 0x07;		}		if ((j & 0x40) != 0)		{		     if (dev->last_cmd == 0xff)		     {			dev->last_cmd = target_id;		     }		     dev->last_cmd |= 0x40;		}		if (i == 0x85)		{			if ((dev->last_cmd & 0xf0) != 0x40)			{			   dev->last_cmd = 0xff;			}			/*			 *	Flip wide			 */			if (dev->wide_idu != 0)			{				tmport = workportu + 0x1b;				outb(0x01,tmport);				while ((inb(tmport) & 0x01) != 0x01)				{				   outb(0x01,tmport);				}			}			/*			 *	Issue more commands			 */			if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) &&			    (dev->in_snd == 0))			{				send_s870(h);			}			/*			 *	Done			 */			dev->in_int = 0;			return;		}		if (i == 0x40)		{		     dev->last_cmd |= 0x40;		     dev->in_int = 0;		     return;		}		if (i == 0x21)		{			if ((dev->last_cmd & 0xf0) != 0x40)			{			   dev->last_cmd = 0xff;			}			tmport -= 0x05;			adrcntu = 0;			((unsigned char *) &adrcntu)[2] = inb(tmport++);			((unsigned char *) &adrcntu)[1] = inb(tmport++);			((unsigned char *) &adrcntu)[0] = inb(tmport);			k = dev->id[target_id].last_lenu;			k -= adrcntu;			dev->id[target_id].tran_lenu = k;			dev->id[target_id].last_lenu = adrcntu;			tmport -= 0x04;			outb(0x41, tmport);			tmport += 0x08;			outb(0x08, tmport);			dev->in_int = 0;			return;		}		if ((i == 0x80) || (i == 0x8f))		{			lun = 0;			tmport -= 0x07;			j = inb(tmport);			if (j == 0x44 || i==0x80) {				tmport += 0x0d;				lun = inb(tmport) & 0x07;			} else {				if ((dev->last_cmd & 0xf0) != 0x40)				{				   dev->last_cmd = 0xff;				}				if (j == 0x41)				{					tmport += 0x02;					adrcntu = 0;					((unsigned char *) &adrcntu)[2] = inb(tmport++);					((unsigned char *) &adrcntu)[1] = inb(tmport++);					((unsigned char *) &adrcntu)[0] = inb(tmport);					k = dev->id[target_id].last_lenu;					k -= adrcntu;					dev->id[target_id].tran_lenu = k;					dev->id[target_id].last_lenu = adrcntu;					tmport += 0x04;					outb(0x08, tmport);					dev->in_int = 0;					return;				}				else				{					outb(0x46, tmport);					dev->id[target_id].dirctu = 0x00;					tmport += 0x02;					outb(0x00, tmport++);					outb(0x00, tmport++);					outb(0x00, tmport++);					tmport += 0x03;					outb(0x08, tmport);					dev->in_int = 0;					return;				}			}			if (dev->last_cmd != 0xff)			{			   dev->last_cmd |= 0x40;			}			tmport = workportu + 0x10;			outb(0x45, tmport);			tmport += 0x06;			target_id = inb(tmport);			/*			 *	Remap wide identifiers			 */			if ((target_id & 0x10) != 0)			{				target_id = (target_id & 0x07) | 0x08;			} else {				target_id &= 0x07;			}			workrequ = dev->id[target_id].curr_req;			tmport = workportu + 0x0f;			outb(lun, tmport);			tmport += 0x02;			outb(dev->id[target_id].devspu, tmport++);			adrcntu = dev->id[target_id].tran_lenu;			k = dev->id[target_id].last_lenu;			outb(((unsigned char *) &k)[2], tmport++);			outb(((unsigned char *) &k)[1], tmport++);			outb(((unsigned char *) &k)[0], tmport++);			/* Remap wide */			j = target_id;			if (target_id > 7) {				j = (j & 0x07) | 0x40;			}			/* Add direction */			j |= dev->id[target_id].dirctu;			outb(j, tmport++);			outb(0x80, tmport);			/* enable 32 bit fifo transfer */			if (dev->deviceid != 0x8081)			{			   tmport = workportu + 0x3a;			   if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) ||			       (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a))			   {			      outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport);			   }			   else			   {			      outb((unsigned char)(inb(tmport) & 0xf3),tmport);			   }			}			else			{			   tmport = workportu - 0x05;			   if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) ||			       (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a))			   {			      outb((unsigned char)((inb(tmport) & 0x3f) | 0xc0),tmport);			   }			   else			   {			      outb((unsigned char)(inb(tmport) & 0x3f),tmport);			   }			}			tmport = workportu + 0x1b;			j = 0;			id = 1;			id = id << target_id;			/*			 *	Is this a wide device			 */			if ((id & dev->wide_idu) != 0) {				j |= 0x01;			}			outb(j, tmport);			while ((inb(tmport) & 0x01) != j)			{			   outb(j,tmport);			}			if (dev->id[target_id].last_lenu == 0) {				tmport = workportu + 0x18;				outb(0x08, tmport);				dev->in_int = 0;				return;			}			prd = dev->id[target_id].prd_posu;			while (adrcntu != 0)			{				id = ((unsigned short int *) (prd))[2];				if (id == 0) {					k = 0x10000;				} else {					k = id;				}				if (k > adrcntu) {					((unsigned short int *) (prd))[2] = (unsigned short int)					    (k - adrcntu);					((unsigned long *) (prd))[0] += adrcntu;					adrcntu = 0;					dev->id[target_id].prd_posu = prd;				} else {					adrcntu -= k;					dev->id[target_id].prdaddru += 0x08;					prd += 0x08;					if (adrcntu == 0) {						dev->id[target_id].prd_posu = prd;					}				}			}			tmpcip = dev->pciport + 0x04;			outl(dev->id[target_id].prdaddru, tmpcip);			tmpcip -= 0x02;			outb(0x06, tmpcip);			outb(0x00, tmpcip);			tmpcip -= 0x02;			tmport = workportu + 0x18;			/*			 *	Check transfer direction			 */			if (dev->id[target_id].dirctu != 0) {				outb(0x08, tmport);				outb(0x01, tmpcip);				dev->in_int = 0;				return;			}			outb(0x08, tmport);			outb(0x09, tmpcip);			dev->in_int = 0;			return;		}		/*		 *	Current scsi request on this target		 */		workrequ = dev->id[target_id].curr_req;		if (i == 0x42) {			if ((dev->last_cmd & 0xf0) != 0x40)			{			   dev->last_cmd = 0xff;			}			errstus = 0x02;			workrequ->result = errstus;			goto go_42;		}		if (i == 0x16)		{			if ((dev->last_cmd & 0xf0) != 0x40)			{			   dev->last_cmd = 0xff;			}			errstus = 0;			tmport -= 0x08;			errstus = inb(tmport);			workrequ->result = errstus;go_42:			/*			 *	Complete the command			 */			spin_lock_irqsave(&io_request_lock, flags);			(*workrequ->scsi_done) (workrequ);			/*			 *	Clear it off the queue			 */			dev->id[target_id].curr_req = 0;			dev->working--;			spin_unlock_irqrestore(&io_request_lock, flags);			/*			 *	Take it back wide			 */			if (dev->wide_idu != 0) {				tmport = workportu + 0x1b;				outb(0x01,tmport);				while ((inb(tmport) & 0x01) != 0x01)				{				   outb(0x01,tmport);				}			}			/*			 *	If there is stuff to send and nothing going then send it			 */			if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) &&			    (dev->in_snd == 0))			{			   send_s870(h);			}			dev->in_int = 0;			return;		}		if ((dev->last_cmd & 0xf0) != 0x40)		{		   dev->last_cmd = 0xff;		}		if (i == 0x4f) {			i = 0x89;		}		i &= 0x0f;		if (i == 0x09) {			tmpcip = tmpcip + 4;			outl(dev->id[target_id].prdaddru, tmpcip);			tmpcip = tmpcip - 2;			outb(0x06, tmpcip);			outb(0x00, tmpcip);			tmpcip = tmpcip - 2;			tmport = workportu + 0x10;			outb(0x41, tmport);			dev->id[target_id].dirctu = 0x00;			tmport += 0x08;			outb(0x08, tmport);			outb(0x09, tmpcip);			dev->in_int = 0;			return;		}		if (i == 0x08) {			tmpcip = tmpcip + 4;			outl(dev->id[target_id].prdaddru, tmpcip);			tmpcip = tmpcip - 2;			outb(0x06, tmpcip);			outb(0x00, tmpcip);			tmpcip = tmpcip - 2;			tmport = workportu + 0x10;			outb(0x41, tmport);			tmport += 0x05;			outb((unsigned char) (inb(tmport) | 0x20), tmport);			dev->id[target_id].dirctu = 0x20;			tmport += 0x03;			outb(0x08, tmport);			outb(0x01, tmpcip);			dev->in_int = 0;			return;		}		tmport -= 0x07;		if (i == 0x0a) {			outb(0x30, tmport);		} else {			outb(0x46, tmport);		}		dev->id[target_id].dirctu = 0x00;		tmport += 0x02;		outb(0x00, tmport++);		outb(0x00, tmport++);		outb(0x00, tmport++);		tmport += 0x03;		outb(0x08, tmport);		dev->in_int = 0;		return;	} else {//		tmport = workportu + 0x17;//		inb(tmport);//		dev->working = 0;		dev->in_int = 0;		return;	}}int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *)){	unsigned char h;	unsigned long flags;	unsigned short int m;	unsigned int tmport;	struct atp_unit *dev;	for (h = 0; h <= admaxu; h++) {		if (req_p->host == atp_host[h]) {			goto host_ok;		}	}	return 0;host_ok:	if (req_p->channel != 0) {		req_p->result = 0x00040000;		done(req_p);		return 0;	}	dev = &atp_unit[h];	m = 1;	m = m << req_p->target;	/*	 *	Fake a timeout for missing targets	 */	if ((m & dev->active_idu) == 0) {		req_p->result = 0x00040000;		done(req_p);		return 0;	}	if (done) {		req_p->scsi_done = done;	} else {		printk(KERN_WARNING "atp870u_queuecommand: done can't be NULL\n");		req_p->result = 0;		done(req_p);		return 0;	}	/*	 *	Count new command	 */	save_flags(flags);	cli();	dev->quendu++;	if (dev->quendu >= qcnt) {		dev->quendu = 0;	}	/*	 *	Check queue state	 */	if (dev->quhdu == dev->quendu) {		if (dev->quendu == 0) {			dev->quendu = qcnt;		}		dev->quendu--;		req_p->result = 0x00020000;		done(req_p);		restore_flags(flags);		return 0;	}	dev->querequ[dev->quendu] = req_p;	tmport = dev->ioport + 0x1c;	restore_flags(flags);	if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) {		send_s870(h);	}	return 0;}void mydlyu(unsigned int dlycnt){	unsigned int i;	for (i = 0; i < dlycnt; i++) {		inb(0x80);	}}void send_s870(unsigned char h){	unsigned int tmport;	Scsi_Cmnd *workrequ;	unsigned long flags;	unsigned int i;	unsigned char j, target_id;	unsigned char *prd;	unsigned short int tmpcip, w;	unsigned long l, bttl;	unsigned int workportu;	struct scatterlist *sgpnt;	struct atp_unit *dev = &atp_unit[h];	save_flags(flags);	cli();	if (dev->in_snd != 0) {		restore_flags(flags);		return;	}	dev->in_snd = 1;	if ((dev->last_cmd != 0xff) && ((dev->last_cmd & 0x40) != 0)) {		dev->last_cmd &= 0x0f;		workrequ = dev->id[dev->last_cmd].curr_req;		if (workrequ != NULL)	     /* check NULL pointer */		{		   goto cmd_subp;		}		dev->last_cmd = 0xff;		if (dev->quhdu == dev->quendu)		{		   dev->in_snd = 0;		   restore_flags(flags);		   return ;		}	}	if ((dev->last_cmd != 0xff) && (dev->working != 0))	{	     dev->in_snd = 0;	     restore_flags(flags);	     return ;	}	dev->working++;	j = dev->quhdu;	dev->quhdu++;	if (dev->quhdu >= qcnt) {		dev->quhdu = 0;	}	workrequ = dev->querequ[dev->quhdu];	if (dev->id[workrequ->target].curr_req == 0) {		dev->id[workrequ->target].curr_req = workrequ;		dev->last_cmd = workrequ->target;		goto cmd_subp;	}	dev->quhdu = j;	dev->working--;	dev->in_snd = 0;	restore_flags(flags);	return;cmd_subp:	workportu = dev->ioport;	tmport = workportu + 0x1f;	if ((inb(tmport) & 0xb0) != 0) {		goto abortsnd;	}	tmport = workportu + 0x1c;	if (inb(tmport) == 0) {		goto oktosend;	}abortsnd:	dev->last_cmd |= 0x40;	dev->in_snd = 0;	restore_flags(flags);	return;oktosend:	memcpy(&dev->ata_cdbu[0], &workrequ->cmnd[0], workrequ->cmd_len);	if (dev->ata_cdbu[0] == READ_CAPACITY) {		if (workrequ->request_bufflen > 8) {			workrequ->request_bufflen = 0x08;		}	}	if (dev->ata_cdbu[0] == 0x00) {		workrequ->request_bufflen = 0;	}	tmport = workportu + 0x1b;	j = 0;	target_id = workrequ->target;	/*	 *	Wide ?	 */	w = 1;	w = w << target_id;	if ((w & dev->wide_idu) != 0) {		j |= 0x01;	}	outb(j, tmport);	while ((inb(tmport) & 0x01) != j)	{	   outb(j,tmport);	}	/*	 *	Write the command	 */	tmport = workportu;

⌨️ 快捷键说明

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