论坛风格切换切换到宽版
发帖 回复
返回列表  提醒:不能用迅雷等P2P下载,否则下载失败标(二级)的板块,需二级才能下载,没二级不要购买,下载不了
  • 1320阅读
  • 0回复

RK3288  WAN 驱动源码 [复制链接]

上一主题 下一主题
离线mark83136
 

性别:
帅哥
发帖
1210
金币
360
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看楼主 倒序阅读 使用道具 0楼 发表于: 2015-07-07
[j? <9  
/* ~qS/90,  
* pc300_tty.c    Cyclades-PC300(tm) TTY Driver. ]CZLaID~  
* W\,lII0  
* Author:    Regina Kodato <reginak@cyclades.com> 0'hxw3#  
* a+/|O*>#  
* Copyright:    (c) 1999-2002 Cyclades Corp. Y*k<NeDyn  
* 17cW8\  
*    This program is free software; you can redistribute it and/or .e"Qv*[^  
*  modify it under the terms of the GNU General Public License MI(i%$R-A  
*  as published by the Free Software Foundation; either version 8q3TeMYV  
*  2 of the License, or (at your option) any later version. WQpJd7  
*   u =kSs  
*  $Log: pc300_tty.c,v $ N >!xedw=  
*  Revision 3.7  2002/03/07 14:17:09  henrique zb/Xfu.)?6  
*  License data fixed pU ]{Z(  
* IBkH+j  
*  Revision 3.6  2001/12/10 12:29:42  regina V@:=}*E  
*  Fix the MLPPP bug 3}21bL  
* SSLs hY~d  
*  Revision 3.5  2001/10/31 11:20:05  regina ~It+|X=Kx  
*  automatic pppd starts Z]TVH8%|k  
* 0lCd,a 2:  
*  Revision 3.4  2001/08/06 12:01:51  regina C[nr>   
*  problem in DSR_DE bit !|h2&tH  
* t4@g;U?o  
*  Revision 3.3  2001/07/26 22:58:41  regina [T]qm7 ?  
*  update EDA value  #U52\3G  
* E$tk1SVo  
*  Revision 3.2  2001/07/12 13:11:20  regina R0mT/h2  
*  bug fix - DCD-OFF in pc300 tty driver -Y=c g;  
* |/^aL j^u  
*    DMA transmission bug fix y]]Vp~R:[  
*   aRKRy  
*  Revision 3.1  2001/06/22 13:13:02  regina f_h"gZWV  
*  MLPPP implementation m=\eL~ h  
* pE/3-0;}N  
*/ K4/P(*r`  
""'eTpe  
#include <linux/module.h> ~_db<!a  
#include <linux/kernel.h> Jf<yTAm  
#include <linux/errno.h> $lAb6e$n  
#include <linux/string.h> ;9p5YxD  
#include <linux/init.h> %4|}&,%%r  
#include <linux/netdevice.h> s<_LcQbt{  
#include <linux/spinlock.h> 0aTbzOn&  
#include <linux/slab.h> qV8\/7'A0a  
#include <linux/if.h> _@pf1d$  
#include <linux/skbuff.h> jjwMvf.R  
/* TTY includes */ E'S;4B5?  
#include <linux/tty.h> 8N* -2/P&  
#include <linux/tty_flip.h> _K}_h\e.  
#include <linux/serial.h> vDeG20.?Z  
8+|V!q   
#include <asm/io.h> FR,#s^kF  
#include <asm/uaccess.h> 6a]f&={E  
h"1"h.  
#include "pc300.h" ;=VK _3"  
^ $+f3Z'  
/* defines and macros */ Qv0>Pf  
/* TTY Global definitions */ ,cy/fW  
#define    CPC_TTY_NPORTS    8    /* maximum number of the sync tty connections */ 8pL>wL &C  
#define    CPC_TTY_MAJOR    CYCLADES_MAJOR     O<Sc.@~  
#define CPC_TTY_MINOR_START    240    /* minor of the first PC300 interface */ sJI -  
HvgK_'  
#define CPC_TTY_MAX_MTU    2000     PP[)h,ZL*  
";?C4%L  
/* tty interface state */ aRO_,n9  
#define    CPC_TTY_ST_IDLE    0 }:9|*m<$t  
#define CPC_TTY_ST_INIT    1    /* configured with MLPPP and up */ yp2'KES>  
#define CPC_TTY_ST_OPEN    2    /* opened by application */ <aSLm=  
MZMS ?}.2  
#define    CPC_TTY_LOCK(card,flags)\ E}b> 7L&w  
    do {\ 95?5=T F  
        spin_lock_irqsave(&card->card_lock, flags);    \ K~y9zF{  
    } while (0) _ U8OIXN  
{`Fx~w;i  
#define CPC_TTY_UNLOCK(card,flags)    \ v>y8s&/  
    do {\ @@{_[ir  
        spin_unlock_irqrestore(&card->card_lock, flags);    \ F {*9[jY  
    } while (0) %<J(lC9,C  
fyg~KF}  
//#define    CPC_TTY_DBG(format,a...)    printk(format,##a) |6(qg5"  
#define    CPC_TTY_DBG(format,a...) kLPO+lg+  
(m3I#L  
/* data structures */ n L+YL  
typedef struct _st_cpc_rx_buf { OZC/+"\,  
    struct _st_cpc_rx_buf    *next; z)W#&JFF  
    int        size; <7FP"YU  
    unsigned char    data[1]; 0 bPJEEd  
} st_cpc_rx_buf; fJn3"D'  
cfC;eRgq~  
struct st_cpc_rx_list { ,LW(mdIe(  
    st_cpc_rx_buf    *first; /[nZ#zj!3  
    st_cpc_rx_buf    *last; t.>te'DK/  
}; C?/r}ly<\  
71 L\t3fG  
typedef    struct _st_cpc_tty_area { 9-a2L JI  
    int        state;        /* state of the TTY interface */ k{}[>))Q  
    int        num_open;     N}}PlGp$  
    unsigned int     tty_minor;    /* minor this interface */ zy5s$f1IA  
    volatile struct st_cpc_rx_list buf_rx;    /* ptr. to reception buffer */ 0XR;5kd%  
    unsigned char*    buf_tx;        /* ptr. to transmission buffer */ S4k^&$;  
    pc300dev_t*    pc300dev;    /* ptr. to info struct in PC300 driver */ NDe[2  
    unsigned char    name[20];    /* interf. name + "-tty" */ mHI4wS>()+  
    struct tty_struct *tty;         XMeL^|D  
    struct work_struct tty_tx_work; /* tx work - tx interrupt */ p;n3`aVh  
    struct work_struct tty_rx_work; /* rx work - rx interrupt */ p-Rm,xyL%  
    } st_cpc_tty_area; m|nL!Wc  
`b^#quz  
/* TTY data structures */ 2sd ) w  
static struct tty_driver serial_drv; JI+KS  
Y>78h2AU  
/* local variables */ `uNvFlP  
static st_cpc_tty_area    cpc_tty_area[CPC_TTY_NPORTS]; '.%iPMM  
#!8^!}nFO  
static int cpc_tty_cnt = 0;    /* number of intrfaces configured with MLPPP */ e}](6"t`5  
static int cpc_tty_unreg_flag = 0; &e HM#as  
~ C/Yv&58  
/* TTY functions prototype */ P^K?E  
static int cpc_tty_open(struct tty_struct *tty, struct file *flip); >Bh)7>`3c  
static void cpc_tty_close(struct tty_struct *tty, struct file *flip); M!&_qj&N,  
static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count); 9&O#+FU  
static int cpc_tty_write_room(struct tty_struct *tty); .y %pGi  
static int cpc_tty_chars_in_buffer(struct tty_struct *tty); PuCwdTan_  
static void cpc_tty_flush_buffer(struct tty_struct *tty); "o^bN 9=  
static void cpc_tty_hangup(struct tty_struct *tty); VVI8)h8  
static void cpc_tty_rx_work(struct work_struct *work); Giy3eva2  
static void cpc_tty_tx_work(struct work_struct *work); &prdlh=UE  
static int cpc_tty_send_to_card(pc300dev_t *dev,void *buf, int len); #uD)0zdw  
static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx); Gs_*/E7,  
static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char); koncWyW  
static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char); =9;[C:p0-  
>+Sv9S  
static int pc300_tiocmset(struct tty_struct *, unsigned int, unsigned int); 3r~>~ueZ  
static int pc300_tiocmget(struct tty_struct *); 1EC-e|M.  
xUiWiOihr6  
/* functions called by PC300 driver */ 5';/@M  
void cpc_tty_init(pc300dev_t *dev); 1AV1d%F  
void cpc_tty_unregister_service(pc300dev_t *pc300dev); m0x J05Zx  
void cpc_tty_receive(pc300dev_t *pc300dev); 5YTb7M  
void cpc_tty_trigger_poll(pc300dev_t *pc300dev); #/n|@z'  
void cpc_tty_reset_var(void); 8X}^~e  
};|!Lhl+  
/* tsTR2+GZS  
* PC300 TTY clear "signal" Lf,CxZL5  
*/ iwG>]:K3  
static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char signal) ]~j_N^oZ1X  
{ 1&X}1  
    pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; {\vI9cni|"  
    pc300_t *card = (pc300_t *) pc300chan->card; 5`4}A%@&  
    int ch = pc300chan->channel; {f`lSu  
    unsigned long flags; ffmG~$Yh_  
UC8vR>e\  
    CPC_TTY_DBG("%s-tty: Clear signal %x\n", x !#Ma  
        pc300dev->dev->name, signal); GN:Ru|n  
    CPC_TTY_LOCK(card, flags); k%EWkM)?  
    cpc_writeb(card->hw.scabase + M_REG(CTL,ch), -:)DX++  
        cpc_readb(card->hw.scabase+M_REG(CTL,ch))& signal); ttK,((=@  
    CPC_TTY_UNLOCK(card,flags); wFK:Dp_^  
} nuf@}W>y  
?o2;SY(-  
/* |_l<JQvf`E  
* PC300 TTY set "signal" to ON E/"YId `A  
*/ Ez zTJ>  
static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char signal) dIoF~8V  
{ kJ%{ [1fr  
    pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; Zvd ;KGO(a  
    pc300_t *card = (pc300_t *) pc300chan->card; BKa A=Bl  
    int ch = pc300chan->channel; HBt|}uZ?6i  
    unsigned long flags; !7A"vTs  
@+}rEe_(  
    CPC_TTY_DBG("%s-tty: Set signal %x\n", fp.!VOy  
        pc300dev->dev->name, signal); >|l;*Kw,/P  
    CPC_TTY_LOCK(card, flags); *0=fT}&!  
    cpc_writeb(card->hw.scabase + M_REG(CTL,ch), pY^pTWs(  
        cpc_readb(card->hw.scabase+M_REG(CTL,ch))& ~signal); e%PC e9  
    CPC_TTY_UNLOCK(card,flags); >}ro[x`K  
} MC4284A5  
l\K%  
5Z* b(R  
static const struct tty_operations pc300_ops = { Of1IdE6~  
    .open = cpc_tty_open, B1|?RfCe  
    .close = cpc_tty_close, |?\gEY-Se  
    .write = cpc_tty_write, ?wGiog<Q{  
    .write_room = cpc_tty_write_room, pp/#Am  
    .chars_in_buffer = cpc_tty_chars_in_buffer, 8# 6\+R  
    .tiocmset = pc300_tiocmset, L@7Qs6G2u  
    .tiocmget = pc300_tiocmget, gb.f%rlZ`  
    .flush_buffer = cpc_tty_flush_buffer, ]O6KKz  
    .hangup = cpc_tty_hangup, ~Y\QGuT  
}; Lf5%M|o.)  
t{+ M|Y  
5gO /-Zj  
/* /)sDnJ1r  
* PC300 TTY initialization routine gE\A9L~b  
* IO}+[%ptc*  
* This routine is called by the PC300 driver during board configuration mG0L !5  
* (ioctl=SIOCSP300CONF). At this point the adapter is completely =hJfL}&O3  
* initialized. EYA/CI   
* o verify kernel version (only 2.4.x) x}v1X`6b  
* o register TTY driver  pgC d  
* o init cpc_tty_area struct #0}Ok98P  
*/ VMaS;)0f@  
void cpc_tty_init(pc300dev_t *pc300dev) 9 TqoLX  
{ ?lF mXZy`  
    unsigned long port; 7;^((.]ln  
    int aux; {d| |q<.-  
    st_cpc_tty_area * cpc_tty; -<8B,  
7 rH'1U  
    /* hdlcX - X=interface number */ )\8URc|J  
    port = pc300dev->dev->name[4] - '0'; V{43HA10b  
    if (port >= CPC_TTY_NPORTS) { - o4@#p>>  
        printk("%s-tty: invalid interface selected (0-%i): %li", xcHen/4X  
            pc300dev->dev->name, @XeEpDn]  
            CPC_TTY_NPORTS-1,port); I%SuT7"Do  
        return; E3y6c)<  
    } VK9Q?nu  
yb69Q#V2  
    if (cpc_tty_cnt == 0) { /* first TTY connection -> register driver */ Q6u{@$(/N  
        CPC_TTY_DBG("%s-tty: driver init, major:%i, minor range:%i=%i\n", $+7ci~gs  
            pc300dev->dev->name, cvhlRI%6  
            CPC_TTY_MAJOR, CPC_TTY_MINOR_START, +eU`H[iu  
            CPC_TTY_MINOR_START+CPC_TTY_NPORTS); &j3` )N  
        /* initialize tty driver struct */ p=2zS.  
        memset(&serial_drv,0,sizeof(struct tty_driver)); <F ew<r2  
        serial_drv.magic = TTY_DRIVER_MAGIC; l(gJLjTH%  
        serial_drv.owner = THIS_MODULE; nHnk#SAA u  
        serial_drv.driver_name = "pc300_tty"; :MK=h;5Z  
        serial_drv.name = "ttyCP"; \$j^_C>  
        serial_drv.major = CPC_TTY_MAJOR; IeZ&7u  
        serial_drv.minor_start = CPC_TTY_MINOR_START; mU50pM~/i  
        serial_drv.num = CPC_TTY_NPORTS; itw{;j   
        serial_drv.type = TTY_DRIVER_TYPE_SERIAL; ooY\t +  
        serial_drv.subtype = SERIAL_TYPE_NORMAL; Ky *DfQA  
A1Ka(3"  
        serial_drv.init_termios = tty_std_termios; J6DnPaw-G  
        serial_drv.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; FtN}]@F  
        serial_drv.flags = TTY_DRIVER_REAL_RAW; f?Z|>3.2  
|P>|D+I0  
        /* interface routines from the upper tty layer to the tty driver */ #^Ys{  
        tty_set_operations(&serial_drv, &pc300_ops); ?<! nm&~  
MvBD@`&7  
        /* register the TTY driver */ o_sQQF  
        if (tty_register_driver(&serial_drv)) { C>4UbU  
            printk("%s-tty: Failed to register serial driver! ", n3'dLJH|  
                pc300dev->dev->name); 6p#g0t  
               return; ~> PgJ ^G  
        } o!=WFAi[pX  
A?DB#-z.r  
        memset((void *)cpc_tty_area, 0, U~wjR"='  
                                sizeof(st_cpc_tty_area) * CPC_TTY_NPORTS); j AQU~Ol_  
    } 7u::5W-q  
pr$~8e=c  
    cpc_tty = &cpc_tty_area[port]; :&9TW]*g  
     #sZIDn J#  
    if (cpc_tty->state != CPC_TTY_ST_IDLE) { IO"hF  
        CPC_TTY_DBG("%s-tty: TTY port %i, already in use.\n", q4k.f_{  
                pc300dev->dev->name, port); g,=^'D  
        return; &L%Jy #=  
    } 8aZ$5^z  
XMw.wQ '?  
    cpc_tty_cnt++; =e{.yggE  
    cpc_tty->state = CPC_TTY_ST_INIT; lufeieW  
    cpc_tty->num_open= 0; 781]THY=  
    cpc_tty->tty_minor = port + CPC_TTY_MINOR_START; iX%n0i  
    cpc_tty->pc300dev = pc300dev; IC/Q  
L,$3Yj  
    INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work); #uKWuGz]  
    INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work); csDQva\  
     qp&4 1  
    cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = NULL; @\jQoaLT$_  
I+" lrU  
    pc300dev->cpc_tty = (void *)cpc_tty; /c#l9&,  
     . :a<2sp6  
    aux = strlen(pc300dev->dev->name); K &dT(U  
    memcpy(cpc_tty->name, pc300dev->dev->name, aux); MM gx|"  
    memcpy(&cpc_tty->name[aux], "-tty", 5); a$$ Wt<&Y  
     Kt6>L5:94  
    cpc_open(pc300dev->dev); 0hwj\{"  
    cpc_tty_signal_off(pc300dev, CTL_DTR); 7"cv|6y|  
X;VQEDMPU  
    CPC_TTY_DBG("%s: Initializing TTY Sync Driver, tty major#%d minor#%i\n", smup,RNZRX  
            cpc_tty->name,CPC_TTY_MAJOR,cpc_tty->tty_minor); !Lkm? (_  
    return; uPLErO9Es[  
} "hPCQp`Tj  
lhO2'#]i  
/* 3m=2x5 {L  
* PC300 TTY OPEN routine ~5 >[`)  
* [s}/nu~U  
* This routine is called by the tty driver to open the interface RJ}#)cT  
* o verify minor +EkW>$  
* o allocate buffer to Rx and Tx QDE$E.a  
*/ K5`Rk" s  
static int cpc_tty_open(struct tty_struct *tty, struct file *flip) w z=z?AZW  
{ mCdgKr|n  
    int port ; " U8S81'  
    st_cpc_tty_area *cpc_tty; AVFjBybu9  
+pp9d-n  
    if (!tty) { *aRX \ TnN  
        return -ENODEV; @Y-TOCadT  
    } $Q/Ya@o  
8\# ^k#X  
    port = tty->index; hO( RZ '{  
<kbyZXV@K  
    if ((port < 0) || (port >= CPC_TTY_NPORTS)){ c!wtf,F  
        CPC_TTY_DBG("pc300_tty: open invalid port %d\n", port); _|zBUrN  
        return -ENODEV; j O8k6<l  
    } /;oqf4MF  
o8ppMM8_R[  
    cpc_tty = &cpc_tty_area[port]; JE;+T[I  
     4l @)K9F  
    if (cpc_tty->state == CPC_TTY_ST_IDLE){ WG5W0T_  
        CPC_TTY_DBG("%s: open - invalid interface, port=%d\n", "HlgRp]u  
                    cpc_tty->name, tty->index); LM"y\q ]  
        return -ENODEV;  CdZ BG  
    } gQouOjfP  
Z cpmquf8L  
    if (cpc_tty->num_open == 0) { /* first open of this tty */ lddp^ #f  
        if (!cpc_tty_area[port].buf_tx){ XvKFPr0~  
            cpc_tty_area[port].buf_tx = kmalloc(CPC_TTY_MAX_MTU,GFP_KERNEL); s'u(B]E  
            if (!cpc_tty_area[port].buf_tx) { ( u`W!{1\  
                CPC_TTY_DBG("%s: error in memory allocation\n",cpc_tty->name); GEe`ZhG,  
                return -ENOMEM; L*]0"E  
            } }}T,W.#%u  
        } LFu%v7L`  
q p~g P  
        if (cpc_tty_area[port].buf_rx.first) { y%cO#P@  
            unsigned char * aux; \40 YGFO  
            while (cpc_tty_area[port].buf_rx.first) { *#&*`iJ(  
                aux = (unsigned char *)cpc_tty_area[port].buf_rx.first; '{[),*nCn  
                cpc_tty_area[port].buf_rx.first = cpc_tty_area[port].buf_rx.first->next; rU2iy"L  
                kfree(aux); 2R.2D'4)`  
            } `xz&Scil  
            cpc_tty_area[port].buf_rx.first = NULL; CxF-Z7 '  
            cpc_tty_area[port].buf_rx.last = NULL; uaw <  
        } -]S.<8<$  
M+xdHBg  
        cpc_tty_area[port].state = CPC_TTY_ST_OPEN; 0KvVw rWJ  
        cpc_tty_area[port].tty = tty; e3m*i}K}  
        tty->driver_data = &cpc_tty_area[port]; d,cN(  
h(' )"  
        cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR); EKZVF`L  
    } ga0'zo9K  
$_X|, v9  
    cpc_tty->num_open++; #A<P6zJXR  
%2l7Hmp4H  
    CPC_TTY_DBG("%s: opening TTY driver\n", cpc_tty->name); ,k0r  
     u8vuwbra!  
    /* avisar driver PC300 */ <J{'o`{  
    return 0; F n|gVR  
} R,_d1^|*w  
K :LL_,  
/* =f7r69I"  
* PC300 TTY CLOSE routine "!UVs+)]  
* BNucc']  
* This routine is called by the tty driver to close the interface LE=k  
* o call close channel in PC300 driver (cpc_closech) q4 k@l  
* o free Rx and Tx buffers }e]f  
*/ :Vuf6,  
K_BPZ5w  
static void cpc_tty_close(struct tty_struct *tty, struct file *flip) C"w {\ &R  
{ =o=1"o[  
    st_cpc_tty_area    *cpc_tty; (pR.Abq  
    unsigned long flags; ;LwqTlJ*[L  
    int res; C>QIrZu  
yL1bS|@  
    if (!tty || !tty->driver_data ) { Ufid%T'  
        CPC_TTY_DBG("hdlx-tty: no TTY in close\n"); g:#d l\k  
        return; /Cr/RG:OX  
    } Rf"Mr:^  
0b|zk <  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; 8E^@yZo{  
qE7R4>5xjO  
    if ((cpc_tty->tty != tty)|| (cpc_tty->state != CPC_TTY_ST_OPEN)) { Qx`~g,wk8  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); -9Ws=r0R  
        return; %$ceJ`%1e  
    } p@Q5b}xCG_  
       !?FK We  
    if (!cpc_tty->num_open) { O&Z' r  
        CPC_TTY_DBG("%s: TTY is closed\n",cpc_tty->name); IB5BO7J  
        return; ` %?9=h%  
    } &%C4Ugo  
9'~- U  
    if (--cpc_tty->num_open > 0) { C;rG]t^%  
        CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name); -$a>f4]  
        return; NCS!:d:Ry  
    } N2,D:m\  
H{G{H=K_  
    cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); )Hw:E71h2  
x4K`]Fvhl  
    CPC_TTY_LOCK(cpc_tty->pc300dev->chan->card, flags);  /* lock irq */ ,^s  
    cpc_tty->tty = NULL; *OTS'W~t  
    cpc_tty->state = CPC_TTY_ST_INIT; 9IZu$-  
    CPC_TTY_UNLOCK(cpc_tty->pc300dev->chan->card, flags); /* unlock irq */ dZ(|uC!?  
     A.%CAGU5w  
    if (cpc_tty->buf_rx.first) { Tupiq  
        unsigned char * aux; cPF<D$B  
        while (cpc_tty->buf_rx.first) { pBJAaCGm  
            aux = (unsigned char *)cpc_tty->buf_rx.first; =hH.zrI6e  
            cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; =tdSq"jh  
            kfree(aux); m:CTPzAt  
        } .p6+l!"  
        cpc_tty->buf_rx.first = NULL; /!&R9!6 :  
        cpc_tty->buf_rx.last = NULL; XSRdqU>Aun  
    } ~Pf5ORoe  
     -V<t-}h.  
    kfree(cpc_tty->buf_tx); : mGAt[Cc  
    cpc_tty->buf_tx = NULL; NX6nQ  
x5si70BKC/  
    CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name);  Qo0H  
     iU2KEqCm  
    if (!serial_drv.refcount && cpc_tty_unreg_flag) { ^HA %q8| n  
        cpc_tty_unreg_flag = 0; -pb&-@Hul  
        CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); =[tSd)D,y  
        if ((res=tty_unregister_driver(&serial_drv))) { Bx~[F  
            CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", =_TaA(79  
                            cpc_tty->name,res); d5j_6X  
        } v> z@  
    } qN| fEO>  
    return; fQLax  
} yfNX7  
rjWLMbd.<  
/* {bNXedZ\  
* PC300 TTY WRITE routine \}]iS C.2  
* ]`=X'fED  
* This routine is called by the tty driver to write a series of characters p9ZXbAJ{  
* to the tty device. The characters may come from user or kernel space. R4's7k  
* o verify the DCD signal '` CspY  
* o send characters to board and start the transmission rXi uwz\  
*/ %"$@%"8;3  
static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) [w \?j,  
{  -7]Xjb5  
    st_cpc_tty_area    *cpc_tty; }-<zWI {p  
    pc300ch_t *pc300chan; >`T5]_a  
    pc300_t *card;  b`mj_b  
    int ch; hZ\+FOx;  
    unsigned long flags; '_0]vupvY  
    struct net_device_stats *stats; sKaE-sbJY  
(&\aA 0-}H  
    if (!tty || !tty->driver_data ) { 0Fr1Ku!  
        CPC_TTY_DBG("hdlcX-tty: no TTY in write\n"); F phDF  
        return -ENODEV; =H5\$&xj4.  
    } ^s/  
;&;W T  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; "E=j|q  
%'Xk)-+y  
    if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { \>/M .2  
        CPC_TTY_DBG("%s: TTY is not opened\n", cpc_tty->name); % g"eV4 j  
        return -ENODEV; Ju` [m  
    } ><?BqRm+  
tx7~S Ur  
    if (count > CPC_TTY_MAX_MTU) { kMxazx1  
        CPC_TTY_DBG("%s: count is invalid\n",cpc_tty->name); 2s ,8R  
        return -EINVAL;        /* frame too big */ V,7%1TZ:  
    } /'DwfX  
u62)QJE  
    CPC_TTY_DBG("%s: cpc_tty_write data len=%i\n",cpc_tty->name,count); ) |#%Czd4  
     ni CE\B~  
    pc300chan = (pc300ch_t *)((pc300dev_t*)cpc_tty->pc300dev)->chan; n]CbDbNw7)  
    stats = &cpc_tty->pc300dev->dev->stats; u V6g[J  
    card = (pc300_t *) pc300chan->card; b B  
    ch = pc300chan->channel; N]/!mo?  
&%aXR A#+  
    /* verify DCD signal*/ q`|CrOzO  
    if (cpc_readb(card->hw.scabase + M_REG(ST3,ch)) & ST3_DCD) { N1EezC'^  
        /* DCD is OFF */ !E\[SjY@J  
        CPC_TTY_DBG("%s : DCD is OFF\n", cpc_tty->name); sYbH|}  
        stats->tx_errors++; j0-McLc  
        stats->tx_carrier_errors++; USML~]G z  
        CPC_TTY_LOCK(card, flags); $\Lyi#<  
        cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_BUF_CLR); rjA@U<o  
         Bn wzcl  
        if (card->hw.type == PC300_TE) { 7hNb/O004  
            cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, **_&i!dtL  
                cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) & |?m` xO  
                ~(CPLD_REG2_FALC_LED1 << (2 *ch))); AD5) .}[F  
        } cSP*f0n,eo  
P @% .`8  
        CPC_TTY_UNLOCK(card, flags); ENh8kD l5  
8s}J!/2  
        return -EINVAL; L-i>R:N4  
    } m 40m<@  
JHV)ZOO  
    if (cpc_tty_send_to_card(cpc_tty->pc300dev, (void*)buf, count)) { ;]D(33) (  
       /* failed to send */ VkmRh,T  
       CPC_TTY_DBG("%s: trasmition error\n", cpc_tty->name); `\$8`Zb;  
       return 0; {i{xo2<1"  
    } KJhN J  
    return count; >O`l8tM  
} 0Dv JZ|e  
m$Y :0_^-  
/* 3-Bl  
* PC300 TTY Write Room routine pJpNO$$w  
* C*Vd-U  
* This routine returns the numbers of characteres the tty driver will accept &vUq}r%P  
* for queuing to be written. Xh3;   
* o return MTU ?2J?XS>  
*/ [W,|kDK  
static int cpc_tty_write_room(struct tty_struct *tty) ,32xcj}j)r  
{ dJ3IUe  
    st_cpc_tty_area    *cpc_tty; +",S2Qmo  
lPq\=V  
    if (!tty || !tty->driver_data ) { g$37;d3Tx  
        CPC_TTY_DBG("hdlcX-tty: no TTY to write room\n"); E$\~lcq  
        return -ENODEV; +=@^i'  
    } V-W'RunnW  
=jAFgwP\  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; D> ef  
3x*z\VJ  
    if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { `x8B n"  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); 7 _jE[10  
        return -ENODEV; xN->cA$A  
    } LgqGVh3\s  
       fjz) Gp  
    CPC_TTY_DBG("%s: write room\n",cpc_tty->name); %HuyK  
     GlYly5F  
    return CPC_TTY_MAX_MTU; "PWl4a&  
} M].8HwC+  
TRvZ  
/* Q4'C;<\@(Q  
* PC300 TTY chars in buffer routine _2Zp1h,  
* 3}Xc71|v  
* This routine returns the chars number in the transmission buffer >>'C :7+Y  
* o returns 0 ~5aE2w0K   
*/ C 0C0GqN,  
static int cpc_tty_chars_in_buffer(struct tty_struct *tty) :R6Q=g=  
{ >9K//co"of  
    st_cpc_tty_area    *cpc_tty; S'i;xL>  
Utl t<  
    if (!tty || !tty->driver_data ) { 7} O;FX+x  
        CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n"); %e%7oqR?  
        return -ENODEV; HMQI&Lh=U  
    } jZ9[=?   
4iX-(ir,  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; 4YA./j%'  
u=K2Q4  
    if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { L10IF  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); W Ox_y,  
        return -ENODEV; Cnh|D^{s  
    } JJk#,AP  
   5D`26dB2  
    return 0; kA?_%fi1  
} APBK9ky  
mV\$q@sII  
static int pc300_tiocmset(struct tty_struct *tty, GrI&?=S^  
              unsigned int set, unsigned int clear) v548ysE)  
{  -;c  
    st_cpc_tty_area    *cpc_tty; /'&;Q7!)  
?[1SiJT  
    CPC_TTY_DBG("%s: set:%x clear:%x\n", __func__, set, clear); ?T'][q  
:{}_|]>K  
    if (!tty || !tty->driver_data ) { ';YgG<u  
           CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n");     s;.=5wcvi?  
        return -ENODEV; .XH8YT42  
    } "Ai6<:ml  
Wr%7~y*K  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; KFhG(   
p8>%Mflf  
    if (set & TIOCM_RTS) Yv\!vW7I  
        cpc_tty_signal_on(cpc_tty->pc300dev, CTL_RTS); U6j/BJT"  
    if (set & TIOCM_DTR) lgD]{\O$ip  
        cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR); \ aKd5@  
S7sb7c'4 k  
    if (clear & TIOCM_RTS) HYClm|   
        cpc_tty_signal_off(cpc_tty->pc300dev, CTL_RTS); 4O$2]D.\  
    if (clear & TIOCM_DTR) 3:`XG2'  
        cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); 2<6j1D^jM  
W kkxU.xXE  
    return 0; -F`he=Ev9  
} 9YKDguG  
X0i3_RVa  
static int pc300_tiocmget(struct tty_struct *tty) >{&A%b4JF  
{ ([pSVOnIz  
    unsigned int result; $G";2(-k  
    unsigned char status; __\P`S_  
    unsigned long flags; v*TeTA %  
    st_cpc_tty_area  *cpc_tty = (st_cpc_tty_area *) tty->driver_data; &=w|vB)(p  
    pc300dev_t *pc300dev = cpc_tty->pc300dev; _w u*M  
    pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; ~ =.CTm]vf  
    pc300_t *card = (pc300_t *) pc300chan->card; &?<AwtNN  
    int ch = pc300chan->channel; :YvbU Y  
uw_?O[ZA[  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; ww,Z )m  
Rt4di^v  
    CPC_TTY_DBG("%s-tty: tiocmget\n", f%Ke8'&  
        ((struct net_device*)(pc300dev->hdlc))->name); &HF]\`RNr  
TmP8 q  
    CPC_TTY_LOCK(card, flags); -u6#-}S  
    status = cpc_readb(card->hw.scabase+M_REG(CTL,ch)); *\q8BZ  
    CPC_TTY_UNLOCK(card,flags); qei$<j'b  
htHv&  
    result = ((status & CTL_DTR) ? TIOCM_DTR : 0) | /H&aMk}J@y  
         ((status & CTL_RTS) ? TIOCM_RTS : 0); *x,HnHT  
j%xBo:  
    return result; i^/54  
} JMsHK,(  
>]/dOH,A  
/* FdxsU DL  
* PC300 TTY Flush Buffer routine Lk nVqZ|k  
* *zQOJsg"e  
* This routine resets the transmission buffer d]7*mzw^j  
*/ mxL;;-  
static void cpc_tty_flush_buffer(struct tty_struct *tty) Bl4 dhBZoO  
{ {hd-w4"115  
    st_cpc_tty_area    *cpc_tty; R}k69-1vL  
     (,tHL  
    if (!tty || !tty->driver_data ) { ,cQA*;6  
           CPC_TTY_DBG("hdlcX-tty: no TTY to flush buffer\n");     !; WbOnLP  
        return; mQ,{=C=D  
    } # #>a&,  
[=~!w_  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; <!!nI%NC  
IwRQL%  
    if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { ;&mxqY8`'  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); ;,`]O!G:P  
        return; Czh8zB+r  
    } U.Hdbmix  
_3&/(B%H  
    CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name); =uc^433.  
`.8-cz  
    tty_wakeup(tty);     /Sj_y*x1e  
    return; a7 )@BzF#  
} 32y[  
yA}nPXrd  
/* )52#:27F  
* PC300 TTY Hangup routine gMay  
* n)CH^WHL&  
* This routine is called by the tty driver to hangup the interface 1^sbT[%R  
* o clear DTR signal .EzSSU7n)  
*/ swt\Ru6,  
bL MkPty  
static void cpc_tty_hangup(struct tty_struct *tty) -x?Hj/  
{ S)Mby  
    st_cpc_tty_area    *cpc_tty; 6vWii)O.D  
    int res; hXnw..0"  
!PI0oh  
    if (!tty || !tty->driver_data ) { @Yarz1  
        CPC_TTY_DBG("hdlcX-tty: no TTY to hangup\n");     JU2P%3  
        return ; FvA|1c  
    } 3Tw%W0q  
s kY0\V  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; 8J^d7uC  
Gl"wEL*  
    if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { 0#]!#1utg  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); >vxWx[fRu  
        return ; Xky@[Td*  
    } Vy r] x  
    if (!serial_drv.refcount && cpc_tty_unreg_flag) { i8eA_Q  
        cpc_tty_unreg_flag = 0; T7s+9CE  
        CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); ZR2\ dH*  
        if ((res=tty_unregister_driver(&serial_drv))) { x3_,nl  
            CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", . Nk6  
                            cpc_tty->name,res); `>y[wa>9r  
        } GJ>ypEWo  
    } (I!1sE!?1  
    cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); ]%||KC!O  
} 6ku8`WyoF  
w&9F>`VET  
/* *.,8,e8Vq  
* PC300 TTY RX work routine 9QZ}Hn`p  
* This routine treats RX work wH!}qz /  
* o verify read buffer 9M nem*  
* o call the line disc. read du8!3I  
* o free memory %Au T8  
*/ -$b?rt]h1g  
static void cpc_tty_rx_work(struct work_struct *work) wNbTM.@  
{ ~6MMErSj  
    st_cpc_tty_area *cpc_tty; pj j}K  
    unsigned long port; '%:5axg?]  
    int i, j; ,A^L=+  
    volatile st_cpc_rx_buf *buf; }il%AAI9}r  
    char flags=0,flg_rx=1; <G&WYk%u*  
    struct tty_ldisc *ld; Px$'(eMj^3  
O${r^6Hh  
    if (cpc_tty_cnt == 0) return; G1A$PR  
     Vj29L?3  
    for (i=0; (i < 4) && flg_rx ; i++) { 83B\+]{hD  
        flg_rx = 0; d{?)q  
5#P: "U  
        cpc_tty = container_of(work, st_cpc_tty_area, tty_rx_work); ZIDFF  
        port = cpc_tty - cpc_tty_area; I? A~zigO  
+OKA_b"wB  
        for (j=0; j < CPC_TTY_NPORTS; j++) { XpOCQyFnM  
            cpc_tty = &cpc_tty_area[port]; e1oFnu2R  
         ]}5`7  
            if ((buf=cpc_tty->buf_rx.first) != NULL) { FV`3,NFk  
                if (cpc_tty->tty) { TjT](?'o  
                    ld = tty_ldisc_ref(cpc_tty->tty); 20n%o&kG]8  
                    if (ld) { 7%W!k zp>  
                        if (ld->ops->receive_buf) { IM$ 'J  
                            CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); qmQFHC_  
                            ld->ops->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size); }1l}-w`F  
                        } LZbRQ"!!o  
                        tty_ldisc_deref(ld); R,uJK)m  
                    } ZV0) ."^Z  
                }     )0'Y et}  
                cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;  'Dnq+  
                kfree((void *)buf); kg zwlKK  
                buf = cpc_tty->buf_rx.first; u|(aS^H=q  
                flg_rx = 1; FW/6{tm  
            } "sC$%D<oc  
            if (++port == CPC_TTY_NPORTS) port = 0; Pxap;;\  
        } w6%l8+{R  
    } w($XEv;  
} hU |LFjc  
7&#'c8]/qh  
/* L!`*R)I45  
* PC300 TTY RX work routine q=T<^Tk#e  
* \?aOExG I  
* This routine treats RX interrupt. g8C+1G8  
* o read all frames in card =#7s+d-  
* o verify the frame size "X\q%%P=?  
* o read the frame in rx buffer ^XtHF|%0T  
*/ 1 OuSH+  
static void cpc_tty_rx_disc_frame(pc300ch_t *pc300chan) Ufyxw5u5F  
{ VG? yL2y  
    volatile pcsca_bd_t __iomem * ptdescr; 3 t~X:  
    volatile unsigned char status; !$g(&  
    pc300_t *card = (pc300_t *)pc300chan->card; dP$y>%cB  
    int ch = pc300chan->channel; BF@m )w.v  
IO?~b XP  
    /* dma buf read */ {9y9Kr|(P:  
    ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + |j\eBCnH3  
                RX_BD_ADDR(ch, pc300chan->rx_first_bd)); 0:~gW#lD  
    while (pc300chan->rx_first_bd != pc300chan->rx_last_bd) { <6~/sa4GN  
        status = cpc_readb(&ptdescr->status); c`Lpqs`  
        cpc_writeb(&ptdescr->status, 0); Y;~EcM  
        cpc_writeb(&ptdescr->len, 0); Tom}sFl][  
        pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & fo/(()  
                    (N_DMA_RX_BUF - 1); J$o[$G_Z  
        if (status & DST_EOM) { ,:\zXESy4  
            break; /* end of message */ 8Xt=eL/P  
        } &QiAM`MbC=  
        ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + cpc_readl(&ptdescr->next)); zW|$x<M^  
    } EfMG(oI  
} 1"87EP   
2d,wrC<'$  
void cpc_tty_receive(pc300dev_t *pc300dev) e!O &~#'h}  
{ %a%+!wX0x  
    st_cpc_tty_area *cpc_tty; Py(wT%w  
    pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; 3?-V>-[G_  
    pc300_t *card = (pc300_t *)pc300chan->card; C={sE*&dYX  
    int ch = pc300chan->channel; ^v()iF !  
    volatile pcsca_bd_t  __iomem * ptdescr; 2}W6{T'  
    struct net_device_stats *stats = &pc300dev->dev->stats; #)Id J]  
    int rx_len, rx_aux; 0ll,V  
    volatile unsigned char status; + xkMW%e<  
    unsigned short first_bd = pc300chan->rx_first_bd; R$~JhcX*l'  
    st_cpc_rx_buf *new = NULL; &k {t0>  
    unsigned char dsr_rx; |qFN~!  
kr &:;  
    if (pc300dev->cpc_tty == NULL) { y"{UN M|R  
        return; t/4/G']W  
    } :{e`$kz  
lB YS>4~  
    dsr_rx = cpc_readb(card->hw.scabase + DSR_RX(ch)); lUm}nsp=X  
x %!OP\  
    cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; yDl5t-0`  
&AkzSgP  
    while (1) { ^$^Vd@t>a  
        rx_len = 0; Tg}H < T  
        ptdescr = (pcsca_bd_t  __iomem *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd)); [NR0] #h  
        while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { Xqq?S  
            rx_len += cpc_readw(&ptdescr->len); eFeCS{LV+  
            first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1); O>{t}6o  
            if (status & DST_EOM) { e3bAT.P  
                break; `\}zm~  
            } lVO(9sl*i  
            ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase+cpc_readl(&ptdescr->next)); `jl. f  
        } jw&}N6^G  
             v: !7n  
        if (!rx_len) { }pU!1GsO  
            if (dsr_rx & DSR_BOF) { ^!{ oAzy9  
                /* update EDA */ )@};lmPR  
                cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), D(2kb  
                        RX_BD_ADDR(ch, pc300chan->rx_last_bd)); Y?q*hS0!H  
            } M 2U@gC|{  
            kfree(new); ^Ypb"Wx8  
            return; ui:>eYv  
        } Ib<5u  
         YQw/[  
        if (rx_len > CPC_TTY_MAX_MTU) { 0L 4]z'5  
            /* Free RX descriptors */ d%"@#bB  
            CPC_TTY_DBG("%s: frame size is invalid.\n",cpc_tty->name); m/"=5*pA  
            stats->rx_errors++; :D)&>{?  
            stats->rx_frame_errors++; +P<w<GfQ  
            cpc_tty_rx_disc_frame(pc300chan);  s`{#[&[  
            continue; g#bfY=C  
        } A+Pm "|  
         m0q`A5!)  
        new = kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC); fuwpp  
        if (!new) { B[k+#YYY  
            cpc_tty_rx_disc_frame(pc300chan); ztt%l #  
            continue; e&VR>VJEA  
        } H;"N|pBy  
         LKwUpu!  
        /* dma buf read */ q2"'W|I  
        ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + mU0r"\**c3  
                RX_BD_ADDR(ch, pc300chan->rx_first_bd)); clU3#8P!=  
j,V$vKP  
        rx_len = 0;    /* counter frame size */ r5$?4t  
         u{dN>}{  
        while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { 2ucsTh@  
            rx_aux = cpc_readw(&ptdescr->len); Eo3Aak o  
            if ((status & (DST_OVR | DST_CRC | DST_RBIT |  DST_SHRT | DST_ABT)) 7Q4Pjc D  
                || (rx_aux > BD_DEF_LEN)) { 8Nl|\3nl-  
                CPC_TTY_DBG("%s: reception error\n", cpc_tty->name); I]j/ ab7>  
                stats->rx_errors++; qS`|=5f  
                if (status & DST_OVR) { "Z1&z-   
                    stats->rx_fifo_errors++; 6 GevO3  
                } s9Q)6=mE  
                if (status & DST_CRC) { Bo\dt@0;  
                    stats->rx_crc_errors++; 3Tte8]0  
                } GzE3B';g  
                if ((status & (DST_RBIT | DST_SHRT | DST_ABT)) || 113x9+w[  
                    (rx_aux > BD_DEF_LEN))    { "u> sS  
                    stats->rx_frame_errors++; 8=_| qy}l/  
                } )*AA9   
                /* discard remainig descriptors used by the bad frame */ jgfP|oD  
                CPC_TTY_DBG("%s: reception error - discard descriptors", $5 p'+bE  
                        cpc_tty->name); i(qYyO'  
                cpc_tty_rx_disc_frame(pc300chan); c#-97"_8  
                rx_len = 0; i)^ZH#G p  
                kfree(new); "a_D]D(d5  
                new = NULL; g5YsV p  
                break; /* read next frame - while(1) */ >Ki]8 &  
            } NCh(-E  
""KN?qh9  
            if (cpc_tty->state != CPC_TTY_ST_OPEN) { OU964vv  
                /* Free RX descriptors */ b.u8w2(  
                cpc_tty_rx_disc_frame(pc300chan); 2/o/UfYjgF  
                stats->rx_dropped++; %<o$ J~l~  
                rx_len = 0; 7)8}8tY^{  
                kfree(new); jQBdS. }'v  
                new = NULL; *Zo o  
                break; /* read next frame - while(1) */ lM]),}   
            } <$Kv^Y*  
jtOsb91c}  
            /* read the segment of the frame */ >Ti2E+}[M  
            if (rx_aux != 0) { ~0$F V  
                memcpy_fromio((new->data + rx_len), wN0OAbtX'  
                    (void __iomem *)(card->hw.rambase + "+ JwS  
                     cpc_readl(&ptdescr->ptbuf)), rx_aux); h+d;`7Z>  
                rx_len += rx_aux; \36;csu  
            } ,$(v#Tz  
            cpc_writeb(&ptdescr->status,0); 7%x+7  
            cpc_writeb(&ptdescr->len, 0); SG o:FG  
            pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & 80" =Qu{s  
                    (N_DMA_RX_BUF -1); 6G})h!  
            if (status & DST_EOM)break; U[ungvU1U  
             |MR?8A^"  
            ptdescr = (pcsca_bd_t __iomem *) (card->hw.rambase + N5_.m(:  
                    cpc_readl(&ptdescr->next)); YxqQg  
        } lTd2~_  
        /* update pointer */ P+|8MT0  
        pc300chan->rx_last_bd = (pc300chan->rx_first_bd - 1) & 3jVm[c5%]  
                    (N_DMA_RX_BUF - 1) ; <R8Z[H:bV  
        if (!(dsr_rx & DSR_BOF)) { zjZTar1Re  
            /* update EDA */ e{+{,g{iu  
            cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), NKh {iSLm  
                    RX_BD_ADDR(ch, pc300chan->rx_last_bd)); 1KR|i"  
        } *^5,7}9Qo  
        if (rx_len != 0) { /6*.%M>r  
            stats->rx_bytes += rx_len; 6OW-Dif^AG  
         \uPTk)oaB  
            if (pc300dev->trace_on) { D}U<7=\3H  
                cpc_tty_trace(pc300dev, new->data,rx_len, 'R'); WQC6{^/4[1  
            } j7 3@Yi%  
            new->size = rx_len; |6Z M xY  
            new->next = NULL; ,(=]6V  
            if (cpc_tty->buf_rx.first == NULL) { */e5lRO\  
                cpc_tty->buf_rx.first = new; ~ J{{n_G{  
                cpc_tty->buf_rx.last = new; Cb-E<W&2D  
            } else { D8{HOv;d^  
                cpc_tty->buf_rx.last->next = new; meD (ja  
                cpc_tty->buf_rx.last = new; {4q:4 i  
            } BT#g?=n#`  
            schedule_work(&(cpc_tty->tty_rx_work)); |;-r};  
            stats->rx_packets++; vfDb9QP  
        } @h,$&=HY  
    }  (t['  
} u@'zvkb@  
f)P /@rh  
/* ay|{!MkQ  
* PC300 TTY TX work routine itgO#(g$Q  
* gQDK?aQX  
* This routine treats TX interrupt. X1dG'PQ  
* o if need call line discipline wakeup `\0a5UFR  
* o call wake_up_interruptible 5z>\'a1U  
*/ {f3fc8(p  
static void cpc_tty_tx_work(struct work_struct *work) ][1u:V/ U  
{ HwuPjc#  
    st_cpc_tty_area *cpc_tty = ;O11)u?/s|  
        container_of(work, st_cpc_tty_area, tty_tx_work); I*2rS_i[T  
    struct tty_struct *tty; 5/ju it  
AwrK82  
    CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name); 0.0!5D[  
     p00AcUTq  
    if ((tty = cpc_tty->tty) == NULL) { =lD]sk  
        CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name); ,4,c-   
        return; DdO '  
    } L:Eb(z/D  
    tty_wakeup(tty); .U%"oD  
} R  |%  
Zw{tuO7}K  
/* ptQ (7N  
* PC300 TTY send to card routine p2(_YN;s  
* =7,U qMl_  
* This routine send data to card. [ 1GEe  
* o clear descriptors 1z:N$O _v  
* o write data to DMA buffers Zx 1z hc  
* o start the transmission L|w-s4L  
*/ j #YFwX4.  
static int cpc_tty_send_to_card(pc300dev_t *dev,void* buf, int len) 9#6/c  
{ +cH(nZ*f  
    pc300ch_t *chan = (pc300ch_t *)dev->chan; R*m" '|U  
    pc300_t *card = (pc300_t *)chan->card; ,+9r/}K]/  
    int ch = chan->channel; -rlX<(pl)  
    struct net_device_stats *stats = &dev->dev->stats; vDvGT<d  
    unsigned long flags; 18`%WUPnT  
    volatile pcsca_bd_t __iomem *ptdescr; >cL2PN_y  
    int i, nchar; %T\x~)  
    int tosend = len; AoeW<}MO  
    int nbuf = ((len - 1)/BD_DEF_LEN) + 1; -5.%{Go$[  
    unsigned char *pdata=buf; NM.B=<Aw*  
[+z:^a1?V  
    CPC_TTY_DBG("%s:cpc_tty_send_to_cars len=%i", eov-"SJB  
            (st_cpc_tty_area *)dev->cpc_tty->name,len);     $t}1|q|  
Ghc0{M<  
    if (nbuf >= card->chan[ch].nfree_tx_bd) { q+~CA[H5K  
        return 1; Q$j48,e  
    } tvRy8u;  
     Z+(V \  
    /* write buffer to DMA buffers */ T@.D5[q0:  
    CPC_TTY_DBG("%s: call dma_buf_write\n", eUlb6{!y?  
            (st_cpc_tty_area *)dev->cpc_tty->name);     EZBzQ""  
    for (i = 0 ; i < nbuf ; i++) { m)}MkC-  
        ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + d2sq]Q  
            TX_BD_ADDR(ch, card->chan[ch].tx_next_bd)); gw T,D.'Ut  
        nchar = (BD_DEF_LEN > tosend) ? tosend : BD_DEF_LEN; 6QQ oHYtZ  
        if (cpc_readb(&ptdescr->status) & DST_OSB) { qV,j)b3M  
            memcpy_toio((void __iomem *)(card->hw.rambase + NhX.yLb$   
                cpc_readl(&ptdescr->ptbuf)), q/79'>`|ai  
                &pdata[len - tosend], lJ#>Y5Qg  
                nchar); k)Wz b  
            card->chan[ch].nfree_tx_bd--; 9zd/5|W  
            if ((i + 1) == nbuf) { {m:R v&T  
                /* This must be the last BD to be used */ Mk?I}  
                cpc_writeb(&ptdescr->status, DST_EOM); J7o?h9  
            } else { 926oM77  
                cpc_writeb(&ptdescr->status, 0); pr(\?\a  
            } a*y mBGF  
            cpc_writew(&ptdescr->len, nchar); 89mre;v`  
        } else { &S]v+wF  
            CPC_TTY_DBG("%s: error in dma_buf_write\n", MX,0gap  
                    (st_cpc_tty_area *)dev->cpc_tty->name);     H_nJST<v`  
            stats->tx_dropped++; qCN7i&k,  
            return 1; ^/vWK\-  
        } =]"|x7'!  
        tosend -= nchar; Dj"=kL0  
        card->chan[ch].tx_next_bd =  ?Nql7F4  
            (card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1); 8f5^@K\c  
    } *DzPkaYD>  
|Eu~= J7@  
    if (dev->trace_on) { }* JMc+!9@  
        cpc_tty_trace(dev, buf, len,'T'); zAJUL  
    } v"~I( kf$  
*!@x<Hf<  
    /* start transmission */ %Oqe7Cx>+  
    CPC_TTY_DBG("%s: start transmission\n", #SNI dc>9\  
        (st_cpc_tty_area *)dev->cpc_tty->name);     ;tiU OixJ  
     ~1sl.8tF  
    CPC_TTY_LOCK(card, flags); _\PoZ|G4y  
    cpc_writeb(card->hw.scabase + DTX_REG(EDAL, ch), e}AJxBE  
            TX_BD_ADDR(ch, chan->tx_next_bd)); %=y3  
    cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA); q.{/{9  
    cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE); !5!$h` g  
t'x:fO?cp  
    if (card->hw.type == PC300_TE) { JZxF)] ^  
        cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, ; @~*z4U  
            cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) | #!# X3j  
            (CPLD_REG2_FALC_LED1 << (2 * ch))); rd4'y~#S  
    } ,8nZzVo  
    CPC_TTY_UNLOCK(card, flags); ABmDSV5i  
    return 0; /+O8A}  
} #q.G_-H4J@  
[ {LnE:  
/* X.9MOdG70  
*    PC300 TTY trace routine n3j h\  
* <W') ~o}  
*  This routine send trace of connection to application. 2_b'mepV  
*  o clear descriptors =2)t1 H  
*  o write data to DMA buffers vaJXX  
*  o start the transmission }px]   
*/ })vr*[  
}h h^U^ia  
static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx) E9 q;>)}  
{ fO!O" D5  
    struct sk_buff *skb; z}2e;d 7  
) '`AX\  
    if ((skb = dev_alloc_skb(10 + len)) == NULL) { 4 xzJql  
        /* out of memory */ bTp2)a^G  
        CPC_TTY_DBG("%s: tty_trace - out of memory\n", dev->dev->name); F>(#Af9  
        return; )Hm[j)YI  
    } HTyF<K  
! H=k7s  
    skb_put (skb, 10 + len); m>dcb 6B+g  
    skb->dev = dev->dev; h^$}1[  
    skb->protocol = htons(ETH_P_CUST); qpqz. {\  
    skb_reset_mac_header(skb); H<7DcwXv  
    skb->pkt_type = PACKET_HOST; M 8j(1&(:  
    skb->len = 10 + len; )pn7DIXG  
C_ZD<UPA\  
    skb_copy_to_linear_data(skb, dev->dev->name, 5); Q4LlToHn  
    skb->data[5] = '['; e - ]c  
    skb->data[6] = rxtx; }Rxg E~ F  
    skb->data[7] = ']'; 7P^{*!  
    skb->data[8] = ':'; m&0BbyE.z  
    skb->data[9] = ' '; M2P@ &  
    skb_copy_to_linear_data_offset(skb, 10, buf, len); C!k9JAa$Z  
    netif_rx(skb); b\j&!_   
}     <i\zfa'6  
7r[ %| :  
/* tDHHQ  
*    PC300 TTY unregister service routine 7e{X$'  
* 6aZt4Lw2\  
*    This routine unregister one interface. RzJ}CT  
*/ [aZ v?Z  
void cpc_tty_unregister_service(pc300dev_t *pc300dev) mQ60@_"Y=,  
{ Fxth> O`$  
    st_cpc_tty_area *cpc_tty; 0mD;.1:  
    ulong flags; K[>@'P}y  
    int res; VIYksv   
}A)36  
    if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == NULL) { jw(> @SXz  
        CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->name); %*6oUb  
        return; 6SBvn%  
    } nHA`B.:B  
    CPC_TTY_DBG("%s: cpc_tty_unregister_service", cpc_tty->name); j_'rhEdLP  
h$7Fe +#I#  
    if (cpc_tty->pc300dev != pc300dev) { DkF2R @  
        CPC_TTY_DBG("%s: invalid tty ptr=%s\n", n &\'Hm  
        pc300dev->dev->name, cpc_tty->name); +fP/|A8P  
        return; L+~YCat|$U  
    } VXc+Wm*W  
7l#2,d4  
    if (--cpc_tty_cnt == 0) { m$E^u[  
        if (serial_drv.refcount) { i B!hEbz  
            CPC_TTY_DBG("%s: unregister is not possible, refcount=%d", j #I:6yA3  
                            cpc_tty->name, serial_drv.refcount); /q"d`!h)w  
            cpc_tty_cnt++; <K#'3&*$s  
            cpc_tty_unreg_flag = 1; f5yux}A{  
            return; yg+IkQDf4U  
        } else { k Kp6  
            CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); Ng'ZAG;O  
            if ((res=tty_unregister_driver(&serial_drv))) { JXLWRe  
                CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", B=gsd0^]  
                                cpc_tty->name,res); FSU%?PxO  
            } 1ntkM?  
        } {NY~JFM  
    } >)n4s Mq  
    CPC_TTY_LOCK(pc300dev->chan->card,flags); S\3AW,c]w  
    cpc_tty->tty = NULL; 4Ay`rG  
    CPC_TTY_UNLOCK(pc300dev->chan->card, flags); q1TW?\pjb:  
    cpc_tty->tty_minor = 0; 2l)9Lz=;L  
    cpc_tty->state = CPC_TTY_ST_IDLE; gVnws E  
} $\,BpZ }3  
iJZ|[jEDV  
/* uh5Pn#da^  
* PC300 TTY trigger poll routine ]/o12pI  
* This routine is called by pc300driver to treats Tx interrupt. oGJ*Rn)Z  
*/ rW FcIh5  
void cpc_tty_trigger_poll(pc300dev_t *pc300dev) ovDJ{3L6O  
{ 5i4V5N>3  
    st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; AvrL9D  
    if (!cpc_tty) { c:llOHA  
        return; ;J(rw  
    } A{aw< P|+  
    schedule_work(&(cpc_tty->tty_tx_work)); pM&]&Nk  
} Tf#2"(!  
97(Xu=tX  
/* Q&Z4r9+Z  
* PC300 TTY reset var routine r:c@17  
* This routine is called by pc300driver to init the TTY area. g= FDm*  
*/ SE;Tujwhqi  
! EX?m }7  
void cpc_tty_reset_var(void) ~[| V3h4v  
{ ?E+:]j_  
    int i ; W,HH *!  
JO2ZS6k[  
    CPC_TTY_DBG("hdlcX-tty: reset variables\n"); =f4[=C$&`  
    /* reset  the tty_driver structure - serial_drv */ /ojO>Y[<   
    memset(&serial_drv, 0, sizeof(struct tty_driver)); +}7Ea:K   
    for (i=0; i < CPC_TTY_NPORTS; i++){ 11)/] ?/j  
        memset(&cpc_tty_area,0, sizeof(st_cpc_tty_area)); j{{~ZM  
    } OU,PO2xX9  
} yV:EK{E  


评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

一般

差劲
快速回复
限150 字节
 
上一个 下一个