tst-driver.c
#ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif
#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> /* printk() */ #include <linux/init.h> /* __init __exit */
#include <linux/types.h> /* size_t */ #include <linux/fs.h> /* file_operation */ #include <asm/uaccess.h> /* copy_to_user, copy_from_user */ #include <asm/hardware.h> #include<asm-arm/arch-s3c2410/S3C2410.h> #include "tst-driver.h"
#define DRIVER_NAME "myDriver"
#ifdef DEBUG #define PRINTK(fmt, arg...) printk(KERN_NOTICE fmt, ##arg) #else #define PRINTK(fmt, arg...) #endif /* KERN_EMERG 用于紧急事件,一般是系统崩溃前的提示信息 KERN_ALERT 用于需要立即采取动作的场合 KERN_CRIT 临界状态,通常设计验证的硬件或软件操作失败 KERN_ERR 用于报告错误状态.设备驱动程序通常会用它报告来自硬件的问题 KERN_WARNING 就可能出现的问题提出警告.这些问题通常不会对系统造成严重破坏 KERN_NOTICE 有必要提示的正常情况.许多安全相关的情况用这个级别汇报 KERN_INFO 提示性信息.有很多驱动程序在启动时用这个级别打印相关信息 KERN_DEBUG 用于调试的信息 */
static int myDriver_Major = 0; /* Driver Major Number */ static int AD_READ (void) { int i,j; int val,aa; val = 0; ADCCON |= 0x2; //ADC转换通过读操作来启动
aa = ADCDAT0 &0x03ff; //启动ADC转换
for(i=0;i<16;i++) { while(!ADCCON&0x8000); //判断ADC转换是否结束
val += (ADCDAT0 &0x03ff); //取出ADC转换值
for(j=0;j<500;j++); } val = val/16; //计算ADC平均转换值
return val; }
/* Driver Operation Functions */ static int myDriver_open(struct inode *inode, struct file *filp) { // int Minor = MINOR(inode->i_rdev);
// filp->private_data = 0;
MOD_INC_USE_COUNT; PRINTK("myDriver open called!\n"); ADCDLY = 10; //ADC转换延时
ADCTSC =(0<<2); //设置ADC为普通模式
/* 进行ADC模块设置,其中x< ADCCON = (0 << 0) | // ADC转换设置 未设置
(0 << 1) | // 读AD数据触发AD转换 未使用
(0 << 2) | // StandBy模式选择 为普通操作模式
(255 << 6) | // CLKDIV = Fpclk /49+1/5 ,即转换时钟为1MHz Fpclk = 10M ADC转换频率400K
(1 << 14) ; // 使能软件预设值
PRINTK(" ADC INIT OK \n"); return 0; }
static int myDriver_release(struct inode *inode, struct file *filp) { // int Minor = MINOR(inode->i_rdev);
MOD_DEC_USE_COUNT; PRINTK("myDriver release called!\n"); return 0; }
static ssize_t myDriver_read(struct file *filp, char *adc_value, size_t count, loff_t *f_pos) { int adc=0; size_t read_size = count; // PRINTK("myDriver read called!\n");
// PRINTK("\tcount=%d, pos=%d\n", count, (int)*f_pos);
adc= AD_READ(); copy_to_user(adc_value, &adc, sizeof(adc)); // PRINTK("adc_vale = %d \n",adc);
return read_size; }
static int myDriver_ioctl(struct inode *inode, struct file *file, unsigned int ch,unsigned long arg) { PRINTK("myDriver ioctl called!\n"); if( (ch>8)||(ch<0 ) ) { PRINTK(" not a valid parameter,parameter must betwween 0 and 8 \n"); return -1; } ADCCON |= (ch << 3);// channel set
PRINTK(" ADC INIT OK \n"); return 0; }
/* Driver Operation structure */ static struct file_operations myDriver_fops = { owner: THIS_MODULE, open: myDriver_open, ioctl: myDriver_ioctl, read: myDriver_read, release: myDriver_release, };
/* Module Init & Exit function */ #ifdef CONFIG_DEVFS_FS devfs_handle_t devfs_myDriver_dir; devfs_handle_t devfs_myDriver_raw; #endif static int __init myModule_init(void) {
/* Module init code */ PRINTK("myModule_init\n"); /* Driver register */ myDriver_Major = register_chrdev(0, DRIVER_NAME, &myDriver_fops); PRINTK("register myDriver OK! Major = %d\n", myDriver_Major); return 0; }
static void __exit myModule_exit(void) { /* Module exit code */ PRINTK("myModule_exit\n"); /* Driver unregister */ if(myDriver_Major > 0) { #ifdef CONFIG_DEVFS_FS devfs_unregister(devfs_myDriver_raw); devfs_unregister(devfs_myDriver_dir); #endif unregister_chrdev(myDriver_Major, DRIVER_NAME); } return; }
MODULE_AUTHOR("tastesweet@yeah.net"); MODULE_LICENSE("Dual BSD/GPL"); module_init(myModule_init); module_exit(myModule_exit);
|