처음으로 Linux 드라이버를 만들어야 하는데 궁금한 점이 있는데 편리한 답변을 찾지 못했습니다. 내 목표는 PWM 드라이버를 만드는 것입니다. IOCTL 덕분에 드라이버를 성공적으로 만들고 작업했지만 두 가지 더 하고 싶은 일이 있는데 그 중 하나는 어떻게 해야 할지 모르겠습니다.
첫 번째: 부팅 시 드라이버를 로드하고 싶습니다. 프로브 기능에 대해 많이 읽었지만 작동 방식을 이해하지 못합니다. 어떤 사람들은 module-load.r에 대해 이야기하는데 가장 좋은 방법은 무엇입니까?
두 번째 사항: 해당 드라이버를 사용하는 장치의 각 장치 트리 선언에 대해 많은 드라이버를 만들어야 합니다. 그런데 각 인스턴스에 대해 /dev/에 파일을 동적으로 생성하려면 어떻게 해야 합니까?
명확한지는 모르겠지만 코드와 장치 트리를 제공했습니다.
#define WR_DUTYCYCLE _IOW('a', 1, int32_t *)
#define WR_FREQ _IOW('a', 2, int32_t *)
#define RD_DUTYCYCLE _IOR('a', 3, int32_t *)
#define RD_FREQ _IOR('a', 4, int32_t *)
#define DEV_CLASS_MODE ((umode_t)(S_IRUGO|S_IWUGO))
/* Meta Information */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Benjamin CLEMENT");
MODULE_DESCRIPTION("Generate a PWM with chosen DUTY CYCLE and FREQUENCY");
/* Variables for device and device class */
static dev_t my_device_nr;
static struct class *my_class;
static struct cdev my_device;
static struct platform_device *pdev;
unsigned long *base_addr;
unsigned long *base_addr;
#define DRIVER_NAME "pwm"
#define DRIVER_CLASS "MyModuleClass"
/**
* @brief This function is called, when the device file is opened
*/
static int driver_open(struct inode *device_file, struct file *instance) {
printk("dev_nr - open was called!\n");
return 0;
}
/**
* @brief This function is called, when the device file is opened
*/
static int driver_close(struct inode *device_file, struct file *instance) {
printk("dev_nr - close was called!\n");
return 0;
}
/**
* @brief This function is called, when the module use IOCTL for write or read
*/
static long int my_ioctl(struct file *file, unsigned cmd, unsigned long arg){
long int back; //Looking for the register
char *path = "/";
struct device_node *dt_node;
dt_node = of_find_node_by_path(path);
struct device_node *dt_pwm;
u32 reg[4];
//Looking for base_adress
if (!dt_node) {
printk(KERN_ERR "Failed to find node by path: %s.\n");
} else {
dt_pwm = of_find_node_by_name(dt_node, file->f_path.dentry->d_iname);
if (!dt_pwm) {
printk(KERN_ERR "Failed to find node pwm: %s.\n");
}
else{
of_property_read_u32_array(dt_pwm, "reg", reg, 4);
//printk("Adress GPIO1 : %x", reg[1]);
//printk("ADRESS GPIO2 : %x", reg[1] + 8);
}
}
switch(cmd){
case WR_DUTYCYCLE:
writel(arg, ioremap(reg[1], 8));
//printk("test wrdc %lu\n", arg);
back = 0;
break;
case WR_FREQ:
writel(arg, ioremap(reg[1] + 8, 8));
back = 0;
break;
case RD_DUTYCYCLE:
back = readl(ioremap(reg[1], 8));
printk("Valeur ecrite dc : %d", back);
break;
case RD_FREQ:
back = readl(ioremap(reg[1] + 8, 8));
printk("Valeur ecrite : %d", back);
break;
}
return back;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = driver_open,
.release = driver_close,
.unlocked_ioctl = my_ioctl,
};
/**
* @brief This function is called at init for permit all users to call this drivers
*/
static char *mydevnode(struct device *dev, umode_t *mode)
{
if (mode)
*mode = DEV_CLASS_MODE;;
return NULL;
}
/**
* @brief This function is called, when the module is loaded into the kernel
*/
static int __init ModuleInit(void) {
int retval;
printk("Hello, Kernel! test2\n");
/* Allocate a device nr */
if(alloc_chrdev_region(&my_device_nr, 0, 1, DRIVER_NAME) < 0) {
printk("Device Nr. could not be allocated!\n");
return -1;
}
printk("read_write - Device Nr. Major: %d, Minor: %d was registered!\n", my_device_nr >> 20, my_device_nr && 0xfffff);
/* Create device class */
if((my_class = class_create(THIS_MODULE, DRIVER_CLASS)) == NULL) {
printk("Device class can not be created!\n");
goto ClassError;
}
//Activate for all users
my_class->devnode = mydevnode;
/* create device file */
if(device_create(my_class, NULL, my_device_nr, NULL, DRIVER_NAME) == NULL){
printk("Can not create device file!\n");
goto FileError;
}
/* Initialize device file */
cdev_init(&my_device, &fops);
/* Registering device to kernel */
if(cdev_add(&my_device, my_device_nr, 1) == -1) {
printk("Registering of device to kernel failed!\n");
goto AddError;
}
return 0;
AddError:
device_destroy(my_class, my_device_nr);
FileError:
class_destroy(my_class);
ClassError:
unregister_chrdev_region(my_device_nr, 1);
return -1;
}
/**
* @brief This function is called, when the module is removed from the kernel
*/
static void __exit ModuleExit(void) {
cdev_del(&my_device);
device_destroy(my_class, my_device_nr);
class_destroy(my_class);
unregister_chrdev_region(my_device_nr, 1);
printk("Goodbye, Kernel\n");
}
module_init(ModuleInit);
module_exit(ModuleExit);
내가 관심을 갖는 장치 트리는 다음과 같습니다.
amba_pl@0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges ;
pwm1@80000000 {
#gpio-cells = <3>;
clock-names = "s_axi_aclk";
clocks = <&zynqmp_clk 71>;
compatible = "pwm";
gpio-controller ;
reg = <0x0 0x80000000 0x0 0x10000>;
xlnx,all-inputs = <0x1>;
xlnx,all-inputs-2 = <0x1>;
xlnx,all-outputs = <0x0>;
xlnx,all-outputs-2 = <0x0>;
xlnx,dout-default = <0x00000000>;
xlnx,dout-default-2 = <0x00000000>;
xlnx,gpio-width = <0x20>;
xlnx,gpio2-width = <0x20>;
xlnx,interrupt-present = <0x0>;
xlnx,is-dual = <0x1>;
xlnx,tri-default = <0xFFFFFFFF>;
xlnx,tri-default-2 = <0xFFFFFFFF>;
};
pwm0@80010000 {
#gpio-cells = <3>;
clock-names = "s_axi_aclk";
clocks = <&zynqmp_clk 71>;
compatible = "pwm";
gpio-controller ;
reg = <0x0 0x80010000 0x0 0x10000>;
xlnx,all-inputs = <0x0>;
xlnx,all-inputs-2 = <0x0>;
xlnx,all-outputs = <0x1>;
xlnx,all-outputs-2 = <0x1>;
xlnx,dout-default = <0x00000000>;
xlnx,dout-default-2 = <0x00000000>;
xlnx,gpio-width = <0x8>;
xlnx,gpio2-width = <0x20>;
xlnx,interrupt-present = <0x0>;
xlnx,is-dual = <0x1>;
xlnx,tri-default = <0xFFFFFFFF>;
xlnx,tri-default-2 = <0xFFFFFFFF>;
};
};
도와주셔서 감사합니다!
답변1
첫 번째: 부팅 시 드라이버를 로드하고 싶습니다. 프로브 기능에 대해 많이 읽었지만 작동 방식을 이해하지 못합니다. 어떤 사람들은 module-load.r에 대해 이야기하는데 가장 좋은 방법은 무엇입니까?
아마도 /etc/modules-load.d/
디렉토리를 의미했을 것입니다.
하드웨어 검색으로 인해 커널 모듈이 자동으로 로드되지 않거나 다른 모듈이 이에 의존하는 경우 해당 디렉토리에 원하는 모듈 이름이 포함된 텍스트 파일을 생성하여 부팅 시 로드되도록 모듈을 구성할 수 있습니다. 로드하려면 한 줄에 하나의 이름을 입력하세요. 원하는 대로 파일 이름을 지정할 수 있지만 접미사가 있어야 합니다 .conf
.
두 번째는장치 드라이버 개발에 대한 프로그래밍 질문이므로 다음 위치에 배치해야 합니다.스택 오버플로대신에.