カーネルモジュールの作成

カーネルモジュールの作成

初めてLinuxドライバを作成する必要がありますが、質問がありましたが、便利な答えが見つかりませんでした。私の目標はPWMドライバを作成することです。 IOCTLのおかげで、ドライバを正常に作成して作業しましたが、もう2つやりたいことがありますが、そのうちの1つはどうすればよいかわかりません。

まず、起動時にドライバをロードしたいと思います。私はプローブの機能についてたくさん読んでいましたが、どのように動作するのかわかりません。何人かの人々がmodule-load.rについて話すための最良の方法は何ですか?

2番目の点:そのドライバを使用するデバイスの各デバイスツリー宣言に対して、多くのドライバを作成する必要があります。しかし、各インスタンスに対して/ 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/ディレクトリを意味したでしょう。

ハードウェア検索によってカーネルモジュールが自動的にロードされない場合、または他のモジュールがそれに依存している場合は、そのディレクトリに必要なモジュール名を含むテキストファイルを作成して、起動時にロードするようにモジュールを設定できます。読み込むには、1行に1つの名前を入力してください。必要に応じてファイル名を指定できますが、サフィックスが必要です.conf

二つ目はデバイスドライバの開発に関するプログラミングの質問したがって、次の場所に配置する必要があります。スタックオーバーフロー代わりに。

関連情報