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

📄 nodemgr.c

📁 ieee1394驱动,不多说了!直接可以在linux2.6内核中使用
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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/bitmap.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/kthread.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/freezer.h>#include <asm/atomic.h>#include "csr.h"#include "highlevel.h"#include "hosts.h"#include "ieee1394.h"#include "ieee1394_core.h"#include "ieee1394_hotplug.h"#include "ieee1394_types.h"#include "ieee1394_transactions.h"#include "nodemgr.h"static int ignore_drivers;module_param(ignore_drivers, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");struct nodemgr_csr_info {	struct hpsb_host *host;	nodeid_t nodeid;	unsigned int generation;	unsigned int speed_unverified:1;};/* * Correct the speed map entry.  This is necessary *  - for nodes with link speed < phy speed, *  - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX. * A possible speed is determined by trial and error, using quadlet reads. */static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,			       quadlet_t *buffer){	quadlet_t q;	u8 i, *speed, old_speed, good_speed;	int error;	speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);	old_speed = *speed;	good_speed = IEEE1394_SPEED_MAX + 1;	/* Try every speed from S100 to old_speed.	 * If we did it the other way around, a too low speed could be caught	 * if the retry succeeded for some other reason, e.g. because the link	 * just finished its initialization. */	for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {		*speed = i;		error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,				  &q, sizeof(quadlet_t));		if (error)			break;		*buffer = q;		good_speed = i;	}	if (good_speed <= IEEE1394_SPEED_MAX) {		HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s",			   NODE_BUS_ARGS(ci->host, ci->nodeid),			   hpsb_speedto_str[good_speed]);		*speed = good_speed;		ci->speed_unverified = 0;		return 0;	}	*speed = old_speed;	return error;}static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,			    void *buffer, void *__ci){	struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;	int i, error;	for (i = 1; ; i++) {		error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,				  buffer, length);		if (!error) {			ci->speed_unverified = 0;			break;		}		/* Give up after 3rd failure. */		if (i == 3)			break;		/* The ieee1394_core guessed the node's speed capability from		 * the self ID.  Check whether a lower speed works. */		if (ci->speed_unverified && length == sizeof(quadlet_t)) {			error = nodemgr_check_speed(ci, addr, buffer);			if (!error)				break;		}		if (msleep_interruptible(334))			return -EINTR;	}	return error;}static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci){	return (CSR1212_BE32_TO_CPU(bus_info_data[2]) >> 8) & 0x3;}static struct csr1212_bus_ops nodemgr_csr_ops = {	.bus_read =	nodemgr_bus_read,	.get_max_rom =	nodemgr_get_max_rom};/* * 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 relies heavily on the Driver Model for device callbacks and * driver/device mappings. The old nodemgr used to handle all this itself, * but now we are much simpler because of the LDM. */static DEFINE_MUTEX(nodemgr_serialize);struct host_info {	struct hpsb_host *host;	struct list_head list;	struct task_struct *thread;};static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,			  char *buffer, int buffer_size);static void nodemgr_resume_ne(struct node_entry *ne);static void nodemgr_remove_ne(struct node_entry *ne);static struct node_entry *find_entry_by_guid(u64 guid);struct bus_type ieee1394_bus_type = {	.name		= "ieee1394",	.match		= nodemgr_bus_match,};static void host_cls_release(struct class_device *class_dev){	put_device(&container_of((class_dev), struct hpsb_host, class_dev)->device);}struct class hpsb_host_class = {	.name		= "ieee1394_host",	.release	= host_cls_release,};static void ne_cls_release(struct class_device *class_dev){	put_device(&container_of((class_dev), struct node_entry, class_dev)->device);}static struct class nodemgr_ne_class = {	.name		= "ieee1394_node",	.release	= ne_cls_release,};static void ud_cls_release(struct class_device *class_dev){	put_device(&container_of((class_dev), struct unit_directory, class_dev)->device);}/* The name here is only so that unit directory hotplug works with old * style hotplug, which only ever did unit directories anyway. */static struct class nodemgr_ud_class = {	.name		= "ieee1394",	.release	= ud_cls_release,	.uevent		= nodemgr_uevent,};static struct hpsb_highlevel nodemgr_highlevel;static void nodemgr_release_ud(struct device *dev){	struct unit_directory *ud = container_of(dev, struct unit_directory, device);	if (ud->vendor_name_kv)		csr1212_release_keyval(ud->vendor_name_kv);	if (ud->model_name_kv)		csr1212_release_keyval(ud->model_name_kv);	kfree(ud);}static void nodemgr_release_ne(struct device *dev){	struct node_entry *ne = container_of(dev, struct node_entry, device);	if (ne->vendor_name_kv)		csr1212_release_keyval(ne->vendor_name_kv);	kfree(ne);}static void nodemgr_release_host(struct device *dev){	struct hpsb_host *host = container_of(dev, struct hpsb_host, device);	csr1212_destroy_csr(host->csr.rom);	kfree(host);}static int nodemgr_ud_platform_data;static struct device nodemgr_dev_template_ud = {	.bus		= &ieee1394_bus_type,	.release	= nodemgr_release_ud,	.platform_data	= &nodemgr_ud_platform_data,};static struct device nodemgr_dev_template_ne = {	.bus		= &ieee1394_bus_type,	.release	= nodemgr_release_ne,};/* This dummy driver prevents the host devices from being scanned. We have no * useful drivers for them yet, and there would be a deadlock possible if the * driver core scans the host device while the host's low-level driver (i.e. * the host's parent device) is being removed. */static struct device_driver nodemgr_mid_layer_driver = {	.bus		= &ieee1394_bus_type,	.name		= "nodemgr",	.owner		= THIS_MODULE,};struct device nodemgr_dev_template_host = {	.bus		= &ieee1394_bus_type,	.release	= nodemgr_release_host,};#define fw_attr(class, class_type, field, type, format_string)		\static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\{									\	class_type *class;						\	class = container_of(dev, class_type, device);			\	return sprintf(buf, format_string, (type)class->field);		\}									\static struct device_attribute dev_attr_##class##_##field = {		\	.attr = {.name = __stringify(field), .mode = S_IRUGO },		\	.show   = fw_show_##class##_##field,				\};#define fw_attr_td(class, class_type, td_kv)				\static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\{									\	int len;							\	class_type *class = container_of(dev, class_type, device);	\	len = (class->td_kv->value.leaf.len - 2) * sizeof(quadlet_t);	\	memcpy(buf,							\	       CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv),	\	       len);							\	while ((buf + len - 1) == '\0')					\		len--;							\	buf[len++] = '\n';						\	buf[len] = '\0';						\	return len;							\}									\static struct device_attribute dev_attr_##class##_##td_kv = {		\	.attr = {.name = __stringify(td_kv), .mode = S_IRUGO },		\	.show   = fw_show_##class##_##td_kv,				\};#define fw_drv_attr(field, type, format_string)			\static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \{								\	struct hpsb_protocol_driver *driver;			\	driver = container_of(drv, struct hpsb_protocol_driver, driver); \	return sprintf(buf, format_string, (type)driver->field);\}								\static struct driver_attribute driver_attr_drv_##field = {	\	.attr = {.name = __stringify(field), .mode = S_IRUGO },	\	.show   = fw_drv_show_##field,				\};static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf){	struct node_entry *ne = container_of(dev, struct node_entry, device);	return sprintf(buf, "IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) "		       "LSPD(%d) MAX_REC(%d) MAX_ROM(%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.max_rom,		       ne->busopt.cyc_clk_acc);}static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);#ifdef HPSB_DEBUG_TLABELSstatic ssize_t fw_show_ne_tlabels_free(struct device *dev,				       struct device_attribute *attr, char *buf){	struct node_entry *ne = container_of(dev, struct node_entry, device);	unsigned long flags;	unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;	int tf;	spin_lock_irqsave(&hpsb_tlabel_lock, flags);	tf = 64 - bitmap_weight(tp, 64);	spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);	return sprintf(buf, "%d\n", tf);}static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);static ssize_t fw_show_ne_tlabels_mask(struct device *dev,				       struct device_attribute *attr, char *buf){	struct node_entry *ne = container_of(dev, struct node_entry, device);	unsigned long flags;	unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;	u64 tm;	spin_lock_irqsave(&hpsb_tlabel_lock, flags);#if (BITS_PER_LONG <= 32)	tm = ((u64)tp[0] << 32) + tp[1];#else	tm = tp[0];#endif	spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);	return sprintf(buf, "0x%016llx\n", (unsigned long long)tm);}static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);#endif /* HPSB_DEBUG_TLABELS */static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	struct unit_directory *ud = container_of(dev, struct unit_directory, device);	int state = simple_strtoul(buf, NULL, 10);	if (state == 1) {		ud->ignore_driver = 1;		down_write(&ieee1394_bus_type.subsys.rwsem);		device_release_driver(dev);		up_write(&ieee1394_bus_type.subsys.rwsem);	} else if (state == 0)		ud->ignore_driver = 0;	return count;}static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf){	struct unit_directory *ud = container_of(dev, struct unit_directory, device);	return sprintf(buf, "%d\n", ud->ignore_driver);}static DEVICE_ATTR(ignore_driver, S_IWUSR | S_IRUGO, fw_get_ignore_driver, fw_set_ignore_driver);static ssize_t fw_set_destroy_node(struct bus_type *bus, const char *buf, size_t count){	struct node_entry *ne;	u64 guid = (u64)simple_strtoull(buf, NULL, 16);	ne = find_entry_by_guid(guid);	if (ne == NULL || !ne->in_limbo)		return -EINVAL;	nodemgr_remove_ne(ne);	return count;}static ssize_t fw_get_destroy_node(struct bus_type *bus, char *buf){	return sprintf(buf, "You can destroy in_limbo nodes by writing their GUID to this file\n");}static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node);static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf,			     size_t count){	int error = 0;	if (simple_strtoul(buf, NULL, 10) == 1)		error = bus_rescan_devices(&ieee1394_bus_type);	return error ? error : count;}static ssize_t fw_get_rescan(struct bus_type *bus, char *buf){	return sprintf(buf, "You can force a rescan of the bus for "			"drivers by writing a 1 to this file\n");}static BUS_ATTR(rescan, S_IWUSR | S_IRUGO, fw_get_rescan, fw_set_rescan);static ssize_t fw_set_ignore_drivers(struct bus_type *bus, const char *buf, size_t count){	int state = simple_strtoul(buf, NULL, 10);	if (state == 1)		ignore_drivers = 1;	else if (state == 0)		ignore_drivers = 0;	return count;}static ssize_t fw_get_ignore_drivers(struct bus_type *bus, char *buf){	return sprintf(buf, "%d\n", ignore_drivers);}static BUS_ATTR(ignore_drivers, S_IWUSR | S_IRUGO, fw_get_ignore_drivers, fw_set_ignore_drivers);struct bus_attribute *const fw_bus_attrs[] = {	&bus_attr_destroy_node,	&bus_attr_rescan,	&bus_attr_ignore_drivers,	NULL};fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n")fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")fw_attr_td(ne, struct node_entry, vendor_name_kv)fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");static struct device_attribute *const fw_ne_attrs[] = {	&dev_attr_ne_guid,	&dev_attr_ne_guid_vendor_id,	&dev_attr_ne_capabilities,	&dev_attr_ne_vendor_id,	&dev_attr_ne_nodeid,	&dev_attr_bus_options,#ifdef HPSB_DEBUG_TLABELS

⌨️ 快捷键说明

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