source: asp_wo_cfg/trunk/syssvc/serial.c@ 49

Last change on this file since 49 was 49, checked in by ertl-hiro, 12 years ago

asp_wo_kernelをコミット。

  • Property svn:keywords set to Id
File size: 20.6 KB
Line 
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-2012 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 49 2012-09-06 04:41:53Z 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 * オブジェクトのID
56 */
57#include "kernel_id.h"
58
59/*
60 * バッファサイズのデフォルト値とバッファの定義
61 */
62#ifndef SERIAL_RCV_BUFSZ1
63#define SERIAL_RCV_BUFSZ1 256 /* ポート1の受信バッファサイズ */
64#endif /* SERIAL_RCV_BUFSZ1 */
65
66#ifndef SERIAL_SND_BUFSZ1
67#define SERIAL_SND_BUFSZ1 256 /* ポート1の送信バッファサイズ */
68#endif /* SERIAL_SND_BUFSZ1 */
69
70static char rcv_buffer1[SERIAL_RCV_BUFSZ1];
71static char snd_buffer1[SERIAL_SND_BUFSZ1];
72
73#if TNUM_PORT >= 2 /* ポート2に関する定義 */
74
75#ifndef SERIAL_RCV_BUFSZ2
76#define SERIAL_RCV_BUFSZ2 256 /* ポート2の受信バッファサイズ */
77#endif /* SERIAL_RCV_BUFSZ2 */
78
79#ifndef SERIAL_SND_BUFSZ2
80#define SERIAL_SND_BUFSZ2 256 /* ポート2の送信バッファサイズ */
81#endif /* SERIAL_SND_BUFSZ2 */
82
83static char rcv_buffer2[SERIAL_RCV_BUFSZ2];
84static char snd_buffer2[SERIAL_SND_BUFSZ2];
85
86#endif /* TNUM_PORT >= 2 */
87
88#if TNUM_PORT >= 3 /* ポート3に関する定義 */
89
90#ifndef SERIAL_RCV_BUFSZ3
91#define SERIAL_RCV_BUFSZ3 256 /* ポート3の受信バッファサイズ */
92#endif /* SERIAL_RCV_BUFSZ3 */
93
94#ifndef SERIAL_SND_BUFSZ3
95#define SERIAL_SND_BUFSZ3 256 /* ポート3の送信バッファサイズ */
96#endif /* SERIAL_SND_BUFSZ3 */
97
98static char rcv_buffer3[SERIAL_RCV_BUFSZ3];
99static char snd_buffer3[SERIAL_SND_BUFSZ3];
100
101#endif /* TNUM_PORT >= 3 */
102
103#if TNUM_PORT >= 4 /* ポート4に関する定義 */
104
105#ifndef SERIAL_RCV_BUFSZ4
106#define SERIAL_RCV_BUFSZ4 256 /* ポート4の受信バッファサイズ */
107#endif /* SERIAL_RCV_BUFSZ4 */
108
109#ifndef SERIAL_SND_BUFSZ4
110#define SERIAL_SND_BUFSZ4 256 /* ポート4の送信バッファサイズ */
111#endif /* SERIAL_SND_BUFSZ4 */
112
113static char rcv_buffer4[SERIAL_RCV_BUFSZ4];
114static char snd_buffer4[SERIAL_SND_BUFSZ4];
115
116#endif /* TNUM_PORT >= 4 */
117
118/*
119 * フロー制御に関連する定数とマクロ
120 */
121#define FC_STOP '\023' /* コントロール-S */
122#define FC_START '\021' /* コントロール-Q */
123
124#define BUFCNT_STOP(bufsz) ((bufsz) * 3 / 4) /* STOPを送る基準文字数 */
125#define BUFCNT_START(bufsz) ((bufsz) / 2) /* STARTを送る基準文字数 */
126
127/*
128 * シリアルポート初期化ブロック
129 */
130typedef struct serial_port_initialization_block {
131 ID rcv_semid; /* 受信バッファ管理用セマフォのID */
132 ID snd_semid; /* 送信バッファ管理用セマフォのID */
133 uint_t rcv_bufsz; /* 受信バッファサイズ */
134 char *rcv_buffer; /* 受信バッファ */
135 uint_t snd_bufsz; /* 送信バッファサイズ */
136 char *snd_buffer; /* 送信バッファ */
137} SPINIB;
138
139static const SPINIB spinib_table[TNUM_PORT] = {
140 { SERIAL_RCV_SEM1, SERIAL_SND_SEM1,
141 SERIAL_RCV_BUFSZ1, rcv_buffer1,
142 SERIAL_SND_BUFSZ1, snd_buffer1 },
143#if TNUM_PORT >= 2
144 { SERIAL_RCV_SEM2, SERIAL_SND_SEM2,
145 SERIAL_RCV_BUFSZ2, rcv_buffer2,
146 SERIAL_SND_BUFSZ2, snd_buffer2 },
147#endif /* TNUM_PORT >= 2 */
148#if TNUM_PORT >= 3
149 { SERIAL_RCV_SEM3, SERIAL_SND_SEM3,
150 SERIAL_RCV_BUFSZ3, rcv_buffer3,
151 SERIAL_SND_BUFSZ3, snd_buffer3 },
152#endif /* TNUM_PORT >= 3 */
153#if TNUM_PORT >= 4
154 { SERIAL_RCV_SEM4, SERIAL_SND_SEM4,
155 SERIAL_RCV_BUFSZ4, rcv_buffer4,
156 SERIAL_SND_BUFSZ4, snd_buffer4 },
157#endif /* TNUM_PORT >= 4 */
158};
159
160/*
161 * シリアルポート管理ブロック
162 */
163typedef struct serial_port_control_block {
164 const SPINIB *p_spinib; /* シリアルポート初期化ブロック */
165 SIOPCB *p_siopcb; /* シリアルI/Oポート管理ブロック */
166 bool_t openflag; /* オープン済みフラグ */
167 bool_t errorflag; /* エラーフラグ */
168 uint_t ioctl; /* 動作制御の設定値 */
169
170 uint_t rcv_read_ptr; /* 受信バッファ読出しポインタ */
171 uint_t rcv_write_ptr; /* 受信バッファ書込みポインタ */
172 uint_t rcv_count; /* 受信バッファ中の文字数 */
173 char rcv_fc_chr; /* 送るべきSTART/STOP */
174 bool_t rcv_stopped; /* STOPを送った状態か? */
175
176 uint_t snd_read_ptr; /* 送信バッファ読出しポインタ */
177 uint_t snd_write_ptr; /* 送信バッファ書込みポインタ */
178 uint_t snd_count; /* 送信バッファ中の文字数 */
179 bool_t snd_stopped; /* STOPを受け取った状態か? */
180} SPCB;
181
182static SPCB spcb_table[TNUM_PORT];
183
184/*
185 * シリアルポートIDからシリアルポート管理ブロックを取り出すためのマクロ
186 */
187#define INDEX_PORT(portid) ((uint_t)((portid) - 1))
188#define get_spcb(portid) (&(spcb_table[INDEX_PORT(portid)]))
189
190/*
191 * ポインタのインクリメント
192 */
193#define INC_PTR(ptr, bufsz) do { \
194 if (++(ptr) == (bufsz)) { \
195 (ptr) = 0; \
196 } \
197} while (false)
198
199/*
200 * サービスコール呼出しマクロ
201 *
202 * サービスコール呼出しを含む式expを評価し,返値がエラー(負の値)の場
203 * 合には,ercにercd_expを評価した値を代入し,error_exitにgotoする.
204 */
205#define SVC(exp, ercd_exp) do { \
206 if ((exp) < 0) { \
207 ercd = (ercd_exp); \
208 goto error_exit; \
209 } \
210} while (false)
211
212/*
213 * E_SYSエラーの生成
214 */
215static ER
216gen_ercd_sys(SPCB *p_spcb)
217{
218 p_spcb->errorflag = true;
219 return(E_SYS);
220}
221
222/*
223 * 待ちに入るサービスコールからのエラーの変換
224 */
225static ER
226gen_ercd_wait(ER rercd, SPCB *p_spcb)
227{
228 switch (MERCD(rercd)) {
229 case E_RLWAI:
230 case E_DLT:
231 return(rercd);
232 default:
233 p_spcb->errorflag = true;
234 return(E_SYS);
235 }
236}
237
238/*
239 * シリアルインタフェースドライバの初期化ルーチン
240 */
241void
242serial_initialize(intptr_t exinf)
243{
244 T_CSEM csem;
245 SPCB *p_spcb;
246 uint_t i;
247 ER ercd;
248
249 /*
250 * シリアルI/Oデバイス(SIO)ドライバの初期化
251 */
252 sio_initialize(0);
253
254 /*
255 * シリアルインタフェースドライバの初期化処理(serial.cfg相当の処理)
256 *
257 * CRE_SEM(SERIAL_RCV_SEM1, { TA_TPRI, 0, 1 });
258 * CRE_SEM(SERIAL_SND_SEM1, { TA_TPRI, 1, 1 });
259 */
260 csem.sematr = TA_TPRI;
261 csem.isemcnt = 0;
262 csem.maxsem = 1;
263 ercd = cre_sem(SERIAL_RCV_SEM1, &csem);
264 assert(ercd == E_OK);
265
266 csem.sematr = TA_TPRI;
267 csem.isemcnt = 1;
268 csem.maxsem = 1;
269 ercd = cre_sem(SERIAL_SND_SEM1, &csem);
270 assert(ercd == E_OK);
271
272#if TNUM_PORT >= 2 /* ポート2に関する定義 */
273 /*
274 * CRE_SEM(SERIAL_RCV_SEM2, { TA_TPRI, 0, 1 });
275 * CRE_SEM(SERIAL_SND_SEM2, { TA_TPRI, 1, 1 });
276 */
277 csem.sematr = TA_TPRI;
278 csem.isemcnt = 0;
279 csem.maxsem = 1;
280 ercd = cre_sem(SERIAL_RCV_SEM2, &csem);
281 assert(ercd == E_OK);
282
283 csem.sematr = TA_TPRI;
284 csem.isemcnt = 1;
285 csem.maxsem = 1;
286 ercd = acre_sem(SERIAL_SND_SEM2, &csem);
287 assert(ercd == E_OK);
288#endif /* TNUM_PORT >= 2 */
289
290#if TNUM_PORT >= 3 /* ポート3に関する定義 */
291 /*
292 * CRE_SEM(SERIAL_RCV_SEM3, { TA_TPRI, 0, 1 });
293 * CRE_SEM(SERIAL_SND_SEM3, { TA_TPRI, 1, 1 });
294 */
295 csem.sematr = TA_TPRI;
296 csem.isemcnt = 0;
297 csem.maxsem = 1;
298 ercd = cre_sem(SERIAL_RCV_SEM3, &csem);
299 assert(ercd == E_OK);
300
301 csem.sematr = TA_TPRI;
302 csem.isemcnt = 1;
303 csem.maxsem = 1;
304 ercd = acre_sem(SERIAL_SND_SEM3, &csem);
305 assert(ercd == E_OK);
306#endif /* TNUM_PORT >= 3 */
307
308#if TNUM_PORT >= 4 /* ポート4に関する定義 */
309 /*
310 * CRE_SEM(SERIAL_RCV_SEM4, { TA_TPRI, 0, 1 });
311 * CRE_SEM(SERIAL_SND_SEM4, { TA_TPRI, 1, 1 });
312 */
313 csem.sematr = TA_TPRI;
314 csem.isemcnt = 0;
315 csem.maxsem = 1;
316 ercd = cre_sem(SERIAL_RCV_SEM4, &csem);
317 assert(ercd == E_OK);
318
319 csem.sematr = TA_TPRI;
320 csem.isemcnt = 1;
321 csem.maxsem = 1;
322 ercd = acre_sem(SERIAL_SND_SEM4, &csem);
323 assert(ercd == E_OK);
324#endif /* TNUM_PORT >= 4 */
325
326 /*
327 * シリアルポート管理ブロックの初期化(元のserial_initializeの処理)
328 *
329 * ATT_INI({ TA_NULL, 0, serial_initialize });
330 */
331 for (i = 0; i < TNUM_PORT; i++) {
332 p_spcb = &(spcb_table[i]);
333 p_spcb->p_spinib = &(spinib_table[i]);
334 p_spcb->openflag = false;
335 }
336}
337
338/*
339 * シリアルポートのオープン(サービスコール)
340 */
341ER
342serial_opn_por(ID portid)
343{
344 SPCB *p_spcb;
345 ER ercd;
346
347 if (sns_dpn()) { /* コンテキストのチェック */
348 return(E_CTX);
349 }
350 if (!(1 <= portid && portid <= TNUM_PORT)) {
351 return(E_ID); /* ポート番号のチェック */
352 }
353 p_spcb = get_spcb(portid);
354
355 SVC(dis_dsp(), gen_ercd_sys(p_spcb));
356 if (p_spcb->openflag) { /* オープン済みかのチェック */
357 ercd = E_OBJ;
358 }
359 else {
360 /*
361 * 変数の初期化
362 */
363 p_spcb->ioctl = (IOCTL_ECHO | IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV);
364
365 p_spcb->rcv_read_ptr = 0U;
366 p_spcb->rcv_write_ptr = 0U;
367 p_spcb->rcv_count = 0U;
368 p_spcb->rcv_fc_chr = '\0';
369 p_spcb->rcv_stopped = false;
370
371 p_spcb->snd_read_ptr = 0U;
372 p_spcb->snd_write_ptr = 0U;
373 p_spcb->snd_count = 0U;
374 p_spcb->snd_stopped = false;
375
376 /*
377 * これ以降,割込みを禁止する.
378 */
379 if (loc_cpu() < 0) {
380 ercd = E_SYS;
381 goto error_exit_enadsp;
382 }
383
384 /*
385 * ハードウェア依存のオープン処理
386 */
387 p_spcb->p_siopcb = sio_opn_por(portid, (intptr_t) p_spcb);
388
389 /*
390 * 受信通知コールバックを許可する.
391 */
392 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_RCV);
393 p_spcb->openflag = true;
394 p_spcb->errorflag = false;
395
396 if (unl_cpu() < 0) {
397 p_spcb->errorflag = true;
398 ercd = E_SYS;
399 goto error_exit_enadsp;
400 }
401 ercd = E_OK;
402 }
403
404 error_exit_enadsp:
405 SVC(ena_dsp(), gen_ercd_sys(p_spcb));
406
407 error_exit:
408 return(ercd);
409}
410
411/*
412 * シリアルポートのクローズ(サービスコール)
413 */
414ER
415serial_cls_por(ID portid)
416{
417 SPCB *p_spcb;
418 ER ercd;
419 bool_t eflag = false;
420
421 if (sns_dpn()) { /* コンテキストのチェック */
422 return(E_CTX);
423 }
424 if (!(1 <= portid && portid <= TNUM_PORT)) {
425 return(E_ID); /* ポート番号のチェック */
426 }
427 p_spcb = get_spcb(portid);
428
429 SVC(dis_dsp(), gen_ercd_sys(p_spcb));
430 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
431 ercd = E_OBJ;
432 }
433 else {
434 /*
435 * ハードウェア依存のクローズ処理
436 */
437 if (loc_cpu() < 0) {
438 eflag = true;
439 }
440 sio_cls_por(p_spcb->p_siopcb);
441 p_spcb->openflag = false;
442 if (unl_cpu() < 0) {
443 eflag = true;
444 }
445
446 /*
447 * セマフォの初期化
448 */
449 if (ini_sem(p_spcb->p_spinib->snd_semid) < 0) {
450 eflag = true;
451 }
452 if (ini_sem(p_spcb->p_spinib->rcv_semid) < 0) {
453 eflag = true;
454 }
455
456 /*
457 * エラーコードの設定
458 */
459 if (eflag) {
460 ercd = gen_ercd_sys(p_spcb);
461 }
462 else {
463 ercd = E_OK;
464 }
465 }
466 SVC(ena_dsp(), gen_ercd_sys(p_spcb));
467
468 error_exit:
469 return(ercd);
470}
471
472/*
473 * シリアルポートへの文字送信
474 *
475 * p_spcbで指定されるシリアルI/Oポートに対して,文字cを送信する.文字
476 * を送信レジスタにいれた場合にはtrueを返す.そうでない場合には,送信
477 * レジスタが空いたことを通知するコールバック関数を許可し,falseを返す.
478 * この関数は,CPUロック状態で呼び出される.
479 */
480Inline bool_t
481serial_snd_chr(SPCB *p_spcb, char c)
482{
483 if (sio_snd_chr(p_spcb->p_siopcb, c)) {
484 return(true);
485 }
486 else {
487 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
488 return(false);
489 }
490}
491
492/*
493 * シリアルポートへの1文字送信
494 */
495static ER_BOOL
496serial_wri_chr(SPCB *p_spcb, char c)
497{
498 bool_t buffer_full;
499 ER ercd, rercd;
500
501 /*
502 * LFの前にCRを送信する.
503 */
504 if (c == '\n' && (p_spcb->ioctl & IOCTL_CRLF) != 0U) {
505 /*
506 * 以下のコードは再帰呼出しになっているが,引数cが'\n'の場合に
507 * 引数cを'\r'として呼び出すことから,この再帰呼出しは2回目の
508 * 呼び出しで必ず止まる.
509 */
510 SVC(rercd = serial_wri_chr(p_spcb, '\r'), rercd);
511 if ((bool_t) rercd) {
512 SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
513 gen_ercd_wait(rercd, p_spcb));
514 }
515 }
516
517 SVC(loc_cpu(), gen_ercd_sys(p_spcb));
518 if (p_spcb->snd_count == 0U && !(p_spcb->snd_stopped)
519 && serial_snd_chr(p_spcb, c)) {
520 /*
521 * シリアルI/Oデバイスの送信レジスタに文字を入れることに成功し
522 * た場合.
523 */
524 buffer_full = false;
525 }
526 else {
527 /*
528 * 送信バッファに文字を入れる.
529 */
530 p_spcb->p_spinib->snd_buffer[p_spcb->snd_write_ptr] = c;
531 INC_PTR(p_spcb->snd_write_ptr, p_spcb->p_spinib->snd_bufsz);
532 p_spcb->snd_count++;
533 buffer_full = (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz);
534 }
535
536 SVC(unl_cpu(), gen_ercd_sys(p_spcb));
537 ercd = (ER_BOOL) buffer_full;
538
539 error_exit:
540 return(ercd);
541}
542
543/*
544 * シリアルポートへの文字列送信(サービスコール)
545 */
546ER_UINT
547serial_wri_dat(ID portid, const char *buf, uint_t len)
548{
549 SPCB *p_spcb;
550 bool_t buffer_full;
551 uint_t wricnt = 0U;
552 ER ercd, rercd;
553
554 if (sns_dpn()) { /* コンテキストのチェック */
555 return(E_CTX);
556 }
557 if (!(1 <= portid && portid <= TNUM_PORT)) {
558 return(E_ID); /* ポート番号のチェック */
559 }
560
561 p_spcb = get_spcb(portid);
562 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
563 return(E_OBJ);
564 }
565 if (p_spcb->errorflag) { /* エラー状態かのチェック */
566 return(E_SYS);
567 }
568
569 buffer_full = true; /* ループの1回めはwai_semする */
570 while (wricnt < len) {
571 if (buffer_full) {
572 SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
573 gen_ercd_wait(rercd, p_spcb));
574 }
575 SVC(rercd = serial_wri_chr(p_spcb, *buf++), rercd);
576 wricnt++;
577 buffer_full = (bool_t) rercd;
578 }
579 if (!buffer_full) {
580 SVC(sig_sem(p_spcb->p_spinib->snd_semid), gen_ercd_sys(p_spcb));
581 }
582 ercd = E_OK;
583
584 error_exit:
585 return(wricnt > 0U ? (ER_UINT) wricnt : ercd);
586}
587
588/*
589 * シリアルポートからの1文字受信
590 */
591static bool_t
592serial_rea_chr(SPCB *p_spcb, char *p_c)
593{
594 bool_t buffer_empty;
595 ER ercd;
596
597 SVC(loc_cpu(), gen_ercd_sys(p_spcb));
598
599 /*
600 * 受信バッファから文字を取り出す.
601 */
602 *p_c = p_spcb->p_spinib->rcv_buffer[p_spcb->rcv_read_ptr];
603 INC_PTR(p_spcb->rcv_read_ptr, p_spcb->p_spinib->rcv_bufsz);
604 p_spcb->rcv_count--;
605 buffer_empty = (p_spcb->rcv_count == 0U);
606
607 /*
608 * STARTを送信する.
609 */
610 if (p_spcb->rcv_stopped && p_spcb->rcv_count
611 <= BUFCNT_START(p_spcb->p_spinib->rcv_bufsz)) {
612 if (!serial_snd_chr(p_spcb, FC_START)) {
613 p_spcb->rcv_fc_chr = FC_START;
614 }
615 p_spcb->rcv_stopped = false;
616 }
617
618 SVC(unl_cpu(), gen_ercd_sys(p_spcb));
619 ercd = (ER_BOOL) buffer_empty;
620
621 error_exit:
622 return(ercd);
623}
624
625/*
626 * シリアルポートからの文字列受信(サービスコール)
627 */
628ER_UINT
629serial_rea_dat(ID portid, char *buf, uint_t len)
630{
631 SPCB *p_spcb;
632 bool_t buffer_empty;
633 uint_t reacnt = 0U;
634 char c = '\0'; /* コンパイラの警告を抑止するために初期化する */
635 ER ercd, rercd;
636
637 if (sns_dpn()) { /* コンテキストのチェック */
638 return(E_CTX);
639 }
640 if (!(1 <= portid && portid <= TNUM_PORT)) {
641 return(E_ID); /* ポート番号のチェック */
642 }
643
644 p_spcb = get_spcb(portid);
645 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
646 return(E_OBJ);
647 }
648 if (p_spcb->errorflag) { /* エラー状態かのチェック */
649 return(E_SYS);
650 }
651
652 buffer_empty = true; /* ループの1回めはwai_semする */
653 while (reacnt < len) {
654 if (buffer_empty) {
655 SVC(rercd = wai_sem(p_spcb->p_spinib->rcv_semid),
656 gen_ercd_wait(rercd, p_spcb));
657 }
658 SVC(rercd = serial_rea_chr(p_spcb, &c), rercd);
659 *buf++ = c;
660 reacnt++;
661 buffer_empty = (bool_t) rercd;
662
663 /*
664 * エコーバック処理.
665 */
666 if ((p_spcb->ioctl & IOCTL_ECHO) != 0U) {
667 SVC(rercd = wai_sem(p_spcb->p_spinib->snd_semid),
668 gen_ercd_wait(rercd, p_spcb));
669 SVC(rercd = serial_wri_chr(p_spcb, c), rercd);
670 if (!((bool_t) rercd)) {
671 SVC(sig_sem(p_spcb->p_spinib->snd_semid),
672 gen_ercd_sys(p_spcb));
673 }
674 }
675 }
676 if (!buffer_empty) {
677 SVC(sig_sem(p_spcb->p_spinib->rcv_semid), gen_ercd_sys(p_spcb));
678 }
679 ercd = E_OK;
680
681 error_exit:
682 return(reacnt > 0U ? (ER_UINT) reacnt : ercd);
683}
684
685/*
686 * シリアルポートの制御(サービスコール)
687 */
688ER
689serial_ctl_por(ID portid, uint_t ioctl)
690{
691 SPCB *p_spcb;
692
693 if (sns_dpn()) { /* コンテキストのチェック */
694 return(E_CTX);
695 }
696 if (!(1 <= portid && portid <= TNUM_PORT)) {
697 return(E_ID); /* ポート番号のチェック */
698 }
699
700 p_spcb = get_spcb(portid);
701 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
702 return(E_OBJ);
703 }
704 if (p_spcb->errorflag) { /* エラー状態かのチェック */
705 return(E_SYS);
706 }
707
708 p_spcb->ioctl = ioctl;
709 return(E_OK);
710}
711
712/*
713 * シリアルポート状態の参照(サービスコール)
714 */
715ER
716serial_ref_por(ID portid, T_SERIAL_RPOR *pk_rpor)
717{
718 SPCB *p_spcb;
719
720 if (sns_dpn()) { /* コンテキストのチェック */
721 return(E_CTX);
722 }
723 if (!(1 <= portid && portid <= TNUM_PORT)) {
724 return(E_ID); /* ポート番号のチェック */
725 }
726
727 p_spcb = get_spcb(portid);
728 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
729 return(E_OBJ);
730 }
731 if (p_spcb->errorflag) { /* エラー状態かのチェック */
732 return(E_SYS);
733 }
734
735 pk_rpor->reacnt = p_spcb->rcv_count;
736 pk_rpor->wricnt = p_spcb->snd_count;
737 return(E_OK);
738}
739
740/*
741 * シリアルポートからの送信可能コールバック
742 */
743void
744sio_irdy_snd(intptr_t exinf)
745{
746 SPCB *p_spcb;
747
748 p_spcb = (SPCB *) exinf;
749 if (p_spcb->rcv_fc_chr != '\0') {
750 /*
751 * START/STOP を送信する.
752 */
753 (void) sio_snd_chr(p_spcb->p_siopcb, p_spcb->rcv_fc_chr);
754 p_spcb->rcv_fc_chr = '\0';
755 }
756 else if (!(p_spcb->snd_stopped) && p_spcb->snd_count > 0U) {
757 /*
758 * 送信バッファ中から文字を取り出して送信する.
759 */
760 (void) sio_snd_chr(p_spcb->p_siopcb,
761 p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr]);
762 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
763 if (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz) {
764 if (isig_sem(p_spcb->p_spinib->snd_semid) < 0) {
765 p_spcb->errorflag = true;
766 }
767 }
768 p_spcb->snd_count--;
769 }
770 else {
771 /*
772 * 送信すべき文字がない場合は,送信可能コールバックを禁止する.
773 */
774 sio_dis_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
775 }
776}
777
778/*
779 * シリアルポートからの受信通知コールバック
780 */
781void
782sio_irdy_rcv(intptr_t exinf)
783{
784 SPCB *p_spcb;
785 char c;
786
787 p_spcb = (SPCB *) exinf;
788 c = (char) sio_rcv_chr(p_spcb->p_siopcb);
789 if ((p_spcb->ioctl & IOCTL_FCSND) != 0U && c == FC_STOP) {
790 /*
791 * 送信を一時停止する.送信中の文字はそのまま送信する.
792 */
793 p_spcb->snd_stopped = true;
794 }
795 else if (p_spcb->snd_stopped && (c == FC_START
796 || (p_spcb->ioctl & IOCTL_FCANY) != 0U)) {
797 /*
798 * 送信を再開する.
799 */
800 p_spcb->snd_stopped = false;
801 if (p_spcb->snd_count > 0U) {
802 c = p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr];
803 if (serial_snd_chr(p_spcb, c)) {
804 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
805 if (p_spcb->snd_count == p_spcb->p_spinib->snd_bufsz) {
806 if (isig_sem(p_spcb->p_spinib->snd_semid) < 0) {
807 p_spcb->errorflag = true;
808 }
809 }
810 p_spcb->snd_count--;
811 }
812 }
813 }
814 else if ((p_spcb->ioctl & IOCTL_FCSND) != 0U && c == FC_START) {
815 /*
816 * 送信に対してフロー制御している場合,START は捨てる.
817 */
818 }
819 else if (p_spcb->rcv_count == p_spcb->p_spinib->rcv_bufsz) {
820 /*
821 * バッファフルの場合,受信した文字を捨てる.
822 */
823 }
824 else {
825 /*
826 * 受信した文字を受信バッファに入れる.
827 */
828 p_spcb->p_spinib->rcv_buffer[p_spcb->rcv_write_ptr] = c;
829 INC_PTR(p_spcb->rcv_write_ptr, p_spcb->p_spinib->rcv_bufsz);
830 if (p_spcb->rcv_count == 0U) {
831 if (isig_sem(p_spcb->p_spinib->rcv_semid) < 0) {
832 p_spcb->errorflag = true;
833 }
834 }
835 p_spcb->rcv_count++;
836
837 /*
838 * STOPを送信する.
839 */
840 if ((p_spcb->ioctl & IOCTL_FCRCV) != 0U && !(p_spcb->rcv_stopped)
841 && p_spcb->rcv_count
842 >= BUFCNT_STOP(p_spcb->p_spinib->rcv_bufsz)) {
843 if (!serial_snd_chr(p_spcb, FC_STOP)) {
844 p_spcb->rcv_fc_chr = FC_STOP;
845 }
846 p_spcb->rcv_stopped = true;
847 }
848 }
849}
850
851/*
852 * シリアルインタフェースドライバからの未送信文字の取出し
853 */
854bool_t
855serial_get_chr(ID portid, char *p_c)
856{
857 SPCB *p_spcb;
858
859 if (1 <= portid && portid <= TNUM_PORT) { /* ポート番号のチェック */
860 p_spcb = get_spcb(portid);
861 if (p_spcb->openflag) { /* オープン済みかのチェック */
862 if (p_spcb->snd_count > 0U) {
863 *p_c = p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr];
864 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
865 p_spcb->snd_count--;
866 return(true);
867 }
868 }
869 }
870 return(false);
871}
872
873/*
874 * シリアルインタフェースドライバの終了処理ルーチン
875 */
876void
877serial_terminate(intptr_t exinf)
878{
879 sio_terminate(0);
880}
Note: See TracBrowser for help on using the repository browser.