?? linux_serial.c
字號:
/* * TOPPERS/JSP Kernel * Toyohashi Open Platform for Embedded Real-Time Systems/ * Just Standard Profile Kernel * * Copyright (C) 2000,2001 by Embedded and Real-Time Systems Laboratory * Toyohashi Univ. of Technology, JAPAN * * 懼淡螟侯涪莢は·Free Software Foundation によって給山されている * GNU General Public License の Version 2 に淡揭されている掘鳳か·笆 * 布の(1)×(4)の掘鳳を塔たす眷圭に嘎り·塑ソフトウェア∈塑ソフトウェ * アを猖恃したものを崔むˉ笆布票じ∷を蝗脫ˇ剩瀾ˇ猖恃ˇ浩芹邵∈笆布· * 網(wǎng)脫と鈣ぶ∷することを痰浸で釣滿するˉ * (1) 塑ソフトウェアをソ〖スコ〖ドの妨で網(wǎng)脫する眷圭には·懼淡の螟侯 * 涪山績·この網(wǎng)脫掘鳳および布淡の痰瘦沮憚年が·そのままの妨でソ〖 * スコ〖ド面に崔まれていることˉ * (2) 塑ソフトウェアを浩網(wǎng)脫材墻なバイナリコ〖ド∈リロケ〖タブルオブ * ジェクトファイルやライブラリなど∷の妨で網(wǎng)脫する眷圭には·網(wǎng)脫 * に燃うドキュメント∈網(wǎng)脫莢マニュアルなど∷に·懼淡の螟侯涪山績· * この網(wǎng)脫掘鳳および布淡の痰瘦沮憚年を非很することˉ * (3) 塑ソフトウェアを浩網(wǎng)脫稍材墻なバイナリコ〖ドの妨または怠達に寥 * み哈んだ妨で網(wǎng)脫する眷圭には·肌のいずれかの掘鳳を塔たすことˉ * (a) 網(wǎng)脫に燃うドキュメント∈網(wǎng)脫莢マニュアルなど∷に·懼淡の螟侯 * 涪山績·この網(wǎng)脫掘鳳および布淡の痰瘦沮憚年を非很することˉ * (b) 網(wǎng)脫の妨輪を·侍に年める數(shù)恕によって·懼淡螟侯涪莢に鼠桂する * ことˉ * (4) 塑ソフトウェアの網(wǎng)脫により木儡弄または粗儡弄に欄じるいかなる祿 * 巢からも·懼淡螟侯涪莢を倘勒することˉ * * 塑ソフトウェアは·痰瘦沮で捏丁されているものであるˉ懼淡螟侯涪莢は· * 塑ソフトウェアに簇して·その努脫材墻拉も崔めて·いかなる瘦沮も乖わ * ないˉまた·塑ソフトウェアの網(wǎng)脫により木儡弄または粗儡弄に欄じたい * かなる祿巢に簇しても·その勒扦を砷わないˉ * * @(#) $Id: linux_serial.c,v 1.6 2002/04/08 05:30:13 hiro Exp $ */#define _LINX_SERIAL_#include <jsp_services.h>#include <signal.h>#include <termios.h>#include <fcntl.h>#include <errno.h>#undef __USE_MISC #include <unistd.h>#include <linux_sigio.h>#include "kernel_id.h"#include "sys_config.h"/* * シリアルポ〖トの你レベル年盜 */typedef struct hardware_serial_port_descripter { char *path; /* UNIX 懼でのファイル嘆 */ int fd; /* ファイルディスクリプタ */ struct termios current_term; /* 眉瑣擴告攫鼠 */ struct termios saved_term; } HWPORT;#define NUM_PORT 1#define RAWPORT1 { 0 }/* * UNIX レベルのポ〖ト介袋步/シャットダウン借妄 * * 附哼の悸劉では·眉瑣を蝗うケ〖スしか雇えていないˉ塑丸は·open し * たのが眉瑣かどうかで借妄を恃えるべきˉ */Inline voidhw_port_initialize(HWPORT *p){ if (p->path) { p->fd = open(p->path, O_RDWR|O_NDELAY); } else { p->fd = 0; /* 篩潔掐叫蝸を蝗う */ } fcntl(p->fd, F_SETOWN, getpid()); fcntl(p->fd, F_SETFL, FASYNC|FNDELAY); tcgetattr(p->fd, &(p->saved_term)); p->current_term = p->saved_term; p->current_term.c_lflag &= ~(ECHO); p->current_term.c_lflag &= ~(ICANON); p->current_term.c_cc[VMIN] = 1; p->current_term.c_cc[VTIME] = 0; tcsetattr(p->fd, TCSAFLUSH, &(p->current_term));}Inline voidhw_port_terminate(HWPORT *p){ tcsetattr(p->fd, TCSAFLUSH, &(p->saved_term)); fcntl(p->fd, F_SETFL, 0); if (p->path) { close(p->fd); }}/* * シリアルインタフェ〖スドライバ脫の SIGIO 奶夢イベントブロック */static SIGIOEB serial_sigioeb;/* * シリアルポ〖ト瓷妄ブロックの年盜 */typedef struct ioctl_descripter { int echo; int input; int newline; int flowc;} IOCTL;#define SERIAL_BUFSZ 256 /* シリアルインタフェ〖ス脫バッファのサイズ */#define inc(x) (((x)+1 < SERIAL_BUFSZ) ? (x)+1 : 0)#define INC(x) ((x) = inc(x))typedef struct serial_port_control_block { BOOL init_flag; /* 介袋步貉か々 */ HWPORT hwport; /* ハ〖ドウェア巴賂攫鼠 */ ID in_semid; /* 減慨バッファ瓷妄脫セマフォの ID */ ID out_semid; /* 流慨バッファ瓷妄脫セマフォの ID */ int in_read_ptr; /* 減慨バッファ粕み叫しポインタ */ int in_write_ptr; /* 減慨バッファ今き哈みポインタ */ int out_read_ptr; /* 流慨バッファ粕み叫しポインタ */ int out_write_ptr; /* 流慨バッファ今き哈みポインタ */ UINT ioctl; /* ioctl による肋年柒推 */ BOOL send_enabled; /* 流慨をイネ〖ブルしてあるか々 */ BOOL ixon_stopped; /* STOP を減け艱った覺輪か々 */ BOOL ixoff_stopped; /* 陵緘に STOP を流った覺輪か々 */ char ixoff_send; /* 陵緘に START/STOP を流るか々 */ char in_buffer[SERIAL_BUFSZ]; /* 減慨バッファエリア */ char out_buffer[SERIAL_BUFSZ]; /* 減慨バッファエリア */} SPCB;#define IN_BUFFER_EMPTY(spcb) \ ((spcb)->in_read_ptr == (spcb)->in_write_ptr)#define IN_BUFFER_FULL(spcb) \ ((spcb)->in_read_ptr == inc((spcb)->in_write_ptr))#define OUT_BUFFER_FULL(spcb) \ ((spcb)->out_read_ptr == inc((spcb)->out_write_ptr))/* * モジュ〖ル柒で蝗う簇眶 */static void sigint_handler();static BOOL serial_getc(SPCB *spcb, char *c);static BOOL serial_putc(SPCB *spcb, char c);/* * シリアルポ〖ト瓷妄ブロックの年盜と介袋步 */static SPCB spcb_table[NUM_PORT] = { {0, RAWPORT1, SEM_SERIAL1_IN, SEM_SERIAL1_OUT }};#define get_spcb(portid) (&(spcb_table[(portid)-1]))#define get_spcb_def(portid) get_spcb((portid) ? (portid) : CONSOLE_PORTID)/* * ポ〖トの介袋步 */intserial_open(ID portid){ SPCB *spcb; ER ercd = E_OK;; if (!(1 <= portid && portid <= NUM_PORT)) { return(E_PAR); } spcb = get_spcb(portid); /* * 剩眶のタスクが票箕に serial_open を鈣ぶ覺斗には灤炳してい * ないˉ */ if (spcb->init_flag) { /* 介袋步貉かのチェック */ return(E_OK); } /* * 恃眶の介袋步 */ spcb->in_read_ptr = spcb->in_write_ptr = 0; spcb->out_read_ptr = spcb->out_write_ptr = 0; spcb->ixon_stopped = spcb->ixoff_stopped = FALSE; spcb->ixoff_send = 0; /* * ハ〖ドウェア巴賂の介袋步 */ hw_port_initialize(&(spcb->hwport)); /* * プロセスを姜位させるシグナルを梳まえる * sigaction()で今き木した數(shù)がいいのか? */ signal(SIGHUP, sigint_handler); signal(SIGINT, sigint_handler); signal(SIGTERM, sigint_handler); spcb->init_flag = TRUE; spcb->send_enabled = FALSE; return(ercd);}/* * ポ〖トのシャットダウン * * flush が TRUE の眷圭は·シリアルポ〖トへの流慨バッファが鄂になるま * で略つˉ */#define MAX_FLUSH_LOOP 1000000intserial_close(ID portid, int flush){ SPCB *spcb; int i; if (!(1 <= portid && portid <= NUM_PORT)) { return(E_PAR); /* ポ〖ト戎規(guī)のチェック */ } spcb = get_spcb(portid); if (!(spcb->init_flag)) { /* 介袋步貉かのチェック */ return(E_OBJ); } /* * バッファのフラッシュ借妄 */ if (flush) { for (i = 0; i < MAX_FLUSH_LOOP; i++) { if (spcb->out_write_ptr == spcb->out_read_ptr) { break; } } } /* * ハ〖ドウェア巴賂のシャットダウン借妄 */ syscall(loc_cpu()); hw_port_terminate(&(spcb->hwport)); syscall(unl_cpu()); spcb->init_flag = FALSE; return(E_OK);}/* * プロセスを姜位させるシグナルに灤するハンドラ */voidsigint_handler(){ SPCB *spcb; int i; for (i = 1; i <= NUM_PORT; i++) { spcb = get_spcb(i); if (spcb->init_flag) { hw_port_terminate(&(spcb->hwport)); } } exit(0);}/* * フロ〖コントロ〖ル簇犯の年盜 */#define STOP '\023' /* Control-S */#define START '\021' /* Control-Q */#define IXOFF_STOP 64 /* buffer area size to send STOP */#define IXOFF_START 128 /* buffer area size to send START */#define in_buf_area(p) \ ((spcb->in_read_ptr >= spcb->in_write_ptr) ? \ (spcb->in_read_ptr - spcb->in_write_ptr) : \ (spcb->in_read_ptr + SERIAL_BUFSZ - spcb->in_write_ptr))/* * ユ〖ティリティル〖チン */Inline BOOLread_char(SPCB *spcb, char *c){ int n; if ((n = read(spcb->hwport.fd, c, 1)) == 1) { return(1); } assert(n < 0 && errno == EWOULDBLOCK); return(0);}Inline BOOLwrite_char(SPCB *spcb, char c){ int n; if ((n = write(spcb->hwport.fd, &c, 1)) == 1) { return(1); } assert(n < 0 && errno == EWOULDBLOCK); return(0);}/* * シリアルポ〖トからの減慨 */static BOOLserial_getc(SPCB *spcb, char *c){ BOOL buffer_empty; syscall(loc_cpu()); *c = spcb->in_buffer[spcb->in_read_ptr]; if (inc(spcb->in_write_ptr) == spcb->in_read_ptr) { /* * バッファフル覺輪が豺近されたら、充り哈みが掐ったのと * 票じ慷る神いをさせる。 */ kill(getpid(), SIGIO); } INC(spcb->in_read_ptr); if (*c == '\r' && (spcb->ioctl & IOCTL_RAW) == 0) { *c = '\n'; } if (spcb->ixoff_stopped && (in_buf_area(spcb) > IXOFF_START)) { if (!write_char(spcb, START)) { spcb->ixoff_send = START; } spcb->ixoff_stopped = FALSE; } buffer_empty = IN_BUFFER_EMPTY(spcb); syscall(unl_cpu()); return(buffer_empty);}intserial_read(int portid, char *buf, unsigned int len){ SPCB *spcb; BOOL buffer_empty; char c; int i; if (sns_dpn()) { /* コンテキストのチェック */ return(E_CTX); } if (!(0 <= portid && portid <= NUM_PORT)) { return(E_PAR); /* ポ〖ト戎規(guī)のチェック */ } spcb = get_spcb_def(portid); if (!(spcb->init_flag)) { /* 介袋步貉かのチェック */ return(E_OBJ); } if (len == 0) { return(len); } syscall(wai_sem(spcb->in_semid)); buffer_empty = FALSE; for (i = 0; i < len; i++) { buffer_empty = serial_getc(spcb, &c); if ((spcb->ioctl & IOCTL_ECHO) != 0) { syscall(wai_sem(spcb->out_semid)); if (!serial_putc(spcb, c)) { syscall(sig_sem(spcb->out_semid)); } } *buf++ = c; if ((spcb->ioctl & IOCTL_RAW) != 0 || ((spcb->ioctl & IOCTL_CANONICAL) != 0 && c == '\n')) { len = i + 1; break; } if (buffer_empty && i < len - 1) { syscall(wai_sem(spcb->in_semid)); } } if (!buffer_empty) { syscall(sig_sem(spcb->in_semid)); } return(len);}/* * シリアルポ〖トへの流慨 */static BOOLserial_putc(SPCB *spcb, char c){ BOOL buffer_full; if (c == '\n' && (spcb->ioctl & IOCTL_CRLF) != 0) { if (serial_putc(spcb, '\r')) { syscall(wai_sem(spcb->out_semid)); } } syscall(loc_cpu()); if (!(spcb->ixon_stopped) && write_char(spcb, c)) { buffer_full = FALSE; } else { spcb->out_buffer[spcb->out_write_ptr] = c; INC(spcb->out_write_ptr); buffer_full = OUT_BUFFER_FULL(spcb); } syscall(unl_cpu()); return(buffer_full);}ER_UINTserial_write(ID portid, char *buf, unsigned int len){ SPCB *spcb; BOOL buffer_full; int i; if (sns_dpn()) { /* コンテキストのチェック */ return(E_CTX); } if (!(0 <= portid && portid <= NUM_PORT)) { return(E_PAR); /* ポ〖ト戎規(guī)のチェック */ } spcb = get_spcb_def(portid); if (!(spcb->init_flag)) { /* 介袋步貉かのチェック */ return(E_OBJ); } syscall(wai_sem(spcb->out_semid)); buffer_full = FALSE; for (i = 0; i < len; i++) { buffer_full = serial_putc(spcb, *buf++); if (buffer_full && i < len - 1) { syscall(wai_sem(spcb->out_semid)); } } if (!buffer_full) { syscall(sig_sem(spcb->out_semid)); } return(len);}/* * シリアルポ〖トの擴告 */intserial_ioctl(ID portid, UINT ioctl){ SPCB *spcb; if (sns_ctx()) { /* コンテキストのチェック */ return(E_CTX); } if (!(0 <= portid && portid <= NUM_PORT)) { return(E_PAR); /* ポ〖ト戎規(guī)のチェック */ } spcb = get_spcb_def(portid); if (!(spcb->init_flag)) { /* 介袋步貉かのチェック */ return(E_OBJ); } spcb->ioctl = ioctl; return(E_OK);}/* * シリアルポ〖ト充哈みハンドラ */static BOOLserial_int_handler(ID portid){ SPCB *spcb; BOOL flag; char c; spcb = get_spcb(portid); flag = 0; /* * 1矢機減慨借妄 * * まず·バッファフルでない眷圭に·1矢機粕んでみるˉ粕めれば· * それに炳じた借妄を乖うˉ */ if (inc(spcb->in_write_ptr) != spcb->in_read_ptr && read_char(spcb, &c)) { if ((spcb->ioctl & IOCTL_IXON) != 0 && c == STOP) { spcb->ixon_stopped = TRUE; } else if (((spcb->ioctl & IOCTL_IXON) != 0 || spcb->ixon_stopped) && (c == START || (spcb->ioctl & IOCTL_IXANY) != 0)) { spcb->ixon_stopped = FALSE; } else { spcb->in_buffer[spcb->in_write_ptr] = c; if(spcb->in_read_ptr == spcb->in_write_ptr){ syscall(sig_sem(spcb->in_semid)); } INC(spcb->in_write_ptr); if ((spcb->ioctl & IOCTL_IXOFF) != 0 && !(spcb->ixoff_stopped) && (in_buf_area(p) < IXOFF_STOP)) { spcb->ixoff_stopped = TRUE; spcb->ixoff_send = STOP; } } flag = 1; } /* * 1矢機流慨借妄 */ if (spcb->ixoff_send) { if (write_char(spcb, spcb->ixoff_send)) { spcb->ixoff_send = 0; flag = 1; } } else if (!(spcb->ixon_stopped) && spcb->out_read_ptr != spcb->out_write_ptr) { if (write_char(spcb, spcb->out_buffer[spcb->out_read_ptr])) { if(OUT_BUFFER_FULL(spcb)){ syscall(isig_sem(spcb->out_semid)); } INC(spcb->out_read_ptr); flag = 1; } } return(flag);}/* * SIGIO コ〖ルバックル〖チン */static BOOLserial_sigio_callback(VP arg){ BOOL flag; do { syscall(loc_cpu()); flag = serial_int_handler(1); syscall(unl_cpu()); } while (flag); return(0);}/* * シリアルインタフェ〖スドライバの彈瓢 */voidserial_initialize(VP_INT portid){ syscall(serial_open((ID) portid)); serial_sigioeb.callback = serial_sigio_callback; serial_sigioeb.arg = (VP) 0; syscall(enqueue_sigioeb_initialize(&serial_sigioeb)); syslog_1(LOG_NOTICE, "Serial driver service starts on port %d.\r", portid);}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -