/*
* author: chwenj@gmail.com.
* Agreement: GPL.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define GPIO_SET 0xAC
#define GPIO_GET 0xAB
#define DEVICE_FILE "/dev/gpio_cdev"
typedef struct {
unsigned char count; //GPIO序列
unsigned char data; //GPIO电平状态
} gpio_userspace_t;
/*main*/
int main(/* int argc, char **argv */)
{
/*open*/
int gpio_fd, ret;
gpio_fd = open(DEVICE_FILE, O_RDWR); //读写权限打开文件
if (gpio_fd < 0) {
printf("gpio device fail to open.\n");
return -1;
}
printf("%s opend.\n", DEVICE_FILE);
#if 1
/*write*/
gpio_userspace_t write_gpio;
write_gpio.count = 5; //GPIO序列号
write_gpio.data = 1; //GPIO电平值
printf("write: count = %d , data = %d.\n", write_gpio.count, write_gpio.data);
ret = write(gpio_fd, &write_gpio, sizeof(gpio_userspace_t));
if (ret < 0) {
printf("%s fail to write.\n", DEVICE_FILE);
return -1;
}
#endif
/*ioctl*/
gpio_userspace_t ioctl_gpio;
ioctl_gpio.data = 0xff; //level:0xff
ioctl_gpio.count = 5; //pin:4
ret = ioctl(gpio_fd, GPIO_SET, &ioctl_gpio);
if (ret < 0) {
printf("ioctl: ioctl fail.\n");
return -1;
}
/*read*/
gpio_userspace_t read_gpio;
ret = read(gpio_fd, &read_gpio, sizeof(gpio_userspace_t));
if (ret < 0) {
printf("read: fail to read.\n");
return -1;
}
printf("read: count = %d, data = %d.\n", read_gpio.count, read_gpio.data);
/*close*/
close(gpio_fd);
printf("%s close.\n", DEVICE_FILE);
return 0;
}
#include <linux/fs.h>#include <linux/types.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/cdev.h>#include <linux/platform_device.h>#include <linux/utsname.h>#include <asm/uaccess.h>#include <asm/io.h>#include <mach/sys_config.h>#include <mach/includes.h>#include <linux/gpio.h>#include <linux/delay.h>/**********************************************************/#define GPIO_SET 0xAC #define GPIO_GET 0xAB /**********************************************************/script_item_u *gpio_list = NULL;//gpio_userspace_t 和 gpio_pdata_t 在序列上是一一对应的关系.typedef struct { unsigned char count; //IO序列:0,1,2,..., 19. unsigned char data; //IO电平.} gpio_userspace_t;typedef struct { struct gpio_config gpio; char gpio_name[32]; int gpio_cnt;} gpio_pdata_t;typedef struct {//debug tag for printk #define __DEBUG_TAG__ #ifdef __DEBUG_TAG__ #define dprintk(fmt, arg...) printk(fmt, ## arg) #else #define dprintk(fmt, arg...) #endif//char device name: /dev/gpio_cdev #define DEVICE_NAME "gpio_cdev"//multiple #define MUL_SEL_INPUT 0 #define MUL_SEL_OUTPUT 1//char device struct cdev *gpio_cdev; dev_t devid; struct class *gpio_class;//gpio count int gpio_cnt;//general gpio subsystem gpio_pdata_t pin[20];//} gpio_info_t;static gpio_info_t info;//global gpio pin record:char pin_count;/**********************************************************/static int gpio_cdev_open(struct inode *inode, struct file *file){ dprintk("[gpio]: gpio_cdev_open fn.\n");<span style="white-space:pre"> </span>return 0;}static int gpio_cdev_release(struct inode *inode, struct file *file){ dprintk("[gpio]: gpio_cdev_release fn.\n");<span style="white-space:pre"> </span>return 0;}/**********************************************************///writestatic ssize_t gpio_cdev_write(struct file *file, const char __user *buf, \ size_t count, loff_t *ppos){ gpio_userspace_t write_gpio; unsigned char write_data, write_count; dprintk("[gpio]: gpio_cdev_write fn.\n"); copy_from_user(&write_gpio, (gpio_userspace_t *)buf, sizeof(gpio_userspace_t)); write_data = write_gpio.data; write_count = write_gpio.count; dprintk("[gpio][write]: data=%d, count=%d.\n", write_data, write_count); //error correction. if ((write_data != 0) && (write_data != 1)) { dprintk("[gpio][write][error]: write_data invalid.\n"); } if ((write_count < 0) || (write_count >19)) { dprintk("[gpio][write][error]: write_count does not exit.\n"); } gpio_direction_output(info.pin[write_count].gpio.gpio, write_data); //mdelay(1); return 0;}//read static ssize_t gpio_cdev_read(struct file *file, char __user *buf, \ size_t count, loff_t *ppos){ int i; unsigned char data; unsigned int gpio; gpio_userspace_t read_gpio; dprintk("[gpio]: gpio_cdev_read fn.\n");#if 0 gpio_userspace_t read_gpio[20]; for (i = 0; i < 20; i++) { gpio = info.pin[i].gpio.gpio; //调试用;不要轻易打开: #if 0 if(0 != gpio_direction_input(gpio)) { dprintk("set to input failed.\n"); continue; } #endif data = __gpio_get_value(gpio); read_gpio[i].count = i; read_gpio[i].data = data; dprintk("[gpio][read]: pin_%d = %d.\n", read_gpio[i].count, read_gpio[i].data); } copy_to_user(buf, read_gpio, 20*sizeof(gpio_userspace_t));#else i = pin_count; dprintk("[gpio][read]: pin_count = %d.\n", i); gpio = info.pin[i].gpio.gpio; data = __gpio_get_value(gpio); read_gpio.count = i; read_gpio.data = data; dprintk("[gpio][read]: count = %d; data = %d.\n", read_gpio.count, read_gpio.data); copy_to_user(buf, &read_gpio, sizeof(gpio_userspace_t));#endif return 0;}static long gpio_cdev_ioctl(struct file *file, unsigned int cmd, \ unsigned long arg){ dprintk("[gpio]: gpio_cdev_ioctl fn;"); dprintk(" cmd = %d.\n", cmd); void __user *uarg; uarg = (void __user *)arg; gpio_userspace_t ioctl_gpio; copy_from_user(&ioctl_gpio, (gpio_userspace_t *)uarg, sizeof(gpio_userspace_t)); dprintk("[gpio]:count = %d, data = %d.\n", ioctl_gpio.count, ioctl_gpio.data); switch(cmd) { case GPIO_SET: dprintk("[gpio]: ioctl cmd = GPIO_SET.\n"); pin_count = ioctl_gpio.count; dprintk("[gpio]: pin_count = %d.\n", pin_count); if ((pin_count > 19)|| (pin_count < 0)) { dprintk("[gpio][error]: gpio_cdev_ioctl: pin_count invalide.\n"); } break; case GPIO_GET: dprintk("[gpio]: ioctl cmd = GPIO_SET.\n"); break; default: dprintk("[gpio]: ioctl cmd = default.\n"); break; } return 0;}static const struct file_operations gpio_cdev_fops = { .owner = THIS_MODULE, .open = gpio_cdev_open, .release = gpio_cdev_release, .write = gpio_cdev_write, .read = gpio_cdev_read, .unlocked_ioctl = gpio_cdev_ioctl,};static int gpio_fetch_config(void){ char buffer[32] = {}; int i; int cnt = info.gpio_cnt; script_item_value_type_e type; script_item_u val; dprintk("[gpio]: gpio_fetch_config fn.\n"); dprintk("[gpio]: gpio_cnt=%d.\n", cnt); dprintk("--------------------\n"); for(i=0; i< cnt; i++) { //format sprintf sprintf(buffer, "gpio_pin_%d", i); dprintk("[gpio]: buffer=%s.\n", buffer); //fetch gpio_pin_# issue type = script_get_item("gpio_para", buffer, &val); if (SCIRPT_ITEM_VALUE_TYPE_PIO != type) { dprintk("[gpio]: item value type INVALID.\n"); return -1; } else { info.pin[i].gpio.gpio = val.gpio.gpio; info.pin[i].gpio.mul_sel = val.gpio.mul_sel; dprintk("[gpio][pin%d]: gpio=%d, mul_sel=%d, ", i, info.pin[i].gpio.gpio, info.pin[i].gpio.mul_sel); strcpy(info.pin[i].gpio_name, buffer); dprintk("name=%s, ", info.pin[i].gpio_name); info.pin[i].gpio_cnt = i; dprintk("gpio_cnt=%d.\n", info.pin[i].gpio_cnt); dprintk("--------------------\n"); } } dprintk("[gpio]: success to gpio_fetch_config.\n"); return 0;}static int __init gpio_module_init(void){ int ret = 0, err; int cnt = 0, i; script_item_value_type_e type; script_item_u val; dprintk("[gpio]: gpio_module_init fn.\n"); ret = alloc_chrdev_region(&(info.devid), 0, 20, DEVICE_NAME); if ( ret ) { dprintk("[gpio]: fail to alloc_chrdev_region.\n"); return -1; } dprintk("[gpio]: devid major=%d, minor=%d.\n", MAJOR(info.devid), MINOR(info.devid)); info.gpio_cdev = cdev_alloc(); cdev_init(info.gpio_cdev, &gpio_cdev_fops); info.gpio_cdev->owner = THIS_MODULE; err = cdev_add(info.gpio_cdev, info.devid, 1); if (err) { dprintk("[gpio]: cdev_add fail.\n"); return -1; } info.gpio_class = class_create(THIS_MODULE, DEVICE_NAME); if (IS_ERR(info.gpio_class)) { dprintk("[gpio]: class_create fail.\n"); return -1; } <span style="white-space:pre"> </span>device_create(info.gpio_class, NULL, info.devid, NULL, DEVICE_NAME);<span style="white-space:pre"> </span> dprintk("[gpio]: success to create a gpio cdev.\n"); // type = script_get_item("gpio_para", "gpio_used", &val); if (SCIRPT_ITEM_VALUE_TYPE_INT != type) { dprintk("[gpio]: type not right.\n"); return -1; } if (!val.val) { dprintk("[gpio]: gpio is not used.\n"); return -1; } dprintk("[gpio]: gpio is used.\n"); // cnt = script_get_pio_list("gpio_para", &gpio_list); dprintk("[gpio]: cnt = %d.\n", cnt); info.gpio_cnt = cnt; if (cnt == 0) { dprintk("[gpio]: fail to script_get_pio_list.\n"); return -1; } else { dprintk("[gpio]: requeset gpio(s).\n"); for (i=0; i < cnt; i++) { dprintk("[gpio]: requeset gpio No.%d.\n", i+1); if (0 != gpio_request(gpio_list[i].gpio.gpio, NULL)) dprintk("[gpio]: i = %d; fail to gpio_request.\n", i); } } //dprintk("[gpio]: 1.\n"); //config gpio. if (0 != sw_gpio_setall_range(&gpio_list[0], cnt)) { dprintk("[gpio]: fail to sw_gpio_setall_range.\n"); return -1; } //dprintk("[gpio]: 2.\n"); /*************************************************************/ gpio_fetch_config(); //dprintk("[gpio]: 3.\n"); #if 0 //test gpio. gpio_direction_output(info.pin[4].gpio.gpio, 0); mdelay(5); gpio_direction_output(info.pin[4].gpio.gpio, 1); mdelay(5);#endif //dprintk("[gpio]: 4.\n"); <span style="white-space:pre"> </span>return 0;}static void __exit gpio_module_exit(void){ dprintk("[gpio]: gpio_module_exit fn.\n"); <span style="white-space:pre"> </span> device_destroy(info.gpio_class, info.devid); class_destroy(info.gpio_class); cdev_del(info.gpio_cdev);}module_init(gpio_module_init);module_exit(gpio_module_exit);MODULE_AUTHOR("chwenj@gmail.com");MODULE_DESCRIPTION("gpio driver");MODULE_LICENSE("GPL");