📄 devices.c
字号:
msg += 7; uevent->action = msg; } else if(!strncmp(msg, "DEVPATH=", 8)) { msg += 8; uevent->path = msg; } else if(!strncmp(msg, "SUBSYSTEM=", 10)) { msg += 10; uevent->subsystem = msg; } else if(!strncmp(msg, "FIRMWARE=", 9)) { msg += 9; uevent->firmware = msg; } else if(!strncmp(msg, "MAJOR=", 6)) { msg += 6; uevent->major = atoi(msg); } else if(!strncmp(msg, "MINOR=", 6)) { msg += 6; uevent->minor = atoi(msg); } /* advance to after the next \0 */ while(*msg++) ; } log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n", uevent->action, uevent->path, uevent->subsystem, uevent->firmware, uevent->major, uevent->minor);}static void handle_device_event(struct uevent *uevent){ char devpath[96]; char *base, *name; int block; /* if it's not a /dev device, nothing to do */ if((uevent->major < 0) || (uevent->minor < 0)) return; /* do we have a name? */ name = strrchr(uevent->path, '/'); if(!name) return; name++; /* too-long names would overrun our buffer */ if(strlen(name) > 64) return; /* are we block or char? where should we live? */ if(!strncmp(uevent->path, "/block", 6)) { block = 1; base = "/dev/block/"; mkdir(base, 0755); } else { block = 0; /* this should probably be configurable somehow */ if(!strncmp(uevent->path, "/class/graphics/", 16)) { base = "/dev/graphics/"; mkdir(base, 0755); } else if (!strncmp(uevent->path, "/class/oncrpc/", 14)) { base = "/dev/oncrpc/"; mkdir(base, 0755); } else if (!strncmp(uevent->path, "/class/adsp/", 12)) { base = "/dev/adsp/"; mkdir(base, 0755); } else if(!strncmp(uevent->path, "/class/input/", 13)) { base = "/dev/input/"; mkdir(base, 0755); } else if(!strncmp(uevent->path, "/class/mtd/", 11)) { base = "/dev/mtd/"; mkdir(base, 0755); } else if(!strncmp(uevent->path, "/class/misc/", 12) && !strncmp(name, "log_", 4)) { base = "/dev/log/"; mkdir(base, 0755); name += 4; } else base = "/dev/"; } snprintf(devpath, sizeof(devpath), "%s%s", base, name); if(!strcmp(uevent->action, "add")) { make_device(devpath, block, uevent->major, uevent->minor); return; } if(!strcmp(uevent->action, "remove")) { unlink(devpath); return; }}static int load_firmware(int fw_fd, int loading_fd, int data_fd){ struct stat st; long len_to_copy; int ret = 0; if(fstat(fw_fd, &st) < 0) return -1; len_to_copy = st.st_size; write(loading_fd, "1", 1); /* start transfer */ while (len_to_copy > 0) { char buf[PAGE_SIZE]; ssize_t nr; nr = read(fw_fd, buf, sizeof(buf)); if(!nr) break; if(nr < 0) { ret = -1; break; } len_to_copy -= nr; while (nr > 0) { ssize_t nw = 0; nw = write(data_fd, buf + nw, nr); if(nw <= 0) { ret = -1; goto out; } nr -= nw; } }out: if(!ret) write(loading_fd, "0", 1); /* successful end of transfer */ else write(loading_fd, "-1", 2); /* abort transfer */ return ret;}static void process_firmware_event(struct uevent *uevent){ char *root, *loading, *data, *file; int l, loading_fd, data_fd, fw_fd; log_event_print("firmware event { '%s', '%s' }\n", uevent->path, uevent->firmware); l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path); if (l == -1) return; l = asprintf(&loading, "%sloading", root); if (l == -1) goto root_free_out; l = asprintf(&data, "%sdata", root); if (l == -1) goto loading_free_out; l = asprintf(&file, FIRMWARE_DIR"/%s", uevent->firmware); if (l == -1) goto data_free_out; loading_fd = open(loading, O_WRONLY); if(loading_fd < 0) goto file_free_out; data_fd = open(data, O_WRONLY); if(data_fd < 0) goto loading_close_out; fw_fd = open(file, O_RDONLY); if(fw_fd < 0) goto data_close_out; if(!load_firmware(fw_fd, loading_fd, data_fd)) log_event_print("firmware copy success { '%s', '%s' }\n", root, file); else log_event_print("firmware copy failure { '%s', '%s' }\n", root, file); close(fw_fd);data_close_out: close(data_fd);loading_close_out: close(loading_fd);file_free_out: free(file);data_free_out: free(data);loading_free_out: free(loading);root_free_out: free(root);}static void handle_firmware_event(struct uevent *uevent){ pid_t pid; if(strcmp(uevent->subsystem, "firmware")) return; if(strcmp(uevent->action, "add")) return; /* we fork, to avoid making large memory allocations in init proper */ pid = fork(); if (!pid) { process_firmware_event(uevent); exit(EXIT_SUCCESS); }}#define UEVENT_MSG_LEN 1024void handle_device_fd(int fd){ char msg[UEVENT_MSG_LEN+2]; int n; while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) { struct uevent uevent; if(n == UEVENT_MSG_LEN) /* overflow -- discard */ continue; msg[n] = '\0'; msg[n+1] = '\0'; parse_event(msg, &uevent); handle_device_event(&uevent); handle_firmware_event(&uevent); }}/* Coldboot walks parts of the /sys tree and pokes the uevent files** to cause the kernel to regenerate device add events that happened** before init's device manager was started**** We drain any pending events from the netlink socket every time** we poke another uevent file to make sure we don't overrun the** socket's buffer. */static void do_coldboot(int event_fd, DIR *d){ struct dirent *de; int dfd, fd; dfd = dirfd(d); fd = openat(dfd, "uevent", O_WRONLY); if(fd >= 0) { write(fd, "add\n", 4); close(fd); handle_device_fd(event_fd); } while((de = readdir(d))) { DIR *d2; if(de->d_type != DT_DIR || de->d_name[0] == '.') continue; fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); if(fd < 0) continue; d2 = fdopendir(fd); if(d2 == 0) close(fd); else { do_coldboot(event_fd, d2); closedir(d2); } }}static void coldboot(int event_fd, const char *path){ DIR *d = opendir(path); if(d) { do_coldboot(event_fd, d); closedir(d); }}int device_init(void){ suseconds_t t0, t1; int fd; fd = open_uevent_socket(); if(fd < 0) return -1; fcntl(fd, F_SETFD, FD_CLOEXEC); fcntl(fd, F_SETFL, O_NONBLOCK); t0 = get_usecs(); coldboot(fd, "/sys/class"); coldboot(fd, "/sys/block"); coldboot(fd, "/sys/devices"); t1 = get_usecs(); log_event_print("coldboot %ld uS\n", ((long) (t1 - t0))); return fd;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -