OSDN Git Service

7ecf59eb1108947c841e89f7619857f786fd2a26
[toppersasp4lpc/asp.git] / asp / syssvc / serial.c
1 /*
2  *  TOPPERS/ASP Kernel
3  *      Toyohashi Open Platform for Embedded Real-Time Systems/
4  *      Advanced Standard Profile Kernel
5  * 
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
10  * 
11  *  上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
12  *  ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
13  *  変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
14  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16  *      スコード中に含まれていること.
17  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
20  *      の無保証規定を掲載すること.
21  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
23  *      と.
24  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
26  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
27  *        報告すること.
28  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30  *      また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
31  *      由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
32  *      免責すること.
33  * 
34  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
35  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
36  *  に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
37  *  アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
38  *  の責任を負わない.
39  * 
40  *  @(#) $Id: serial.c 1176 2008-07-01 10:24:46Z ertl-hiro $
41  */
42
43 /*
44  *              シリアルインタフェースドライバ
45  */
46
47 #include <kernel.h>
48 #include <t_syslog.h>
49 #include "target_syssvc.h"
50 #include "target_serial.h"
51 #include "serial.h"
52 #include "kernel_cfg.h"
53
54 /*
55  *  バッファサイズのデフォルト値とバッファの定義
56  */
57 #ifndef SERIAL_RCV_BUFSZ1
58 #define SERIAL_RCV_BUFSZ1       256                     /* ポート1の受信バッファサイズ */
59 #endif /* SERIAL_RCV_BUFSZ1 */
60
61 #ifndef SERIAL_SND_BUFSZ1
62 #define SERIAL_SND_BUFSZ1       256                     /* ポート1の送信バッファサイズ */
63 #endif /* SERIAL_SND_BUFSZ1 */
64
65 static char_t   rcv_buffer1[SERIAL_RCV_BUFSZ1];
66 static char_t   snd_buffer1[SERIAL_SND_BUFSZ1];
67
68 #if TNUM_PORT >= 2                                              /* ポート2に関する定義 */
69
70 #ifndef SERIAL_RCV_BUFSZ2
71 #define SERIAL_RCV_BUFSZ2       256                     /* ポート2の受信バッファサイズ */
72 #endif /* SERIAL_RCV_BUFSZ2 */
73
74 #ifndef SERIAL_SND_BUFSZ2
75 #define SERIAL_SND_BUFSZ2       256                     /* ポート2の送信バッファサイズ */
76 #endif /* SERIAL_SND_BUFSZ2 */
77
78 static char_t   rcv_buffer2[SERIAL_RCV_BUFSZ2];
79 static char_t   snd_buffer2[SERIAL_SND_BUFSZ2];
80
81 #endif /* TNUM_PORT >= 2 */
82
83 #if TNUM_PORT >= 3                                              /* ポート3に関する定義 */
84
85 #ifndef SERIAL_RCV_BUFSZ3
86 #define SERIAL_RCV_BUFSZ3       256                     /* ポート3の受信バッファサイズ */
87 #endif /* SERIAL_RCV_BUFSZ3 */
88
89 #ifndef SERIAL_SND_BUFSZ3
90 #define SERIAL_SND_BUFSZ3       256                     /* ポート3の送信バッファサイズ */
91 #endif /* SERIAL_SND_BUFSZ3 */
92
93 static char_t   rcv_buffer3[SERIAL_RCV_BUFSZ3];
94 static char_t   snd_buffer3[SERIAL_SND_BUFSZ3];
95
96 #endif /* TNUM_PORT >= 3 */
97
98 /*
99  *  フロー制御に関連する定数とマクロ
100  */
101 #define FC_STOP                 '\023'          /* コントロール-S */
102 #define FC_START                '\021'          /* コントロール-Q */
103
104 #define BUFCNT_STOP(bufsz)              ((bufsz) * 3 / 4)       /* STOPを送る基準文字数 */
105 #define BUFCNT_START(bufsz)             ((bufsz) / 2)           /* STARTを送る基準文字数 */
106
107 /*
108  *  シリアルポート初期化ブロック
109  */
110 typedef struct serial_port_initialization_block {
111         ID              rcv_semid;              /* 受信バッファ管理用セマフォのID */
112         ID              snd_semid;              /* 送信バッファ管理用セマフォのID */
113         uint_t  rcv_bufsz;              /* 受信バッファサイズ */
114         char_t  *rcv_buffer;    /* 受信バッファ */
115         uint_t  snd_bufsz;              /* 送信バッファサイズ */
116         char_t  *snd_buffer;    /* 送信バッファ */
117 } SPINIB;
118
119 static const SPINIB spinib_table[TNUM_PORT] = {
120         { SERIAL_RCV_SEM1, SERIAL_SND_SEM1,
121           SERIAL_RCV_BUFSZ1, rcv_buffer1,
122           SERIAL_SND_BUFSZ1, snd_buffer1 },
123 #if TNUM_PORT >= 2
124         { SERIAL_RCV_SEM2, SERIAL_SND_SEM2,
125           SERIAL_RCV_BUFSZ2, rcv_buffer2,
126           SERIAL_SND_BUFSZ2, snd_buffer2 },
127 #endif /* TNUM_PORT >= 2 */
128 #if TNUM_PORT >= 3
129         { SERIAL_RCV_SEM3, SERIAL_SND_SEM3,
130           SERIAL_RCV_BUFSZ3, rcv_buffer3,
131           SERIAL_SND_BUFSZ3, snd_buffer3 },
132 #endif /* TNUM_PORT >= 3 */
133 };
134
135 /*
136  *  シリアルポート管理ブロック
137  */
138 typedef struct serial_port_control_block {
139         const SPINIB *p_spinib;         /* シリアルポート初期化ブロック */
140         SIOPCB  *p_siopcb;                      /* シリアルI/Oポート管理ブロック */
141         bool_t  openflag;                       /* オープン済みフラグ */
142         bool_t  errorflag;                      /* エラーフラグ */
143         uint_t  ioctl;                          /* 動作制御の設定値 */
144
145         uint_t  rcv_read_ptr;           /* 受信バッファ読出しポインタ */
146         uint_t  rcv_write_ptr;          /* 受信バッファ書込みポインタ */
147         uint_t  rcv_count;                      /* 受信バッファ中の文字数 */
148         char_t  rcv_fc_chr;                     /* 送るべきSTART/STOP */
149         bool_t  rcv_stopped;            /* STOPを送った状態か? */
150
151         uint_t  snd_read_ptr;           /* 送信バッファ読出しポインタ */
152         uint_t  snd_write_ptr;          /* 送信バッファ書込みポインタ */
153         uint_t  snd_count;                      /* 送信バッファ中の文字数 */
154         bool_t  snd_stopped;            /* STOPを受け取った状態か? */
155 } SPCB;
156
157 static SPCB     spcb_table[TNUM_PORT];
158
159 /*
160  *  シリアルポートIDからシリアルポート管理ブロックを取り出すためのマクロ
161  */
162 #define INDEX_PORT(portid)      ((uint_t)((portid) - 1))
163 #define get_spcb(portid)        (&(spcb_table[INDEX_PORT(portid)]))
164
165 /*
166  *  ポインタのインクリメント
167  */
168 #define INC_PTR(ptr, bufsz)             { if (++(ptr) == (bufsz)) { (ptr) = 0; }}
169
170 /*
171  *  サービスコール呼出しマクロ
172  *
173  *  サービスコール呼出しを含む式expを評価し,返値がエラー(負の値)の場
174  *  合には,ercにercd_expを評価した値を代入し,error_exitにgotoする.
175  */
176 #define SVC(exp, ercd_exp) \
177                                 { if ((exp) < 0) { ercd = (ercd_exp); goto error_exit; }}
178
179 /*
180  *  E_SYSエラーの生成
181  */
182 static ER
183 gen_ercd_sys(SPCB *p_spcb)
184 {
185         p_spcb->errorflag = true;
186         return(E_SYS);
187 }
188
189 /*
190  *  待ちに入るサービスコールからのエラーの変換
191  */
192 static ER
193 gen_ercd_wait(ER rercd, SPCB *p_spcb)
194 {
195         switch (MERCD(rercd)) {
196         case E_RLWAI:
197         case E_DLT:
198                 return(rercd);
199         default:
200                 p_spcb->errorflag = true;
201                 return(E_SYS);
202         }
203 }
204
205 /*
206  *  シリアルインタフェースドライバの初期化ルーチン
207  */
208 void
209 serial_initialize(intptr_t exinf)
210 {
211         uint_t  i;
212         SPCB    *p_spcb;
213
214         for (p_spcb = spcb_table, i = 0; i < TNUM_PORT; p_spcb++, i++) {
215                 p_spcb->p_spinib = &(spinib_table[i]);
216                 p_spcb->openflag = false;
217         }
218 }
219
220 /*
221  *  シリアルポートのオープン(サービスコール)
222  */
223 ER
224 serial_opn_por(ID portid)
225 {
226         SPCB    *p_spcb;
227         ER              ercd;
228
229         if (sns_dpn()) {                                /* コンテキストのチェック */
230                 return(E_CTX);
231         }
232         if (!(1 <= portid && portid <= TNUM_PORT)) {
233                 return(E_ID);                           /* ポート番号のチェック */
234         }
235         p_spcb = get_spcb(portid);
236
237         SVC(dis_dsp(), gen_ercd_sys(p_spcb));
238         if (p_spcb->openflag) {                 /* オープン済みかのチェック */
239                 ercd = E_OBJ;
240         }
241         else {
242                 /*
243                  *  変数の初期化
244                  */
245                 p_spcb->ioctl = (IOCTL_ECHO | IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV);
246
247                 p_spcb->rcv_read_ptr = p_spcb->rcv_write_ptr = 0U;
248                 p_spcb->rcv_count = 0U;
249                 p_spcb->rcv_fc_chr = '\0';
250                 p_spcb->rcv_stopped = false;
251
252                 p_spcb->snd_read_ptr = p_spcb->snd_write_ptr = 0U;
253                 p_spcb->snd_count = 0U;
254                 p_spcb->snd_stopped = false;
255
256                 /*
257                  *  これ以降,割込みを禁止する.
258                  */
259                 if (loc_cpu() < 0) {
260                         ercd = E_SYS;
261                         goto error_exit_enadsp;
262                 }
263
264                 /*
265                  *  ハードウェア依存のオープン処理
266                  */
267                 p_spcb->p_siopcb = sio_opn_por(portid, (intptr_t) p_spcb);
268
269                 /*
270                  *  受信通知コールバックを許可する.
271                  */
272                 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_RCV);
273                 p_spcb->openflag = true;
274                 p_spcb->errorflag = false;
275
276                 if (unl_cpu() < 0) {
277                         p_spcb->errorflag = true;
278                         ercd = E_SYS;
279                         goto error_exit_enadsp;
280                 }
281                 ercd = E_OK;
282         }
283
284   error_exit_enadsp:
285         SVC(ena_dsp(), gen_ercd_sys(p_spcb));
286
287   error_exit:
288         return(ercd);
289 }
290
291 /*
292  *  シリアルポートのクローズ(サービスコール)
293  */
294 ER
295 serial_cls_por(ID portid)
296 {
297         SPCB    *p_spcb;
298         ER              ercd;
299         bool_t  eflag = false;
300
301         if (sns_dpn()) {                                /* コンテキストのチェック */
302                 return(E_CTX);
303         }
304         if (!(1 <= portid && portid <= TNUM_PORT)) {
305                 return(E_ID);                           /* ポート番号のチェック */
306         }
307         p_spcb = get_spcb(portid);
308
309         SVC(dis_dsp(), gen_ercd_sys(p_spcb));
310         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
311                 ercd = E_OBJ;
312         }
313         else {
314                 /*
315                  *  ハードウェア依存のクローズ処理
316                  */
317                 if (loc_cpu() < 0) {
318                         eflag = true;
319                 }
320                 sio_cls_por(p_spcb->p_siopcb);
321                 p_spcb->openflag = false;
322                 if (unl_cpu() < 0) {
323                         eflag = true;
324                 }
325
326                 /*
327                  *  セマフォの初期化
328                  */
329                 if (ini_sem(p_spcb->p_spinib->snd_semid) < 0) {
330                         eflag = true;
331                 }
332                 if (ini_sem(p_spcb->p_spinib->rcv_semid) < 0) {
333                         eflag = true;
334                 }
335
336                 /*
337                  *  エラーコードの設定
338                  */
339                 if (eflag) {
340                         ercd = gen_ercd_sys(p_spcb);
341                 }
342                 else {
343                         ercd = E_OK;
344                 }
345         }
346         SVC(ena_dsp(), gen_ercd_sys(p_spcb));
347
348   error_exit:
349         return(ercd);
350 }
351
352 /*
353  *  シリアルポートへの文字送信
354  *
355  *  p_spcbで指定されるシリアルI/Oポートに対して,文字cを送信する.文字
356  *  を送信レジスタにいれた場合にはtrueを返す.そうでない場合には,送信
357  *  レジスタが空いたことを通知するコールバック関数を許可し,falseを返す.
358  *  この関数は,CPUロック状態で呼び出される.
359  */
360 Inline bool_t
361 serial_snd_chr(SPCB *p_spcb, char_t c)
362 {
363         if (sio_snd_chr(p_spcb->p_siopcb, c)) {
364                 return(true);
365         }
366         else {
367                 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
368                 return(false);
369         }
370 }
371
372 /*
373  *  シリアルポートへの1文字送信
374  */
375 static ER_BOOL
376 serial_wri_chr(SPCB *p_spcb, char_t c)
377 {
378         bool_t  buffer_full;
379         ER              ercd, rercd;
380
381         /*
382          *  LFの前にCRを送信する.
383          */
384         if (c == '\n' && (p_spcb->ioctl & IOCTL_CRLF) != 0U) {
385                 SVC(rercd = serial_wri_chr(p_spcb, '\r'), rercd);
386                 if ((bool_t) rercd) {
387                         SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
388                                                                                 gen_ercd_wait(rercd, p_spcb));
389                 }
390         }
391
392         SVC(loc_cpu(), gen_ercd_sys(p_spcb));
393         if (p_spcb->snd_count == 0U && !(p_spcb->snd_stopped)
394                                                                 && serial_snd_chr(p_spcb, c)) {
395                 /*
396                  *  シリアルI/Oデバイスの送信レジスタに文字を入れることに成功し
397                  *  た場合.
398                  */
399                 buffer_full = false;
400         }
401         else {
402                 /*
403                  *  送信バッファに文字を入れる.
404                  */
405                 p_spcb->p_spinib->snd_buffer[p_spcb->snd_write_ptr] = c;
406                 INC_PTR(p_spcb->snd_write_ptr, p_spcb->p_spinib->snd_bufsz);
407                 p_spcb->snd_count++;
408                 buffer_full = (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz);
409         }
410
411         SVC(unl_cpu(), gen_ercd_sys(p_spcb));
412         ercd = (ER_BOOL) buffer_full;
413
414   error_exit:
415         return(ercd);
416 }
417
418 /*
419  *  シリアルポートへの文字列送信(サービスコール)
420  */
421 ER_UINT
422 serial_wri_dat(ID portid, const char_t *buf, uint_t len)
423 {
424         SPCB    *p_spcb;
425         bool_t  buffer_full;
426         uint_t  wricnt = 0U;
427         ER              ercd, rercd;
428
429         if (sns_dpn()) {                                /* コンテキストのチェック */
430                 return(E_CTX);
431         }
432         if (!(1 <= portid && portid <= TNUM_PORT)) {
433                 return(E_ID);                           /* ポート番号のチェック */
434         }
435
436         p_spcb = get_spcb(portid);
437         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
438                 return(E_OBJ);
439         }
440         if (p_spcb->errorflag) {                /* エラー状態かのチェック */
441                 return(E_SYS);
442         }
443
444         buffer_full = true;                             /* ループの1回めはwai_semする */
445         while (wricnt < len) {
446                 if (buffer_full) {
447                         SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
448                                                                                 gen_ercd_wait(rercd, p_spcb));
449                 }
450                 SVC(rercd = serial_wri_chr(p_spcb, *buf++), rercd);
451                 wricnt++;
452                 buffer_full = (bool_t) rercd;
453         }
454         if (!buffer_full) {
455                 SVC(sig_sem(p_spcb->p_spinib->snd_semid), gen_ercd_sys(p_spcb));
456         }
457         ercd = E_OK;
458
459   error_exit:
460         return(wricnt > 0U ? (ER_UINT) wricnt : ercd);
461 }
462
463 /*
464  *  シリアルポートからの1文字受信
465  */
466 static bool_t
467 serial_rea_chr(SPCB *p_spcb, char_t *p_c)
468 {
469         bool_t  buffer_empty;
470         ER              ercd;
471
472         SVC(loc_cpu(), gen_ercd_sys(p_spcb));
473
474         /*
475          *  受信バッファから文字を取り出す.
476          */
477         *p_c = p_spcb->p_spinib->rcv_buffer[p_spcb->rcv_read_ptr];
478         INC_PTR(p_spcb->rcv_read_ptr, p_spcb->p_spinib->rcv_bufsz);
479         p_spcb->rcv_count--;
480         buffer_empty = (p_spcb->rcv_count == 0U);
481
482         /*
483          *  STARTを送信する.
484          */
485         if (p_spcb->rcv_stopped && p_spcb->rcv_count
486                                                                 <= BUFCNT_START(p_spcb->p_spinib->rcv_bufsz)) {
487                 if (!serial_snd_chr(p_spcb, FC_START)) {
488                         p_spcb->rcv_fc_chr = FC_START;
489                 }
490                 p_spcb->rcv_stopped = false;
491         }
492
493         SVC(unl_cpu(), gen_ercd_sys(p_spcb));
494         ercd = (ER_BOOL) buffer_empty;
495
496   error_exit:
497         return(ercd);
498 }
499
500 /*
501  *  シリアルポートからの文字列受信(サービスコール)
502  */
503 ER_UINT
504 serial_rea_dat(ID portid, char_t *buf, uint_t len)
505 {
506         SPCB    *p_spcb;
507         bool_t  buffer_empty;
508         uint_t  reacnt = 0U;
509         char_t  c = '\0';               /* コンパイラの警告を抑止するために初期化する */
510         ER              ercd, rercd;
511
512         if (sns_dpn()) {                                /* コンテキストのチェック */
513                 return(E_CTX);
514         }
515         if (!(1 <= portid && portid <= TNUM_PORT)) {
516                 return(E_ID);                           /* ポート番号のチェック */
517         }
518
519         p_spcb = get_spcb(portid);
520         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
521                 return(E_OBJ);
522         }
523         if (p_spcb->errorflag) {                /* エラー状態かのチェック */
524                 return(E_SYS);
525         }
526
527         buffer_empty = true;                    /* ループの1回めはwai_semする */
528         while (reacnt < len) {
529                 if (buffer_empty) {
530                         SVC(rercd = wai_sem(p_spcb->p_spinib->rcv_semid),
531                                                                                 gen_ercd_wait(rercd, p_spcb));
532                 }
533                 SVC(rercd = serial_rea_chr(p_spcb, &c), rercd);
534                 *buf++ = c;
535                 reacnt++;
536                 buffer_empty = (bool_t) rercd;
537
538                 /*
539                  *  エコーバック処理.
540                  */
541                 if ((p_spcb->ioctl & IOCTL_ECHO) != 0U) {
542                         SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
543                                                                                 gen_ercd_wait(rercd, p_spcb));
544                         SVC(rercd = serial_wri_chr(p_spcb, c), rercd);
545                         if (!((bool_t) rercd)) {
546                                 SVC(sig_sem(p_spcb->p_spinib->snd_semid),
547                                                                                 gen_ercd_sys(p_spcb));
548                         }
549                 }
550         }
551         if (!buffer_empty) {
552                 SVC(sig_sem(p_spcb->p_spinib->rcv_semid), gen_ercd_sys(p_spcb));
553         }
554         ercd = E_OK;
555
556   error_exit:
557         return(reacnt > 0U ? (ER_UINT) reacnt : ercd);
558 }
559
560 /*
561  *  シリアルポートの制御(サービスコール)
562  */
563 ER
564 serial_ctl_por(ID portid, uint_t ioctl)
565 {
566         SPCB    *p_spcb;
567
568         if (sns_dpn()) {                                /* コンテキストのチェック */
569                 return(E_CTX);
570         }
571         if (!(1 <= portid && portid <= TNUM_PORT)) {
572                 return(E_ID);                           /* ポート番号のチェック */
573         }
574
575         p_spcb = get_spcb(portid);
576         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
577                 return(E_OBJ);
578         }
579         if (p_spcb->errorflag) {                /* エラー状態かのチェック */
580                 return(E_SYS);
581         }
582
583         p_spcb->ioctl = ioctl;
584         return(E_OK);
585 }
586
587 /*
588  *  シリアルポート状態の参照(サービスコール)
589  */
590 ER
591 serial_ref_por(ID portid, T_SERIAL_RPOR *pk_rpor)
592 {
593         SPCB    *p_spcb;
594
595         if (sns_dpn()) {                                /* コンテキストのチェック */
596                 return(E_CTX);
597         }
598         if (!(1 <= portid && portid <= TNUM_PORT)) {
599                 return(E_ID);                           /* ポート番号のチェック */
600         }
601
602         p_spcb = get_spcb(portid);
603         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
604                 return(E_OBJ);
605         }
606         if (p_spcb->errorflag) {                /* エラー状態かのチェック */
607                 return(E_SYS);
608         }
609
610         pk_rpor->reacnt = p_spcb->rcv_count;
611         pk_rpor->wricnt = p_spcb->snd_count;
612         return(E_OK);
613 }
614
615 /*
616  *  シリアルポートからの送信可能コールバック
617  */
618 void
619 sio_irdy_snd(intptr_t exinf)
620 {
621         SPCB    *p_spcb;
622
623         p_spcb = (SPCB *) exinf;
624         if (p_spcb->rcv_fc_chr != '\0') {
625                 /*
626                  *  START/STOP を送信する.
627                  */
628                 (void) sio_snd_chr(p_spcb->p_siopcb, p_spcb->rcv_fc_chr);
629                 p_spcb->rcv_fc_chr = '\0';
630         }
631         else if (!(p_spcb->snd_stopped) && p_spcb->snd_count > 0U) {
632                 /*
633                  *  送信バッファ中から文字を取り出して送信する.
634                  */
635                 (void) sio_snd_chr(p_spcb->p_siopcb,
636                                         p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr]);
637                 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
638                 if (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz) {
639                         if (isig_sem(p_spcb->p_spinib->snd_semid) < 0) {
640                                 p_spcb->errorflag = true;
641                         }
642                 }
643                 p_spcb->snd_count--;
644         }
645         else {
646                 /*
647                  *  送信すべき文字がない場合は,送信可能コールバックを禁止する.
648                  */
649                 sio_dis_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
650         }
651 }
652
653 /*
654  *  シリアルポートからの受信通知コールバック
655  */
656 void
657 sio_irdy_rcv(intptr_t exinf)
658 {
659         SPCB    *p_spcb;
660         char_t  c;
661
662         p_spcb = (SPCB *) exinf;
663         c = (char_t) sio_rcv_chr(p_spcb->p_siopcb);
664         if ((p_spcb->ioctl & IOCTL_FCSND) != 0U && c == FC_STOP) {
665                 /*
666                  *  送信を一時停止する.送信中の文字はそのまま送信する.
667                  */
668                 p_spcb->snd_stopped = true;
669         }
670         else if (p_spcb->snd_stopped && (c == FC_START
671                                 || (p_spcb->ioctl & IOCTL_FCANY) != 0U)) {
672                 /*
673                  *  送信を再開する.
674                  */
675                 p_spcb->snd_stopped = false;
676                 if (p_spcb->snd_count > 0U) {
677                         c = p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr];
678                         if (serial_snd_chr(p_spcb, c)) {
679                                 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
680                                 if (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz) {
681                                         if (isig_sem(p_spcb->p_spinib->snd_semid) < 0) {
682                                                 p_spcb->errorflag = true;
683                                         }
684                                 }
685                                 p_spcb->snd_count--;
686                         }
687                 }
688         }
689         else if ((p_spcb->ioctl & IOCTL_FCSND) != 0U && c == FC_START) {
690                 /*
691                  *  送信に対してフロー制御している場合,START は捨てる.
692                  */
693         }
694         else if (p_spcb->rcv_count == p_spcb->p_spinib->rcv_bufsz) {
695                 /*
696                  *  バッファフルの場合,受信した文字を捨てる.
697                  */
698         }
699         else {
700                 /*
701                  *  受信した文字を受信バッファに入れる.
702                  */
703                 p_spcb->p_spinib->rcv_buffer[p_spcb->rcv_write_ptr] = c;
704                 INC_PTR(p_spcb->rcv_write_ptr, p_spcb->p_spinib->rcv_bufsz);
705                 if (p_spcb->rcv_count == 0U) {
706                         if (isig_sem(p_spcb->p_spinib->rcv_semid) < 0) {
707                                 p_spcb->errorflag = true;
708                         }
709                 }
710                 p_spcb->rcv_count++;
711
712                 /*
713                  *  STOPを送信する.
714                  */
715                 if ((p_spcb->ioctl & IOCTL_FCRCV) != 0U && !(p_spcb->rcv_stopped)
716                                                 && p_spcb->rcv_count
717                                                         >= BUFCNT_STOP(p_spcb->p_spinib->rcv_bufsz)) {
718                         if (!serial_snd_chr(p_spcb, FC_STOP)) {
719                                 p_spcb->rcv_fc_chr = FC_STOP;
720                         }
721                         p_spcb->rcv_stopped = true;
722                 }
723         }
724 }
725
726 /*
727  *  シリアルインタフェースドライバからの未送信文字の取出し
728  */
729 bool_t
730 serial_get_chr(ID portid, char_t *p_c)
731 {
732         SPCB    *p_spcb;
733
734         if (1 <= portid && portid <= TNUM_PORT) {       /* ポート番号のチェック */
735                 p_spcb = get_spcb(portid);
736                 if (p_spcb->openflag) {                                 /* オープン済みかのチェック */
737                         if (p_spcb->snd_count > 0U) {
738                                 *p_c = p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr];
739                                 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
740                                 p_spcb->snd_count--;
741                                 return(true);
742                         }
743                 }
744         }
745         return(false);
746 }