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

📄 nodemgr.c

📁 IEE1394 火线接口驱动 for 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 + -