結論から言うと、Raspberry piで学ぶARMデバイスドライバプログラミングの本の方法は、
最新のカーネルに対応していなかった。
# insmod leddriver.ko
すると、request_mem_region()で落ちてしまう。
最新の方法はこっち
http://d.hatena.ne.jp/seinzumtode/20171020/1508476422
#include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/kdev_t.h> #include <linux/errno.h> #include <linux/cdev.h> #include <linux/sched.h> #include <linux/stat.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/version.h> #include <linux/device.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/uaccess.h> #define BLOCK_SIZE 4096 #define REG_BASE 0x3F200000 #define GPIO_BASE (REG_BASE+0x200000) #define FSEL0_INDEX 0 #define FSEL2_INDEX 0x02 #define SET0_INDEX 0x07 #define CLR0_INDEX 0x0A #define GPF_OUTPUT 0x01 #define PINNUM 27 MODULE_AUTHOR("Shohei Aoki"); MODULE_LICENSE("Dual BSD/GPL"); #define NUM_DEVS 1 #define NMAJOR 0 #define NMINOR 0 #define DEVNAME "awesomeled" static int major = NMAJOR; static int minor = NMINOR; static struct cdev *cdev_array = NULL; static struct class *led_class = NULL; #define GPIO_MAPNAME "gpio_map" static void __iomem *gpio_map; static volatile uint32_t *gpio_base; static int led_gpio_map(void) { if(!request_mem_region(GPIO_BASE,BLOCK_SIZE,GPIO_MAPNAME)){ printk(KERN_ALERT "request mem region failed\n"); return -EBUSY; } gpio_map = ioremap_nocache(GPIO_BASE,BLOCK_SIZE); gpio_base = (volatile uint32_t *) gpio_map; } static int gpio_unmap(void) { iounmap(gpio_map); release_mem_region(GPIO_BASE,BLOCK_SIZE); gpio_map = NULL; gpio_base = NULL; return 0; } static int function_set(int pin, uint32_t func) { //int index = FSEL0_INDEX + pin/10; int index = FSEL2_INDEX; uint32_t mask = ~(0x7 << ((pin % 10) * 3)); uint32_t masked = (gpio_base[index] & mask); uint32_t added = (func & 0x7) << ((pin % 10) * 3); uint32_t final = masked | added; gpio_base[index] = final; return 1; } static int setpin(int pin) { gpio_base[SET0_INDEX] = 1 << pin; } static int clearpin(int pin) { gpio_base[CLR0_INDEX] = 1 << pin; } static int led_open(struct inode *inode, struct file *filep) { int retval; if(gpio_base != NULL){ printk(KERN_ERR "led is already open.\n"); return -EIO; } retval = led_gpio_map(); if(retval!=0){ printk(KERN_ERR "Cannot open led.\n"); return retval; } return 0; } static int led_release(struct inode *inode, struct file *filep) { gpio_unmap(); return 0; } static ssize_t led_write( struct file *filep, const char __user *buf, size_t count, loff_t *f_pos) { char cvalue; int retval; if(count>0){ if(copy_from_user(&cvalue, buf, sizeof(char))){ return -EFAULT; } int i; int num = cvalue - '0'; //hack of ctoi() for(i=0;i<num;i++){ setpin(PINNUM); msleep(100); clearpin(PINNUM); msleep(100); } return sizeof(char); } return 0; } struct file_operations led_fops = { .open = led_open, .release = led_release, .write = led_write, }; static int led_register_dev(void) { int retval; dev_t dev; size_t size; int i; retval = alloc_chrdev_region( &dev, NMINOR, NUM_DEVS, DEVNAME ); if(retval<0){ printk(KERN_ERR "alloc chrdev region failed\n"); return retval; } major = MAJOR(dev); led_class = class_create(THIS_MODULE, DEVNAME); if(IS_ERR(led_class)) return PTR_ERR(led_class); size = sizeof(struct cdev) * NUM_DEVS; cdev_array = (struct cdev*) kmalloc(size, GFP_KERNEL); for (i=0;i<NUM_DEVS;i++){ dev_t devno = MKDEV(major,minor+i); cdev_init(&(cdev_array[i]),&led_fops); cdev_array[i].owner = THIS_MODULE; if(cdev_add(&(cdev_array[i]),devno,1) < 0){ printk(KERN_ERR "cdev add failed minor = %d\n",minor+i); } else { device_create( led_class, NULL, devno, NULL, DEVNAME"%u",minor+i ); } } return 0; } static int led_init(void) { int retval; int i; printk(KERN_INFO "%s loading...\n", DEVNAME); retval = led_gpio_map(); if(retval!=0){ printk(KERN_ALERT "Can not use GPIO registers\n"); return -EBUSY; } function_set(PINNUM, GPF_OUTPUT); for(i=0;i<10;i++){ msleep(50); } return 0; } static void led_exit(void) { int i; dev_t devno; for(i=0;i<NUM_DEVS;i++){ cdev_del(&(cdev_array[i])); devno = MKDEV(major,minor+i); device_destroy(led_class,devno); } devno = MKDEV(major,minor); unregister_chrdev_region(devno, NUM_DEVS); class_destroy(led_class); kfree(cdev_array); } module_init(led_init); module_exit(led_exit);