1. 程式人生 > >Android4.0 input輸入子系統詳解

Android4.0 input輸入子系統詳解

下面的文章是基於mini2440的gpio按鍵來講解input子系統。

mini2440為例,用該板的bsp檔案,進行input子系統的講解.所用的版本為android4.0.

先來看下板級支援檔案都註冊了那些資源。

下面是五個按鍵的資源:

#define KEY_POWER           116  /* SC System Power Down */

#define KEY_F1                   59

#define KEY_F2                   60

#define KEY_F3                   61

#define KEY_F5                   63

struct gpio_keys_button {

       /* Configuration parameters */

       unsigned int code;  /* input event code (KEY_*, SW_*) *///上報事件的code

int gpio;//所用的gpio引腳

int active_low;//是否低電平有效

const char *desc; //該按鍵的描述符

       unsigned int type;   /* input event type (EV_KEY, EV_SW, EV_ABS) */

       int wakeup;            /* configure the button as a wake-up source */

       int debounce_interval;    /* debounce ticks interval in msecs */

       bool can_disable;

       int value;        /* axis value for EV_ABS */

};

static struct gpio_keys_button mini2440_buttons[] = {

       {

              .gpio              = S3C2410_GPG(0),            /* K1 */

              .code             = KEY_F1,

              .desc              = "Button 1",

              .active_low     = 1,

       },

       {

              .gpio              = S3C2410_GPG(3),            /* K2 */

              .code             = KEY_F2,

              .desc              = "Button 2",

              .active_low     = 1,

       },

       {

              .gpio              = S3C2410_GPG(5),            /* K3 */

              .code             = KEY_F3,

              .desc              = "Button 3",

              .active_low     = 1,

       },

       {

              .gpio              = S3C2410_GPG(6),            /* K4 */

              .code             = KEY_POWER,

              .desc              = "Power",

              .active_low     = 1,

       },

       {

              .gpio              = S3C2410_GPG(7),            /* K5 */

              .code             = KEY_F5,

              .desc              = "Button 5",

              .active_low     = 1,

       },

};

/*下面是平臺數據的宣告*/

struct gpio_keys_platform_data {

struct gpio_keys_button *buttons;

int nbuttons;

       unsigned int poll_interval;      /* polling interval in msecs -

                                      for polling driver only */

       unsigned int rep:1;         /* enable input subsystem auto repeat */

       int (*enable)(struct device *dev);

       void (*disable)(struct device *dev);

       const char *name;         /* input device name */

};

static struct gpio_keys_platform_data mini2440_button_data = {

       .buttons   = mini2440_buttons,

       .nbuttons = ARRAY_SIZE(mini2440_buttons),

};

/*下面是平臺裝置的宣告*/

struct platform_device {

const char      * name;

int           id;

struct device   dev;

       u32         num_resources;

       struct resource       * resource;

       const struct platform_device_id    *id_entry;

       /* MFD cell pointer */

       struct mfd_cell *mfd_cell;

       /* arch specific additions */

       struct pdev_archdata     archdata;

};

static struct platform_device mini2440_button_device = {

       .name             = "gpio-keys",

       .id           = -1,

       .dev        = {

              .platform_data = &mini2440_button_data,

       }

};

static struct platform_device *mini2440_devices[] __initdata = {

       ...................

&mini2440_button_device,

       ………

};

static void __init mini2440_init(void)

{

       .............................

       platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));

       ……………

}

MACHINE_START(MINI2440, "MINI2440")

       /* Maintainer: Michel Pollet <[email protected]> */

       .boot_params  = S3C2410_SDRAM_PA + 0x100,

       .map_io          = mini2440_map_io,

       .init_machine  = mini2440_init,

       .init_irq   = s3c24xx_init_irq,

       .timer             = &s3c24xx_timer,

MACHINE_END

上面是把該設備註冊到平臺總線上。

下面看下平臺驅動的註冊:

static struct platform_driver gpio_keys_device_driver = {

       .probe            = gpio_keys_probe,

       .remove          = __devexit_p(gpio_keys_remove),

       .driver            = {

              .name      = "gpio-keys",

              .owner    = THIS_MODULE,

       }

};

static int __init gpio_keys_init(void)

{

       return platform_driver_register(&gpio_keys_device_driver);

}

module_init(gpio_keys_init);

在註冊平臺驅動時,如果成功匹配平臺裝置後,會呼叫平臺驅動的probe函式。

下面看下該驅動的probe函式。

static int __devinit gpio_keys_probe(struct platform_device *pdev)

{

       /*取出再bsp檔案註冊的平臺數據*/

       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;

       /*這裡出現了一個新的結構體,該結構體定義如下*/

/*struct gpio_keys_drvdata {

       struct input_dev *input;

       struct mutex disable_lock;

       unsigned int n_buttons;

       int (*enable)(struct device *dev);

       void (*disable)(struct device *dev);

       struct gpio_button_data data[0];

};*/

       struct gpio_keys_drvdata *ddata;

       struct device *dev = &pdev->dev;

       struct input_dev *input;

       /*分配gpio_keys_drvdata結構體記憶體*/

       ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +

                     pdata->nbuttons * sizeof(struct gpio_button_data),

                     GFP_KERNEL);

       /*分配一個input結構體,並初始化部分成員*/

       input = input_allocate_device();

       /*ddata的各個成員變數賦值*/

       ddata->input = input;

       ddata->n_buttons = pdata->nbuttons;

       mutex_init(&ddata->disable_lock);

       /*ddata裝置pdev平臺裝置的driver data*/

       platform_set_drvdata(pdev, ddata);

       /*ddata裝置input裝置的driver data*/

       input_set_drvdata(input, ddata);

       /*設定input裝置的各個成員變數*/

       input->phys = "gpio-keys/input0";

       input->dev.parent = &pdev->dev;

       input->open = gpio_keys_open;

       input->close = gpio_keys_close;

       input->id.bustype = BUS_HOST;

       input->id.vendor = 0x0001;

       input->id.product = 0x0001;

       input->id.version = 0x0100;

       /* 根據pdatarep成員值,裝置input子系統的功能*/

       if (pdata->rep)

              __set_bit(EV_REP, input->evbit);

       /*取出pdata中得資源進行賦值*/

       for (i = 0; i < pdata->nbuttons; i++) {

              struct gpio_keys_button *button = &pdata->buttons[i];

              struct gpio_button_data *bdata = &ddata->data[i];

              /*為三目運算子,相當於button->type ?: button->type:EV_KEY;*/

              unsigned int type = button->type ?: EV_KEY;

              bdata->input = input;//

              bdata->button = button;

              error = gpio_keys_setup_key(pdev, bdata, button);

if (button->wakeup)//該鍵能否作為喚醒源?

                     wakeup = 1;

              input_set_capability(input, type, button->code);

       }

       }

       error = input_register_device(input);

       /* get current state of buttons */

       for (i = 0; i < pdata->nbuttons; i++)

              gpio_keys_report_event(&ddata->data[i]);

       input_sync(input);

       device_init_wakeup(&pdev->dev, wakeup);

       return 0;

}

下面逐步分解上面標成粉色的函式。

第一個分配一個input dev並進行初始化

struct input_dev *input_allocate_device(void)

{

       struct input_dev *dev;

       dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);

       if (dev) {

dev->dev.type = &input_dev_type;

dev->dev.class = &input_class;

              device_initialize(&dev->dev);

              mutex_init(&dev->mutex);

              spin_lock_init(&dev->event_lock);

              INIT_LIST_HEAD(&dev->h_list);

              INIT_LIST_HEAD(&dev->node);

       }

       return dev;

}

分析第二個:

static int __devinit gpio_keys_setup_key(struct platform_device *pdev,

                                    struct gpio_button_data *bdata,

                                    struct gpio_keys_button *button)

{

       /*取出按鍵的描述符*/

       const char *desc = button->desc ? button->desc : "gpio_keys";

       struct device *dev = &pdev->dev;

       /*設定該bdata的定時器函式*/

       setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);

       /*設定該bdatawork函式*/

       INIT_WORK(&bdata->work, gpio_keys_work_func);

       /*申請buttongpio*/

       error = gpio_request(button->gpio, desc);

       /*設定gpio的方向*/

       error = gpio_direction_input(button->gpio);

       if (button->debounce_interval) { //設定gpio的去抖間隔

              error = gpio_set_debounce(button->gpio,

                                     button->debounce_interval * 1000);

              /* use timer if gpiolib doesn't provide debounce */

              if (error < 0)

                     bdata->timer_debounce = button->debounce_interval;

       }

       irq = gpio_to_irq(button->gpio); //gpio引腳對應分配的中斷

       irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;

       if (!button->can_disable)

              irqflags |= IRQF_SHARED;

       /*註冊該irq的中斷處理函式,並設定標記*/

       error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata);

其中中斷處理函式如下:

static irqreturn_t gpio_keys_isr(int irq, void *dev_id)

{

       struct gpio_button_data *bdata = dev_id;

       struct gpio_keys_button *button = bdata->button;

       BUG_ON(irq != gpio_to_irq(button->gpio));

       if (bdata->timer_debounce)//如果有去抖間隔則修改定時器

              mod_timer(&bdata->timer,

                     jiffies + msecs_to_jiffies(bdata->timer_debounce));

       else

              schedule_work(&bdata->work);//如果沒有,直接執行work

       return IRQ_HANDLED;

}

}

如果定時器到期,則執行定時器處理函式:

static void gpio_keys_timer(unsigned long _data)

{

       struct gpio_button_data *data = (struct gpio_button_data *)_data;

       schedule_work(&data->work);//執行相應的work

}

中斷處理的結果是執行相應的work。看下work函式

static void gpio_keys_work_func(struct work_struct *work)

{

       struct gpio_button_data *bdata =

              container_of(work, struct gpio_button_data, work);

       gpio_keys_report_event(bdata);//input子系統,向上層報事件

}

第三個函式,設定該input dev的能力記錄本裝置對那些事件感興趣

void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)

{

       switch (type) {

       case EV_KEY:

              __set_bit(code, dev->keybit);//比如按鍵,應該對哪些鍵值的按鍵進行處理(對於其它按鍵不予理睬)

              break;

       __set_bit(type, dev->evbit);

}

第四個函式:向input核心註冊input裝置

int input_register_device(struct input_dev *dev)

{

       static atomic_t input_no = ATOMIC_INIT(0);

       struct input_handler *handler;

       const char *path;

       int error;

       /* Every input device generates EV_SYN/SYN_REPORT events. */

       __set_bit(EV_SYN, dev->evbit); //設定支援的能力

       /* KEY_RESERVED is not supposed to be transmitted to userspace. */

       __clear_bit(KEY_RESERVED, dev->keybit);//清除該支援的能力

       /* Make sure that bitmasks not mentioned in dev->evbit are clean. */

       input_cleanse_bitmasks(dev);//確保在dev->evbit中沒有支援的能力被清除掉

       if (!dev->hint_events_per_packet)

              dev->hint_events_per_packet = input_estimate_events_per_packet(dev);

       /*

        * If delay and period are pre-set by the driver, then autorepeating

        * is handled by the driver itself and we don't do it in input.c.

        */

       init_timer(&dev->timer);

       if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {

              dev->timer.data = (long) dev;

              dev->timer.function = input_repeat_key;

              dev->rep[REP_DELAY] = 250;

              dev->rep[REP_PERIOD] = 33;

       }

       /*設定input dev成員變數的處理函式*/

       if (!dev->getkeycode)

              dev->getkeycode = input_default_getkeycode;

       if (!dev->setkeycode)

              dev->setkeycode = input_default_setkeycode;

       /*設定該dev name*/

       dev_set_name(&dev->dev, "input%ld",

                   (unsigned long) atomic_inc_return(&input_no) - 1);

       error = device_add(&dev->dev);//把該裝置增加到裝置驅動模型中

       /*把該dev加入到input_dev_list 連結串列*/

       list_add_tail(&dev->node, &input_dev_list);

       /*遍歷input_hander_list連結串列中得hander,以便匹配input dev*/

       list_for_each_entry(handler, &input_handler_list, node)

              input_attach_handler(dev, handler);

       return 0;

}

下面看下匹配函式:

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)

{

       const struct input_device_id *id;

       id = input_match_device(handler, dev);//返回匹配成功的id

       error = handler->connect(handler, dev, id);//如果匹配成功,則呼叫handerconnect函式

       return error;

}

下面主要看下match的過程:

static const struct input_device_id *input_match_device(struct input_handler *handler,

                                                 struct input_dev *dev)

{

       const struct input_device_id *id;

       for (id = handler->id_table; id->flags || id->driver_info; id++) {

              if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)//如果是匹配bus,則比較id.bus

                     if (id->bustype != dev->id.bustype)

                            continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) //如果是匹配vender則比較id.vender

                     if (id->vendor != dev->id.vendor)

                            continue;

//如果是匹配product則比較id.product

              if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)

                     if (id->product != dev->id.product)

                            continue;

//如果是匹配versiont則比較id.version

              if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)

                     if (id->version != dev->id.version)

                            continue;

/*如果hander支援該能力,則dev也要支援,否則不匹配*/

MATCH_BIT(evbit,  EV_MAX);

              MATCH_BIT(keybit, KEY_MAX);

              MATCH_BIT(relbit, REL_MAX);

              MATCH_BIT(absbit, ABS_MAX);

              MATCH_BIT(mscbit, MSC_MAX);

              MATCH_BIT(ledbit, LED_MAX);

              MATCH_BIT(sndbit, SND_MAX);

              MATCH_BIT(ffbit,  FF_MAX);

              MATCH_BIT(swbit,  SW_MAX);

下面看下這個巨集:

#define MATCH_BIT(bit, max) \

              for (i = 0; i < BITS_TO_LONGS(max); i++) \

                     if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \

                            break; \

              if (i != BITS_TO_LONGS(max)) \

                     continue;

/*如果handermatch空,則返回該id,或者呼叫match繼續匹配,匹配成員的話也返回id*/

              if (!handler->match || handler->match(handler, dev))

                     return id;

       }

       return NULL;

}

上面input dev已經註冊完了,下面看看hander的註冊.

static const struct input_device_id evdev_ids[] = {

{ .driver_info = 1 },      /* Matches all devices 來則不拒,公交車*/

       { },                /* Terminating zero entry */

};

MODULE_DEVICE_TABLE(input, evdev_ids);

static struct input_handler evdev_handler = {

       .event             = evdev_event,

       .connect  = evdev_connect,

       .disconnect     = evdev_disconnect,

       .fops              = &evdev_fops,

       .minor            = EVDEV_MINOR_BASE,

       .name             = "evdev",

       .id_table  = evdev_ids,//匹配的列表

};

static int __init evdev_init(void)

{

       return input_register_handler(&evdev_handler);

}

module_init(evdev_init);

下面看下hander的註冊:

static struct input_handler *input_table[8];

int input_register_handler(struct input_handler *handler)

{

       struct input_dev *dev;

       int retval;

       INIT_LIST_HEAD(&handler->h_list);

       if (handler->fops != NULL) {

              if (input_table[handler->minor >> 5]) {//判斷input_table的相應項是否被佔用

                     retval = -EBUSY;

                     goto out;

              }

              input_table[handler->minor >> 5] = handler; // 如果沒有佔用,則把hander填入

       }

/*把要註冊的hander加入input_handler_list連結串列中*/

       list_add_tail(&handler->node, &input_handler_list);

       /*遍歷input_dev_list連結串列上得每一個dev,去匹配該hander*/

       list_for_each_entry(dev, &input_dev_list, node)

              input_attach_handler(dev, handler);//開始進行匹配

}

匹配成功後,返回匹配成功的id,然後呼叫該handlerconnect函式。

static struct evdev *evdev_table[EVDEV_MINORS]; //evdev的容器

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,

                      const struct input_device_id *id)

{

       struct evdev *evdev;

       int minor;

       /*在容器中找個空閒的地方*/

       for (minor = 0; minor < EVDEV_MINORS; minor++)

              if (!evdev_table[minor])

                     break;

       /*分配一個evdev變數*/

       evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);

       /*初始化該evdev的成員變數*/

       INIT_LIST_HEAD(&evdev->client_list);

       spin_lock_init(&evdev->client_lock);

       mutex_init(&evdev->mutex);

       init_waitqueue_head(&evdev->wait);

       dev_set_name(&evdev->dev, "event%d", minor);

       evdev->exist = true;

       evdev->minor = minor;

/*初始化該evdev的成員變數handlehandle相當於是紅娘連線input dev和相應的hander*/

       evdev->handle.dev = input_get_device(dev);//增加該dev的引用計數

       evdev->handle.name = dev_name(&evdev->dev);//設定該evdevname

       evdev->handle.handler = handler;

       evdev->handle.private = evdev;//設定hander的私有資料,這個在下面會用到

       /*初始化該evdev的成員變數dev*/

       evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);

       evdev->dev.class = &input_class;

       evdev->dev.parent = &dev->dev;

       evdev->dev.release = evdev_free;

       device_initialize(&evdev->dev);

       /*註冊上面初始化好的handle*/

       error = input_register_handle(&evdev->handle);

       /*安裝evdev,其實就是放到全域性的evdev_table 陣列中*/

error = evdev_install_chrdev(evdev);

該函式如下:

static int evdev_install_chrdev(struct evdev *evdev)

{

evdev_table[evdev->minor] = evdev;

return 0;

}

/*把該evdev裝置增加到裝置驅動模型中*/

       error = device_add(&evdev->dev);

       return 0;

}

下面主要看input_register_handle幹了啥活?

int input_register_handle(struct input_handle *handle)

{

       struct input_handler *handler = handle->handler;

       struct input_dev *dev = handle->dev;

       list_add_tail_rcu(&handle->d_node, &dev->h_list);//加入到dev hist連結串列的末尾

       list_add_tail_rcu(&handle->h_node, &handler->h_list);//加入到handerhist尾部

       return 0;

註冊的過程也就是把該handle加入devhander的連結串列中

}

上面input devhandler用網上的一個圖可以表示:

該圖形象的描述了三者的關係.

 

該搭的關係已經搞好啦,下面就是要用啦,用的時候看三者是怎麼配合的。

下面看現在中斷處理中,是如何用的?

上面有說過,在中斷髮生後,會呼叫work,在work中去處理上報鍵值:上報函式如下:

static void gpio_keys_report_event(struct gpio_button_data *bdata)

{

       struct gpio_keys_button *button = bdata->button;//取出每一個鍵的結構體

       struct input_dev *input = bdata->input;        //把該鍵的input裝置也取出來

       unsigned int type = button->type ?: EV_KEY;   //型別為key

       int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;

       input_event(input, type, button->code, !!state);

       input_sync(input);

}

繼續分析:

void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)

{

       if (is_event_supported(type, dev->evbit, EV_MAX)) {//判斷該事件是否被支援

              ……….

              input_handle_event(dev, type, code, value);

              ..................

       }

}

下面繼續跟蹤:

static void input_handle_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)

{

       int disposition = INPUT_IGNORE_EVENT;

       switch (type) {

       case EV_KEY:

              if (is_event_supported(code, dev->keybit, KEY_MAX) &&  /判斷該code是否被支援

                  !!test_bit(code, dev->key) != value) {

                     if (value != 2) {

                            __change_bit(code, dev->key);

                            if (value)

                                   input_start_autorepeat(dev, code);

                            else

                                   input_stop_autorepeat(dev);

                     }

                     disposition = INPUT_PASS_TO_HANDLERS;

              }

              break;

       }

       if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)

              dev->sync = false;

if (disposition & INPUT_PASS_TO_HANDLERS)

input_pass_event(dev, type, code, value);

}

繼續跟蹤該函式:

static void input_pass_event(struct input_dev *dev,

                          unsigned int type, unsigned int code, int value)

{

       struct input_handler *handler;

       struct input_handle *handle;

              list_for_each_entry_rcu(handle, &dev->h_list, d_node) {

                     if (!handle->open)//如果該handle沒有被開啟,則找下一個handle

                            continue;

相關推薦

Android4.0 input輸入子系統

下面的文章是基於mini2440的gpio按鍵來講解input子系統。 以mini2440為例,用該板的bsp檔案,進行input子系統的講解.所用的版本為android4.0. 先來看下板級支援檔案都註冊了那些資源。 下面是五個按鍵的資源: #define KEY_POWER           116 

Android4.0 Telephony應用層

Android4.0 Phone通話中關鍵類 InCallScreen ——通話介面 CallCard ——通話使用者資訊卡 InCallTouchUi ——響鈴介面

input子系統

Input子系統詳解 一.Input子系統架構 Linux系統提供了input子系統,按鍵、觸控式螢幕、鍵盤、滑鼠等輸入都可以利用input介面函式來實現裝置驅動,下面是Input子系統架構: Input子系統架構 二.Input系統的組成 輸入子系統由驅動層(

EditText(輸入框)

屏幕 fill main delet 分開 odm 單行 多個 ear 本節引言: 上一節中我們學習了第一個 UI控件TextView(文本框),文中給出了很多實際開發中可能遇到的一些需求 的解決方法,應該會為你的開發帶來便利,在本節中,我們來學習第二個很常用的控件Ed

Docker Compose 1.18.0 之服務編排

ubun 它的 snapshot rep har container cdb 單獨 lib 一個使用Docker容器的應用,通常由多個容器組成。使用Docker Compose,不再需要使用shell腳本來啟動容器。在配置文件中,所有的容器通過services來定義,然後使

Centos6.0破解ROOT密碼

roo water oss ado pro 用戶模式 term mark 窗口 我們來看Centos6.8破解密碼1.開機出現以下畫面是連續點擊鍵盤上的“e”鍵; 2.彈出下面畫面,繼續連續點擊“e”鍵;3.出現下面畫面,按下箭頭選擇到“kernel”打頭的行,再連續點擊“

linux input輸入子系統分析《四》:input子系統整體流程全面分析

總線 返回值 分代 並不是 事件 等等 lag pri 位置 1 input輸入子系統整體流程 本節分析input子系統在內核中的實現,包括輸入子系統(Input Core),事件處理層(Event Handler)和設備驅動層。由於上節代碼講解了設備驅動層的寫法

【fabric實戰指南二】Fabric v1.0 部署過程原理

fabric區塊鏈兄弟社區,區塊鏈技術專業問答先行者,中國區塊鏈技術愛好者聚集地作者:吳壽鶴來源:區塊鏈兄弟原文鏈接:http://www.blockchainbrother.com/article/18著權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。編譯fabric tools我們會編譯以

Django 2.0 新款URL配置

Django2.0釋出後,很多人都擁抱變化,加入了2的行列。 但是和1.11相比,2.0在url的使用方面發生了很大的變化,下面介紹一下: 一、例項 先看一個例子: from django.urls import path from . import views urlpattern

%date~0,4%和 %time~0,2%等用法

在windows中,有個原始並且功能強大的批處理,好像是被人遺忘了,比如博主最近在一個專案中就用到它,非常好用。今天就和博主一直來看看用批處理生動生成每日的資料夾。 為了能正確地生成每天的日期資料夾,請先將本機時間的短日期格式設定為yyyy-MM-dd。   然後就開始寫bat批處理檔案了,新

CentOS 7下Cloudera Manager及CDH 6.0.1安裝過程

一、概念介紹 1、CDH 概覽 CDH是Apache Hadoop和相關專案的最完整、最受測試和最流行的發行版。CDH提供Hadoop的核心元素-可伸縮儲存和分散式計算-以及基於web的使用者介面和重要的企業功能。CDH是Apache許可的開放原始碼,是唯一提供統一批處理、互動式SQL和互動式搜尋以及基於

0 httpd2.2配置-Apache配置檔案-(二)

httpd-2.2 15 curl命令 curl是基於URL語法在命令列方式下工作的檔案傳輸工具,它支援FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE及LDAP等協議。curl支援HTTPS認證,並且支援HTTP的POST、PU

0 httpd2.2配置-Apache配置文件-(二)

切換 more 簡化 css 程序 ip地址 在服務器 filter utf httpd-2.2 15 curl命令 curl是基於URL語法在命令行方式下工作的文件傳輸工具,它支持FTP, FTPS, HTTP, HTTPS, GOPHER,

INPUT輸入子系統的測試方式 evtest

INPUT輸入子系統的測試方式 evtest 2018年04月09日 17:17:43 匠芯 閱讀數:175 版權宣告:匠芯築夢,不負所期,轉載請宣告轉載地址http://blog.csdn.net/qq84395064,謝謝大家。如有技術需要請聯絡博主QQ:84395064 微控制器學習交

Tensorflow資料輸入---TFRecords\TFRecords影象預處理

目錄 1、概述 2、預處理資料 2.1、常量定義 2.2、匯入庫 2.3、從train.txt檔案中讀取圖片-標籤對 2.4、預處理圖片並儲存 2.5、呼叫main函式 3、讀取預處理後的資料

react中的ref在input中的

當我們在專案中遇見文字輸入框的時候,獲取時刻輸入框中的值 1、受控元件 class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: ''};

C語言是什麼和vc6.0的安裝步驟及第一個c程式

從今天開始,我每天會分享一些關於計算機的知識,包括C語言、Python、資料庫、網路、Linux、網路安全等相關知識;今天我們就以C語言來開始我們的交流、學習吧。 C語言是一門通用計算機程式語言,廣泛應用於底層開發。C語言的設計目標是提供一種能以簡易的方式編譯、

vue2.0之axios使用

axios 基於 Promise 的 HTTP 請求客戶端,可同時在瀏覽器和 node.js 中使用 功能特性 在 node.js 中傳送 http請求 攔截請求和響應 轉換請求和響應資料 自動轉換 JSON 資料 客戶端支援保護安全免受 XSRF 攻擊

INPUT輸入子系統

一、什麼是input輸入子系統? 1、Linux系統支援的輸入裝置繁多,例如鍵盤、滑鼠、觸控式螢幕、手柄或者是一些輸入裝置像體感輸入等等,Linux系統是如何管理如此之多的不同型別、不同原理、不同的輸入資訊的 輸入裝置的呢?其實就是通過input輸入子系統這套軟體體系來完