Chinaunix首页 | 论坛 | 博客
  • 博客访问: 319185
  • 博文数量: 68
  • 博客积分: 1501
  • 博客等级: 上尉
  • 技术积分: 1010
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-30 09:52
文章分类

全部博文(68)

文章存档

2010年(1)

2009年(67)

我的朋友

分类:

2009-01-10 21:22:40

/*
 * main.c -- the bare test char module
 *
 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
 * Copyright (C) 2001 O'Reilly & Associates
 *
 * The source code in this file can be freely used, adapted,
 * and redistributed in source or binary form, so long as an
 * acknowledgment appears in derived source files.  The citation
 * should list that the code comes from the book "Linux Device
 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 * by O'Reilly & Associates.   No warranty is attached;
 * we cannot take responsibility for errors or fitness for use.
 *
 */
//#include
#include
#include
#include
#include    // tasklet
#include  /* printk() */
#include   /* kmalloc() */
#include   /* everything... */
#include  /* error codes */
#include  /* size_t */
#include
#include  /* O_ACCMODE */
#include
#include
#include
//#include
#include

#include  // wait_event_interruptible, wake_up_interruptible
#include
#include   /* cli(), *_flags */
#include  /* copy_*_user */
#include
#include
#include
#include
#include
#include
 
int test_major =   220;
int test_minor =   0;
int test_nr_devs = 1; /* number of bare test devices */
 
static struct cdev *test_devices;
static struct semaphore sem; 
static wait_queue_head_t mywait;

module_param(test_major, int, S_IRUGO);
module_param(test_minor, int, S_IRUGO);
module_param(test_nr_devs, int, S_IRUGO);

MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");
 
void __iomem * base_addr; 
#define WAIT4INT(x)  (((x)<<8) | S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_XY_PST(3))
#define AUTOPST         (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
#define AD_COUNT 5
unsigned int Gabs[AD_COUNT];
unsigned long xp;
unsigned long yp;
void Startad(void)
{
   writel((S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST), base_addr+S3C2410_ADCTSC);
   writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
   printk("<1> start ad conveting\n");
 }
irqreturn_t stylus_updown(int irq,void * dev_id,struct pt_regs * regs)
{
 int temp_updown;
 temp_updown=__raw_readl(base_addr+S3C2410_ADCDAT0)&(1<<15);
 if (temp_updown==0)       // stylus down
  {
  printk("<1>the stylus is down,state=%d\n",temp_updown);
  Startad();
   }
 else
  {  
  printk("<1>the stylus is up,state=%d\n",temp_updown);
  writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
  }
 printk("<1> in interrupt\n");
 return IRQ_HANDLED;

}
irqreturn_t ad_action(int irq,void * dev_id,struct pt_regs * regs)
{
    unsigned long data0;
    unsigned long data1;
    static char counter=0;                      // AD计算次数
    data0 = readl(base_addr+S3C2410_ADCDAT0);
    data1 = readl(base_addr+S3C2410_ADCDAT1);
    counter++;
    xp+=(data1&0x3ff);
    yp+=(data0&0x3ff);
    if (counter>AD_COUNT)
     {
  xp=xp/AD_COUNT;
  yp=yp/AD_COUNT;
 
  writel(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
//此处若不添加触摸笔抬起状态,只要触摸笔点击就会一直连续的计算坐标值,添加后就只计算5次
  printk("<1> xp_average=%d,yp_average=%d,counter=%d\n",xp,yp,counter);
  counter=0;
  xp=0;
  yp=0;
  return IRQ_HANDLED;
  }
 
 printk("<1> xp=%d,yp=%d,\n",xp,yp);
 Startad();
       
 return IRQ_HANDLED;

}
int test_open(struct inode *inode, struct file *filp)
{

 struct clk *clk;
 clk=clk_get(NULL,"adc");
 if(IS_ERR(clk))  panic("error to get adc clock\n"); 
 clk_enable(clk);
       
 
 try_module_get(THIS_MODULE);
 
 printk(KERN_EMERG"device opening\n");
 
 
 s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPIO_OUTPUT);               // LED
 
     s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);
     s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);
     s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);
     s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
 
 base_addr=ioremap(S3C2410_PA_ADC,0X100);
 if (base_addr == NULL) {
        printk(KERN_ERR "Failed to remap register block\n");
        return -ENOMEM;
    }
     __raw_writel(1<<14|55<<6,base_addr+S3C2410_ADCCON);         // prescale
     __raw_writel(20000,base_addr+S3C2410_ADCDLY);              // adcdly
 writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);   // 设置updown=0,等待触摸笔点击状态
printk(KERN_EMERG"device opening over \n");
           
 
 
 return 0;          /* success */
}
int test_release(struct inode *inode, struct file *filp)
{
 module_put(THIS_MODULE);
 
 iounmap(base_addr);
 printk(KERN_EMERG"device closeing now\n");
 
 
 return 0;
}
/*
 * Follow the list
 */

ssize_t test_read(struct file *filp, int __user *buf, size_t count,
                loff_t *f_pos)
{

 ssize_t retval = 0;
 
 char b[5]={0};
 
 
 if (down_interruptible(&sem))
  return -ERESTARTSYS;
 
 /*
 if (copy_to_user(buf, &test_value, sizeof(test_value))) {
  retval = -EFAULT;
  printk("<1> read error");
  goto out;
 }
 */
 
 
 

 
 
 retval = count;
 printk(KERN_EMERG"device reading\n,b[0]=%d,b[1]=%d\n",b[0],b[1]);
  out:
 up(&sem);
 return retval;
}
 
 
struct file_operations test_fops = {
 .owner =    THIS_MODULE,
 .read =     test_read,
 .open =     test_open,
 .release =  test_release,
 
};
/*
 * Finally, the module stuff
 */
/*
 * The cleanup function is used to handle initialization failures as well.
 * Thefore, it must be careful to work correctly even if some of the items
 * have not been initialized
 */
void test_cleanup_module(void)
{
 
 dev_t devno = MKDEV(test_major, test_minor);
 if (test_devices) {
   
  cdev_del(test_devices);
  
        }
 free_irq(IRQ_TC,NULL);
    free_irq(IRQ_ADC,NULL);
 unregister_chrdev_region(devno, 1);
}

/*
 * Set up the char_dev structure for this device.
 */
static void test_setup_cdev(struct cdev *dev, int index)          
{
 int err, devno = MKDEV(test_major, test_minor + index);
   
     dev=cdev_alloc();
 cdev_init(dev, &test_fops);     
 dev->owner = THIS_MODULE;
 dev->ops = &test_fops;
 err = cdev_add (dev, devno, 1);    
 
 if (err)
  printk(KERN_NOTICE "Error %d adding test%d", err, index);
}

int test_init_module(void)
{
 int result;
 dev_t dev = 0;

 if (test_major)
  {
  dev = MKDEV  (test_major,test_minor);       
  result = register_chrdev_region(dev, 1, "test");        
  }
  else
  {                  
   result = alloc_chrdev_region(&dev, test_minor, 1, 
     "test");
   test_major = MAJOR(dev);     
  }
 if (result < 0) {
  printk(KERN_WARNING "test: can't get major %d\n", test_major);
  return result;
 }
  init_MUTEX(&sem);                           
  test_setup_cdev(test_devices, 0);
  init_waitqueue_head(&mywait);
        /* At this point call the init function for any friend device */
    dev = MKDEV(test_major, test_minor);
 printk("<1>hello,i am coming\n");
 
  if (request_irq(IRQ_ADC, ad_action,IRQF_SAMPLE_RANDOM, "s3c2410_action", NULL))
      {
        printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
        iounmap(base_addr);
        return -EIO;
      }
       if (request_irq(IRQ_TC, stylus_updown,IRQF_SAMPLE_RANDOM, "s3c2410_action", NULL))
      {
        printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
        iounmap(base_addr);
        return -EIO;
      }
     
 return 0; /* succeed */
  fail:
 test_cleanup_module();
 return result;
}
module_init(test_init_module);
module_exit(test_cleanup_module);
阅读(1024) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~