nodemgr.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,745 行 · 第 1/4 页

C
1,745
字号
/* * 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>#include <linux/pci.h>#include <linux/moduleparam.h>#include <linux/suspend.h>#include <asm/atomic.h>#include "ieee1394_types.h"#include "ieee1394.h"#include "hosts.h"#include "ieee1394_transactions.h"#include "highlevel.h"#include "csr.h"#include "nodemgr.h"static int ignore_drivers = 0;module_param(ignore_drivers, int, 0444);MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");struct nodemgr_csr_info {	struct hpsb_host *host;	nodeid_t nodeid;	unsigned int generation;};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;}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, ret = 0;	for (i = 0; i < 3; i++) {		ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,				buffer, length);		if (!ret)			break;		set_current_state(TASK_INTERRUPTIBLE);		if (schedule_timeout (HZ/3))			return -EINTR;	}	return ret;}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 DECLARE_MUTEX(nodemgr_serialize);struct host_info {	struct hpsb_host *host;	struct list_head list;	struct completion exited;	struct semaphore reset_sem;	int pid;	char daemon_name[15];	int kill_me;};static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);static int nodemgr_hotplug(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);}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. */struct class nodemgr_ud_class = {	.name		= "ieee1394",	.release	= ud_cls_release,	.hotplug	= nodemgr_hotplug,};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,};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, 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, 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, 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);static ssize_t fw_show_ne_tlabels_free(struct device *dev, char *buf){	struct node_entry *ne = container_of(dev, struct node_entry, device);	return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1);}static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, char *buf){	struct node_entry *ne = container_of(dev, struct node_entry, device);	return sprintf(buf, "%u\n", ne->tpool->allocations);}static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL);static ssize_t fw_show_ne_tlabels_mask(struct device *dev, char *buf){	struct node_entry *ne = container_of(dev, struct node_entry, device);#if (BITS_PER_LONG <= 32)	return sprintf(buf, "0x%08lx%08lx\n", ne->tpool->pool[0], ne->tpool->pool[1]);#else	return sprintf(buf, "0x%016lx\n", ne->tpool->pool[0]);#endif}static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);static ssize_t fw_set_ignore_driver(struct device *dev, 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) {		down_write(&dev->bus->subsys.rwsem);		device_release_driver(dev);		ud->ignore_driver = 1;		up_write(&dev->bus->subsys.rwsem);	} else if (!state)		ud->ignore_driver = 0;	return count;}static ssize_t fw_get_ignore_driver(struct device *dev, 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 int nodemgr_rescan_bus_thread(void *__unused){	/* No userlevel access needed */	daemonize("kfwrescan");	bus_rescan_devices(&ieee1394_bus_type);	return 0;}static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, size_t count){	int state = simple_strtoul(buf, NULL, 10);	/* Don't wait for this, or care about errors. Root could do	 * something stupid and spawn this a lot of times, but that's	 * root's fault. */	if (state == 1)		kernel_thread(nodemgr_rescan_bus_thread, NULL, CLONE_KERNEL);	return 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)		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, vendor_oui, const char *, "%s\n")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, guid_vendor_oui, const char *, "%s\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,	&dev_attr_tlabels_free,	&dev_attr_tlabels_allocations,	&dev_attr_tlabels_mask,};

⌨️ 快捷键说明

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