Chinaunix首页 | 论坛 | 博客
  • 博客访问: 82087
  • 博文数量: 14
  • 博客积分: 117
  • 博客等级: 民兵
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-08 12:40
文章分类

全部博文(14)

文章存档

2013年(2)

2012年(12)

我的朋友

分类: LINUX

2012-04-12 20:26:29


点击(此处)折叠或打开

您没有插入代码!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define GPBCON 0x56000010
#define GPBDAT 0x56000014
#define GPBUP  0x56000018
#define DEVICE_NAME "my_irq_test"
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;
volatile unsigned long *gpfup  = NULL;
unsigned int  my_major   = 0;
unsigned int  my_minor   = 0;
unsigned int  baseminor  = 0;
unsigned int  wait_count = 0;
char *my_name = "leds_test";
dev_t dev;
struct cdev *cdev;
char key_value;
int print_key_value;
/*定义并初始化小任务队列*/
void my_do_tasklet(unsigned long);
DECLARE_TASKLET(my_tasklet, my_do_tasklet, 0);
/*初始化等待队列*/
DECLARE_WAIT_QUEUE_HEAD(my_queue);
/*定义定时器变量*/
struct timer_list my_timer;
int ret;
/*tasklet中断下半部处理函数:打印键值*/
void my_do_tasklet(unsigned long my)
{
 printk("now key_value is %d\n", print_key_value);
}
/*设置定时器超时处理程序:1s后灭灯*/
static void timer_func(unsigned long data)
{
     *gpfdat |=  (0xF<<5);           
}
/*中断上半部处理函数*/
static irqreturn_t my_interrupt(int irq, void *dev_id)
{
 switch(irq)
 {
  case 17: //IRQ_EINT1
   printk("--enter interrupt 1--\n"); 
   key_value=0x1;
   break;
  case 18:  //IRQ_EINT2
   printk("--enter interrupt 2--\n"); 
   key_value=0x2;
   break;
  case 19: //IRQ_EINT3
   printk("--enter interrupt 3--\n"); 
   key_value=0x3;
   break;
  case 48:   //IRQ_EINT4
   printk("--enter interrupt 4--\n"); 
   key_value=0x4;
   break;
  defaule:
   printk("%d\n",irq);
   break;
 }
   
 print_key_value = (int)key_value;
 wait_count= 1; 
 /* 唤醒休眠的进程 */
 wake_up_interruptible(&my_queue);
 
 /*调度my_tasklet函数*/
 tasklet_schedule(&my_tasklet);  
 return IRQ_HANDLED;
}
/*设置为中断模式并下降沿触发 */
static void init_key_exint(void)
{  
 /*key configure, 1、2、3可以不用配置,因为本开发板已经实现*/
 s3c2410_gpio_cfgpin(S3C2410_GPF1,S3C2410_GPF1_EINT1);
 s3c2410_gpio_pullup(S3C2410_GPF1,1);
 s3c2410_gpio_cfgpin(S3C2410_GPF2,S3C2410_GPF2_EINT2);
 s3c2410_gpio_pullup(S3C2410_GPF4,1);
 s3c2410_gpio_cfgpin(S3C2410_GPF3,S3C2410_GPF3_EINT3);
 s3c2410_gpio_pullup(S3C2410_GPF4,1);
 s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF4_EINT4);
 s3c2410_gpio_pullup(S3C2410_GPF4,1);
 /*EXINT1-4:falling edge triger*/ 
 /*__raw_writel((__raw_readl(S3C2410_EXTINT0) &
  (~(0xfff<<4)))|(0x492<<4), S3C2410_EXTINT0);
 */
 //用以上的方法经常会出现异常情况,原因?
 set_irq_type(IRQ_EINT1 , IRQ_TYPE_EDGE_FALLING);
 set_irq_type(IRQ_EINT2 , IRQ_TYPE_EDGE_FALLING);
 set_irq_type(IRQ_EINT3 , IRQ_TYPE_EDGE_FALLING);
 set_irq_type(IRQ_EINT4 , IRQ_TYPE_EDGE_FALLING);
 
}

static int chr_open(struct inode *inode,struct file *file)

 init_key_exint();
 
 if (request_irq(IRQ_EINT1, &my_interrupt, IRQF_DISABLED, DEVICE_NAME, NULL))
  return -EAGAIN;
 if (request_irq(IRQ_EINT2, &my_interrupt, IRQF_DISABLED, DEVICE_NAME, NULL))
  return -EAGAIN;
 if (request_irq(IRQ_EINT3, &my_interrupt, IRQF_DISABLED, DEVICE_NAME, NULL))
  return -EAGAIN;
 if (request_irq(IRQ_EINT4, &my_interrupt, IRQF_DISABLED, DEVICE_NAME, NULL))
  return -EAGAIN;
 
 return 0;
}
static int chr_close(struct inode *inode,struct file *file)
{
 free_irq(IRQ_EINT1,NULL);
 free_irq(IRQ_EINT2,NULL);
 free_irq(IRQ_EINT3,NULL);
 free_irq(IRQ_EINT4,NULL);
 del_timer(&my_timer);
 return 0;
}
static ssize_t chr_write(struct file *file, const int __user *user_buf, size_t count, loff_t *ofset)
{
 printk("write finished\n"); 
 return count;
}
static ssize_t chr_read(struct file *file,char __user *user_buf, size_t count, loff_t *ofset)
{
 wait_count = 0;
 
 if (count < 1024)
 {
  if (!wait_count)
  {
   if (file->f_flags & O_NONBLOCK)
   {
    return -EAGAIN;
   }
   else
   {
    /* 如果wait_count等于0,休眠 */
    printk("wait for interrupt...\n");
    wait_event_interruptible(my_queue, wait_count);
   }
  }
  /* 执行到这里时,ev_press等于1,将它清0 */
     wait_count = 0;
     /* 将按键状态复制给用户,并清0 */
  if(copy_to_user(user_buf,&key_value,count))
  {
    printk("copy to user fail \n");
     return -EFAULT;
  }
  
  *ofset += count;
 }
 else
 {
  return -EINVAL;
 }
 return count;
}
static int test_chardev_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)

 switch(cmd)
 {
  case 1:
   *gpfdat=(*gpfdat & ~(0xF<<5)) | (0xE<<5); 
   break;
  case 2:
   *gpfdat=(*gpfdat & ~(0xF<<5)) | (0xD<<5);
   break;
  case 3:
   *gpfdat=(*gpfdat & ~(0xF<<5)) | (0xB<<5);
   break;
  case 4:
   *gpfdat=(*gpfdat & ~(0xF<<5)) | (0x7<<5);
   break;
  default:
            printk("ioctl is  fail\n");
   return -1;
 }
 
 /*初始化并启动定时器,完成下半部工作部署*/
 init_timer(&my_timer);      
    my_timer.expires = jiffies + HZ;   
    my_timer.function = timer_func; 
 printk("1s letar led turn off\n");
 /*激活定时器*/
    add_timer(&my_timer);
     return 0;
}
static struct file_operations f_ops = {
 .owner    =  THIS_MODULE,
 .open    =  chr_open,
 .release  =  chr_close,
 .write    =  chr_write,
 .read     =  chr_read,
 .ioctl    =  test_chardev_ioctl,
};
static int __init leds_drv_init(void)
{
 request_mem_region(GPBCON,4,"GPBC");
    request_mem_region(GPBDAT,4,"GPBD");
    request_mem_region(GPBUP ,4,"GPBU");
 
    /*IO内存映射*/
    gpfcon = ioremap_nocache(GPBCON,4);
    gpfdat = ioremap_nocache(GPBDAT,4);
    gpfup  = ioremap_nocache(GPBUP ,4);
     /*对映射后的IO内存进行位操作*/
 *gpfcon = (*gpfcon & ~(0xFF<<10)) | (0x55<<10);   //配置GPB5-8为输出
    *gpfdat = (*gpfdat & ~(0xF<<5))   | (0xF<<5);     //配置GPB5-8输出 1
    *gpfup  = (*gpfup  & ~(0xF<<5))   | (0xF<<5);     //配置GPB5-8 上拉电阻禁止

 /*分配设备编号*/
 if (my_major)
 {
  dev = MKDEV(my_major, my_minor);
  register_chrdev_region(dev, 1, my_name);
 }
 else
 {
  alloc_chrdev_region(&dev, baseminor, 1, my_name);
 }
 /*注册字符设备*/
 cdev = cdev_alloc();
 cdev_init(cdev, &f_ops);
 cdev->owner = THIS_MODULE;
 cdev_add(cdev, dev, 1);
 
 return 0;
}
static void __exit leds_drv_exit(void)
{
 unregister_chrdev_region(dev, 1);
 cdev_del(cdev); 
 /*IO内存释放*/
    release_mem_region(GPBCON,4);
    release_mem_region(GPBDAT,4);
    release_mem_region(GPBUP,4);
 
    /*IO内存解除映射*/
    iounmap(gpfcon);
    iounmap(gpfdat);
    iounmap(gpfup);
}
module_init(leds_drv_init);
module_exit(leds_drv_exit);
MODULE_LICENSE("GPL");
 
 
 
通过前两天学习了设备模型(新内核的一种重要的机制),故可将以上程序改为如下(程序已在S3C2440开发板运行过):
 

/*
*按键中断,点亮LED,打印键值,其中涉及到中断、小任务队列,内核定时器,platform平台等内容
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "my_dev"
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
#define GPBUP 0x56000018
volatile unsigned long *gpbc = NULL;
volatile unsigned long *gpbd = NULL;
volatile unsigned long *gpbu = NULL;
static unsigned my_major = 0;
static unsigned my_minor = 0;
static struct cdev *test_cdev;
static dev_t dev;
int print_key_value;
int key_value;
int wait_count;
int result;
/*初始化小任务队列*/
void my_do_tasklet(unsigned long my);
DECLARE_TASKLET(my_tasklet, my_do_tasklet, 0);
/*初始化等待队列*/
DECLARE_WAIT_QUEUE_HEAD(my_queue);
/*定义定时器变量*/
struct timer_list my_timer;
/*设置小任务队列函数作为中断下半部处理:打印键值*/
void my_do_tasklet(unsigned long my)
{
 printk("deal to my_tasklet\n");
 printk("key_value is %d\n", print_key_value);
}
/*设置定时器处理函数:1秒后让灯灭*/
static void timer_fuc(unsigned long data)
{
 printk("time out\n");
 *gpbd |=  (0xF<<5);
}
/*中断上部处理函数*/
static irqreturn_t interrupt_handler(int irq, void * dev_id)
{
 switch(irq)
 {
  case 17: //IRQ_EINT1   
  printk("--enter interrupt 1--\n");    
  key_value=0x1;   
  break;  
 case 18:   //IRQ_EINT2   
  printk("--enter interrupt 2--\n");    
  key_value=0x2;   
  break;  
 case 19: //IRQ_EINT3   
  printk("--enter interrupt 3--\n");    
  key_value=0x3;   
  break;  
 case 48:   //IRQ_EINT4   
  printk("--enter interrupt 4--\n");    
  key_value=0x4;   
  break;  
 default:   
  printk("irq wrong\n");   
  break;   
 }
 print_key_value = (int)key_value;
 wait_count = 1;
 
 /*唤醒休眠的进程*/
 wake_up_interruptible(&my_queue);
 /*调度小任务队列*/
 tasklet_schedule(&my_tasklet);
 return IRQ_HANDLED;
}

/*按键初始化*/
static void init_key_exint(void)
{
 /*key configure*/
 s3c2410_gpio_cfgpin(S3C2410_GPF1,S3C2410_GPF1_EINT1);
 s3c2410_gpio_pullup(S3C2410_GPF1, 1);
 s3c2410_gpio_cfgpin(S3C2410_GPF2,S3C2410_GPF2_EINT2);
 s3c2410_gpio_pullup(S3C2410_GPF2, 1);
 s3c2410_gpio_cfgpin(S3C2410_GPF3,S3C2410_GPF3_EINT3);
 s3c2410_gpio_pullup(S3C2410_GPF3, 1);
 s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF4_EINT4);
 s3c2410_gpio_pullup(S3C2410_GPF4, 1);
 /*EXINT1-4:falling edge triger*/
 set_irq_type(IRQ_EINT1 , IRQ_TYPE_EDGE_FALLING);
 set_irq_type(IRQ_EINT2 , IRQ_TYPE_EDGE_FALLING);
 set_irq_type(IRQ_EINT3 , IRQ_TYPE_EDGE_FALLING);
 set_irq_type(IRQ_EINT4 , IRQ_TYPE_EDGE_FALLING); 
}
static int my_chr_file_open(struct inode *inode, struct file *file)
{
 //按键初始化
 init_key_exint();
 
 //中断申请
 if (request_irq(IRQ_EINT1, &interrupt_handler, IRQF_DISABLED, "my_irq", NULL))
  return -EAGAIN;
 if (request_irq(IRQ_EINT2, &interrupt_handler, IRQF_DISABLED, "my_irq", NULL))
  return -EAGAIN;
 if (request_irq(IRQ_EINT3, &interrupt_handler, IRQF_DISABLED, "my_irq", NULL))
  return -EAGAIN;
 if (request_irq(IRQ_EINT4, &interrupt_handler, IRQF_DISABLED, "my_irq", NULL))
  return -EAGAIN;
 
 //返回
 return 0;
}
static void my_chr_file_release(struct inode *inode, struct file *file)
{
 //中断释放
 free_irq(IRQ_EINT1,NULL); 
 free_irq(IRQ_EINT2,NULL); 
 free_irq(IRQ_EINT3,NULL); 
 free_irq(IRQ_EINT4,NULL); 
 //定时器释放
 del_timer(&my_timer);
}

static ssize_t my_chr_file_read(struct file *file, const int __user *user_buf, size_t count, loff_t *ofset)
{
 wait_count = 0;
 if (count < 1024)
 {
  if (!wait_count)
  {
   if (file->f_flags & O_NONBLOCK)
   {    
    return -EAGAIN;
   }
   else
   {
    printk("wait for interrupt.....\n");
    wait_event_interruptible(my_queue, wait_count);
   }
  }
  /*被唤醒后执行到此,此时将wait_count清0*/
  wait_count = 0;
  if (copy_to_user(user_buf, &key_value, count))
  {
    printk("copy to user fail \n");
    return -EFAULT;
  }
  
  *ofset += count;
 }
 else
 {  
  return -EINVAL;
 }
 
 return count;
}
static ssize_t my_chr_file_write(struct file *file, const int __user *user_buf, size_t count, loff_t *ofset)
{
 printk("write finish\n");
 return 0;
}
static int my_chr_file_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
 switch (cmd)
 {
  case 1:
   *gpbd =(*gpbd & ~(0xF<<5)) | (0xE<<5);    
   break;
  case 2:
   *gpbd =(*gpbd & ~(0xF<<5)) | (0xD<<5);    
   break;
  case 3:
   *gpbd =(*gpbd & ~(0xF<<5)) | (0xB<<5);    
   break;
  case 4:
   *gpbd =(*gpbd & ~(0xF<<5)) | (0x7<<5);    
   break;
  default:
   printk("ioctl fail\n");
   break;
 }
 /*初始化并启动定时器,完成下半部工作部署*/
 init_timer(&my_timer);
 my_timer.expires  = jiffies + HZ;
 my_timer.function = timer_fuc;
 add_timer(&my_timer);     //激活定时器
 return 0;
}
/*文件操作结构体定义*/
static struct file_operations f_ops = {
 .owner   = THIS_MODULE,
 .open   = my_chr_file_open,
 .release  = my_chr_file_release,
 .read   = my_chr_file_read,
 .write   = my_chr_file_write,
 .ioctl   = my_chr_file_ioctl,
};
static void my_dev_release(struct device *dev)
{
 printk("goodby my_dev release\n");
}
/*平台设备结构体定义*/
static struct platform_device my_chr_device = {
 .name = "my_chr_dev",
 .id = -1,
 .dev = {
  .release = my_dev_release,
 },
};
EXPORT_SYMBOL(my_chr_device); //声明一个内核的全局符号my_dev_device

/*设备探测*/
static int __devinit my_dev_probe(struct platform_device *pdev)

 //分配设备号
 if (my_major)
 {
  dev = MKDEV(my_major, my_minor);
  register_chrdev_region(dev, 1, DEVICE_NAME);
 }
 else
 {
  result= alloc_chrdev_region(&dev, my_minor, 1, DEVICE_NAME);
  my_major = MAJOR(dev);
 }
 if (result < 0)
 {
  printk(KERN_WARNING"my_dev: cannot get major %d \n",my_major); 
  return result;
 }

 //字符设备注册
 test_cdev = cdev_alloc();
 cdev_init(test_cdev, &f_ops);
 test_cdev->owner = THIS_MODULE;
 result = cdev_add(test_cdev, dev, 1);
 if(result)
 {
  printk("<1>Error %d while register device!\n",result);
 }
 
 //IO内存申请
 request_mem_region(GPBCON, 4, "GPBC");
 request_mem_region(GPBDAT, 4, "GPBD");
 request_mem_region(GPBUP, 4, "GPBU");
 //IO内存映射
 gpbc = ioremap_nocache(GPBCON, 4);
 gpbd = ioremap_nocache(GPBDAT, 4);
 gpbu = ioremap_nocache(GPBUP, 4);
 //对映射后的IO进行位操作
 *gpbc = (*gpbc & ~(0xFF<<10)) | (0x55<<10);   //配置GPB5-8为输出
 *gpbd = (*gpbd & ~(0xF<<5))   | (0xF<<5);     //GPB5-8输出为1
 *gpbu = (*gpbu & ~(0xF<<5))   | (0xF<<5);     //禁止上拉
 return 0;
}
static void __devexit my_dev_remove(struct platform_device *pdev)
{
 //注销字符设备
 unregister_chrdev_region(dev, 1);
 cdev_del(test_cdev);
 
 //IO内存释放
 release_mem_region(GPBCON, 4);
 release_mem_region(GPBDAT, 4);
 release_mem_region(GPBUP, 4);
 
 //IO去映射
 iounmap(gpbc);
    iounmap(gpbd);
    iounmap(gpbu);
}

/*平台驱动结构体定义*/
static struct platform_driver my_chr_dev_driver = {
 .probe = my_dev_probe,                 //驱动探测
 .remove = __devexit_p(my_dev_remove),  //驱动移除
 .driver = {
  .name = "my_chr_dev",    //务必和平台设备的名字一样
  .owner = THIS_MODULE,
 },
  
};
EXPORT_SYMBOL(my_chr_dev_driver); //声明一个内核的全局符号my_dev_driver

static int __init my_chr_dev_init(void)
{
 //平台设备注册
 platform_device_register(&my_chr_device);
 printk("go to my_dev_probe init\n");
 //平台驱动注册
 return platform_driver_register(&my_chr_dev_driver);
}
static void __exit my_chr_dev_exit(void)
{
 //平台设备注销
 platform_device_unregister(&my_chr_device);
 printk("goodby my_dev probe cleanup\n");
 
 //平台驱动注销
 platform_driver_unregister(&my_chr_dev_driver);
}
 
module_init(my_chr_dev_init);
module_exit(my_chr_dev_exit);
MODULE_LICENSE("GPL");
阅读(3403) | 评论(6) | 转发(1) |
给主人留下些什么吧!~~

hua9072012-04-17 20:03:59

十七岁的回忆: result= alloc_chrdev_region(&dev, my_minor, 1, DEVICE_NAME);
  my_major = MAJOR(dev);
这一句是干什么的???.....
你好,这是动态分配设备编号。

十七岁的回忆2012-04-16 21:12:09

result= alloc_chrdev_region(&dev, my_minor, 1, DEVICE_NAME);
  my_major = MAJOR(dev);
这一句是干什么的???

我是月老2012-04-15 20:49:23

呵呵,楼主的帖子不错,可以看一看的

十七岁的回忆2012-04-14 12:11:19

还好啊,其实再多看看基本能知道个大概啊

夏冰软件2012-04-13 16:55:53

写的不错,支持一下