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

📄 nodemgr.c

📁 1394在linux下单独的驱动程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/** Node information (ConfigROM) collection and management.** Copyright (C) 2000		Andreas E. Bombe*               2001-2003	Ben Collins <bcollins@debian.net>** This code is licensed under the GPL.  See the file COPYING in the root* directory of the kernel sources for details.*/#include <linux/kernel.h>#include <linux/config.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/kmod.h>#include <linux/completion.h>#include <linux/delay.h>#ifdef CONFIG_PROC_FS#include <linux/proc_fs.h>#endif#include "ieee1394_types.h"#include "ieee1394.h"#include "nodemgr.h"#include "hosts.h"#include "ieee1394_transactions.h"#include "highlevel.h"#include "csr.h"#include "nodemgr.h"static char *nodemgr_find_oui_name(int oui){#ifdef CONFIG_IEEE1394_OUI_DB	extern struct oui_list_struct {		int oui;		char *name;	} oui_list[];	int i;		for (i = 0; oui_list[i].name; i++)		if (oui_list[i].oui == oui)			return oui_list[i].name;#endif		return NULL;}/* * Basically what we do here is start off retrieving the bus_info block.* From there will fill in some info about the node, verify it is of IEEE* 1394 type, and that the crc checks out ok. After that we start off with* the root directory, and subdirectories. To do this, we retrieve the* quadlet header for a directory, find out the length, and retrieve the* complete directory entry (be it a leaf or a directory). We then process* it and add the info to our structure for that particular node.** We verify CRC's along the way for each directory/block/leaf. The entire* node structure is generic, and simply stores the information in a way* that's easy to parse by the protocol interface.*//* The nodemgr maintains a number of data structures: the node list,* the driver list, unit directory list and the host info list.  The* first three lists are accessed from process context only: /proc* readers, insmod and rmmod, and the nodemgr thread.  Access to these* lists are serialized by means of the nodemgr_serialize mutex, which* must be taken before accessing the structures and released* afterwards.  The host info list is only accessed during insmod,* rmmod and from interrupt and allways only for a short period of* time, so a spinlock is used to protect this list.*/static DECLARE_MUTEX(nodemgr_serialize);static LIST_HEAD(node_list);static LIST_HEAD(driver_list);static LIST_HEAD(unit_directory_list);struct host_info {	struct hpsb_host *host;	struct completion exited;	struct semaphore reset_sem;	int pid;	char daemon_name[15];};static struct hpsb_highlevel nodemgr_highlevel;#ifdef CONFIG_PROC_FS#define PUTF(fmt, args...)				\	do {							\	len += sprintf(page + len, fmt, ## args);	\	pos = begin + len;				\	if (pos < off) {				\	len = 0;				\	begin = pos;				\	}						\	if (pos > off + count)				\	goto done_proc;				\	} while (0)static int raw1394_read_proc(char *page, char **start, off_t off,							 int count, int *eof, void *data){	struct list_head *lh;	struct node_entry *ne;	off_t begin = 0, pos = 0;	int len = 0;		if (down_interruptible(&nodemgr_serialize))		return -EINTR;		list_for_each(lh, &node_list) {		struct list_head *l;		int ud_count = 0, lud_count = 0;				ne = list_entry(lh, struct node_entry, list);		if (!ne)			continue;				PUTF("Node[" NODE_BUS_FMT "]  GUID[%016Lx]:\n",			NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);				/* Generic Node information */		PUTF("  Vendor ID: `%s' [0x%06x]\n",			ne->vendor_name ?: "Unknown", ne->vendor_id);		PUTF("  Capabilities: 0x%06x\n", ne->capabilities);		PUTF("  Bus Options:\n");		PUTF("    IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d)\n"			"    LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)\n",			ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,			ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,			ne->busopt.max_rec, ne->busopt.cyc_clk_acc);				/* If this is the host entry, output some info about it aswell */		if (ne->host != NULL && ne->host->node_id == ne->nodeid) {			PUTF("  Host Node Status:\n");			PUTF("    Host Driver     : %s\n", ne->host->driver->name);			PUTF("    Nodes connected : %d\n", ne->host->node_count);			PUTF("    Nodes active    : %d\n", ne->host->nodes_active);			PUTF("    SelfIDs received: %d\n", ne->host->selfid_count);			PUTF("    Irm ID          : [" NODE_BUS_FMT "]\n",				NODE_BUS_ARGS(ne->host, ne->host->irm_id));			PUTF("    BusMgr ID       : [" NODE_BUS_FMT "]\n",				NODE_BUS_ARGS(ne->host, ne->host->busmgr_id));			PUTF("    In Bus Reset    : %s\n", ne->host->in_bus_reset ? "yes" : "no");			PUTF("    Root            : %s\n", ne->host->is_root ? "yes" : "no");			PUTF("    Cycle Master    : %s\n", ne->host->is_cycmst ? "yes" : "no");			PUTF("    IRM             : %s\n", ne->host->is_irm ? "yes" : "no");			PUTF("    Bus Manager     : %s\n", ne->host->is_busmgr ? "yes" : "no");		}				/* Now the unit directories */		list_for_each (l, &ne->unit_directories) {			struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);			int printed = 0; // small hack						if (ud->parent == NULL)				PUTF("  Unit Directory %d:\n", lud_count++);			else				PUTF("  Logical Unit Directory %d:\n", ud_count++);			if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {				PUTF("    Vendor/Model ID: %s [%06x]",					ud->vendor_name ?: "Unknown", ud->vendor_id);				printed = 1;			}			if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {				if (!printed)					PUTF("    Vendor/Model ID: %s [%06x]",					ne->vendor_name ?: "Unknown", ne->vendor_id);				PUTF(" / %s [%06x]", ud->model_name ?: "Unknown", ud->model_id);				printed = 1;			}			if (printed)				PUTF("\n");						if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)				PUTF("    Software Specifier ID: %06x\n", ud->specifier_id);			if (ud->flags & UNIT_DIRECTORY_VERSION)				PUTF("    Software Version: %06x\n", ud->version);			if (ud->driver)				PUTF("    Driver: %s\n", ud->driver->name);			PUTF("    Length (in quads): %d\n", ud->length);		}			}	done_proc:	up(&nodemgr_serialize);		*start = page + (off - begin);	len -= (off - begin);	if (len > count)		len = count;	else {		*eof = 1;		if (len <= 0)			return 0;	}		return len;}							 #undef PUTF#endif /* CONFIG_PROC_FS */static void nodemgr_process_config_rom(struct node_entry *ne, 									   quadlet_t busoptions);static int nodemgr_read_quadlet(struct hpsb_host *host,								nodeid_t nodeid, unsigned int generation,								octlet_t address, quadlet_t *quad){	int i;	int ret = 0;		for (i = 0; i < 3; i++) {		ret = hpsb_read(host, nodeid, generation, address, quad, 4);		if (!ret)			break;				set_current_state(TASK_INTERRUPTIBLE);		if (schedule_timeout (HZ/3))			return -1;	}	*quad = be32_to_cpu(*quad);		return ret;}static int nodemgr_size_text_leaf(struct hpsb_host *host,								  nodeid_t nodeid, unsigned int generation,								  octlet_t address){	quadlet_t quad;	int size = 0;		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))		return -1;		if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) {		/* This is the offset.  */		address += 4 * CONFIG_ROM_VALUE(quad); 		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))			return -1;		/* Now we got the size of the text descriptor leaf. */		size = CONFIG_ROM_LEAF_LENGTH(quad);	}		return size;}static int nodemgr_read_text_leaf(struct node_entry *ne,								  octlet_t address,								  quadlet_t *quadp){	quadlet_t quad;	int i, size, ret;		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)		|| CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF)		return -1;		/* This is the offset.  */	address += 4 * CONFIG_ROM_VALUE(quad);	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad))		return -1;		/* Now we got the size of the text descriptor leaf. */	size = CONFIG_ROM_LEAF_LENGTH(quad) - 2;	if (size <= 0)		return -1;		address += 4;	for (i = 0; i < 2; i++, address += 4, quadp++) {		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, quadp))			return -1;	}		/* Now read the text string.  */	ret = -ENXIO;	for (; size > 0; size--, address += 4, quadp++) {		for (i = 0; i < 3; i++) {			ret = hpsb_node_read(ne, address, quadp, 4);			if (ret != -EAGAIN)				break;		}		if (ret)			break;	}		return ret;}static struct node_entry *nodemgr_scan_root_directory(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation){	octlet_t address;	quadlet_t quad;	int length;	int code, size, total_size;	struct node_entry *ne;		address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))		return NULL;		if (CONFIG_ROM_BUS_INFO_LENGTH(quad) == 1)  /* minimal config rom */		return NULL;		address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))		return NULL;	length = CONFIG_ROM_ROOT_LENGTH(quad);	address += 4;		size = 0;	total_size = sizeof(struct node_entry);	for (; length > 0; length--, address += 4) {		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))			return NULL;		code = CONFIG_ROM_KEY(quad);				if (code == CONFIG_ROM_VENDOR_ID && length > 0) {		/* Check if there is a text descriptor leaf			immediately after this.  */			size = nodemgr_size_text_leaf(host, nodeid, generation,				address + 4);			if (size > 0) {				address += 4;				length--;				total_size += (size + 1) * sizeof (quadlet_t);			} else if (size < 0)				return NULL;		}	}	ne = kmalloc(total_size, GFP_KERNEL);		if (!ne)		return NULL;		memset(ne, 0, total_size);		if (size != 0) {		ne->vendor_name = (const char *) &(ne->quadlets[2]);		ne->quadlets[size] = 0;	} else {		ne->vendor_name = NULL;	}		return ne; }static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,											  struct host_info *hi,											  nodeid_t nodeid, unsigned int generation){	struct hpsb_host *host = hi->host;	struct node_entry *ne;		ne = nodemgr_scan_root_directory (host, nodeid, generation);	if (!ne) return NULL;		INIT_LIST_HEAD(&ne->list);	INIT_LIST_HEAD(&ne->unit_directories);	ne->host = host;	ne->nodeid = nodeid;	ne->generation = generation;	ne->guid = guid;	ne->guid_vendor_id = (guid >> 40) & 0xffffff;	ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id);		list_add_tail(&ne->list, &node_list);		nodemgr_process_config_rom (ne, busoptions);		HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",		(host->node_id == nodeid) ? "Host" : "Node",		NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);		return ne;}static struct node_entry *find_entry_by_guid(u64 guid){	struct list_head *lh;	struct node_entry *ne;		list_for_each(lh, &node_list) {		ne = list_entry(lh, struct node_entry, list);		if (ne->guid == guid) return ne;	}		return NULL;}static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid){	struct list_head *lh;	struct node_entry *ne;		list_for_each(lh, &node_list) {		ne = list_entry(lh, struct node_entry, list);		if (ne->nodeid == nodeid && ne->host == host)			return ne;	}		return NULL;}static struct unit_directory *nodemgr_scan_unit_directory(struct node_entry *ne, octlet_t address){	struct unit_directory *ud;	quadlet_t quad;	u8 flags, todo;	int length, size, total_size, count;	int vendor_name_size, model_name_size;		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad))		return NULL;	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;	address += 4;		size = 0;	total_size = sizeof (struct unit_directory);	flags = 0;	count = 0;	vendor_name_size = 0;	model_name_size = 0;	for (; length > 0; length--, address += 4) {		int code;		quadlet_t value;				if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,			address, &quad))			return NULL;		code = CONFIG_ROM_KEY(quad);		value = CONFIG_ROM_VALUE(quad);				todo = 0;		switch (code) {		case CONFIG_ROM_VENDOR_ID:			todo = UNIT_DIRECTORY_VENDOR_TEXT;			break;					case CONFIG_ROM_MODEL_ID:			todo = UNIT_DIRECTORY_MODEL_TEXT;			break;					case CONFIG_ROM_SPECIFIER_ID:		case CONFIG_ROM_UNIT_SW_VERSION:			break;					case CONFIG_ROM_DESCRIPTOR_LEAF:		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:			/* TODO: read strings... icons? */			break;					default:		/* Which types of quadlets do we want to		store?  Only count immediate values and			CSR offsets for now.  */			code &= CONFIG_ROM_KEY_TYPE_MASK;			if ((code & CONFIG_ROM_KEY_TYPE_LEAF) == 0)				count++;			break;		}				if (todo && length > 0) {		/* Check if there is a text descriptor leaf			immediately after this.  */			size = nodemgr_size_text_leaf(ne->host,				ne->nodeid,				ne->generation,				address + 4);						if (todo == UNIT_DIRECTORY_VENDOR_TEXT)				vendor_name_size = size;			else				model_name_size = size;						if (size > 0) {				address += 4;				length--;				flags |= todo;				total_size += (size + 1) * sizeof (quadlet_t);			}			else if (size < 0)				return NULL;		}	}		total_size += count * sizeof (quadlet_t);	ud = kmalloc (total_size, GFP_KERNEL);		if (ud != NULL) {		memset (ud, 0, total_size);		ud->flags = flags;		ud->length = count;		ud->vendor_name_size = vendor_name_size;

⌨️ 快捷键说明

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