📄 nodemgr.c
字号:
snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u", ne->device.bus_id, ud->id); if (device_register(&ud->device)) goto fail_devreg; if (class_device_register(&ud->class_dev)) goto fail_classdevreg; get_device(&ud->device); nodemgr_create_ud_dev_files(ud); return;fail_classdevreg: device_unregister(&ud->device);fail_devreg: HPSB_ERR("Failed to create unit %s", ud->device.bus_id);} /* This implementation currently only scans the config rom and its * immediate unit directories looking for software_id and * software_version entries, in order to get driver autoloading working. */static struct unit_directory *nodemgr_process_unit_directory (struct host_info *hi, struct node_entry *ne, struct csr1212_keyval *ud_kv, unsigned int *id, struct unit_directory *parent){ struct unit_directory *ud; struct unit_directory *ud_child = NULL; struct csr1212_dentry *dentry; struct csr1212_keyval *kv; u8 last_key_id = 0; ud = kzalloc(sizeof(*ud), GFP_KERNEL); if (!ud) goto unit_directory_error; ud->ne = ne; ud->ignore_driver = ignore_drivers; ud->address = ud_kv->offset + CSR1212_CONFIG_ROM_SPACE_BASE; ud->ud_kv = ud_kv; ud->id = (*id)++; csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) { switch (kv->key.id) { case CSR1212_KV_ID_VENDOR: if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { ud->vendor_id = kv->value.immediate; ud->flags |= UNIT_DIRECTORY_VENDOR_ID; } break; case CSR1212_KV_ID_MODEL: 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: /* Logical Unit Number */ if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { if (ud->flags & UNIT_DIRECTORY_HAS_LUN) { ud_child = kmemdup(ud, sizeof(*ud_child), GFP_KERNEL); if (!ud_child) goto unit_directory_error; nodemgr_register_device(ne, ud_child, &ne->device); ud_child = NULL; ud->id = (*id)++; } ud->lun = kv->value.immediate; ud->flags |= UNIT_DIRECTORY_HAS_LUN; /* Logical Unit Directory */ } else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) { /* This should really be done in SBP2 as this is * doing SBP2 specific parsing. */ /* first register the parent unit */ ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY; if (ud->device.bus != &ieee1394_bus_type) nodemgr_register_device(ne, ud, &ne->device); /* process the child unit */ ud_child = nodemgr_process_unit_directory(hi, ne, kv, id, ud); if (ud_child == NULL) break; /* inherit unspecified values, the driver core picks it up */ if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) && !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID)) { ud_child->flags |= UNIT_DIRECTORY_MODEL_ID; ud_child->model_id = ud->model_id; } if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) && !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID)) { ud_child->flags |= UNIT_DIRECTORY_SPECIFIER_ID; ud_child->specifier_id = ud->specifier_id; } if ((ud->flags & UNIT_DIRECTORY_VERSION) && !(ud_child->flags & UNIT_DIRECTORY_VERSION)) { ud_child->flags |= UNIT_DIRECTORY_VERSION; ud_child->version = ud->version; } /* register the child unit */ ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY; nodemgr_register_device(ne, ud_child, &ud->device); } break; default: break; } last_key_id = kv->key.id; } /* do not process child units here and only if not already registered */ if (!parent && ud->device.bus != &ieee1394_bus_type) nodemgr_register_device(ne, ud, &ne->device); return ud;unit_directory_error: 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; 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_name_kv && device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv)) goto fail; return;fail: HPSB_ERR("Failed to add sysfs attribute for node %016Lx", (unsigned long long)ne->guid);}#ifdef CONFIG_HOTPLUGstatic int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, char *buffer, int buffer_size){ struct unit_directory *ud; int i = 0; int length = 0; /* ieee1394:venNmoNspNverN */ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; 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); snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", ud->vendor_id, ud->model_id, ud->specifier_id, ud->version); PUT_ENVP("MODALIAS=%s", buf);#undef PUT_ENVP envp[i] = NULL; return 0;}#elsestatic int nodemgr_uevent(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 *drv, struct module *owner){ int error; drv->driver.bus = &ieee1394_bus_type; drv->driver.owner = owner; drv->driver.name = drv->name; /* This will cause a probe for devices */ error = driver_register(&drv->driver); if (!error) nodemgr_create_drv_files(drv); return error;}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; } else { /* old cache is valid, so update its generation */ struct nodemgr_csr_info *ci = ne->csr->private; ci->generation = generation; /* free the partially filled now unneeded new cache */ kfree(csr->private); csr1212_destroy_csr(csr); } 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; u8 *speed; ci = kmalloc(sizeof(*ci), GFP_KERNEL); if (!ci) return; ci->host = host; ci->nodeid = nodeid; ci->generation = generation; /* Prepare for speed probe which occurs when reading the ROM */ speed = &(host->speed[NODEID_TO_NODE(nodeid)]); if (*speed > host->csr.lnk_spd) *speed = host->csr.lnk_spd; ci->speed_unverified = *speed > IEEE1394_SPEED_100; /* 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);}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; WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); 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 && (!ud->device.driver->suspend || ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) device_release_driver(&ud->device); up_write(&ieee1394_bus_type.subsys.rwsem); } up(&nodemgr_ud_class.sem);}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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -