OSDN Git Service

First commitment for the BlackTank LPC1769.
[blacktank/blacktank.git] / kernel / 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 #if TNUM_PORT >= 4                                              /* ポート4に関する定義 */
99
100 #ifndef SERIAL_RCV_BUFSZ4
101 #define SERIAL_RCV_BUFSZ4       256                     /* ポート4の受信バッファサイズ */
102 #endif /* SERIAL_RCV_BUFSZ4 */
103
104 #ifndef SERIAL_SND_BUFSZ4
105 #define SERIAL_SND_BUFSZ4       256                     /* ポート4の送信バッファサイズ */
106 #endif /* SERIAL_SND_BUFSZ4 */
107
108 static char_t   rcv_buffer4[SERIAL_RCV_BUFSZ4];
109 static char_t   snd_buffer4[SERIAL_SND_BUFSZ4];
110
111 #endif /* TNUM_PORT >= 4 */
112
113 /*
114  *  フロー制御に関連する定数とマクロ
115  */
116 #define FC_STOP                 '\023'          /* コントロール-S */
117 #define FC_START                '\021'          /* コントロール-Q */
118
119 #define BUFCNT_STOP(bufsz)              ((bufsz) * 3 / 4)       /* STOPを送る基準文字数 */
120 #define BUFCNT_START(bufsz)             ((bufsz) / 2)           /* STARTを送る基準文字数 */
121
122 /*
123  *  シリアルポート初期化ブロック
124  */
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;    /* 送信バッファ */
132 } SPINIB;
133
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 },
138 #if TNUM_PORT >= 2
139         { SERIAL_RCV_SEM2, SERIAL_SND_SEM2,
140           SERIAL_RCV_BUFSZ2, rcv_buffer2,
141           SERIAL_SND_BUFSZ2, snd_buffer2 },
142 #endif /* TNUM_PORT >= 2 */
143 #if TNUM_PORT >= 3
144         { SERIAL_RCV_SEM3, SERIAL_SND_SEM3,
145           SERIAL_RCV_BUFSZ3, rcv_buffer3,
146           SERIAL_SND_BUFSZ3, snd_buffer3 },
147 #endif /* TNUM_PORT >= 3 */
148 #if TNUM_PORT >= 4
149         { SERIAL_RCV_SEM4, SERIAL_SND_SEM4,
150           SERIAL_RCV_BUFSZ4, rcv_buffer4,
151           SERIAL_SND_BUFSZ4, snd_buffer4 },
152 #endif /* TNUM_PORT >= 4 */
153 };
154
155 /*
156  *  シリアルポート管理ブロック
157  */
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;                          /* 動作制御の設定値 */
164
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を送った状態か? */
170
171         uint_t  snd_read_ptr;           /* 送信バッファ読出しポインタ */
172         uint_t  snd_write_ptr;          /* 送信バッファ書込みポインタ */
173         uint_t  snd_count;                      /* 送信バッファ中の文字数 */
174         bool_t  snd_stopped;            /* STOPを受け取った状態か? */
175 } SPCB;
176
177 static SPCB     spcb_table[TNUM_PORT];
178
179 /*
180  *  シリアルポートIDからシリアルポート管理ブロックを取り出すためのマクロ
181  */
182 #define INDEX_PORT(portid)      ((uint_t)((portid) - 1))
183 #define get_spcb(portid)        (&(spcb_table[INDEX_PORT(portid)]))
184
185 /*
186  *  ポインタのインクリメント
187  */
188 #define INC_PTR(ptr, bufsz)             { if (++(ptr) == (bufsz)) { (ptr) = 0; }}
189
190 /*
191  *  サービスコール呼出しマクロ
192  *
193  *  サービスコール呼出しを含む式expを評価し,返値がエラー(負の値)の場
194  *  合には,ercにercd_expを評価した値を代入し,error_exitにgotoする.
195  */
196 #define SVC(exp, ercd_exp) \
197                                 { if ((exp) < 0) { ercd = (ercd_exp); goto error_exit; }}
198
199 /*
200  *  E_SYSエラーの生成
201  */
202 static ER
203 gen_ercd_sys(SPCB *p_spcb)
204 {
205         p_spcb->errorflag = true;
206         return(E_SYS);
207 }
208
209 /*
210  *  待ちに入るサービスコールからのエラーの変換
211  */
212 static ER
213 gen_ercd_wait(ER rercd, SPCB *p_spcb)
214 {
215         switch (MERCD(rercd)) {
216         case E_RLWAI:
217         case E_DLT:
218                 return(rercd);
219         default:
220                 p_spcb->errorflag = true;
221                 return(E_SYS);
222         }
223 }
224
225 /*
226  *  シリアルインタフェースドライバの初期化ルーチン
227  */
228 void
229 serial_initialize(intptr_t exinf)
230 {
231         uint_t  i;
232         SPCB    *p_spcb;
233
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;
237         }
238 }
239
240 /*
241  *  シリアルポートのオープン(サービスコール)
242  */
243 ER
244 serial_opn_por(ID portid)
245 {
246         SPCB    *p_spcb;
247         ER              ercd;
248
249         if (sns_dpn()) {                                /* コンテキストのチェック */
250                 return(E_CTX);
251         }
252         if (!(1 <= portid && portid <= TNUM_PORT)) {
253                 return(E_ID);                           /* ポート番号のチェック */
254         }
255         p_spcb = get_spcb(portid);
256
257         SVC(dis_dsp(), gen_ercd_sys(p_spcb));
258         if (p_spcb->openflag) {                 /* オープン済みかのチェック */
259                 ercd = E_OBJ;
260         }
261         else {
262                 /*
263                  *  変数の初期化
264                  *  エコーバックさせたい時にはIOCTL_ECHOを追加すると良い。
265                  */
266                 p_spcb->ioctl = (IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV);
267
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;
272
273                 p_spcb->snd_read_ptr = p_spcb->snd_write_ptr = 0U;
274                 p_spcb->snd_count = 0U;
275                 p_spcb->snd_stopped = false;
276
277                 /*
278                  *  これ以降,割込みを禁止する.
279                  */
280                 if (loc_cpu() < 0) {
281                         ercd = E_SYS;
282                         goto error_exit_enadsp;
283                 }
284
285                 /*
286                  *  ハードウェア依存のオープン処理
287                  */
288                 p_spcb->p_siopcb = sio_opn_por(portid, (intptr_t) p_spcb);
289
290                 /*
291                  *  受信通知コールバックを許可する.
292                  */
293                 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_RCV);
294                 p_spcb->openflag = true;
295                 p_spcb->errorflag = false;
296
297                 if (unl_cpu() < 0) {
298                         p_spcb->errorflag = true;
299                         ercd = E_SYS;
300                         goto error_exit_enadsp;
301                 }
302                 ercd = E_OK;
303         }
304
305   error_exit_enadsp:
306         SVC(ena_dsp(), gen_ercd_sys(p_spcb));
307
308   error_exit:
309         return(ercd);
310 }
311
312 /*
313  *  シリアルポートのクローズ(サービスコール)
314  */
315 ER
316 serial_cls_por(ID portid)
317 {
318         SPCB    *p_spcb;
319         ER              ercd;
320         bool_t  eflag = false;
321
322         if (sns_dpn()) {                                /* コンテキストのチェック */
323                 return(E_CTX);
324         }
325         if (!(1 <= portid && portid <= TNUM_PORT)) {
326                 return(E_ID);                           /* ポート番号のチェック */
327         }
328         p_spcb = get_spcb(portid);
329
330         SVC(dis_dsp(), gen_ercd_sys(p_spcb));
331         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
332                 ercd = E_OBJ;
333         }
334         else {
335                 /*
336                  *  ハードウェア依存のクローズ処理
337                  */
338                 if (loc_cpu() < 0) {
339                         eflag = true;
340                 }
341                 sio_cls_por(p_spcb->p_siopcb);
342                 p_spcb->openflag = false;
343                 if (unl_cpu() < 0) {
344                         eflag = true;
345                 }
346
347                 /*
348                  *  セマフォの初期化
349                  */
350                 if (ini_sem(p_spcb->p_spinib->snd_semid) < 0) {
351                         eflag = true;
352                 }
353                 if (ini_sem(p_spcb->p_spinib->rcv_semid) < 0) {
354                         eflag = true;
355                 }
356
357                 /*
358                  *  エラーコードの設定
359                  */
360                 if (eflag) {
361                         ercd = gen_ercd_sys(p_spcb);
362                 }
363                 else {
364                         ercd = E_OK;
365                 }
366         }
367         SVC(ena_dsp(), gen_ercd_sys(p_spcb));
368
369   error_exit:
370         return(ercd);
371 }
372
373 /*
374  *  シリアルポートへの文字送信
375  *
376  *  p_spcbで指定されるシリアルI/Oポートに対して,文字cを送信する.文字
377  *  を送信レジスタにいれた場合にはtrueを返す.そうでない場合には,送信
378  *  レジスタが空いたことを通知するコールバック関数を許可し,falseを返す.
379  *  この関数は,CPUロック状態で呼び出される.
380  */
381 Inline bool_t
382 serial_snd_chr(SPCB *p_spcb, char_t c)
383 {
384         if (sio_snd_chr(p_spcb->p_siopcb, c)) {
385                 return(true);
386         }
387         else {
388                 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
389                 return(false);
390         }
391 }
392
393 /*
394  *  シリアルポートへの1文字送信
395  */
396 static ER_BOOL
397 serial_wri_chr(SPCB *p_spcb, char_t c)
398 {
399         bool_t  buffer_full;
400         ER              ercd, rercd;
401
402         /*
403          *  LFの前にCRを送信する.
404          */
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));
410                 }
411         }
412
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)) {
416                 /*
417                  *  シリアルI/Oデバイスの送信レジスタに文字を入れることに成功し
418                  *  た場合.
419                  */
420                 buffer_full = false;
421         }
422         else {
423                 /*
424                  *  送信バッファに文字を入れる.
425                  */
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);
428                 p_spcb->snd_count++;
429                 buffer_full = (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz);
430         }
431
432         SVC(unl_cpu(), gen_ercd_sys(p_spcb));
433         ercd = (ER_BOOL) buffer_full;
434
435   error_exit:
436         return(ercd);
437 }
438
439 /*
440  *  シリアルポートへの文字列送信(サービスコール)
441  */
442 ER_UINT
443 serial_wri_dat(ID portid, const char_t *buf, uint_t len)
444 {
445         SPCB    *p_spcb;
446         bool_t  buffer_full;
447         uint_t  wricnt = 0U;
448         ER              ercd, rercd;
449
450         if (sns_dpn()) {                                /* コンテキストのチェック */
451                 return(E_CTX);
452         }
453         if (!(1 <= portid && portid <= TNUM_PORT)) {
454                 return(E_ID);                           /* ポート番号のチェック */
455         }
456
457         p_spcb = get_spcb(portid);
458         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
459                 return(E_OBJ);
460         }
461         if (p_spcb->errorflag) {                /* エラー状態かのチェック */
462                 return(E_SYS);
463         }
464
465         buffer_full = true;                             /* ループの1回めはwai_semする */
466         while (wricnt < len) {
467                 if (buffer_full) {
468                         SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
469                                                                                 gen_ercd_wait(rercd, p_spcb));
470                 }
471                 SVC(rercd = serial_wri_chr(p_spcb, *buf++), rercd);
472                 wricnt++;
473                 buffer_full = (bool_t) rercd;
474         }
475         if (!buffer_full) {
476                 SVC(sig_sem(p_spcb->p_spinib->snd_semid), gen_ercd_sys(p_spcb));
477         }
478         ercd = E_OK;
479
480   error_exit:
481         return(wricnt > 0U ? (ER_UINT) wricnt : ercd);
482 }
483
484 /*
485  *  シリアルポートからの1文字受信
486  */
487 static bool_t
488 serial_rea_chr(SPCB *p_spcb, char_t *p_c)
489 {
490         bool_t  buffer_empty;
491         ER              ercd;
492
493         SVC(loc_cpu(), gen_ercd_sys(p_spcb));
494
495         /*
496          *  受信バッファから文字を取り出す.
497          */
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);
500         p_spcb->rcv_count--;
501         buffer_empty = (p_spcb->rcv_count == 0U);
502
503         /*
504          *  STARTを送信する.
505          */
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;
510                 }
511                 p_spcb->rcv_stopped = false;
512         }
513
514         SVC(unl_cpu(), gen_ercd_sys(p_spcb));
515         ercd = (ER_BOOL) buffer_empty;
516
517   error_exit:
518         return(ercd);
519 }
520
521 /*
522  *  シリアルポートからの文字列受信(サービスコール)
523  */
524 ER_UINT
525 serial_rea_dat(ID portid, char_t *buf, uint_t len)
526 {
527         SPCB    *p_spcb;
528         bool_t  buffer_empty;
529         uint_t  reacnt = 0U;
530         char_t  c = '\0';               /* コンパイラの警告を抑止するために初期化する */
531         ER              ercd, rercd;
532
533         if (sns_dpn()) {                                /* コンテキストのチェック */
534                 return(E_CTX);
535         }
536         if (!(1 <= portid && portid <= TNUM_PORT)) {
537                 return(E_ID);                           /* ポート番号のチェック */
538         }
539
540         p_spcb = get_spcb(portid);
541         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
542                 return(E_OBJ);
543         }
544         if (p_spcb->errorflag) {                /* エラー状態かのチェック */
545                 return(E_SYS);
546         }
547
548         buffer_empty = true;                    /* ループの1回めはwai_semする */
549         while (reacnt < len) {
550                 if (buffer_empty) {
551                         SVC(rercd = wai_sem(p_spcb->p_spinib->rcv_semid),
552                                                                                 gen_ercd_wait(rercd, p_spcb));
553                 }
554                 SVC(rercd = serial_rea_chr(p_spcb, &c), rercd);
555                 *buf++ = c;
556                 reacnt++;
557                 buffer_empty = (bool_t) rercd;
558
559                 /*
560                  *  エコーバック処理.
561                  */
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));
569                         }
570                 }
571         }
572         if (!buffer_empty) {
573                 SVC(sig_sem(p_spcb->p_spinib->rcv_semid), gen_ercd_sys(p_spcb));
574         }
575         ercd = E_OK;
576
577   error_exit:
578         return(reacnt > 0U ? (ER_UINT) reacnt : ercd);
579 }
580
581 /*
582  *  シリアルポートの制御(サービスコール)
583  */
584 ER
585 serial_ctl_por(ID portid, uint_t ioctl)
586 {
587         SPCB    *p_spcb;
588
589         if (sns_dpn()) {                                /* コンテキストのチェック */
590                 return(E_CTX);
591         }
592         if (!(1 <= portid && portid <= TNUM_PORT)) {
593                 return(E_ID);                           /* ポート番号のチェック */
594         }
595
596         p_spcb = get_spcb(portid);
597         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
598                 return(E_OBJ);
599         }
600         if (p_spcb->errorflag) {                /* エラー状態かのチェック */
601                 return(E_SYS);
602         }
603
604         p_spcb->ioctl = ioctl;
605         return(E_OK);
606 }
607
608 /*
609  *  シリアルポート状態の参照(サービスコール)
610  */
611 ER
612 serial_ref_por(ID portid, T_SERIAL_RPOR *pk_rpor)
613 {
614         SPCB    *p_spcb;
615
616         if (sns_dpn()) {                                /* コンテキストのチェック */
617                 return(E_CTX);
618         }
619         if (!(1 <= portid && portid <= TNUM_PORT)) {
620                 return(E_ID);                           /* ポート番号のチェック */
621         }
622
623         p_spcb = get_spcb(portid);
624         if (!(p_spcb->openflag)) {              /* オープン済みかのチェック */
625                 return(E_OBJ);
626         }
627         if (p_spcb->errorflag) {                /* エラー状態かのチェック */
628                 return(E_SYS);
629         }
630
631         pk_rpor->reacnt = p_spcb->rcv_count;
632         pk_rpor->wricnt = p_spcb->snd_count;
633         return(E_OK);
634 }
635
636 /*
637  *  シリアルポートからの送信可能コールバック
638  */
639 void
640 sio_irdy_snd(intptr_t exinf)
641 {
642         SPCB    *p_spcb;
643
644         p_spcb = (SPCB *) exinf;
645         if (p_spcb->rcv_fc_chr != '\0') {
646                 /*
647                  *  START/STOP を送信する.
648                  */
649                 (void) sio_snd_chr(p_spcb->p_siopcb, p_spcb->rcv_fc_chr);
650                 p_spcb->rcv_fc_chr = '\0';
651         }
652         else if (!(p_spcb->snd_stopped) && p_spcb->snd_count > 0U) {
653                 /*
654                  *  送信バッファ中から文字を取り出して送信する.
655                  */
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;
662                         }
663                 }
664                 p_spcb->snd_count--;
665         }
666         else {
667                 /*
668                  *  送信すべき文字がない場合は,送信可能コールバックを禁止する.
669                  */
670                 sio_dis_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
671         }
672 }
673
674 /*
675  *  シリアルポートからの受信通知コールバック
676  */
677 void
678 sio_irdy_rcv(intptr_t exinf)
679 {
680         SPCB    *p_spcb;
681         char_t  c;
682
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) {
686                 /*
687                  *  送信を一時停止する.送信中の文字はそのまま送信する.
688                  */
689                 p_spcb->snd_stopped = true;
690         }
691         else if (p_spcb->snd_stopped && (c == FC_START
692                                 || (p_spcb->ioctl & IOCTL_FCANY) != 0U)) {
693                 /*
694                  *  送信を再開する.
695                  */
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;
704                                         }
705                                 }
706                                 p_spcb->snd_count--;
707                         }
708                 }
709         }
710         else if ((p_spcb->ioctl & IOCTL_FCSND) != 0U && c == FC_START) {
711                 /*
712                  *  送信に対してフロー制御している場合,START は捨てる.
713                  */
714         }
715         else if (p_spcb->rcv_count == p_spcb->p_spinib->rcv_bufsz) {
716                 /*
717                  *  バッファフルの場合,受信した文字を捨てる.
718                  */
719         }
720         else {
721                 /*
722                  *  受信した文字を受信バッファに入れる.
723                  */
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;
729                         }
730                 }
731                 p_spcb->rcv_count++;
732
733                 /*
734                  *  STOPを送信する.
735                  */
736                 if ((p_spcb->ioctl & IOCTL_FCRCV) != 0U && !(p_spcb->rcv_stopped)
737                                                 && p_spcb->rcv_count
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;
741                         }
742                         p_spcb->rcv_stopped = true;
743                 }
744         }
745 }
746
747 /*
748  *  シリアルインタフェースドライバからの未送信文字の取出し
749  */
750 bool_t
751 serial_get_chr(ID portid, char_t *p_c)
752 {
753         SPCB    *p_spcb;
754
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);
761                                 p_spcb->snd_count--;
762                                 return(true);
763                         }
764                 }
765         }
766         return(false);
767 }