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

📄 ieee1394_core.c

📁 1394在linux下单独的驱动程序代码
💻 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/config.h>#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/proc_fs.h>#include <linux/bitops.h>#include <asm/byteorder.h>#include <asm/semaphore.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"/** Disable the nodemgr detection and config rom reading functionality.*/MODULE_PARM(disable_nodemgr, "i");MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");static int disable_nodemgr = 0;/* We are GPL, so treat us special */MODULE_LICENSE("GPL");static kmem_cache_t *hpsb_packet_cache;/* Some globals used */const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };#ifdef CONFIG_IEEE1394_VERBOSEDEBUGstatic void dump_packet(const char *text, quadlet_t *data, int size){	int i;		size /= 4;	size = (size > 4 ? 4 : size);		printk(KERN_DEBUG "ieee1394: %s", text);	for (i = 0; i < size; i++)		printk(" %08x", data[i]);	printk("\n");}#else#define dump_packet(x,y,z)#endifstatic void run_packet_complete(struct hpsb_packet *packet){	if (packet->complete_routine != NULL) {		void (*complete_routine)(void*) = packet->complete_routine;		void *complete_data = packet->complete_data;				packet->complete_routine = NULL;		packet->complete_data = NULL;		complete_routine(complete_data);	}	return;}/*** 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){	BUG_ON(packet->complete_routine != NULL);	packet->complete_routine = routine;	packet->complete_data = data;	return;}/*** alloc_hpsb_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 *alloc_hpsb_packet(size_t data_size){	struct hpsb_packet *packet = NULL;	void *data = NULL;		packet = kmem_cache_alloc(hpsb_packet_cache, GFP_ATOMIC);	if (packet == NULL)		return NULL;		memset(packet, 0, sizeof(struct hpsb_packet));	packet->header = packet->embedded_header;		if (data_size) {		data = kmalloc(data_size + 8, GFP_ATOMIC);		if (data == NULL) {			kmem_cache_free(hpsb_packet_cache, packet);			return NULL;		}				packet->data = data;		packet->data_size = data_size;	}		INIT_LIST_HEAD(&packet->list);	sema_init(&packet->state_change, 0);	packet->complete_routine = NULL;	packet->complete_data = NULL;	packet->state = hpsb_unused;	packet->generation = -1;	packet->data_be = 1;		return packet;}/*** free_hpsb_packet - free packet and data associated with it* @packet: packet to free (is NULL safe)** This function will free packet->data, packet->header and finally the packet* itself.*/void free_hpsb_packet(struct hpsb_packet *packet){	if (!packet) return;		kfree(packet->data);	kmem_cache_free(hpsb_packet_cache, packet);}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;	}}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 == 0x2) || (esid->portb == 0x2)			|| (esid->portc == 0x2) || (esid->portd == 0x2)			|| (esid->porte == 0x2) || (esid->portf == 0x2)			|| (esid->portg == 0x2) || (esid->porth == 0x2)) {			HPSB_INFO("SelfIDs failed root check on "				"extended SelfID");			return 0;		}		esid--;	}		sid = (struct selfid *)esid;	if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) {		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 speedcap[nodecount];	u8 cldcnt[nodecount];	u8 *map = host->speed_map;	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 == 0x3) cldcnt[n]++;			if (esid->portb == 0x3) cldcnt[n]++;			if (esid->portc == 0x3) cldcnt[n]++;			if (esid->portd == 0x3) cldcnt[n]++;			if (esid->porte == 0x3) cldcnt[n]++;			if (esid->portf == 0x3) cldcnt[n]++;			if (esid->portg == 0x3) cldcnt[n]++;			if (esid->porth == 0x3) cldcnt[n]++;		} else {			if (sid->port0 == 0x3) cldcnt[n]++;			if (sid->port1 == 0x3) cldcnt[n]++;			if (sid->port2 == 0x3) 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]);			}		}	}}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;		build_speed_map(host, host->node_count);	}		HPSB_VERBOSE("selfid_complete called with successful SelfID stage "		"... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);		/* irm_id is kept up to date by check_selfids() */	if (host->irm_id == host->node_id) {		host->is_irm = 1;	} else {		host->is_busmgr = 0;		host->is_irm = 0;	}		if (isroot) {		host->driver->devctl(host, ACT_CYCLE_MASTER, 1);		host->is_cycmst = 1;	}	atomic_inc(&host->generation);	host->in_bus_reset = 0;	highlevel_host_reset(host);}void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,                       int ackcode){	unsigned long flags;		packet->ack_code = ackcode;		if (packet->no_waiter) {		/* must not have a tlabel allocated */		free_hpsb_packet(packet);		return;	}		if (ackcode != ACK_PENDING || !packet->expect_response) {		packet->state = hpsb_complete;		up(&packet->state_change);		up(&packet->state_change);		run_packet_complete(packet);		return;	}		packet->state = hpsb_pending;	packet->sendtime = jiffies;		spin_lock_irqsave(&host->pending_pkt_lock, flags);	list_add_tail(&packet->list, &host->pending_packets);	spin_unlock_irqrestore(&host->pending_pkt_lock, flags);		up(&packet->state_change);	mod_timer(&host->timeout, jiffies + host->timeout_interval);}/*** hpsb_send_phy_config - transmit a PHY configuration packet on the bus* @host: host that PHY config packet gets sent through* @rootid: root whose force_root bit should get set (-1 = don't set force_root)* @gapcnt: gap count value to set (-1 = don't set gap count)** This function sends a PHY config packet on the bus through the specified host.*

⌨️ 快捷键说明

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