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

📄 nodemgr.c

📁 idt mips 32365上面移植实现的iee1394驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Node information (ConfigROM) collection and management. * * Copyright (C) 2000 Andreas E. Bombe *               2001 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/list.h>#include <linux/slab.h>#include <asm/byteorder.h>#include <asm/atomic.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/kmod.h>#include "ieee1394_types.h"#include "ieee1394.h"#include "hosts.h"#include "ieee1394_transactions.h"#include "ieee1394_hotplug.h"#include "highlevel.h"#include "csr.h"#include "nodemgr.h"/*  * 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. */static LIST_HEAD(node_list);static rwlock_t node_lock = RW_LOCK_UNLOCKED;static LIST_HEAD(driver_list);static rwlock_t driver_lock = RW_LOCK_UNLOCKED;/* The rwlock unit_directory_lock is always held when manipulating the * global unit_directory_list, but this also protects access to the * lists of unit directories stored in the protocol drivers. */static LIST_HEAD(unit_directory_list);static rwlock_t unit_directory_lock = RW_LOCK_UNLOCKED;static LIST_HEAD(host_info_list);static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;struct host_info {	struct hpsb_host *host;	struct tq_struct task;	struct list_head list;};static void nodemgr_process_config_rom(struct node_entry *ne, 				       quadlet_t busoptions);static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,					      struct hpsb_host *host, nodeid_t nodeid){        struct node_entry *ne;        unsigned long flags;        ne = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC);        if (!ne) return NULL;        INIT_LIST_HEAD(&ne->list);	INIT_LIST_HEAD(&ne->unit_directories);        ne->host = host;        ne->nodeid = nodeid;        ne->guid = guid;	atomic_set(&ne->generation, get_hpsb_generation(ne->host));        write_lock_irqsave(&node_lock, flags);        list_add_tail(&ne->list, &node_list);        write_unlock_irqrestore(&node_lock, flags);	nodemgr_process_config_rom (ne, busoptions);	HPSB_DEBUG("%s added: node " NODE_BUS_FMT ", GUID %016Lx",		   (host->node_id == nodeid) ? "Local host" : "Device",		   NODE_BUS_ARGS(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(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) return ne;	}	return NULL;}int nodemgr_read_quadlet(struct node_entry *ne,			 octlet_t address, quadlet_t *quad){	int i;	int ret = 0;	for (i = 0; i < 3; i++) {		ret = hpsb_read(ne->host, ne->nodeid, address, quad, 4);		if (ret != -EAGAIN)			break;	}	*quad = be32_to_cpu(*quad);	return ret;}#define CONFIG_ROM_VENDOR_ID		0x03#define CONFIG_ROM_MODEL_ID		0x17#define CONFIG_ROM_NODE_CAPABILITES	0x0C#define CONFIG_ROM_UNIT_DIRECTORY	0xd1#define CONFIG_ROM_SPECIFIER_ID		0x12 #define CONFIG_ROM_VERSION		0x13#define CONFIG_ROM_DESCRIPTOR_LEAF	0x81#define CONFIG_ROM_DESCRIPTOR_DIRECTORY	0xc1/* This implementation currently only scans the config rom and its * immediate unit directories looking for software_id and * software_version entries, in order to get driver autoloading working. */static void nodemgr_process_unit_directory(struct node_entry *ne, 					   octlet_t address){	struct unit_directory *ud;	octlet_t a;	quadlet_t quad;	int length, i;	if (!(ud = kmalloc (sizeof *ud, GFP_KERNEL)))		goto unit_directory_error;	memset (ud, 0, sizeof *ud);	ud->ne = ne;	ud->address = address;	ud->arb_count = 0;	if (nodemgr_read_quadlet(ne, address, &quad))		goto unit_directory_error;	length = quad >> 16;	a = address + 4;	for (i = 0; i < length; i++, a += 4) {		int code;		quadlet_t value;		if (nodemgr_read_quadlet(ne, a, &quad))			goto unit_directory_error;		code = quad >> 24;		value = quad & 0xffffff;		switch (code) {		case CONFIG_ROM_VENDOR_ID:			ud->vendor_id = value;			ud->flags |= UNIT_DIRECTORY_VENDOR_ID;			break;		case CONFIG_ROM_MODEL_ID:			ud->model_id = value;			ud->flags |= UNIT_DIRECTORY_MODEL_ID;			break;		case CONFIG_ROM_SPECIFIER_ID:			ud->specifier_id = value;			ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;			break;		case CONFIG_ROM_VERSION:			ud->version = value;			ud->flags |= UNIT_DIRECTORY_VERSION;			break;		case CONFIG_ROM_DESCRIPTOR_LEAF:		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:			/* TODO: read strings... icons? */			break;		default:			if (ud->arb_count < 16) {				/* Place them in the arbitrary pairs */				ud->arb_keys[ud->arb_count] = code;				ud->arb_values[ud->arb_count] = value;				ud->arb_count++;			}		}	}	list_add_tail(&ud->node_list, &ne->unit_directories);	list_add_tail(&ud->driver_list, &unit_directory_list);	return;unit_directory_error:		if (ud != NULL)		kfree(ud);}static void dump_directories (struct node_entry *ne){#ifdef CONFIG_IEEE1394_VERBOSEDEBUG	struct list_head *l;	HPSB_DEBUG("vendor_id=0x%06x, capabilities=0x%06x",		   ne->vendor_id, ne->capabilities);	list_for_each (l, &ne->unit_directories) {		struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);		HPSB_DEBUG("unit directory:");		if (ud->flags & UNIT_DIRECTORY_VENDOR_ID)			HPSB_DEBUG("  vendor_id=0x%06x ", ud->vendor_id);		if (ud->flags & UNIT_DIRECTORY_MODEL_ID)			HPSB_DEBUG("  model_id=0x%06x ", ud->model_id);		if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)			HPSB_DEBUG("  sw_specifier_id=0x%06x ", ud->specifier_id);		if (ud->flags & UNIT_DIRECTORY_VERSION)			HPSB_DEBUG("  sw_version=0x%06x ", ud->version);	}#else	return;#endif}static void nodemgr_process_root_directory(struct node_entry *ne){	octlet_t address;	quadlet_t quad;	int length, i;	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;		if (nodemgr_read_quadlet(ne, address, &quad))		return;	address += 4 + (quad >> 24) * 4;	if (nodemgr_read_quadlet(ne, address, &quad))		return;	length = quad >> 16;	address += 4;	for (i = 0; i < length; i++, address += 4) {		int code, value;		if (nodemgr_read_quadlet(ne, address, &quad))			return;		code = quad >> 24;		value = quad & 0xffffff;		switch (code) {		case CONFIG_ROM_VENDOR_ID:			ne->vendor_id = value;			break;		case CONFIG_ROM_NODE_CAPABILITES:			ne->capabilities = value;			break;		case CONFIG_ROM_UNIT_DIRECTORY:			nodemgr_process_unit_directory(ne, address + value * 4);			break;					case CONFIG_ROM_DESCRIPTOR_LEAF:		case CONFIG_ROM_DESCRIPTOR_DIRECTORY:			/* TODO: read strings... icons? */			break;		}	}	dump_directories(ne);}#ifdef CONFIG_HOTPLUGstatic void nodemgr_call_policy(char *verb, struct unit_directory *ud){	char *argv [3], **envp, *buf, *scratch;	int i = 0, value;	if (!hotplug_path [0])		return;	if (!current->fs->root)		return;	if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {		HPSB_DEBUG ("ENOMEM");		return;	}	if (!(buf = kmalloc(256, GFP_KERNEL))) {		kfree(envp);		HPSB_DEBUG("ENOMEM2");		return;	}	/* only one standardized param to hotplug command: type */	argv[0] = hotplug_path;	argv[1] = "ieee1394";	argv[2] = 0;	/* minimal command environment */	envp[i++] = "HOME=/";	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";#ifdef CONFIG_IEEE1394_VERBOSEDEBUG	/* hint that policy agent should enter no-stdout debug mode */	envp[i++] = "DEBUG=kernel";#endif	/* extensible set of named bus-specific parameters,	 * supporting multiple driver selection algorithms.	 */	scratch = buf;	envp[i++] = scratch;	scratch += sprintf(scratch, "ACTION=%s", verb) + 1;	envp[i++] = scratch;	scratch += sprintf(scratch, "VENDOR_ID=%06x", ud->ne->vendor_id) + 1;	envp[i++] = scratch;	scratch += sprintf(scratch, "GUID=%016Lx", (long long unsigned)ud->ne->guid) + 1;	envp[i++] = scratch;	scratch += sprintf(scratch, "SPECIFIER_ID=%06x", ud->specifier_id) + 1;	envp[i++] = scratch;	scratch += sprintf(scratch, "VERSION=%06x", ud->version) + 1;	envp[i++] = 0;	/* NOTE: user mode daemons can call the agents too */#ifdef CONFIG_IEEE1394_VERBOSEDEBUG	HPSB_DEBUG("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid);#endif	value = call_usermodehelper(argv[0], argv, envp);	kfree(buf);	kfree(envp);	if (value != 0)		HPSB_DEBUG("NodeMgr: hotplug policy returned %d", value);}#elsestatic inline voidnodemgr_call_policy(char *verb, struct unit_directory *ud){#ifdef CONFIG_IEEE1394_VERBOSEDEBUG	HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled");#endif	return;} #endif /* CONFIG_HOTPLUG */static void nodemgr_claim_unit_directory(struct unit_directory *ud,					 struct hpsb_protocol_driver *driver){	ud->driver = driver;	list_del(&ud->driver_list);	list_add_tail(&ud->driver_list, &driver->unit_directories);}static void nodemgr_release_unit_directory(struct unit_directory *ud){	ud->driver = NULL;	list_del(&ud->driver_list);	list_add_tail(&ud->driver_list, &unit_directory_list);}void hpsb_release_unit_directory(struct unit_directory *ud){	unsigned long flags;	write_lock_irqsave(&unit_directory_lock, flags);	nodemgr_release_unit_directory(ud);	write_unlock_irqrestore(&unit_directory_lock, flags);}static void nodemgr_free_unit_directories(struct node_entry *ne){	struct list_head *lh;	struct unit_directory *ud;	lh = ne->unit_directories.next;	while (lh != &ne->unit_directories) {		ud = list_entry(lh, struct unit_directory, node_list);		lh = lh->next;		if (ud->driver && ud->driver->disconnect)			ud->driver->disconnect(ud);		nodemgr_release_unit_directory(ud);		nodemgr_call_policy("remove", ud);		list_del(&ud->driver_list);		kfree(ud);	}}static struct ieee1394_device_id *nodemgr_match_driver(struct hpsb_protocol_driver *driver, 		     struct unit_directory *ud){	struct ieee1394_device_id *id;	for (id = driver->id_table; id->match_flags != 0; id++) {		if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&		    id->vendor_id != ud->vendor_id)			continue;		if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&		    id->model_id != ud->model_id)			continue;		if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&		    id->specifier_id != ud->specifier_id)			continue;		if ((id->match_flags & IEEE1394_MATCH_VERSION) &&		    id->version != ud->version)			continue;		return id;	}	return NULL;}static struct hpsb_protocol_driver *nodemgr_find_driver(struct unit_directory *ud){	struct list_head *l;	struct hpsb_protocol_driver *match, *driver;	struct ieee1394_device_id *device_id;	match = NULL;	list_for_each(l, &driver_list) {		driver = list_entry(l, struct hpsb_protocol_driver, list);		device_id = nodemgr_match_driver(driver, ud);		if (device_id != NULL) {			match = driver;			break;		}	}	return match;}static void nodemgr_bind_drivers (struct node_entry *ne){	struct list_head *lh;	struct hpsb_protocol_driver *driver;	struct unit_directory *ud;	list_for_each(lh, &ne->unit_directories) {		ud = list_entry(lh, struct unit_directory, node_list);		driver = nodemgr_find_driver(ud);		if (driver != NULL && driver->probe(ud) == 0)			nodemgr_claim_unit_directory(ud, driver);		nodemgr_call_policy("add", ud);	}}int hpsb_register_protocol(struct hpsb_protocol_driver *driver){	struct unit_directory *ud;	struct list_head *lh;	unsigned long flags;        write_lock_irqsave(&driver_lock, flags);

⌨️ 快捷键说明

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