📄 nodemgr.c
字号:
ud->model_name_size = model_name_size; } return ud;}/* 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 node_entry *ne, octlet_t address, struct unit_directory *parent){ struct unit_directory *ud; quadlet_t quad; quadlet_t *infop; int length; struct unit_directory *ud_temp = NULL; if (!(ud = nodemgr_scan_unit_directory(ne, address))) goto unit_directory_error; ud->ne = ne; ud->address = address; if (parent) { ud->flags |= UNIT_DIRECTORY_LUN_DIRECTORY; ud->parent = parent; } if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) goto unit_directory_error; length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ; address += 4; infop = (quadlet_t *) ud->quadlets; for (; length > 0; length--, address += 4) { int code; quadlet_t value; quadlet_t *quadp; if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) goto unit_directory_error; code = CONFIG_ROM_KEY(quad) ; value = CONFIG_ROM_VALUE(quad); switch (code) { case CONFIG_ROM_VENDOR_ID: ud->vendor_id = value; ud->flags |= UNIT_DIRECTORY_VENDOR_ID; if (ud->vendor_id) ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id); if ((ud->flags & UNIT_DIRECTORY_VENDOR_TEXT) != 0) { length--; address += 4; quadp = &(ud->quadlets[ud->length]); if (nodemgr_read_text_leaf(ne, address, quadp) == 0 && quadp[0] == 0 && quadp[1] == 0) { /* We only support minimal ASCII and English. */ quadp[ud->vendor_name_size] = 0; ud->vendor_name = (const char *) &(quadp[2]); } } break; case CONFIG_ROM_MODEL_ID: ud->model_id = value; ud->flags |= UNIT_DIRECTORY_MODEL_ID; if ((ud->flags & UNIT_DIRECTORY_MODEL_TEXT) != 0) { length--; address += 4; quadp = &(ud->quadlets[ud->length + ud->vendor_name_size + 1]); if (nodemgr_read_text_leaf(ne, address, quadp) == 0 && quadp[0] == 0 && quadp[1] == 0) { /* We only support minimal ASCII and English. */ quadp[ud->model_name_size] = 0; ud->model_name = (const char *) &(quadp[2]); } } break; case CONFIG_ROM_SPECIFIER_ID: ud->specifier_id = value; ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID; break; case CONFIG_ROM_UNIT_SW_VERSION: ud->version = value; ud->flags |= UNIT_DIRECTORY_VERSION; break; case CONFIG_ROM_DESCRIPTOR_LEAF: case CONFIG_ROM_DESCRIPTOR_DIRECTORY: /* TODO: read strings... icons? */ break; case CONFIG_ROM_LOGICAL_UNIT_DIRECTORY: ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY; ud_temp = nodemgr_process_unit_directory(ne, address + value * 4, ud); 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; } 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: /* Which types of quadlets do we want to store? Only count immediate values and CSR offsets for now. */ code &= CONFIG_ROM_KEY_TYPE_MASK; if ((code & CONFIG_ROM_KEY_TYPE_LEAF) == 0) *infop++ = quad; break; } } list_add_tail(&ud->node_list, &ne->unit_directories); list_add_tail(&ud->driver_list, &unit_directory_list); return ud; unit_directory_error: if (ud != NULL) kfree(ud); return NULL;}static void nodemgr_process_root_directory(struct node_entry *ne){ octlet_t address; quadlet_t quad; int length; address = CSR_REGISTER_BASE + CSR_CONFIG_ROM; if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) return; address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4; if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) return; length = CONFIG_ROM_ROOT_LENGTH(quad); address += 4; for (; length > 0; length--, address += 4) { int code, value; if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) return; code = CONFIG_ROM_KEY(quad); value = CONFIG_ROM_VALUE(quad); switch (code) { case CONFIG_ROM_VENDOR_ID: ne->vendor_id = value; if (ne->vendor_id) ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id); /* Now check if there is a vendor name text string. */ if (ne->vendor_name != NULL) { length--; address += 4; if (nodemgr_read_text_leaf(ne, address, ne->quadlets) != 0 || ne->quadlets[0] != 0 || ne->quadlets[1] != 0) /* We only support minimal ASCII and English. */ ne->vendor_name = NULL; } break; case CONFIG_ROM_NODE_CAPABILITES: ne->capabilities = value; break; case CONFIG_ROM_UNIT_DIRECTORY: nodemgr_process_unit_directory(ne, address + value * 4, NULL); break; case CONFIG_ROM_DESCRIPTOR_LEAF: case CONFIG_ROM_DESCRIPTOR_DIRECTORY: /* TODO: read strings... icons? */ break; } }}#ifdef CONFIG_HOTPLUGstatic void nodemgr_call_policy(char *verb, struct unit_directory *ud){ char *argv [3], **envp, *buf, *scratch; int i = 0, value; if (!hotplug_path [0]) return; if (!current->fs->root) return; if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) { HPSB_DEBUG ("ENOMEM"); return; } if (!(buf = kmalloc(256, GFP_KERNEL))) { kfree(envp); HPSB_DEBUG("ENOMEM2"); return; } /* only one standardized param to hotplug command: type */ argv[0] = hotplug_path; argv[1] = "ieee1394"; argv[2] = 0; /* minimal command environment */ envp[i++] = "HOME=/"; envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; #ifdef CONFIG_IEEE1394_VERBOSEDEBUG /* hint that policy agent should enter no-stdout debug mode */ envp[i++] = "DEBUG=kernel";#endif /* extensible set of named bus-specific parameters, * supporting multiple driver selection algorithms. */ scratch = buf; envp[i++] = scratch; scratch += sprintf(scratch, "ACTION=%s", verb) + 1; envp[i++] = scratch; scratch += sprintf(scratch, "VENDOR_ID=%06x", ud->vendor_id) + 1; envp[i++] = scratch; scratch += sprintf(scratch, "GUID=%016Lx", (long long unsigned)ud->ne->guid) + 1; envp[i++] = scratch; scratch += sprintf(scratch, "SPECIFIER_ID=%06x", ud->specifier_id) + 1; envp[i++] = scratch; scratch += sprintf(scratch, "VERSION=%06x", ud->version) + 1; envp[i++] = 0; /* NOTE: user mode daemons can call the agents too */ HPSB_VERBOSE("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid); value = call_usermodehelper(argv[0], argv, envp); kfree(buf); kfree(envp); if (value != 0) HPSB_DEBUG("NodeMgr: hotplug policy returned %d", value);}#elsestatic inline voidnodemgr_call_policy(char *verb, struct unit_directory *ud){ HPSB_VERBOSE("NodeMgr: nodemgr_call_policy(): hotplug not enabled"); return;} #endif /* CONFIG_HOTPLUG */static void nodemgr_claim_unit_directory(struct unit_directory *ud, struct hpsb_protocol_driver *driver){ ud->driver = driver; list_move_tail(&ud->driver_list, &driver->unit_directories);}static void nodemgr_release_unit_directory(struct unit_directory *ud){ ud->driver = NULL; list_move_tail(&ud->driver_list, &unit_directory_list);}void hpsb_release_unit_directory(struct unit_directory *ud){ down(&nodemgr_serialize); nodemgr_release_unit_directory(ud); up(&nodemgr_serialize);}static void nodemgr_free_unit_directories(struct node_entry *ne){ struct list_head *lh, *next; struct unit_directory *ud; list_for_each_safe(lh, next, &ne->unit_directories) { ud = list_entry(lh, struct unit_directory, node_list); if (ud->driver && ud->driver->disconnect) ud->driver->disconnect(ud); nodemgr_release_unit_directory(ud); nodemgr_call_policy("remove", ud); list_del(&ud->driver_list); list_del(&ud->node_list); kfree(ud); }}static struct ieee1394_device_id *nodemgr_match_driver(struct hpsb_protocol_driver *driver, struct unit_directory *ud){ struct ieee1394_device_id *id; for (id = driver->id_table; id->match_flags != 0; id++) { if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && id->vendor_id != ud->vendor_id) continue; if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) && id->model_id != ud->model_id) continue; if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) && id->specifier_id != ud->specifier_id) continue; /* software version does a bitwise comparison instead of equality */ if ((id->match_flags & IEEE1394_MATCH_VERSION) && !(id->version & ud->version)) continue; return id; } return NULL;}static struct hpsb_protocol_driver *nodemgr_find_driver(struct unit_directory *ud){ struct list_head *l; struct hpsb_protocol_driver *match, *driver; struct ieee1394_device_id *device_id; match = NULL; list_for_each(l, &driver_list) { driver = list_entry(l, struct hpsb_protocol_driver, list); device_id = nodemgr_match_driver(driver, ud); if (device_id != NULL) { match = driver; break; } } return match;}static void nodemgr_bind_drivers (struct node_entry *ne){ struct list_head *lh; struct hpsb_protocol_driver *driver; struct unit_directory *ud; list_for_each(lh, &ne->unit_directories) { ud = list_entry(lh, struct unit_directory, node_list); driver = nodemgr_find_driver(ud); if (driver && (!driver->probe || driver->probe(ud) == 0)) nodemgr_claim_unit_directory(ud, driver); nodemgr_call_policy("add", ud); }}int hpsb_register_protocol(struct hpsb_protocol_driver *driver){ struct unit_directory *ud; struct list_head *lh, *next; if (down_interruptible(&nodemgr_serialize)) return -EINTR; list_add_tail(&driver->list, &driver_list); INIT_LIST_HEAD(&driver->unit_directories); list_for_each_safe (lh, next, &unit_directory_list) { ud = list_entry(lh, struct unit_directory, driver_list); if (nodemgr_match_driver(driver, ud) && (!driver->probe || driver->probe(ud) == 0)) nodemgr_claim_unit_directory(ud, driver); } up(&nodemgr_serialize); /* * Right now registration always succeeds, but maybe we should * detect clashes in protocols handled by other drivers. * DRD> No because multiple drivers are needed to handle certain devices. * For example, a DV camera is an IEC 61883 device (dv1394) and AV/C (raw1394). * This will become less an issue with libiec61883 using raw1394. * * BenC: But can we handle this with an ALLOW_SHARED flag for a * protocol? When we get an SBP-3 driver, it will be nice if they were * mutually exclusive, since SBP-3 can handle SBP-2 protocol. * * Not to mention that we currently do not seem to support multiple * drivers claiming the same unitdirectory. If we implement both of * those, then we'll need to keep probing when a driver claims a * unitdirectory, but is sharable. */ return 0;}void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver){ struct list_head *lh, *next; struct unit_directory *ud; down(&nodemgr_serialize); list_del(&driver->list); list_for_each_safe (lh, next, &driver->unit_directories) { ud = list_entry(lh, struct unit_directory, driver_list); if (ud->driver && ud->driver->disconnect) ud->driver->disconnect(ud); nodemgr_release_unit_directory(ud); } up(&nodemgr_serialize);}static void nodemgr_process_config_rom(struct node_entry *ne, quadlet_t busoptions){ ne->busopt.irmc = (busoptions >> 31) & 1; ne->busopt.cmc = (busoptions >> 30) & 1; ne->busopt.isc = (busoptions >> 29) & 1; ne->busopt.bmc = (busoptions >> 28) & 1; ne->busopt.pmc = (busoptions >> 27) & 1; ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff; ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1); ne->busopt.generation = (busoptions >> 4) & 0xf; ne->busopt.lnkspd = busoptions & 0x7; HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d " "cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d", busoptions, ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc, ne->busopt.cyc_clk_acc, ne->busopt.max_rec, ne->busopt.generation, ne->busopt.lnkspd); /* * When the config rom changes we disconnect all drivers and * free the cached unit directories and reread the whole * thing. If this was a new device, the call to * nodemgr_disconnect_drivers is a no-op and all is well. */ nodemgr_free_unit_directories(ne); nodemgr_process_root_directory(ne); nodemgr_bind_drivers(ne);}/** 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, quadlet_t busoptions, struct host_info *hi, nodeid_t nodeid,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -