nodemgr.c

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

C
1,745
字号
			ud->model_id = kv->value.immediate;			ud->flags |= UNIT_DIRECTORY_MODEL_ID;			break;		case CSR1212_KV_ID_SPECIFIER_ID:			ud->specifier_id = kv->value.immediate;			ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;			break;		case CSR1212_KV_ID_VERSION:			ud->version = kv->value.immediate;			ud->flags |= UNIT_DIRECTORY_VERSION;			break;		case CSR1212_KV_ID_DESCRIPTOR:			if (kv->key.type == CSR1212_KV_TYPE_LEAF &&			    CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&			    CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {				switch (last_key_id) {				case CSR1212_KV_ID_VENDOR:					ud->vendor_name_kv = kv;					csr1212_keep_keyval(kv);					break;				case CSR1212_KV_ID_MODEL:					ud->model_name_kv = kv;					csr1212_keep_keyval(kv);					break;				}			} /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */			break;		case CSR1212_KV_ID_DEPENDENT_INFO:			if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {				/* This should really be done in SBP2 as this is				 * doing SBP2 specific parsing. */				ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;				ud_temp = nodemgr_process_unit_directory(hi, ne, kv, id,									 parent);				if (ud_temp == NULL)					break;				/* inherit unspecified values */				if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) &&				    !(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID))				{					ud_temp->flags |=  UNIT_DIRECTORY_VENDOR_ID;					ud_temp->vendor_id = ud->vendor_id;					ud_temp->vendor_oui = ud->vendor_oui;				}				if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&				    !(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID))				{					ud_temp->flags |=  UNIT_DIRECTORY_MODEL_ID;					ud_temp->model_id = ud->model_id;				}				if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&				    !(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID))				{					ud_temp->flags |=  UNIT_DIRECTORY_SPECIFIER_ID;					ud_temp->specifier_id = ud->specifier_id;				}				if ((ud->flags & UNIT_DIRECTORY_VERSION) &&				    !(ud_temp->flags & UNIT_DIRECTORY_VERSION))				{					ud_temp->flags |=  UNIT_DIRECTORY_VERSION;					ud_temp->version = ud->version;				}			}			break;		default:			break;		}		last_key_id = kv->key.id;	}	memcpy(&ud->device, &nodemgr_dev_template_ud,	       sizeof(ud->device));	if (parent) {		ud->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;		ud->device.parent = &parent->device;	} else		ud->device.parent = &ne->device;	snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u",		 ne->device.bus_id, ud->id);	ud->class_dev.dev = &ud->device;	ud->class_dev.class = &nodemgr_ud_class;	snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",		 ne->device.bus_id, ud->id);	device_register(&ud->device);	class_device_register(&ud->class_dev);	get_device(&ud->device);	if (ud->vendor_oui)		device_create_file(&ud->device, &dev_attr_ud_vendor_oui);	nodemgr_create_ud_dev_files(ud);	return ud;unit_directory_error:	if (ud != NULL)		kfree(ud);	return NULL;}static void nodemgr_process_root_directory(struct host_info *hi, struct node_entry *ne){	unsigned int ud_id = 0;	struct csr1212_dentry *dentry;	struct csr1212_keyval *kv;	u8 last_key_id = 0;	ne->needs_probe = 0;	csr1212_for_each_dir_entry(ne->csr, kv, ne->csr->root_kv, dentry) {		switch (kv->key.id) {		case CSR1212_KV_ID_VENDOR:			ne->vendor_id = kv->value.immediate;			if (ne->vendor_id)				ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id);			break;		case CSR1212_KV_ID_NODE_CAPABILITIES:			ne->capabilities = kv->value.immediate;			break;		case CSR1212_KV_ID_UNIT:			nodemgr_process_unit_directory(hi, ne, kv, &ud_id, NULL);			break;		case CSR1212_KV_ID_DESCRIPTOR:			if (last_key_id == CSR1212_KV_ID_VENDOR) {				if (kv->key.type == CSR1212_KV_TYPE_LEAF &&				    CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&				    CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {					ne->vendor_name_kv = kv;					csr1212_keep_keyval(kv);				}			}			break;		}		last_key_id = kv->key.id;	}	if (ne->vendor_oui)		device_create_file(&ne->device, &dev_attr_ne_vendor_oui);	if (ne->vendor_name_kv)		device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv);}#ifdef CONFIG_HOTPLUGstatic int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp,			   char *buffer, int buffer_size){	struct unit_directory *ud;	int i = 0;	int length = 0;	if (!cdev)		return -ENODEV;	ud = container_of(cdev, struct unit_directory, class_dev);	if (ud->ne->in_limbo || ud->ignore_driver)		return -ENODEV;#define PUT_ENVP(fmt,val) 					\do {								\    	int printed;						\	envp[i++] = buffer;					\	printed = snprintf(buffer, buffer_size - length,	\			   fmt, val);				\	if ((buffer_size - (length+printed) <= 0) || (i >= num_envp))	\		return -ENOMEM;					\	length += printed+1;					\	buffer += printed+1;					\} while (0)	PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);	PUT_ENVP("MODEL_ID=%06x", ud->model_id);	PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);	PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);	PUT_ENVP("VERSION=%06x", ud->version);#undef PUT_ENVP	envp[i] = NULL;	return 0;}#elsestatic int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp,			   char *buffer, int buffer_size){	return -ENODEV;}#endif /* CONFIG_HOTPLUG */int hpsb_register_protocol(struct hpsb_protocol_driver *driver){	int ret;	/* This will cause a probe for devices */	ret = driver_register(&driver->driver);	if (!ret)		nodemgr_create_drv_files(driver);	return ret;}void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver){	nodemgr_remove_drv_files(driver);	/* This will subsequently disconnect all devices that our driver	 * is attached to. */	driver_unregister(&driver->driver);}/* * This function updates nodes that were present on the bus before the * reset and still are after the reset.  The nodeid and the config rom * may have changed, and the drivers managing this device must be * informed that this device just went through a bus reset, to allow * the to take whatever actions required. */static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr,				struct host_info *hi, nodeid_t nodeid,				unsigned int generation){	if (ne->nodeid != nodeid) {		HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT,			   NODE_BUS_ARGS(ne->host, ne->nodeid),			   NODE_BUS_ARGS(ne->host, nodeid));		ne->nodeid = nodeid;	}	if (ne->busopt.generation != ((be32_to_cpu(csr->bus_info_data[2]) >> 4) & 0xf)) {		kfree(ne->csr->private);		csr1212_destroy_csr(ne->csr);		ne->csr = csr;		/* If the node's configrom generation has changed, we		 * unregister all the unit directories. */		nodemgr_remove_uds(ne);		nodemgr_update_bus_options(ne);		/* Mark the node as new, so it gets re-probed */		ne->needs_probe = 1;	}	if (ne->in_limbo)		nodemgr_resume_ne(ne);	/* Mark the node current */	ne->generation = generation;}static void nodemgr_node_scan_one(struct host_info *hi,				  nodeid_t nodeid, int generation){	struct hpsb_host *host = hi->host;	struct node_entry *ne;	octlet_t guid;	struct csr1212_csr *csr;	struct nodemgr_csr_info *ci;	ci = kmalloc(sizeof(struct nodemgr_csr_info), GFP_KERNEL);	if (!ci)		return;	ci->host = host;	ci->nodeid = nodeid;	ci->generation = generation;	/* We need to detect when the ConfigROM's generation has changed,	 * so we only update the node's info when it needs to be.  */	csr = csr1212_create_csr(&nodemgr_csr_ops, 5 * sizeof(quadlet_t), ci);	if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) {		HPSB_ERR("Error parsing configrom for node " NODE_BUS_FMT,			 NODE_BUS_ARGS(host, nodeid));		if (csr)			csr1212_destroy_csr(csr);		kfree(ci);		return;	}	if (csr->bus_info_data[1] != IEEE1394_BUSID_MAGIC) {		/* This isn't a 1394 device, but we let it slide. There		 * was a report of a device with broken firmware which		 * reported '2394' instead of '1394', which is obviously a		 * mistake. One would hope that a non-1394 device never		 * gets connected to Firewire bus. If someone does, we		 * shouldn't be held responsible, so we'll allow it with a		 * warning.  */		HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",			  NODE_BUS_ARGS(host, nodeid), csr->bus_info_data[1]);	}	guid = ((u64)be32_to_cpu(csr->bus_info_data[3]) << 32) | be32_to_cpu(csr->bus_info_data[4]);	ne = find_entry_by_guid(guid);	if (ne && ne->host != host && ne->in_limbo) {		/* Must have moved this device from one host to another */		nodemgr_remove_ne(ne);		ne = NULL;	}	if (!ne)		nodemgr_create_node(guid, csr, hi, nodeid, generation);	else		nodemgr_update_node(ne, csr, hi, nodeid, generation);	return;}static void nodemgr_node_scan(struct host_info *hi, int generation){        int count;        struct hpsb_host *host = hi->host;        struct selfid *sid = (struct selfid *)host->topology_map;        nodeid_t nodeid = LOCAL_BUS;        /* Scan each node on the bus */        for (count = host->selfid_count; count; count--, sid++) {                if (sid->extended)                        continue;                if (!sid->link_active) {                        nodeid++;                        continue;                }                nodemgr_node_scan_one(hi, nodeid++, generation);        }}static void nodemgr_suspend_ne(struct node_entry *ne){	struct class_device *cdev;	struct unit_directory *ud;	HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);	ne->in_limbo = 1;	device_create_file(&ne->device, &dev_attr_ne_in_limbo);	down_write(&ne->device.bus->subsys.rwsem);	list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {		ud = container_of(cdev, struct unit_directory, class_dev);		if (ud->ne != ne)			continue;		if (ud->device.driver &&		    (!ud->device.driver->suspend ||		      ud->device.driver->suspend(&ud->device, 0, 0)))			device_release_driver(&ud->device);	}	up_write(&ne->device.bus->subsys.rwsem);}static void nodemgr_resume_ne(struct node_entry *ne){	struct class_device *cdev;	struct unit_directory *ud;	ne->in_limbo = 0;	device_remove_file(&ne->device, &dev_attr_ne_in_limbo);	down_read(&ne->device.bus->subsys.rwsem);	list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {		ud = container_of(cdev, struct unit_directory, class_dev);		if (ud->ne != ne)			continue;		if (ud->device.driver && ud->device.driver->resume)			ud->device.driver->resume(&ud->device, 0);	}	up_read(&ne->device.bus->subsys.rwsem);	HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);}static void nodemgr_update_pdrv(struct node_entry *ne){	struct unit_directory *ud;	struct hpsb_protocol_driver *pdrv;	struct class *class = &nodemgr_ud_class;	struct class_device *cdev;	down_read(&class->subsys.rwsem);	list_for_each_entry(cdev, &class->children, node) {		ud = container_of(cdev, struct unit_directory, class_dev);		if (ud->ne != ne || !ud->device.driver)			continue;		pdrv = container_of(ud->device.driver, struct hpsb_protocol_driver, driver);		if (pdrv->update && pdrv->update(ud)) {			down_write(&ud->device.bus->subsys.rwsem);			device_release_driver(&ud->device);			up_write(&ud->device.bus->subsys.rwsem);		}	}	up_read(&class->subsys.rwsem);

⌨️ 快捷键说明

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