3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Advanced Standard Profile Kernel
6 * Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
7 * Toyohashi Univ. of Technology, JAPAN
8 * Copyright (C) 2006-2008 by Embedded and Real-Time Systems Laboratory
9 * Graduate School of Information Science, Nagoya Univ., JAPAN
11 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
12 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
13 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
14 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
17 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
21 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
24 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
26 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
28 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
31 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
34 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
35 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
36 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
37 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
40 * @(#) $Id: serial.c 1176 2008-07-01 10:24:46Z ertl-hiro $
49 #include "target_syssvc.h"
50 #include "target_serial.h"
52 #include "kernel_cfg.h"
55 * バッファサイズのデフォルト値とバッファの定義
57 #ifndef SERIAL_RCV_BUFSZ1
58 #define SERIAL_RCV_BUFSZ1 256 /* ポート1の受信バッファサイズ */
59 #endif /* SERIAL_RCV_BUFSZ1 */
61 #ifndef SERIAL_SND_BUFSZ1
62 #define SERIAL_SND_BUFSZ1 256 /* ポート1の送信バッファサイズ */
63 #endif /* SERIAL_SND_BUFSZ1 */
65 static char_t rcv_buffer1[SERIAL_RCV_BUFSZ1];
66 static char_t snd_buffer1[SERIAL_SND_BUFSZ1];
68 #if TNUM_PORT >= 2 /* ポート2に関する定義 */
70 #ifndef SERIAL_RCV_BUFSZ2
71 #define SERIAL_RCV_BUFSZ2 256 /* ポート2の受信バッファサイズ */
72 #endif /* SERIAL_RCV_BUFSZ2 */
74 #ifndef SERIAL_SND_BUFSZ2
75 #define SERIAL_SND_BUFSZ2 256 /* ポート2の送信バッファサイズ */
76 #endif /* SERIAL_SND_BUFSZ2 */
78 static char_t rcv_buffer2[SERIAL_RCV_BUFSZ2];
79 static char_t snd_buffer2[SERIAL_SND_BUFSZ2];
81 #endif /* TNUM_PORT >= 2 */
83 #if TNUM_PORT >= 3 /* ポート3に関する定義 */
85 #ifndef SERIAL_RCV_BUFSZ3
86 #define SERIAL_RCV_BUFSZ3 256 /* ポート3の受信バッファサイズ */
87 #endif /* SERIAL_RCV_BUFSZ3 */
89 #ifndef SERIAL_SND_BUFSZ3
90 #define SERIAL_SND_BUFSZ3 256 /* ポート3の送信バッファサイズ */
91 #endif /* SERIAL_SND_BUFSZ3 */
93 static char_t rcv_buffer3[SERIAL_RCV_BUFSZ3];
94 static char_t snd_buffer3[SERIAL_SND_BUFSZ3];
96 #endif /* TNUM_PORT >= 3 */
98 #if TNUM_PORT >= 4 /* ポート4に関する定義 */
100 #ifndef SERIAL_RCV_BUFSZ4
101 #define SERIAL_RCV_BUFSZ4 256 /* ポート4の受信バッファサイズ */
102 #endif /* SERIAL_RCV_BUFSZ4 */
104 #ifndef SERIAL_SND_BUFSZ4
105 #define SERIAL_SND_BUFSZ4 256 /* ポート4の送信バッファサイズ */
106 #endif /* SERIAL_SND_BUFSZ4 */
108 static char_t rcv_buffer4[SERIAL_RCV_BUFSZ4];
109 static char_t snd_buffer4[SERIAL_SND_BUFSZ4];
111 #endif /* TNUM_PORT >= 4 */
116 #define FC_STOP '\023' /* コントロール-S */
117 #define FC_START '\021' /* コントロール-Q */
119 #define BUFCNT_STOP(bufsz) ((bufsz) * 3 / 4) /* STOPを送る基準文字数 */
120 #define BUFCNT_START(bufsz) ((bufsz) / 2) /* STARTを送る基準文字数 */
125 typedef struct serial_port_initialization_block {
126 ID rcv_semid; /* 受信バッファ管理用セマフォのID */
127 ID snd_semid; /* 送信バッファ管理用セマフォのID */
128 uint_t rcv_bufsz; /* 受信バッファサイズ */
129 char_t *rcv_buffer; /* 受信バッファ */
130 uint_t snd_bufsz; /* 送信バッファサイズ */
131 char_t *snd_buffer; /* 送信バッファ */
134 static const SPINIB spinib_table[TNUM_PORT] = {
135 { SERIAL_RCV_SEM1, SERIAL_SND_SEM1,
136 SERIAL_RCV_BUFSZ1, rcv_buffer1,
137 SERIAL_SND_BUFSZ1, snd_buffer1 },
139 { SERIAL_RCV_SEM2, SERIAL_SND_SEM2,
140 SERIAL_RCV_BUFSZ2, rcv_buffer2,
141 SERIAL_SND_BUFSZ2, snd_buffer2 },
142 #endif /* TNUM_PORT >= 2 */
144 { SERIAL_RCV_SEM3, SERIAL_SND_SEM3,
145 SERIAL_RCV_BUFSZ3, rcv_buffer3,
146 SERIAL_SND_BUFSZ3, snd_buffer3 },
147 #endif /* TNUM_PORT >= 3 */
149 { SERIAL_RCV_SEM4, SERIAL_SND_SEM4,
150 SERIAL_RCV_BUFSZ4, rcv_buffer4,
151 SERIAL_SND_BUFSZ4, snd_buffer4 },
152 #endif /* TNUM_PORT >= 4 */
158 typedef struct serial_port_control_block {
159 const SPINIB *p_spinib; /* シリアルポート初期化ブロック */
160 SIOPCB *p_siopcb; /* シリアルI/Oポート管理ブロック */
161 bool_t openflag; /* オープン済みフラグ */
162 bool_t errorflag; /* エラーフラグ */
163 uint_t ioctl; /* 動作制御の設定値 */
165 uint_t rcv_read_ptr; /* 受信バッファ読出しポインタ */
166 uint_t rcv_write_ptr; /* 受信バッファ書込みポインタ */
167 uint_t rcv_count; /* 受信バッファ中の文字数 */
168 char_t rcv_fc_chr; /* 送るべきSTART/STOP */
169 bool_t rcv_stopped; /* STOPを送った状態か? */
171 uint_t snd_read_ptr; /* 送信バッファ読出しポインタ */
172 uint_t snd_write_ptr; /* 送信バッファ書込みポインタ */
173 uint_t snd_count; /* 送信バッファ中の文字数 */
174 bool_t snd_stopped; /* STOPを受け取った状態か? */
177 static SPCB spcb_table[TNUM_PORT];
180 * シリアルポートIDからシリアルポート管理ブロックを取り出すためのマクロ
182 #define INDEX_PORT(portid) ((uint_t)((portid) - 1))
183 #define get_spcb(portid) (&(spcb_table[INDEX_PORT(portid)]))
188 #define INC_PTR(ptr, bufsz) { if (++(ptr) == (bufsz)) { (ptr) = 0; }}
193 * サービスコール呼出しを含む式expを評価し,返値がエラー(負の値)の場
194 * 合には,ercにercd_expを評価した値を代入し,error_exitにgotoする.
196 #define SVC(exp, ercd_exp) \
197 { if ((exp) < 0) { ercd = (ercd_exp); goto error_exit; }}
203 gen_ercd_sys(SPCB *p_spcb)
205 p_spcb->errorflag = true;
210 * 待ちに入るサービスコールからのエラーの変換
213 gen_ercd_wait(ER rercd, SPCB *p_spcb)
215 switch (MERCD(rercd)) {
220 p_spcb->errorflag = true;
226 * シリアルインタフェースドライバの初期化ルーチン
229 serial_initialize(intptr_t exinf)
234 for (p_spcb = spcb_table, i = 0; i < TNUM_PORT; p_spcb++, i++) {
235 p_spcb->p_spinib = &(spinib_table[i]);
236 p_spcb->openflag = false;
241 * シリアルポートのオープン(サービスコール)
244 serial_opn_por(ID portid)
249 if (sns_dpn()) { /* コンテキストのチェック */
252 if (!(1 <= portid && portid <= TNUM_PORT)) {
253 return(E_ID); /* ポート番号のチェック */
255 p_spcb = get_spcb(portid);
257 SVC(dis_dsp(), gen_ercd_sys(p_spcb));
258 if (p_spcb->openflag) { /* オープン済みかのチェック */
264 * エコーバックさせたい時にはIOCTL_ECHOを追加すると良い。
266 p_spcb->ioctl = (IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV);
268 p_spcb->rcv_read_ptr = p_spcb->rcv_write_ptr = 0U;
269 p_spcb->rcv_count = 0U;
270 p_spcb->rcv_fc_chr = '\0';
271 p_spcb->rcv_stopped = false;
273 p_spcb->snd_read_ptr = p_spcb->snd_write_ptr = 0U;
274 p_spcb->snd_count = 0U;
275 p_spcb->snd_stopped = false;
282 goto error_exit_enadsp;
288 p_spcb->p_siopcb = sio_opn_por(portid, (intptr_t) p_spcb);
293 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_RCV);
294 p_spcb->openflag = true;
295 p_spcb->errorflag = false;
298 p_spcb->errorflag = true;
300 goto error_exit_enadsp;
306 SVC(ena_dsp(), gen_ercd_sys(p_spcb));
313 * シリアルポートのクローズ(サービスコール)
316 serial_cls_por(ID portid)
320 bool_t eflag = false;
322 if (sns_dpn()) { /* コンテキストのチェック */
325 if (!(1 <= portid && portid <= TNUM_PORT)) {
326 return(E_ID); /* ポート番号のチェック */
328 p_spcb = get_spcb(portid);
330 SVC(dis_dsp(), gen_ercd_sys(p_spcb));
331 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
341 sio_cls_por(p_spcb->p_siopcb);
342 p_spcb->openflag = false;
350 if (ini_sem(p_spcb->p_spinib->snd_semid) < 0) {
353 if (ini_sem(p_spcb->p_spinib->rcv_semid) < 0) {
361 ercd = gen_ercd_sys(p_spcb);
367 SVC(ena_dsp(), gen_ercd_sys(p_spcb));
376 * p_spcbで指定されるシリアルI/Oポートに対して,文字cを送信する.文字
377 * を送信レジスタにいれた場合にはtrueを返す.そうでない場合には,送信
378 * レジスタが空いたことを通知するコールバック関数を許可し,falseを返す.
379 * この関数は,CPUロック状態で呼び出される.
382 serial_snd_chr(SPCB *p_spcb, char_t c)
384 if (sio_snd_chr(p_spcb->p_siopcb, c)) {
388 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
397 serial_wri_chr(SPCB *p_spcb, char_t c)
405 if (c == '\n' && (p_spcb->ioctl & IOCTL_CRLF) != 0U) {
406 SVC(rercd = serial_wri_chr(p_spcb, '\r'), rercd);
407 if ((bool_t) rercd) {
408 SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
409 gen_ercd_wait(rercd, p_spcb));
413 SVC(loc_cpu(), gen_ercd_sys(p_spcb));
414 if (p_spcb->snd_count == 0U && !(p_spcb->snd_stopped)
415 && serial_snd_chr(p_spcb, c)) {
417 * シリアルI/Oデバイスの送信レジスタに文字を入れることに成功し
426 p_spcb->p_spinib->snd_buffer[p_spcb->snd_write_ptr] = c;
427 INC_PTR(p_spcb->snd_write_ptr, p_spcb->p_spinib->snd_bufsz);
429 buffer_full = (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz);
432 SVC(unl_cpu(), gen_ercd_sys(p_spcb));
433 ercd = (ER_BOOL) buffer_full;
440 * シリアルポートへの文字列送信(サービスコール)
443 serial_wri_dat(ID portid, const char_t *buf, uint_t len)
450 if (sns_dpn()) { /* コンテキストのチェック */
453 if (!(1 <= portid && portid <= TNUM_PORT)) {
454 return(E_ID); /* ポート番号のチェック */
457 p_spcb = get_spcb(portid);
458 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
461 if (p_spcb->errorflag) { /* エラー状態かのチェック */
465 buffer_full = true; /* ループの1回めはwai_semする */
466 while (wricnt < len) {
468 SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
469 gen_ercd_wait(rercd, p_spcb));
471 SVC(rercd = serial_wri_chr(p_spcb, *buf++), rercd);
473 buffer_full = (bool_t) rercd;
476 SVC(sig_sem(p_spcb->p_spinib->snd_semid), gen_ercd_sys(p_spcb));
481 return(wricnt > 0U ? (ER_UINT) wricnt : ercd);
488 serial_rea_chr(SPCB *p_spcb, char_t *p_c)
493 SVC(loc_cpu(), gen_ercd_sys(p_spcb));
498 *p_c = p_spcb->p_spinib->rcv_buffer[p_spcb->rcv_read_ptr];
499 INC_PTR(p_spcb->rcv_read_ptr, p_spcb->p_spinib->rcv_bufsz);
501 buffer_empty = (p_spcb->rcv_count == 0U);
506 if (p_spcb->rcv_stopped && p_spcb->rcv_count
507 <= BUFCNT_START(p_spcb->p_spinib->rcv_bufsz)) {
508 if (!serial_snd_chr(p_spcb, FC_START)) {
509 p_spcb->rcv_fc_chr = FC_START;
511 p_spcb->rcv_stopped = false;
514 SVC(unl_cpu(), gen_ercd_sys(p_spcb));
515 ercd = (ER_BOOL) buffer_empty;
522 * シリアルポートからの文字列受信(サービスコール)
525 serial_rea_dat(ID portid, char_t *buf, uint_t len)
530 char_t c = '\0'; /* コンパイラの警告を抑止するために初期化する */
533 if (sns_dpn()) { /* コンテキストのチェック */
536 if (!(1 <= portid && portid <= TNUM_PORT)) {
537 return(E_ID); /* ポート番号のチェック */
540 p_spcb = get_spcb(portid);
541 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
544 if (p_spcb->errorflag) { /* エラー状態かのチェック */
548 buffer_empty = true; /* ループの1回めはwai_semする */
549 while (reacnt < len) {
551 SVC(rercd = wai_sem(p_spcb->p_spinib->rcv_semid),
552 gen_ercd_wait(rercd, p_spcb));
554 SVC(rercd = serial_rea_chr(p_spcb, &c), rercd);
557 buffer_empty = (bool_t) rercd;
562 if ((p_spcb->ioctl & IOCTL_ECHO) != 0U) {
563 SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
564 gen_ercd_wait(rercd, p_spcb));
565 SVC(rercd = serial_wri_chr(p_spcb, c), rercd);
566 if (!((bool_t) rercd)) {
567 SVC(sig_sem(p_spcb->p_spinib->snd_semid),
568 gen_ercd_sys(p_spcb));
573 SVC(sig_sem(p_spcb->p_spinib->rcv_semid), gen_ercd_sys(p_spcb));
578 return(reacnt > 0U ? (ER_UINT) reacnt : ercd);
582 * シリアルポートの制御(サービスコール)
585 serial_ctl_por(ID portid, uint_t ioctl)
589 if (sns_dpn()) { /* コンテキストのチェック */
592 if (!(1 <= portid && portid <= TNUM_PORT)) {
593 return(E_ID); /* ポート番号のチェック */
596 p_spcb = get_spcb(portid);
597 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
600 if (p_spcb->errorflag) { /* エラー状態かのチェック */
604 p_spcb->ioctl = ioctl;
609 * シリアルポート状態の参照(サービスコール)
612 serial_ref_por(ID portid, T_SERIAL_RPOR *pk_rpor)
616 if (sns_dpn()) { /* コンテキストのチェック */
619 if (!(1 <= portid && portid <= TNUM_PORT)) {
620 return(E_ID); /* ポート番号のチェック */
623 p_spcb = get_spcb(portid);
624 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
627 if (p_spcb->errorflag) { /* エラー状態かのチェック */
631 pk_rpor->reacnt = p_spcb->rcv_count;
632 pk_rpor->wricnt = p_spcb->snd_count;
637 * シリアルポートからの送信可能コールバック
640 sio_irdy_snd(intptr_t exinf)
644 p_spcb = (SPCB *) exinf;
645 if (p_spcb->rcv_fc_chr != '\0') {
649 (void) sio_snd_chr(p_spcb->p_siopcb, p_spcb->rcv_fc_chr);
650 p_spcb->rcv_fc_chr = '\0';
652 else if (!(p_spcb->snd_stopped) && p_spcb->snd_count > 0U) {
654 * 送信バッファ中から文字を取り出して送信する.
656 (void) sio_snd_chr(p_spcb->p_siopcb,
657 p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr]);
658 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
659 if (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz) {
660 if (isig_sem(p_spcb->p_spinib->snd_semid) < 0) {
661 p_spcb->errorflag = true;
668 * 送信すべき文字がない場合は,送信可能コールバックを禁止する.
670 sio_dis_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
675 * シリアルポートからの受信通知コールバック
678 sio_irdy_rcv(intptr_t exinf)
683 p_spcb = (SPCB *) exinf;
684 c = (char_t) sio_rcv_chr(p_spcb->p_siopcb);
685 if ((p_spcb->ioctl & IOCTL_FCSND) != 0U && c == FC_STOP) {
687 * 送信を一時停止する.送信中の文字はそのまま送信する.
689 p_spcb->snd_stopped = true;
691 else if (p_spcb->snd_stopped && (c == FC_START
692 || (p_spcb->ioctl & IOCTL_FCANY) != 0U)) {
696 p_spcb->snd_stopped = false;
697 if (p_spcb->snd_count > 0U) {
698 c = p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr];
699 if (serial_snd_chr(p_spcb, c)) {
700 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
701 if (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz) {
702 if (isig_sem(p_spcb->p_spinib->snd_semid) < 0) {
703 p_spcb->errorflag = true;
710 else if ((p_spcb->ioctl & IOCTL_FCSND) != 0U && c == FC_START) {
712 * 送信に対してフロー制御している場合,START は捨てる.
715 else if (p_spcb->rcv_count == p_spcb->p_spinib->rcv_bufsz) {
717 * バッファフルの場合,受信した文字を捨てる.
724 p_spcb->p_spinib->rcv_buffer[p_spcb->rcv_write_ptr] = c;
725 INC_PTR(p_spcb->rcv_write_ptr, p_spcb->p_spinib->rcv_bufsz);
726 if (p_spcb->rcv_count == 0U) {
727 if (isig_sem(p_spcb->p_spinib->rcv_semid) < 0) {
728 p_spcb->errorflag = true;
736 if ((p_spcb->ioctl & IOCTL_FCRCV) != 0U && !(p_spcb->rcv_stopped)
738 >= BUFCNT_STOP(p_spcb->p_spinib->rcv_bufsz)) {
739 if (!serial_snd_chr(p_spcb, FC_STOP)) {
740 p_spcb->rcv_fc_chr = FC_STOP;
742 p_spcb->rcv_stopped = true;
748 * シリアルインタフェースドライバからの未送信文字の取出し
751 serial_get_chr(ID portid, char_t *p_c)
755 if (1 <= portid && portid <= TNUM_PORT) { /* ポート番号のチェック */
756 p_spcb = get_spcb(portid);
757 if (p_spcb->openflag) { /* オープン済みかのチェック */
758 if (p_spcb->snd_count > 0U) {
759 *p_c = p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr];
760 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);