openDeviceLocked

转自http://blog.csdn.net/coldsnow33/article/details/16846105

识别和匹配idc配置文件

按键映射

  1. status_t EventHub::openDeviceLocked(const char *devicePath) {  
  2.     char buffer[80];  
  3.   
  4.     ALOGV("Opening device: %s", devicePath);  
  5.   
  6.     int fd = open(devicePath, O_RDWR | O_CLOEXEC);/*open()系统调用返回文件描述符,O_RDWR是指以读写方式打开,O_CLOEXEC的作用是百度来的。Linux中,文件描述符有一个属性:CLOEXEC,即当调用exec()函数成功后,文件描述符会自动关闭。在以往的内核版本(2.6.23以前)中,需要调用 fcntl(fd, F_SETFD, FD_CLOEXEC)来设置这个属性。而新版本(2.6.23开始)中,可以在调用open函数的时候,通过 flags 参数设置CLOEXEC 功能,如open(filename, O_CLOEXEC)。*/  
  7.     if(fd < 0) {  
  8.         ALOGE("could not open %s, %s\n", devicePath, strerror(errno));  
  9.         return -1;  
  10.     }  
  11.   
  12.   InputDeviceIdentifier identifier;//input设备标识符  
  13.   struct InputDeviceIdentifier {  
  14.       inline InputDeviceIdentifier() :  
  15.               bus(0), vendor(0), product(0), version(0) {  
  16.       }  
  17.     
  18.       // Information provided by the kernel.  
  19.       String8 name;  
  20.       String8 location;  
  21.       String8 uniqueId;//唯一的ID  
  22.       uint16_t bus;  
  23.       uint16_t vendor;  
  24.       uint16_t product;  
  25.       uint16_t version;  
  26.     
  27.       // A composite input device descriptor string that uniquely identifies the device  
  28.       // even across reboots or reconnections.  The value of this field is used by  
  29.       // upper layers of the input system to associate settings with individual devices.  
  30.       // It is hashed from whatever kernel provided information is available.  
  31.       // Ideally, the way this value is computed should not change between Android releases  
  32.       // because that would invalidate persistent settings that rely on it.  
  33.       String8 descriptor;  
  34.   };  
  35.   
  36.     // Get device name.  
  37.   if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {//input_dev的name,”ft5x06”  
  38.         //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));  
  39.     } else {  
  40.         buffer[sizeof(buffer) - 1] = '\0';  
  41.         identifier.name.setTo(buffer);  
  42.     }  
  43.   
  44.   // Check to see if the device is on our excluded list  
  45.   //检查是不是要排除的device,一般都不是  
  46.     for (size_t i = 0; i < mExcludedDevices.size(); i++) {  
  47.         const String8& item = mExcludedDevices.itemAt(i);  
  48.         if (identifier.name == item) {  
  49.             ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());  
  50.             close(fd);  
  51.             return -1;  
  52.         }  
  53.     }  
  54.   
  55.     // Get device driver version.  
  56.     int driverVersion;  
  57.     if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {// 得到EV_VERSION 0x010001  
  58.         ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));  
  59.         close(fd);  
  60.         return -1;  
  61.     }  
  62.   
  63.     // Get device identifier.  
  64.     struct input_id inputId;  
  65.     if(ioctl(fd, EVIOCGID, &inputId)) {//返回struct input_id  
  66.         ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));  
  67.         close(fd);  
  68.         return -1;  
  69.     }  
  70.     identifier.bus = inputId.bustype;  
  71.     identifier.product = inputId.product;  
  72.     identifier.vendor = inputId.vendor;  
  73.     identifier.version = inputId.version;  
  74.   
  75.     // Get device physical location.  
  76.     if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {//物理位置,字符串  
  77.         //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));  
  78.     } else {  
  79.         buffer[sizeof(buffer) - 1] = '\0';  
  80.         identifier.location.setTo(buffer);  
  81.     }  
  82.   
  83.     // Get device unique id.  
  84.     if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {//唯一ID,字符串  
  85.         //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));  
  86.     } else {  
  87.         buffer[sizeof(buffer) - 1] = '\0';  
  88.         identifier.uniqueId.setTo(buffer);  
  89.     }  
  90.   
  91.     // Fill in the descriptor.  
  92.     setDescriptor(identifier);//设置identifier.descriptor  
  93.   
  94.     // Make file descriptor non-blocking for use with poll().  
  95.     if (fcntl(fd, F_SETFL, O_NONBLOCK)) {//设置fd非阻塞  
  96.         ALOGE("Error %d making device file descriptor non-blocking.", errno);  
  97.         close(fd);  
  98.         return -1;  
  99.     }  
  100.   
  101.     // Allocate device.  (The device object takes ownership of the fd at this point.)  
  102.     int32_t deviceId = mNextDeviceId++;//deviceId=1,mNextDeviceId=2  
  103.     Device* device = new Device(fd, deviceId, String8(devicePath), identifier);//一个input device  
  104.   
  105.     ALOGV("add device %d: %s\n", deviceId, devicePath);  
  106.     ALOGV("  bus:        %04x\n"  
  107.          "  vendor      %04x\n"  
  108.          "  product     %04x\n"  
  109.          "  version     %04x\n",  
  110.         identifier.bus, identifier.vendor, identifier.product, identifier.version);  
  111.     ALOGV("  name:       \"%s\"\n", identifier.name.string());  
  112.     ALOGV("  location:   \"%s\"\n", identifier.location.string());  
  113.     ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.string());  
  114.     ALOGV("  descriptor: \"%s\"\n", identifier.descriptor.string());  
  115.     ALOGV("  driver:     v%d.%d.%d\n",  
  116.         driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);  
  117.   
  118.     // Load the configuration file for the device.  
  119.     loadConfigurationLocked(device);  
  120.   /*获取输入设备配置文件,有几个路径,依次找,找到为止 
  121.   // Figure out the kinds of events the device reports. 
  122. /*使用EVIOCGBIT ioctl可以获取设备的能力和特性。它告知你设备是否有key或者button。EVIOCGBIT ioctl处理4个参数( ioctl(fd, EVIOCGBIT(ev_type, max_bytes), bitfield))。 ev_type是返回的 type feature( 0是个特殊 case,表示返回设备支持的所有的 type features)。 max_bytes表示返回的最大字节数。bitfield域是指向保存结果的内存指针。return value表示保存结果的实际字节数,如果调用失败,则返回负值。*/  
  123.     ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);  
  124.     ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);  
  125.     ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);  
  126.     ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);  
  127.     ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);  
  128.     ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);  
  129.     ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);  
  130.   
  131.     // See if this is a keyboard.  Ignore everything in the button range except for  
  132.   // joystick and gamepad buttons which are handled like keyboards for the most part.  
  133.   /*如果是键盘,除了操纵杆和大部分像键盘一样处理的游戏手柄按钮之外,可以忽略所以的按钮范围*/  
  134.     bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))  
  135.             || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),  
  136.                     sizeof_bit_array(KEY_MAX + 1));  
  137. /* 
  138. haveKeyboardKeys:上报0~BTN_MISC(100)-1或KEY_OK(160)~KEY_MAX(0x2ff)之间的type。 
  139. haveGamepadButtons:上报BTN_MISC~BTN_MOUSE(0x110)-1或BTN_JOYSTICK(0x120)~BTN_DIGI(0x140)的type。 
  140. */  
  141.     bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),  
  142.                     sizeof_bit_array(BTN_MOUSE))  
  143.             || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),  
  144.                     sizeof_bit_array(BTN_DIGI));  
  145.     if (haveKeyboardKeys || haveGamepadButtons) {  
  146.         device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;/*input外设是一个键盘或者按钮*/  
  147.     }  
  148.   
  149.     // See if this is a cursor device such as a trackball or mouse.  
  150.     if (test_bit(BTN_MOUSE, device->keyBitmask)  
  151.             && test_bit(REL_X, device->relBitmask)  
  152.             && test_bit(REL_Y, device->relBitmask)) {  
  153.         device->classes |= INPUT_DEVICE_CLASS_CURSOR;//是一个光标,比如轨迹球或鼠标  
  154.     }  
  155.   
  156.     // See if this is a touch pad.  
  157.     // Is this a new modern multi-touch driver?  
  158.     if (test_bit(ABS_MT_POSITION_X, device->absBitmask)  
  159.             && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {  
  160.         // Some joysticks such as the PS3 controller report axes that conflict  
  161.         // with the ABS_MT range.  Try to confirm that the device really is  
  162.         // a touch screen.  
  163.         if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {  
  164.             device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;  
  165.         }  
  166.     // Is this an old style single-touch driver?  
  167.     } else if (test_bit(BTN_TOUCH, device->keyBitmask)  
  168.             && test_bit(ABS_X, device->absBitmask)  
  169.             && test_bit(ABS_Y, device->absBitmask)) {  
  170.         device->classes |= INPUT_DEVICE_CLASS_TOUCH;  
  171.     }  
  172. /* 
  173. (1) 如果是一个touch pad(不透明的触摸板),还要看它是不是现代的多点触摸driver,所以要看一下有没有report ABS_MT_POSITION_X和ABS_MT_POSITION_Y;多点协议要求的。 
  174. (2) 如果是多点上报协议,还要看下是不是操纵杆。比如PS3控制器也会上报坐标轴,这与多点上报 ABS_MT范围是冲突的,所以还要确认一下这个外设确实是触摸屏。怎么看呢?如果上报了BTN_TOUCH那就是touch,如果没有上报BTN_TOUCH,也不是游戏手柄按钮,那也是touch。device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT。 
  175. (3) 如果是老式的单点上报,device->classes |= INPUT_DEVICE_CLASS_TOUCH。 
  176. */  
  177.     // See if this device is a joystick.  
  178.     // Assumes that joysticks always have gamepad buttons in order to distinguish them  
  179.   // from other devices such as accelerometers that also have absolute axes.  
  180.   //如果这个外设是一个操纵杆。假设它总是有游戏手柄按钮,为了与同样上报绝对坐标的其他外设,比如感应器区分开来,还需要设置INPUT_DEVICE_CLASS_JOYSTICK。  
  181.     if (haveGamepadButtons) {  
  182.         uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;  
  183.         for (int i = 0; i <= ABS_MAX; i++) {  
  184.             if (test_bit(i, device->absBitmask)  
  185.                     && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {  
  186.                 device->classes = assumedClasses;  
  187.                 break;  
  188.             }  
  189.         }  
  190.     }  
  191.   
  192.     // Check whether this device has switches.开关  
  193.     for (int i = 0; i <= SW_MAX; i++) {  
  194.         if (test_bit(i, device->swBitmask)) {  
  195.             device->classes |= INPUT_DEVICE_CLASS_SWITCH;  
  196.             break;  
  197.         }  
  198.     }  
  199.   
  200.     // Check whether this device supports the vibrator.振荡器  
  201.     if (test_bit(FF_RUMBLE, device->ffBitmask)) {  
  202.         device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;  
  203.     }  
  204.   
  205.     // Configure virtual keys.  
  206.     if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {  
  207.         // Load the virtual keys for the touch screen, if any.  
  208.         // We do this now so that we can make sure to load the keymap if necessary.  
  209. /*如果有的话,为触摸屏load虚拟按键。我们现在这样做,所以可以确保load键映射,如果需要的话。一般虚拟按键都是利用触摸屏的边缘坐标模拟的按键。配置文件名就是/sys/board_properties/virtualkeys.{devicename},格式为:0x1:扫描码:X:Y:W:H:0x1: ……例如: 
  210. 0x01:158:55:835:90:55:0x01:139:172:835:125:55:0x01:102:298:835:115:55:0x01:217:412:835:95:55。如果定义了这个配置文件就可以自动把RawInputEvent(原始输入事件)转换为KeyEvent(按键事件)。base/core/java/android/view/inputDevice.java负责处理虚拟按键。要实现虚拟按键还可以在driver中用input_event发送按键消息,往往是这种方式较为常用,尤其是需要校准的电阻屏。 
  211. 注意:使用虚拟按键转换成为的是按键的扫描码,不是按键码,因此依然需要经过按键布局文件的转化才能得到按键码。我们driver中所用的也是扫描码,例如:KEY_MENU、KEY_BACK。 
  212. */  
  213.         status_t status = loadVirtualKeyMapLocked(device);//load虚拟按键配置文件  
  214.         if (!status) {  
  215.             device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;//支持键盘  
  216.         }  
  217.     }  
  218.   
  219.     // Load the key map.  
  220.   // We need to do this for joysticks too because the key layout may specify axes.  
  221.   //Load按键映射,我们还需要为操纵杆做这个是因为键盘布局可能是一个指定轴。  
  222.     status_t keyMapStatus = NAME_NOT_FOUND;  
  223.     if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {  
  224.         // Load the keymap for the device.先找*.kl,再找*.kcm,查找顺序同  
  225.         keyMapStatus = loadKeyMapLocked(device);  
  226.     }  
  227.   
  228.     // Configure the keyboard, gamepad or virtual keyboard.  
  229.     if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {  
  230.         // Register the keyboard as a built-in keyboard if it is eligible.  
  231. //如果有资格注册一个键盘作为嵌入键盘,什么是有资格,就是if的条件了  
  232.         if (!keyMapStatus//上一节load keymap失败了  
  233.                 && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD(构造函数是这样初始化的)  
  234.                 && isEligibleBuiltInKeyboard(device->identifier,  
  235.                         device->configuration, &device->keyMap)) {  
  236.             mBuiltInKeyboardId = device->id;  
  237.         }  
  238. /*isEligibleBuiltInKeyboard()成立的条件是: 
  239. (1) *.kcm有,type不是SPECIAL_FUNCTION。 
  240. (2) 如果idc文件中设置了keyboard.builtIn = true,那(1)+(2)条件成立。 
  241. (3) 如果input device的name中含有"-keypad",那(1)+(3)条件也成立。  
  242. */  
  243.         // 'Q' key support = cheap test of whether this is an alpha-capable kbd  
  244. //简单测试下是否有字母功能的键盘文本  
  245.         if (hasKeycodeLocked(device, AKEYCODE_Q)) {  
  246.             device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;  
  247.         }  
  248.   
  249.         // See if this device has a DPAD.//D-Pad( directional pad)方向键  
  250.         if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&  
  251.                 hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&  
  252.                 hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&  
  253.                 hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&  
  254.                 hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {  
  255.             device->classes |= INPUT_DEVICE_CLASS_DPAD;  
  256.         }  
  257.   
  258.         // See if this device has a gamepad.  
  259.         for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {  
  260.             if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {  
  261.                 device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;  
  262.                 break;  
  263.             }  
  264.         }  
  265.   
  266.         // Disable kernel key repeat since we handle it ourselves  
  267. //失能 kernel key repeat,因为我们除了它  
  268.         unsigned int repeatRate[] = {0,0};  
  269.         if (ioctl(fd, EVIOCSREP, repeatRate)) {  
  270.             ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));  
  271.         }  
  272.     }  
  273.   
  274.   // If the device isn't recognized as something we handle, don't monitor it.  
  275.   //如果device没有被识别为我们可以处理的东西,就不要监视它了  
  276.     if (device->classes == 0) {  
  277.         ALOGV("Dropping device: id=%d, path='%s', name='%s'",  
  278.                 deviceId, devicePath, device->identifier.name.string());  
  279.         delete device;  
  280.         return -1;  
  281.     }  
  282.   
  283.   // Determine whether the device is external or internal.  
  284.   //确定是内部设备还是外部设备  
  285.     if (isExternalDeviceLocked(device)) {  
  286.         device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;  
  287.     }  
  288.   (1) 如果idc配置文件中,device.internal = true,就直接是内部设备了。  
  289.   (2) 如果device.internal 没有写,要看input device的bus,如果是BUS_USB或者BUS_BLUETOOTH就是外部设备。   
  290.     // Register with epoll.  
  291.     struct epoll_event eventItem;  
  292.     memset(&eventItem, 0, sizeof(eventItem));  
  293.     eventItem.events = EPOLLIN;  
  294.     eventItem.data.u32 = deviceId;  
  295.     if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {  
  296.         ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);  
  297.         delete device;  
  298.         return -1;  
  299.     }  
  300. /*又添加了一个epoll事件,这次是要查询/dev/input/eventx是否可读。 
  301. */  
  302.     // Enable wake-lock behavior on kernels that support it.  
  303.     // TODO: Only need this for devices that can really wake the system.  
  304.     bool usingSuspendBlockIoctl;  
  305.     char value[8];  
  306.     property_get("ro.platform.has.mbxuimode", value, "false");  
  307.     if(strcmp(value, "true") == 0) {  
  308.         usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 0);//失能  
  309.     } else {  
  310.         usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1);//使能  
  311.     }  
  312. /*int property_get(const char *key, char *value, const char *default_value); 
  313. 失能时,到kernel调用evdev_disable_suspend_block()-> 
  314.   client->use_wake_lock = false; 
  315.   wake_lock_destroy(&client->wake_lock); 
  316. 使能时调用evdev_enable_suspend_block()-> 
  317.     wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name); 
  318.     client->use_wake_lock = true; 
  319.     if (client->packet_head != client->tail) 
  320. 这时候是上锁,什么时候解锁呢?循环buffer首尾相接的时候。 
  321.     if (unlikely(client->head == client->tail)) { 
  322.         if (client->use_wake_lock) 
  323.             wake_unlock(&client->wake_lock); 
  324.   } 
  325.     if (client->use_wake_lock && 
  326.         client->packet_head == client->tail) 
  327.         wake_unlock(&client->wake_lock); 
  328. */  
  329.     // Tell the kernel that we want to use the monotonic clock for reporting timestamps  
  330.     // associated with input events.  This is important because the input system  
  331.     // uses the timestamps extensively and assumes they were recorded using the monotonic  
  332.     // clock.  
  333. /*通知kernel我们想用monotonic(单调递增)时钟作为input events的报告时间戳,这是非常重要的,假设input system用monotonic时钟记录时间戳,时间戳的应用非常广泛。 
  334.     // In older kernel, before Linux 3.4, there was no way to tell the kernel which 
  335.     // clock to use to input event timestamps.  The standard kernel behavior was to 
  336.     // record a real time timestamp, which isn't what we want.  Android kernels therefore 
  337.     // contained a patch to the evdev_event() function in drivers/input/evdev.c to 
  338.     // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic 
  339.     // clock to be used instead of the real time clock. 
  340. /*在Linux 3.4之前的内核中,没有办法通知kernel用哪种时钟作为input系统的时间戳。标准内核行为是记录real(实时)时间的时间戳,这个时间并不是我们想要的。因此,android内核包含一个对drivers/input/evdev.c中evdev_event()函数的patch,用ktime_get_ts()取代 do_gettimeofday(),从而实现monotonic时钟代替real time时钟。 
  341. */    
  342.     // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.  
  343.     // Therefore, we no longer require the Android-specific kernel patch described above  
  344.   // as long as we make sure to set select the monotonic clock.  We do that here.  
  345. /*从Linux 3.4开始,出现了新的EVIOCSCLOCKID EVIOCSCLOCKID来设置期望的时钟。因此,我们不再需要android特殊的内核patch,综上所述,只有我们确定需要设置 monotonic clock,就执行下列代码。 
  346. */  
  347.     int clockId = CLOCK_MONOTONIC;  
  348.     bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);  
  349.     ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "  
  350.             "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "  
  351.             "usingSuspendBlockIoctl=%s, usingClockIoctl=%s",  
  352.          deviceId, fd, devicePath, device->identifier.name.string(),  
  353.          device->classes,  
  354.          device->configurationFile.string(),  
  355.          device->keyMap.keyLayoutFile.string(),  
  356.          device->keyMap.keyCharacterMapFile.string(),  
  357.          toString(mBuiltInKeyboardId == deviceId),  
  358.          toString(usingSuspendBlockIoctl), toString(usingClockIoctl));  
  359.   
  360.     addDeviceLocked(device);  
  361.     return 0;  
  362. }  
  363. void EventHub::addDeviceLocked(Device* device) {  
  364.     mDevices.add(device->id, device);  
  365.     device->next = mOpeningDevices;  
  366.     mOpeningDevices = device;  
  367. }  
  368. //KeyedVector.add()添加一个键值对,最后通过device->id就能找到device。  
  369. //通过mOpeningDevices可以找到我们第一open的设备,一直next下去,所以open的都找到了。  
status_t EventHub::openDeviceLocked(const char *devicePath) {
    char buffer[80];

    ALOGV("Opening device: %s", devicePath);

    int fd = open(devicePath, O_RDWR | O_CLOEXEC);/*open()系统调用返回文件描述符,O_RDWR是指以读写方式打开,O_CLOEXEC的作用是百度来的。Linux中,文件描述符有一个属性:CLOEXEC,即当调用exec()函数成功后,文件描述符会自动关闭。在以往的内核版本(2.6.23以前)中,需要调用 fcntl(fd, F_SETFD, FD_CLOEXEC)来设置这个属性。而新版本(2.6.23开始)中,可以在调用open函数的时候,通过 flags 参数设置CLOEXEC 功能,如open(filename, O_CLOEXEC)。*/
    if(fd < 0) {
        ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
        return -1;
    }

  InputDeviceIdentifier identifier;//input设备标识符
  struct InputDeviceIdentifier {
      inline InputDeviceIdentifier() :
              bus(0), vendor(0), product(0), version(0) {
      }
  
      // Information provided by the kernel.
      String8 name;
      String8 location;
      String8 uniqueId;//唯一的ID
      uint16_t bus;
      uint16_t vendor;
      uint16_t product;
      uint16_t version;
  
      // A composite input device descriptor string that uniquely identifies the device
      // even across reboots or reconnections.  The value of this field is used by
      // upper layers of the input system to associate settings with individual devices.
      // It is hashed from whatever kernel provided information is available.
      // Ideally, the way this value is computed should not change between Android releases
      // because that would invalidate persistent settings that rely on it.
      String8 descriptor;
  };

    // Get device name.
  if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {//input_dev的name,”ft5x06”
        //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.name.setTo(buffer);
    }

  // Check to see if the device is on our excluded list
  //检查是不是要排除的device,一般都不是
    for (size_t i = 0; i < mExcludedDevices.size(); i++) {
        const String8& item = mExcludedDevices.itemAt(i);
        if (identifier.name == item) {
            ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());
            close(fd);
            return -1;
        }
    }

    // Get device driver version.
    int driverVersion;
    if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {// 得到EV_VERSION 0x010001
        ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
        close(fd);
        return -1;
    }

    // Get device identifier.
    struct input_id inputId;
    if(ioctl(fd, EVIOCGID, &inputId)) {//返回struct input_id
        ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
        close(fd);
        return -1;
    }
    identifier.bus = inputId.bustype;
    identifier.product = inputId.product;
    identifier.vendor = inputId.vendor;
    identifier.version = inputId.version;

    // Get device physical location.
    if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {//物理位置,字符串
        //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.location.setTo(buffer);
    }

    // Get device unique id.
    if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {//唯一ID,字符串
        //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.uniqueId.setTo(buffer);
    }

    // Fill in the descriptor.
    setDescriptor(identifier);//设置identifier.descriptor

    // Make file descriptor non-blocking for use with poll().
    if (fcntl(fd, F_SETFL, O_NONBLOCK)) {//设置fd非阻塞
        ALOGE("Error %d making device file descriptor non-blocking.", errno);
        close(fd);
        return -1;
    }

    // Allocate device.  (The device object takes ownership of the fd at this point.)
    int32_t deviceId = mNextDeviceId++;//deviceId=1,mNextDeviceId=2
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);//一个input device

    ALOGV("add device %d: %s\n", deviceId, devicePath);
    ALOGV("  bus:        %04x\n"
         "  vendor      %04x\n"
         "  product     %04x\n"
         "  version     %04x\n",
        identifier.bus, identifier.vendor, identifier.product, identifier.version);
    ALOGV("  name:       \"%s\"\n", identifier.name.string());
    ALOGV("  location:   \"%s\"\n", identifier.location.string());
    ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.string());
    ALOGV("  descriptor: \"%s\"\n", identifier.descriptor.string());
    ALOGV("  driver:     v%d.%d.%d\n",
        driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);

    // Load the configuration file for the device.
    loadConfigurationLocked(device);
  /*获取输入设备配置文件,有几个路径,依次找,找到为止
  // Figure out the kinds of events the device reports.
/*使用EVIOCGBIT ioctl可以获取设备的能力和特性。它告知你设备是否有key或者button。EVIOCGBIT ioctl处理4个参数( ioctl(fd, EVIOCGBIT(ev_type, max_bytes), bitfield))。 ev_type是返回的 type feature( 0是个特殊 case,表示返回设备支持的所有的 type features)。 max_bytes表示返回的最大字节数。bitfield域是指向保存结果的内存指针。return value表示保存结果的实际字节数,如果调用失败,则返回负值。*/
    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
    ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
    ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
    ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
    ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);

    // See if this is a keyboard.  Ignore everything in the button range except for
  // joystick and gamepad buttons which are handled like keyboards for the most part.
  /*如果是键盘,除了操纵杆和大部分像键盘一样处理的游戏手柄按钮之外,可以忽略所以的按钮范围*/
    bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))
            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
                    sizeof_bit_array(KEY_MAX + 1));
/*
haveKeyboardKeys:上报0~BTN_MISC(100)-1或KEY_OK(160)~KEY_MAX(0x2ff)之间的type。
haveGamepadButtons:上报BTN_MISC~BTN_MOUSE(0x110)-1或BTN_JOYSTICK(0x120)~BTN_DIGI(0x140)的type。
*/
    bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
                    sizeof_bit_array(BTN_MOUSE))
            || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
                    sizeof_bit_array(BTN_DIGI));
    if (haveKeyboardKeys || haveGamepadButtons) {
        device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;/*input外设是一个键盘或者按钮*/
    }

    // See if this is a cursor device such as a trackball or mouse.
    if (test_bit(BTN_MOUSE, device->keyBitmask)
            && test_bit(REL_X, device->relBitmask)
            && test_bit(REL_Y, device->relBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_CURSOR;//是一个光标,比如轨迹球或鼠标
    }

    // See if this is a touch pad.
    // Is this a new modern multi-touch driver?
    if (test_bit(ABS_MT_POSITION_X, device->absBitmask)
            && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
        // Some joysticks such as the PS3 controller report axes that conflict
        // with the ABS_MT range.  Try to confirm that the device really is
        // a touch screen.
        if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
            device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
        }
    // Is this an old style single-touch driver?
    } else if (test_bit(BTN_TOUCH, device->keyBitmask)
            && test_bit(ABS_X, device->absBitmask)
            && test_bit(ABS_Y, device->absBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_TOUCH;
    }
/*
(1) 如果是一个touch pad(不透明的触摸板),还要看它是不是现代的多点触摸driver,所以要看一下有没有report ABS_MT_POSITION_X和ABS_MT_POSITION_Y;多点协议要求的。
(2) 如果是多点上报协议,还要看下是不是操纵杆。比如PS3控制器也会上报坐标轴,这与多点上报 ABS_MT范围是冲突的,所以还要确认一下这个外设确实是触摸屏。怎么看呢?如果上报了BTN_TOUCH那就是touch,如果没有上报BTN_TOUCH,也不是游戏手柄按钮,那也是touch。device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT。
(3) 如果是老式的单点上报,device->classes |= INPUT_DEVICE_CLASS_TOUCH。
*/
    // See if this device is a joystick.
    // Assumes that joysticks always have gamepad buttons in order to distinguish them
  // from other devices such as accelerometers that also have absolute axes.
  //如果这个外设是一个操纵杆。假设它总是有游戏手柄按钮,为了与同样上报绝对坐标的其他外设,比如感应器区分开来,还需要设置INPUT_DEVICE_CLASS_JOYSTICK。
    if (haveGamepadButtons) {
        uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
        for (int i = 0; i <= ABS_MAX; i++) {
            if (test_bit(i, device->absBitmask)
                    && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
                device->classes = assumedClasses;
                break;
            }
        }
    }

    // Check whether this device has switches.开关
    for (int i = 0; i <= SW_MAX; i++) {
        if (test_bit(i, device->swBitmask)) {
            device->classes |= INPUT_DEVICE_CLASS_SWITCH;
            break;
        }
    }

    // Check whether this device supports the vibrator.振荡器
    if (test_bit(FF_RUMBLE, device->ffBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
    }

    // Configure virtual keys.
    if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
        // Load the virtual keys for the touch screen, if any.
        // We do this now so that we can make sure to load the keymap if necessary.
/*如果有的话,为触摸屏load虚拟按键。我们现在这样做,所以可以确保load键映射,如果需要的话。一般虚拟按键都是利用触摸屏的边缘坐标模拟的按键。配置文件名就是/sys/board_properties/virtualkeys.{devicename},格式为:0x1:扫描码:X:Y:W:H:0x1: ……例如:
0x01:158:55:835:90:55:0x01:139:172:835:125:55:0x01:102:298:835:115:55:0x01:217:412:835:95:55。如果定义了这个配置文件就可以自动把RawInputEvent(原始输入事件)转换为KeyEvent(按键事件)。base/core/java/android/view/inputDevice.java负责处理虚拟按键。要实现虚拟按键还可以在driver中用input_event发送按键消息,往往是这种方式较为常用,尤其是需要校准的电阻屏。
注意:使用虚拟按键转换成为的是按键的扫描码,不是按键码,因此依然需要经过按键布局文件的转化才能得到按键码。我们driver中所用的也是扫描码,例如:KEY_MENU、KEY_BACK。
*/
        status_t status = loadVirtualKeyMapLocked(device);//load虚拟按键配置文件
        if (!status) {
            device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;//支持键盘
        }
    }

    // Load the key map.
  // We need to do this for joysticks too because the key layout may specify axes.
  //Load按键映射,我们还需要为操纵杆做这个是因为键盘布局可能是一个指定轴。
    status_t keyMapStatus = NAME_NOT_FOUND;
    if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
        // Load the keymap for the device.先找*.kl,再找*.kcm,查找顺序同
        keyMapStatus = loadKeyMapLocked(device);
    }

    // Configure the keyboard, gamepad or virtual keyboard.
    if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
        // Register the keyboard as a built-in keyboard if it is eligible.
//如果有资格注册一个键盘作为嵌入键盘,什么是有资格,就是if的条件了
        if (!keyMapStatus//上一节load keymap失败了
                && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD(构造函数是这样初始化的)
                && isEligibleBuiltInKeyboard(device->identifier,
                        device->configuration, &device->keyMap)) {
            mBuiltInKeyboardId = device->id;
        }
/*isEligibleBuiltInKeyboard()成立的条件是:
(1) *.kcm有,type不是SPECIAL_FUNCTION。
(2) 如果idc文件中设置了keyboard.builtIn = true,那(1)+(2)条件成立。
(3) 如果input device的name中含有"-keypad",那(1)+(3)条件也成立。 
*/
        // 'Q' key support = cheap test of whether this is an alpha-capable kbd
//简单测试下是否有字母功能的键盘文本
        if (hasKeycodeLocked(device, AKEYCODE_Q)) {
            device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
        }

        // See if this device has a DPAD.//D-Pad( directional pad)方向键
        if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
                hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
                hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
                hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
                hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
            device->classes |= INPUT_DEVICE_CLASS_DPAD;
        }

        // See if this device has a gamepad.
        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
            if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
                device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
                break;
            }
        }

        // Disable kernel key repeat since we handle it ourselves
//失能 kernel key repeat,因为我们除了它
        unsigned int repeatRate[] = {0,0};
        if (ioctl(fd, EVIOCSREP, repeatRate)) {
            ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));
        }
    }

  // If the device isn't recognized as something we handle, don't monitor it.
  //如果device没有被识别为我们可以处理的东西,就不要监视它了
    if (device->classes == 0) {
        ALOGV("Dropping device: id=%d, path='%s', name='%s'",
                deviceId, devicePath, device->identifier.name.string());
        delete device;
        return -1;
    }

  // Determine whether the device is external or internal.
  //确定是内部设备还是外部设备
    if (isExternalDeviceLocked(device)) {
        device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
    }
  (1) 如果idc配置文件中,device.internal = true,就直接是内部设备了。
  (2) 如果device.internal 没有写,要看input device的bus,如果是BUS_USB或者BUS_BLUETOOTH就是外部设备。 
    // Register with epoll.
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = deviceId;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
        delete device;
        return -1;
    }
/*又添加了一个epoll事件,这次是要查询/dev/input/eventx是否可读。
*/
    // Enable wake-lock behavior on kernels that support it.
    // TODO: Only need this for devices that can really wake the system.
    bool usingSuspendBlockIoctl;
    char value[8];
    property_get("ro.platform.has.mbxuimode", value, "false");
    if(strcmp(value, "true") == 0) {
        usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 0);//失能
    } else {
        usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1);//使能
    }
/*int property_get(const char *key, char *value, const char *default_value);
失能时,到kernel调用evdev_disable_suspend_block()->
  client->use_wake_lock = false;
  wake_lock_destroy(&client->wake_lock);
使能时调用evdev_enable_suspend_block()->
	wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
	client->use_wake_lock = true;
	if (client->packet_head != client->tail)
这时候是上锁,什么时候解锁呢?循环buffer首尾相接的时候。
	if (unlikely(client->head == client->tail)) {
		if (client->use_wake_lock)
			wake_unlock(&client->wake_lock);
  }
	if (client->use_wake_lock &&
		client->packet_head == client->tail)
		wake_unlock(&client->wake_lock);
*/
    // Tell the kernel that we want to use the monotonic clock for reporting timestamps
    // associated with input events.  This is important because the input system
    // uses the timestamps extensively and assumes they were recorded using the monotonic
    // clock.
/*通知kernel我们想用monotonic(单调递增)时钟作为input events的报告时间戳,这是非常重要的,假设input system用monotonic时钟记录时间戳,时间戳的应用非常广泛。
    // In older kernel, before Linux 3.4, there was no way to tell the kernel which
    // clock to use to input event timestamps.  The standard kernel behavior was to
    // record a real time timestamp, which isn't what we want.  Android kernels therefore
    // contained a patch to the evdev_event() function in drivers/input/evdev.c to
    // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic
    // clock to be used instead of the real time clock.
/*在Linux 3.4之前的内核中,没有办法通知kernel用哪种时钟作为input系统的时间戳。标准内核行为是记录real(实时)时间的时间戳,这个时间并不是我们想要的。因此,android内核包含一个对drivers/input/evdev.c中evdev_event()函数的patch,用ktime_get_ts()取代 do_gettimeofday(),从而实现monotonic时钟代替real time时钟。
*/  
    // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.
    // Therefore, we no longer require the Android-specific kernel patch described above
  // as long as we make sure to set select the monotonic clock.  We do that here.
/*从Linux 3.4开始,出现了新的EVIOCSCLOCKID EVIOCSCLOCKID来设置期望的时钟。因此,我们不再需要android特殊的内核patch,综上所述,只有我们确定需要设置 monotonic clock,就执行下列代码。
*/
    int clockId = CLOCK_MONOTONIC;
    bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
    ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
            "usingSuspendBlockIoctl=%s, usingClockIoctl=%s",
         deviceId, fd, devicePath, device->identifier.name.string(),
         device->classes,
         device->configurationFile.string(),
         device->keyMap.keyLayoutFile.string(),
         device->keyMap.keyCharacterMapFile.string(),
         toString(mBuiltInKeyboardId == deviceId),
         toString(usingSuspendBlockIoctl), toString(usingClockIoctl));

    addDeviceLocked(device);
    return 0;
}
void EventHub::addDeviceLocked(Device* device) {
    mDevices.add(device->id, device);
    device->next = mOpeningDevices;
    mOpeningDevices = device;
}
//KeyedVector.add()添加一个键值对,最后通过device->id就能找到device。
//通过mOpeningDevices可以找到我们第一open的设备,一直next下去,所以open的都找到了。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值