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

📄 nodemgr.c

📁 ieee1394驱动,不多说了!直接可以在linux2.6内核中使用
💻 C
📖 第 1 页 / 共 4 页
字号:
	down(&nodemgr_ud_class.sem);	list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {		ud = container_of(cdev, struct unit_directory, class_dev);		if (ud->ne != ne)			continue;		down_read(&ieee1394_bus_type.subsys.rwsem);		if (ud->device.driver && ud->device.driver->resume)			ud->device.driver->resume(&ud->device);		up_read(&ieee1394_bus_type.subsys.rwsem);	}	up(&nodemgr_ud_class.sem);	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_device *cdev;	down(&nodemgr_ud_class.sem);	list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {		ud = container_of(cdev, struct unit_directory, class_dev);		if (ud->ne != ne)			continue;		down_write(&ieee1394_bus_type.subsys.rwsem);		if (ud->device.driver) {			pdrv = container_of(ud->device.driver,					    struct hpsb_protocol_driver,					    driver);			if (pdrv->update && pdrv->update(ud))				device_release_driver(&ud->device);		}		up_write(&ieee1394_bus_type.subsys.rwsem);	}	up(&nodemgr_ud_class.sem);}/* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3.  This * seems like an optional service but in the end it is practically mandatory * as a consequence of these clauses. * * Note that we cannot do a broadcast write to all nodes at once because some * pre-1394a devices would hang. */static void nodemgr_irm_write_bc(struct node_entry *ne, int generation){	const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);	quadlet_t bc_remote, bc_local;	int error;	if (!ne->host->is_irm || ne->generation != generation ||	    ne->nodeid == ne->host->node_id)		return;	bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);	/* Check if the register is implemented and 1394a compliant. */	error = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote,			  sizeof(bc_remote));	if (!error && bc_remote & cpu_to_be32(0x80000000) &&	    bc_remote != bc_local)		hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));}static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation){	struct device *dev;	if (ne->host != hi->host || ne->in_limbo)		return;	dev = get_device(&ne->device);	if (!dev)		return;	nodemgr_irm_write_bc(ne, generation);	/* If "needs_probe", then this is either a new or changed node we	 * rescan totally. If the generation matches for an existing node	 * (one that existed prior to the bus reset) we send update calls	 * down to the drivers. Otherwise, this is a dead node and we	 * suspend it. */	if (ne->needs_probe)		nodemgr_process_root_directory(hi, ne);	else if (ne->generation == generation)		nodemgr_update_pdrv(ne);	else		nodemgr_suspend_ne(ne);	put_device(dev);}static void nodemgr_node_probe(struct host_info *hi, int generation){	struct hpsb_host *host = hi->host;	struct class_device *cdev;	struct node_entry *ne;	/* Do some processing of the nodes we've probed. This pulls them	 * into the sysfs layer if needed, and can result in processing of	 * unit-directories, or just updating the node and it's	 * unit-directories.	 *	 * Run updates before probes. Usually, updates are time-critical	 * while probes are time-consuming. (Well, those probes need some	 * improvement...) */	down(&nodemgr_ne_class.sem);	list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {		ne = container_of(cdev, struct node_entry, class_dev);		if (!ne->needs_probe)			nodemgr_probe_ne(hi, ne, generation);	}	list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {		ne = container_of(cdev, struct node_entry, class_dev);		if (ne->needs_probe)			nodemgr_probe_ne(hi, ne, generation);	}	up(&nodemgr_ne_class.sem);	/* If we had a bus reset while we were scanning the bus, it is	 * possible that we did not probe all nodes.  In that case, we	 * skip the clean up for now, since we could remove nodes that	 * were still on the bus.  Another bus scan is pending which will	 * do the clean up eventually.	 *	 * Now let's tell the bus to rescan our devices. This may seem	 * like overhead, but the driver-model core will only scan a	 * device for a driver when either the device is added, or when a	 * new driver is added. A bus reset is a good reason to rescan	 * devices that were there before.  For example, an sbp2 device	 * may become available for login, if the host that held it was	 * just removed.  */	if (generation == get_hpsb_generation(host))		if (bus_rescan_devices(&ieee1394_bus_type))			HPSB_DEBUG("bus_rescan_devices had an error");}static int nodemgr_send_resume_packet(struct hpsb_host *host){	struct hpsb_packet *packet;	int error = -ENOMEM;	packet = hpsb_make_phypacket(host,			EXTPHYPACKET_TYPE_RESUME |			NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT);	if (packet) {		packet->no_waiter = 1;		packet->generation = get_hpsb_generation(host);		error = hpsb_send_packet(packet);	}	if (error)		HPSB_WARN("fw-host%d: Failed to broadcast resume packet",			  host->id);	return error;}/* Perform a few high-level IRM responsibilities. */static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles){	quadlet_t bc;	/* if irm_id == -1 then there is no IRM on this bus */	if (!host->is_irm || host->irm_id == (nodeid_t)-1)		return 1;	/* We are a 1394a-2000 compliant IRM. Set the validity bit. */	host->csr.broadcast_channel |= 0x40000000;	/* If there is no bus manager then we should set the root node's	 * force_root bit to promote bus stability per the 1394	 * spec. (8.4.2.6) */	if (host->busmgr_id == 0xffff && host->node_count > 1)	{		u16 root_node = host->node_count - 1;		/* get cycle master capability flag from root node */		if (host->is_cycmst ||		    (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host),				(CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)),				&bc, sizeof(quadlet_t)) &&		     be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT))			hpsb_send_phy_config(host, root_node, -1);		else {			HPSB_DEBUG("The root node is not cycle master capable; "				   "selecting a new root node and resetting...");			if (cycles >= 5) {				/* Oh screw it! Just leave the bus as it is */				HPSB_DEBUG("Stopping reset loop for IRM sanity");				return 1;			}			hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);			hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);			return 0;		}	}	/* Some devices suspend their ports while being connected to an inactive	 * host adapter, i.e. if connected before the low-level driver is	 * loaded.  They become visible either when physically unplugged and	 * replugged, or when receiving a resume packet.  Send one once. */	if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host))		host->resume_packet_sent = 1;	return 1;}/* We need to ensure that if we are not the IRM, that the IRM node is capable of * everything we can do, otherwise issue a bus reset and try to become the IRM * ourselves. */static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles){	quadlet_t bc;	int status;	if (hpsb_disable_irm || host->is_irm)		return 1;	status = hpsb_read(host, LOCAL_BUS | (host->irm_id),			   get_hpsb_generation(host),			   (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),			   &bc, sizeof(quadlet_t));	if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {		/* The current irm node does not have a valid BROADCAST_CHANNEL		 * register and we do, so reset the bus with force_root set */		HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting...");		if (cycles >= 5) {			/* Oh screw it! Just leave the bus as it is */			HPSB_DEBUG("Stopping reset loop for IRM sanity");			return 1;		}		hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);		hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);		return 0;	}	return 1;}static int nodemgr_host_thread(void *__hi){	struct host_info *hi = (struct host_info *)__hi;	struct hpsb_host *host = hi->host;	unsigned int g, generation = 0;	int i, reset_cycles = 0;	/* Setup our device-model entries */	nodemgr_create_host_dev_files(host);	for (;;) {		/* Sleep until next bus reset */		set_current_state(TASK_INTERRUPTIBLE);		if (get_hpsb_generation(host) == generation &&		    !kthread_should_stop())			schedule();		__set_current_state(TASK_RUNNING);		/* Thread may have been woken up to freeze or to exit */		if (try_to_freeze())			continue;		if (kthread_should_stop())			goto exit;		if (mutex_lock_interruptible(&nodemgr_serialize)) {			if (try_to_freeze())				continue;			goto exit;		}		/* Pause for 1/4 second in 1/16 second intervals,		 * to make sure things settle down. */		g = get_hpsb_generation(host);		for (i = 0; i < 4 ; i++) {			if (msleep_interruptible(63) || kthread_should_stop())				goto unlock_exit;			/* Now get the generation in which the node ID's we collect			 * are valid.  During the bus scan we will use this generation			 * for the read transactions, so that if another reset occurs			 * during the scan the transactions will fail instead of			 * returning bogus data. */			generation = get_hpsb_generation(host);			/* If we get a reset before we are done waiting, then			 * start the the waiting over again */			if (generation != g)				g = generation, i = 0;		}		if (!nodemgr_check_irm_capability(host, reset_cycles) ||		    !nodemgr_do_irm_duties(host, reset_cycles)) {			reset_cycles++;			mutex_unlock(&nodemgr_serialize);			continue;		}		reset_cycles = 0;		/* Scan our nodes to get the bus options and create node		 * entries. This does not do the sysfs stuff, since that		 * would trigger uevents and such, which is a bad idea at		 * this point. */		nodemgr_node_scan(hi, generation);		/* This actually does the full probe, with sysfs		 * registration. */		nodemgr_node_probe(hi, generation);		/* Update some of our sysfs symlinks */		nodemgr_update_host_dev_links(host);		mutex_unlock(&nodemgr_serialize);	}unlock_exit:	mutex_unlock(&nodemgr_serialize);exit:	HPSB_VERBOSE("NodeMgr: Exiting thread");	return 0;}int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)){	struct class_device *cdev;	struct hpsb_host *host;	int error = 0;	down(&hpsb_host_class.sem);	list_for_each_entry(cdev, &hpsb_host_class.children, node) {		host = container_of(cdev, struct hpsb_host, class_dev);		if ((error = cb(host, __data)))			break;	}	up(&hpsb_host_class.sem);	return error;}/* The following four convenience functions use a struct node_entry * for addressing a node on the bus.  They are intended for use by any * process context, not just the nodemgr thread, so we need to be a * little careful when reading out the node ID and generation.  The * thing that can go wrong is that we get the node ID, then a bus * reset occurs, and then we read the generation.  The node ID is * possibly invalid, but the generation is current, and we end up * sending a packet to a the wrong node. * * The solution is to make sure we read the generation first, so that * if a reset occurs in the process, we end up with a stale generation * and the transactions will fail instead of silently using wrong node * ID's. */void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt){	pkt->host = ne->host;	pkt->generation = ne->generation;	barrier();	pkt->node_id = ne->nodeid;}int hpsb_node_write(struct node_entry *ne, u64 addr,		    quadlet_t *buffer, size_t length){	unsigned int generation = ne->generation;	barrier();	return hpsb_write(ne->host, ne->nodeid, generation,			  addr, buffer, length);}static void nodemgr_add_host(struct hpsb_host *host){	struct host_info *hi;	hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi));	if (!hi) {		HPSB_ERR("NodeMgr: out of memory in add host");		return;	}	hi->host = host;	hi->thread = kthread_run(nodemgr_host_thread, hi, "knodemgrd_%d",				 host->id);	if (IS_ERR(hi->thread)) {		HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id);		hpsb_destroy_hostinfo(&nodemgr_highlevel, host);	}}static void nodemgr_host_reset(struct hpsb_host *host){	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);	if (hi) {		HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id);		wake_up_process(hi->thread);	}}static void nodemgr_remove_host(struct hpsb_host *host){	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);	if (hi) {		kthread_stop(hi->thread);		nodemgr_remove_host_dev(&host->device);	}}static struct hpsb_highlevel nodemgr_highlevel = {	.name =		"Node manager",	.add_host =	nodemgr_add_host,	.host_reset =	nodemgr_host_reset,	.remove_host =	nodemgr_remove_host,};int init_ieee1394_nodemgr(void){	int error;	error = class_register(&nodemgr_ne_class);	if (error)		goto fail_ne;	error = class_register(&nodemgr_ud_class);	if (error)		goto fail_ud;	error = driver_register(&nodemgr_mid_layer_driver);	if (error)		goto fail_ml;	/* This driver is not used if nodemgr is off (disable_nodemgr=1). */	nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;	hpsb_register_highlevel(&nodemgr_highlevel);	return 0;fail_ml:	class_unregister(&nodemgr_ud_class);fail_ud:	class_unregister(&nodemgr_ne_class);fail_ne:	return error;}void cleanup_ieee1394_nodemgr(void){	hpsb_unregister_highlevel(&nodemgr_highlevel);	driver_unregister(&nodemgr_mid_layer_driver);	class_unregister(&nodemgr_ud_class);	class_unregister(&nodemgr_ne_class);}

⌨️ 快捷键说明

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