模块驱动相关
基本思路:
1.module_init(初始化函数)
2.module_exit(退出时的函数)
3.初始化函数要做的基本工作:
request_irq()//为设备申请中断
register_chrdev()//注册字符型设备的操作
操作类型存于file_operations结构体中
4.具体实现file_operations结构体中涉及的操作,基本的有open,read,write,release,ctl...
ps:
module_init,module_exit两个宏定义在<linux/init.h>中,
file_operations结构体定义于<linux/fs.h>中,
register_chrdev()函数声明在<linux/fs.h>中,定义在<linux/fs/dervices.c>中,
request_irq()函数声明在<linux/sched.h>中,
//AD驱动模块
 /*
/*
 * s3c2410-adc.c
 * s3c2410-adc.c
 *
 *
 * S3C2410 ADC
 * S3C2410 ADC 
 *  exclusive with s3c2410-ts.c
 *  exclusive with s3c2410-ts.c
 *
 *
 * Author: SeonKon Choi <bushi@mizi.com>
 * Author: SeonKon Choi <bushi@mizi.com>
 * Date  : $Date: 2003/01/20 14:24:49 $
 * Date  : $Date: 2003/01/20 14:24:49 $ 
 *
 *
 * $Revision: 1.1.2.6 $
 * $Revision: 1.1.2.6 $
 *
 *
 2004-6-14 add a device by threewater<threewater@up-tech.com>
    2004-6-14 add a device by threewater<threewater@up-tech.com>

 Fri Dec 03 2002 SeonKon Choi <bushi@mizi.com>
   Fri Dec 03 2002 SeonKon Choi <bushi@mizi.com>
 - initial
   - initial

 *
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 * for more details.
 */
 */
 #include <linux/config.h>
#include <linux/config.h>
 #include <linux/module.h>
#include <linux/module.h>
 #include <linux/kernel.h>
#include <linux/kernel.h>
 #include <linux/init.h>
#include <linux/init.h>

 #include <linux/sched.h>
#include <linux/sched.h>
 #include <linux/irq.h>
#include <linux/irq.h>
 #include <linux/delay.h>
#include <linux/delay.h>

 #include <asm/hardware.h>
#include <asm/hardware.h>
 #include <asm/semaphore.h>
#include <asm/semaphore.h>
 #include <asm/uaccess.h>
#include <asm/uaccess.h>

 #include "s3c2410-adc.h"
#include "s3c2410-adc.h"

 #undef DEBUG
#undef DEBUG
 //#define DEBUG
//#define DEBUG
 #ifdef DEBUG
#ifdef DEBUG
 #define DPRINTK(x
#define DPRINTK(x ) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
 #else
#else
 #define DPRINTK(x
#define DPRINTK(x ) (void)(0)
) (void)(0)
 #endif
#endif

 #define DEVICE_NAME    "s3c2410-adc"
#define DEVICE_NAME    "s3c2410-adc"
 #define ADCRAW_MINOR    1
#define ADCRAW_MINOR    1

 static int adcMajor = 0;
static int adcMajor = 0;

 typedef struct {
typedef struct {
 struct semaphore lock;
    struct semaphore lock;
 wait_queue_head_t wait;
    wait_queue_head_t wait;
 int channel;
    int channel;
 int prescale;
    int prescale;
 }ADC_DEV;
}ADC_DEV;

 static ADC_DEV adcdev;
static ADC_DEV adcdev;

 #define START_ADC_AIN(ch, prescale) \
#define START_ADC_AIN(ch, prescale) \
 do{ \
    do{ \
 ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
        ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
 ADCCON |= ADC_START; \
        ADCCON |= ADC_START; \
 }while(0)
    }while(0)

 static void adcdone_int_handler(int irq, void *dev_id, struct pt_regs *reg)
static void adcdone_int_handler(int irq, void *dev_id, struct pt_regs *reg)
 {
{
 wake_up(&adcdev.wait);
    wake_up(&adcdev.wait);
 }
}

 static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 {
{
 int data;
    int data;

 if(count!=sizeof(data)){
    if(count!=sizeof(data)){
 //error input data size
        //error input data size
 DPRINTK("the size of  input data must be %d\n", sizeof(data));
        DPRINTK("the size of  input data must be %d\n", sizeof(data));
 return 0;
        return 0;
 }
    }

 copy_from_user(&data, buffer, count);
    copy_from_user(&data, buffer, count);
 adcdev.channel=ADC_WRITE_GETCH(data);
    adcdev.channel=ADC_WRITE_GETCH(data);
 adcdev.prescale=ADC_WRITE_GETPRE(data);
    adcdev.prescale=ADC_WRITE_GETPRE(data);

 DPRINTK("set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);
    DPRINTK("set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);

 return count;
    return count;
 }
}

 static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
 {
{
 int ret = 0;
    int ret = 0;

 if (down_interruptible(&adcdev.lock))
    if (down_interruptible(&adcdev.lock))
 return -ERESTARTSYS;
        return -ERESTARTSYS;

 START_ADC_AIN(adcdev.channel, adcdev.prescale);
    START_ADC_AIN(adcdev.channel, adcdev.prescale);
 interruptible_sleep_on(&adcdev.wait);
    interruptible_sleep_on(&adcdev.wait);

 ret = ADCDAT0;
    ret = ADCDAT0;
 ret &= 0x3ff;
    ret &= 0x3ff;
 DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, ret, ADCCON & 0x80 ? 1:0);
    DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, ret, ADCCON & 0x80 ? 1:0);

 copy_to_user(buffer, (char *)&ret, sizeof(ret));
    copy_to_user(buffer, (char *)&ret, sizeof(ret));

 up(&adcdev.lock);
    up(&adcdev.lock);

 return sizeof(ret);
    return sizeof(ret);
 }
}

 static int s3c2410_adc_open(struct inode *inode, struct file *filp)
static int s3c2410_adc_open(struct inode *inode, struct file *filp)
 {
{
 init_MUTEX(&adcdev.lock);
    init_MUTEX(&adcdev.lock);
 init_waitqueue_head(&(adcdev.wait));
    init_waitqueue_head(&(adcdev.wait));

 adcdev.channel=0;
    adcdev.channel=0;
 adcdev.prescale=0xff;
    adcdev.prescale=0xff;

 MOD_INC_USE_COUNT;
    MOD_INC_USE_COUNT;
 DPRINTK( "adc opened\n");
    DPRINTK( "adc opened\n");
 return 0;
    return 0;
 }
}

 static int s3c2410_adc_release(struct inode *inode, struct file *filp)
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
 {
{
 MOD_DEC_USE_COUNT;
    MOD_DEC_USE_COUNT;
 DPRINTK( "adc closed\n");
    DPRINTK( "adc closed\n");
 return 0;
    return 0;
 }
}


 static struct file_operations s3c2410_fops = {
static struct file_operations s3c2410_fops = {
 owner:    THIS_MODULE,
    owner:    THIS_MODULE,
 open:    s3c2410_adc_open,
    open:    s3c2410_adc_open,
 read:    s3c2410_adc_read,
    read:    s3c2410_adc_read,    
 write:    s3c2410_adc_write,
    write:    s3c2410_adc_write,
 release:    s3c2410_adc_release,
    release:    s3c2410_adc_release,
 };
};

 #ifdef CONFIG_DEVFS_FS
#ifdef CONFIG_DEVFS_FS
 static devfs_handle_t devfs_adc_dir, devfs_adcraw;
static devfs_handle_t devfs_adc_dir, devfs_adcraw;
 #endif
#endif

 int __init s3c2410_adc_init(void)
int __init s3c2410_adc_init(void)
 {
{
 int ret;
    int ret;

 /* normal ADC */
    /* normal ADC */
 ADCTSC = 0; //XP_PST(NOP_MODE);
    ADCTSC = 0; //XP_PST(NOP_MODE);

 ret = request_irq(IRQ_ADC_DONE, adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL);
    ret = request_irq(IRQ_ADC_DONE, adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL);
 if (ret) {
    if (ret) {
 return ret;
        return ret;
 }
    }

 ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);
    ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);
 if (ret < 0) {
    if (ret < 0) {
 printk(DEVICE_NAME " can't get major number\n");
        printk(DEVICE_NAME " can't get major number\n");
 return ret;
        return ret;
 }
    }
 adcMajor=ret;
    adcMajor=ret;

 #ifdef CONFIG_DEVFS_FS
#ifdef CONFIG_DEVFS_FS
 devfs_adc_dir = devfs_mk_dir(NULL, "adc", NULL);
    devfs_adc_dir = devfs_mk_dir(NULL, "adc", NULL);
 devfs_adcraw = devfs_register(devfs_adc_dir, "0raw", DEVFS_FL_DEFAULT,
    devfs_adcraw = devfs_register(devfs_adc_dir, "0raw", DEVFS_FL_DEFAULT,
 adcMajor, ADCRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR, &s3c2410_fops, NULL);
                adcMajor, ADCRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR, &s3c2410_fops, NULL);
 #endif
#endif
 printk (DEVICE_NAME"\tinitialized\n");
    printk (DEVICE_NAME"\tinitialized\n");

 return 0;
    return 0;
 }
}

 module_init(s3c2410_adc_init);
module_init(s3c2410_adc_init);

 #ifdef MODULE
#ifdef MODULE
 void __exit s3c2410_adc_exit(void)
void __exit s3c2410_adc_exit(void)
 {
{
 #ifdef CONFIG_DEVFS_FS
#ifdef CONFIG_DEVFS_FS    
 devfs_unregister(devfs_adcraw);
    devfs_unregister(devfs_adcraw);
 devfs_unregister(devfs_adc_dir);
    devfs_unregister(devfs_adc_dir);
 #endif
#endif
 unregister_chrdev(adcMajor, DEVICE_NAME);
    unregister_chrdev(adcMajor, DEVICE_NAME);

 free_irq(IRQ_ADC_DONE, NULL);
    free_irq(IRQ_ADC_DONE, NULL);
 }
}

 module_exit(s3c2410_adc_exit);
module_exit(s3c2410_adc_exit);
 MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");
 #endif
#endif
 
//Makefile
 TARGET = helloworld
TARGET = helloworld
 KDIR = /usr/src/linux
KDIR = /usr/src/linux
 PWD = $(shell pwd)
PWD = $(shell pwd)
 obj-m += $(TARGET).o
obj-m += $(TARGET).o
 default:
default:
 make -C $(KDIR) M=$(PWD) modules
 make -C $(KDIR) M=$(PWD) modules 
1.module_init(初始化函数)
2.module_exit(退出时的函数)
3.初始化函数要做的基本工作:
request_irq()//为设备申请中断
register_chrdev()//注册字符型设备的操作
操作类型存于file_operations结构体中
4.具体实现file_operations结构体中涉及的操作,基本的有open,read,write,release,ctl...
ps:
module_init,module_exit两个宏定义在<linux/init.h>中,
file_operations结构体定义于<linux/fs.h>中,
register_chrdev()函数声明在<linux/fs.h>中,定义在<linux/fs/dervices.c>中,
request_irq()函数声明在<linux/sched.h>中,
//AD驱动模块
 /*
/* * s3c2410-adc.c
 * s3c2410-adc.c *
 * * S3C2410 ADC
 * S3C2410 ADC  *  exclusive with s3c2410-ts.c
 *  exclusive with s3c2410-ts.c *
 * * Author: SeonKon Choi <bushi@mizi.com>
 * Author: SeonKon Choi <bushi@mizi.com> * Date  : $Date: 2003/01/20 14:24:49 $
 * Date  : $Date: 2003/01/20 14:24:49 $  *
 * * $Revision: 1.1.2.6 $
 * $Revision: 1.1.2.6 $ *
 * 2004-6-14 add a device by threewater<threewater@up-tech.com>
    2004-6-14 add a device by threewater<threewater@up-tech.com>
 Fri Dec 03 2002 SeonKon Choi <bushi@mizi.com>
   Fri Dec 03 2002 SeonKon Choi <bushi@mizi.com> - initial
   - initial
 *
 * * This file is subject to the terms and conditions of the GNU General Public
 * This file is subject to the terms and conditions of the GNU General Public * License.  See the file COPYING in the main directory of this archive
 * License.  See the file COPYING in the main directory of this archive * for more details.
 * for more details. */
 */ #include <linux/config.h>
#include <linux/config.h> #include <linux/module.h>
#include <linux/module.h> #include <linux/kernel.h>
#include <linux/kernel.h> #include <linux/init.h>
#include <linux/init.h>
 #include <linux/sched.h>
#include <linux/sched.h> #include <linux/irq.h>
#include <linux/irq.h> #include <linux/delay.h>
#include <linux/delay.h>
 #include <asm/hardware.h>
#include <asm/hardware.h> #include <asm/semaphore.h>
#include <asm/semaphore.h> #include <asm/uaccess.h>
#include <asm/uaccess.h>
 #include "s3c2410-adc.h"
#include "s3c2410-adc.h"
 #undef DEBUG
#undef DEBUG //#define DEBUG
//#define DEBUG #ifdef DEBUG
#ifdef DEBUG #define DPRINTK(x
#define DPRINTK(x ) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);} #else
#else #define DPRINTK(x
#define DPRINTK(x ) (void)(0)
) (void)(0) #endif
#endif
 #define DEVICE_NAME    "s3c2410-adc"
#define DEVICE_NAME    "s3c2410-adc" #define ADCRAW_MINOR    1
#define ADCRAW_MINOR    1
 static int adcMajor = 0;
static int adcMajor = 0;
 typedef struct {
typedef struct { struct semaphore lock;
    struct semaphore lock; wait_queue_head_t wait;
    wait_queue_head_t wait; int channel;
    int channel; int prescale;
    int prescale; }ADC_DEV;
}ADC_DEV;
 static ADC_DEV adcdev;
static ADC_DEV adcdev;
 #define START_ADC_AIN(ch, prescale) \
#define START_ADC_AIN(ch, prescale) \ do{ \
    do{ \ ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
        ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \ ADCCON |= ADC_START; \
        ADCCON |= ADC_START; \ }while(0)
    }while(0)
 static void adcdone_int_handler(int irq, void *dev_id, struct pt_regs *reg)
static void adcdone_int_handler(int irq, void *dev_id, struct pt_regs *reg) {
{ wake_up(&adcdev.wait);
    wake_up(&adcdev.wait); }
}
 static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) {
{ int data;
    int data;
 if(count!=sizeof(data)){
    if(count!=sizeof(data)){ //error input data size
        //error input data size DPRINTK("the size of  input data must be %d\n", sizeof(data));
        DPRINTK("the size of  input data must be %d\n", sizeof(data)); return 0;
        return 0; }
    }
 copy_from_user(&data, buffer, count);
    copy_from_user(&data, buffer, count); adcdev.channel=ADC_WRITE_GETCH(data);
    adcdev.channel=ADC_WRITE_GETCH(data); adcdev.prescale=ADC_WRITE_GETPRE(data);
    adcdev.prescale=ADC_WRITE_GETPRE(data);
 DPRINTK("set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);
    DPRINTK("set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);
 return count;
    return count; }
}
 static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) {
{ int ret = 0;
    int ret = 0;
 if (down_interruptible(&adcdev.lock))
    if (down_interruptible(&adcdev.lock)) return -ERESTARTSYS;
        return -ERESTARTSYS;
 START_ADC_AIN(adcdev.channel, adcdev.prescale);
    START_ADC_AIN(adcdev.channel, adcdev.prescale); interruptible_sleep_on(&adcdev.wait);
    interruptible_sleep_on(&adcdev.wait);
 ret = ADCDAT0;
    ret = ADCDAT0; ret &= 0x3ff;
    ret &= 0x3ff; DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, ret, ADCCON & 0x80 ? 1:0);
    DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, ret, ADCCON & 0x80 ? 1:0);
 copy_to_user(buffer, (char *)&ret, sizeof(ret));
    copy_to_user(buffer, (char *)&ret, sizeof(ret));
 up(&adcdev.lock);
    up(&adcdev.lock);
 return sizeof(ret);
    return sizeof(ret); }
}
 static int s3c2410_adc_open(struct inode *inode, struct file *filp)
static int s3c2410_adc_open(struct inode *inode, struct file *filp) {
{ init_MUTEX(&adcdev.lock);
    init_MUTEX(&adcdev.lock); init_waitqueue_head(&(adcdev.wait));
    init_waitqueue_head(&(adcdev.wait));
 adcdev.channel=0;
    adcdev.channel=0; adcdev.prescale=0xff;
    adcdev.prescale=0xff;
 MOD_INC_USE_COUNT;
    MOD_INC_USE_COUNT; DPRINTK( "adc opened\n");
    DPRINTK( "adc opened\n"); return 0;
    return 0; }
}
 static int s3c2410_adc_release(struct inode *inode, struct file *filp)
static int s3c2410_adc_release(struct inode *inode, struct file *filp) {
{ MOD_DEC_USE_COUNT;
    MOD_DEC_USE_COUNT; DPRINTK( "adc closed\n");
    DPRINTK( "adc closed\n"); return 0;
    return 0; }
}

 static struct file_operations s3c2410_fops = {
static struct file_operations s3c2410_fops = { owner:    THIS_MODULE,
    owner:    THIS_MODULE, open:    s3c2410_adc_open,
    open:    s3c2410_adc_open, read:    s3c2410_adc_read,
    read:    s3c2410_adc_read,     write:    s3c2410_adc_write,
    write:    s3c2410_adc_write, release:    s3c2410_adc_release,
    release:    s3c2410_adc_release, };
};
 #ifdef CONFIG_DEVFS_FS
#ifdef CONFIG_DEVFS_FS static devfs_handle_t devfs_adc_dir, devfs_adcraw;
static devfs_handle_t devfs_adc_dir, devfs_adcraw; #endif
#endif
 int __init s3c2410_adc_init(void)
int __init s3c2410_adc_init(void) {
{ int ret;
    int ret;
 /* normal ADC */
    /* normal ADC */ ADCTSC = 0; //XP_PST(NOP_MODE);
    ADCTSC = 0; //XP_PST(NOP_MODE);
 ret = request_irq(IRQ_ADC_DONE, adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL);
    ret = request_irq(IRQ_ADC_DONE, adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL); if (ret) {
    if (ret) { return ret;
        return ret; }
    }
 ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);
    ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops); if (ret < 0) {
    if (ret < 0) { printk(DEVICE_NAME " can't get major number\n");
        printk(DEVICE_NAME " can't get major number\n"); return ret;
        return ret; }
    } adcMajor=ret;
    adcMajor=ret;
 #ifdef CONFIG_DEVFS_FS
#ifdef CONFIG_DEVFS_FS devfs_adc_dir = devfs_mk_dir(NULL, "adc", NULL);
    devfs_adc_dir = devfs_mk_dir(NULL, "adc", NULL); devfs_adcraw = devfs_register(devfs_adc_dir, "0raw", DEVFS_FL_DEFAULT,
    devfs_adcraw = devfs_register(devfs_adc_dir, "0raw", DEVFS_FL_DEFAULT, adcMajor, ADCRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR, &s3c2410_fops, NULL);
                adcMajor, ADCRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR, &s3c2410_fops, NULL); #endif
#endif printk (DEVICE_NAME"\tinitialized\n");
    printk (DEVICE_NAME"\tinitialized\n");
 return 0;
    return 0; }
}
 module_init(s3c2410_adc_init);
module_init(s3c2410_adc_init);
 #ifdef MODULE
#ifdef MODULE void __exit s3c2410_adc_exit(void)
void __exit s3c2410_adc_exit(void) {
{ #ifdef CONFIG_DEVFS_FS
#ifdef CONFIG_DEVFS_FS     devfs_unregister(devfs_adcraw);
    devfs_unregister(devfs_adcraw); devfs_unregister(devfs_adc_dir);
    devfs_unregister(devfs_adc_dir); #endif
#endif unregister_chrdev(adcMajor, DEVICE_NAME);
    unregister_chrdev(adcMajor, DEVICE_NAME);
 free_irq(IRQ_ADC_DONE, NULL);
    free_irq(IRQ_ADC_DONE, NULL); }
}
 module_exit(s3c2410_adc_exit);
module_exit(s3c2410_adc_exit); MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL"); #endif
#endif
//Makefile
 TARGET = helloworld
TARGET = helloworld KDIR = /usr/src/linux
KDIR = /usr/src/linux PWD = $(shell pwd)
PWD = $(shell pwd) obj-m += $(TARGET).o
obj-m += $(TARGET).o default:
default: make -C $(KDIR) M=$(PWD) modules
 make -C $(KDIR) M=$(PWD) modules  
                    
                 

 
    