charter device file을 만든다
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
/* device number를 할당 */
#define MY_MAJOR_NUM 202
static struct cdev char_dev;
static int open(struct inode *inode, struct file *file)
{
pr_info("open() is called.\n");
return 0;
}
static int close(struct inode *inode, struct file *file)
{
pr_info("close() is called.\n");
return 0;
}
static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
pr_info("ioctl() is called. cmd = [%d], arg = [%ld]\n", cmd, arg);
return 0;
}
/* charter device에 open, close, ioctl 명령시 호출 할 함수 등록*/
static const struct file_operations char_dev_fops = {
.owner = THIS_MODULE,
.open = open,
.release = close,
.unlocked_ioctl = ioctl,
};
static int __init hello_init(void)
{
int ret;
/* device number를 만든다 */
dev_t dev = MKDEV(MY_MAJOR_NUM, 0);
pr_info("hello_init\n");
/* register_chrdev_region(device number, minor 갯수, device name(/proc/devices에 생성)) */
ret = register_chrdev_region(dev, 1, "char_device");
if (ret < 0){
printk("Unable allocate mayor number %d\n", MY_MAJOR_NUM);
return ret;
}
/* charter device 를 init */
cdev_init(&char_dev, &char_dev_fops);
/* charter device를 추가 */
ret= cdev_add(&char_dev, dev, 1);
if (ret < 0){
/*실패시 char device 등록해제*/
unregister_chrdev_region(dev, 1);
pr_info("Unable to add cdev\n");
return ret;
}
return 0;
}
static void __exit hello_exit(void)
{
pr_info("hello_exit\n");
cdev_del(&char_dev);
unregister_chrdev_region(MKDEV(MY_MAJOR_NUM, 0), 1);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
charter device file에 명령(ioctl) 할 app을 만든다
ioctl_test.c
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
/* 생성한 mydev를 open */
int my_dev = open("/dev/mydev", 0);
if (my_dev < 0) {
perror("Fail open device file: /dev/mydev.");
} else {
/* 생성한 mydev에 ioctl 명령 */
ioctl(my_dev, 10, 20);
/* 생성한 mydev를 close */
close(my_dev);
}
return 0;
}
ioctl app을 build 하기 위한 Makefile
CC = arm-linux-gnueabihf-gcc
ioctl_test : ioctl_test.c
$(CC) -o $@ $^
clean :
rm ioctl_test
deploy : ioctl_test
scp $^ root@10.0.0.10:/home/pi
위 Makefile을 'make' 하면 ioctl_test 파일이 생성
'mknod /dev/mydev c 202 0' command로 charter device file을 생성한다.
'mknod {경로/파일이름} {device 종류} {major number} {nimor number}
이제 ioctl_test app을 실행하면 driver로 command가 전달되다.
root@raspberrypi:/home/board# ./ioctl_test
root@raspberrypi:/home/board# dmesg
[ 1518.516277] hello_init
[ 1933.485801] open() is called.
[ 1933.485826] ioctl() is called. cmd = [10], arg = [20]
[ 1933.485843] close() is called.
-------------
class charter module을 만들어보자
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#define DEVICE_NAME "mydev"
#define CLASS_NAME "hello_class"
static struct class* helloClass;
static struct cdev my_dev;
dev_t dev;
static int open(struct inode *inode, struct file *file)
{
pr_info("open() is called.\n");
return 0;
}
static int close(struct inode *inode, struct file *file)
{
pr_info("close() is called.\n");
return 0;
}
static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
pr_info("ioctl() is called. cmd = %d, arg = %ld\n", cmd, arg);
return 0;
}
/* declare a file_operations structure */
static const struct file_operations my_dev_fops = {
.owner = THIS_MODULE,
.open = open,
.release = close,
.unlocked_ioctl = ioctl,
};
static int __init hello_init(void)
{
int ret;
dev_t alloc_dev;
int Major;
struct device* helloDevice;
pr_info("hello_init\n");
/*
device number 주번호 동적 할당
alloc_chrdev_region( 동적 할당할 dev major number, first minor number
, minor 갯수, charter device name )
*/
ret = alloc_chrdev_region(&alloc_dev, 0, 1, DEVICE_NAME);
if (ret < 0){
pr_info("fail to allocate Mayor number \n");
return ret;
}
/* device number 생성 */
Major = MAJOR(alloc_dev);
dev = MKDEV(Major,0);
pr_info("major number %d\n", Major);
/*
cdev init, add cdev to kernel 공간
cdev_init(struct cdev, cdev 함수 호출시 동작할 file operation)
*/
cdev_init(&my_dev, &my_dev_fops);
ret = cdev_add(&my_dev, dev, 1);
if (ret < 0){
unregister_chrdev_region(dev, 1);
pr_info("fail to add cdev\n");
return ret;
}
/*
device class 등록
class_create( , class file name)
*/
helloClass = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(helloClass)){
unregister_chrdev_region(dev, 1);
cdev_del(&my_dev);
pr_info("Fail to register device class\n");
return PTR_ERR(helloClass);
}
pr_info("class device is create sucess\n");
/*
'/dev/'에 device node 생성
device_create(class_device, , device number , , /dev/에 생성할 name)
*/
helloDevice = device_create(helloClass, NULL, dev, NULL, DEVICE_NAME);
if (IS_ERR(helloDevice)){
class_destroy(helloClass);
cdev_del(&my_dev);
unregister_chrdev_region(dev, 1);
pr_info("Fail to create the device\n");
return PTR_ERR(helloDevice);
}
pr_info("device is create sucess\n");
return 0;
}
static void __exit hello_exit(void)
{
device_destroy(helloClass, dev);
class_destroy(helloClass);
cdev_del(&my_dev);
unregister_chrdev_region(dev, 1);
pr_info("hello_exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
'/sys/class/' 에 file을 생성하고 user 단에서 접근이 가능하다
class_create() - '/sys/class/' file 생성
class_destory() - '/sys/class/' file 삭제
'/dev/'에 device node를 생성한다
device_create() 함수를 사용하면 mknod를 상요하여 /dev/ 경로에 file을 수동으로 생성 하지 않아도 된다.
device_create() - '/dev/' file 생성
device_destroy() - '/dev/' file 삭제
register_chrdev_region() 함수를 사용하면 주번호를 입력해야된다 하지만 alloc_chrdev_region() 함수를 사용하면
주번호를 입력하지 않고 동적으로 할당 가능하다
root@raspberrypi:/home/board# insmod class_driver.ko
root@raspberrypi:/home/board# dmesg
[ 103.479103] class_driver: loading out-of-tree module taints kernel.
[ 103.479814] hello_init
[ 103.479829] major number 237
[ 103.479892] class device is create sucess
[ 103.484609] device is create sucess
insmod 후 '/sys/class/' 경로에 'hello_class'이 생성
root@raspberrypi:/sys/class/hello_class# pwd
/sys/class/hello_class
'hello_class'에 mydev 생성
root@raspberrypi:/sys/class/hello_class# ls
mydev
mydev 디렉토리에 아래 파일들 생성
root@raspberrypi:/sys/class/hello_class/mydev# ls
dev power subsystem uevent
'/dev'/에 mydev 파일 생성
root@raspberrypi:/dev# ls -l /dev/mydev
crw------- 1 root root 237, 0 May 21 07:14 /dev/mydev
'device driver' 카테고리의 다른 글
charter device driver - 6. led_class_platform 만들기 (0) | 2023.05.26 |
---|---|
charter device driver - 5. platform_driver로 led control 해보자 (0) | 2023.05.22 |
charter device driver - 4. platform driver module 만들기 (0) | 2023.05.21 |
charter device driver - 3. misc driver 만들기 (0) | 2023.05.21 |
charter device driver - 1. 간단한 module 만들기 (0) | 2023.05.21 |
댓글