📄 linux_serial.c
字号:
/*
* TOPPERS/JSP Kernel
* Toyohashi Open Platform for Embedded Real-Time Systems/
* Just Standard Profile Kernel
*
* Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
* Toyohashi Univ. of Technology, JAPAN
*
* 忋婰挊嶌尃幰偼丆埲壓偺 (1)乣(4) 偺忦審偐丆Free Software Foundation
* 偵傛偭偰岞昞偝傟偰偄傞 GNU General Public License 偺 Version 2 偵婰
* 弎偝傟偰偄傞忦審傪枮偨偡応崌偵尷傝丆杮僜僼僩僂僃傾乮杮僜僼僩僂僃傾
* 傪夵曄偟偨傕偺傪娷傓丏埲壓摨偠乯傪巊梡丒暋惢丒夵曄丒嵞攝晍乮埲壓丆
* 棙梡偲屇傇乯偡傞偙偲傪柍彏偱嫋戻偡傞丏
* (1) 杮僜僼僩僂僃傾傪僜乕僗僐乕僪偺宍偱棙梡偡傞応崌偵偼丆忋婰偺挊嶌
* 尃昞帵丆偙偺棙梡忦審偍傛傃壓婰偺柍曐徹婯掕偑丆偦偺傑傑偺宍偱僜乕
* 僗僐乕僪拞偵娷傑傟偰偄傞偙偲丏
* (2) 杮僜僼僩僂僃傾傪丆儔僀僽儔儕宍幃側偳丆懠偺僜僼僩僂僃傾奐敪偵巊
* 梡偱偒傞宍偱嵞攝晍偡傞応崌偵偼丆嵞攝晍偵敽偆僪僉儏儊儞僩乮棙梡
* 幰儅僯儏傾儖側偳乯偵丆忋婰偺挊嶌尃昞帵丆偙偺棙梡忦審偍傛傃壓婰
* 偺柍曐徹婯掕傪宖嵹偡傞偙偲丏
* (3) 杮僜僼僩僂僃傾傪丆婡婍偵慻傒崬傓側偳丆懠偺僜僼僩僂僃傾奐敪偵巊
* 梡偱偒側偄宍偱嵞攝晍偡傞応崌偵偼丆師偺偄偢傟偐偺忦審傪枮偨偡偙
* 偲丏
* (a) 嵞攝晍偵敽偆僪僉儏儊儞僩乮棙梡幰儅僯儏傾儖側偳乯偵丆忋婰偺挊
* 嶌尃昞帵丆偙偺棙梡忦審偍傛傃壓婰偺柍曐徹婯掕傪宖嵹偡傞偙偲丏
* (b) 嵞攝晍偺宍懺傪丆暿偵掕傔傞曽朄偵傛偭偰丆TOPPERS僾儘僕僃僋僩偵
* 曬崘偡傞偙偲丏
* (4) 杮僜僼僩僂僃傾偺棙梡偵傛傝捈愙揑傑偨偼娫愙揑偵惗偠傞偄偐側傞懝
* 奞偐傜傕丆忋婰挊嶌尃幰偍傛傃TOPPERS僾儘僕僃僋僩傪柶愑偡傞偙偲丏
*
* 杮僜僼僩僂僃傾偼丆柍曐徹偱採嫙偝傟偰偄傞傕偺偱偁傞丏忋婰挊嶌尃幰偍
* 傛傃TOPPERS僾儘僕僃僋僩偼丆杮僜僼僩僂僃傾偵娭偟偰丆偦偺揔梡壜擻惈傕
* 娷傔偰丆偄偐側傞曐徹傕峴傢側偄丏傑偨丆杮僜僼僩僂僃傾偺棙梡偵傛傝捈
* 愙揑傑偨偼娫愙揑偵惗偠偨偄偐側傞懝奞偵娭偟偰傕丆偦偺愑擟傪晧傢側偄丏
*
* @(#) $Id: linux_serial.c,v 1.10 2003/07/16 09:09:53 honda Exp $
*/
#define _LINX_SERIAL_
#include <t_services.h>
#include <signal.h>
#include <termios.h>
#include <fcntl.h>
#include <errno.h>
#undef __USE_MISC
#include <unistd.h>
#include <linux_sigio.h>
#include "kernel_id.h"
#include "sys_config.h"
#include "cpu_config.h"
/*
* 僔儕傾儖億乕僩偺掅儗儀儖掕媊
*/
typedef struct hardware_serial_port_descripter {
char *path; /* UNIX 忋偱偺僼傽僀儖柤 */
int fd; /* 僼傽僀儖僨傿僗僋儕僾僞 */
struct termios current_term; /* 抂枛惂屼忣曬 */
struct termios saved_term;
} HWPORT;
#define NUM_PORT 1
#define RAWPORT1 { 0 }
/*
* UNIX 儗儀儖偺億乕僩弶婜壔/僔儍僢僩僟僂儞張棟
*
* 尰嵼偺幚憰偱偼丆抂枛傪巊偆働乕僗偟偐峫偊偰偄側偄丏杮棃偼丆open 偟
* 偨偺偑抂枛偐偳偆偐偱張棟傪曄偊傞傋偒丏
*/
Inline void
hw_port_initialize(HWPORT *p)
{
if (p->path) {
p->fd = open(p->path, O_RDWR|O_NDELAY);
}
else {
p->fd = 0; /* 昗弨擖弌椡傪巊偆 */
}
fcntl(p->fd, F_SETOWN, getpid());
fcntl(p->fd, F_SETFL, FASYNC|FNDELAY);
tcgetattr(p->fd, &(p->saved_term));
p->current_term = p->saved_term;
p->current_term.c_lflag &= ~(ECHO);
p->current_term.c_lflag &= ~(ICANON);
p->current_term.c_cc[VMIN] = 1;
p->current_term.c_cc[VTIME] = 0;
tcsetattr(p->fd, TCSAFLUSH, &(p->current_term));
}
Inline void
hw_port_terminate(HWPORT *p)
{
tcsetattr(p->fd, TCSAFLUSH, &(p->saved_term));
fcntl(p->fd, F_SETFL, 0);
if (p->path) {
close(p->fd);
}
}
/*
* 僔儕傾儖僀儞僞僼僃乕僗僪儔僀僶梡偺 SIGIO 捠抦僀儀儞僩僽儘僢僋
*/
static SIGIOEB serial_sigioeb;
/*
* 僔儕傾儖億乕僩娗棟僽儘僢僋偺掕媊
*/
typedef struct ioctl_descripter {
int echo;
int input;
int newline;
int flowc;
} IOCTL;
#define SERIAL_BUFSZ 256 /* 僔儕傾儖僀儞僞僼僃乕僗梡僶僢僼傽偺僒僀僘 */
#define inc(x) (((x)+1 < SERIAL_BUFSZ) ? (x)+1 : 0)
#define INC(x) ((x) = inc(x))
typedef struct serial_port_control_block {
BOOL init_flag; /* 弶婜壔嵪偐丠 */
HWPORT hwport; /* 僴乕僪僂僃傾埶懚忣曬 */
ID in_semid; /* 庴怣僶僢僼傽娗棟梡僙儅僼僅偺 ID */
ID out_semid; /* 憲怣僶僢僼傽娗棟梡僙儅僼僅偺 ID */
int in_read_ptr; /* 庴怣僶僢僼傽撉傒弌偟億僀儞僞 */
int in_write_ptr; /* 庴怣僶僢僼傽彂偒崬傒億僀儞僞 */
int out_read_ptr; /* 憲怣僶僢僼傽撉傒弌偟億僀儞僞 */
int out_write_ptr; /* 憲怣僶僢僼傽彂偒崬傒億僀儞僞 */
UINT ioctl; /* ioctl 偵傛傞愝掕撪梕 */
BOOL send_enabled; /* 憲怣傪僀僱乕僽儖偟偰偁傞偐丠 */
BOOL ixon_stopped; /* STOP 傪庴偗庢偭偨忬懺偐丠 */
BOOL ixoff_stopped; /* 憡庤偵 STOP 傪憲偭偨忬懺偐丠 */
char ixoff_send; /* 憡庤偵 START/STOP 傪憲傞偐丠 */
char in_buffer[SERIAL_BUFSZ]; /* 庴怣僶僢僼傽僄儕傾 */
char out_buffer[SERIAL_BUFSZ]; /* 庴怣僶僢僼傽僄儕傾 */
} SPCB;
#define IN_BUFFER_EMPTY(spcb) \
((spcb)->in_read_ptr == (spcb)->in_write_ptr)
#define IN_BUFFER_FULL(spcb) \
((spcb)->in_read_ptr == inc((spcb)->in_write_ptr))
#define OUT_BUFFER_FULL(spcb) \
((spcb)->out_read_ptr == inc((spcb)->out_write_ptr))
/*
* 儌僕儏乕儖撪偱巊偆娭悢
*/
static void sigint_handler();
static BOOL serial_getc(SPCB *spcb, char *c);
static BOOL serial_putc(SPCB *spcb, char c);
/*
* 僔儕傾儖億乕僩娗棟僽儘僢僋偺掕媊偲弶婜壔
*/
static SPCB spcb_table[NUM_PORT] = {
{0, RAWPORT1, SEM_SERIAL1_IN, SEM_SERIAL1_OUT }
};
#define get_spcb(portid) (&(spcb_table[(portid)-1]))
#define get_spcb_def(portid) get_spcb((portid) ? (portid) : CONSOLE_PORTID)
/*
* 億乕僩偺弶婜壔
*/
int
serial_opn_por(ID portid)
{
SPCB *spcb;
ER ercd = E_OK;;
if (!(1 <= portid && portid <= NUM_PORT)) {
return(E_PAR);
}
spcb = get_spcb(portid);
/*
* 暋悢偺僞僗僋偑摨帪偵 serial_open 傪屇傇忬嫷偵偼懳墳偟偰偄
* 側偄丏
*/
if (spcb->init_flag) { /* 弶婜壔嵪偐偺僠僃僢僋 */
return(E_OK);
}
/*
* 曄悢偺弶婜壔
*/
spcb->in_read_ptr = spcb->in_write_ptr = 0;
spcb->out_read_ptr = spcb->out_write_ptr = 0;
spcb->ixon_stopped = spcb->ixoff_stopped = FALSE;
spcb->ixoff_send = 0;
/*
* 僴乕僪僂僃傾埶懚偺弶婜壔
*/
hw_port_initialize(&(spcb->hwport));
/*
* 僾儘僙僗傪廔椆偝偣傞僔僌僫儖傪曔傑偊傞
* sigaction()偱彂偒捈偟偨曽偑偄偄偺偐?
*/
signal(SIGHUP, sigint_handler);
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler);
spcb->init_flag = TRUE;
spcb->send_enabled = FALSE;
return(ercd);
}
/*
* 億乕僩偺僔儍僢僩僟僂儞
*/
ER
serial_cls_por(ID portid)
{
SPCB *spcb;
if (!(1 <= portid && portid <= NUM_PORT)) {
return(E_PAR); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb(portid);
if (!(spcb->init_flag)) { /* 弶婜壔嵪偐偺僠僃僢僋 */
return(E_OBJ);
}
/*
* 僴乕僪僂僃傾埶懚偺僔儍僢僩僟僂儞張棟
*/
syscall(loc_cpu());
hw_port_terminate(&(spcb->hwport));
syscall(unl_cpu());
spcb->init_flag = FALSE;
return(E_OK);
}
/*
* 僾儘僙僗傪廔椆偝偣傞僔僌僫儖偵懳偡傞僴儞僪儔
*/
void
sigint_handler()
{
SPCB *spcb;
int i;
for (i = 1; i <= NUM_PORT; i++) {
spcb = get_spcb(i);
if (spcb->init_flag) {
hw_port_terminate(&(spcb->hwport));
}
}
exit(0);
}
/*
* 僼儘乕僐儞僩儘乕儖娭學偺掕媊
*/
#define STOP '\023' /* Control-S */
#define START '\021' /* Control-Q */
#define IXOFF_STOP 64 /* buffer area size to send STOP */
#define IXOFF_START 128 /* buffer area size to send START */
#define in_buf_area(p) \
((spcb->in_read_ptr >= spcb->in_write_ptr) ? \
(spcb->in_read_ptr - spcb->in_write_ptr) : \
(spcb->in_read_ptr + SERIAL_BUFSZ - spcb->in_write_ptr))
/*
* 儐乕僥傿儕僥傿儖乕僠儞
*/
Inline BOOL
read_char(SPCB *spcb, char *c)
{
int n;
if ((n = read(spcb->hwport.fd, c, 1)) == 1) {
return(1);
}
assert(n < 0 && errno == EWOULDBLOCK);
return(0);
}
Inline BOOL
write_char(SPCB *spcb, char c)
{
int n;
if ((n = write(spcb->hwport.fd, &c, 1)) == 1) {
return(1);
}
assert(n < 0 && errno == EWOULDBLOCK);
return(0);
}
/*
* 僔儕傾儖億乕僩偐傜偺庴怣
*/
static BOOL
serial_getc(SPCB *spcb, char *c)
{
BOOL buffer_empty;
syscall(loc_cpu());
*c = spcb->in_buffer[spcb->in_read_ptr];
if (inc(spcb->in_write_ptr) == spcb->in_read_ptr) {
/*
* 僶僢僼傽僼儖忬懺偑夝彍偝傟偨傜丄妱傝崬傒偑擖偭偨偺偲
* 摨偠怳傞晳偄傪偝偣傞丅
*/
kill(getpid(), SIGIO);
}
INC(spcb->in_read_ptr);
if (spcb->ixoff_stopped && (in_buf_area(spcb) > IXOFF_START)) {
if (!write_char(spcb, START)) {
spcb->ixoff_send = START;
}
spcb->ixoff_stopped = FALSE;
}
buffer_empty = IN_BUFFER_EMPTY(spcb);
syscall(unl_cpu());
return(buffer_empty);
}
ER_UINT
serial_rea_dat(ID portid, char *buf, UINT len)
{
SPCB *spcb;
BOOL buffer_empty;
char c;
int i;
if (sns_dpn()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(0 <= portid && portid <= NUM_PORT)) {
return(E_PAR); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb_def(portid);
if (!(spcb->init_flag)) { /* 弶婜壔嵪偐偺僠僃僢僋 */
return(E_OBJ);
}
if (len == 0) {
return(len);
}
syscall(wai_sem(spcb->in_semid));
buffer_empty = FALSE;
for (i = 0; i < len; i++) {
buffer_empty = serial_getc(spcb, &c);
if ((spcb->ioctl & IOCTL_ECHO) != 0) {
syscall(wai_sem(spcb->out_semid));
if (!serial_putc(spcb, c)) {
syscall(sig_sem(spcb->out_semid));
}
}
*buf++ = c;
if (buffer_empty && i < len - 1) {
syscall(wai_sem(spcb->in_semid));
}
}
if (!buffer_empty) {
syscall(sig_sem(spcb->in_semid));
}
return(len);
}
/*
* 僔儕傾儖億乕僩傊偺憲怣
*/
static BOOL
serial_putc(SPCB *spcb, char c)
{
BOOL buffer_full;
if (c == '\n' && (spcb->ioctl & IOCTL_CRLF) != 0) {
if (serial_putc(spcb, '\r')) {
syscall(wai_sem(spcb->out_semid));
}
}
syscall(loc_cpu());
if (!(spcb->ixon_stopped) && write_char(spcb, c)) {
buffer_full = FALSE;
}
else {
spcb->out_buffer[spcb->out_write_ptr] = c;
INC(spcb->out_write_ptr);
buffer_full = OUT_BUFFER_FULL(spcb);
}
syscall(unl_cpu());
return(buffer_full);
}
ER_UINT
serial_wri_dat(ID portid, char *buf, UINT len)
{
SPCB *spcb;
BOOL buffer_full;
int i;
if (sns_dpn()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(0 <= portid && portid <= NUM_PORT)) {
return(E_PAR); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb_def(portid);
if (!(spcb->init_flag)) { /* 弶婜壔嵪偐偺僠僃僢僋 */
return(E_OBJ);
}
syscall(wai_sem(spcb->out_semid));
buffer_full = FALSE;
for (i = 0; i < len; i++) {
buffer_full = serial_putc(spcb, *buf++);
if (buffer_full && i < len - 1) {
syscall(wai_sem(spcb->out_semid));
}
}
if (!buffer_full) {
syscall(sig_sem(spcb->out_semid));
}
return(len);
}
/*
* 僔儕傾儖億乕僩偺惂屼
*/
int
serial_ctl_por(ID portid, UINT ioctl)
{
SPCB *spcb;
if (sns_ctx()) { /* 僐儞僥僉僗僩偺僠僃僢僋 */
return(E_CTX);
}
if (!(0 <= portid && portid <= NUM_PORT)) {
return(E_PAR); /* 億乕僩斣崋偺僠僃僢僋 */
}
spcb = get_spcb_def(portid);
if (!(spcb->init_flag)) { /* 弶婜壔嵪偐偺僠僃僢僋 */
return(E_OBJ);
}
spcb->ioctl = ioctl;
return(E_OK);
}
/*
* 僔儕傾儖億乕僩妱崬傒僴儞僪儔
*/
static BOOL
serial_int_handler(ID portid)
{
SPCB *spcb;
BOOL flag;
char c;
spcb = get_spcb(portid);
flag = 0;
/*
* 1暥帤庴怣張棟
*
* 傑偢丆僶僢僼傽僼儖偱側偄応崌偵丆1暥帤撉傫偱傒傞丏撉傔傟偽丆
* 偦傟偵墳偠偨張棟傪峴偆丏
*/
if (inc(spcb->in_write_ptr) != spcb->in_read_ptr
&& read_char(spcb, &c)) {
if ((spcb->ioctl & IOCTL_FCSND) != 0 && c == STOP) {
spcb->ixon_stopped = TRUE;
}
else if (((spcb->ioctl & IOCTL_FCSND) != 0 || spcb->ixon_stopped)
&& (c == START || (spcb->ioctl & IOCTL_FCANY) != 0)) {
spcb->ixon_stopped = FALSE;
}
else {
spcb->in_buffer[spcb->in_write_ptr] = c;
if(spcb->in_read_ptr == spcb->in_write_ptr){
syscall(sig_sem(spcb->in_semid));
}
INC(spcb->in_write_ptr);
if ((spcb->ioctl & IOCTL_FCRCV) != 0 && !(spcb->ixoff_stopped)
&& (in_buf_area(p) < IXOFF_STOP)) {
spcb->ixoff_stopped = TRUE;
spcb->ixoff_send = STOP;
}
}
flag = 1;
}
/*
* 1暥帤憲怣張棟
*/
if (spcb->ixoff_send) {
if (write_char(spcb, spcb->ixoff_send)) {
spcb->ixoff_send = 0;
flag = 1;
}
}
else if (!(spcb->ixon_stopped)
&& spcb->out_read_ptr != spcb->out_write_ptr) {
if (write_char(spcb, spcb->out_buffer[spcb->out_read_ptr])) {
if(OUT_BUFFER_FULL(spcb)){
syscall(sig_sem(spcb->out_semid));
}
INC(spcb->out_read_ptr);
flag = 1;
}
}
return(flag);
}
/*
* SIGIO 僐乕儖僶僢僋儖乕僠儞
*/
static BOOL
serial_sigio_callback(VP arg)
{
BOOL flag;
do {
// syscall(loc_cpu());
flag = serial_int_handler(1);
// syscall(unl_cpu());
} while (flag);
return(0);
}
/*
* 僔儕傾儖僀儞僞僼僃乕僗僪儔僀僶偺婲摦
*/
void
serial_initialize(VP_INT exinf)
{
serial_sigioeb.callback = serial_sigio_callback;
serial_sigioeb.arg = (VP) 0;
syscall(enqueue_sigioeb_initialize(&serial_sigioeb));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -