以前写的,但是没写完,偏偏你要的那部分没写。
呵呵~~ 先声明,没调试过。
仅供参考,有错误的地方请指正,谢谢!/////////////////////////******setport.h*******/////////////////////////#ifndef SETPORT_H#define SETPORT_H/********************* int dwBaudRate; //波特率 char bTTY; //串口号 char bDataBit; //数据位 5,6,7,8 char bParity; //奇偶校验 无校验:'N' 偶校验'E' 奇校验'O' char bStopBit; //停止位 1,2 char bFctl; //流控制 无控制:'N' 硬件控制:'H' 软件控制:'S'**********************///-------------------打开串口-------------------//bTTY==0,1,2,3, 对应串口Com1到Com4,成功返回文件描述符,失败==(-1) extern int PortOpen(char bTTY);//-------------------设置串口-------------------//成功==(0) 失败==(-1) extern int PortSet(int dwFdcom,int dwBaudRate,char bTTY,char bDataBit,char bParity,char bStopBit,char bFctl);//-------------------关闭串口-------------------// extern void PortClose(int dwFdcom);//-------------------写串口-------------------//成功返回datalen 失败==(<0) extern int PortWrite(int dwFdcom,char *cpSendBuf,unsigned int DataLen);//-------------------读串口-------------------//成功返回datalen 失败==(-1) extern int PortRead(int dwFdcom,char *cpRecvBuf,unsigned int DataLen,unsigned int dwBaudRate);//-------------------超时设置-------------------//成功==0 失败==(<0) extern int PortTimeOut(int dwFdcom, char timeout, int len);#endif//////////////////////////////***********setport.c*******/////////////////////////////#include #include #include #include #include #include #include #include #include #include "setport.h"//-------------------打开串口-------------------// extern int PortOpen(char bTTY) { int dwFdcom; unsigned char Ptty[10]="/dev/ttyS"; unsigned char *cpGtty; cpGtty=strcat(Ptty,&bTTY); if(!cpGtty) return -1; else { dwFdcom=open(cpGtty,O_RDWR|O_NOCTTY); } return (dwFdcom); }//-------------------关闭串口-------------------// extern void PortClose(int dwFdcom) { close(dwFdcom); }//-------------------设置串口-------------------// extern int PortSet(int dwFdcom,int dwBaudRate,char bTTY,char bDataBit,char bParity,char bStopBit,char bFctl) { static int speed_arr[] = {B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300}; static int name_arr[] = {38400, 19200, 9600, 4800, 2400,1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300}; struct termios oldtm_t,newtm_t; int i=0; char *pDatabit; bzero(&oldtm_t,sizeof(oldtm_t)); bzero(&newtm_t,sizeof(newtm_t)); cfmakeraw(&newtm_t); tcgetattr(dwFdcom,&oldtm_t); /*------------设置端口属性------------*/ for( ; i { if(dwBaudRate==name_arr[i]) { cfsetispeed(&newtm_t,speed_arr[i]); cfsetospeed(&newtm_t,speed_arr[i]); } else return -1; } newtm_t.c_cflag|=CLOCAL; newtm_t.c_cflag|=CREAD; newtm_t.c_cflag &= ~CSIZE; switch(bDataBit) //数据位 { case '5': newtm_t.c_cflag|=CS5; break; case '6': newtm_t.c_cflag|=CS6; break; case '7': newtm_t.c_cflag|=CS7; break; case '8': newtm_t.c_cflag|=CS8; break; default: return -2; } switch(bParity) { case 'N':{ //无校验 newtm_t.c_cflag&=~PARENB; newtm_t.c_iflag&= ~INPCK; }break; case 'O':{ //奇校验 newtm_t.c_cflag |= (PARODD | PARENB); newtm_t.c_iflag |= INPCK; }break; case 'E':{ //偶校验 newtm_t.c_cflag |= PARENB; newtm_t.c_cflag &= ~PARODD; newtm_t.c_iflag |= INPCK; }break; default: return -3; } //停止位 if(bStopBit=='2') newtm_t.c_cflag|=CSTOPB; //2 else newtm_t.c_cflag&=~CSTOPB; //1 switch(bFctl) //流控制 { case 'N':{ //无控制 newtm_t.c_cflag &= ~CRTSCTS; newtm_t.c_iflag &= ~(IXON | IXOFF | IXANY ); }break; case 'H':{ //硬件控制 newtm_t.c_cflag |= CRTSCTS; newtm_t.c_iflag &= ~(IXON | IXOFF | IXANY ); }break; case 'S':{ //软件控制 newtm_t.c_cflag &= ~CRTSCTS; newtm_t.c_iflag |= (IXON | IXOFF | IXANY ); }break; default: return -4; } tcflush(dwFdcom,TCIFLUSH); //端口复位 tcsetattr(dwFdcom,TCSANOW,&newtm_t); //使端口属性设置生效 return 0; }//-------------------超时设置-------------------// extern int PortTimeOut(int dwFdcom, char timeout, int len) { struct termios newtm_t; if(tcgetattr(dwFdcom, &newtm_t) != 0) { return (-1); } newtm_t.c_lflag &= ~ICANON; newtm_t.c_cc[VTIME] = timeout; newtm_t.c_cc[VMIN] = len; if(tcsetattr(dwFdcom, TCSANOW, &newtm_t) != 0) { return (-2); } return 0; }////读写串口用文件读写方式,read和write两个方法,////read是接收数据,write是发送数据。
从个人的理解,Linux2。
6内核对中断处理程序的现在的处理可以分为两种模式,一种就是上面说的老的模式(非共享中断线),一种属于使用共享中断线的新模式,从其使用的注册中断处理程序的函数中来分析,函数原型如下: int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void * dev_id); 参数1:中断线号 参数2:中断处理程序函数指针 参数3:标志掩码(SA_INTERRUPT, SA_SAMPLE_RANDOM, SA_SHIRQ) 参数4:用于参数3为SA_SHIRQ(共享中断线)的时候,其他为NULL 原来对于计算机设备比较少的时候,可能一个中断线好可以对应一个中断处理程序(非共享中断线),这时候参数4为NULL,没有任何用,但随着计算机设备的增加,一个中断线号对应一个中断处理程序已经不太现实,这个时候就使用了共享的中断线号,多个设备使用同一个中断线号,同一个中断设备线号的所有处理程序链接成一个链表,这样当在共享中断线号的方式下一个中断产生的时候,就要遍历其对应的处理程序链表,但这个中断是由使用同一个中断线号的多个设备中间的一个产生的,不可能链表里面的所有处理程序都调用一遍吧,呵呵,这个时候就该第四个参数派上用场了。 因为多个设备共享同一个中断线号,当中断产生的时候到底是那一个设备产生的中断呢,这个就取决于第四个参数dev_id,这个参数必须是唯一的,也就是能区分到底是那个设备产生的中断,而且从第二个参数可以看出来,这个参数被传入中断处理程序(第二个参数),可以这么理解,当中断产生的时候,如果是共享的中断线号,则对应链表的所有中断处理程序都被调用,不过在每个中断处理程序的内部首先检查(参数信息以及设备硬件的支持)是不是这个中断处理程序对应的设备产生的中断,如果不是,立即返回,如果是,则处理完成,如果链表中没有一个是,则说明出现错误。
下来说说中断处理程序,先看看原型: static irqreturn_t intr_handler(int irq, void * dev_id, struct pt_regs * regs); 参数1:中断线号 参数2:设备的信息,唯一确定性 参数3:中断之前的处理器寄存器的信息和状态 通过上面的分析,大概可以看到,参数1(中断线号)貌似有点多余,因为如果是非共享的中断线,通过中断线号直接调用处理程序,将这个参数传进去好像没什么用,如果属于共享的中断线,则通过中断线号直接找到对应的中断处理程序链表,挨个遍历,都是一个中断线号,传进去也没用,该不该调用,通过第二个参数来区分,那为什么要保留这个参数呢?答案是历史遗留问题,往后可能越来越没用了,至于为什么是历史遗留问题,可能在没有第二个参数的时候才在第一个上面做了点手脚,既然第二个参数已经添加进去了,第一个的作用就越来越少了。 如果是共享的中断线号,则对应链表的所有中断处理程序都被调用,不过在每个中断处理程序的内部首先检查(参数信息以及设备硬件的支持)是不是这个中断处理程序对应的设备产生的中断,如果不是,立即返回,如果是,则处理完成,如果链表中没有一个是,则说明出现错误。
Linux混入了mmu内存管理之后,ARM的中断是怎么样的呢?和我们在裸板上的中断有没有区别?让我们从源代码入手,做一个粗略的分析:init/main。
c->start_kernel()->trap_init()//-----------------------------------------------1。 trap_init()//glietpletely changes the structure of the visible * memory space。 You will not be able to trace execution through this。
* If you have an enquiry about this, *please* check the linux-arm-kernel * mailing list archives BEFORE sending another post to the list。 */ 。
type __ret, %function__ret: ldr lr, __switch_data mcr p15, 0, r0, c1, c0//将__arm920_setup中设置的r0值,置入cp15协处理器c1寄存器中 mrc p15, 0, r0, c1, c0, 0 @ read it back。 mov r0, r0//填充armv4中的三级流水线:mov r0,r0 对应一个nop,所以对应2个nop和一个mov pc,lr刚好三个"无用"操作 mov r0, r0 mov pc, lr//跳转到__mmap_switched函数 gliethtttp/* * The following fragment of code is executed with the MMU on, and uses * absolute addresses; this is not position independent。
* * r0 = processor control register * r1 = machine ID * r9 = processor ID */ 。align 5__mmap_switched: adr r3, __switch_data + 4 ldmia r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat//2007-07-04 gliethttp//r4 ~ __bss_start//r5 ~ _end//r6 ~ processor_id//r7 ~ __machine_arch_type//r8 ~ cr_alignment//sp ~ (init_task_union)+8192//以下几步操作对processor_id,__machine_arch_type,cr_alignment赋值gliethttp mov fp, #0 @ Clear BSS (and zero fp)1: cmp r4, r5 //bss区清0 strcc fp, [r4],#4 bcc 1b str r9, [r6] @ Save processor ID str r1, [r7] @ Save machine type#ifdef CONFIG_ALIGNMENT_TRAP orr r0, r0, #2 @ 。
A。#endif bic r2, r0, #2 @ Clear 'A' bit//r2存放 禁用TRAP队列故障 后的r0值//r8->cr_alignment,cr_no_alignment//所以stmia r8, {r0, r2}后,cr_alignment = r0,cr_no_alignment = r2 stmia r8, {r0, r2} @ Save control register values b SYMBOL_NAME(start_kernel) //进入内核C程序//--------------------------------------2。
2 __arm920_proc_info//gliethttp arch/arm/mm/proc-arm920。S。
section "。proc。
info", #alloc, #execinstr 。type __arm920_proc_info,#object__arm920_proc_info://该地址存储到r10中 。
long 0x41009200 。long 0xff00fff0 。
long 0x00000c1e @ mmuflags b __arm920_setup//add pc, r10, #12 gliethttp将使cpu执行b __arm920_setup跳转指令 。 long cpu_arch_name 。
long cpu_elf_name 。long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 。
long cpu_arm920_。
自旋锁 Linux内核中最常见的锁是自旋锁。
一个自旋锁就是一个互斥设备,它只能有两个值:"锁定"和"解锁"。如果锁可用,则"锁定"位被设置,而代码继续进入临界区;相反,如果锁被其他进程争用,则代码进入忙循环并重复检查这个锁,直到锁可用为止。
这个循环就是自旋锁的"自旋"。自旋锁最多只能被一个可执行的线程持有。
如果一个执行线程试图获得一个被争用的自旋锁,那么该线程就会一直进行忙循环-旋转-等待锁重新可用。注意,同一个锁可以用在多个位置。
缺点:一个被争用的自旋锁使得请求它的线程在等待锁重新可用时自旋(特别浪费处理器时间)。 所以,自旋锁不应该被长时间持有。
当然,可以采用另外的方式处理对锁的争用:让请求线程睡眠,直到锁重新可用时在唤醒它。但是,这里有两次明显的上下文切换,被阻塞的线程要换入或换出。
因此,持有自旋锁的时间最好小于完成两次上下文切换的耗时。 注意: 1) 如果禁止内核被抢占,那么在编译时自旋锁会被完成剔除出内核。
2) Linux内核实现的自旋锁是不可递归的。小心自加锁。
3) 调试自旋锁, 加上配置选项CONFIG_DEBUG_SPINLOCK。 4)自旋锁可以使用在中断处理程序中(此处不能使用信号量,因为它们会导致睡眠),在中断处理程序中使用自旋锁时,一定要在获取锁之前,首先禁止本地中断 (在当前处理器上的中断请求),否则中断处理程序就会打断正持有锁的内核代码,有可能试图去争用这个已经被持有的自旋锁。
5) 加锁是对数据不是对代码。 6) 所有自旋锁的等待在本质上都是不可中断的。
1。1。
自旋锁API介绍自旋锁实现与体系结构密切相关,定义在中。在编译时对自旋锁的初始化: spinlock_t my_lock=SPIN_LOCK_UNLOCKED; 或者在运行时: void spin_lock_init(spinlock_t *lock); 进入临界区: spin_lock(&my_lock); /*访问数据*/ spin_unlock(&my_lock); 内核提供禁止中断同时请求锁的接口: spinlock_t my_lock=SPIN_LOCK_UNLOCKED; unsigned long flags; spin_lock_irqsave(&my_lock, flags); /*访问数据*/ spin_unlock_irqrestore(&my_lock, flags);函数spin_lock_irqsave保存了中断的当前状态,并禁止了本地中断,然后在获取指定的锁;函数 spin_unlock_irqrestore对指定的锁解锁,然后让中断恢复到加锁前的状态。
内核提供的自旋锁的接口: void spin_lock_irq (spinlock_t *lock); void spin_unlock_irq (spinlock_t *lock); void spin_lock_bh (spinlock_t *lock); void spin_unlock_bh (spinlock_t *lock); 如果能够确保没有任何其他代码禁止本地处理器的中断,也就是说,能够确保在释放自旋锁时应该启用中断,这可以使用spin_lock_irq函数,而无需跟踪标志。 函数spin_lock_bh在获得锁之前禁止软件中断,但是会让硬件中断保持打开。
以上是我对于这个问题的解答,希望能够帮到大家。
声明:本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
蜀ICP备2020033479号-4 Copyright © 2016 学习鸟. 页面生成时间:3.307秒