Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
// キャラクタデバイスの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