bus_type注册以及sysfs_notify的使用

驱动程序:

创建一个bus_type, 在这个bus下分别注册driver和device,之后创建设备的属性文件用于poll测试

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/kthread.h>
#include <linux/async.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/devinfo.h>

int sp_bus_match(struct device *dev, struct device_driver *drv)
{
	return 1;
}

struct bus_type sp_bus = {
	.name = "sp_bus",
	.match = sp_bus_match,
};

struct sp_device {
	struct device device;
};

struct sp_driver {
	struct device_driver driver;
};


void spdev_release(struct device *dev)
{
}
int sp_driver_remove(struct device *dev)
{
	return 0;
}
void sp_driver_shutdown(struct device *dev)
{
}

ssize_t poll_show(struct device *dev, struct device_attribute *attr,
		char *buf)
{
	return sprintf(buf, "poll show\n\r");

}
ssize_t poll_store(struct device *dev, struct device_attribute *attr,
		 const char *buf, size_t count)
{
	/** poll或者epoll可用
	 *  poll使用 POLLPRI 事件; epoll使用 EPOLLWAKEUP 事件
	 *  调用poll("value"); epoll_wait() 之前要调用一次read("value"), 原因不明
	 *
	 *  即:往poll节点写数据时,唤醒value上的poll休眠
	 */
	sysfs_notify(&dev->kobj, NULL, "value");

	return count;
}
static DEVICE_ATTR_RW(poll);

ssize_t value_show(struct device *dev, struct device_attribute *attr,
		char *buf)
{
	return sprintf(buf, "5A5A\n\r");
}
static DEVICE_ATTR_RO(value);

int sp_driver_probe(struct device *dev)
{
	/* 3. 创建device的属性文件 */
	device_create_file(dev, &dev_attr_poll);
	device_create_file(dev, &dev_attr_value);
	return 0;
}

int sp_register_device(struct sp_device *sp_dev)
{
	if (sp_dev->device.init_name == NULL ||
		sp_dev->device.release == NULL) {
		printk("register sp_device failed!\n");
		return -EINVAL;
	}		
	sp_dev->device.bus = &sp_bus;
	return device_register(&sp_dev->device);
}

int sp_register_driver(struct sp_driver *sp_drv)
{
	if (sp_drv->driver.name == NULL) {
		printk("register sp_driver failed!\n");
		return -EINVAL;
	};
	sp_drv->driver.bus = &sp_bus;
	sp_drv->driver.owner = THIS_MODULE;
	sp_drv->driver.probe = sp_driver_probe;
	sp_drv->driver.shutdown = sp_driver_shutdown;
	sp_drv->driver.remove = sp_driver_remove;
	return driver_register(&sp_drv->driver);
}

static int __init sys_poll_init(void)
{
	struct sp_device *spdev;
	struct sp_driver *spdrv;

	spdev = kzalloc(sizeof(*spdev), GFP_KERNEL);
	spdrv = kzalloc(sizeof(*spdrv), GFP_KERNEL);
	if (spdev == NULL && spdev == NULL) {
		printk("alloc for device or driver failed!\n");
		return -ENOMEM;
	}

	/* 1. 注册一个bus_type */
	bus_register(&sp_bus);

	/* 2. 在这个bus下注册device和driver */
	spdev->device.init_name = "spdev0";
	spdev->device.release = spdev_release;
	sp_register_device(spdev);
	
	spdrv->driver.name = "spdrv";
	sp_register_driver(spdrv);

	return 0;
}

static void __exit sys_poll_exit(void)
{
	//to do ...
}

module_init(sys_poll_init);
module_exit(sys_poll_exit);
MODULE_LICENSE("GPL");

APP

/** 测试用例:
 *		测试驱动程序 sys_notify() 函数
 *  测试方式:
 * 		./test.out &
 * 		echo xxx > /sys/bus/sp_bus/devices/spdev0/poll 或者 等待10s
 *  desc:
 *  	使用poll在 /sys/bus/sp_bus/devices/spdev0/value 属性文件上进入睡眠,10s超时
 *  	往  /sys/bus/sp_bus/devices/spdev0/poll 写值时,驱动程序调用 sys_notify() 唤醒poll
 *  	value 返回 5A5A
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <sys/epoll.h>

#define FILE 		"/sys/bus/sp_bus/devices/spdev0/value"
#define POLL_CNT	6
#define TIME_OUT	(10*1000)


int main(int argc, char **argv)
{
	int fd, ret, readCnt;
	char value[4] = {0};

	fd = open(FILE, O_RDONLY);
	/** need read dummy once */
	read(fd, value, 4);

	/** epoll */
	int epollFd, pollCnt = POLL_CNT;
	struct epoll_event event;
	
	event.events = EPOLLWAKEUP | EPOLLERR;
	
	epollFd = epoll_create(1);
	ret = epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &event);
	if (ret) {
		printf("epoll_ctl failed!\n");
	}
	while (pollCnt--) {
		ret = epoll_wait(epollFd, &event, 1, TIME_OUT);
		if (ret == 0) {
			printf("epoll_wait time out!\n");
		} else if (ret < 0) {
			printf("epoll_wait failed!\n");
		} else {
			lseek(fd, 0, SEEK_SET);
			readCnt = read(fd, value, sizeof(value));
			printf("now can read! value is %s\n", value);
		}
	}

	close(fd);
	
	return 0;
}

上机测试:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值