第一次在X86下写LINUX驱动,具体来说应该是IO驱动。X86的IO是独立编址的。所以用OUTB和INB直接操作IO地址就可以。这点跟ARM等其它CPU不一样。。
数据采集采用DMA的传输方式。。
2.4下可调的调式代码如下:
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h> /* size_t */
#include <linux/fs.h> /* file_operation */
#include <asm/uaccess.h> /* copy_to_user, copy_from_user */
#include<asm/io.h>
#include<asm/dma.h>
#define DRIVER_NAME "myPump"
#define DMA_BUFFER_SIZE 1024
#define PUMP_ADDRESS 0x308
#define ADBase 0x300 /*ADT采集板基地址*/
static unsigned char IO =0xFF;
static char status[20]="abcdefg ni hao";
static int myPump_Major = 0; /* Driver Major Number */
static unsigned char IT[3]={0xFF,0xFF,0xFF};
static short DA[4]={0,0,0,0};
static void DASentOut();
static short *dma_buffer;
static int Add[16];
static short ADC[16];
static short ADM;
static short AD[10][16],ADSS[10][16];
static short ADFast[16];
static short st=0;//测10组数。DMA读1024*2个字节读10次
static unsigned int AD_IRQ=0x77;
static void int_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
{
register int i;
st++;
if(st>9)
{
memcpy(ADSS,AD,320);
st = 0;
}
memset(Add,0,64);
memset(ADC,0,32);
for(i=0;i<DMA_BUFFER_SIZE;i++)
{ ADM=(dma_buffer[i]>>12)&0x0f;
Add[ADM]+=dma_buffer[i]&0x0fff;
ADC[ADM]++;
}
for(i=0;i<16;i++)
if(ADC[i]>0)
{ ADFast[i]=(int)(Add[i]/ADC[i]);
AD[st][i]=ADFast[i];
}
else
{ AD[st][i]=0;
}
outb(inb(ADBase+5)&0xfd,ADBase+5);
outb(0x20,0xa0);
outb(0x20,0x20);
}
static ad_dma_start(int channel,int mode,unsigned char *dma_buffer,unsigned int count)
{
unsigned long flags;
flags = claim_dma_lock();
disable_dma(channel);
clear_dma_ff(channel);
set_dma_mode(channel,mode);
set_dma_addr(channel,virt_to_bus(dma_buffer));
set_dma_count(channel,count);
outb(0xf0,ADBase+3);
outb(inb(ADBase+4)|0x70,ADBase+4);
outb((((inb(ADBase+6))&0xC0)|0x0C),ADBase+6);
enable_dma(channel);
}
static int myPump_open(struct inode *inode, struct file *filp)
{
MOD_INC_USE_COUNT;
// dma_buffer = (short*)__get_dma_pages(GFP_KERNEL,get_order(DMA_BUFFER_SIZE*2));
//request_irq(AD_IRQ,int_interrupt,0,DRIVER_NAME,myPump_Major);
//request_dma(3,DRIVER_NAME);
// ad_dma_start(3,DMA_MODE_READ,dma_buffer,1024*2);
return 0;
}
static int myPump_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
free_dma(3);
free_irq(AD_IRQ,myPump_Major);
if(dma_buffer)
{
free_pages((unsigned long)dma_buffer,get_order(DMA_BUFFER_SIZE));
}
return 0;
}
static ssize_t myPump_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
// status = inb(PUMP_ADDRESS);
// printk(KERN_ALERT "Rd, The fucking Rt\n");
//outb(0xFE,ADBase+8);
// TestShow();
copy_to_user(buf,ADSS,count);
return 0;
}
static ssize_t myPump_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
// unsigned char status;
// get_user(status,(char *)buf)
char strt;
int lsb=0,msb=0;
int i;
copy_from_user(status,buf,count);
memcpy(DA,&status[1],8);
switch(status[0])
{
case 0x01://SendPump
outb(status[1],PUMP_ADDRESS);
break;
case 0x02://SendDa;
outb(inb(ADBase+4)|0x80,ADBase+4);
for(i=0;i<4;i++)
{ lsb=DA[i]&0xff;
msb=(DA[i]/256)&0x0f;
outb(msb+(i)*16,ADBase+2);
outb(lsb,ADBase+1);
}
inb(ADBase+2);
break;
}
/* int lsb=0,msb=0;
int i;
if(IT[0]&0x08)
{ IT[0]=IT[0]&0xf7;
outb(IT[0],0x308);
}
outb(0xfb,PUMP_ADDRESS);
short DA[4]={4000,4000,4000,4000};
outb(inb(ADBase+4)|0x80,ADBase+4);
for(i=1;i<5;i++)
{ lsb=DA[i]&0xff;
msb=(DA[i]/256)&0x0f;
outb(msb+(i-1)*16,ADBase+2);
outb(lsb,ADBase+1);
}
inb(ADBase+2);*/
// outb(0xFF,ADBase+8);
return 0;
}
static int myPump_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
printk(KERN_ALERT "Hello,CTRIO init open \n");
DA[0]=cmd;DA[1]=cmd;DA[2]=cmd;DA[3]=cmd;
DASentOut();
return 1;
}
static struct file_operations myPump_fops = {
owner: THIS_MODULE,
write: myPump_write,
read: myPump_read,
ioctl: myPump_ioctl,
open: myPump_open,
release: myPump_release,
};
static int myPump_init(void)
{
printk(KERN_ALERT "Hello, The fucking crazy world\n");
myPump_Major = register_chrdev(240, DRIVER_NAME, &myPump_fops);
// request_region(ADBase, 16, DRIVER_NAME);
outb(0x88,ADBase+11);
DASentOut();
outb(0xff,ADBase+8);
outb(0xff,ADBase+9);
outb(0xF0,ADBase+10);
// IO[2]=inportb(ADBase+10);
return 0;
}
static void myPump_exit(void)
{
printk(KERN_ALERT "Bye, The fucking crazy world!\n");
}
static void DASentOut()
{
int lsb=0,msb=0;
int i;
outb(inb(ADBase+4)|0x80,ADBase+4);
for(i=0;i<4;i++)
{ lsb=DA[i]&0xff;
msb=(DA[i]/256)&0x0f;
outb(msb+(i)*16,ADBase+2);
outb(lsb,ADBase+1);
}
inb(ADBase+2);
}
module_init(myPump_init);
module_exit(myPump_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("albcamus <sankye@163.com>");
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h> /* size_t */
#include <linux/fs.h> /* file_operation */
#include <asm/uaccess.h> /* copy_to_user, copy_from_user */
#include<asm/io.h>
#include<asm/dma.h>
#define DRIVER_NAME "myPump"
#define DMA_BUFFER_SIZE 1024
#define PUMP_ADDRESS 0x308
#define ADBase 0x300 /*ADT采集板基地址*/
static unsigned char IO =0xFF;
static char status[20]="abcdefg ni hao";
static int myPump_Major = 0; /* Driver Major Number */
static unsigned char IT[3]={0xFF,0xFF,0xFF};
static short DA[4]={0,0,0,0};
static void DASentOut();
static short *dma_buffer;
static int Add[16];
static short ADC[16];
static short ADM;
static short AD[10][16],ADSS[10][16];
static short ADFast[16];
static short st=0;//测10组数。DMA读1024*2个字节读10次
static unsigned int AD_IRQ=0x77;
static void int_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
{
register int i;
st++;
if(st>9)
{
memcpy(ADSS,AD,320);
st = 0;
}
memset(Add,0,64);
memset(ADC,0,32);
for(i=0;i<DMA_BUFFER_SIZE;i++)
{ ADM=(dma_buffer[i]>>12)&0x0f;
Add[ADM]+=dma_buffer[i]&0x0fff;
ADC[ADM]++;
}
for(i=0;i<16;i++)
if(ADC[i]>0)
{ ADFast[i]=(int)(Add[i]/ADC[i]);
AD[st][i]=ADFast[i];
}
else
{ AD[st][i]=0;
}
outb(inb(ADBase+5)&0xfd,ADBase+5);
outb(0x20,0xa0);
outb(0x20,0x20);
}
static ad_dma_start(int channel,int mode,unsigned char *dma_buffer,unsigned int count)
{
unsigned long flags;
flags = claim_dma_lock();
disable_dma(channel);
clear_dma_ff(channel);
set_dma_mode(channel,mode);
set_dma_addr(channel,virt_to_bus(dma_buffer));
set_dma_count(channel,count);
outb(0xf0,ADBase+3);
outb(inb(ADBase+4)|0x70,ADBase+4);
outb((((inb(ADBase+6))&0xC0)|0x0C),ADBase+6);
enable_dma(channel);
}
static int myPump_open(struct inode *inode, struct file *filp)
{
MOD_INC_USE_COUNT;
// dma_buffer = (short*)__get_dma_pages(GFP_KERNEL,get_order(DMA_BUFFER_SIZE*2));
//request_irq(AD_IRQ,int_interrupt,0,DRIVER_NAME,myPump_Major);
//request_dma(3,DRIVER_NAME);
// ad_dma_start(3,DMA_MODE_READ,dma_buffer,1024*2);
return 0;
}
static int myPump_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
free_dma(3);
free_irq(AD_IRQ,myPump_Major);
if(dma_buffer)
{
free_pages((unsigned long)dma_buffer,get_order(DMA_BUFFER_SIZE));
}
return 0;
}
static ssize_t myPump_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
// status = inb(PUMP_ADDRESS);
// printk(KERN_ALERT "Rd, The fucking Rt\n");
//outb(0xFE,ADBase+8);
// TestShow();
copy_to_user(buf,ADSS,count);
return 0;
}
static ssize_t myPump_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
// unsigned char status;
// get_user(status,(char *)buf)
char strt;
int lsb=0,msb=0;
int i;
copy_from_user(status,buf,count);
memcpy(DA,&status[1],8);
switch(status[0])
{
case 0x01://SendPump
outb(status[1],PUMP_ADDRESS);
break;
case 0x02://SendDa;
outb(inb(ADBase+4)|0x80,ADBase+4);
for(i=0;i<4;i++)
{ lsb=DA[i]&0xff;
msb=(DA[i]/256)&0x0f;
outb(msb+(i)*16,ADBase+2);
outb(lsb,ADBase+1);
}
inb(ADBase+2);
break;
}
/* int lsb=0,msb=0;
int i;
if(IT[0]&0x08)
{ IT[0]=IT[0]&0xf7;
outb(IT[0],0x308);
}
outb(0xfb,PUMP_ADDRESS);
short DA[4]={4000,4000,4000,4000};
outb(inb(ADBase+4)|0x80,ADBase+4);
for(i=1;i<5;i++)
{ lsb=DA[i]&0xff;
msb=(DA[i]/256)&0x0f;
outb(msb+(i-1)*16,ADBase+2);
outb(lsb,ADBase+1);
}
inb(ADBase+2);*/
// outb(0xFF,ADBase+8);
return 0;
}
static int myPump_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
printk(KERN_ALERT "Hello,CTRIO init open \n");
DA[0]=cmd;DA[1]=cmd;DA[2]=cmd;DA[3]=cmd;
DASentOut();
return 1;
}
static struct file_operations myPump_fops = {
owner: THIS_MODULE,
write: myPump_write,
read: myPump_read,
ioctl: myPump_ioctl,
open: myPump_open,
release: myPump_release,
};
static int myPump_init(void)
{
printk(KERN_ALERT "Hello, The fucking crazy world\n");
myPump_Major = register_chrdev(240, DRIVER_NAME, &myPump_fops);
// request_region(ADBase, 16, DRIVER_NAME);
outb(0x88,ADBase+11);
DASentOut();
outb(0xff,ADBase+8);
outb(0xff,ADBase+9);
outb(0xF0,ADBase+10);
// IO[2]=inportb(ADBase+10);
return 0;
}
static void myPump_exit(void)
{
printk(KERN_ALERT "Bye, The fucking crazy world!\n");
}
static void DASentOut()
{
int lsb=0,msb=0;
int i;
outb(inb(ADBase+4)|0x80,ADBase+4);
for(i=0;i<4;i++)
{ lsb=DA[i]&0xff;
msb=(DA[i]/256)&0x0f;
outb(msb+(i)*16,ADBase+2);
outb(lsb,ADBase+1);
}
inb(ADBase+2);
}
module_init(myPump_init);
module_exit(myPump_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("albcamus <sankye@163.com>");
功能:控制泵的运行,数据采集。。。。
还有点问题:DMA传完后处理的中断1S才发生一次。。不是设置好的100MS一次。。