驱动开发
如何创建设备属性节点
文章目录
- 驱动开发
- 前言
- 一、代码添加
- 二、编译
- 三、 验证
- 总结
前言
最简单的设备属性节点
一、代码添加
在AU_LINUX_ANDROID_LA.VENDOR.1.0\kernel_platform\msm-kernel\drivers\misc\目录下新建test_device.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>static char test_flag[32]="0";static ssize_t test_mode_show(struct device *dev,struct device_attribute *attr,char *buf)
{ printk("xxxxx xxx %s,%d: buf: %s test_flag:%s\n",__func__,__LINE__,buf,test_flag);return sprintf(buf, "%s\n",test_flag);
}static ssize_t test_mode_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{ sprintf(test_flag, "%s",buf);printk("xxxxx %s,%d: buf: %s \n",__func__,__LINE__,buf); return count;
}static DEVICE_ATTR(xxx_test_mode,0644, test_mode_show, test_mode_store);static int test_driver_probe(struct platform_device *pdev)
{int ret; int force_gpio;struct device_node *np = pdev->dev.of_node;printk("xxxxx %s,%d: Enter\n",__func__,__LINE__);force_gpio = of_get_named_gpio(np,"qcom,gpio-force-download", 0);if(gpio_is_valid(force_gpio)){ret = gpio_request(force_gpio, "qcom-force-9008-gpio");gpio_export(force_gpio,0);}ret = device_create_file(&pdev->dev, &dev_attr_xxx_test_mode); if (ret < 0){ printk("xxxxx create files fail\n"); return ret;} return 0;
}static int test_driver_remove(struct platform_device *pdev)
{ printk("xxxxx %s,%d: Enter\n",__func__,__LINE__);device_remove_file(&pdev->dev, &dev_attr_xxx_test_mode); return 0;
}static const struct of_device_id of_xxx_test_mode_match[] = {{ .compatible = "xxx-force-usb-boot", },{},
};static struct platform_driver test_driver ={ .probe = test_driver_probe, .remove = test_driver_remove, .driver = {.name = "xxx-test-mode", .owner = THIS_MODULE,.of_match_table = of_match_ptr(of_xxx_test_mode_match),},
};static int test_driver_init(void)
{ printk("xxxxx %s,%d: Enter\n",__func__,__LINE__);return platform_driver_register(&test_driver);
}static void test_driver_exit(void)
{ printk("xxxxx %s,%d: Enter\n",__func__,__LINE__);platform_driver_unregister(&test_driver); return;
}module_init(test_driver_init);
module_exit(test_driver_exit);MODULE_AUTHOR("zh@testsmart.com");
MODULE_DESCRIPTION("test Smart Hardware Verion driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:test-mode-driver");
kernel_platform/qcom/proprietary/devicetree/qcom/cape-mtp.dtsi
&soc {gpio_keys {compatible = "gpio-keys";label = "gpio-keys";pinctrl-names = "default";pinctrl-0 = <&key_vol_up_default>,<&gpio_keys_active>;vol_up {label = "volume_up";gpios = <&pm8350_gpios 6 GPIO_ACTIVE_LOW>;linux,input-type = <1>;linux,code = <KEY_VOLUMEUP>;gpio-key,wakeup;debounce-interval = <15>;linux,can-disable;};home {label = "home";gpios = <&tlmm 46 GPIO_ACTIVE_LOW>;linux,input-type = <1>;linux,code = <KEY_HOME>;debounce-interval = <15>;gpio-key,wakeup;linux,can-disable;};vol_down {label = "volume_down";gpios = <&tlmm 19 GPIO_ACTIVE_LOW>;linux,input-type = <1>;linux,code = <KEY_VOLUMEDOWN>;gpio-key,wakeup;debounce-interval = <15>;linux,can-disable;};};+xxx-force-usb {+ compatible = "xxx-force-usb-boot";+ qcom,gpio-force-download = <&tlmm 47 0x2002>;+};};
修改misc目录下的Makefile
AU_LINUX_ANDROID_LA.VENDOR.1.0\kernel_platform\msm-kernel\drivers\misc\Makefile
+obj-m += test_device.o
注:obj-m最好是以宏控的方式控制,当然也可以以obj-y的方式编译进内核,后续详细介绍
二、编译
以骁龙8 gen1 plus平台为例
在AU_LINUX_ANDROID_LA.VENDOR.1.0目录下执行:
xxxx@u99:~/AU_LINUX_ANDROID_LA.VENDOR.1.0$bash kernel_platform/qcom/proprietary/prebuilt_HY11/vendorsetup.shxxxx@u99:~/AU_LINUX_ANDROID_LA.VENDOR.1.0$cd kernel_platform/xxxx@u99:~/AU_LINUX_ANDROID_LA.VENDOR.1.0/kernel_platform$BUILD_CONFIG=./common/build.config.msm.waipio ./build/all-variants.sh "./build/build.sh"
如上编译完成后AU_LINUX_ANDROID_LA.VENDOR.1.0\kernel_platform\out\msm-waipio-waipio-consolidate\dist\目录下会生成hello_world.ko;push到设备中验证即可。
三、 验证
adb push AU_LINUX_ANDROID_LA.VENDOR.1.0\kernel_platform\out\msm-waipio-waipio-consolidate\dist\test_device.ko /vendor_dlkm/lib/modules/
adb push AU_LINUX_ANDROID_LA.VENDOR.1.0\kernel_platform\out\msm-waipio-waipio-consolidate\dist\test_device.ko /vendor/lib/modules/
taro:/ # insmod vendor/lib/modules/test_device.ko
taro:/ # dmesg |grep xxx
[ 6455.143660] xxxxx test_driver_exit,96: Enter
[ 6455.143738] xxxxx test_driver_remove,66: Enter
[ 6467.130438] xxxxx test_driver_init,89: Enter
[ 6467.131992] xxxxx test_driver_probe,46: Enter
taro:/ #
130|taro:/ # cat sys/devices/platform/soc/soc:xxx-force-usb/xxx_test_mode
0
taro:/ # echo 1 > sys/devices/platform/soc/soc:xxx-force-usb/xxx_test_mode
taro:/ # echo 1 > sys/devices/platform/soc/soc:xxx-force-usb/xxx_test_mode
taro:/ # cat sys/devices/platform/soc/soc:xxx-force-usb/xxx_test_mode
1taro:/ # dmesg |grep xxx
[ 6455.143660] xxxxx test_driver_exit,96: Enter
[ 6455.143738] xxxxx test_driver_remove,66: Enter
[ 6467.130438] xxxxx test_driver_init,89: Enter
[ 6467.131992] xxxxx test_driver_probe,46: Enter
[ 6486.875923] xxxxx xxx test_mode_show,24: buf: test_flag:0
[ 6491.227092] xxxxx test_mode_store,33: buf: 1\x0a
[ 6493.537732] xxxxx test_mode_store,33: buf: 1\x0a
[ 6495.128476] xxxxx xxx test_mode_show,24: buf: test_flag:1\x0a
taro:/ #
总结
这里是设备属性节点的添加,添加设备树的目的是为了申请gpio47,这样在开机后sys/class/gpio目录下就可以看到gpio348(SM8475平台的gpio偏移是301),以供厂测使用。关机时,此gpio拉高就可以进9008,即FORCE_USB_BOOT功能。
kernel_platform/common/arch/arm64/configs/consolidate.fragment
需要打开宏控,sys/class/gpio
+CONFIG_GPIO_SYSFS=y
关于设备节点有几种比较方式:
static ssize_t xxx_store(struct kobject *dev, struct kobj_attribute *attr, const char *buf, size_t count)
{int value = 0;if (num != sscanf(buf, "%d\n", &value)){pr_err("mcu_wake>>>%s: num=%d!=1,regaddr=%d\n", __func__, num, value);return -1;}if((value==1)||(value==0)){if(value==1) {}else {}}else{pr_err("%s\n",__func__);}return count;
}
==========static ssize_t mode_show(struct device *dev, struct device_attribute *attr,char *buf)
{struct dwc3_msm *mdwc = dev_get_drvdata(dev);if (mdwc->vbus_active)return snprintf(buf, PAGE_SIZE, "peripheral\n");if (mdwc->id_state == DWC3_ID_GROUND)return snprintf(buf, PAGE_SIZE, "host\n");return snprintf(buf, PAGE_SIZE, "none\n");
}static ssize_t mode_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
{struct dwc3_msm *mdwc = dev_get_drvdata(dev);if (sysfs_streq(buf, "peripheral")) {mdwc->vbus_active = true;mdwc->id_state = DWC3_ID_FLOAT;} else if (sysfs_streq(buf, "host")) {mdwc->vbus_active = false;mdwc->id_state = DWC3_ID_GROUND;} else {mdwc->vbus_active = false;mdwc->id_state = DWC3_ID_FLOAT;}dwc3_ext_event_notify(mdwc);return count;
}
==============static ssize_t usb_compliance_mode_show(struct device *dev,struct device_attribute *attr, char *buf)
{struct dwc3_msm *mdwc = dev_get_drvdata(dev);return snprintf(buf, PAGE_SIZE, "%c\n",mdwc->usb_compliance_mode ? 'Y' : 'N');
}static ssize_t usb_compliance_mode_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
{int ret = 0;struct dwc3_msm *mdwc = dev_get_drvdata(dev);ret = strtobool(buf, &mdwc->usb_compliance_mode);if (ret)return ret;return count;
}
=====================
static ssize_t dbg_state_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{struct sdhci_host *host = dev_get_drvdata(dev);struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);bool v;if (!capable(CAP_SYS_ADMIN))return -EACCES;if (kstrtobool(buf, &v))return -EINVAL;msm_host->dbg_en = v;return count;
}=========
static ssize_t gtp_dofwupdate_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{struct goodix_ts_data *ts = dev_get_drvdata(dev);char update_file_name[FW_NAME_MAX_LEN];int retval;if (count > FW_NAME_MAX_LEN) {dev_info(&ts->client->dev, "FW filename is too long\n");retval = -EINVAL;goto exit;}strlcpy(update_file_name, buf, count);ts->force_update = true;retval = gup_update_proc(update_file_name);if (retval == FAIL)dev_err(&ts->client->dev, "Fail to update GTP firmware.\n");elsedev_info(&ts->client->dev, "Update success\n");return count;exit: