|
|
serial.c説明を見る。00001 /* 00002 * TOPPERS/FDMP Kernel 00003 * Toyohashi Open Platform for Embedded Real-Time Systems/ 00004 * Function Distributed Multiprocessor Kernel 00005 * 00006 * Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory 00007 * Toyohashi Univ. of Technology, JAPAN 00008 * 00009 * 上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 00010 * によって公表されている GNU General Public License の Version 2 に記 00011 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア 00012 * を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下, 00013 * 利用と呼ぶ)することを無償で許諾する. 00014 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 00015 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー 00016 * スコード中に含まれていること. 00017 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 00018 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 00019 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 00020 * の無保証規定を掲載すること. 00021 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 00022 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ 00023 * と. 00024 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 00025 * 作権表示,この利用条件および下記の無保証規定を掲載すること. 00026 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに 00027 * 報告すること. 00028 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 00029 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. 00030 * 00031 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お 00032 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も 00033 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直 00034 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない. 00035 * 00036 * @(#) $Id: serial.c,v 1.1 2005/04/03 13:33:19 honda Exp $ 00037 */ 00038 00043 #include <t_services.h> 00044 #include <serial.h> 00045 #include <hw_serial.h> 00046 #include "kernel_id.h" 00047 00048 /* 00049 * バッファサイズとフロー制御に関連する定数 00050 */ 00051 00052 #define SERIAL_BUFSZ 256 /* ドライバのバッファサイズ */ 00053 00054 #define FC_STOP '\023' /* コントロール-S */ 00055 #define FC_START '\021' /* コントロール-Q */ 00056 00057 #define BUFCNT_STOP (SERIAL_BUFSZ - 64) /* STOPを送る基準文字数 */ 00058 #define BUFCNT_START (SERIAL_BUFSZ - 128) /* STARTを送る基準文字数 */ 00059 00060 /* 00061 * クローズの際に送信を待つ最大時間(msec単位) 00062 */ 00063 #define MAX_FLUSH_WAIT 1000 00064 00065 /* 00066 * シリアルポート初期化ブロック 00067 */ 00068 typedef struct serial_port_initialization_block { 00069 ID rcv_semid; /* 受信バッファ管理用セマフォのID */ 00070 ID snd_semid; /* 送信バッファ管理用セマフォのID */ 00071 } SPINIB; 00072 00073 static const SPINIB spinib_table[TNUM_PORT] = { 00074 { SERIAL_RCV_SEM1, SERIAL_SND_SEM1 } 00075 #if TNUM_PORT >= 2 00076 ,{ SERIAL_RCV_SEM2, SERIAL_SND_SEM2 } 00077 #endif 00078 #if TNUM_PORT >= 3 00079 ,{ SERIAL_RCV_SEM3, SERIAL_SND_SEM3 } 00080 #endif 00081 }; 00082 00083 /* 00084 * シリアルポート管理ブロック 00085 */ 00086 typedef struct serial_port_control_block { 00087 const SPINIB *spinib; /* シリアルポート初期化ブロック */ 00088 SIOPCB *siopcb; /* シリアルI/Oポート管理ブロック */ 00089 BOOL openflag; /* オープン済みフラグ */ 00090 UINT ioctl; /* 動作制御の設定値 */ 00091 00092 UINT rcv_read_ptr; /* 受信バッファ読出しポインタ */ 00093 UINT rcv_write_ptr; /* 受信バッファ書込みポインタ */ 00094 UINT rcv_count; /* 受信バッファ中の文字数 */ 00095 char rcv_fc_chr; /* 送るべき START/STOP */ 00096 BOOL rcv_stopped; /* STOP を送った状態か? */ 00097 00098 UINT snd_read_ptr; /* 送信バッファ読出しポインタ */ 00099 UINT snd_write_ptr; /* 送信バッファ書込みポインタ */ 00100 UINT snd_count; /* 送信バッファ中の文字数 */ 00101 BOOL snd_stopped; /* STOP を受け取った状態か? */ 00102 00103 char rcv_buffer[SERIAL_BUFSZ]; /* 受信バッファ */ 00104 char snd_buffer[SERIAL_BUFSZ]; /* 送信バッファ */ 00105 } SPCB; 00106 00107 static SPCB spcb_table[TNUM_PORT]; 00108 00109 /* 00110 * シリアルポートIDからシリアルポート管理ブロックを取り出すためのマクロ 00111 */ 00112 #define INDEX_PORT(portid) ((UINT)((portid) - 1)) 00113 #define get_spcb(portid) (&(spcb_table[INDEX_PORT(portid)])) 00114 00118 #define INC_PTR(ptr) { if (++ptr == SERIAL_BUFSZ) ptr = 0; } 00119 00120 /* 00121 * シリアルインタフェースドライバの初期化ルーチン 00122 */ 00123 void 00124 serial_initialize(VP_INT exinf) 00125 { 00126 SPCB *spcb; 00127 UINT i; 00128 00129 sio_initialize(); 00130 for (spcb = spcb_table, i = 0; i < TNUM_PORT; spcb++, i++) { 00131 spcb->spinib = &(spinib_table[i]); 00132 spcb->openflag = FALSE; 00133 } 00134 } 00135 00136 /* 00137 * シリアルポートのオープン 00138 */ 00139 ER 00140 serial_opn_por(ID portid) 00141 { 00142 SPCB *spcb; 00143 ER ercd; 00144 00145 if (sns_ctx()) { /* コンテキストのチェック */ 00146 return(E_CTX); 00147 } 00148 if (!(1 <= portid && portid <= TNUM_PORT)) { 00149 return(E_ID); /* ポート番号のチェック */ 00150 } 00151 spcb = get_spcb(portid); 00152 00153 _syscall(loc_cpu()); 00154 if (spcb->openflag) { /* オープン済みかのチェック */ 00155 ercd = E_OBJ; 00156 } 00157 else { 00158 /* 00159 * 変数の初期化 00160 */ 00161 spcb->ioctl = (IOCTL_ECHO | IOCTL_CRLF 00162 | IOCTL_FCSND | IOCTL_FCRCV); 00163 00164 00165 spcb->rcv_read_ptr = spcb->rcv_write_ptr = 0; 00166 spcb->rcv_count = 0; 00167 spcb->rcv_fc_chr = '\0'; 00168 spcb->rcv_stopped = FALSE; 00169 00170 spcb->snd_read_ptr = spcb->snd_write_ptr = 0; 00171 spcb->snd_count = 0; 00172 spcb->snd_stopped = FALSE; 00173 00174 /* 00175 * ハードウェア依存のオープン処理 00176 */ 00177 spcb->siopcb = sio_opn_por(portid, (VP_INT) spcb); 00178 00179 /* 00180 * 受信通知コールバックを許可する. 00181 */ 00182 sio_ena_cbr(spcb->siopcb, SIO_ERDY_RCV); 00183 spcb->openflag = TRUE; 00184 ercd = E_OK; 00185 } 00186 _syscall(unl_cpu()); 00187 return(ercd); 00188 } 00189 00190 /* 00191 * シリアルポートのクローズ 00192 */ 00193 ER 00194 serial_cls_por(ID portid) 00195 { 00196 SPCB *spcb; 00197 ER ercd; 00198 00199 if (sns_ctx()) { /* コンテキストのチェック */ 00200 return(E_CTX); 00201 } 00202 if (!(1 <= portid && portid <= TNUM_PORT)) { 00203 return(E_ID); /* ポート番号のチェック */ 00204 } 00205 spcb = get_spcb(portid); 00206 00207 _syscall(loc_cpu()); 00208 if (!(spcb->openflag)) { /* オープン済みかのチェック */ 00209 ercd = E_OBJ; 00210 } 00211 else { 00212 /* 00213 * ハードウェア依存のクローズ処理 00214 */ 00215 sio_cls_por(spcb->siopcb); 00216 spcb->openflag = FALSE; 00217 ercd = E_OK; 00218 } 00219 _syscall(unl_cpu()); 00220 return(ercd); 00221 } 00222 00223 /* 00224 * シリアルポートへの文字送信 00225 */ 00226 Inline BOOL 00227 serial_snd_chr(SPCB *spcb, char c) 00228 { 00229 if (sio_snd_chr(spcb->siopcb, c)) { 00230 return(TRUE); 00231 } 00232 else { 00233 sio_ena_cbr(spcb->siopcb, SIO_ERDY_SND); 00234 return(FALSE); 00235 } 00236 } 00237 00238 /* 00239 * シリアルポートへの送信 00240 */ 00241 static BOOL 00242 serial_wri_chr(SPCB *spcb, char c) 00243 { 00244 BOOL buffer_full; 00245 00246 /* 00247 * LF の前に CR を送信する. 00248 */ 00249 if (c == '\n' && (spcb->ioctl & IOCTL_CRLF) != 0) { 00250 if (serial_wri_chr(spcb, '\r')) { 00251 _syscall(wai_sem(spcb->spinib->snd_semid)); 00252 } 00253 } 00254 00255 _syscall(loc_cpu()); 00256 if (spcb->snd_count == 0 && !(spcb->snd_stopped) 00257 && serial_snd_chr(spcb, c)) { 00258 /* 00259 * シリアルI/Oデバイスの送信レジスタに文字を入れるこ 00260 * とに成功した場合. 00261 */ 00262 buffer_full = FALSE; 00263 } 00264 else { 00265 /* 00266 * 送信バッファに文字を入れる. 00267 */ 00268 spcb->snd_buffer[spcb->snd_write_ptr] = c; 00269 INC_PTR(spcb->snd_write_ptr); 00270 spcb->snd_count++; 00271 buffer_full = (spcb->snd_count == SERIAL_BUFSZ); 00272 } 00273 _syscall(unl_cpu()); 00274 return(buffer_full); 00275 } 00276 00277 ER_UINT 00278 serial_wri_dat(ID portid, char *buf, UINT len) 00279 { 00280 SPCB *spcb; 00281 BOOL buffer_full; 00282 UINT i; 00283 00284 if (sns_dpn()) { /* コンテキストのチェック */ 00285 return(E_CTX); 00286 } 00287 if (!(1 <= portid && portid <= TNUM_PORT)) { 00288 return(E_ID); /* ポート番号のチェック */ 00289 } 00290 00291 spcb = get_spcb(portid); 00292 if (!(spcb->openflag)) { /* オープン済みかのチェック */ 00293 return(E_OBJ); 00294 } 00295 00296 buffer_full = TRUE; /* ループの1回めは wai_sem する */ 00297 for (i = 0; i < len; i++) { 00298 if (buffer_full) { 00299 _syscall(wai_sem(spcb->spinib->snd_semid)); 00300 } 00301 buffer_full = serial_wri_chr(spcb, *buf++); 00302 } 00303 if (!buffer_full) { 00304 _syscall(sig_sem(spcb->spinib->snd_semid)); 00305 } 00306 return(len); 00307 } 00308 00309 /* 00310 * シリアルポートからの受信 00311 */ 00312 static BOOL 00313 serial_rea_chr(SPCB *spcb, char *c) 00314 { 00315 BOOL buffer_empty; 00316 00317 _syscall(loc_cpu()); 00318 00319 /* 00320 * 受信バッファから文字を取り出す. 00321 */ 00322 *c = spcb->rcv_buffer[spcb->rcv_read_ptr]; 00323 INC_PTR(spcb->rcv_read_ptr); 00324 spcb->rcv_count--; 00325 buffer_empty = (spcb->rcv_count == 0); 00326 00327 /* 00328 * START を送信する. 00329 */ 00330 if (spcb->rcv_stopped && spcb->rcv_count <= BUFCNT_START) { 00331 if (!serial_snd_chr(spcb, FC_START)) { 00332 spcb->rcv_fc_chr = FC_START; 00333 } 00334 spcb->rcv_stopped = FALSE; 00335 } 00336 _syscall(unl_cpu()); 00337 00338 /* 00339 * エコーバック処理. 00340 */ 00341 if ((spcb->ioctl & IOCTL_ECHO) != 0) { 00342 _syscall(wai_sem(spcb->spinib->snd_semid)); 00343 if (!serial_wri_chr(spcb, *c)) { 00344 _syscall(sig_sem(spcb->spinib->snd_semid)); 00345 } 00346 } 00347 return(buffer_empty); 00348 } 00349 00350 ER_UINT 00351 serial_rea_dat(ID portid, char *buf, UINT len) 00352 { 00353 SPCB *spcb; 00354 BOOL buffer_empty; 00355 UINT i; 00356 00357 if (sns_dpn()) { /* コンテキストのチェック */ 00358 return(E_CTX); 00359 } 00360 if (!(1 <= portid && portid <= TNUM_PORT)) { 00361 return(E_ID); /* ポート番号のチェック */ 00362 } 00363 00364 spcb = get_spcb(portid); 00365 if (!(spcb->openflag)) { /* オープン済みかのチェック */ 00366 return(E_OBJ); 00367 } 00368 00369 buffer_empty = TRUE; /* ループの1回めは wai_sem する */ 00370 for (i = 0; i < len; i++) { 00371 if (buffer_empty) { 00372 _syscall(wai_sem(spcb->spinib->rcv_semid)); 00373 } 00374 buffer_empty = serial_rea_chr(spcb, buf++); 00375 } 00376 if (!buffer_empty) { 00377 _syscall(sig_sem(spcb->spinib->rcv_semid)); 00378 } 00379 return(len); 00380 } 00381 00382 /* 00383 * シリアルポートの制御 00384 */ 00385 ER 00386 serial_ctl_por(ID portid, UINT ioctl) 00387 { 00388 SPCB *spcb; 00389 00390 if (sns_ctx()) { /* コンテキストのチェック */ 00391 return(E_CTX); 00392 } 00393 if (!(1 <= portid && portid <= TNUM_PORT)) { 00394 return(E_ID); /* ポート番号のチェック */ 00395 } 00396 00397 spcb = get_spcb(portid); 00398 if (!(spcb->openflag)) { /* オープン済みかのチェック */ 00399 return(E_OBJ); 00400 } 00401 00402 spcb->ioctl = ioctl; 00403 return(E_OK); 00404 } 00405 00406 /* 00407 * シリアルポート状態の参照 00408 */ 00409 ER 00410 serial_ref_por(ID portid, T_SERIAL_RPOR *pk_rpor) 00411 { 00412 SPCB *spcb; 00413 00414 if (sns_ctx()) { /* コンテキストのチェック */ 00415 return(E_CTX); 00416 } 00417 if (!(1 <= portid && portid <= TNUM_PORT)) { 00418 return(E_ID); /* ポート番号のチェック */ 00419 } 00420 00421 spcb = get_spcb(portid); 00422 if (!(spcb->openflag)) { /* オープン済みかのチェック */ 00423 return(E_OBJ); 00424 } 00425 00426 pk_rpor->reacnt = spcb->rcv_count; 00427 pk_rpor->wricnt = spcb->snd_count; 00428 return(E_OK); 00429 } 00430 00431 /* 00432 * シリアルポートからの送信可能コールバック 00433 */ 00434 void 00435 sio_ierdy_snd(VP_INT exinf) 00436 { 00437 SPCB *spcb; 00438 00439 spcb = (SPCB *) exinf; 00440 if (spcb->rcv_fc_chr != '\0') { 00441 /* 00442 * START/STOP を送信する. 00443 */ 00444 (void) sio_snd_chr(spcb->siopcb, spcb->rcv_fc_chr); 00445 spcb->rcv_fc_chr = '\0'; 00446 } 00447 else if (!(spcb->snd_stopped) && spcb->snd_count > 0) { 00448 /* 00449 * 送信バッファ中から文字を取り出して送信する. 00450 */ 00451 (void) sio_snd_chr(spcb->siopcb, 00452 spcb->snd_buffer[spcb->snd_read_ptr]); 00453 INC_PTR(spcb->snd_read_ptr); 00454 if (spcb->snd_count == SERIAL_BUFSZ) { 00455 _syscall(isig_sem(spcb->spinib->snd_semid)); 00456 } 00457 spcb->snd_count--; 00458 } 00459 else { 00460 /* 00461 * 送信すべき文字がない場合は,送信可能コールバックを 00462 * 禁止する. 00463 */ 00464 sio_dis_cbr(spcb->siopcb, SIO_ERDY_SND); 00465 } 00466 } 00467 00468 /* 00469 * シリアルポートからの受信通知コールバック 00470 */ 00471 void 00472 sio_ierdy_rcv(VP_INT exinf) 00473 { 00474 SPCB *spcb; 00475 char c; 00476 00477 spcb = (SPCB *) exinf; 00478 c = (char) sio_rcv_chr(spcb->siopcb); 00479 if ((spcb->ioctl & IOCTL_FCSND) != 0 && c == FC_STOP) { 00480 /* 00481 * 送信を一時停止する.送信中の文字はそのまま送信する. 00482 */ 00483 spcb->snd_stopped = TRUE; 00484 } 00485 else if (spcb->snd_stopped && (c == FC_START 00486 || (spcb->ioctl & IOCTL_FCANY) != 0)) { 00487 /* 00488 * 送信を再開する. 00489 */ 00490 spcb->snd_stopped = FALSE; 00491 if (spcb->snd_count > 0) { 00492 c = spcb->snd_buffer[spcb->snd_read_ptr]; 00493 if (serial_snd_chr(spcb, c)) { 00494 INC_PTR(spcb->snd_read_ptr); 00495 if (spcb->snd_count == SERIAL_BUFSZ) { 00496 _syscall(isig_sem(spcb->spinib 00497 ->snd_semid)); 00498 } 00499 spcb->snd_count--; 00500 } 00501 } 00502 } 00503 else if ((spcb->ioctl & IOCTL_FCSND) != 0 && c == FC_START) { 00504 /* 00505 * 送信に対してフロー制御している場合,START は捨てる. 00506 */ 00507 } 00508 else if (spcb->rcv_count == SERIAL_BUFSZ) { 00509 /* 00510 * バッファフルの場合,受信した文字を捨てる. 00511 */ 00512 } 00513 else { 00514 /* 00515 * 受信した文字を受信バッファに入れる. 00516 */ 00517 spcb->rcv_buffer[spcb->rcv_write_ptr] = c; 00518 INC_PTR(spcb->rcv_write_ptr); 00519 if (spcb->rcv_count == 0) { 00520 _syscall(isig_sem(spcb->spinib->rcv_semid)); 00521 } 00522 spcb->rcv_count++; 00523 00524 /* 00525 * STOP を送信する. 00526 */ 00527 if ((spcb->ioctl & IOCTL_FCRCV) != 0 && !(spcb->rcv_stopped) 00528 && (spcb->rcv_count >= BUFCNT_STOP)) { 00529 if (!serial_snd_chr(spcb, FC_STOP)) { 00530 spcb->rcv_fc_chr = FC_STOP; 00531 } 00532 spcb->rcv_stopped = TRUE; 00533 } 00534 } 00535 } Copyright © 2006 by TAKAGI Nobuhisa. このページは Mon Apr 3 23:49:13 2006 に Doxygen によって生成されました。 |