日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux按键驱动中的结构体,linux 驱动之input子系统(gpio-keys)实现

發布時間:2025/3/20 linux 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux按键驱动中的结构体,linux 驱动之input子系统(gpio-keys)实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.概述

Gpio-keys 是基于input子系統實現的一個通用按鍵驅動,該驅動也符合linux驅動實現模型,即driver和device分離模型.一般按鍵驅動,都是基于gpio-keys進行開發的.

2. gpio-keys 代碼分析(基于 linux 4.14.40)

(1)整體來說分為以下四步

static int gpio_keys_probe(struct platform_device *pdev)

{

...........

...........

/*第一,從設備樹獲取button,即gpio相關控制方式和屬性*/

pdata = gpio_keys_get_devtree_pdata(dev);

...........

...........

/*第二,分配一個input 設備*/

input = devm_input_allocate_device(dev);

...........

...........

/*第三,注冊gpio相關信息和分配資源*/

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

error = gpio_keys_setup_key(pdev, input, ddata,

button, i, child);

...........

...........

/*第四,注冊input 設備到kernel*/

error = input_register_device(input);

...........

...........

return 0;

}

(2)從注冊一個input設備來看,二,四步是一個通用的步驟,第三步和第一步是關鍵,先看第三步.

static int gpio_keys_setup_key(struct platform_device *pdev,

struct input_dev *input,

struct gpio_keys_drvdata *ddata,

const struct gpio_keys_button *button,

int idx,

struct fwnode_handle *child)

{

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

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

/*第一,請求gpio并獲取irq 資源*/

error = devm_gpio_request_one(dev, button->gpio, flags, desc);

irq = gpiod_to_irq(bdata->gpiod);

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

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

/*第二,注冊一個delayed work任務,這個任務的目的,當中斷發生時,需要向

通過input子系統發消息,這個過程有可能會sleep或者schedule,所以必須通一個

delay work去完成這件事.

*/

INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);

isr = gpio_keys_gpio_isr;

irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;}

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

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

/*第三,注冊中斷*/

error = devm_request_any_context_irq(dev, bdata->irq, isr, irqflags,

desc, bdata);

return 0;

}

(3)下面來看中斷和delay work做了什么事

static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)

{

struct gpio_button_data *bdata = dev_id;

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

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

/*中斷中,唯一做的事,就是把delay work加入到了system_wq隊列中去.還做了一個延遲

這個延遲目的是為了去抖動.*/

mod_delayed_work(system_wq,

&bdata->work,

msecs_to_jiffies(bdata->software_debounce));

return IRQ_HANDLED;

}

static void gpio_keys_gpio_work_func(struct work_struct *work)

{

/*調用上報消息,接著向下看*/

...........

gpio_keys_gpio_report_event(bdata);

...........

}

static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)

{

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

/*第一步,獲取gpio 狀態.*/

state = gpiod_get_value_cansleep(bdata->gpiod);

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

/*發送消息到input*/

input_event(input, type, *bdata->code, state);

input_sync(input);

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

}

(4)下面請看第一步工作,以及設備樹的配置

(紅色為必要部分)

label : 一個key 的別名

linux,code :? 鍵值,作為按鍵的唯一識別號

linux,input-type: input類型(EV_KEY(按鍵), EV_ABS(相對坐標), EV_REL(絕對坐標)...) 默認為EV_KEY

wakeup-source: 與pm相關,默認為disable

linux,can-disable:是否共享中斷line ((默認)0:shared, 1: not shared)

debounce-interval : 去抖延時

gpios :? gpio 的相關信息

/*用于gpio資源的申請及初始化,可列舉很多*/

gpio_keys_pins_default: gpio_keys_pins_default {

pinctrl-single,pins = <

AM4372_IOPAD(0x9a0, PIN_INPUT | MUX_MODE9) /* (L23) mcasp0_aclkr.gpio0[18] */

>;

};

/*創建gpio-keys 設備描述*/

gpio_keys: gpio_keys {

compatible = "gpio-keys";

pinctrl-names = "default";

pinctrl-0 = ;

#address-cells = <1>;

#size-cells = <0>;

/*添加一個button, 用于做系統reset*/

button0 {

label = "reset";

linux,code = <0x198>; /*KEY_RESTART*/

gpios = ;

};

};

3. 內核模塊選擇配置

| with configuration data saying which GPIOs are used. |

| |

| To compile this driver as a module, choose M here: the |

| module will be called gpio_keys. |

| |

| Symbol: KEYBOARD_GPIO [=y] |

| Type : tristate |

| Prompt: GPIO Buttons |

| Location: |

| -> Device Drivers |

| -> Input device support |

| -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y]) |

| -> Keyboards (INPUT_KEYBOARD [=y]) |

| Defined at drivers/input/keyboard/Kconfig:214 |

| Depends on: !UML && INPUT [=y] && INPUT_KEYBOARD [=y] && (GPIOLIB [=y] || COMPILE_TEST [=n])

4.?cat /proc/bus/input/devices

通過這個可以看到接到input事件的handler是哪一個

$: cat /proc/bus/input/devices

I: Bus=0019 Vendor=0001 Product=0001 Version=0100

N: Name="gpio_keys"

P: Phys=gpio-keys/input0

S: Sysfs=/devices/platform/gpio_keys/input/input0

U: Uniq=

H: Handlers=event0

B: PROP=0

B: EV=3

B: KEY=1000000 0 0 0 0 0 0 0 0 0 0 0 0

/下面的信息有助于你編寫udev rules

$:udevadm info -a -p /sys//devices/platform/gpio_keys/input/input0

looking at device '/devices/platform/gpio_keys/input/input0':

KERNEL=="input0"

SUBSYSTEM=="input"

DRIVER==""

ATTR{name}=="gpio_keys"

ATTR{phys}=="gpio-keys/input0"

ATTR{properties}=="0"

ATTR{uniq}==""

looking at parent device '/devices/platform/gpio_keys':

KERNELS=="gpio_keys"

SUBSYSTEMS=="platform"

DRIVERS=="gpio-keys"

ATTRS{disabled_keys}==""

ATTRS{disabled_switches}==""

ATTRS{driver_override}=="(null)"

ATTRS{keys}=="408"

ATTRS{switches}==""

looking at parent device '/devices/platform':

KERNELS=="platform"

SUBSYSTEMS==""

DRIVERS==""

4.如何接收按鍵消息,以下例程供參考

#include #include #include #include #include #include #include #include #include #define KEY_DEVICE_FILE "/dev/input/event0"

struct input_event {

struct timeval time;

unsigned short type;

unsigned short code;

int value;

};

int main()

{

int fd_key = -1;

struct input_event key_evt;

int ret = 0;

fd_key= open(KEY_DEVICE_FILE, O_RDONLY);

if(fd_key< 0) {

return fd_key;

}

monitor_key:

ret = read(fd_key, (char*)&key_evt, sizeof(struct input_event));

if(ret < 0)

{

printf("read key event failed:%d\n", ret);

}else{

if(key_evt.code == 408 && key_evt.value == 1)

{

printf("The press of reset button is detected\n");

return 0;

}

#if 0

printf("%lld seconds %ld microseconds", key_evt.time.tv_sec,

key_evt.time.tv_usec);

printf("type:%d code:%d value:%d\n", key_evt.type, key_evt.code, key_evt.value);

#endif

}

goto monitor_key;

return 0;

}

總結

以上是生活随笔為你收集整理的linux按键驱动中的结构体,linux 驱动之input子系统(gpio-keys)实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。