devices.c revision 27b8b3a1aab015ed8673ffd03bbf57f63adb85f0
1e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/* 2e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Copyright (C) 2007 The Android Open Source Project 3e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * 4e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 5e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * you may not use this file except in compliance with the License. 6e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * You may obtain a copy of the License at 7e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * 8e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 9e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * 10e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Unless required by applicable law or agreed to in writing, software 11e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 12e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * See the License for the specific language governing permissions and 14e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * limitations under the License. 15e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy */ 16e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy 1785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy#include <errno.h> 18e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <stdio.h> 19e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <stdlib.h> 20e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <sys/stat.h> 21e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <sys/types.h> 22e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy 23bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy#include <fcntl.h> 2403d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy#include <dirent.h> 25694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#include <unistd.h> 265cbbce535744b89df5ecea95de21ee3733298260Romain Guy#include <string.h> 275cbbce535744b89df5ecea95de21ee3733298260Romain Guy 28e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy#include <sys/socket.h> 2985bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy#include <sys/un.h> 3008aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy#include <linux/netlink.h> 3108aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy#include <private/android_filesystem_config.h> 325b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#include <sys/time.h> 335b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#include <asm/page.h> 3485bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy 350fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy#include "init.h" 36710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik#include "devices.h" 37a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy 38e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#define CMDLINE_PREFIX "/dev" 39e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#define SYSFS_PREFIX "/sys" 409d5316e3f56d138504565ff311145ac01621dff4Romain Guy#define FIRMWARE_DIR "/etc/firmware" 419d5316e3f56d138504565ff311145ac01621dff4Romain Guy#define MAX_QEMU_PERM 6 429d5316e3f56d138504565ff311145ac01621dff4Romain Guy 439d5316e3f56d138504565ff311145ac01621dff4Romain Guystruct uevent { 449d5316e3f56d138504565ff311145ac01621dff4Romain Guy const char *action; 459d5316e3f56d138504565ff311145ac01621dff4Romain Guy const char *path; 46759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy const char *subsystem; 47759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy const char *firmware; 48759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy int major; 49f877308f77f7c6f3edd91618a092207dd3be9077Romain Guy int minor; 50dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy}; 51d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy 52d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guystatic int open_uevent_socket(void) 539d5316e3f56d138504565ff311145ac01621dff4Romain Guy{ 549d5316e3f56d138504565ff311145ac01621dff4Romain Guy struct sockaddr_nl addr; 559d5316e3f56d138504565ff311145ac01621dff4Romain Guy int sz = 64*1024; // XXX larger? udev uses 16MB! 569d5316e3f56d138504565ff311145ac01621dff4Romain Guy int s; 57889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy 58889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy memset(&addr, 0, sizeof(addr)); 59889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy addr.nl_family = AF_NETLINK; 60889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy addr.nl_pid = getpid(); 61889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy addr.nl_groups = 0xffffffff; 62889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy 63889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 64889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy if(s < 0) 65889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy return -1; 66026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy 67026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)); 68026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy 692ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 702ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy close(s); 712ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy return -1; 722ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy } 732ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy 742ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy return s; 752ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy} 762ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy 772ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guystruct perms_ { 782ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy char *name; 792ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy mode_t perm; 802ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy unsigned int uid; 812ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy unsigned int gid; 822ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy unsigned short prefix; 832ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy}; 84026c5e16704e817cac7d9c382914c947e34f87e0Romain Guystatic struct perms_ devperms[] = { 85e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy { "/dev/null", 0666, AID_ROOT, AID_ROOT, 0 }, 8687a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy { "/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 }, 8787a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy { "/dev/full", 0666, AID_ROOT, AID_ROOT, 0 }, 8887a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy { "/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 }, 89f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy { "/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 }, 902ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy { "/dev/random", 0666, AID_ROOT, AID_ROOT, 0 }, 912ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy { "/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 }, 922ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy { "/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 }, 932ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy { "/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 }, 942ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy 952ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy /* logger should be world writable (for logging) but not readable */ 962ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy { "/dev/log/", 0662, AID_ROOT, AID_LOG, 1 }, 972ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy 982ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy /* the msm hw3d client device node is world writable/readable. */ 992ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy { "/dev/msm_hw3dc", 0666, AID_ROOT, AID_ROOT, 0 }, 1002ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy 1012ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy /* gpu driver for adreno200 is globally accessible */ 1022ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy { "/dev/kgsl", 0666, AID_ROOT, AID_ROOT, 0 }, 1032ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy 1042ffefd48e20d311b38c0673edadb27c1f6ad328bRomain Guy /* STOPSHIP: temporarily make this be writable by all. We need to 105f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy * remove this entirely before we ship. */ 106f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy { "/dev/pmem_gpu", 0666, AID_ROOT, AID_ROOT, 1 }, 107f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy 108f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy /* these should not be world writable */ 109f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy { "/dev/diag", 0660, AID_RADIO, AID_RADIO, 0 }, 110f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy { "/dev/diag_arm9", 0660, AID_RADIO, AID_RADIO, 0 }, 111fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy { "/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 }, 11206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy { "/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 }, 113db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy { "/dev/ttyMSM0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, 1141e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy { "/dev/ttyHS0", 0600, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, 1155ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy { "/dev/uinput", 0660, AID_SYSTEM, AID_BLUETOOTH, 0 }, 116026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy { "/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 }, 117ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy { "/dev/tty0", 0660, AID_ROOT, AID_SYSTEM, 0 }, 118ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy { "/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 }, 119ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy { "/dev/msm_hw3dm", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, 120e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy { "/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 }, 121e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy { "/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 }, 12285bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy { "/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 }, 12329d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy { "/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, 12429d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy { "/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 125e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy { "/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 }, 126e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy { "/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 }, 127f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy { "/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 12813631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 }, 12913631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/msm_camera/", 0660, AID_SYSTEM, AID_SYSTEM, 1 }, 13013631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 }, 13113631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 13213631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/akm8973_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 }, 13313631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/akm8973_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 13413631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/bma150", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 13513631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/cm3602", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 13613631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 13713631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/lightsensor", 0640, AID_SYSTEM, AID_SYSTEM, 0 }, 13813631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 13913631f3da855f200a151e7837ed9f6b079622b58Romain Guy { "/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 140f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy { "/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 141f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy { "/dev/msm_snd", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 142f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy { "/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 14349c5fc0b9e850497233e189ff9dcc71a78ebe6e7Romain Guy { "/dev/audience_a1026", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 14449c5fc0b9e850497233e189ff9dcc71a78ebe6e7Romain Guy { "/dev/msm_audpre", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 14549c5fc0b9e850497233e189ff9dcc71a78ebe6e7Romain Guy { "/dev/msm_audio_ctl", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 14649c5fc0b9e850497233e189ff9dcc71a78ebe6e7Romain Guy { "/dev/htc-acoustic", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 14785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy { "/dev/vdec", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 14835643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/snd/dsp", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 14935643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/snd/dsp1", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 15035643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/snd/mixer", 0660, AID_SYSTEM, AID_AUDIO, 0 }, 15135643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 }, 15235643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/qemu_trace", 0666, AID_SYSTEM, AID_SYSTEM, 0 }, 15335643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 }, 15435643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 }, 15535643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 }, 15635643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy { "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 }, 157260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy /* CDMA radio interface MUX */ 158bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy { "/dev/ts0710mux", 0640, AID_RADIO, AID_RADIO, 1 }, 159bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy { "/dev/ppp", 0660, AID_RADIO, AID_VPN, 0 }, 160bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy { "/dev/tun", 0640, AID_VPN, AID_VPN, 0 }, 161eb99356a0548684a501766e6a524529ab93304c8Romain Guy { NULL, 0, 0, 0, 0 }, 162eb99356a0548684a501766e6a524529ab93304c8Romain Guy}; 163eb99356a0548684a501766e6a524529ab93304c8Romain Guy 164e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/* devperms_partners list and perm_node are for hardware specific /dev entries */ 165e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guystruct perm_node { 16644b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase struct perms_ dp; 16744b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase struct listnode plist; 1687d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy}; 1697d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guylist_declare(devperms_partners); 17044b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase 171fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy/* 172fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy * Permission override when in emulator mode, must be parsed before 1738aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy * system properties is initalized. 1748aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy */ 17584962f2fe6ce779c583cc54b11a9de2b6a568117Romain Guystatic int qemu_perm_count; 1768fb954263dd2f918ad339045cc6d82e346515599Romain Guystatic struct perms_ qemu_perms[MAX_QEMU_PERM + 1]; 177f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy 1787d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guyint add_devperms_partners(const char *name, mode_t perm, unsigned int uid, 1792b7028eabac80cec170572bc0e945a1d4224e595Romain Guy unsigned int gid, unsigned short prefix) { 180ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy int size; 18145e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy struct perm_node *node = malloc(sizeof (struct perm_node)); 18245e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy if (!node) 18345e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy return -ENOMEM; 18445e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy 18545e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy size = strlen(name) + 1; 18645e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy if ((node->dp.name = malloc(size)) == NULL) 18745e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy return -ENOMEM; 18845e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy 18945e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy memcpy(node->dp.name, name, size); 190ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy node->dp.perm = perm; 1917d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy node->dp.uid = uid; 1922b7028eabac80cec170572bc0e945a1d4224e595Romain Guy node->dp.gid = gid; 1932b7028eabac80cec170572bc0e945a1d4224e595Romain Guy node->dp.prefix = prefix; 1942b7028eabac80cec170572bc0e945a1d4224e595Romain Guy 1956b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy list_add_tail(&devperms_partners, &node->plist); 196586cae3ac69c0c667fbf8a954edbd399f620a717Romain Guy return 0; 197ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy} 1986b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy 19944b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haasevoid qemu_init(void) { 200ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy qemu_perm_count = 0; 201ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy memset(&qemu_perms, 0, sizeof(qemu_perms)); 202ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy} 20344b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase 20444b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haasestatic int qemu_perm(const char* name, mode_t perm, unsigned int uid, 205ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy unsigned int gid, unsigned short prefix) 206ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy{ 207ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy char *buf; 208ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy if (qemu_perm_count == MAX_QEMU_PERM) 209ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy return -ENOSPC; 210ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy 211ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy buf = malloc(strlen(name) + 1); 212ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy if (!buf) 213ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy return -errno; 2146b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy 215bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy strlcpy(buf, name, strlen(name) + 1); 216bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy qemu_perms[qemu_perm_count].name = buf; 2172b7028eabac80cec170572bc0e945a1d4224e595Romain Guy qemu_perms[qemu_perm_count].perm = perm; 2182b7028eabac80cec170572bc0e945a1d4224e595Romain Guy qemu_perms[qemu_perm_count].uid = uid; 2192b7028eabac80cec170572bc0e945a1d4224e595Romain Guy qemu_perms[qemu_perm_count].gid = gid; 2202b7028eabac80cec170572bc0e945a1d4224e595Romain Guy qemu_perms[qemu_perm_count].prefix = prefix; 2212b7028eabac80cec170572bc0e945a1d4224e595Romain Guy 2222b7028eabac80cec170572bc0e945a1d4224e595Romain Guy qemu_perm_count++; 2232b7028eabac80cec170572bc0e945a1d4224e595Romain Guy return 0; 2242b7028eabac80cec170572bc0e945a1d4224e595Romain Guy} 2252b7028eabac80cec170572bc0e945a1d4224e595Romain Guy 2262b7028eabac80cec170572bc0e945a1d4224e595Romain Guy/* Permission overrides for emulator that are parsed from /proc/cmdline. */ 2272b7028eabac80cec170572bc0e945a1d4224e595Romain Guyvoid qemu_cmdline(const char* name, const char *value) 2282b7028eabac80cec170572bc0e945a1d4224e595Romain Guy{ 2292b7028eabac80cec170572bc0e945a1d4224e595Romain Guy char *buf; 2302b7028eabac80cec170572bc0e945a1d4224e595Romain Guy if (!strcmp(name, "android.ril")) { 2312b7028eabac80cec170572bc0e945a1d4224e595Romain Guy /* cmd line params currently assume /dev/ prefix */ 2322b7028eabac80cec170572bc0e945a1d4224e595Romain Guy if (asprintf(&buf, CMDLINE_PREFIX"/%s", value) == -1) { 2332b7028eabac80cec170572bc0e945a1d4224e595Romain Guy return; 2342b7028eabac80cec170572bc0e945a1d4224e595Romain Guy } 2352b7028eabac80cec170572bc0e945a1d4224e595Romain Guy INFO("nani- buf:: %s\n", buf); 2362b7028eabac80cec170572bc0e945a1d4224e595Romain Guy qemu_perm(buf, 0660, AID_RADIO, AID_ROOT, 0); 2372b7028eabac80cec170572bc0e945a1d4224e595Romain Guy } 238b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy} 2392b7028eabac80cec170572bc0e945a1d4224e595Romain Guy 2402b7028eabac80cec170572bc0e945a1d4224e595Romain Guystatic int get_device_perm_inner(struct perms_ *perms, const char *path, 241b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy unsigned *uid, unsigned *gid, mode_t *perm) 242b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy{ 243b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy int i; 2445baa3a62a97544669fba6d65a11c07f252e654ddSteve Block for(i = 0; perms[i].name; i++) { 245a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy 246a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy if(perms[i].prefix) { 247a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy if(strncmp(path, perms[i].name, strlen(perms[i].name))) 248a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy continue; 249a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy } else { 250a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy if(strcmp(path, perms[i].name)) 251a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy continue; 252a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy } 253a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy *uid = perms[i].uid; 254a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy *gid = perms[i].gid; 255a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy *perm = perms[i].perm; 256a44a63ac5c29b2cc57df95ec495def8cdddd9c6fRomain Guy return 0; 257a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy } 258a07105b7d2a27e6d69407bf96ddb773bddb5e553Romain Guy return -1; 259b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy} 260b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy 261c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy/* First checks for emulator specific permissions specified in /proc/cmdline. */ 262c15008e72ec00ca20a271c3006dac649fd07533bRomain Guystatic mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) 263e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy{ 264e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy mode_t perm; 265e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy 266e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy if (get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) { 267c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy return perm; 268b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy } else if (get_device_perm_inner(devperms, path, uid, gid, &perm) == 0) { 269b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy return perm; 2706c319ca1275c8db892c39b48fc54864c949f9171Romain Guy } else { 271da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy struct listnode *node; 272da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy struct perm_node *perm_node; 273da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy struct perms_ *dp; 274da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy 275da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy /* Check partners list. */ 276da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy list_for_each(node, &devperms_partners) { 27750c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy perm_node = node_to_item(node, struct perm_node, plist); 27815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy dp = &perm_node->dp; 279f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy 28015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy if (dp->prefix) { 281da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy if (strncmp(path, dp->name, strlen(dp->name))) 282da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy continue; 2836c319ca1275c8db892c39b48fc54864c949f9171Romain Guy } else { 28408837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase if (strcmp(path, dp->name)) 28508837c246c9c27902c59b41c8661c2f27a4aa2bcChet Haase continue; 28635643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy } 28735643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy /* Found perm in partner list. */ 2883e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy *uid = dp->uid; 2893e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy *gid = dp->gid; 2908025061c594e5171e1bf370d8fdd77e0e9a02b47Chet Haase return dp->perm; 291586cae3ac69c0c667fbf8a954edbd399f620a717Romain Guy } 29282bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy /* Default if nothing found. */ 293746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy *uid = 0; 294da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy *gid = 0; 295a1d3c91afbd52c7e8b01f4a9060c5459f02ae7a5Romain Guy return 0600; 29650c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy } 29750c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy} 29850c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy 29950c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guystatic void make_device(const char *path, int block, int major, int minor) 30050c0f093d942a59d4e01b2c76d26c0e9d6ed796cRomain Guy{ 301da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy unsigned uid; 302da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy unsigned gid; 30335643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy mode_t mode; 30435643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy dev_t dev; 30535643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy 30635643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy if(major > 255 || minor > 255) 30735643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy return; 30835643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy 30935643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); 31035643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy dev = (major << 8) | minor; 31135643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy mknod(path, mode, dev); 312ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy chown(path, uid, gid); 313932b7f6765968bd526c03512f3805fbc3924dc29Chris Craik} 314ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy 3158f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy#if LOG_UEVENTS 316ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy 317ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guystatic inline suseconds_t get_usecs(void) 318ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy{ 3198f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy struct timeval tv; 320ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy gettimeofday(&tv, 0); 321ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec; 3223d745c03ace18ee59c539e1b7f1df13f22beb57dRomain Guy} 3238f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy 324ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#define log_event_print(x...) INFO(x) 325ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy 326ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#else 327ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy 328ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#define log_event_print(fmt, args...) do { } while (0) 329ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#define get_usecs() 0 330ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy 331ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy#endif 332ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy 333ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guystatic void parse_event(const char *msg, struct uevent *uevent) 334ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy{ 335ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy uevent->action = ""; 336ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy uevent->path = ""; 337ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy uevent->subsystem = ""; 338ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy uevent->firmware = ""; 339ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy uevent->major = -1; 340ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy uevent->minor = -1; 341ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy 342c2c9543c135ffc4e18c7db0e817112ac03e3e97aChris Craik /* currently ignoring SEQNUM */ 343ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy while(*msg) { 344ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy if(!strncmp(msg, "ACTION=", 7)) { 345c2c9543c135ffc4e18c7db0e817112ac03e3e97aChris Craik msg += 7; 346ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy uevent->action = msg; 347c2c9543c135ffc4e18c7db0e817112ac03e3e97aChris Craik } else if(!strncmp(msg, "DEVPATH=", 8)) { 348c2c9543c135ffc4e18c7db0e817112ac03e3e97aChris Craik msg += 8; 3498f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy uevent->path = msg; 3508f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy } else if(!strncmp(msg, "SUBSYSTEM=", 10)) { 351beb8bd0db28d8c5cad2a258f2ba2f3b8b76cf037Chet Haase msg += 10; 352beb8bd0db28d8c5cad2a258f2ba2f3b8b76cf037Chet Haase uevent->subsystem = msg; 353beb8bd0db28d8c5cad2a258f2ba2f3b8b76cf037Chet Haase } else if(!strncmp(msg, "FIRMWARE=", 9)) { 354beb8bd0db28d8c5cad2a258f2ba2f3b8b76cf037Chet Haase msg += 9; 3558f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy uevent->firmware = msg; 3568f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy } else if(!strncmp(msg, "MAJOR=", 6)) { 3578f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy msg += 6; 3588f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy uevent->major = atoi(msg); 3598f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy } else if(!strncmp(msg, "MINOR=", 6)) { 3608f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy msg += 6; 361daf98e941e140e8739458126640183b9f296a2abChet Haase uevent->minor = atoi(msg); 362932b7f6765968bd526c03512f3805fbc3924dc29Chris Craik } 363c8538ade8df2c2f013f8b93094912057ee1cc417Chris Craik 3648a4ac610e1aaf04931ac1af54b146a7fc8e66114Romain Guy /* advance to after the next \0 */ 365f90f8171e6acb56f9f87093c01fd586f2140697aRomain Guy while(*msg++) 366f90f8171e6acb56f9f87093c01fd586f2140697aRomain Guy ; 367f90f8171e6acb56f9f87093c01fd586f2140697aRomain Guy } 368d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy 36980911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n", 37080911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy uevent->action, uevent->path, uevent->subsystem, 37180911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy uevent->firmware, uevent->major, uevent->minor); 372d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy} 373d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy 374d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guystatic void handle_device_event(struct uevent *uevent) 375d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy{ 376d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy char devpath[96]; 377d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy char *base, *name; 37808aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy int block; 37908aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy 38008aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy /* if it's not a /dev device, nothing to do */ 38108aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy if((uevent->major < 0) || (uevent->minor < 0)) 38208aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy return; 38308aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy 3847b6a75872bd2df96a23453d31c2e2e7fcc373554Chet Haase /* do we have a name? */ 3857b6a75872bd2df96a23453d31c2e2e7fcc373554Chet Haase name = strrchr(uevent->path, '/'); 38608aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy if(!name) 38780911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy return; 388486590963e2207d68eebd6944fec70d50d41116aChet Haase name++; 389cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy 3908f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy /* too-long names would overrun our buffer */ 39108aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy if(strlen(name) > 64) 392cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy return; 3938f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy 39465924a3e56c2e7ac863f8e25e9f9a58b9db7d513Chris Craik /* are we block or char? where should we live? */ 395ba6be8a62dcdb3ffd210cd36b9af4e3a658eac47Romain Guy if(!strncmp(uevent->subsystem, "block", 5)) { 3968f3b8e32993d190a26c70c839a63d8ce4c3b16d9Romain Guy block = 1; 397cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy base = "/dev/block/"; 398cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy mkdir(base, 0755); 399daf98e941e140e8739458126640183b9f296a2abChet Haase } else { 4006554943a1dd6854c0f4976900956e556767b49e1Romain Guy block = 0; 401daf98e941e140e8739458126640183b9f296a2abChet Haase /* this should probably be configurable somehow */ 402daf98e941e140e8739458126640183b9f296a2abChet Haase if(!strncmp(uevent->subsystem, "graphics", 8)) { 403f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy base = "/dev/graphics/"; 404f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy mkdir(base, 0755); 405f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) { 406f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy base = "/dev/oncrpc/"; 407bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy mkdir(base, 0755); 4087ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy } else if (!strncmp(uevent->subsystem, "adsp", 4)) { 409bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy base = "/dev/adsp/"; 410bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy mkdir(base, 0755); 411bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) { 4128aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy base = "/dev/msm_camera/"; 413bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy mkdir(base, 0755); 414bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy } else if(!strncmp(uevent->subsystem, "input", 5)) { 415bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy base = "/dev/input/"; 4162542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy mkdir(base, 0755); 4172542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy } else if(!strncmp(uevent->subsystem, "mtd", 3)) { 4187ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy base = "/dev/mtd/"; 419bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy mkdir(base, 0755); 420bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy } else if(!strncmp(uevent->subsystem, "sound", 5)) { 421bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy base = "/dev/snd/"; 4228fb954263dd2f918ad339045cc6d82e346515599Romain Guy mkdir(base, 0755); 423bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy } else if(!strncmp(uevent->subsystem, "misc", 4) && 4248fb954263dd2f918ad339045cc6d82e346515599Romain Guy !strncmp(name, "log_", 4)) { 4252542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy base = "/dev/log/"; 4267ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy mkdir(base, 0755); 427bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy name += 4; 428bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy } else 4298aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy base = "/dev/"; 4308aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy } 4318fb954263dd2f918ad339045cc6d82e346515599Romain Guy 432bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy snprintf(devpath, sizeof(devpath), "%s%s", base, name); 433bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy 434bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy if(!strcmp(uevent->action, "add")) { 4357ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy make_device(devpath, block, uevent->major, uevent->minor); 436bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy return; 437eb99356a0548684a501766e6a524529ab93304c8Romain Guy } 438bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy 439bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy if(!strcmp(uevent->action, "remove")) { 4407ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy unlink(devpath); 441bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy return; 442eb99356a0548684a501766e6a524529ab93304c8Romain Guy } 443eb99356a0548684a501766e6a524529ab93304c8Romain Guy} 444eb99356a0548684a501766e6a524529ab93304c8Romain Guy 445eb99356a0548684a501766e6a524529ab93304c8Romain Guystatic int load_firmware(int fw_fd, int loading_fd, int data_fd) 446eb99356a0548684a501766e6a524529ab93304c8Romain Guy{ 447eb99356a0548684a501766e6a524529ab93304c8Romain Guy struct stat st; 4488b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy long len_to_copy; 4498b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy int ret = 0; 4508b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy 4512542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy if(fstat(fw_fd, &st) < 0) 452746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy return -1; 4538fb954263dd2f918ad339045cc6d82e346515599Romain Guy len_to_copy = st.st_size; 4542542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy 4555ec9924d24495822b589f1a17996655d66273b30Romain Guy write(loading_fd, "1", 1); /* start transfer */ 4565ec9924d24495822b589f1a17996655d66273b30Romain Guy 4575ec9924d24495822b589f1a17996655d66273b30Romain Guy while (len_to_copy > 0) { 4585ec9924d24495822b589f1a17996655d66273b30Romain Guy char buf[PAGE_SIZE]; 4592542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy ssize_t nr; 460d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy 4615cbbce535744b89df5ecea95de21ee3733298260Romain Guy nr = read(fw_fd, buf, sizeof(buf)); 462f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy if(!nr) 463bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy break; 464bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy if(nr < 0) { 465bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy ret = -1; 466bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy break; 4675c13d89c1332fcc499379b9064b891187b75ca32Chet Haase } 468eb99356a0548684a501766e6a524529ab93304c8Romain Guy 469eb99356a0548684a501766e6a524529ab93304c8Romain Guy len_to_copy -= nr; 470d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy while (nr > 0) { 471af636ebf5feb2837683fbfe965040cb706b32ec1Romain Guy ssize_t nw = 0; 472e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy 473e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy nw = write(data_fd, buf + nw, nr); 474e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy if(nw <= 0) { 475e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy ret = -1; 476e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy goto out; 477710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik } 478a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy nr -= nw; 479e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy } 480d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy } 481d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy 482d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haaseout: 483dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy if(!ret) 484d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy write(loading_fd, "0", 1); /* successful end of transfer */ 485d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy else 486bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy write(loading_fd, "-1", 2); /* abort transfer */ 487bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy 488bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy return ret; 489bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy} 490f877308f77f7c6f3edd91618a092207dd3be9077Romain Guy 4918aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guystatic void process_firmware_event(struct uevent *uevent) 4928b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy{ 4938aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy char *root, *loading, *data, *file; 4948aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy int l, loading_fd, data_fd, fw_fd; 4958aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy 4968b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy log_event_print("firmware event { '%s', '%s' }\n", 497d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy uevent->path, uevent->firmware); 498bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy 4991c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path); 5001c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy if (l == -1) 5011c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy return; 5021c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy 5031c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy l = asprintf(&loading, "%sloading", root); 5041c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy if (l == -1) 5051c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy goto root_free_out; 5061c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy 5071c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy l = asprintf(&data, "%sdata", root); 5081c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy if (l == -1) 5091c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy goto loading_free_out; 5101c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy 5111c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy l = asprintf(&file, FIRMWARE_DIR"/%s", uevent->firmware); 5121c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy if (l == -1) 5131c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy goto data_free_out; 5141c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy 5151c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy loading_fd = open(loading, O_WRONLY); 5166b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy if(loading_fd < 0) 5176b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy goto file_free_out; 5186b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy 5196b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy data_fd = open(data, O_WRONLY); 5201c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy if(data_fd < 0) 5211c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy goto loading_close_out; 5221c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy 5231c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy fw_fd = open(file, O_RDONLY); 52487a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy if(fw_fd < 0) 5251c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy goto data_close_out; 5261c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy 5271c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy if(!load_firmware(fw_fd, loading_fd, data_fd)) 5281c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy log_event_print("firmware copy success { '%s', '%s' }\n", root, file); 5291c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy else 5301c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy log_event_print("firmware copy failure { '%s', '%s' }\n", root, file); 5311c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy 5321c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy close(fw_fd); 5331c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guydata_close_out: 5341c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy close(data_fd); 5351c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guyloading_close_out: 5361c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy close(loading_fd); 5371c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guyfile_free_out: 5381c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy free(file); 5391c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guydata_free_out: 5401c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy free(data); 5411c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guyloading_free_out: 5421c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy free(loading); 5431c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guyroot_free_out: 54487a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy free(root); 54587a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy} 54687a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy 54787a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guystatic void handle_firmware_event(struct uevent *uevent) 54887a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy{ 5491c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy pid_t pid; 550d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 551d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase if(strcmp(uevent->subsystem, "firmware")) 552eb99356a0548684a501766e6a524529ab93304c8Romain Guy return; 553fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy 554dda570201ac851dd85af3861f7e575721d3345daRomain Guy if(strcmp(uevent->action, "add")) 555eb99356a0548684a501766e6a524529ab93304c8Romain Guy return; 556eb99356a0548684a501766e6a524529ab93304c8Romain Guy 557f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy /* we fork, to avoid making large memory allocations in init proper */ 558d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase pid = fork(); 5598aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy if (!pid) { 560d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase process_firmware_event(uevent); 561d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase exit(EXIT_SUCCESS); 562d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase } 563d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase} 564d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 565d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase#define UEVENT_MSG_LEN 1024 566d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haasevoid handle_device_fd(int fd) 567d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase{ 568d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase char msg[UEVENT_MSG_LEN+2]; 569d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase int n; 570d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 571d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) { 572ad37cd3b5d3de9dd0858af04fbccd102e8ff4b0eRomain Guy struct uevent uevent; 573d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 574d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase if(n == UEVENT_MSG_LEN) /* overflow -- discard */ 575d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase continue; 576d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 577d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase msg[n] = '\0'; 578d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase msg[n+1] = '\0'; 579d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 580d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase parse_event(msg, &uevent); 581d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 582d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase handle_device_event(&uevent); 583d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase handle_firmware_event(&uevent); 584d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase } 585ad37cd3b5d3de9dd0858af04fbccd102e8ff4b0eRomain Guy} 586d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 587d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase/* Coldboot walks parts of the /sys tree and pokes the uevent files 588eb99356a0548684a501766e6a524529ab93304c8Romain Guy** to cause the kernel to regenerate device add events that happened 589bf434114cbf55b216fdc76fc8d65a75e84c9dab5Romain Guy** before init's device manager was started 590746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy** 591d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase** We drain any pending events from the netlink socket every time 592d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase** we poke another uevent file to make sure we don't overrun the 593d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase** socket's buffer. 594dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy*/ 595d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 596dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guystatic void do_coldboot(int event_fd, DIR *d) 597dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy{ 598dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy struct dirent *de; 599d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase int dfd, fd; 600b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy 601b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy dfd = dirfd(d); 602dda570201ac851dd85af3861f7e575721d3345daRomain Guy 603a1d3c91afbd52c7e8b01f4a9060c5459f02ae7a5Romain Guy fd = openat(dfd, "uevent", O_WRONLY); 6048550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy if(fd >= 0) { 605f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy write(fd, "add\n", 4); 606f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy close(fd); 607bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy handle_device_fd(event_fd); 608bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy } 6099ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy 6108aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy while((de = readdir(d))) { 6119ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy DIR *d2; 6129ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy 6139ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy if(de->d_type != DT_DIR || de->d_name[0] == '.') 614a23eed808a1ae4ec0d818c0a9238385e797fd056Chet Haase continue; 615dda570201ac851dd85af3861f7e575721d3345daRomain Guy 6168fb954263dd2f918ad339045cc6d82e346515599Romain Guy fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); 617d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase if(fd < 0) 618d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase continue; 6191d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy 620eb99356a0548684a501766e6a524529ab93304c8Romain Guy d2 = fdopendir(fd); 621d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase if(d2 == 0) 622eb99356a0548684a501766e6a524529ab93304c8Romain Guy close(fd); 623eb99356a0548684a501766e6a524529ab93304c8Romain Guy else { 6249ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy do_coldboot(event_fd, d2); 625514fb18827186591d66973c2362c859b64b63556Romain Guy closedir(d2); 6269ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy } 6279ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy } 628d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase} 6299ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy 6309ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guystatic void coldboot(int event_fd, const char *path) 631514fb18827186591d66973c2362c859b64b63556Romain Guy{ 632514fb18827186591d66973c2362c859b64b63556Romain Guy DIR *d = opendir(path); 633d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase if(d) { 634514fb18827186591d66973c2362c859b64b63556Romain Guy do_coldboot(event_fd, d); 6357b5b6abf852c039983eded25ebe43a70fef5a4abRomain Guy closedir(d); 63654be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy } 63754be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy} 638ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy 639eb99356a0548684a501766e6a524529ab93304c8Romain Guyint device_init(void) 640f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy{ 641d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy suseconds_t t0, t1; 642bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy int fd; 643bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy 644d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase fd = open_uevent_socket(); 6459ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy if(fd < 0) 6465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return -1; 647d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 648d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase fcntl(fd, F_SETFD, FD_CLOEXEC); 649d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase fcntl(fd, F_SETFL, O_NONBLOCK); 650d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 651d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase t0 = get_usecs(); 652d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase coldboot(fd, "/sys/class"); 653d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase coldboot(fd, "/sys/block"); 654d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase coldboot(fd, "/sys/devices"); 655d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase t1 = get_usecs(); 656d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase 657d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase log_event_print("coldboot %ld uS\n", ((long) (t1 - t0))); 6585b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 6592b7028eabac80cec170572bc0e945a1d4224e595Romain Guy return fd; 6605b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy} 6619ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy