欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

n_r3964.c

linux 内核源代码
C
第 1 页 / 共 3 页
字号:
static void retry_transmit(struct r3964_info *pInfo){	if (pInfo->nRetry < R3964_MAX_RETRIES) {		TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);		pInfo->bcc = 0;		put_char(pInfo, STX);		flush(pInfo);		pInfo->state = R3964_TX_REQUEST;		pInfo->nRetry++;		mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);	} else {		TRACE_PE("transmission failed after %d retries",			 R3964_MAX_RETRIES);		remove_from_tx_queue(pInfo, R3964_TX_FAIL);		put_char(pInfo, NAK);		flush(pInfo);		pInfo->state = R3964_IDLE;		trigger_transmit(pInfo);	}}static void transmit_block(struct r3964_info *pInfo){	struct tty_struct *tty = pInfo->tty;	struct r3964_block_header *pBlock = pInfo->tx_first;	int room = 0;	if ((tty == NULL) || (pBlock == NULL)) {		return;	}	if (tty->driver->write_room)		room = tty->driver->write_room(tty);	TRACE_PS("transmit_block %p, room %d, length %d",		 pBlock, room, pBlock->length);	while (pInfo->tx_position < pBlock->length) {		if (room < 2)			break;		if (pBlock->data[pInfo->tx_position] == DLE) {			/* send additional DLE char: */			put_char(pInfo, DLE);		}		put_char(pInfo, pBlock->data[pInfo->tx_position++]);		room--;	}	if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {		put_char(pInfo, DLE);		put_char(pInfo, ETX);		if (pInfo->flags & R3964_BCC) {			put_char(pInfo, pInfo->bcc);		}		pInfo->state = R3964_WAIT_FOR_TX_ACK;		mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);	}	flush(pInfo);}static void on_receive_block(struct r3964_info *pInfo){	unsigned int length;	struct r3964_client_info *pClient;	struct r3964_block_header *pBlock;	length = pInfo->rx_position;	/* compare byte checksum characters: */	if (pInfo->flags & R3964_BCC) {		if (pInfo->bcc != pInfo->last_rx) {			TRACE_PE("checksum error - got %x but expected %x",				 pInfo->last_rx, pInfo->bcc);			pInfo->flags |= R3964_CHECKSUM;		}	}	/* check for errors (parity, overrun,...): */	if (pInfo->flags & R3964_ERROR) {		TRACE_PE("on_receive_block - transmission failed error %x",			 pInfo->flags & R3964_ERROR);		put_char(pInfo, NAK);		flush(pInfo);		if (pInfo->nRetry < R3964_MAX_RETRIES) {			pInfo->state = R3964_WAIT_FOR_RX_REPEAT;			pInfo->nRetry++;			mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);		} else {			TRACE_PE("on_receive_block - failed after max retries");			pInfo->state = R3964_IDLE;		}		return;	}	/* received block; submit DLE: */	put_char(pInfo, DLE);	flush(pInfo);	del_timer_sync(&pInfo->tmr);	TRACE_PS(" rx success: got %d chars", length);	/* prepare struct r3964_block_header: */	pBlock = kmalloc(length + sizeof(struct r3964_block_header),			GFP_KERNEL);	TRACE_M("on_receive_block - kmalloc %p", pBlock);	if (pBlock == NULL)		return;	pBlock->length = length;	pBlock->data = ((unsigned char *)pBlock) +			sizeof(struct r3964_block_header);	pBlock->locks = 0;	pBlock->next = NULL;	pBlock->owner = NULL;	memcpy(pBlock->data, pInfo->rx_buf, length);	/* queue block into rx_queue: */	add_rx_queue(pInfo, pBlock);	/* notify attached client processes: */	for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {		if (pClient->sig_flags & R3964_SIG_DATA) {			add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,				pBlock);		}	}	wake_up_interruptible(&pInfo->read_wait);	pInfo->state = R3964_IDLE;	trigger_transmit(pInfo);}static void receive_char(struct r3964_info *pInfo, const unsigned char c){	switch (pInfo->state) {	case R3964_TX_REQUEST:		if (c == DLE) {			TRACE_PS("TX_REQUEST - got DLE");			pInfo->state = R3964_TRANSMITTING;			pInfo->tx_position = 0;			transmit_block(pInfo);		} else if (c == STX) {			if (pInfo->nRetry == 0) {				TRACE_PE("TX_REQUEST - init conflict");				if (pInfo->priority == R3964_SLAVE) {					goto start_receiving;				}			} else {				TRACE_PE("TX_REQUEST - secondary init "					"conflict!? Switching to SLAVE mode "					"for next rx.");				goto start_receiving;			}		} else {			TRACE_PE("TX_REQUEST - char != DLE: %x", c);			retry_transmit(pInfo);		}		break;	case R3964_TRANSMITTING:		if (c == NAK) {			TRACE_PE("TRANSMITTING - got NAK");			retry_transmit(pInfo);		} else {			TRACE_PE("TRANSMITTING - got invalid char");			pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;			mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);		}		break;	case R3964_WAIT_FOR_TX_ACK:		if (c == DLE) {			TRACE_PS("WAIT_FOR_TX_ACK - got DLE");			remove_from_tx_queue(pInfo, R3964_OK);			pInfo->state = R3964_IDLE;			trigger_transmit(pInfo);		} else {			retry_transmit(pInfo);		}		break;	case R3964_WAIT_FOR_RX_REPEAT:		/* FALLTROUGH */	case R3964_IDLE:		if (c == STX) {			/* Prevent rx_queue from overflow: */			if (pInfo->blocks_in_rx_queue >=			    R3964_MAX_BLOCKS_IN_RX_QUEUE) {				TRACE_PE("IDLE - got STX but no space in "						"rx_queue!");				pInfo->state = R3964_WAIT_FOR_RX_BUF;				mod_timer(&pInfo->tmr,					  jiffies + R3964_TO_NO_BUF);				break;			}start_receiving:			/* Ok, start receiving: */			TRACE_PS("IDLE - got STX");			pInfo->rx_position = 0;			pInfo->last_rx = 0;			pInfo->flags &= ~R3964_ERROR;			pInfo->state = R3964_RECEIVING;			mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);			pInfo->nRetry = 0;			put_char(pInfo, DLE);			flush(pInfo);			pInfo->bcc = 0;		}		break;	case R3964_RECEIVING:		if (pInfo->rx_position < RX_BUF_SIZE) {			pInfo->bcc ^= c;			if (c == DLE) {				if (pInfo->last_rx == DLE) {					pInfo->last_rx = 0;					goto char_to_buf;				}				pInfo->last_rx = DLE;				break;			} else if ((c == ETX) && (pInfo->last_rx == DLE)) {				if (pInfo->flags & R3964_BCC) {					pInfo->state = R3964_WAIT_FOR_BCC;					mod_timer(&pInfo->tmr,						  jiffies + R3964_TO_ZVZ);				} else {					on_receive_block(pInfo);				}			} else {				pInfo->last_rx = c;char_to_buf:				pInfo->rx_buf[pInfo->rx_position++] = c;				mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);			}		}		/* else: overflow-msg? BUF_SIZE>MTU; should not happen? */		break;	case R3964_WAIT_FOR_BCC:		pInfo->last_rx = c;		on_receive_block(pInfo);		break;	}}static void receive_error(struct r3964_info *pInfo, const char flag){	switch (flag) {	case TTY_NORMAL:		break;	case TTY_BREAK:		TRACE_PE("received break");		pInfo->flags |= R3964_BREAK;		break;	case TTY_PARITY:		TRACE_PE("parity error");		pInfo->flags |= R3964_PARITY;		break;	case TTY_FRAME:		TRACE_PE("frame error");		pInfo->flags |= R3964_FRAME;		break;	case TTY_OVERRUN:		TRACE_PE("frame overrun");		pInfo->flags |= R3964_OVERRUN;		break;	default:		TRACE_PE("receive_error - unknown flag %d", flag);		pInfo->flags |= R3964_UNKNOWN;		break;	}}static void on_timeout(unsigned long priv){	struct r3964_info *pInfo = (void *)priv;	switch (pInfo->state) {	case R3964_TX_REQUEST:		TRACE_PE("TX_REQUEST - timeout");		retry_transmit(pInfo);		break;	case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:		put_char(pInfo, NAK);		flush(pInfo);		retry_transmit(pInfo);		break;	case R3964_WAIT_FOR_TX_ACK:		TRACE_PE("WAIT_FOR_TX_ACK - timeout");		retry_transmit(pInfo);		break;	case R3964_WAIT_FOR_RX_BUF:		TRACE_PE("WAIT_FOR_RX_BUF - timeout");		put_char(pInfo, NAK);		flush(pInfo);		pInfo->state = R3964_IDLE;		break;	case R3964_RECEIVING:		TRACE_PE("RECEIVING - timeout after %d chars",			 pInfo->rx_position);		put_char(pInfo, NAK);		flush(pInfo);		pInfo->state = R3964_IDLE;		break;	case R3964_WAIT_FOR_RX_REPEAT:		TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");		pInfo->state = R3964_IDLE;		break;	case R3964_WAIT_FOR_BCC:		TRACE_PE("WAIT_FOR_BCC - timeout");		put_char(pInfo, NAK);		flush(pInfo);		pInfo->state = R3964_IDLE;		break;	}}static struct r3964_client_info *findClient(struct r3964_info *pInfo,		struct pid *pid){	struct r3964_client_info *pClient;	for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {		if (pClient->pid == pid) {			return pClient;		}	}	return NULL;}static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg){	struct r3964_client_info *pClient;	struct r3964_client_info **ppClient;	struct r3964_message *pMsg;	if ((arg & R3964_SIG_ALL) == 0) {		/* Remove client from client list */		for (ppClient = &pInfo->firstClient; *ppClient;		     ppClient = &(*ppClient)->next) {			pClient = *ppClient;			if (pClient->pid == pid) {				TRACE_PS("removing client %d from client list",					 pid_nr(pid));				*ppClient = pClient->next;				while (pClient->msg_count) {					pMsg = remove_msg(pInfo, pClient);					if (pMsg) {						kfree(pMsg);						TRACE_M("enable_signals - msg "							"kfree %p", pMsg);					}				}				put_pid(pClient->pid);				kfree(pClient);				TRACE_M("enable_signals - kfree %p", pClient);				return 0;			}		}		return -EINVAL;	} else {		pClient = findClient(pInfo, pid);		if (pClient) {			/* update signal options */			pClient->sig_flags = arg;		} else {			/* add client to client list */			pClient = kmalloc(sizeof(struct r3964_client_info),					GFP_KERNEL);			TRACE_M("enable_signals - kmalloc %p", pClient);			if (pClient == NULL)				return -ENOMEM;			TRACE_PS("add client %d to client list", pid_nr(pid));			spin_lock_init(&pClient->lock);			pClient->sig_flags = arg;			pClient->pid = get_pid(pid);			pClient->next = pInfo->firstClient;			pClient->first_msg = NULL;			pClient->last_msg = NULL;			pClient->next_block_to_read = NULL;			pClient->msg_count = 0;			pInfo->firstClient = pClient;		}	}	return 0;}static int read_telegram(struct r3964_info *pInfo, struct pid *pid,			 unsigned char __user * buf){	struct r3964_client_info *pClient;	struct r3964_block_header *block;	if (!buf) {		return -EINVAL;	}	pClient = findClient(pInfo, pid);	if (pClient == NULL) {		return -EINVAL;	}	block = pClient->next_block_to_read;	if (!block) {		return 0;	} else {		if (copy_to_user(buf, block->data, block->length))			return -EFAULT;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -