⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial_cnxt.c

📁 一个Linux下的软猫驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Virtual serial port driver for Conexant modems * *	Written by Marc Boucher <marc@linuxant.com> *//* * Copyright (c) 2001-2002 Conexant Systems, Inc. * Copyright (c) 2003-2004 Linuxant inc. *  * 1.  General Public License. This program is free software, and may * be redistributed or modified subject to the terms of the GNU General * Public License (version 2) or the GNU Lesser General Public License, * or (at your option) any later versions ("Open Source" code). You may * obtain a copy of the GNU General Public License at * http://www.fsf.org/copyleft/gpl.html and a copy of the GNU Lesser * General Public License at http://www.fsf.org/copyleft/less.html, * or you may alternatively write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA. *  * 2.   Disclaimer of Warranties. CONEXANT AND OTHER CONTRIBUTORS MAKE NO * REPRESENTATION ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. * IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTIES OF ANY KIND. * CONEXANT AND OTHER CONTRIBUTORS DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE, GOOD TITLE AND AGAINST INFRINGEMENT. *  * This software has not been formally tested, and there is no guarantee that * it is free of errors including, but not limited to, bugs, defects, * interrupted operation, or unexpected results. Any use of this software is * at user's own risk. *  * 3.   No Liability. *  * (a) Conexant or contributors shall not be responsible for any loss or * damage to Company, its customers, or any third parties for any reason * whatsoever, and CONEXANT OR CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY * ACTUAL, DIRECT, INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL, OR CONSEQUENTIAL * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED, WHETHER IN CONTRACT, STRICT OR OTHER LEGAL THEORY OF * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. *  * (b) User agrees to hold Conexant and contributors harmless from any * liability, loss, cost, damage or expense, including attorney's fees, * as a result of any claims which may be made by any person, including * but not limited to User, its agents and employees, its customers, or * any third parties that arise out of or result from the manufacture, * delivery, actual or alleged ownership, performance, use, operation * or possession of the software furnished hereunder, whether such claims * are based on negligence, breach of contract, absolute liability or any * other legal theory. *  * 4.   Notices. User hereby agrees not to remove, alter or destroy any * copyright, trademark, credits, other proprietary notices or confidential * legends placed upon, contained within or associated with the Software, * and shall include all such unaltered copyright, trademark, credits, * other proprietary notices or confidential legends on or in every copy of * the Software. *  */#include <linux/version.h>#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/major.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <asm/serial.h>#include <linux/serial.h>#if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))#if (!defined(CONFIG_SERIAL_CORE) && !defined(CONFIG_SERIAL_CORE_MODULE))#error CONFIG_SERIAL_CORE needed; enable 8250/16550 and compatible serial support in kernel config#endif#include <linux/serial_core.h>#endif#include "oscompat.h"#include "osservices.h"#include "comtypes.h"#include "comctrl_ex.h"#include "oslinux.h"#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)#include "serial_core.h"#endif#include "serial_cnxt.h"#define NR_PORTS		CNXTMAXMDM#define CNXT_ISR_PASS_LIMIT	256#define CNXT_READBUF_SIZE	256#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)static struct tty_driver cnxt_tty_driver_normal;static struct tty_driver cnxt_tty_driver_callout;static struct tty_struct *cnxt_tty_table[NR_PORTS];static struct termios *cnxt_termios[NR_PORTS], *cnxt_termios_locked[NR_PORTS];#endifstruct cnxt_serial_inst {    spinlock_t lock;    struct module *owner;    POS_DEVNODE devnode;    HANDLE hcomctrl;    char *typestr;    struct uart_port *port;    int rxenabled;    int txenabled;    int evt_rxchar;    int evt_rxbreak;    int evt_rxovrn;    int evt_txempty;    unsigned char readbuf[CNXT_READBUF_SIZE];    int readcount, readoffset;    u_int mctrl_flags;    OSSCHED intr_tqueue;    struct uart_port *uart_port;    struct uart_info *uart_info;#ifdef CONFIG_PROC_FS    struct proc_dir_entry *proc_unit_dir;    struct proc_dir_entry *proc_hwinst;    struct proc_dir_entry *proc_hwprofile;    struct proc_dir_entry *proc_hwrevision;#ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT    struct proc_dir_entry *proc_lastcallstatus;#endif#endif};#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *cnxt_serial_proc_dir;#endifstatic struct cnxt_serial_inst cnxt_serial_inst[NR_PORTS];static struct uart_port cnxt_ports[NR_PORTS];#ifdef COMCTRL_MONITOR_POUND_UG_SUPPORTstatic int loglastcallstatus;#endifstatic voidcnxt_sched_intr(struct cnxt_serial_inst *inst){    if(inst->uart_info) {	OsModuleUseCountInc();	if (OsThreadSchedule(OsMdmThread, &inst->intr_tqueue) <= 0) {	    OsModuleUseCountDec();	}    }}static void#ifdef FOUND_TTY_START_STOPcnxt_stop_tx(struct uart_port *port, u_int tty_stop)#elsecnxt_stop_tx(struct uart_port *port)#endif{    struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports];    //printk(KERN_DEBUG "%s\n", __FUNCTION__);    inst->txenabled = 0;}static void#ifdef FOUND_TTY_START_STOPcnxt_start_tx(struct uart_port *port, u_int tty_start)#elsecnxt_start_tx(struct uart_port *port)#endif{    struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports];    //printk(KERN_DEBUG "%s\n", __FUNCTION__);    inst->txenabled = 1;    cnxt_sched_intr(inst);}static voidcnxt_stop_rx(struct uart_port *port){    struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports];    //printk(KERN_DEBUG "%s\n", __FUNCTION__);    inst->rxenabled = 0;}static inline intcnxt_rx_ready(struct cnxt_serial_inst *inst){    int r;    if(!inst->rxenabled)	return FALSE;    if(inst->readoffset == inst->readcount) {	r = ComCtrl_Read(inst->hcomctrl, inst->readbuf, sizeof(inst->readbuf));	if(r < 0) {	    printk(KERN_ERR"%s: ComCtrlRead returned %d\n", __FUNCTION__, r);	} else {	    inst->readcount = r;	    inst->readoffset = 0;	}    }    return (inst->readcount > inst->readoffset) || inst->evt_rxbreak || inst->evt_rxovrn;}static inline voidcnxt_rx_chars(struct cnxt_serial_inst *inst){    struct tty_struct *tty = inst->uart_info->tty;    int max_count = sizeof(inst->readbuf);    unsigned char flag;    inst->evt_rxchar = 0;    while(max_count-- > 0 && cnxt_rx_ready(inst)) {#ifndef FOUND_TTY_NEW_API	if(unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)	    tty->flip.tqueue.routine((void *) tty);#else	    tty->flip.work.func((void *)tty);#endif	    if(tty->flip.count >= TTY_FLIPBUF_SIZE) {		return; // if TTY_DONT_FLIP is set	    }	}#endif	if (inst->evt_rxovrn) {	    inst->evt_rxovrn = 0;	    inst->uart_port->icount.overrun++;#ifdef FOUND_TTY_NEW_API	    tty_insert_flip_char(tty, 0, TTY_OVERRUN);#else	    *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;	    *tty->flip.char_buf_ptr++ = 0;	    tty->flip.count++;#endif	    continue;	}	inst->uart_port->icount.rx++;	if (inst->evt_rxbreak) {	    inst->evt_rxbreak = 0;	    inst->uart_port->icount.brk++;	    flag = TTY_BREAK;	} else	    flag = TTY_NORMAL;#ifdef FOUND_TTY_NEW_API	tty_insert_flip_char(tty, inst->readbuf[inst->readoffset++], flag);#else	*tty->flip.flag_buf_ptr++ = flag;	*tty->flip.char_buf_ptr++ = inst->readbuf[inst->readoffset++];	tty->flip.count++;#endif    }    tty_flip_buffer_push(tty);    return;}#if 0static inline intcnxt_tx_free(struct cnxt_serial_inst *inst){    int r;    UINT32 val = 0;    if ((r=ComCtrl_Monitor(inst->hcomctrl, COMCTRL_MONITOR_TXFREE, &val)) != COM_STATUS_SUCCESS) {	printk(KERN_ERR "%s: ComCtrlMonitor COMCTRL_MONITOR_TXFREE failed, status=%d\n", __FUNCTION__, r);	return 0;    }    //printk(KERN_DEBUG "%s: val=%lu\n", __FUNCTION__, val);    return val;}#endifstatic inline intcnxt_put_char(struct cnxt_serial_inst *inst, unsigned char ch){    int r;    //printk(KERN_DEBUG "%s: ch=%x\n", __FUNCTION__, (int)ch);    inst->evt_txempty = 0;    r = ComCtrl_Write(inst->hcomctrl, &ch, 1);    if(r < 0) {	printk(KERN_ERR "%s: ComCtrlWrite returned %d\n", __FUNCTION__, r);    }    return r == 1;}static inline voidcnxt_tx_chars(struct cnxt_serial_inst *inst){    struct circ_buf *xmit;    struct uart_info *info = inst->uart_info;    struct uart_port *port;    spinlock_t *lock;    unsigned long flags;       port = inst->uart_port;    xmit = &info->xmit;    if (port->x_char) {	cnxt_put_char(inst, port->x_char);	port->icount.tx++;	port->x_char = 0;	return;    }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)    lock = &info->lock;#else    lock = &port->lock;#endif    spin_lock_irqsave(lock, flags);    if (uart_circ_empty(xmit)	    || info->tty->stopped	    || info->tty->hw_stopped) {#ifdef FOUND_TTY_START_STOP	cnxt_stop_tx(port, 0);#else	cnxt_stop_tx(port);#endif	spin_unlock_irqrestore(lock, flags);	return;    }    while (xmit->buf/*&& cnxt_tx_free(inst) > 0*/) {	if(!cnxt_put_char(inst, xmit->buf[xmit->tail]))	    break;	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);	port->icount.tx++;	if (uart_circ_empty(xmit))	    break;    }    if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)	uart_event(info, EVT_WRITE_WAKEUP);#else	uart_write_wakeup(port);#endif    if (uart_circ_empty(xmit))#ifdef FOUND_TTY_START_STOP	cnxt_stop_tx(port, 0);#else	cnxt_stop_tx(port);#endif    spin_unlock_irqrestore(lock, flags);}static inline intcnxt_tx_ready(struct cnxt_serial_inst *inst) {	return (inst->txenabled /*&& inst->evt_txempty*/);}static voidcnxt_intr(void *dev_id){    unsigned int pass_counter = 0;    struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)dev_id;    while (inst->uart_info && (cnxt_rx_ready(inst) || cnxt_tx_ready(inst))) {	cnxt_rx_chars(inst);	if(cnxt_tx_ready(inst))	    cnxt_tx_chars(inst);	if (pass_counter++ > CNXT_ISR_PASS_LIMIT)	    break;    }    OsModuleUseCountDec();    OsThreadScheduleDone();}/* * Return TIOCSER_TEMT when transmitter is not busy. */static u_intcnxt_tx_empty(struct uart_port *port){    struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports];    return inst->evt_txempty ? TIOCSER_TEMT : 0;}static u_intcnxt_get_mctrl(struct uart_port *port){    struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports];    return inst->mctrl_flags;}#ifdef COMCTRL_MONITOR_POUND_UG_SUPPORTstatic COM_STATUScnxt_monitor(struct cnxt_serial_inst *inst, COMCTRL_MONITOR_CODE eCode, PVOID pMonitor){    int r;    if(!inst->hcomctrl)	return COM_STATUS_INST_NOT_INIT;    r = ComCtrl_Monitor(inst->hcomctrl, eCode, pMonitor);    if (r != COM_STATUS_SUCCESS) {	printk(KERN_ERR "%s: ComCtrlMonitor %d failed, status=%d\n", __FUNCTION__, eCode, r);    }    return r;}#endifstatic COM_STATUScnxt_control(struct cnxt_serial_inst *inst, COMCTRL_CONTROL_CODE eCode, PVOID pControl){    int r;    if(!inst->hcomctrl)	return COM_STATUS_INST_NOT_INIT;    r = ComCtrl_Control(inst->hcomctrl, eCode, pControl);    if (r != COM_STATUS_SUCCESS) {	printk(KERN_ERR "%s: ComCtrlControl %d failed, status=%d\n", __FUNCTION__, eCode, r);    }    return r;}static voidcnxt_set_mctrl(struct uart_port *port, u_int mctrl){    struct cnxt_serial_inst *inst = &cnxt_serial_inst[port - cnxt_ports];    //printk(KERN_DEBUG "%s: mctrl=%x\n", __FUNCTION__, mctrl);    if ((mctrl & TIOCM_RTS) && !(inst->mctrl_flags & TIOCM_RTS)) {	inst->mctrl_flags |= TIOCM_RTS;	cnxt_control(inst, COMCTRL_CONTROL_SETRTS, 0);    }    if (!(mctrl & TIOCM_RTS) && (inst->mctrl_flags & TIOCM_RTS)) {

⌨️ 快捷键说明

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