android平台驱动开发(二)--设备属性节点的创建

驱动开发

如何创建设备属性节点



前言

最简单的设备属性节点


一、代码添加

在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.sh

xxxx@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
1

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
[ 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");
	else
		dev_info(&ts->client->dev, "Update success\n");

	return count;

exit:
	



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这段代码定义了一个名为 `dwc3_notify_event` 的枚举类型,用于表示 DWC3(DesignWare USB 3.0 超级速度 USB 控制器)的不同通知事件。这些事件用于在 DWC3 控制器的驱动程序中进行事件处理和通信。 下面是每个枚举值的含义和可能的用途: - `DWC3_CONTROLLER_ERROR_EVENT`:表示控制器错误事件,用于处理控制器发生错误的情况。 - `DWC3_CONTROLLER_RESET_EVENT`:表示控制器复位事件,用于处理控制器复位操作。 - `DWC3_CORE_PM_SUSPEND_EVENT`:表示核心挂起事件,用于处理 USB 核心的挂起操作。 - `DWC3_CORE_PM_RESUME_EVENT`:表示核心恢复事件,用于处理 USB 核心的恢复操作。 - `DWC3_CONTROLLER_CONNDONE_EVENT`:表示连接完成事件,用于处理 DWC3 控制器连接完成后的操作。 - `DWC3_CONTROLLER_NOTIFY_OTG_EVENT`:表示 OTG(On-The-Go)通知事件,用于处理 OTG 相关的通知。 - `DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT`:表示设置当前电流消耗事件,用于设置 DWC3 控制器的当前电流消耗。 - `DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER`:表示禁用更新传输事件,用于禁用传输更新。 - `DWC3_CONTROLLER_PULLUP`:表示上拉事件,用于处理 USB 接口的上拉操作。 此外,还有一些与 USB GSI(Generic SuperSpeed Inter-Chip)事件缓冲区相关的通知事件: - `DWC3_GSI_EVT_BUF_ALLOC`:表示事件缓冲区分配事件。 - `DWC3_GSI_EVT_BUF_SETUP`:表示事件缓冲区设置事件。 - `DWC3_GSI_EVT_BUF_CLEANUP`:表示事件缓冲区清理事件。 - `DWC3_GSI_EVT_BUF_CLEAR`:表示事件缓冲区清除事件。 - `DWC3_GSI_EVT_BUF_FREE`:表示事件缓冲区释放事件。 最后,`DWC3_CONTROLLER_NOTIFY_CLEAR_DB` 表示清除数据包通知。 这些枚举值用于在 DWC3 控制器的驱动程序中标识和处理不同的通知事件。具体的使用和含义可能因驱动程序实现和配置而有所不同,需要查阅相关的文档或源代码来了解其具体用法和上下文。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨染天姬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值