RS232串口驱动的一些问题,请各位执教

d5211 2006-04-03 07:24:06
最近,要写一个linux下的RS232驱动程序,想在驱动程序一级实现异步IO。
但是我遇到了一些问题(我从来没有在linux下写程序,更不用说驱动了)
一:系统已经有了RS232串口的驱动。机器重新启动以后,硬件的端口地址仍然不会改变对吧?
二:我怎么知道我的硬件(比如RS232)的的端口地址呢?
三:如果我要写一个RS232,如果硬件忙,我放到一个缓冲里面,我怎么保重硬件空闲的时候从缓冲
中取出数据进行实际意义上的写出呢?

走过路过,不要错过。

各位请多多赐教,讲得无论多少都是对我的帮助,谢谢了!再谢谢!
...全文
1231 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
d5211 2006-04-05
  • 打赏
  • 举报
回复
耐心回答我的两位朋友:我给分的时候总分不对。等下我调整一下。如果
多几分或者少几分,不好意思哦!
d5211 2006-04-05
  • 打赏
  • 举报
回复
不错!结贴~


再次感谢tb01412(tb)
tb01412 2006-04-04
  • 打赏
  • 举报
回复
概括一下:
驱动是自己约定的,比如内核自行约定次设备号0就是COM1,1就是COM2,那么内核就可以区分自己到底是操作哪一个IO!!!!
应用层就需要遵守这种约定,但为了简化操作,应用层在使用设备时,直接操作文件就可以了,这就需要将文件与设备关联起来,这就是设备文件的概念,需要用到mknod命令,这个命令在使用时需要遵守你内核中的约定,这样就将应用层与驱动程统一起来了!!!!!

驱动程序不管每个引脚的电平特征,直接往它上面读写就可以了么?
在PC机上的驱动程序基本上需要两个函数来操作设备,outb,inb,用于向设备的指定端口读写数据,具体的电平特征,在调试的时候可能会汲及到,比如你用示波器来看某个IO脚到底输出了数据没有!!!

如果串口被焊下来了!
我怎么探测它不见了?用什么特征(电气特征?或者用系统的某种数据结构?)可以探测到它的存在/消失?

对于一个键壮的驱动程序,有时需要在设备初始化例程中探测相应的设备是否存在,原理很简单,就是通过改写外围硬件一个寄存器,再去观察另一个会受影响的寄存器,看它是否是你想要的结果,这跟具体的硬件相关,需要结合具体硬件的芯片资料,当然,你也完全不用去判断这个硬件是否存在
tb01412 2006-04-04
  • 打赏
  • 举报
回复
怎么区分两个或多个相同的设备?
驱动通过主、次设备号来区分到底是哪一个设备,首先由驱动把真实的设备与主、次设备号关联;
应用层通过不同的设备文件名来区分,而在此之前需要mknod来关联主,次设备号与真实设备

在中断处理程序中无法获取当前设备的次设备号,所以就需要在open设备时开一个私有数据与自己进行关联,中断处理中可以访问私有数据里的相关标识来确定到底是哪一个设备,或者可以通过中断号来识别当前是COM1或者COM2(如果你不共用中断的话,比如在PCI中就存在共用中断号的情况,此时就需要另想办法),而在open,close等操作中都可以获取到用户到底想要操作哪一个设备!!!!
caijize 2006-04-04
  • 打赏
  • 举报
回复

//////////////////////////Rs232.cpp///////////////
//////////////////////////////////////////////////////////////////////
//文件名: Rs232.cpp
//描述: 实现Rs232类
//修改人: ***
//最后修改时间: Mar. 23 2006
//////////////////////////////////////////////////////////////////////
#include <dos.h>
#include "rs232.h"
//#include "const.h"
//=========================================================================//
CRs232::CRs232()
{
m_nCom1Disabled = 0;
m_nCom2Disabled = 0;
}
//=========================================================================//
CRs232::~CRs232()
{
}
//=========================================================================//
void CRs232::Disable(int port)
{
port==COM1? m_nCom1Disabled = 1 : m_nCom2Disabled = 1;
}
//=========================================================================//
void CRs232::Enable(int port)
{
port==COM1? m_nCom1Disabled = 0 : m_nCom2Disabled = 0;
}
//=========================================================================//
void CRs232::SetBaudrate(int port,unsigned int baudrate)
{
#ifdef __GNUC__
short int word = (short int)(1.8432*1e6/baudrate/16);
#else
int word = (int)(1.8432*1e6/baudrate/16);
#endif
unsigned char low_byte,high_byte;
low_byte = word&0xff;
high_byte = ((word&0x00ff)>>8);
if(port==COM1)
{
outportb(0x3fb,0x80); // select baudrate register
outportb(0x3f8,low_byte); // baudrate low byte
outportb(0x3f9,high_byte); // baudrate high byte
outportb(0x3fb,0x0b); // data format
outportb(0x3fc,0xb); // DTR and RTS =1,if byte.4=1,tx connect rx interanl.
outportb(0x3f9,0x1); // disable interrupt
outportb(0x3fa,0x21); // 允许FIFO工作(16550后才有)
}
else
{
outportb(0x2fb,0x80); // select baudrate register
outportb(0x2f8,low_byte); // baudrate low byte
outportb(0x2f9,high_byte); // baudrate high byte
outportb(0x2fb,0x0b); // data format
outportb(0x2fc,0xb); // DTR and RTS =1,if byte.4=1,tx connect rx interanl.
outportb(0x2f9,0x1); // disable interrupt
outportb(0x2fa,0x21); // 允许FIFO工作(16550后才有)
}
}
//=========================================================================//
unsigned int CRs232::Receive(int port)
{
static int nErrNm1=0,nErrNm2=0;
unsigned int retval = 0xff00;
unsigned char state;
state = inportb(port==COM1? 0x3fd : 0x2fd);
if((state&0x1))
{
if((state&0x4)!=1) //no parity check error
{
retval = (int)inportb(port==COM1? 0x3f8 : 0x2f8);
port==COM1? nErrNm1=0 : nErrNm2=0;
}
else
{ //parity check error
port==COM1? nErrNm1++ : nErrNm2++;
if(nErrNm1>=2||nErrNm2>=2)
{
// ::Warning("警告:串行口通讯错误! 按ESC键继续……");
// ::OutStr16(5,459,12,"警告:串行口通讯错误!");
// return 0;
}
else outportb((port==COM1? 0x3f8 : 0x2f8),0xaa);
}
}
if(port==COM1&&m_nCom1Disabled) return 0xff00;
if(port==COM2&&m_nCom2Disabled) return 0xff00;
return retval;
}
//=========================================================================//
int CRs232::Send(int port,unsigned char key)
{
unsigned char state;
state = inportb(port==COM1? 0x3fd : 0x2fd);
if((state&0x20)&&(state&0x40))
{
outportb((port==COM1? 0x3f8:0x2f8),key);
return 1;
}
else return 0;

/*while( !(inportb( port==1?0x3fd:0x2fd )&0x20) ){}
outportb( port==1?0x3f8:0x2f8, key );
return 1;*/

}
//=========================================================================//
void CRs232::Initiate()
{
//initiate COM1
outportb(0x3fb,0x80); //select baudrate register
outportb(0x3f8,0x30); //baudrate low byte
outportb(0x3f9,0x0); //baudrate high byte
outportb(0x3fb,0x0b); //data format
outportb(0x3fc,0xb); // DTR and RTS =1,if byte.4=1,tx connect rx interanl.
outportb(0x3f9,0x1); // disable interrupt
outportb(0x3fa,0x21); // 允许FIFO工作(16550后才有)

//initiate COM2
outportb(0x2fb,0x80); //select baudrate register
outportb(0x2f8,0x30); //baudrate low byte
outportb(0x2f9,0x0); //bardrate high byte
outportb(0x2fb,0x0b); //data format
outportb(0x2fc,0xb); // DTR and RTS =1,if byte.4=1,tx connect rx interanl.
outportb(0x2f9,0x1); // disable interrupt
outportb(0x2fa,0x21); // 允许FIFO工作(16550后才有)
}
//=========================================================================//


上面是在DOS下的 RS232 使用文件, RS232.h文件是对类的定义,你自己写.
caijize 2006-04-04
  • 打赏
  • 举报
回复
给你代码,你自己参考一下,

////////////////////////Linux 驱动测试调试////////////////////////
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>


#define DP_MAJOR 50
#define DP_MINOR 0
static int char_read(struct file *filp,char __user *buffer,size_t,loff_t *);
static int char_open(struct inode *,struct file *);
static int char_write(struct file *filp,const char __user *buffer,size_t ,loff_t*);
static int char_release(struct inode *,struct file *);
static char *arr,*p;
static int chropen;
struct cdev *my_cdev;
static int len;
struct file_operations Fops = {
.read = char_read,
.write = char_write,
.open = char_open,
.release = char_release, /* a.k.a. close */
};

static int irq=4;
static char *interface="test";
/*
MODULE_PARM(interface, "s");
MODULE_PARM_DESC(interface, "A network interface");
MODULE_PARM(irq, "i");
MODULE_PARM_DESC(irq, "The IRQ of the network interface");
*/
static irqreturn_t myinterrupt(int irq, void *dev_id, struct pt_regs *regs)
{
static int mycount = 0;

if (mycount < 10) {
printk("Interrupt!\n");
mycount++;
}

return IRQ_NONE;
}

static int __init char_init(void)
{
printk(KERN_ALERT"Initing......\n");
dev_t dev;
dev=MKDEV(DP_MAJOR,DP_MINOR);
my_cdev = cdev_alloc( );
arr=kmalloc(1024,GFP_KERNEL);

if(arr==NULL){
printk(KERN_ALERT"kmalloc error\n");
}

sprintf(arr,"Hello,Pid=%d\n",current->pid);
if(my_cdev==NULL){
return -1;
}

if(register_chrdev_region(dev,10,interface)<0){
printk(KERN_ALERT"Register char dev error\n");
return -1;
}

if (request_irq(irq, &myinterrupt, SA_SHIRQ, interface, &irq)) {
printk(KERN_ERR "myirqtest: cannot register IRQ %d\n", irq);
return -EIO;
}

printk("Request on IRQ %d succeeded\n", irq);

chropen=0;
len=0;
my_cdev->ops = &Fops;
cdev_init(my_cdev,&Fops);
cdev_add(my_cdev,dev,1);

return 0;
}

static int char_open(struct inode *inode,struct file *file)
{
if(chropen==0)
chropen++;
else{
printk(KERN_ALERT"Another process open the char device\n");
return -1;
}
p=arr;
try_module_get(THIS_MODULE);
return 0;
}

static int char_release(struct inode *inode,struct file *file)
{
chropen--;
module_put(THIS_MODULE);
return 0;
}

static int char_read(struct file *filp,char __user *buffer,size_t length,loff_t *offset)
{
int i=0;
if(*p=='\0')
return 0;
while(length&&*p){
put_user(*(p++),buffer++);
length--;
i++;
}
return i;
}

static int char_write(struct file *filp,const char __user *buffer,size_t length,loff_t *offset)
{

int i;
for(i=0;i<length&&i<1024;i++)
get_user(p[i],buffer+i);

p[i]=0;
len=i;
return i;
}




static void module_close()
{
len=0;
printk(KERN_ALERT"Unloading..........\n");
kfree(arr);
free_irq(irq, &irq);
unregister_chrdev_region(MKDEV(DP_MAJOR,DP_MINOR),10);
cdev_del(my_cdev);
}

module_init(char_init);
module_exit(module_close);
//////////////////////////////////



这是在2.6内核的驱动测试代码,你可以参考一下,


d5211 2006-04-04
  • 打赏
  • 举报
回复
如果串口被焊下来了!

我怎么探测它不见了?用什么特征(电气特征?或者用系统的某种数据结构?)可以探测到它的存在/消失?



d5211 2006-04-04
  • 打赏
  • 举报
回复
再问一下:怎么区分两个或多个相同的设备?
驱动程序利用次设备号能区分,怎么区分的,否则怎么知道他们各自的IO端口地址?

驱动程序不管每个引脚的电平特征,直接往它上面读写就可以了么?


tb01412(tb) 和 caijize(砂子)再帮我考虑一下。 路过的各位也帮我看一下!


好像:我的分还是够给大家的哈!呵呵!
d5211 2006-04-04
  • 打赏
  • 举报
回复
tb01412(tb) 和 caijize(砂子)的回答我都比较满意哈!

如果还有谁有什么补充或者更详细的论述,继续啊!

ps:稍微== 很快结贴哈
tb01412 2006-04-03
  • 打赏
  • 举报
回复
第一次看到居然还给出99分的!!!!!!
1.如果你的串口是PC机上的标准串口,其地址是固定的,如果是PCI卡上的扩展串口,就不一定了
2.PC上的标准串口的地址是固定的,COM1的串口基地址就是0x3f8
3.那是你驱动做的事情,用户层可以不管!!!具体实现在LINUX设备驱动程序一书中有说明,你PC机上的串口驱动程序本身就支持异步方式,你需要用异步IO的方式对设备进行读写就行了,用不着去实现一个驱动,并且系统已经自带了这样的驱动,你是无法再为此写另一个驱动的,这涉及到设备是否独占的问题,默认情况下,串口设备是被独占的
d5211 2006-04-03
  • 打赏
  • 举报
回复
帖子的保重改成:保证

如果你曾经编写过类似的字符设备驱动,可否告诉我一般的开发流程/一些重要的数据结构/经验教训等。

很急,我必须在4.15号以前完成啊!

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧