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

📄 fw-device.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		 * As per IEEE1212 7.2, during power-up, devices can		 * reply with a 0 for the first quadlet of the config		 * rom to indicate that they are booting (for example,		 * if the firmware is on the disk of a external		 * harddisk).  In that case we just fail, and the		 * retry mechanism will try again later.		 */		if (i == 0 && rom[i] == 0)			return -1;	}	device->max_speed = device->node->max_speed;	/*	 * Determine the speed of	 *   - devices with link speed less than PHY speed,	 *   - devices with 1394b PHY (unless only connected to 1394a PHYs),	 *   - all devices if there are 1394b repeaters.	 * Note, we cannot use the bus info block's link_spd as starting point	 * because some buggy firmwares set it lower than necessary and because	 * 1394-1995 nodes do not have the field.	 */	if ((rom[2] & 0x7) < device->max_speed ||	    device->max_speed == SCODE_BETA ||	    device->card->beta_repeaters_present) {		u32 dummy;		/* for S1600 and S3200 */		if (device->max_speed == SCODE_BETA)			device->max_speed = device->card->link_speed;		while (device->max_speed > SCODE_100) {			if (read_rom(device, 0, &dummy) == RCODE_COMPLETE)				break;			device->max_speed--;		}	}	/*	 * Now parse the config rom.  The config rom is a recursive	 * directory structure so we parse it using a stack of	 * references to the blocks that make up the structure.  We	 * push a reference to the root directory on the stack to	 * start things off.	 */	length = i;	sp = 0;	stack[sp++] = 0xc0000005;	while (sp > 0) {		/*		 * Pop the next block reference of the stack.  The		 * lower 24 bits is the offset into the config rom,		 * the upper 8 bits are the type of the reference the		 * block.		 */		key = stack[--sp];		i = key & 0xffffff;		if (i >= ARRAY_SIZE(rom))			/*			 * The reference points outside the standard			 * config rom area, something's fishy.			 */			return -1;		/* Read header quadlet for the block to get the length. */		if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)			return -1;		end = i + (rom[i] >> 16) + 1;		i++;		if (end > ARRAY_SIZE(rom))			/*			 * This block extends outside standard config			 * area (and the array we're reading it			 * into).  That's broken, so ignore this			 * device.			 */			return -1;		/*		 * Now read in the block.  If this is a directory		 * block, check the entries as we read them to see if		 * it references another block, and push it in that case.		 */		while (i < end) {			if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)				return -1;			if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&			    sp < ARRAY_SIZE(stack))				stack[sp++] = i + rom[i];			i++;		}		if (length < i)			length = i;	}	device->config_rom = kmalloc(length * 4, GFP_KERNEL);	if (device->config_rom == NULL)		return -1;	memcpy(device->config_rom, rom, length * 4);	device->config_rom_length = length;	return 0;}static void fw_unit_release(struct device *dev){	struct fw_unit *unit = fw_unit(dev);	kfree(unit);}static struct device_type fw_unit_type = {	.uevent		= fw_unit_uevent,	.release	= fw_unit_release,};static int is_fw_unit(struct device *dev){	return dev->type == &fw_unit_type;}static void create_units(struct fw_device *device){	struct fw_csr_iterator ci;	struct fw_unit *unit;	int key, value, i;	i = 0;	fw_csr_iterator_init(&ci, &device->config_rom[5]);	while (fw_csr_iterator_next(&ci, &key, &value)) {		if (key != (CSR_UNIT | CSR_DIRECTORY))			continue;		/*		 * Get the address of the unit directory and try to		 * match the drivers id_tables against it.		 */		unit = kzalloc(sizeof(*unit), GFP_KERNEL);		if (unit == NULL) {			fw_error("failed to allocate memory for unit\n");			continue;		}		unit->directory = ci.p + value - 1;		unit->device.bus = &fw_bus_type;		unit->device.type = &fw_unit_type;		unit->device.parent = &device->device;		snprintf(unit->device.bus_id, sizeof(unit->device.bus_id),			 "%s.%d", device->device.bus_id, i++);		init_fw_attribute_group(&unit->device,					fw_unit_attributes,					&unit->attribute_group);		if (device_register(&unit->device) < 0)			goto skip_unit;		continue;	skip_unit:		kfree(unit);	}}static int shutdown_unit(struct device *device, void *data){	device_unregister(device);	return 0;}static DECLARE_RWSEM(idr_rwsem);static DEFINE_IDR(fw_device_idr);int fw_cdev_major;struct fw_device *fw_device_from_devt(dev_t devt){	struct fw_device *device;	down_read(&idr_rwsem);	device = idr_find(&fw_device_idr, MINOR(devt));	up_read(&idr_rwsem);	return device;}static void fw_device_shutdown(struct work_struct *work){	struct fw_device *device =		container_of(work, struct fw_device, work.work);	int minor = MINOR(device->device.devt);	down_write(&idr_rwsem);	idr_remove(&fw_device_idr, minor);	up_write(&idr_rwsem);	fw_device_cdev_remove(device);	device_for_each_child(&device->device, NULL, shutdown_unit);	device_unregister(&device->device);}static struct device_type fw_device_type = {	.release	= fw_device_release,};/* * These defines control the retry behavior for reading the config * rom.  It shouldn't be necessary to tweak these; if the device * doesn't respond to a config rom read within 10 seconds, it's not * going to respond at all.  As for the initial delay, a lot of * devices will be able to respond within half a second after bus * reset.  On the other hand, it's not really worth being more * aggressive than that, since it scales pretty well; if 10 devices * are plugged in, they're all getting read within one second. */#define MAX_RETRIES	10#define RETRY_DELAY	(3 * HZ)#define INITIAL_DELAY	(HZ / 2)static void fw_device_init(struct work_struct *work){	struct fw_device *device =		container_of(work, struct fw_device, work.work);	int minor, err;	/*	 * All failure paths here set node->data to NULL, so that we	 * don't try to do device_for_each_child() on a kfree()'d	 * device.	 */	if (read_bus_info_block(device) < 0) {		if (device->config_rom_retries < MAX_RETRIES) {			device->config_rom_retries++;			schedule_delayed_work(&device->work, RETRY_DELAY);		} else {			fw_notify("giving up on config rom for node id %x\n",				  device->node_id);			if (device->node == device->card->root_node)				schedule_delayed_work(&device->card->work, 0);			fw_device_release(&device->device);		}		return;	}	err = -ENOMEM;	down_write(&idr_rwsem);	if (idr_pre_get(&fw_device_idr, GFP_KERNEL))		err = idr_get_new(&fw_device_idr, device, &minor);	up_write(&idr_rwsem);	if (err < 0)		goto error;	device->device.bus = &fw_bus_type;	device->device.type = &fw_device_type;	device->device.parent = device->card->device;	device->device.devt = MKDEV(fw_cdev_major, minor);	snprintf(device->device.bus_id, sizeof(device->device.bus_id),		 "fw%d", minor);	init_fw_attribute_group(&device->device,				fw_device_attributes,				&device->attribute_group);	if (device_add(&device->device)) {		fw_error("Failed to add device.\n");		goto error_with_cdev;	}	create_units(device);	/*	 * Transition the device to running state.  If it got pulled	 * out from under us while we did the intialization work, we	 * have to shut down the device again here.  Normally, though,	 * fw_node_event will be responsible for shutting it down when	 * necessary.  We have to use the atomic cmpxchg here to avoid	 * racing with the FW_NODE_DESTROYED case in	 * fw_node_event().	 */	if (atomic_cmpxchg(&device->state,		    FW_DEVICE_INITIALIZING,		    FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)		fw_device_shutdown(&device->work.work);	else		fw_notify("created new fw device %s "			  "(%d config rom retries, S%d00)\n",			  device->device.bus_id, device->config_rom_retries,			  1 << device->max_speed);	/*	 * Reschedule the IRM work if we just finished reading the	 * root node config rom.  If this races with a bus reset we	 * just end up running the IRM work a couple of extra times -	 * pretty harmless.	 */	if (device->node == device->card->root_node)		schedule_delayed_work(&device->card->work, 0);	return; error_with_cdev:	down_write(&idr_rwsem);	idr_remove(&fw_device_idr, minor);	up_write(&idr_rwsem); error:	put_device(&device->device);}static int update_unit(struct device *dev, void *data){	struct fw_unit *unit = fw_unit(dev);	struct fw_driver *driver = (struct fw_driver *)dev->driver;	if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {		down(&dev->sem);		driver->update(unit);		up(&dev->sem);	}	return 0;}static void fw_device_update(struct work_struct *work){	struct fw_device *device =		container_of(work, struct fw_device, work.work);	fw_device_cdev_update(device);	device_for_each_child(&device->device, NULL, update_unit);}void fw_node_event(struct fw_card *card, struct fw_node *node, int event){	struct fw_device *device;	switch (event) {	case FW_NODE_CREATED:	case FW_NODE_LINK_ON:		if (!node->link_on)			break;		device = kzalloc(sizeof(*device), GFP_ATOMIC);		if (device == NULL)			break;		/*		 * Do minimal intialization of the device here, the		 * rest will happen in fw_device_init().  We need the		 * card and node so we can read the config rom and we		 * need to do device_initialize() now so		 * device_for_each_child() in FW_NODE_UPDATED is		 * doesn't freak out.		 */		device_initialize(&device->device);		atomic_set(&device->state, FW_DEVICE_INITIALIZING);		device->card = fw_card_get(card);		device->node = fw_node_get(node);		device->node_id = node->node_id;		device->generation = card->generation;		INIT_LIST_HEAD(&device->client_list);		/*		 * Set the node data to point back to this device so		 * FW_NODE_UPDATED callbacks can update the node_id		 * and generation for the device.		 */		node->data = device;		/*		 * Many devices are slow to respond after bus resets,		 * especially if they are bus powered and go through		 * power-up after getting plugged in.  We schedule the		 * first config rom scan half a second after bus reset.		 */		INIT_DELAYED_WORK(&device->work, fw_device_init);		schedule_delayed_work(&device->work, INITIAL_DELAY);		break;	case FW_NODE_UPDATED:		if (!node->link_on || node->data == NULL)			break;		device = node->data;		device->node_id = node->node_id;		device->generation = card->generation;		if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {			PREPARE_DELAYED_WORK(&device->work, fw_device_update);			schedule_delayed_work(&device->work, 0);		}		break;	case FW_NODE_DESTROYED:	case FW_NODE_LINK_OFF:		if (!node->data)			break;		/*		 * Destroy the device associated with the node.  There		 * are two cases here: either the device is fully		 * initialized (FW_DEVICE_RUNNING) or we're in the		 * process of reading its config rom		 * (FW_DEVICE_INITIALIZING).  If it is fully		 * initialized we can reuse device->work to schedule a		 * full fw_device_shutdown().  If not, there's work		 * scheduled to read it's config rom, and we just put		 * the device in shutdown state to have that code fail		 * to create the device.		 */		device = node->data;		if (atomic_xchg(&device->state,				FW_DEVICE_SHUTDOWN) == FW_DEVICE_RUNNING) {			PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);			schedule_delayed_work(&device->work, 0);		}		break;	}}

⌨️ 快捷键说明

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