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

📄 ieee1394_core.c

📁 ieee1394驱动,不多说了!直接可以在linux2.6内核中使用
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * IEEE 1394 for Linux * * Core support: hpsb_packet management, packet handling and forwarding to *               highlevel or lowlevel code * * Copyright (C) 1999, 2000 Andreas E. Bombe *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.at> * * This code is licensed under the GPL.  See the file COPYING in the root * directory of the kernel sources for details. * * * Contributions: * * Manfred Weihs <weihs@ict.tuwien.ac.at> *        loopback functionality in hpsb_send_packet *        allow highlevel drivers to disable automatic response generation *              and to generate responses themselves (deferred) * */#include <linux/kernel.h>#include <linux/list.h>#include <linux/string.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/bitops.h>#include <linux/kdev_t.h>#include <linux/skbuff.h>#include <linux/suspend.h>#include <linux/kthread.h>#include <linux/preempt.h>#include <linux/time.h>#include <asm/system.h>#include <asm/byteorder.h>#include "ieee1394_types.h"#include "ieee1394.h"#include "hosts.h"#include "ieee1394_core.h"#include "highlevel.h"#include "ieee1394_transactions.h"#include "csr.h"#include "nodemgr.h"#include "dma.h"#include "iso.h"#include "config_roms.h"/* * Disable the nodemgr detection and config rom reading functionality. */static int disable_nodemgr;module_param(disable_nodemgr, int, 0444);MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");/* Disable Isochronous Resource Manager functionality */int hpsb_disable_irm = 0;module_param_named(disable_irm, hpsb_disable_irm, bool, 0444);MODULE_PARM_DESC(disable_irm,		 "Disable Isochronous Resource Manager functionality.");/* We are GPL, so treat us special */MODULE_LICENSE("GPL");/* Some globals used */const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };struct class *hpsb_protocol_class;#ifdef CONFIG_IEEE1394_VERBOSEDEBUGstatic void dump_packet(const char *text, quadlet_t *data, int size, int speed){	int i;	size /= 4;	size = (size > 4 ? 4 : size);	printk(KERN_DEBUG "ieee1394: %s", text);	if (speed > -1 && speed < 6)		printk(" at %s", hpsb_speedto_str[speed]);	printk(":");	for (i = 0; i < size; i++)		printk(" %08x", data[i]);	printk("\n");}#else#define dump_packet(a,b,c,d) do {} while (0)#endifstatic void abort_requests(struct hpsb_host *host);static void queue_packet_complete(struct hpsb_packet *packet);/** * hpsb_set_packet_complete_task - set the task that runs when a packet * completes. You cannot call this more than once on a single packet * before it is sent. * * @packet: the packet whose completion we want the task added to * @routine: function to call * @data: data (if any) to pass to the above function */void hpsb_set_packet_complete_task(struct hpsb_packet *packet,				   void (*routine)(void *), void *data){	WARN_ON(packet->complete_routine != NULL);	packet->complete_routine = routine;	packet->complete_data = data;	return;}/** * hpsb_alloc_packet - allocate new packet structure * @data_size: size of the data block to be allocated * * This function allocates, initializes and returns a new &struct hpsb_packet. * It can be used in interrupt context.  A header block is always included, its * size is big enough to contain all possible 1394 headers.  The data block is * only allocated when @data_size is not zero. * * For packets for which responses will be received the @data_size has to be big * enough to contain the response's data block since no further allocation * occurs at response matching time. * * The packet's generation value will be set to the current generation number * for ease of use.  Remember to overwrite it with your own recorded generation * number if you can not be sure that your code will not race with a bus reset. * * Return value: A pointer to a &struct hpsb_packet or NULL on allocation * failure. */struct hpsb_packet *hpsb_alloc_packet(size_t data_size){	struct hpsb_packet *packet = NULL;	struct sk_buff *skb;	data_size = ((data_size + 3) & ~3);	skb = alloc_skb(data_size + sizeof(*packet), GFP_ATOMIC);	if (skb == NULL)		return NULL;	memset(skb->data, 0, data_size + sizeof(*packet));	packet = (struct hpsb_packet *)skb->data;	packet->skb = skb;	packet->header = packet->embedded_header;	packet->state = hpsb_unused;	packet->generation = -1;	INIT_LIST_HEAD(&packet->driver_list);	atomic_set(&packet->refcnt, 1);	if (data_size) {		packet->data = (quadlet_t *)(skb->data + sizeof(*packet));		packet->data_size = data_size;	}	return packet;}/** * hpsb_free_packet - free packet and data associated with it * @packet: packet to free (is NULL safe) * * This function will free packet->data and finally the packet itself. */void hpsb_free_packet(struct hpsb_packet *packet){	if (packet && atomic_dec_and_test(&packet->refcnt)) {		BUG_ON(!list_empty(&packet->driver_list));		kfree_skb(packet->skb);	}}int hpsb_reset_bus(struct hpsb_host *host, int type){	if (!host->in_bus_reset) {		host->driver->devctl(host, RESET_BUS, type);		return 0;	} else {		return 1;	}}/** * hpsb_read_cycle_timer - read cycle timer register and system time * @host: host whose isochronous cycle timer register is read * @cycle_timer: address of bitfield to return the register contents * @local_time: address to return the system time * * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This * format is also read from non-OHCI controllers. * @local_time contains the * system time in microseconds since the Epoch, read at the moment when the * cycle timer was read. * * Return value: 0 for success or error number otherwise. */int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,			  u64 *local_time){	int ctr;	struct timeval tv;	unsigned long flags;	if (!host || !cycle_timer || !local_time)		return -EINVAL;	preempt_disable();	local_irq_save(flags);	ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0);	if (ctr)		do_gettimeofday(&tv);	local_irq_restore(flags);	preempt_enable();	if (!ctr)		return -EIO;	*cycle_timer = ctr;	*local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;	return 0;}int hpsb_bus_reset(struct hpsb_host *host){	if (host->in_bus_reset) {		HPSB_NOTICE("%s called while bus reset already in progress",			    __FUNCTION__);		return 1;	}	abort_requests(host);	host->in_bus_reset = 1;	host->irm_id = -1;	host->is_irm = 0;	host->busmgr_id = -1;	host->is_busmgr = 0;	host->is_cycmst = 0;	host->node_count = 0;	host->selfid_count = 0;	return 0;}/* * Verify num_of_selfids SelfIDs and return number of nodes.  Return zero in * case verification failed. */static int check_selfids(struct hpsb_host *host){	int nodeid = -1;	int rest_of_selfids = host->selfid_count;	struct selfid *sid = (struct selfid *)host->topology_map;	struct ext_selfid *esid;	int esid_seq = 23;	host->nodes_active = 0;	while (rest_of_selfids--) {		if (!sid->extended) {			nodeid++;			esid_seq = 0;			if (sid->phy_id != nodeid) {				HPSB_INFO("SelfIDs failed monotony check with "					  "%d", sid->phy_id);				return 0;			}			if (sid->link_active) {				host->nodes_active++;				if (sid->contender)					host->irm_id = LOCAL_BUS | sid->phy_id;			}		} else {			esid = (struct ext_selfid *)sid;			if ((esid->phy_id != nodeid)			    || (esid->seq_nr != esid_seq)) {				HPSB_INFO("SelfIDs failed monotony check with "					  "%d/%d", esid->phy_id, esid->seq_nr);				return 0;			}			esid_seq++;		}		sid++;	}	esid = (struct ext_selfid *)(sid - 1);	while (esid->extended) {		if ((esid->porta == SELFID_PORT_PARENT) ||		    (esid->portb == SELFID_PORT_PARENT) ||		    (esid->portc == SELFID_PORT_PARENT) ||		    (esid->portd == SELFID_PORT_PARENT) ||		    (esid->porte == SELFID_PORT_PARENT) ||		    (esid->portf == SELFID_PORT_PARENT) ||		    (esid->portg == SELFID_PORT_PARENT) ||		    (esid->porth == SELFID_PORT_PARENT)) {			HPSB_INFO("SelfIDs failed root check on "				  "extended SelfID");			return 0;		}		esid--;	}	sid = (struct selfid *)esid;	if ((sid->port0 == SELFID_PORT_PARENT) ||	    (sid->port1 == SELFID_PORT_PARENT) ||	    (sid->port2 == SELFID_PORT_PARENT)) {		HPSB_INFO("SelfIDs failed root check");		return 0;	}	host->node_count = nodeid + 1;	return 1;}static void build_speed_map(struct hpsb_host *host, int nodecount){	u8 cldcnt[nodecount];	u8 *map = host->speed_map;	u8 *speedcap = host->speed;	struct selfid *sid;	struct ext_selfid *esid;	int i, j, n;	for (i = 0; i < (nodecount * 64); i += 64) {		for (j = 0; j < nodecount; j++) {			map[i+j] = IEEE1394_SPEED_MAX;		}	}	for (i = 0; i < nodecount; i++) {		cldcnt[i] = 0;	}	/* find direct children count and speed */	for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],		     n = nodecount - 1;	     (void *)sid >= (void *)host->topology_map; sid--) {		if (sid->extended) {			esid = (struct ext_selfid *)sid;			if (esid->porta == SELFID_PORT_CHILD) cldcnt[n]++;			if (esid->portb == SELFID_PORT_CHILD) cldcnt[n]++;			if (esid->portc == SELFID_PORT_CHILD) cldcnt[n]++;			if (esid->portd == SELFID_PORT_CHILD) cldcnt[n]++;			if (esid->porte == SELFID_PORT_CHILD) cldcnt[n]++;			if (esid->portf == SELFID_PORT_CHILD) cldcnt[n]++;			if (esid->portg == SELFID_PORT_CHILD) cldcnt[n]++;			if (esid->porth == SELFID_PORT_CHILD) cldcnt[n]++;                } else {			if (sid->port0 == SELFID_PORT_CHILD) cldcnt[n]++;			if (sid->port1 == SELFID_PORT_CHILD) cldcnt[n]++;			if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++;			speedcap[n] = sid->speed;			n--;		}	}	/* set self mapping */	for (i = 0; i < nodecount; i++) {		map[64*i + i] = speedcap[i];	}	/* fix up direct children count to total children count;	 * also fix up speedcaps for sibling and parent communication */	for (i = 1; i < nodecount; i++) {		for (j = cldcnt[i], n = i - 1; j > 0; j--) {			cldcnt[i] += cldcnt[n];			speedcap[n] = min(speedcap[n], speedcap[i]);			n -= cldcnt[n] + 1;		}	}	for (n = 0; n < nodecount; n++) {		for (i = n - cldcnt[n]; i <= n; i++) {			for (j = 0; j < (n - cldcnt[n]); j++) {				map[j*64 + i] = map[i*64 + j] =					min(map[i*64 + j], speedcap[n]);			}			for (j = n + 1; j < nodecount; j++) {				map[j*64 + i] = map[i*64 + j] =					min(map[i*64 + j], speedcap[n]);			}		}	}#if SELFID_SPEED_UNKNOWN != IEEE1394_SPEED_MAX	/* assume maximum speed for 1394b PHYs, nodemgr will correct it */	for (n = 0; n < nodecount; n++)		if (speedcap[n] == SELFID_SPEED_UNKNOWN)			speedcap[n] = IEEE1394_SPEED_MAX;#endif}void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid){	if (host->in_bus_reset) {		HPSB_VERBOSE("Including SelfID 0x%x", sid);		host->topology_map[host->selfid_count++] = sid;	} else {		HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",			    sid, NODEID_TO_BUS(host->node_id));	}}void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot){	if (!host->in_bus_reset)		HPSB_NOTICE("SelfID completion called outside of bus reset!");	host->node_id = LOCAL_BUS | phyid;	host->is_root = isroot;	if (!check_selfids(host)) {		if (host->reset_retries++ < 20) {			/* selfid stage did not complete without error */			HPSB_NOTICE("Error in SelfID stage, resetting");			host->in_bus_reset = 0;			/* this should work from ohci1394 now... */			hpsb_reset_bus(host, LONG_RESET);			return;		} else {			HPSB_NOTICE("Stopping out-of-control reset loop");			HPSB_NOTICE("Warning - topology map and speed map will not be valid");			host->reset_retries = 0;		}	} else {		host->reset_retries = 0;

⌨️ 快捷键说明

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