以前寫的,但是沒寫完,偏偏你要的那部分沒寫。
呵呵~~ 先聲明,沒調(diào)試過。
僅供參考,有錯誤的地方請指正,謝謝!/////////////////////////******setport.h*******/////////////////////////#ifndef SETPORT_H#define SETPORT_H/********************* int dwBaudRate; //波特率 char bTTY; //串口號 char bDataBit; //數(shù)據(jù)位 5,6,7,8 char bParity; //奇偶校驗 無校驗:'N' 偶校驗'E' 奇校驗'O' char bStopBit; //停止位 1,2 char bFctl; //流控制 無控制:'N' 硬件控制:'H' 軟件控制:'S'**********************///-------------------打開串口-------------------//bTTY==0,1,2,3, 對應(yīng)串口Com1到Com4,成功返回文件描述符,失敗==(-1) extern int PortOpen(char bTTY);//-------------------設(shè)置串口-------------------//成功==(0) 失敗==(-1) extern int PortSet(int dwFdcom,int dwBaudRate,char bTTY,char bDataBit,char bParity,char bStopBit,char bFctl);//-------------------關(guān)閉串口-------------------// 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);//-------------------超時設(shè)置-------------------//成功==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); }//-------------------關(guān)閉串口-------------------// extern void PortClose(int dwFdcom) { close(dwFdcom); }//-------------------設(shè)置串口-------------------// 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); /*------------設(shè)置端口屬性------------*/ 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) //數(shù)據(jù)位 { 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); //端口復(fù)位 tcsetattr(dwFdcom,TCSANOW,&newtm_t); //使端口屬性設(shè)置生效 return 0; }//-------------------超時設(shè)置-------------------// 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是接收數(shù)據(jù),write是發(fā)送數(shù)據(jù)。
從個人的理解,Linux2。
6內(nèi)核對中斷處理程序的現(xiàn)在的處理可以分為兩種模式,一種就是上面說的老的模式(非共享中斷線),一種屬于使用共享中斷線的新模式,從其使用的注冊中斷處理程序的函數(shù)中來分析,函數(shù)原型如下: int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void * dev_id); 參數(shù)1:中斷線號 參數(shù)2:中斷處理程序函數(shù)指針 參數(shù)3:標(biāo)志掩碼(SA_INTERRUPT, SA_SAMPLE_RANDOM, SA_SHIRQ) 參數(shù)4:用于參數(shù)3為SA_SHIRQ(共享中斷線)的時候,其他為NULL 原來對于計算機(jī)設(shè)備比較少的時候,可能一個中斷線好可以對應(yīng)一個中斷處理程序(非共享中斷線),這時候參數(shù)4為NULL,沒有任何用,但隨著計算機(jī)設(shè)備的增加,一個中斷線號對應(yīng)一個中斷處理程序已經(jīng)不太現(xiàn)實(shí),這個時候就使用了共享的中斷線號,多個設(shè)備使用同一個中斷線號,同一個中斷設(shè)備線號的所有處理程序鏈接成一個鏈表,這樣當(dāng)在共享中斷線號的方式下一個中斷產(chǎn)生的時候,就要遍歷其對應(yīng)的處理程序鏈表,但這個中斷是由使用同一個中斷線號的多個設(shè)備中間的一個產(chǎn)生的,不可能鏈表里面的所有處理程序都調(diào)用一遍吧,呵呵,這個時候就該第四個參數(shù)派上用場了。 因為多個設(shè)備共享同一個中斷線號,當(dāng)中斷產(chǎn)生的時候到底是那一個設(shè)備產(chǎn)生的中斷呢,這個就取決于第四個參數(shù)dev_id,這個參數(shù)必須是唯一的,也就是能區(qū)分到底是那個設(shè)備產(chǎn)生的中斷,而且從第二個參數(shù)可以看出來,這個參數(shù)被傳入中斷處理程序(第二個參數(shù)),可以這么理解,當(dāng)中斷產(chǎn)生的時候,如果是共享的中斷線號,則對應(yīng)鏈表的所有中斷處理程序都被調(diào)用,不過在每個中斷處理程序的內(nèi)部首先檢查(參數(shù)信息以及設(shè)備硬件的支持)是不是這個中斷處理程序?qū)?yīng)的設(shè)備產(chǎn)生的中斷,如果不是,立即返回,如果是,則處理完成,如果鏈表中沒有一個是,則說明出現(xiàn)錯誤。
下來說說中斷處理程序,先看看原型: static irqreturn_t intr_handler(int irq, void * dev_id, struct pt_regs * regs); 參數(shù)1:中斷線號 參數(shù)2:設(shè)備的信息,唯一確定性 參數(shù)3:中斷之前的處理器寄存器的信息和狀態(tài) 通過上面的分析,大概可以看到,參數(shù)1(中斷線號)貌似有點(diǎn)多余,因為如果是非共享的中斷線,通過中斷線號直接調(diào)用處理程序,將這個參數(shù)傳進(jìn)去好像沒什么用,如果屬于共享的中斷線,則通過中斷線號直接找到對應(yīng)的中斷處理程序鏈表,挨個遍歷,都是一個中斷線號,傳進(jìn)去也沒用,該不該調(diào)用,通過第二個參數(shù)來區(qū)分,那為什么要保留這個參數(shù)呢?答案是歷史遺留問題,往后可能越來越?jīng)]用了,至于為什么是歷史遺留問題,可能在沒有第二個參數(shù)的時候才在第一個上面做了點(diǎn)手腳,既然第二個參數(shù)已經(jīng)添加進(jìn)去了,第一個的作用就越來越少了。 如果是共享的中斷線號,則對應(yīng)鏈表的所有中斷處理程序都被調(diào)用,不過在每個中斷處理程序的內(nèi)部首先檢查(參數(shù)信息以及設(shè)備硬件的支持)是不是這個中斷處理程序?qū)?yīng)的設(shè)備產(chǎn)生的中斷,如果不是,立即返回,如果是,則處理完成,如果鏈表中沒有一個是,則說明出現(xiàn)錯誤。
Linux混入了mmu內(nèi)存管理之后,ARM的中斷是怎么樣的呢?和我們在裸板上的中斷有沒有區(qū)別?讓我們從源代碼入手,做一個粗略的分析: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中設(shè)置的r0值,置入cp15協(xié)處理器c1寄存器中 mrc p15, 0, r0, c1, c0, 0 @ read it back。 mov r0, r0//填充armv4中的三級流水線:mov r0,r0 對應(yīng)一個nop,所以對應(yīng)2個nop和一個mov pc,lr剛好三個"無用"操作 mov r0, r0 mov pc, lr//跳轉(zhuǎn)到__mmap_switched函數(shù) 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區(qū)清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) //進(jìn)入內(nèi)核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執(zhí)行b __arm920_setup跳轉(zhuǎn)指令 。 long cpu_arch_name 。
long cpu_elf_name 。long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB 。
long cpu_arm920_。
自旋鎖 Linux內(nèi)核中最常見的鎖是自旋鎖。
一個自旋鎖就是一個互斥設(shè)備,它只能有兩個值:"鎖定"和"解鎖"。如果鎖可用,則"鎖定"位被設(shè)置,而代碼繼續(xù)進(jìn)入臨界區(qū);相反,如果鎖被其他進(jìn)程爭用,則代碼進(jìn)入忙循環(huán)并重復(fù)檢查這個鎖,直到鎖可用為止。
這個循環(huán)就是自旋鎖的"自旋"。自旋鎖最多只能被一個可執(zhí)行的線程持有。
如果一個執(zhí)行線程試圖獲得一個被爭用的自旋鎖,那么該線程就會一直進(jìn)行忙循環(huán)-旋轉(zhuǎn)-等待鎖重新可用。注意,同一個鎖可以用在多個位置。
缺點(diǎn):一個被爭用的自旋鎖使得請求它的線程在等待鎖重新可用時自旋(特別浪費(fèi)處理器時間)。 所以,自旋鎖不應(yīng)該被長時間持有。
當(dāng)然,可以采用另外的方式處理對鎖的爭用:讓請求線程睡眠,直到鎖重新可用時在喚醒它。但是,這里有兩次明顯的上下文切換,被阻塞的線程要換入或換出。
因此,持有自旋鎖的時間最好小于完成兩次上下文切換的耗時。 注意: 1) 如果禁止內(nèi)核被搶占,那么在編譯時自旋鎖會被完成剔除出內(nèi)核。
2) Linux內(nèi)核實(shí)現(xiàn)的自旋鎖是不可遞歸的。小心自加鎖。
3) 調(diào)試自旋鎖, 加上配置選項CONFIG_DEBUG_SPINLOCK。 4)自旋鎖可以使用在中斷處理程序中(此處不能使用信號量,因為它們會導(dǎo)致睡眠),在中斷處理程序中使用自旋鎖時,一定要在獲取鎖之前,首先禁止本地中斷 (在當(dāng)前處理器上的中斷請求),否則中斷處理程序就會打斷正持有鎖的內(nèi)核代碼,有可能試圖去爭用這個已經(jīng)被持有的自旋鎖。
5) 加鎖是對數(shù)據(jù)不是對代碼。 6) 所有自旋鎖的等待在本質(zhì)上都是不可中斷的。
1。1。
自旋鎖API介紹自旋鎖實(shí)現(xiàn)與體系結(jié)構(gòu)密切相關(guān),定義在中。在編譯時對自旋鎖的初始化: spinlock_t my_lock=SPIN_LOCK_UNLOCKED; 或者在運(yùn)行時: void spin_lock_init(spinlock_t *lock); 進(jìn)入臨界區(qū): spin_lock(&my_lock); /*訪問數(shù)據(jù)*/ spin_unlock(&my_lock); 內(nèi)核提供禁止中斷同時請求鎖的接口: spinlock_t my_lock=SPIN_LOCK_UNLOCKED; unsigned long flags; spin_lock_irqsave(&my_lock, flags); /*訪問數(shù)據(jù)*/ spin_unlock_irqrestore(&my_lock, flags);函數(shù)spin_lock_irqsave保存了中斷的當(dāng)前狀態(tài),并禁止了本地中斷,然后在獲取指定的鎖;函數(shù) spin_unlock_irqrestore對指定的鎖解鎖,然后讓中斷恢復(fù)到加鎖前的狀態(tài)。
內(nèi)核提供的自旋鎖的接口: 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); 如果能夠確保沒有任何其他代碼禁止本地處理器的中斷,也就是說,能夠確保在釋放自旋鎖時應(yīng)該啟用中斷,這可以使用spin_lock_irq函數(shù),而無需跟蹤標(biāo)志。 函數(shù)spin_lock_bh在獲得鎖之前禁止軟件中斷,但是會讓硬件中斷保持打開。
以上是我對于這個問題的解答,希望能夠幫到大家。
聲明:本網(wǎng)站尊重并保護(hù)知識產(chǎn)權(quán),根據(jù)《信息網(wǎng)絡(luò)傳播權(quán)保護(hù)條例》,如果我們轉(zhuǎn)載的作品侵犯了您的權(quán)利,請在一個月內(nèi)通知我們,我們會及時刪除。
蜀ICP備2020033479號-4 Copyright ? 2016 學(xué)習(xí)鳥. 頁面生成時間:3.307秒