This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// キャラクタデバイスのGPIOデバイスドライバ(cdev) | |
#define SUCCESS 0 | |
#define NODE_NAME "Ext_GPIO" | |
#define MY_BUFF_SIZE 4096 | |
#define MAP_SIZE (0x10000) | |
#define MAP_BASE_ADDR (0x41200000) | |
#define BTN_PIO_BASE (0x00000) | |
#define LED_PIO_BASE (0x10000) | |
#define DIP_PIO_BASE (0x20000) | |
#define LED_PIO_DATA_OFFSET (0x0) | |
#define DIP_PIO_DATA_OFFSET (0x0) | |
#define BTN_PIO_DATA_OFFSET (0x0) | |
#include <linux/delay.h> | |
#include <linux/irq.h> | |
#include <linux/uaccess.h> | |
#include <linux/io.h> | |
#include <linux/gpio.h> | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/init.h> | |
#include <linux/mm.h> | |
#include <linux/fs.h> | |
#include <linux/types.h> | |
#include <linux/delay.h> | |
#include <linux/moduleparam.h> | |
#include <linux/slab.h> | |
#include <linux/errno.h> | |
#include <linux/ioctl.h> | |
#include <linux/cdev.h> | |
#include <linux/string.h> | |
#include <linux/list.h> | |
#include <linux/gpio.h> | |
#include <linux/device.h> | |
MODULE_LICENSE("Dual BSD/GPL"); | |
static int major_num = 0; | |
static const int minor_num = 32; | |
static const int minor_je = 24; | |
static struct cdev char_cdev; | |
static struct class *char_class = NULL; | |
#define MY_BUF_SIZE 1024 | |
static unsigned char k_buf[MY_BUF_SIZE]; | |
static int pos; | |
static int read_count = 0; | |
static unsigned long gpio_table [] = { | |
MAP_BASE_ADDR + BTN_PIO_BASE + BTN_PIO_DATA_OFFSET, | |
MAP_BASE_ADDR + DIP_PIO_BASE + DIP_PIO_DATA_OFFSET, | |
0, | |
MAP_BASE_ADDR + LED_PIO_BASE + LED_PIO_DATA_OFFSET | |
}; | |
typedef struct my_buff { | |
int bit; | |
int mode; | |
void *cookie; | |
} GPIO_BUFF; | |
static int char_open (struct inode *inode, struct file *filp) | |
{ | |
int minor = MINOR(inode->i_rdev); | |
int bit = minor & 0x1F; | |
int mode = (minor & 0x10) ? 1 : 0; // Read : 0, Write : 1 | |
void *cookie = ioremap(gpio_table[bit >> 3], MAP_SIZE); | |
GPIO_BUFF *GpioBuff; | |
if ( bit >= 16 && bit <= 23) { | |
printk("Illegal minor number! MINOR Number = %d\n", minor); | |
return -EINVAL; | |
} | |
GpioBuff = (GPIO_BUFF *)kmalloc (sizeof(GPIO_BUFF), GFP_KERNEL); | |
GpioBuff -> bit = bit; | |
GpioBuff -> mode = mode; | |
GpioBuff -> cookie = cookie; | |
filp->private_data = GpioBuff; | |
printk ("----- This is the Open Function -----\n"); | |
printk ("Node NAME: %s:\n", NODE_NAME); | |
printk ("MAJOR Number = %d, MINOR Number = %d\n", | |
MAJOR (inode->i_rdev), minor); | |
printk ("Open device successfully: %s:\n\n", NODE_NAME); | |
printk ("\n"); | |
return SUCCESS; | |
} | |
static int char_release (struct inode *inode, struct file *filp) | |
{ | |
GPIO_BUFF *GpioBuff = (GPIO_BUFF *)filp->private_data; | |
kfree(GpioBuff); | |
printk ("----- This is the Close Function -----\n"); | |
printk ("Closing device: %s:\n\n", NODE_NAME); | |
printk ("\n"); | |
read_count = 0; | |
return SUCCESS; | |
} | |
ssize_t char_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos) | |
{ | |
volatile unsigned int mode_port; | |
unsigned int port_data = 0; | |
void *cookie; | |
char read_buff[2] = {'0', '\n'}; | |
GPIO_BUFF *GpioBuff = (GPIO_BUFF *)filp -> private_data; | |
int ret, bit; | |
if (read_count) { | |
return 0; | |
} | |
mode_port = GpioBuff -> mode; | |
if (mode_port == 1) { | |
printk("This GPIO is Output!! No use read func.\n"); | |
return -EFAULT; | |
} | |
printk ("----- This is the READ function -----\n"); | |
GpioBuff = filp->private_data; | |
bit = GpioBuff -> bit; | |
printk("bit=%d\n", bit); | |
cookie = GpioBuff -> cookie; | |
port_data = ioread32(cookie); | |
if ((~port_data & (0x00000001 << (bit & 0x03)))) { | |
read_buff[0] = '0'; | |
} else { | |
read_buff[0] = '1'; | |
} | |
if (copy_to_user(buf, read_buff, count)) { | |
printk("Copy_to_user Error!!\n"); | |
return -EFAULT; | |
} | |
printk ("\n"); | |
ret = 2; | |
read_count++; | |
return ret; | |
} | |
ssize_t char_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) | |
{ | |
volatile unsigned int mode_port; | |
// unsigned int value; | |
void *cookie; | |
// unsigned int val; | |
const unsigned int VAL[] = { | |
0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10 | |
}; | |
GPIO_BUFF *GpioBuff = (GPIO_BUFF *)filp -> private_data; | |
// int bit; | |
mode_port = GpioBuff -> mode; | |
if (mode_port == 0) { | |
printk("This GPIO is Input!! No use write func.\n"); | |
return -EFAULT; | |
} | |
printk ("---- This is the WRITE function -----\n"); | |
if (copy_from_user(k_buf, buf, count)) { | |
printk( "copy_from_user failed\n"); | |
return -EFAULT; | |
} | |
printk ("\n"); | |
if (k_buf[0] != '0' || k_buf[1] != 'x' || count <= 3) { | |
printk("k_buf is bad format!! k_buf is %s\n", k_buf); | |
return -EFAULT; | |
} | |
cookie = GpioBuff -> cookie; | |
wmb(); | |
if (('0' <= k_buf[2]) && (k_buf[2] <= '9')) { | |
printk("WRITE %02x\n", (unsigned char)VAL[k_buf[2] - '0']); | |
iowrite32( VAL[k_buf[2] - '0'], cookie); | |
} | |
pos = count; | |
printk(KERN_ALERT"k_buf is %s pos = %d\n", k_buf, pos); | |
return count; | |
} | |
struct file_operations char_fops = { | |
.read = char_read, | |
.write = char_write, | |
.open = char_open, | |
.release = char_release | |
}; | |
static int char_init_module(void) | |
{ | |
dev_t dev = MKDEV(major_num, 0); | |
dev_t char_dev; | |
int major_num_ret; | |
int cdev_ret = 0; | |
major_num_ret = alloc_chrdev_region(&dev, 0, minor_num, NODE_NAME); | |
if (major_num_ret < 0) { | |
printk ("Failed chrdev region %d\n", major_num_ret); | |
unregister_chrdev_region(dev, minor_num); | |
return major_num_ret; | |
} | |
major_num = major_num_ret = MAJOR(dev); | |
cdev_init(&char_cdev, &char_fops); | |
char_cdev.owner = THIS_MODULE; | |
cdev_ret = cdev_add(&char_cdev, MKDEV(major_num, 0), minor_num); | |
if (cdev_ret < 0) { | |
printk ("Failed cdev add %d\n", cdev_ret); | |
cdev_del(&char_cdev); | |
return cdev_ret; | |
} | |
/* register class */ | |
char_class = class_create(THIS_MODULE, "zybo_gpio"); | |
if (IS_ERR(char_class)) { | |
printk ("Failed class_create\n"); | |
return -1; | |
} | |
char_dev = MKDEV(major_num, minor_je); | |
device_create(char_class, NULL, char_dev, NULL, "zybo_gpio"); | |
printk ("Device registered successfully, Major No. = %d\n", major_num); | |
return 0; | |
} | |
static void char_exit_module (void) | |
{ | |
dev_t dev = MKDEV(major_num, 0); | |
dev_t char_dev = MKDEV(major_num, minor_je); | |
/* unregister class */ | |
device_destroy(char_class, char_dev); | |
class_destroy(char_class); | |
cdev_del(&char_cdev); | |
unregister_chrdev_region(dev, minor_num); | |
printk ("Device unregistered successfully, Major No. = %d\n", major_num); | |
} | |
module_init(char_init_module); | |
module_exit(char_exit_module); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment