/*
* drivers/char/arisc_test/arisc_test.c
* (C) Copyright 2010-2015
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* sunny <sunny@allwinnertech.com>
*
* sun6i arisc test driver
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
*/
#include "sunxin_gpio.h"
#include <asm/div64.h>
#include <linux/math64.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/atmel_pdc.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/slab.h>
#include <asm/system.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-sunxi.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <mach/sys_config.h>
#include <mach/platform.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/input.h>
#include <linux/keyboard.h>
#include <linux/ioport.h>
#include <asm/irq.h>
#include <mach/sys_config.h>
#include <mach/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/pinconf-sunxi.h>
#include <linux/clk/sunxi.h>
#include <linux/err.h>
//usrlink.h
//Created on: 2014 Author: cr
#ifndef USRLINK_H_
#define USRLINK_H_
#define USER_NETLINK_CMD 25
#define MAXMSGLEN 1024
typedef enum error_e {
NET_ERROR,
NET_OK,
NET_PARAM,
NET_MEM,
NET_SOCK,
} netlink_err;
typedef enum module_e {
HELLO_CMD = 1,
} netlink_module;
typedef enum type_e {
HELLO_SET,
HELLO_GET,
} netlink_type;
#endif /* USRLINK_H_ */
#define gpio_MAJOR 225
#define DEVICE_NAME "gpioctl"
#undef DEBUG_GPIO
static u32 led_hdler[32];
static char *main_key1 = "maxim_rst_para";
static char *led_key1[32] = {
"rst_gpio",
"user3v3_en",
"in_2",
"in_3",
"uart_tx_io",
"uart_rx_io",
"uart_tx_r",
"uart_rx_r",
"spi_din_io",
"spi_dout_io",
"spi_clk_io",
"spi_cs0_io",
"spi_din_r",
"spi_dout_r",
"spi_clk_r",
"spi_cs0_r",
"twi_scl",
};
static struct fasync_struct *fasync_queue;
static bool led_status;
static struct timer_list button_timer_in0;
static struct timer_list button_timer_in1;
static unsigned int timer_on_in0;
static unsigned int timer_on_in1;
static unsigned int g_input;
static struct timer_list gpioctl_timer;
static u32 hdler_in0,hdler_in1;
static u32 isr_num[2]={0,0};
static struct semaphore sem;
static void gpioctl_do_events (struct work_struct *work);
static struct workqueue_struct *gpioctl_wq;
static DECLARE_WORK(gpioctl_do_work, gpioctl_do_events);
static spinlock_t ioctrl_lock;
static int sunxi_gpio_req_ioctrl(struct gpio_config *gpio);
/*
* netlink.c
*
* Created on: 2014 * Author: cr
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/netlink.h>
#include <net/sock.h>
//#include "usrlink.h"
//MODULE_LICENSE("Dual BSD/GPL");
//MODULE_AUTHOR("MDAXIA");
struct sock *netlink_fd;
static struct pin_desc *irq_pd;
static struct input_dev *sunxi_buttons_dev;
static struct timer_list buttons_timer;
//static int key_state[2];
static int key_repeat_report[2];
static unsigned long timeout_0 = 0x00;
static unsigned long timer_cnt_0 = 0x00;
static unsigned long timeout_1 = 0x00;
static unsigned long timer_cnt_1 = 0x00;
static void netlink_to_user(int dest, void *buf, int len)
{
struct nlmsghdr *nl;
struct sk_buff *skb;
int size;
//printk( "dest = %d.\n", dest );
size = NLMSG_SPACE(len);
skb = alloc_skb(size, GFP_ATOMIC);
if(!skb || !buf)
{
printk(KERN_ALERT "netlink_to_user skb of buf null!\n");
return;
}
nl = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0);
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_group = 0;
memcpy(NLMSG_DATA(nl), buf, len);
nl->nlmsg_len = (len > 2) ? (len - 0):len;
netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT);
//printk(KERN_ALERT "K send packet success\n");
}
static int process_hello_get(int dest, void *buf, int len)
{
printk(KERN_ALERT "In process_hello get!\n");
memcpy(buf, "I known you !", 13);
netlink_to_user(dest, buf, 13);
return NET_OK;
}
static int process_hello_set(int dest, void *buf, int len)
{
//printk( "In process_hello set! %s\n", (char *)buf);
//memcpy(buf, "S known you !", 13);
netlink_to_user(dest, buf, len);
return NET_OK;
}
static void netlink_process_packet(struct nlmsghdr *nl)
{
int ret;
switch(nl->nlmsg_type)
{
case HELLO_GET:
printk( "process_hello_get.\n" );
ret = process_hello_get(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
break;
case HELLO_SET:
printk( "process_hello_set.\n" );
ret = process_hello_set(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
break;
default:break;
}
}
static void netlink_recv_packet(struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlhdr;
skb = skb_get(__skb);
if(skb->len >= sizeof(struct nlmsghdr))
{
nlhdr = (struct nlmsghdr *)skb->data;
if(nlhdr->nlmsg_len >= sizeof(struct nlmsghdr) &&
__skb->len >= nlhdr->nlmsg_len)
{
netlink_process_packet(nlhdr);
}
}
else
printk(KERN_ALERT "Kernel receive msg length error!\n");
}
#if 0
static int __init netlink_init(void)
{
netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);
if(NULL == netlink_fd)
{
printk(KERN_ALERT "Init netlink!\n");
return -1;
}
printk(KERN_ALERT "Init netlink success!\n");
return 0;
}
static void __exit netlink_exit(void)
{
netlink_kernel_release(netlink_fd);
printk(KERN_ALERT "Exit netlink!\n");
}
#endif
static void demo_exit(void);
static struct tasklet_struct my_tasklet;
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int flag =0;
ssize_t sleepy_read( void )
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",current->pid,current->comm);
wait_event_interruptible(wq,flag!=0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s) \n",current->pid,current->comm);
return 0;
}
ssize_t sleepy_write(void)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers ...\n",current->pid,current->comm);
flag = 1;
wake_up_interruptible(&wq);
return 0;
//³É¹¦²¢±ÜÃâÖØÊÔ
}
// tasklet´¦Àíº¯Êý
static void tasklet_handler (unsigned long data)
{
printk(KERN_ALERT "tasklet_handler is running.\n");
sleepy_read();
sleepy_write();
}
static int demo_init(void)
{
// ³õʼ»¯tasklet
tasklet_init(&my_tasklet, tasklet_handler, 0);
// µ÷¶Ètasklet´¦Àí³ÌÐò
tasklet_schedule(&my_tasklet);
printk(KERN_ALERT "demo_init.\n");
//demo_exit();
return 0;
}
static void demo_exit(void)
{
// Ïú»Ùtasklet
tasklet_kill(&my_tasklet);
printk(KERN_ALERT "demo_exit.\n");
}
static void timer_dowork(void)
{
//printk( "add gpioctl_dowork\n");
mod_timer(&gpioctl_timer, jiffies + HZ);
//printk( "pin_value = 0x%x.\n", pin_value );
demo_init();
}
static void gpioctl_do_events (struct work_struct *work)
{
int ret = 0;
printk( "add gpioctl_do_events\n");
gpioctl_timer.expires = jiffies + HZ;
gpioctl_timer.data = 100;
gpioctl_timer.function = timer_dowork;
add_timer(&gpioctl_timer);
return;
}
/
#if 1
static void set_gpio_status(int handler, bool status)
{
gpio_set_value(handler, status);
}
static int get_gpio_status(int handler)
{
return gpio_get_value(handler);
}
static void set_led_status(unsigned long arg)
{
int i;
led_status = led_status ? false : true;
for( i = 0; i < 1; i++ ){
set_gpio_status(led_hdler[i], arg);
}
}
//GPIO read
static ssize_t gpio_rd (struct file *file, char *buf, size_t count, loff_t *offset)
{
int ret;
int io_status;
//led_status = led_status ? false : true;
printk( KERN_NOTICE "count = %d.\r\n", count );
//printk( KERN_NOTICE "led_status = %x.\r\n", led_status );
//set_gpio_status(led_hdler[1], led_status);
struct regulator *ldo_dcdc1;
memset( buf, 0, count );
ldo_dcdc1 = regulator_get(NULL,"axp22_dcdc1");
if( IS_ERR(ldo_dcdc1) ){
printk("nand:some error happen, fail to get regulator axp22_dcdc1!");
return -1;
}
//set output voltage to 3.0V
//ret = regulator_set_voltage(regu1,3000000,3000000);
//dp_mcu
ret = regulator_set_voltage(ldo_dcdc1, 3100000, 3100000);
printk( KERN_NOTICE "ret = %d.\r\n", ret );
return count;
}
//PB7_PCM0_DIN_EINT7_LS_INT RST sw_uart_check_baudset
//the 15 pin, ctrl the maxim
//GPIO Write
static ssize_t gpio_wr(struct file *file, const char *buf, size_t count, loff_t *offset)
{
if( buf[0]==0x00 || buf[0]==0x01 ){
set_led_status(buf[0]);
}
printk( KERN_NOTICE "buf[0] = %x.\r\n", buf[0] );
printk( KERN_NOTICE "count = %x.\r\n", count );
return count;
}
static void set_all_cfg_io( void )
{
int io_status = 0;
int ret = 0;
unsigned long flags;
unsigned char buf[128];
unsigned char *sendstr = "12345";
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i;
//ÅäÖÃËùÓÐgpioΪÆÕͨio¿Ú,²¢ÇÒÖÃΪµÍµçƽ
//printk( "cfg to io.\n" );
for( i = 4; i < 6; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 8; i < 12; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 16; i < 17; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
set_gpio_status(led_hdler[4], 0);
set_gpio_status(led_hdler[5], 0);
set_gpio_status(led_hdler[8], 0);
set_gpio_status(led_hdler[9], 0);
set_gpio_status(led_hdler[10], 0);
set_gpio_status(led_hdler[11], 0);
set_gpio_status(led_hdler[16], 0);
}
static long gpio_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{
int io_status = 0;
int ret = 0;
unsigned long flags;
unsigned char buf[128];
unsigned char *sendstr = "12345";
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i;
//printk( "cmd = %d, arg = %d.\n", cmd, arg );
switch ( cmd )
{
case 0:
if( arg==0x00 || arg==0x01 ){
set_gpio_status(led_hdler[0], arg);
}
break;
case 1:
if( arg==0x00 || arg==0x01 ){
set_gpio_status(led_hdler[1], arg);
}
break;
case 3:
//printk( "cfg to io.\n" );
for( i = 4; i < 6; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 8; i < 12; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 16; i < 17; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
set_gpio_status(led_hdler[4], 0);
set_gpio_status(led_hdler[5], 0);
set_gpio_status(led_hdler[8], 0);
set_gpio_status(led_hdler[9], 0);
set_gpio_status(led_hdler[10], 0);
set_gpio_status(led_hdler[11], 0);
set_gpio_status(led_hdler[16], 0);
break;
case 5:
//printk( "cfg to spec.\n" );
for( i = 6; i < 8; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 12; i < 16; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
//set_gpio_status(led_hdler[2], 0);
//set_gpio_status(led_hdler[3], 0);
break;
case 0x06:
if( arg == 0x00 ){
//»ñÈ¡°´¼üÖµ 2¸ö
ret = g_input;
spin_lock_irqsave(&ioctrl_lock, flags);
g_input = 0x00;
spin_unlock_irqrestore(&ioctrl_lock, flags);
return ret;
}else{
//Çå³ý°´¼ü´¦Àí
if( arg==1 || arg==2 || arg==3 ){
spin_lock_irqsave(&ioctrl_lock, flags);
g_input = g_input & (~arg);
spin_unlock_irqrestore(&ioctrl_lock, flags);
}
return 0x00;
}
break;
case 0x07:
if( arg == 0x00 ){
//»ñÈ¡°´¼üÖµ 2¸ö
int pin_value,temp,temp1;
temp = get_gpio_status(led_hdler[2]);
//printk( "pin_value2[%d].\n", temp );
//printk( "led_hdler[2][%d].\n", led_hdler[2] );
temp1 = get_gpio_status(led_hdler[3]);
//printk( "pin_value3[%d].\n", temp1 );
//printk( "led_hdler[3][%d].\n", led_hdler[3] );
pin_value = (temp<<1) | temp1;
return pin_value;
}else{
return 0x00;
}
break;
case 0x08:
//(int dest, void *buf, int len)
buf[0] = '1';
buf[1] = '2';
buf[2] = '3';
buf[3] = '4';
memcpy( buf, sendstr, strlen(sendstr) );
buf[strlen(sendstr)] = '\0';
//printk( "strlen(sendstr)[%d].\n", strlen(sendstr) );
process_hello_set( 1, buf, strlen(sendstr) );
//ÄÚºËÖ÷¶¯·¢ËÍÏûÏ¢¸ø1ºÅÓ¦ÓóÌÐò
break;
//spi_gpio_cleanup
//uart_state
default:
printk(KERN_NOTICE"The value of CMD = %d is err,must < 6\r\n",cmd);
return -2;
break;
}
return io_status;
}
static int sunxi_gpio_req_ioctrl(struct gpio_config *gpio)
{
int ret = 0;
char pin_name[8] = {0};
unsigned long config;
sunxi_gpio_to_name(gpio->gpio, pin_name);
//printk( "pin_name = %s.\n", pin_name );
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, gpio->mul_sel);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
printk("set gpio %s mulsel failed.\n",pin_name);
return -1;
}
if( gpio->pull != GPIO_PULL_DEFAULT ){
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, gpio->pull);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
printk("set gpio %s pull mode failed.\n",pin_name);
return -1;
}
}
if( gpio->drv_level != GPIO_DRVLVL_DEFAULT ){
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, gpio->drv_level);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
printk("set gpio %s driver level failed.\n",pin_name);
return -1;
}
}
if( gpio->data != GPIO_DATA_DEFAULT ){
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, gpio->data);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
printk("set gpio %s initial val failed.\n",pin_name);
return -1;
}
}
return 0;
}
static int gpio_fasync(int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &fasync_queue);
if( retval < 0 ){
return retval;
}
return 0;
}
//g_input = g_input | 0x04;
//kill_fasync(&fasync_queue, SIGIO, POLL_IN);
//ÉèÖüü´¦Àí
static void button_jitter_in0( void )
{
int pin_value_0, pin_value_1;
unsigned long flags;
spin_lock_irqsave(&ioctrl_lock, flags);
pin_value_0 = gpio_get_value(hdler_in0);
//»ñÈ¡´Ë¿ÌµÄÉèÖüüÖµ
if( pin_value_0 == 0x00 ){
//°´ÏÂ״̬
if( time_before(jiffies, timeout_0+200) ){
//»¹Ã»Óг¬Ê±2S
}else{
//ÒѾ³¬Ê±
if( key_repeat_report[0] == 0x00 ){
pin_value_1 = gpio_get_value(hdler_in1);
//×éºÏ³¤°´ÅжÏ
if( pin_value_1 == 0x00 ){
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,0);
input_sync(sunxi_buttons_dev);
key_repeat_report[0]++;
key_repeat_report[1] = 0x01;
printk( "key0 zuhe.\n" );
}else{
input_event(sunxi_buttons_dev,EV_KEY,KEY_F13,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F13,0);
input_sync(sunxi_buttons_dev);
key_repeat_report[0]++;
printk( "key0 long.\n" );
//printk( "pin_value_in03 = 0x%x.\n", pin_value );
}
}
}
timer_cnt_0++;
//½øÈ붨ʱÆ÷´ÎÊý¼Ó1
mod_timer( &button_timer_in0, jiffies + msecs_to_jiffies(100) );
}else{
if( timer_cnt_0 == 0 ){
//Ïû¶¶ÎÞÓð´¼ü
//µÚÒ»¸ö100ms½øÀ´,°´¼ü¾ÍÊÍ·ÅÁË,˵Ã÷Êǰ´¼ü¶¶¶¯
}else{
//°´¼üÒѾÊÍ·Å
if( time_before(jiffies, timeout_0+200) ){
//»¹Ã»Óг¬Ê±,¶Ì°´
//ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´ÏÂ
if( key_repeat_report[0] == 0x00 ){
input_event(sunxi_buttons_dev,EV_KEY,KEY_F14,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F14,0);
input_sync(sunxi_buttons_dev);
printk( "key0 short.\n" );
}
//printk( "pin_value_in02 = 0x%x.\n", pin_value );
}
}
key_repeat_report[0]=0x00;
timer_on_in0 = 0;
//¿ÉÒÔÔÙ´ÎÏìÓ¦ÖжÏÁË
}
spin_unlock_irqrestore(&ioctrl_lock, flags);
}
//·µ»Ø¼ü´¦Àí
static void button_jitter_in1(void)
{
int pin_value_0, pin_value_1;
unsigned long flags;
spin_lock_irqsave( &ioctrl_lock, flags );
pin_value_1 = gpio_get_value(hdler_in1);
//»ñÈ¡´Ë¿ÌµÄ·µ»Ø¼üÖµ
//printk( "pin_value_in1 = 0x%x.\n", pin_value );
if( pin_value_1 == 0x00 ){
//°´ÏÂ״̬
if( time_before(jiffies, timeout_1+200) ){
//»¹Ã»Óг¬Ê±2S
}else{
//ÒѾ³¬Ê±
if( key_repeat_report[1] == 0x00 ){
//ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´ÏÂ
pin_value_0 = gpio_get_value(hdler_in0);
//×éºÏ³¤°´ÅжÏ
if( pin_value_0 == 0x00 ){
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,0);
input_sync(sunxi_buttons_dev);
key_repeat_report[0] = 0x01;
key_repeat_report[1]++;
printk( "key1 zuhe.\n" );
}else{
input_event(sunxi_buttons_dev,EV_KEY,KEY_F16,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F16,0);
input_sync(sunxi_buttons_dev);
key_repeat_report[1]++;
printk( "key1 long.\n" );
//printk( "pin_value_in03 = 0x%x.\n", pin_value );
}
}
}
timer_cnt_1++;
//½øÈ붨ʱÆ÷´ÎÊý¼Ó1
mod_timer( &button_timer_in1, jiffies + msecs_to_jiffies(100) );
}else{
if( timer_cnt_1 == 0 ){
//Ïû¶¶ÎÞÓð´¼ü
//µÚÒ»¸ö100ms½øÀ´,°´¼ü¾ÍÊÍ·ÅÁË,˵Ã÷Êǰ´¼ü¶¶¶¯
}else{
//°´¼üÒѾÊÍ·Å
if( time_before(jiffies, timeout_1+200) ){
//»¹Ã»Óг¬Ê±,¶Ì°´
//ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´ÏÂ
if( key_repeat_report[1] == 0x00 ){
input_event(sunxi_buttons_dev,EV_KEY,KEY_F15,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F15,0);
input_sync(sunxi_buttons_dev);
printk( "key1 short.\n" );
}
}
}
key_repeat_report[1]=0x00;
timer_on_in1 = 0;
//¿ÉÒÔÔÙ´ÎÏìÓ¦ÖжÏÁË
}
spin_unlock_irqrestore(&ioctrl_lock, flags);
}
static irqreturn_t test_sunxi_pinctrl_irq_handler_in0(int irq, void *dev_id)
{
unsigned long flags;
//printk("[%s] handler for test pinctrl eint api.\n",__func__);
//disable_irq_nosync(irq);
spin_lock_irqsave(&ioctrl_lock, flags);
if( key_repeat_report[0] ){
key_repeat_report[0] = 0x00;
goto exit;
}
if( timer_on_in0 == 0x00 ){
g_input = 0x00;
//ÇåÁãËùÓÐ״̬
key_repeat_report[0] = 0x00;
//ÖØ¸´±¨¸æÇåÁã
timeout_0 = jiffies;
//»ñȡʱ¼ä´Á
timer_cnt_0 = 0x00;
//¶¨Ê±Æ÷½øÈë´ÎÊýÇåÁã
button_timer_in0.expires = jiffies + 10;
button_timer_in0.data = 100;
button_timer_in0.function = button_jitter_in0;
add_timer(&button_timer_in0);
timer_on_in0 = 1;
}
exit:
spin_unlock_irqrestore(&ioctrl_lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t test_sunxi_pinctrl_irq_handler_in1(int irq, void *dev_id)
{
unsigned long flags;
spin_lock_irqsave( &ioctrl_lock, flags );
if( key_repeat_report[1] ){
key_repeat_report[1] = 0x00;
goto exit;
}
if( timer_on_in1 == 0x00 ){
g_input = 0x00;
//ÇåÁãËùÓÐ״̬
key_repeat_report[1] = 0x00;
//ÖØ¸´±¨¸æÇåÁã
timeout_1 = jiffies;
//»ñȡʱ¼ä´Á
timer_cnt_1 = 0x00;
//¶¨Ê±Æ÷½øÈë´ÎÊýÇåÁã
button_timer_in1.expires = jiffies + 10;
button_timer_in1.data = 100;
button_timer_in1.function = button_jitter_in1;
add_timer(&button_timer_in1);
timer_on_in1 = 1;
}
exit:
spin_unlock_irqrestore(&ioctrl_lock, flags);
return IRQ_HANDLED;
}
static int sunxi_gpio_eint_test_ioctrl_in0( struct platform_device *pdev )
{
unsigned long arg;
//test_pinctrl_eint_api
//request_irq
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i, pin_index,ret;
int virq;
struct device *dev = &pdev->dev;
#if 0
printk("\n");
printk("\n");
printk("\n");
#endif
type = script_get_item(main_key1, "in_0", &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, "in_0" );
}
#if 0
printk( "type = %d.\n", type );
printk( "val.val = %d.\n", val.val );
printk( "val.str = %s.\n", val.str );
printk( "val.gpio.gpio = %d.\n", val.gpio.gpio );
printk( "val.gpio.mul_sel = %d.\n", val.gpio.mul_sel );
printk( "val.gpio.pull = %d.\n", val.gpio.pull );
#endif
gpio_p = &val.gpio;
pin_index = gpio_p->gpio;
//printk( "GPIOB(6) = %d.\n", GPIOB(6) );
//printk( "pin_index = %d.\n", pin_index );
if( pin_index == 0 ){
printk("gpio led_hdl[%d] failed.\n", pin_index);
}
//mdelay
sunxi_gpio_req_ioctrl(gpio_p);
//ÅäÖÃgpio¿ÚΪÖжÏÊäÈëģʽ
virq = gpio_to_irq(pin_index);
//»ñÈ¡¶ÔÓ¦¶Ë¿ÚµÄÖжϺÅ
//printk( "virq = %d.\n", virq );
//printk( "IS_ERR_VALUE(virq) = %d.\n", IS_ERR_VALUE(virq) );
if (IS_ERR_VALUE(virq)){
printk("map gpio [%d] to virq [%d] failed !\n ",pin_index,virq);
return -EINVAL;
}
ret = request_irq(virq, test_sunxi_pinctrl_irq_handler_in0,IRQF_TRIGGER_FALLING, DEVICE_NAME, (void *)arg);
//ÖжÏ×¢²á
//printk( "ret = %d.\n", ret );
hdler_in0 = gpio_p->gpio;
//¶Ë¿ÚµÄ²Ù×÷¾ä±ú
isr_num[0] = virq;
//¶Ë¿ÚµÄϵͳÖжϺű£´æ,ΪÁËÍ˳öÇý¶¯Ä£¿éµÄʱºòʹÓÃ
//printk( "hdler_in0 = %d.\n", hdler_in0 );
}
static int sunxi_gpio_eint_test_ioctrl_in1( struct platform_device *pdev )
{
unsigned long arg;
//test_pinctrl_eint_api
//request_irq
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i, pin_index,ret;
int virq;
struct device *dev = &pdev->dev;
#if 0
printk("\n");
printk("\n");
printk("\n");
#endif
type = script_get_item(main_key1, "in_1", &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, "in_1" );
}
#if 0
printk( "type = %d.\n", type );
printk( "val.val = %d.\n", val.val );
printk( "val.str = %s.\n", val.str );
printk( "val.gpio.gpio = %d.\n", val.gpio.gpio );
printk( "val.gpio.mul_sel = %d.\n", val.gpio.mul_sel );
printk( "val.gpio.pull = %d.\n", val.gpio.pull );
#endif
gpio_p = &val.gpio;
pin_index = gpio_p->gpio;
//printk( "GPIOB(6) = %d.\n", GPIOB(6) );
//printk( "pin_index = %d.\n", pin_index );
if( pin_index == 0 ){
printk("gpio led_hdl[%d] failed.\n", pin_index);
}
//mdelay
sunxi_gpio_req_ioctrl(gpio_p);
virq = gpio_to_irq(pin_index);
//printk( "virq = %d.\n", virq );
//printk( "IS_ERR_VALUE(virq) = %d.\n", IS_ERR_VALUE(virq) );
if( IS_ERR_VALUE(virq)){
printk("map gpio [%d] to virq [%d] failed !\n ",pin_index,virq);
return -EINVAL;
}
ret = request_irq(virq, test_sunxi_pinctrl_irq_handler_in1,IRQF_TRIGGER_FALLING, DEVICE_NAME, (void *)arg);
//printk( "ret = %d.\n", ret );
hdler_in1 = gpio_p->gpio;
isr_num[1] = virq;
//printk( "hdler_in1 = %d.\n", hdler_in1 );
}
static int __init io_ctl_probe(struct platform_device *pdev)
{
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i;
for( i = 0; i < 4; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
set_gpio_status(led_hdler[0], 1);
set_gpio_status(led_hdler[1], 1);
//ÇжÏmaxim°å×ӵĵçÔ´
//¸ßµçƽ1,µÍµçƽ0
set_gpio_status(led_hdler[2], 1);
set_gpio_status(led_hdler[3], 1);
//printk("gpio hander ok.\n");
sunxi_gpio_eint_test_ioctrl_in0(pdev);
sunxi_gpio_eint_test_ioctrl_in1(pdev);
return 0;
}
static int __exit io_ctl_remove(struct platform_device *pdev)
{
//del_timer(&led_timer);
return 0;
}
static struct platform_driver io_ctrl_driver = {
.driver = {
.name = "io_ctrl",
.owner = THIS_MODULE,
},
.remove = __exit_p(io_ctl_remove),
};
static int gpio_close(struct inode *inode, struct file *file)
{
//printk("gpio_close!\n");
gpio_fasync(-1, file, 0);
return 0;
}
//led-gpio-ctl.c
static struct file_operations gpio_fops = {
.owner = THIS_MODULE,
.read = gpio_rd,
.write = gpio_wr,
.unlocked_ioctl = gpio_ioctl,
.fasync = gpio_fasync,
.release = gpio_close,
};
//Install the gpio dev interface driver
static int __init sunxin_gpio_init( void )
{
int ret;
init_timer(&button_timer_in0);
//ÉèÖüüÏû¶¶¶¨Ê±Æ÷
init_timer(&button_timer_in1);
//·µ»Ø¼üÏû¶¶¶¨Ê±Æ÷
timer_on_in0 = 0x00;
//ÉèÖüü½ûÖ¹ÖØ¸´±¨¸æ
timer_on_in1 = 0x00;
//·µ»Ø¼ü½ûÖ¹ÖØ¸´±¨¸æ
key_repeat_report[0] = 0x00;
key_repeat_report[1] = 0x00;
g_input = 0x00;
//È«¾Ö°´¼ü״̬
//³õʼ»¯ÐźÅÁ¿ºÍ¼Ä´æÆ÷valµÄÖµ
//init_MUTEX(&(dev->sem));
//sema_init( &sem, 1 );
spin_lock_init(&ioctrl_lock);
//×ÔÐýËø
#if 0
gpioctl_wq = create_singlethread_workqueue("gpioctl.do.work");
if( gpioctl_wq == NULL ){
printk("create gpioctl_wq fail!\n");
return -ENOMEM;
}
#endif
//init_timer(&gpioctl_timer);
//queue_work(gpioctl_wq, &gpioctl_do_work);
//printk("\n");
//printk( KERN_ERR "in sunxin_gpio_init.\n" );
if( register_chrdev(gpio_MAJOR, "gpioctl", &gpio_fops) ) {
printk(KERN_ERR "sunxin_gpio: Unable to get major %d for gpio\n", gpio_MAJOR);
return -EIO;
}
//led_ctl_probe();
//set_led_status(1);
ret = platform_driver_probe(&io_ctrl_driver, io_ctl_probe);
//printk( KERN_ERR "[io_ctrl] ret = %d.\n", ret );
//printk(KERN_INFO "sunxin GPIO io-ctrl loaded ok!\n");
//set_all_cfg_io();
#if 0
netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);
if(NULL == netlink_fd)
{
printk(KERN_ALERT "Init netlink!\n");
return -1;
}
printk(KERN_ALERT "Init netlink success!\n");
#endif
#define INPUT_DEV_NAME ("sunxi-keyboard_selfdef_io")
//1.·ÖÅäÒ»¸öinput_dev½á¹¹Ìå
sunxi_buttons_dev = input_allocate_device();
sunxi_buttons_dev->name = INPUT_DEV_NAME;
//sunxi_buttons_dev->phys = "sunxikbd/input0";
//sunxi_buttons_dev->id.bustype = BUS_HOST;
//sunxi_buttons_dev->id.vendor = 0x0001;
//sunxi_buttons_dev->id.product = 0x0001;
//sunxi_buttons_dev->id.version = 0x0100;
//2.ÉèÖÃ
//2.1 ÉèÖð´¼üÄܲúÉúÄÄÀàʼþ
set_bit(EV_KEY,sunxi_buttons_dev->evbit);
set_bit(EV_REP,sunxi_buttons_dev->evbit);
//2.2 ÉèÖÃÄÄЩʼþÄܲúÉúÕâÀà²Ù×÷
set_bit(KEY_F13,sunxi_buttons_dev->keybit);
set_bit(KEY_F14,sunxi_buttons_dev->keybit);
set_bit(KEY_F15,sunxi_buttons_dev->keybit);
//3.×¢²á
ret = input_register_device(sunxi_buttons_dev);
//printk( KERN_ALERT "input_register_device success! = %d\n", ret );
return 0;
}
//Remove the gpio dev interface driver
static void __exit sunxin_gpio_exit( void )
{
if( isr_num[0] ){
free_irq(isr_num[0], NULL);
}
if( isr_num[1] ){
free_irq(isr_num[1], NULL);
}
input_unregister_device(sunxi_buttons_dev);
platform_driver_unregister(&io_ctrl_driver);
unregister_chrdev( gpio_MAJOR, "gpioctl" );
printk(KERN_INFO "sunxin GPIO driver unloaded\n");
netlink_kernel_release(netlink_fd);
printk(KERN_ALERT "Exit netlink!\n");
}
module_init(sunxin_gpio_init);
module_exit(sunxin_gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dp_mcu");
MODULE_DESCRIPTION("GPIO dev interface for MID");
MODULE_VERSION("Ver 1.0");
#endif
//
#if 0
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
//#include "hello.h"
#include <linux/cdev.h>
#include <linux/semaphore.h>
#define HELLO_DEVICE_NODE_NAME "hello"
#define HELLO_DEVICE_FILE_NAME "hello"
#define HELLO_DEVICE_PROC_NAME "hello"
#define HELLO_DEVICE_CLASS_NAME "hello"
struct hello_android_dev {
int val;
struct semaphore sem;
struct cdev dev;
};
/*Ö÷É豸ºÍ´ÓÉ豸ºÅ±äÁ¿*/
static int hello_major = 0;
static int hello_minor = 0;
/*É豸Àà±ðºÍÉ豸±äÁ¿*/
static struct class* hello_class = NULL;
static struct hello_android_dev* hello_dev = NULL;
/*´«Í³µÄÉ豸Îļþ²Ù×÷·½·¨*/
static int hello_open(struct inode* inode, struct file* filp);
static int hello_release(struct inode* inode, struct file* filp);
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);
/*É豸Îļþ²Ù×÷·½·¨±í*/
static struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write,
};
/*·ÃÎÊÉèÖÃÊôÐÔ·½·¨*/
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf);
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);
/*¶¨ÒåÉ豸ÊôÐÔ*/
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);
/*´ò¿ªÉ豸·½·¨*/
static int hello_open(struct inode* inode, struct file* filp) {
struct hello_android_dev* dev;
/*½«×Ô¶¨ÒåÉ豸½á¹¹Ìå±£´æÔÚÎļþÖ¸ÕëµÄ˽ÓÐÊý¾ÝÓòÖУ¬ÒÔ±ã·ÃÎÊÉ豸ʱÄÃÀ´ÓÃ*/
dev = container_of(inode->i_cdev, struct hello_android_dev, dev);
filp->private_data = dev;
return 0;
}
/*É豸ÎļþÊÍ·Åʱµ÷Ó㬿ÕʵÏÖ*/
static int hello_release(struct inode* inode, struct file* filp) {
return 0;
}
/*¶ÁÈ¡É豸µÄ¼Ä´æÆ÷valµÄÖµ*/
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {
ssize_t err = 0;
struct hello_android_dev* dev = filp->private_data;
/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}
if(count < sizeof(dev->val)) {
goto out;
}
/*½«¼Ä´æÆ÷valµÄÖµ¿½±´µ½Óû§ÌṩµÄ»º³åÇø*/
if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) {
err = -EFAULT;
goto out;
}
err = sizeof(dev->val);
out:
up(&(dev->sem));
return err;
}
/*дÉ豸µÄ¼Ä´æÆ÷Öµval*/
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {
struct hello_android_dev* dev = filp->private_data;
ssize_t err = 0;
/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}
if(count != sizeof(dev->val)) {
goto out;
}
/*½«Óû§ÌṩµÄ»º³åÇøµÄֵдµ½É豸¼Ä´æÆ÷È¥*/
if(copy_from_user(&(dev->val), buf, count)) {
err = -EFAULT;
goto out;
}
err = sizeof(dev->val);
out:
up(&(dev->sem));
return err;
}
/*¶ÁÈ¡¼Ä´æÆ÷valµÄÖµµ½»º³åÇøbufÖУ¬ÄÚ²¿Ê¹ÓÃ*/
static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) {
int val = 0;
/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}
val = dev->val;
up(&(dev->sem));
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
/*°Ñ»º³åÇøbufµÄֵдµ½É豸¼Ä´æÆ÷valÖÐÈ¥£¬ÄÚ²¿Ê¹ÓÃ*/
static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {
int val = 0;
/*½«×Ö·û´®×ª»»³ÉÊý×Ö*/
val = simple_strtol(buf, NULL, 10);
/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}
dev->val = val;
up(&(dev->sem));
return count;
}
/*¶ÁÈ¡É豸ÊôÐÔval*/
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {
struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
return __hello_get_val(hdev, buf);
}
/*дÉ豸ÊôÐÔval*/
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {
struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
return __hello_set_val(hdev, buf, count);
}
/*¶ÁÈ¡É豸¼Ä´æÆ÷valµÄÖµ£¬±£´æÔÚpage»º³åÇøÖÐ*/
static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {
if(off > 0) {
*eof = 1;
return 0;
}
return __hello_get_val(hello_dev, page);
}
/*°Ñ»º³åÇøµÄÖµbuff±£´æµ½É豸¼Ä´æÆ÷valÖÐÈ¥*/
static ssize_t hello_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) {
int err = 0;
char* page = NULL;
if(len > PAGE_SIZE) {
printk(KERN_ALERT"The buff is too large: %lu.\n", len);
return -EFAULT;
}
page = (char*)__get_free_page(GFP_KERNEL);
if(!page) {
printk(KERN_ALERT"Failed to alloc page.\n");
return -ENOMEM;
}
/*ÏȰÑÓû§ÌṩµÄ»º³åÇøÖµ¿½±´µ½Äں˻º³åÇøÖÐÈ¥*/
if(copy_from_user(page, buff, len)) {
printk(KERN_ALERT"Failed to copy buff from user.\n");
err = -EFAULT;
goto out;
}
err = __hello_set_val(hello_dev, page, len);
out:
free_page((unsigned long)page);
return err;
}
/*´´½¨/proc/helloÎļþ*/
static void hello_create_proc(void) {
struct proc_dir_entry* entry;
entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL);
if(entry) {
//entry->owner = THIS_MODULE;
entry->read_proc = hello_proc_read;
entry->write_proc = hello_proc_write;
}
}
/*ɾ³ý/proc/helloÎļþ*/
static void hello_remove_proc(void) {
remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL);
}
/*³õʼ»¯É豸*/
static int __hello_setup_dev(struct hello_android_dev* dev) {
int err;
dev_t devno = MKDEV(hello_major, hello_minor);
memset(dev, 0, sizeof(struct hello_android_dev));
cdev_init(&(dev->dev), &hello_fops);
dev->dev.owner = THIS_MODULE;
dev->dev.ops = &hello_fops;
/*×¢²á×Ö·ûÉ豸*/
err = cdev_add(&(dev->dev),devno, 1);
if(err) {
return err;
}
/*³õʼ»¯ÐźÅÁ¿ºÍ¼Ä´æÆ÷valµÄÖµ*/
//init_MUTEX(&(dev->sem));
sema_init (&(dev->sem), 1);
dev->val = 0;
return 0;
}
/*Ä£¿é¼ÓÔØ·½·¨*/
static int __init hello_init(void){
int err = -1;
dev_t dev = 0;
struct device* temp = NULL;
printk(KERN_ALERT"Initializing hello device.\n");
/*¶¯Ì¬·ÖÅäÖ÷É豸ºÍ´ÓÉ豸ºÅ*/
err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME);
if(err < 0) {
printk(KERN_ALERT"Failed to alloc char dev region.\n");
goto fail;
}
hello_major = MAJOR(dev);
hello_minor = MINOR(dev);
printk( KERN_ALERT "hello_major = %x.\n", hello_major );
printk( KERN_ALERT "hello_minor = %x.\n", hello_minor );
/*·ÖÅäheloÉ豸½á¹¹Ìå±äÁ¿*/
hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL);
if(!hello_dev) {
err = -ENOMEM;
printk(KERN_ALERT"Failed to alloc hello_dev.\n");
goto unregister;
}
/*³õʼ»¯É豸*/
err = __hello_setup_dev(hello_dev);
if(err) {
printk(KERN_ALERT"Failed to setup dev: %d.\n", err);
goto cleanup;
}
/*ÔÚ/sys/class/Ŀ¼Ï´´½¨É豸Àà±ðĿ¼hello*/
hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);
if(IS_ERR(hello_class)) {
err = PTR_ERR(hello_class);
printk(KERN_ALERT"Failed to create hello class.\n");
goto destroy_cdev;
}
/*ÔÚ/dev/Ŀ¼ºÍ/sys/class/helloĿ¼Ï·ֱ𴴽¨É豸Îļþhello*/
temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
if(IS_ERR(temp)) {
err = PTR_ERR(temp);
printk(KERN_ALERT"Failed to create hello device.");
goto destroy_class;
}
/*ÔÚ/sys/class/hello/helloĿ¼Ï´´½¨ÊôÐÔÎļþval*/
err = device_create_file(temp, &dev_attr_val);
if(err < 0) {
printk(KERN_ALERT"Failed to create attribute val.");
goto destroy_device;
}
dev_set_drvdata(temp, hello_dev);
/*´´½¨/proc/helloÎļþ*/
hello_create_proc();
printk(KERN_ALERT"Succedded to initialize hello device.\n");
return 0;
destroy_device:
device_destroy(hello_class, dev);
destroy_class:
class_destroy(hello_class);
destroy_cdev:
cdev_del(&(hello_dev->dev));
cleanup:
kfree(hello_dev);
unregister:
unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);
fail:
return err;
}
/*Ä£¿éÐ¶ÔØ·½·¨*/
static void __exit hello_exit(void) {
dev_t devno = MKDEV(hello_major, hello_minor);
printk(KERN_ALERT"Destroy hello device.\n");
/*ɾ³ý/proc/helloÎļþ*/
hello_remove_proc();
/*Ïú»ÙÉ豸Àà±ðºÍÉ豸*/
if(hello_class) {
device_destroy(hello_class, MKDEV(hello_major, hello_minor));
class_destroy(hello_class);
}
/*ɾ³ý×Ö·ûÉ豸ºÍÊÍ·ÅÉ豸ÄÚ´æ*/
if(hello_dev) {
cdev_del(&(hello_dev->dev));
kfree(hello_dev);
}
/*ÊÍ·ÅÉ豸ºÅ*/
unregister_chrdev_region(devno, 1);
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("First Android Driver");
module_init(hello_init);
module_exit(hello_exit);
#endif
//
* drivers/char/arisc_test/arisc_test.c
* (C) Copyright 2010-2015
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* sunny <sunny@allwinnertech.com>
*
* sun6i arisc test driver
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
*/
#include "sunxin_gpio.h"
#include <asm/div64.h>
#include <linux/math64.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/atmel_pdc.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/slab.h>
#include <asm/system.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-sunxi.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <mach/sys_config.h>
#include <mach/platform.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/input.h>
#include <linux/keyboard.h>
#include <linux/ioport.h>
#include <asm/irq.h>
#include <mach/sys_config.h>
#include <mach/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/pinconf-sunxi.h>
#include <linux/clk/sunxi.h>
#include <linux/err.h>
//usrlink.h
//Created on: 2014 Author: cr
#ifndef USRLINK_H_
#define USRLINK_H_
#define USER_NETLINK_CMD 25
#define MAXMSGLEN 1024
typedef enum error_e {
NET_ERROR,
NET_OK,
NET_PARAM,
NET_MEM,
NET_SOCK,
} netlink_err;
typedef enum module_e {
HELLO_CMD = 1,
} netlink_module;
typedef enum type_e {
HELLO_SET,
HELLO_GET,
} netlink_type;
#endif /* USRLINK_H_ */
#define gpio_MAJOR 225
#define DEVICE_NAME "gpioctl"
#undef DEBUG_GPIO
static u32 led_hdler[32];
static char *main_key1 = "maxim_rst_para";
static char *led_key1[32] = {
"rst_gpio",
"user3v3_en",
"in_2",
"in_3",
"uart_tx_io",
"uart_rx_io",
"uart_tx_r",
"uart_rx_r",
"spi_din_io",
"spi_dout_io",
"spi_clk_io",
"spi_cs0_io",
"spi_din_r",
"spi_dout_r",
"spi_clk_r",
"spi_cs0_r",
"twi_scl",
};
static struct fasync_struct *fasync_queue;
static bool led_status;
static struct timer_list button_timer_in0;
static struct timer_list button_timer_in1;
static unsigned int timer_on_in0;
static unsigned int timer_on_in1;
static unsigned int g_input;
static struct timer_list gpioctl_timer;
static u32 hdler_in0,hdler_in1;
static u32 isr_num[2]={0,0};
static struct semaphore sem;
static void gpioctl_do_events (struct work_struct *work);
static struct workqueue_struct *gpioctl_wq;
static DECLARE_WORK(gpioctl_do_work, gpioctl_do_events);
static spinlock_t ioctrl_lock;
static int sunxi_gpio_req_ioctrl(struct gpio_config *gpio);
/*
* netlink.c
*
* Created on: 2014 * Author: cr
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/netlink.h>
#include <net/sock.h>
//#include "usrlink.h"
//MODULE_LICENSE("Dual BSD/GPL");
//MODULE_AUTHOR("MDAXIA");
struct sock *netlink_fd;
static struct pin_desc *irq_pd;
static struct input_dev *sunxi_buttons_dev;
static struct timer_list buttons_timer;
//static int key_state[2];
static int key_repeat_report[2];
static unsigned long timeout_0 = 0x00;
static unsigned long timer_cnt_0 = 0x00;
static unsigned long timeout_1 = 0x00;
static unsigned long timer_cnt_1 = 0x00;
static void netlink_to_user(int dest, void *buf, int len)
{
struct nlmsghdr *nl;
struct sk_buff *skb;
int size;
//printk( "dest = %d.\n", dest );
size = NLMSG_SPACE(len);
skb = alloc_skb(size, GFP_ATOMIC);
if(!skb || !buf)
{
printk(KERN_ALERT "netlink_to_user skb of buf null!\n");
return;
}
nl = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0);
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_group = 0;
memcpy(NLMSG_DATA(nl), buf, len);
nl->nlmsg_len = (len > 2) ? (len - 0):len;
netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT);
//printk(KERN_ALERT "K send packet success\n");
}
static int process_hello_get(int dest, void *buf, int len)
{
printk(KERN_ALERT "In process_hello get!\n");
memcpy(buf, "I known you !", 13);
netlink_to_user(dest, buf, 13);
return NET_OK;
}
static int process_hello_set(int dest, void *buf, int len)
{
//printk( "In process_hello set! %s\n", (char *)buf);
//memcpy(buf, "S known you !", 13);
netlink_to_user(dest, buf, len);
return NET_OK;
}
static void netlink_process_packet(struct nlmsghdr *nl)
{
int ret;
switch(nl->nlmsg_type)
{
case HELLO_GET:
printk( "process_hello_get.\n" );
ret = process_hello_get(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
break;
case HELLO_SET:
printk( "process_hello_set.\n" );
ret = process_hello_set(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
break;
default:break;
}
}
static void netlink_recv_packet(struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlhdr;
skb = skb_get(__skb);
if(skb->len >= sizeof(struct nlmsghdr))
{
nlhdr = (struct nlmsghdr *)skb->data;
if(nlhdr->nlmsg_len >= sizeof(struct nlmsghdr) &&
__skb->len >= nlhdr->nlmsg_len)
{
netlink_process_packet(nlhdr);
}
}
else
printk(KERN_ALERT "Kernel receive msg length error!\n");
}
#if 0
static int __init netlink_init(void)
{
netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);
if(NULL == netlink_fd)
{
printk(KERN_ALERT "Init netlink!\n");
return -1;
}
printk(KERN_ALERT "Init netlink success!\n");
return 0;
}
static void __exit netlink_exit(void)
{
netlink_kernel_release(netlink_fd);
printk(KERN_ALERT "Exit netlink!\n");
}
#endif
static void demo_exit(void);
static struct tasklet_struct my_tasklet;
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int flag =0;
ssize_t sleepy_read( void )
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",current->pid,current->comm);
wait_event_interruptible(wq,flag!=0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s) \n",current->pid,current->comm);
return 0;
}
ssize_t sleepy_write(void)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers ...\n",current->pid,current->comm);
flag = 1;
wake_up_interruptible(&wq);
return 0;
//³É¹¦²¢±ÜÃâÖØÊÔ
}
// tasklet´¦Àíº¯Êý
static void tasklet_handler (unsigned long data)
{
printk(KERN_ALERT "tasklet_handler is running.\n");
sleepy_read();
sleepy_write();
}
static int demo_init(void)
{
// ³õʼ»¯tasklet
tasklet_init(&my_tasklet, tasklet_handler, 0);
// µ÷¶Ètasklet´¦Àí³ÌÐò
tasklet_schedule(&my_tasklet);
printk(KERN_ALERT "demo_init.\n");
//demo_exit();
return 0;
}
static void demo_exit(void)
{
// Ïú»Ùtasklet
tasklet_kill(&my_tasklet);
printk(KERN_ALERT "demo_exit.\n");
}
static void timer_dowork(void)
{
//printk( "add gpioctl_dowork\n");
mod_timer(&gpioctl_timer, jiffies + HZ);
//printk( "pin_value = 0x%x.\n", pin_value );
demo_init();
}
static void gpioctl_do_events (struct work_struct *work)
{
int ret = 0;
printk( "add gpioctl_do_events\n");
gpioctl_timer.expires = jiffies + HZ;
gpioctl_timer.data = 100;
gpioctl_timer.function = timer_dowork;
add_timer(&gpioctl_timer);
return;
}
/
#if 1
static void set_gpio_status(int handler, bool status)
{
gpio_set_value(handler, status);
}
static int get_gpio_status(int handler)
{
return gpio_get_value(handler);
}
static void set_led_status(unsigned long arg)
{
int i;
led_status = led_status ? false : true;
for( i = 0; i < 1; i++ ){
set_gpio_status(led_hdler[i], arg);
}
}
//GPIO read
static ssize_t gpio_rd (struct file *file, char *buf, size_t count, loff_t *offset)
{
int ret;
int io_status;
//led_status = led_status ? false : true;
printk( KERN_NOTICE "count = %d.\r\n", count );
//printk( KERN_NOTICE "led_status = %x.\r\n", led_status );
//set_gpio_status(led_hdler[1], led_status);
struct regulator *ldo_dcdc1;
memset( buf, 0, count );
ldo_dcdc1 = regulator_get(NULL,"axp22_dcdc1");
if( IS_ERR(ldo_dcdc1) ){
printk("nand:some error happen, fail to get regulator axp22_dcdc1!");
return -1;
}
//set output voltage to 3.0V
//ret = regulator_set_voltage(regu1,3000000,3000000);
//dp_mcu
ret = regulator_set_voltage(ldo_dcdc1, 3100000, 3100000);
printk( KERN_NOTICE "ret = %d.\r\n", ret );
return count;
}
//PB7_PCM0_DIN_EINT7_LS_INT RST sw_uart_check_baudset
//the 15 pin, ctrl the maxim
//GPIO Write
static ssize_t gpio_wr(struct file *file, const char *buf, size_t count, loff_t *offset)
{
if( buf[0]==0x00 || buf[0]==0x01 ){
set_led_status(buf[0]);
}
printk( KERN_NOTICE "buf[0] = %x.\r\n", buf[0] );
printk( KERN_NOTICE "count = %x.\r\n", count );
return count;
}
static void set_all_cfg_io( void )
{
int io_status = 0;
int ret = 0;
unsigned long flags;
unsigned char buf[128];
unsigned char *sendstr = "12345";
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i;
//ÅäÖÃËùÓÐgpioΪÆÕͨio¿Ú,²¢ÇÒÖÃΪµÍµçƽ
//printk( "cfg to io.\n" );
for( i = 4; i < 6; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 8; i < 12; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 16; i < 17; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
set_gpio_status(led_hdler[4], 0);
set_gpio_status(led_hdler[5], 0);
set_gpio_status(led_hdler[8], 0);
set_gpio_status(led_hdler[9], 0);
set_gpio_status(led_hdler[10], 0);
set_gpio_status(led_hdler[11], 0);
set_gpio_status(led_hdler[16], 0);
}
static long gpio_ioctl( struct file *file, unsigned int cmd, unsigned long arg)
{
int io_status = 0;
int ret = 0;
unsigned long flags;
unsigned char buf[128];
unsigned char *sendstr = "12345";
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i;
//printk( "cmd = %d, arg = %d.\n", cmd, arg );
switch ( cmd )
{
case 0:
if( arg==0x00 || arg==0x01 ){
set_gpio_status(led_hdler[0], arg);
}
break;
case 1:
if( arg==0x00 || arg==0x01 ){
set_gpio_status(led_hdler[1], arg);
}
break;
case 3:
//printk( "cfg to io.\n" );
for( i = 4; i < 6; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 8; i < 12; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 16; i < 17; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
set_gpio_status(led_hdler[4], 0);
set_gpio_status(led_hdler[5], 0);
set_gpio_status(led_hdler[8], 0);
set_gpio_status(led_hdler[9], 0);
set_gpio_status(led_hdler[10], 0);
set_gpio_status(led_hdler[11], 0);
set_gpio_status(led_hdler[16], 0);
break;
case 5:
//printk( "cfg to spec.\n" );
for( i = 6; i < 8; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
for( i = 12; i < 16; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
//set_gpio_status(led_hdler[2], 0);
//set_gpio_status(led_hdler[3], 0);
break;
case 0x06:
if( arg == 0x00 ){
//»ñÈ¡°´¼üÖµ 2¸ö
ret = g_input;
spin_lock_irqsave(&ioctrl_lock, flags);
g_input = 0x00;
spin_unlock_irqrestore(&ioctrl_lock, flags);
return ret;
}else{
//Çå³ý°´¼ü´¦Àí
if( arg==1 || arg==2 || arg==3 ){
spin_lock_irqsave(&ioctrl_lock, flags);
g_input = g_input & (~arg);
spin_unlock_irqrestore(&ioctrl_lock, flags);
}
return 0x00;
}
break;
case 0x07:
if( arg == 0x00 ){
//»ñÈ¡°´¼üÖµ 2¸ö
int pin_value,temp,temp1;
temp = get_gpio_status(led_hdler[2]);
//printk( "pin_value2[%d].\n", temp );
//printk( "led_hdler[2][%d].\n", led_hdler[2] );
temp1 = get_gpio_status(led_hdler[3]);
//printk( "pin_value3[%d].\n", temp1 );
//printk( "led_hdler[3][%d].\n", led_hdler[3] );
pin_value = (temp<<1) | temp1;
return pin_value;
}else{
return 0x00;
}
break;
case 0x08:
//(int dest, void *buf, int len)
buf[0] = '1';
buf[1] = '2';
buf[2] = '3';
buf[3] = '4';
memcpy( buf, sendstr, strlen(sendstr) );
buf[strlen(sendstr)] = '\0';
//printk( "strlen(sendstr)[%d].\n", strlen(sendstr) );
process_hello_set( 1, buf, strlen(sendstr) );
//ÄÚºËÖ÷¶¯·¢ËÍÏûÏ¢¸ø1ºÅÓ¦ÓóÌÐò
break;
//spi_gpio_cleanup
//uart_state
default:
printk(KERN_NOTICE"The value of CMD = %d is err,must < 6\r\n",cmd);
return -2;
break;
}
return io_status;
}
static int sunxi_gpio_req_ioctrl(struct gpio_config *gpio)
{
int ret = 0;
char pin_name[8] = {0};
unsigned long config;
sunxi_gpio_to_name(gpio->gpio, pin_name);
//printk( "pin_name = %s.\n", pin_name );
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, gpio->mul_sel);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
printk("set gpio %s mulsel failed.\n",pin_name);
return -1;
}
if( gpio->pull != GPIO_PULL_DEFAULT ){
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, gpio->pull);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
printk("set gpio %s pull mode failed.\n",pin_name);
return -1;
}
}
if( gpio->drv_level != GPIO_DRVLVL_DEFAULT ){
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, gpio->drv_level);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
printk("set gpio %s driver level failed.\n",pin_name);
return -1;
}
}
if( gpio->data != GPIO_DATA_DEFAULT ){
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, gpio->data);
ret = pin_config_set(SUNXI_PINCTRL, pin_name, config);
if( ret ){
printk("set gpio %s initial val failed.\n",pin_name);
return -1;
}
}
return 0;
}
static int gpio_fasync(int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &fasync_queue);
if( retval < 0 ){
return retval;
}
return 0;
}
//g_input = g_input | 0x04;
//kill_fasync(&fasync_queue, SIGIO, POLL_IN);
//ÉèÖüü´¦Àí
static void button_jitter_in0( void )
{
int pin_value_0, pin_value_1;
unsigned long flags;
spin_lock_irqsave(&ioctrl_lock, flags);
pin_value_0 = gpio_get_value(hdler_in0);
//»ñÈ¡´Ë¿ÌµÄÉèÖüüÖµ
if( pin_value_0 == 0x00 ){
//°´ÏÂ״̬
if( time_before(jiffies, timeout_0+200) ){
//»¹Ã»Óг¬Ê±2S
}else{
//ÒѾ³¬Ê±
if( key_repeat_report[0] == 0x00 ){
pin_value_1 = gpio_get_value(hdler_in1);
//×éºÏ³¤°´ÅжÏ
if( pin_value_1 == 0x00 ){
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,0);
input_sync(sunxi_buttons_dev);
key_repeat_report[0]++;
key_repeat_report[1] = 0x01;
printk( "key0 zuhe.\n" );
}else{
input_event(sunxi_buttons_dev,EV_KEY,KEY_F13,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F13,0);
input_sync(sunxi_buttons_dev);
key_repeat_report[0]++;
printk( "key0 long.\n" );
//printk( "pin_value_in03 = 0x%x.\n", pin_value );
}
}
}
timer_cnt_0++;
//½øÈ붨ʱÆ÷´ÎÊý¼Ó1
mod_timer( &button_timer_in0, jiffies + msecs_to_jiffies(100) );
}else{
if( timer_cnt_0 == 0 ){
//Ïû¶¶ÎÞÓð´¼ü
//µÚÒ»¸ö100ms½øÀ´,°´¼ü¾ÍÊÍ·ÅÁË,˵Ã÷Êǰ´¼ü¶¶¶¯
}else{
//°´¼üÒѾÊÍ·Å
if( time_before(jiffies, timeout_0+200) ){
//»¹Ã»Óг¬Ê±,¶Ì°´
//ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´ÏÂ
if( key_repeat_report[0] == 0x00 ){
input_event(sunxi_buttons_dev,EV_KEY,KEY_F14,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F14,0);
input_sync(sunxi_buttons_dev);
printk( "key0 short.\n" );
}
//printk( "pin_value_in02 = 0x%x.\n", pin_value );
}
}
key_repeat_report[0]=0x00;
timer_on_in0 = 0;
//¿ÉÒÔÔÙ´ÎÏìÓ¦ÖжÏÁË
}
spin_unlock_irqrestore(&ioctrl_lock, flags);
}
//·µ»Ø¼ü´¦Àí
static void button_jitter_in1(void)
{
int pin_value_0, pin_value_1;
unsigned long flags;
spin_lock_irqsave( &ioctrl_lock, flags );
pin_value_1 = gpio_get_value(hdler_in1);
//»ñÈ¡´Ë¿ÌµÄ·µ»Ø¼üÖµ
//printk( "pin_value_in1 = 0x%x.\n", pin_value );
if( pin_value_1 == 0x00 ){
//°´ÏÂ״̬
if( time_before(jiffies, timeout_1+200) ){
//»¹Ã»Óг¬Ê±2S
}else{
//ÒѾ³¬Ê±
if( key_repeat_report[1] == 0x00 ){
//ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´ÏÂ
pin_value_0 = gpio_get_value(hdler_in0);
//×éºÏ³¤°´ÅжÏ
if( pin_value_0 == 0x00 ){
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F17,0);
input_sync(sunxi_buttons_dev);
key_repeat_report[0] = 0x01;
key_repeat_report[1]++;
printk( "key1 zuhe.\n" );
}else{
input_event(sunxi_buttons_dev,EV_KEY,KEY_F16,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F16,0);
input_sync(sunxi_buttons_dev);
key_repeat_report[1]++;
printk( "key1 long.\n" );
//printk( "pin_value_in03 = 0x%x.\n", pin_value );
}
}
}
timer_cnt_1++;
//½øÈ붨ʱÆ÷´ÎÊý¼Ó1
mod_timer( &button_timer_in1, jiffies + msecs_to_jiffies(100) );
}else{
if( timer_cnt_1 == 0 ){
//Ïû¶¶ÎÞÓð´¼ü
//µÚÒ»¸ö100ms½øÀ´,°´¼ü¾ÍÊÍ·ÅÁË,˵Ã÷Êǰ´¼ü¶¶¶¯
}else{
//°´¼üÒѾÊÍ·Å
if( time_before(jiffies, timeout_1+200) ){
//»¹Ã»Óг¬Ê±,¶Ì°´
//ËÉ¿ª ×îºóÒ»¸ö²ÎÊý: 0-ËÉ¿ª, 1-°´ÏÂ
if( key_repeat_report[1] == 0x00 ){
input_event(sunxi_buttons_dev,EV_KEY,KEY_F15,1);
input_sync(sunxi_buttons_dev);
input_event(sunxi_buttons_dev,EV_KEY,KEY_F15,0);
input_sync(sunxi_buttons_dev);
printk( "key1 short.\n" );
}
}
}
key_repeat_report[1]=0x00;
timer_on_in1 = 0;
//¿ÉÒÔÔÙ´ÎÏìÓ¦ÖжÏÁË
}
spin_unlock_irqrestore(&ioctrl_lock, flags);
}
static irqreturn_t test_sunxi_pinctrl_irq_handler_in0(int irq, void *dev_id)
{
unsigned long flags;
//printk("[%s] handler for test pinctrl eint api.\n",__func__);
//disable_irq_nosync(irq);
spin_lock_irqsave(&ioctrl_lock, flags);
if( key_repeat_report[0] ){
key_repeat_report[0] = 0x00;
goto exit;
}
if( timer_on_in0 == 0x00 ){
g_input = 0x00;
//ÇåÁãËùÓÐ״̬
key_repeat_report[0] = 0x00;
//ÖØ¸´±¨¸æÇåÁã
timeout_0 = jiffies;
//»ñȡʱ¼ä´Á
timer_cnt_0 = 0x00;
//¶¨Ê±Æ÷½øÈë´ÎÊýÇåÁã
button_timer_in0.expires = jiffies + 10;
button_timer_in0.data = 100;
button_timer_in0.function = button_jitter_in0;
add_timer(&button_timer_in0);
timer_on_in0 = 1;
}
exit:
spin_unlock_irqrestore(&ioctrl_lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t test_sunxi_pinctrl_irq_handler_in1(int irq, void *dev_id)
{
unsigned long flags;
spin_lock_irqsave( &ioctrl_lock, flags );
if( key_repeat_report[1] ){
key_repeat_report[1] = 0x00;
goto exit;
}
if( timer_on_in1 == 0x00 ){
g_input = 0x00;
//ÇåÁãËùÓÐ״̬
key_repeat_report[1] = 0x00;
//ÖØ¸´±¨¸æÇåÁã
timeout_1 = jiffies;
//»ñȡʱ¼ä´Á
timer_cnt_1 = 0x00;
//¶¨Ê±Æ÷½øÈë´ÎÊýÇåÁã
button_timer_in1.expires = jiffies + 10;
button_timer_in1.data = 100;
button_timer_in1.function = button_jitter_in1;
add_timer(&button_timer_in1);
timer_on_in1 = 1;
}
exit:
spin_unlock_irqrestore(&ioctrl_lock, flags);
return IRQ_HANDLED;
}
static int sunxi_gpio_eint_test_ioctrl_in0( struct platform_device *pdev )
{
unsigned long arg;
//test_pinctrl_eint_api
//request_irq
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i, pin_index,ret;
int virq;
struct device *dev = &pdev->dev;
#if 0
printk("\n");
printk("\n");
printk("\n");
#endif
type = script_get_item(main_key1, "in_0", &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, "in_0" );
}
#if 0
printk( "type = %d.\n", type );
printk( "val.val = %d.\n", val.val );
printk( "val.str = %s.\n", val.str );
printk( "val.gpio.gpio = %d.\n", val.gpio.gpio );
printk( "val.gpio.mul_sel = %d.\n", val.gpio.mul_sel );
printk( "val.gpio.pull = %d.\n", val.gpio.pull );
#endif
gpio_p = &val.gpio;
pin_index = gpio_p->gpio;
//printk( "GPIOB(6) = %d.\n", GPIOB(6) );
//printk( "pin_index = %d.\n", pin_index );
if( pin_index == 0 ){
printk("gpio led_hdl[%d] failed.\n", pin_index);
}
//mdelay
sunxi_gpio_req_ioctrl(gpio_p);
//ÅäÖÃgpio¿ÚΪÖжÏÊäÈëģʽ
virq = gpio_to_irq(pin_index);
//»ñÈ¡¶ÔÓ¦¶Ë¿ÚµÄÖжϺÅ
//printk( "virq = %d.\n", virq );
//printk( "IS_ERR_VALUE(virq) = %d.\n", IS_ERR_VALUE(virq) );
if (IS_ERR_VALUE(virq)){
printk("map gpio [%d] to virq [%d] failed !\n ",pin_index,virq);
return -EINVAL;
}
ret = request_irq(virq, test_sunxi_pinctrl_irq_handler_in0,IRQF_TRIGGER_FALLING, DEVICE_NAME, (void *)arg);
//ÖжÏ×¢²á
//printk( "ret = %d.\n", ret );
hdler_in0 = gpio_p->gpio;
//¶Ë¿ÚµÄ²Ù×÷¾ä±ú
isr_num[0] = virq;
//¶Ë¿ÚµÄϵͳÖжϺű£´æ,ΪÁËÍ˳öÇý¶¯Ä£¿éµÄʱºòʹÓÃ
//printk( "hdler_in0 = %d.\n", hdler_in0 );
}
static int sunxi_gpio_eint_test_ioctrl_in1( struct platform_device *pdev )
{
unsigned long arg;
//test_pinctrl_eint_api
//request_irq
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i, pin_index,ret;
int virq;
struct device *dev = &pdev->dev;
#if 0
printk("\n");
printk("\n");
printk("\n");
#endif
type = script_get_item(main_key1, "in_1", &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, "in_1" );
}
#if 0
printk( "type = %d.\n", type );
printk( "val.val = %d.\n", val.val );
printk( "val.str = %s.\n", val.str );
printk( "val.gpio.gpio = %d.\n", val.gpio.gpio );
printk( "val.gpio.mul_sel = %d.\n", val.gpio.mul_sel );
printk( "val.gpio.pull = %d.\n", val.gpio.pull );
#endif
gpio_p = &val.gpio;
pin_index = gpio_p->gpio;
//printk( "GPIOB(6) = %d.\n", GPIOB(6) );
//printk( "pin_index = %d.\n", pin_index );
if( pin_index == 0 ){
printk("gpio led_hdl[%d] failed.\n", pin_index);
}
//mdelay
sunxi_gpio_req_ioctrl(gpio_p);
virq = gpio_to_irq(pin_index);
//printk( "virq = %d.\n", virq );
//printk( "IS_ERR_VALUE(virq) = %d.\n", IS_ERR_VALUE(virq) );
if( IS_ERR_VALUE(virq)){
printk("map gpio [%d] to virq [%d] failed !\n ",pin_index,virq);
return -EINVAL;
}
ret = request_irq(virq, test_sunxi_pinctrl_irq_handler_in1,IRQF_TRIGGER_FALLING, DEVICE_NAME, (void *)arg);
//printk( "ret = %d.\n", ret );
hdler_in1 = gpio_p->gpio;
isr_num[1] = virq;
//printk( "hdler_in1 = %d.\n", hdler_in1 );
}
static int __init io_ctl_probe(struct platform_device *pdev)
{
script_item_u val;
script_item_value_type_e type;
struct gpio_config *gpio_p = NULL;
int i;
for( i = 0; i < 4; i++ ){
type = script_get_item(main_key1, led_key1[i], &val);
if( SCIRPT_ITEM_VALUE_TYPE_PIO != type ){
printk("fetch the [%s] %s failed!\n", main_key1, led_key1[i]);
}
//printk( "type = %d.\n", type );
gpio_p = &val.gpio;
led_hdler[i] = gpio_p->gpio;
if( led_hdler[i] == 0 ){
printk("gpio led_hdl[%d] failed.\n", i);
}
//printk( "led_hdler[i] = %d.\n", led_hdler[i] );
sunxi_gpio_req_ioctrl(gpio_p);
}
set_gpio_status(led_hdler[0], 1);
set_gpio_status(led_hdler[1], 1);
//ÇжÏmaxim°å×ӵĵçÔ´
//¸ßµçƽ1,µÍµçƽ0
set_gpio_status(led_hdler[2], 1);
set_gpio_status(led_hdler[3], 1);
//printk("gpio hander ok.\n");
sunxi_gpio_eint_test_ioctrl_in0(pdev);
sunxi_gpio_eint_test_ioctrl_in1(pdev);
return 0;
}
static int __exit io_ctl_remove(struct platform_device *pdev)
{
//del_timer(&led_timer);
return 0;
}
static struct platform_driver io_ctrl_driver = {
.driver = {
.name = "io_ctrl",
.owner = THIS_MODULE,
},
.remove = __exit_p(io_ctl_remove),
};
static int gpio_close(struct inode *inode, struct file *file)
{
//printk("gpio_close!\n");
gpio_fasync(-1, file, 0);
return 0;
}
//led-gpio-ctl.c
static struct file_operations gpio_fops = {
.owner = THIS_MODULE,
.read = gpio_rd,
.write = gpio_wr,
.unlocked_ioctl = gpio_ioctl,
.fasync = gpio_fasync,
.release = gpio_close,
};
//Install the gpio dev interface driver
static int __init sunxin_gpio_init( void )
{
int ret;
init_timer(&button_timer_in0);
//ÉèÖüüÏû¶¶¶¨Ê±Æ÷
init_timer(&button_timer_in1);
//·µ»Ø¼üÏû¶¶¶¨Ê±Æ÷
timer_on_in0 = 0x00;
//ÉèÖüü½ûÖ¹ÖØ¸´±¨¸æ
timer_on_in1 = 0x00;
//·µ»Ø¼ü½ûÖ¹ÖØ¸´±¨¸æ
key_repeat_report[0] = 0x00;
key_repeat_report[1] = 0x00;
g_input = 0x00;
//È«¾Ö°´¼ü״̬
//³õʼ»¯ÐźÅÁ¿ºÍ¼Ä´æÆ÷valµÄÖµ
//init_MUTEX(&(dev->sem));
//sema_init( &sem, 1 );
spin_lock_init(&ioctrl_lock);
//×ÔÐýËø
#if 0
gpioctl_wq = create_singlethread_workqueue("gpioctl.do.work");
if( gpioctl_wq == NULL ){
printk("create gpioctl_wq fail!\n");
return -ENOMEM;
}
#endif
//init_timer(&gpioctl_timer);
//queue_work(gpioctl_wq, &gpioctl_do_work);
//printk("\n");
//printk( KERN_ERR "in sunxin_gpio_init.\n" );
if( register_chrdev(gpio_MAJOR, "gpioctl", &gpio_fops) ) {
printk(KERN_ERR "sunxin_gpio: Unable to get major %d for gpio\n", gpio_MAJOR);
return -EIO;
}
//led_ctl_probe();
//set_led_status(1);
ret = platform_driver_probe(&io_ctrl_driver, io_ctl_probe);
//printk( KERN_ERR "[io_ctrl] ret = %d.\n", ret );
//printk(KERN_INFO "sunxin GPIO io-ctrl loaded ok!\n");
//set_all_cfg_io();
#if 0
netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);
if(NULL == netlink_fd)
{
printk(KERN_ALERT "Init netlink!\n");
return -1;
}
printk(KERN_ALERT "Init netlink success!\n");
#endif
#define INPUT_DEV_NAME ("sunxi-keyboard_selfdef_io")
//1.·ÖÅäÒ»¸öinput_dev½á¹¹Ìå
sunxi_buttons_dev = input_allocate_device();
sunxi_buttons_dev->name = INPUT_DEV_NAME;
//sunxi_buttons_dev->phys = "sunxikbd/input0";
//sunxi_buttons_dev->id.bustype = BUS_HOST;
//sunxi_buttons_dev->id.vendor = 0x0001;
//sunxi_buttons_dev->id.product = 0x0001;
//sunxi_buttons_dev->id.version = 0x0100;
//2.ÉèÖÃ
//2.1 ÉèÖð´¼üÄܲúÉúÄÄÀàʼþ
set_bit(EV_KEY,sunxi_buttons_dev->evbit);
set_bit(EV_REP,sunxi_buttons_dev->evbit);
//2.2 ÉèÖÃÄÄЩʼþÄܲúÉúÕâÀà²Ù×÷
set_bit(KEY_F13,sunxi_buttons_dev->keybit);
set_bit(KEY_F14,sunxi_buttons_dev->keybit);
set_bit(KEY_F15,sunxi_buttons_dev->keybit);
//3.×¢²á
ret = input_register_device(sunxi_buttons_dev);
//printk( KERN_ALERT "input_register_device success! = %d\n", ret );
return 0;
}
//Remove the gpio dev interface driver
static void __exit sunxin_gpio_exit( void )
{
if( isr_num[0] ){
free_irq(isr_num[0], NULL);
}
if( isr_num[1] ){
free_irq(isr_num[1], NULL);
}
input_unregister_device(sunxi_buttons_dev);
platform_driver_unregister(&io_ctrl_driver);
unregister_chrdev( gpio_MAJOR, "gpioctl" );
printk(KERN_INFO "sunxin GPIO driver unloaded\n");
netlink_kernel_release(netlink_fd);
printk(KERN_ALERT "Exit netlink!\n");
}
module_init(sunxin_gpio_init);
module_exit(sunxin_gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dp_mcu");
MODULE_DESCRIPTION("GPIO dev interface for MID");
MODULE_VERSION("Ver 1.0");
#endif
//
#if 0
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
//#include "hello.h"
#include <linux/cdev.h>
#include <linux/semaphore.h>
#define HELLO_DEVICE_NODE_NAME "hello"
#define HELLO_DEVICE_FILE_NAME "hello"
#define HELLO_DEVICE_PROC_NAME "hello"
#define HELLO_DEVICE_CLASS_NAME "hello"
struct hello_android_dev {
int val;
struct semaphore sem;
struct cdev dev;
};
/*Ö÷É豸ºÍ´ÓÉ豸ºÅ±äÁ¿*/
static int hello_major = 0;
static int hello_minor = 0;
/*É豸Àà±ðºÍÉ豸±äÁ¿*/
static struct class* hello_class = NULL;
static struct hello_android_dev* hello_dev = NULL;
/*´«Í³µÄÉ豸Îļþ²Ù×÷·½·¨*/
static int hello_open(struct inode* inode, struct file* filp);
static int hello_release(struct inode* inode, struct file* filp);
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);
/*É豸Îļþ²Ù×÷·½·¨±í*/
static struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write,
};
/*·ÃÎÊÉèÖÃÊôÐÔ·½·¨*/
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf);
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);
/*¶¨ÒåÉ豸ÊôÐÔ*/
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);
/*´ò¿ªÉ豸·½·¨*/
static int hello_open(struct inode* inode, struct file* filp) {
struct hello_android_dev* dev;
/*½«×Ô¶¨ÒåÉ豸½á¹¹Ìå±£´æÔÚÎļþÖ¸ÕëµÄ˽ÓÐÊý¾ÝÓòÖУ¬ÒÔ±ã·ÃÎÊÉ豸ʱÄÃÀ´ÓÃ*/
dev = container_of(inode->i_cdev, struct hello_android_dev, dev);
filp->private_data = dev;
return 0;
}
/*É豸ÎļþÊÍ·Åʱµ÷Ó㬿ÕʵÏÖ*/
static int hello_release(struct inode* inode, struct file* filp) {
return 0;
}
/*¶ÁÈ¡É豸µÄ¼Ä´æÆ÷valµÄÖµ*/
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {
ssize_t err = 0;
struct hello_android_dev* dev = filp->private_data;
/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}
if(count < sizeof(dev->val)) {
goto out;
}
/*½«¼Ä´æÆ÷valµÄÖµ¿½±´µ½Óû§ÌṩµÄ»º³åÇø*/
if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) {
err = -EFAULT;
goto out;
}
err = sizeof(dev->val);
out:
up(&(dev->sem));
return err;
}
/*дÉ豸µÄ¼Ä´æÆ÷Öµval*/
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {
struct hello_android_dev* dev = filp->private_data;
ssize_t err = 0;
/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}
if(count != sizeof(dev->val)) {
goto out;
}
/*½«Óû§ÌṩµÄ»º³åÇøµÄֵдµ½É豸¼Ä´æÆ÷È¥*/
if(copy_from_user(&(dev->val), buf, count)) {
err = -EFAULT;
goto out;
}
err = sizeof(dev->val);
out:
up(&(dev->sem));
return err;
}
/*¶ÁÈ¡¼Ä´æÆ÷valµÄÖµµ½»º³åÇøbufÖУ¬ÄÚ²¿Ê¹ÓÃ*/
static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) {
int val = 0;
/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}
val = dev->val;
up(&(dev->sem));
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
/*°Ñ»º³åÇøbufµÄֵдµ½É豸¼Ä´æÆ÷valÖÐÈ¥£¬ÄÚ²¿Ê¹ÓÃ*/
static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {
int val = 0;
/*½«×Ö·û´®×ª»»³ÉÊý×Ö*/
val = simple_strtol(buf, NULL, 10);
/*ͬ²½·ÃÎÊ*/
if(down_interruptible(&(dev->sem))) {
return -ERESTARTSYS;
}
dev->val = val;
up(&(dev->sem));
return count;
}
/*¶ÁÈ¡É豸ÊôÐÔval*/
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {
struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
return __hello_get_val(hdev, buf);
}
/*дÉ豸ÊôÐÔval*/
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {
struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);
return __hello_set_val(hdev, buf, count);
}
/*¶ÁÈ¡É豸¼Ä´æÆ÷valµÄÖµ£¬±£´æÔÚpage»º³åÇøÖÐ*/
static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {
if(off > 0) {
*eof = 1;
return 0;
}
return __hello_get_val(hello_dev, page);
}
/*°Ñ»º³åÇøµÄÖµbuff±£´æµ½É豸¼Ä´æÆ÷valÖÐÈ¥*/
static ssize_t hello_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) {
int err = 0;
char* page = NULL;
if(len > PAGE_SIZE) {
printk(KERN_ALERT"The buff is too large: %lu.\n", len);
return -EFAULT;
}
page = (char*)__get_free_page(GFP_KERNEL);
if(!page) {
printk(KERN_ALERT"Failed to alloc page.\n");
return -ENOMEM;
}
/*ÏȰÑÓû§ÌṩµÄ»º³åÇøÖµ¿½±´µ½Äں˻º³åÇøÖÐÈ¥*/
if(copy_from_user(page, buff, len)) {
printk(KERN_ALERT"Failed to copy buff from user.\n");
err = -EFAULT;
goto out;
}
err = __hello_set_val(hello_dev, page, len);
out:
free_page((unsigned long)page);
return err;
}
/*´´½¨/proc/helloÎļþ*/
static void hello_create_proc(void) {
struct proc_dir_entry* entry;
entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL);
if(entry) {
//entry->owner = THIS_MODULE;
entry->read_proc = hello_proc_read;
entry->write_proc = hello_proc_write;
}
}
/*ɾ³ý/proc/helloÎļþ*/
static void hello_remove_proc(void) {
remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL);
}
/*³õʼ»¯É豸*/
static int __hello_setup_dev(struct hello_android_dev* dev) {
int err;
dev_t devno = MKDEV(hello_major, hello_minor);
memset(dev, 0, sizeof(struct hello_android_dev));
cdev_init(&(dev->dev), &hello_fops);
dev->dev.owner = THIS_MODULE;
dev->dev.ops = &hello_fops;
/*×¢²á×Ö·ûÉ豸*/
err = cdev_add(&(dev->dev),devno, 1);
if(err) {
return err;
}
/*³õʼ»¯ÐźÅÁ¿ºÍ¼Ä´æÆ÷valµÄÖµ*/
//init_MUTEX(&(dev->sem));
sema_init (&(dev->sem), 1);
dev->val = 0;
return 0;
}
/*Ä£¿é¼ÓÔØ·½·¨*/
static int __init hello_init(void){
int err = -1;
dev_t dev = 0;
struct device* temp = NULL;
printk(KERN_ALERT"Initializing hello device.\n");
/*¶¯Ì¬·ÖÅäÖ÷É豸ºÍ´ÓÉ豸ºÅ*/
err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME);
if(err < 0) {
printk(KERN_ALERT"Failed to alloc char dev region.\n");
goto fail;
}
hello_major = MAJOR(dev);
hello_minor = MINOR(dev);
printk( KERN_ALERT "hello_major = %x.\n", hello_major );
printk( KERN_ALERT "hello_minor = %x.\n", hello_minor );
/*·ÖÅäheloÉ豸½á¹¹Ìå±äÁ¿*/
hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL);
if(!hello_dev) {
err = -ENOMEM;
printk(KERN_ALERT"Failed to alloc hello_dev.\n");
goto unregister;
}
/*³õʼ»¯É豸*/
err = __hello_setup_dev(hello_dev);
if(err) {
printk(KERN_ALERT"Failed to setup dev: %d.\n", err);
goto cleanup;
}
/*ÔÚ/sys/class/Ŀ¼Ï´´½¨É豸Àà±ðĿ¼hello*/
hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);
if(IS_ERR(hello_class)) {
err = PTR_ERR(hello_class);
printk(KERN_ALERT"Failed to create hello class.\n");
goto destroy_cdev;
}
/*ÔÚ/dev/Ŀ¼ºÍ/sys/class/helloĿ¼Ï·ֱ𴴽¨É豸Îļþhello*/
temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);
if(IS_ERR(temp)) {
err = PTR_ERR(temp);
printk(KERN_ALERT"Failed to create hello device.");
goto destroy_class;
}
/*ÔÚ/sys/class/hello/helloĿ¼Ï´´½¨ÊôÐÔÎļþval*/
err = device_create_file(temp, &dev_attr_val);
if(err < 0) {
printk(KERN_ALERT"Failed to create attribute val.");
goto destroy_device;
}
dev_set_drvdata(temp, hello_dev);
/*´´½¨/proc/helloÎļþ*/
hello_create_proc();
printk(KERN_ALERT"Succedded to initialize hello device.\n");
return 0;
destroy_device:
device_destroy(hello_class, dev);
destroy_class:
class_destroy(hello_class);
destroy_cdev:
cdev_del(&(hello_dev->dev));
cleanup:
kfree(hello_dev);
unregister:
unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);
fail:
return err;
}
/*Ä£¿éÐ¶ÔØ·½·¨*/
static void __exit hello_exit(void) {
dev_t devno = MKDEV(hello_major, hello_minor);
printk(KERN_ALERT"Destroy hello device.\n");
/*ɾ³ý/proc/helloÎļþ*/
hello_remove_proc();
/*Ïú»ÙÉ豸Àà±ðºÍÉ豸*/
if(hello_class) {
device_destroy(hello_class, MKDEV(hello_major, hello_minor));
class_destroy(hello_class);
}
/*ɾ³ý×Ö·ûÉ豸ºÍÊÍ·ÅÉ豸ÄÚ´æ*/
if(hello_dev) {
cdev_del(&(hello_dev->dev));
kfree(hello_dev);
}
/*ÊÍ·ÅÉ豸ºÅ*/
unregister_chrdev_region(devno, 1);
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("First Android Driver");
module_init(hello_init);
module_exit(hello_exit);
#endif
//