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

📄 ohci1394.c

📁 1394在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>*              2001      Ben Collins <bcollins@debian.org>** 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* . Config ROM generation** Things implemented, but still in test phase:* . Iso Transmit* . Async Stream Packets Transmit (Receive done via Iso interface)* * Things not implemented:* . DMA error recovery** Known bugs:* . devctl BUS_RESET arg confusion (reset type or root holdoff?)*   added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk*//* * 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** Ben Collins <bcollins@debian.org>*  . Working big-endian support*  . Updated to 2.4.x module scheme (PCI aswell)*  . Removed procfs support since it trashes random mem*  . Config ROM generation** Manfred Weihs <weihs@ict.tuwien.ac.at>*  . Reworked code for initiating bus resets*    (long, short, with or without hold-off)** Nandu Santhi <contactnandu@users.sourceforge.net>*  . Added support for nVidia nForce2 onboard Firewire chipset**/#include <linux/config.h>#include <linux/kernel.h>#include <linux/list.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 <linux/irq.h>#include <asm/byteorder.h>#include <asm/atomic.h>#include <asm/uaccess.h>#include <linux/delay.h>#include <linux/spinlock.h>#include <asm/pgtable.h>#include <asm/page.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/wrapper.h>#include <linux/vmalloc.h>#include <linux/init.h>#ifdef CONFIG_ALL_PPC#include <asm/machdep.h>#include <asm/pmac_feature.h>#include <asm/prom.h>#include <asm/pci-bridge.h>#endif#include "ieee1394.h"#include "ieee1394_types.h"#include "hosts.h"#include "dma.h"#include "iso.h"#include "ieee1394_core.h"#include "highlevel.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 "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)#else#define DBGMSG(card, fmt, args...)#endif#ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG#define OHCI_DMA_ALLOC(fmt, args...) \	HPSB_ERR("%s(%s)alloc(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \++global_outstanding_dmas, ## args)#define OHCI_DMA_FREE(fmt, args...) \	HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \--global_outstanding_dmas, ## args)static int global_outstanding_dmas = 0;#else#define OHCI_DMA_ALLOC(fmt, args...)#define OHCI_DMA_FREE(fmt, args...)#endif/* print general (card independent) information */#define PRINT_G(level, fmt, args...) \printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)/* print card specific information */#define PRINT(level, card, fmt, args...) \printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)static char version[] __devinitdata ="$Rev$ Ben Collins <bcollins@debian.org>";/* Module Parameters */MODULE_PARM(phys_dma,"i");MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1).");static int phys_dma = 1;static void dma_trm_tasklet(unsigned long data);static void dma_trm_reset(struct dma_trm_ctx *d);static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,							 enum context_type type, int ctx, int num_desc,							 int buf_size, int split_buf_size, int context_base);static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,							 enum context_type type, int ctx, int num_desc,							 int context_base);static void ohci1394_pci_remove(struct pci_dev *pdev);#ifndef __LITTLE_ENDIANstatic unsigned hdr_sizes[] = {		3,	/* TCODE_WRITEQ */		4,	/* TCODE_WRITEB */		3,	/* TCODE_WRITE_RESPONSE */		0,	/* ??? */		3,	/* TCODE_READQ */		4,	/* TCODE_READB */		3,	/* TCODE_READQ_RESPONSE */		4,	/* TCODE_READB_RESPONSE */		1,	/* TCODE_CYCLE_START (???) */		4,	/* TCODE_LOCK_REQUEST */		2,	/* TCODE_ISO_DATA */		4,	/* TCODE_LOCK_RESPONSE */};/* Swap headers */static inline void packet_swab(quadlet_t *data, int tcode){	size_t size = hdr_sizes[tcode];		//TCODE_LOCK_RESPONSE:0xb,see ieee1394.h	if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0)		return;		while (size--)		data[size] = swab32(data[size]);}#else/* Don't waste cycles on same sex byte swaps */#define packet_swab(w,x)#endif /* !LITTLE_ENDIAN *//************************************ IEEE-1394 functionality section ************************************/static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr) {	int i;	unsigned long flags;	quadlet_t r;		spin_lock_irqsave (&ohci->phy_reg_lock, flags);		//OHCI1394_PhyControl:0xEC,see pdf_doc,p54	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);		//rdReg		//wait for rdDone	for (i = 0; i < OHCI_LOOP_COUNT; i++) {		if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)			break;				mdelay(1);	}		//OHCI1394_PhyControl:0xEC,see pdf_doc,p54	r = reg_read(ohci, OHCI1394_PhyControl);		if (i >= OHCI_LOOP_COUNT)		PRINT (KERN_ERR, ohci->id, "Get PHY Reg timeout [0x%08x/0x%08x/%d]",		r, r & 0x80000000, i);		spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);		return (r & 0x00ff0000) >> 16;}static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data){	int i;	unsigned long flags;	u32 r = 0;		spin_lock_irqsave (&ohci->phy_reg_lock, flags);		//OHCI1394_PhyControl:0xEC,see pdf_doc,p54	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);	//wrReg		//wait for wrReg done	for (i = 0; i < OHCI_LOOP_COUNT; i++) {		r = reg_read(ohci, OHCI1394_PhyControl);		if (!(r & 0x00004000))			break;				mdelay(1);	}		if (i == OHCI_LOOP_COUNT)		PRINT (KERN_ERR, ohci->id, "Set PHY Reg timeout [0x%08x/0x%08x/%d]",		r, r & 0x00004000, i);		spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);		return;}/* Or's our value into the current value */static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data){	u8 old;		old = get_phy_reg (ohci, addr);	old |= data;	set_phy_reg (ohci, addr, old);		return;}//used in function:	ohci_irq_handler()static void 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);	//OHCI1394_SelfIDCount:0x68,see pdf_doc,p147	size_t size;	quadlet_t q0, q1;		/* Check status of self-id reception */		if (ohci->selfid_swap)		//see function:	ohci1394_pci_probe()		q0 = le32_to_cpu(q[0]);	else		q0 = q[0];		if ((self_id_count & 0x80000000) || 		((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {		PRINT(KERN_ERR, ohci->id, 			"Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",			self_id_count, q0, ohci->self_id_errors);					/* Tip by James Goodwin <jamesg@Filanet.com>:		* We had an error, generate another bus reset in response.  */		if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) {			set_phy_reg_mask (ohci, 1, 0x40);			ohci->self_id_errors++;		} else {			PRINT(KERN_ERR, ohci->id, 				"Too many errors on SelfID error reception, giving up!");		}		return;	}		/* SelfID Ok, reset error counter. */	ohci->self_id_errors = 0;		size = ((self_id_count & 0x00001FFC) >> 2) - 1;	q++;		while (size > 0) {		if (ohci->selfid_swap) {			q0 = le32_to_cpu(q[0]);			q1 = le32_to_cpu(q[1]);		} else {			q0 = q[0];			q1 = q[1];		}				if (q0 == ~q1) {			DBGMSG (ohci->id, "SelfID packet 0x%x received", q0);			hpsb_selfid_received(host, cpu_to_be32(q0));	//see ieee1394_core.c,host->topology_map[host->selfid_count++] = sid;			if (((q0 & 0x3f000000) >> 24) == phyid)				DBGMSG (ohci->id, "SelfID for this node is 0x%08x", q0);		} else {			PRINT(KERN_ERR, ohci->id,				"SelfID is inconsistent [0x%08x/0x%08x]", q0, q1);		}		q += 2;		size -= 2;	}		DBGMSG(ohci->id, "SelfID complete");		return;}//soft resetstatic void ohci_soft_reset(struct ti_ohci *ohci) {	int i;		//OHCI1394_HCControlSet:0x50	//OHCI1394_HCControl_softReset:0x10000,see pdf_doc,p45,p47	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);		for (i = 0; i < OHCI_LOOP_COUNT; i++) {		if (!reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset)			break;		mdelay(1);	}	DBGMSG (ohci->id, "Soft reset finished");}//在运行之前,判断OHCI的nodeNumber是否有效,并且保证nodeNumber!=63,//然后再Run the dma context.//called by:	dma_trm_flush()static int run_context(struct ti_ohci *ohci, int reg, char *msg){	u32 nodeId;		/* check that the node id is valid */	//OHCI1394_NodeID:0xE8,see pdf_doc,p53	nodeId = reg_read(ohci, OHCI1394_NodeID);	//iDValid ?	if (!(nodeId&0x80000000)) {		PRINT(KERN_ERR, ohci->id, 			"Running dma failed because Node ID is 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_DEBUG, 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, int generate_irq){	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++) {		u32 c;				//DMA_CTL_INPUT_MORE:0x20000000	:cmd		//DMA_CTL_UPDATE:0x08000000			:s		//DMA_CTL_BRANCH:0x000c0000			:key		//DMA_CTL_IRQ:0x00300000				:i		c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;		//see pdf_doc,p95		if (generate_irq)			c |= DMA_CTL_IRQ;				d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size);	//d->buf_size:	reqCount				/* End of descriptor list? */		if (i + 1 < d->num_desc) {			d->prg_cpu[i]->branchAddress =				cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1);

⌨️ 快捷键说明

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