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

📄 ohci1394.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * ohci1394.c - driver for OHCI 1394 boards * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au> *                        Gord Peters <GordPeters@smarttech.com> * * 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 of the License, 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; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* * Things known to be working: * . Async Request Transmit * . Async Response Receive * . Async Request Receive * . Async Response Transmit * . Iso Receive * . DMA mmap for iso receive *  * Things not implemented: * . Iso Transmit * . DMA error recovery * * Things to be fixed: * . Config ROM * * Known bugs: * . Self-id are sometimes not received properly  *   if card is initialized with no other nodes  *   on the bus * . Apple PowerBook detected but not working yet *//*  * Acknowledgments: * * Adam J Richter <adam@yggdrasil.com> *  . Use of pci_class to find device * Andreas Tobler <toa@pop.agri.ch> *  . Updated proc_fs calls * Emilie Chung	<emilie.chung@axis.com> *  . Tip on Async Request Filter * Pascal Drolet <pascal.drolet@informission.ca> *  . Various tips for optimization and functionnalities * Robert Ficklin <rficklin@westengineering.com> *  . Loop in irq_handler * James Goodwin <jamesg@Filanet.com> *  . Various tips on initialization, self-id reception, etc. * Albrecht Dress <ad@mpifr-bonn.mpg.de> *  . Apple PowerBook detection * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de> *  . Reset the board properly before leaving + misc cleanups * Leon van Stuivenberg <leonvs@iae.nl> *  . Bug fixes */#include <linux/config.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/wait.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/fs.h>#include <linux/poll.h>#include <asm/byteorder.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/proc_fs.h>#include <linux/tqueue.h>#include <linux/delay.h>#include <asm/pgtable.h>#include <asm/page.h>#include <linux/sched.h>#include <asm/segment.h>#include <linux/types.h>#include <linux/wrapper.h>#include <linux/vmalloc.h>#include <linux/init.h>#include "ieee1394.h"#include "ieee1394_types.h"#include "hosts.h"#include "ieee1394_core.h"#include "ohci1394.h"#ifdef CONFIG_IEEE1394_VERBOSEDEBUG#define OHCI1394_DEBUG#endif#ifdef DBGMSG#undef DBGMSG#endif#ifdef OHCI1394_DEBUG#define DBGMSG(card, fmt, args...) \printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args)#else#define DBGMSG(card, fmt, args...)#endif/* print general (card independent) information */#define PRINT_G(level, fmt, args...) \printk(level "ohci1394: " fmt "\n" , ## args)/* print card specific information */#define PRINT(level, card, fmt, args...) \printk(level "ohci1394_%d: " fmt "\n" , card , ## args)#define FAIL(fmt, args...) \	PRINT_G(KERN_ERR, fmt , ## args); \	  num_of_cards--; \	    remove_card(ohci); \	      return 1;#if USE_DEVICEint supported_chips[][2] = {	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV22 },	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV23 },	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV26 },	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_PCI4450 },	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },	{ PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 },	{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72862 },	{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 },	{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 },	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW },	{ PCI_VENDOR_ID_AL, PCI_DEVICE_ID_ALI_OHCI1394_M5251 },	{ PCI_VENDOR_ID_LUCENT, PCI_DEVICE_ID_LUCENT_FW323 },	{ -1, -1 }};#else#define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)static struct pci_device_id ohci1394_pci_tbl[] __initdata = {	{		class: 		PCI_CLASS_FIREWIRE_OHCI,		class_mask: 	0x00ffffff,		vendor:		PCI_ANY_ID,		device:		PCI_ANY_ID,		subvendor:	PCI_ANY_ID,		subdevice:	PCI_ANY_ID,	},	{ 0, },};MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);#endif#endif /* USE_DEVICE */MODULE_PARM(attempt_root,"i");static int attempt_root = 0;static struct ti_ohci cards[MAX_OHCI1394_CARDS];static int num_of_cards = 0;static int add_card(struct pci_dev *dev);static void remove_card(struct ti_ohci *ohci);static int init_driver(void);static void dma_trm_bh(void *data);static void dma_rcv_bh(void *data);static void dma_trm_reset(struct dma_trm_ctx *d);/*********************************** * IEEE-1394 functionality section * ***********************************/#if 0 /* not needed at this time */static int get_phy_reg(struct ti_ohci *ohci, int addr) {	int timeout=10000;	static quadlet_t r;	if ((addr < 1) || (addr > 15)) {		PRINT(KERN_ERR, ohci->id, __FUNCTION__		      ": PHY register address %d out of range", addr);		return -EFAULT;	}	spin_lock(&ohci->phy_reg_lock);	/* initiate read request */	reg_write(ohci, OHCI1394_PhyControl, 		  ((addr<<8)&0x00000f00) | 0x00008000);	/* wait */	while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)		timeout--;	if (!timeout) {		PRINT(KERN_ERR, ohci->id, "get_phy_reg timeout !!!\n");		spin_unlock(&ohci->phy_reg_lock);		return -EFAULT;	}	r = reg_read(ohci, OHCI1394_PhyControl);  	spin_unlock(&ohci->phy_reg_lock);     	return (r&0x00ff0000)>>16;}static int set_phy_reg(struct ti_ohci *ohci, int addr, unsigned char data) {	int timeout=10000;	u32 r;	if ((addr < 1) || (addr > 15)) {		PRINT(KERN_ERR, ohci->id, __FUNCTION__		      ": PHY register address %d out of range", addr);		return -EFAULT;	}	r = ((addr<<8)&0x00000f00) | 0x00004000 | ((u32)data & 0x000000ff);	spin_lock(&ohci->phy_reg_lock);	reg_write(ohci, OHCI1394_PhyControl, r);	/* wait */	while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout)		timeout--;	spin_unlock(&ohci->phy_reg_lock);	if (!timeout) {		PRINT(KERN_ERR, ohci->id, "set_phy_reg timeout !!!\n");		return -EFAULT;	}	return 0;}#endif /* unneeded functions */inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,				int phyid, int isroot){	quadlet_t *q = ohci->selfid_buf_cpu;	quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);	size_t size;	quadlet_t lsid;	/* Self-id handling seems much easier than for the aic5800 chip.	   All the self-id packets, including this device own self-id,	   should be correctly arranged in the selfid buffer at this	   stage */	/* Check status of self-id reception */	if ((self_id_count&0x80000000) || 	    ((self_id_count&0x00FF0000) != (q[0]&0x00FF0000))) {		PRINT(KERN_ERR, ohci->id, 		      "Error in reception of self-id packets"		      "Self-id count: %08x q[0]: %08x",		      self_id_count, q[0]);		/*		 * Tip by James Goodwin <jamesg@Filanet.com>:		 * We had an error, generate another bus reset in response. 		 * TODO. Actually read the current value in the phy before 		 * generating a bus reset (read modify write). This way		 * we don't stomp any current gap count settings, etc.		 */		if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) {			reg_write(ohci, OHCI1394_PhyControl, 0x000041ff);      			ohci->self_id_errors++;		}		else {			PRINT(KERN_ERR, ohci->id, 			      "Timeout on self-id error reception");		}		return -1;	}		size = ((self_id_count&0x00001FFC)>>2) - 1;	q++;	while (size > 0) {		if (q[0] == ~q[1]) {			PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd", 			      q[0]);			hpsb_selfid_received(host, cpu_to_be32(q[0]));			if (((q[0]&0x3f000000)>>24)==phyid) {				lsid=q[0];				PRINT(KERN_INFO, ohci->id, 				      "This node self-id is 0x%08x", lsid);			}		} else {			PRINT(KERN_ERR, ohci->id,			      "inconsistent selfid 0x%x/0x%x", q[0], q[1]);		}		q += 2;		size -= 2;	}	PRINT(KERN_INFO, ohci->id, "calling self-id complete");	hpsb_selfid_complete(host, phyid, isroot);	return 0;}static int ohci_detect(struct hpsb_host_template *tmpl){	struct hpsb_host *host;	int i;	init_driver();	for (i = 0; i < num_of_cards; i++) {		host = hpsb_get_host(tmpl, 0);		if (host == NULL) {			/* simply don't init more after out of mem */			return i;		}		host->hostdata = &cards[i];		cards[i].host = host;	}  	return num_of_cards;}static int ohci_soft_reset(struct ti_ohci *ohci) {	int timeout=10000;	reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);  	while ((reg_read(ohci, OHCI1394_HCControlSet)&0x00010000) && timeout) 		timeout--;	if (!timeout) {		PRINT(KERN_ERR, ohci->id, "soft reset timeout !!!");		return -EFAULT;	}	else PRINT(KERN_INFO, ohci->id, "soft reset finished");	return 0;}static int run_context(struct ti_ohci *ohci, int reg, char *msg){	u32 nodeId;	/* check that the node id is valid */	nodeId = reg_read(ohci, OHCI1394_NodeID);	if (!(nodeId&0x80000000)) {		PRINT(KERN_ERR, ohci->id, 		      "Running dma failed because Node ID not valid");		return -1;	}	/* check that the node number != 63 */	if ((nodeId&0x3f)==63) {		PRINT(KERN_ERR, ohci->id, 		      "Running dma failed because Node ID == 63");		return -1;	}		/* Run the dma context */	reg_write(ohci, reg, 0x8000);		if (msg) PRINT(KERN_INFO, ohci->id, "%s", msg);		return 0;}/* Generate the dma receive prgs and start the context */static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d){	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);	int i;	ohci1394_stop_context(ohci, d->ctrlClear, NULL);	for (i=0; i<d->num_desc; i++) {				/* end of descriptor list? */		if ((i+1) < d->num_desc) {			d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size;			d->prg_cpu[i]->branchAddress =				(d->prg_bus[i+1] & 0xfffffff0) | 0x1;		} else {			d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size;			d->prg_cpu[i]->branchAddress =				d->prg_bus[0] & 0xfffffff0;		}		d->prg_cpu[i]->address = d->buf_bus[i];		d->prg_cpu[i]->status = d->buf_size;	}        d->buf_ind = 0;        d->buf_offset = 0;	/* Tell the controller where the first AR program is */	reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);	/* Run AR context */	reg_write(ohci, d->ctrlSet, 0x00008000);	PRINT(KERN_INFO, ohci->id, "Receive DMA ctx=%d initialized", d->ctx);}/* Initialize the dma transmit context */static void initialize_dma_trm_ctx(struct dma_trm_ctx *d){	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);	/* Stop the context */	ohci1394_stop_context(ohci, d->ctrlClear, NULL);        d->prg_ind = 0;	d->sent_ind = 0;	d->free_prgs = d->num_desc;        d->branchAddrPtr = NULL;	d->fifo_first = NULL;	d->fifo_last = NULL;	d->pending_first = NULL;	d->pending_last = NULL;	PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);}/* Count the number of available iso contexts */static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg){	int i,ctx=0;	u32 tmp;	reg_write(ohci, reg, 0xffffffff);	tmp = reg_read(ohci, reg);		DBGMSG(ohci->id,"Iso contexts reg: %08x implemented: %08x", reg, tmp);	/* Count the number of contexts */	for(i=0; i<32; i++) {	    	if(tmp & 1) ctx++;		tmp >>= 1;	}	return ctx;}/* Global initialization */static int ohci_initialize(struct hpsb_host *host){	struct ti_ohci *ohci=host->hostdata;	int retval, i;	spin_lock_init(&ohci->phy_reg_lock);  	/*	 * Tip by James Goodwin <jamesg@Filanet.com>:	 * We need to add delays after the soft reset, setting LPS, and	 * enabling our link. This might fixes the self-id reception 	 * problem at initialization.	 */ 

⌨️ 快捷键说明

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