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

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

上一主题 下一主题
离线mark83136
 

性别:
帅哥
发帖
1210
金币
360
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看楼主 倒序阅读 使用道具 0楼 发表于: 2015-07-07
,wyEo>>4)  
/* {L M Q  
* pc300_tty.c    Cyclades-PC300(tm) TTY Driver. C9>^!?>  
* -KqMSf&9  
* Author:    Regina Kodato <reginak@cyclades.com> PevT`\>  
* Ov.oyke4  
* Copyright:    (c) 1999-2002 Cyclades Corp. 7sVO?:bj}  
* N)KN!!  
*    This program is free software; you can redistribute it and/or x Y}.mP  
*  modify it under the terms of the GNU General Public License Scmew  
*  as published by the Free Software Foundation; either version Emk:@$3{r  
*  2 of the License, or (at your option) any later version. T~?&hZ>  
*   H8Z|gq1r  
*  $Log: pc300_tty.c,v $ 91k-os(4]  
*  Revision 3.7  2002/03/07 14:17:09  henrique )cm^;(#pV  
*  License data fixed T[J8zL O  
* &.Yu%=}  
*  Revision 3.6  2001/12/10 12:29:42  regina e8z?) 4T  
*  Fix the MLPPP bug $ ]^Io)}f@  
* u|Ng>lU  
*  Revision 3.5  2001/10/31 11:20:05  regina -"bC[WN  
*  automatic pppd starts SzUH6|=.R=  
* j& L@L.d  
*  Revision 3.4  2001/08/06 12:01:51  regina }0OQm?xh  
*  problem in DSR_DE bit @CC 6 `D  
* %V#? 1{  
*  Revision 3.3  2001/07/26 22:58:41  regina Rgz zbW  
*  update EDA value &uf|Le4  
* #"[EVF0%1D  
*  Revision 3.2  2001/07/12 13:11:20  regina 0}g~69Z1=  
*  bug fix - DCD-OFF in pc300 tty driver m;>:mwU  
* 5hDPX \  
*    DMA transmission bug fix }=u#,nDl>$  
*   -L wz T  
*  Revision 3.1  2001/06/22 13:13:02  regina +zl [C  
*  MLPPP implementation lKS 2OOYC`  
* $ao7pvU6  
*/ [ -R[rF  
(/!zHq  
#include <linux/module.h> iD>H{1 h  
#include <linux/kernel.h> _gl1Qtv@rf  
#include <linux/errno.h> ++=jh6  
#include <linux/string.h> /?}2OCq  
#include <linux/init.h> 6Z@T /"mU(  
#include <linux/netdevice.h> Ejyo oO45  
#include <linux/spinlock.h> &=wvlI52`  
#include <linux/slab.h> SPtx_+ Q)S  
#include <linux/if.h> zV"'-iP  
#include <linux/skbuff.h> r<Q0zKW!jN  
/* TTY includes */ Qzv&  
#include <linux/tty.h> `9acR>00$  
#include <linux/tty_flip.h> !=6\70lJ  
#include <linux/serial.h> -<(RYMk*)  
!y$+RA7\  
#include <asm/io.h> n ON]YDg  
#include <asm/uaccess.h> #+|0o-  
}gd'pgN"t  
#include "pc300.h" nB4+*=$E+-  
lLU8eHf\  
/* defines and macros */ 1L=)93,M  
/* TTY Global definitions */ R pT7Nr  
#define    CPC_TTY_NPORTS    8    /* maximum number of the sync tty connections */ +HG*T[%/  
#define    CPC_TTY_MAJOR    CYCLADES_MAJOR     }|Bs|$q  
#define CPC_TTY_MINOR_START    240    /* minor of the first PC300 interface */ X-psao0tI`  
4"\%/kG  
#define CPC_TTY_MAX_MTU    2000     iMQ0Sq-%1  
dKa2_|k'  
/* tty interface state */ 8wn{W_5a  
#define    CPC_TTY_ST_IDLE    0 "h8fTB\7S\  
#define CPC_TTY_ST_INIT    1    /* configured with MLPPP and up */ x1}Ono3"T  
#define CPC_TTY_ST_OPEN    2    /* opened by application */ v'r)d-T   
o3h>)4  
#define    CPC_TTY_LOCK(card,flags)\ 7&w|  
    do {\ #WAX&<m  
        spin_lock_irqsave(&card->card_lock, flags);    \ (]zi;  
    } while (0) >G As&\4hs  
Wmx3@]<  
#define CPC_TTY_UNLOCK(card,flags)    \ [c v!YE  
    do {\ 4^:$|\?]  
        spin_unlock_irqrestore(&card->card_lock, flags);    \ {P )O#  
    } while (0) R'fEw3^  
kr-5O0tmf  
//#define    CPC_TTY_DBG(format,a...)    printk(format,##a) ^@Z8 _PZo  
#define    CPC_TTY_DBG(format,a...) aS~~*UHW  
dAy\IfZX=  
/* data structures */ )g KC}_h=  
typedef struct _st_cpc_rx_buf { >=.3Vydi1  
    struct _st_cpc_rx_buf    *next; !-ZY_  
    int        size; FW{K[km^P  
    unsigned char    data[1]; QXgfjo  
} st_cpc_rx_buf; t=fP^bJ  
{.J<^V  
struct st_cpc_rx_list { v7%}ey[  
    st_cpc_rx_buf    *first; Sf@xP.d  
    st_cpc_rx_buf    *last; z:1t vG  
}; s-~`Ao' <  
Ty7)j]b"zl  
typedef    struct _st_cpc_tty_area { l+X\>,  
    int        state;        /* state of the TTY interface */ VmRfnH"  
    int        num_open;     DhD##5a  
    unsigned int     tty_minor;    /* minor this interface */ m)Wq*&,o  
    volatile struct st_cpc_rx_list buf_rx;    /* ptr. to reception buffer */ 8q; aCtei  
    unsigned char*    buf_tx;        /* ptr. to transmission buffer */ kO$n0y5e  
    pc300dev_t*    pc300dev;    /* ptr. to info struct in PC300 driver */ n^*,JL 9@  
    unsigned char    name[20];    /* interf. name + "-tty" */ !T 9CpIM%  
    struct tty_struct *tty;         ^)C#  
    struct work_struct tty_tx_work; /* tx work - tx interrupt */ z#GSt ZT  
    struct work_struct tty_rx_work; /* rx work - rx interrupt */ .K`n;lVs  
    } st_cpc_tty_area; "<^n@=g'q  
}w8yYI  
/* TTY data structures */ G\^<MR|  
static struct tty_driver serial_drv; Mc$rsqDz  
5".bM8o  
/* local variables */ $RUK<JN$6  
static st_cpc_tty_area    cpc_tty_area[CPC_TTY_NPORTS]; c;zk{dP   
w\{#nrhYU  
static int cpc_tty_cnt = 0;    /* number of intrfaces configured with MLPPP */ XL'\$f  
static int cpc_tty_unreg_flag = 0; -Kcjnl92i  
ze21Uj1x*  
/* TTY functions prototype */ !!w(`kmn1  
static int cpc_tty_open(struct tty_struct *tty, struct file *flip); F/3L^k]  
static void cpc_tty_close(struct tty_struct *tty, struct file *flip); }Z< Sca7  
static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count); r3KNRr@  
static int cpc_tty_write_room(struct tty_struct *tty); LXPO@2QF  
static int cpc_tty_chars_in_buffer(struct tty_struct *tty); ]Tg@wMgI  
static void cpc_tty_flush_buffer(struct tty_struct *tty); # s7e/GdKb  
static void cpc_tty_hangup(struct tty_struct *tty); v>N*f~n  
static void cpc_tty_rx_work(struct work_struct *work); 1b2  
static void cpc_tty_tx_work(struct work_struct *work); };<?W){!H  
static int cpc_tty_send_to_card(pc300dev_t *dev,void *buf, int len); C[d1n#@r  
static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx); N">#fYix  
static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char); t*H|*L#YR  
static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char); eZ-fy,E  
kk4+>mk  
static int pc300_tiocmset(struct tty_struct *, unsigned int, unsigned int); :"H? phk  
static int pc300_tiocmget(struct tty_struct *); '2|P-/jU  
Sw5:T  
/* functions called by PC300 driver */ F^S]7{  
void cpc_tty_init(pc300dev_t *dev); [x]~G  
void cpc_tty_unregister_service(pc300dev_t *pc300dev); (h g6<`  
void cpc_tty_receive(pc300dev_t *pc300dev); 1LAd5X  
void cpc_tty_trigger_poll(pc300dev_t *pc300dev); oN%zpz;OR  
void cpc_tty_reset_var(void); %d%?\jVb  
KWAd~8,mk  
/* &\b(  
* PC300 TTY clear "signal" O'{kNr{u  
*/ [-\U)>MY(p  
static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char signal) ,np|KoG|M  
{ (: ?bQA'Td  
    pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; +{C)^!zBK  
    pc300_t *card = (pc300_t *) pc300chan->card; lyyf&?2  
    int ch = pc300chan->channel; NL;sn"  
    unsigned long flags; *c&OAL]  
" Up(Vj@  
    CPC_TTY_DBG("%s-tty: Clear signal %x\n", u0G tzk  
        pc300dev->dev->name, signal); p<}y'7(  
    CPC_TTY_LOCK(card, flags); 3la`S$c  
    cpc_writeb(card->hw.scabase + M_REG(CTL,ch), \NEk B&^n  
        cpc_readb(card->hw.scabase+M_REG(CTL,ch))& signal); g j]8/~lr  
    CPC_TTY_UNLOCK(card,flags); AO|1m$xf  
} 7YK6e  
kM&-t&7  
/* Aq$1#1J  
* PC300 TTY set "signal" to ON cMnN} '  
*/ C=v+e%)x@  
static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char signal) "Z;({a$v  
{ O:pg+o&  
    pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; DT)] [V^w  
    pc300_t *card = (pc300_t *) pc300chan->card;  N&kUTSd  
    int ch = pc300chan->channel; 9F?-zn;2s  
    unsigned long flags; >5"e<mwD7d  
'mTY56Yq  
    CPC_TTY_DBG("%s-tty: Set signal %x\n", pV_zePyOn  
        pc300dev->dev->name, signal); ZbjUOlE02  
    CPC_TTY_LOCK(card, flags); z@pa;_  
    cpc_writeb(card->hw.scabase + M_REG(CTL,ch), =5V7212  
        cpc_readb(card->hw.scabase+M_REG(CTL,ch))& ~signal); ?%Tx% dB  
    CPC_TTY_UNLOCK(card,flags); J YA>Q&  
} yXv@yn  
HW,v"  
BHYguS^qz  
static const struct tty_operations pc300_ops = { UnYb}rF#%  
    .open = cpc_tty_open, ,Z _@]D@  
    .close = cpc_tty_close, @TX@78fWz=  
    .write = cpc_tty_write, *" C9F/R  
    .write_room = cpc_tty_write_room, -)3+/4Q(  
    .chars_in_buffer = cpc_tty_chars_in_buffer, 96QY0  
    .tiocmset = pc300_tiocmset, b4bd^nrqV  
    .tiocmget = pc300_tiocmget, 47 Bg[  
    .flush_buffer = cpc_tty_flush_buffer, F4WX$;1  
    .hangup = cpc_tty_hangup, JtxVF !v  
}; \AA9 m'BZ  
{;& U5<NO  
rqdN%=C  
/* y 5=r r3%v  
* PC300 TTY initialization routine "::2]3e  
* wVnmT94  
* This routine is called by the PC300 driver during board configuration W*CRxGyZCl  
* (ioctl=SIOCSP300CONF). At this point the adapter is completely zwJ&K;"y(  
* initialized. K[0z$T\  
* o verify kernel version (only 2.4.x) ?wCX:? g  
* o register TTY driver Zv=pS (9  
* o init cpc_tty_area struct e@TwZ6l  
*/ ztX$kX:_m  
void cpc_tty_init(pc300dev_t *pc300dev) !6RDq`  
{ {=mGXd`x?l  
    unsigned long port; yt="kZ  
    int aux; knph549  
    st_cpc_tty_area * cpc_tty; ,+6u6  
qGEp 6b H  
    /* hdlcX - X=interface number */ -T{2R:\{  
    port = pc300dev->dev->name[4] - '0'; j>:N0:  
    if (port >= CPC_TTY_NPORTS) { l 'wu-  
        printk("%s-tty: invalid interface selected (0-%i): %li", zNoFM/1Vb  
            pc300dev->dev->name, ~LV]cX2J(  
            CPC_TTY_NPORTS-1,port); yt5<J-m  
        return; m*N8!1Ot  
    } PlLt^q.z[  
.Wy'  
    if (cpc_tty_cnt == 0) { /* first TTY connection -> register driver */ 'ROz|iJ  
        CPC_TTY_DBG("%s-tty: driver init, major:%i, minor range:%i=%i\n", \R]2YY`EP  
            pc300dev->dev->name, Og1vD5a  
            CPC_TTY_MAJOR, CPC_TTY_MINOR_START, 5V =mj+X?  
            CPC_TTY_MINOR_START+CPC_TTY_NPORTS); 7H{1i  
        /* initialize tty driver struct */ su1fsoL0  
        memset(&serial_drv,0,sizeof(struct tty_driver)); t[>UAr1Vt  
        serial_drv.magic = TTY_DRIVER_MAGIC; (PGw{_  
        serial_drv.owner = THIS_MODULE; 6o3#<ap<  
        serial_drv.driver_name = "pc300_tty"; ( B\ UZb  
        serial_drv.name = "ttyCP"; jaKW[@<  
        serial_drv.major = CPC_TTY_MAJOR; @P75f5p}<  
        serial_drv.minor_start = CPC_TTY_MINOR_START; 42"nbJ  
        serial_drv.num = CPC_TTY_NPORTS; R5^6Kwu  
        serial_drv.type = TTY_DRIVER_TYPE_SERIAL; SE^l`.U@  
        serial_drv.subtype = SERIAL_TYPE_NORMAL; .IdbaH _a  
!3k-' ),z&  
        serial_drv.init_termios = tty_std_termios; 7_l Wr  
        serial_drv.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; 9wldd*r  
        serial_drv.flags = TTY_DRIVER_REAL_RAW; v^t7)nx^  
&;P\e  
        /* interface routines from the upper tty layer to the tty driver */ 5=|h~/.k  
        tty_set_operations(&serial_drv, &pc300_ops); q mFbq<&  
2-8Dc4H]r  
        /* register the TTY driver */ =d^hiR!GN  
        if (tty_register_driver(&serial_drv)) { GU2TQx{V  
            printk("%s-tty: Failed to register serial driver! ", ~Hub\kn  
                pc300dev->dev->name); `VO;\s$5j  
               return; ly[d V.<P  
        } :dULsl$Nz  
3I~.'>Pd  
        memset((void *)cpc_tty_area, 0, X5 or5v  
                                sizeof(st_cpc_tty_area) * CPC_TTY_NPORTS); 5!qf{4j  
    } !'F1Ht  
ZlMT) ~fM&  
    cpc_tty = &cpc_tty_area[port]; dEKu5GI  
     tNzO1BK  
    if (cpc_tty->state != CPC_TTY_ST_IDLE) { ut560,h~  
        CPC_TTY_DBG("%s-tty: TTY port %i, already in use.\n", S!=R\_{u$  
                pc300dev->dev->name, port); {fHor  
        return; ,;w~ VZ4  
    } Nr2,m"R{  
}Cw,m0KV/  
    cpc_tty_cnt++; l~]] RgU  
    cpc_tty->state = CPC_TTY_ST_INIT; v :/!OvLe  
    cpc_tty->num_open= 0; 7R:Ij[dV  
    cpc_tty->tty_minor = port + CPC_TTY_MINOR_START; U{oM*[  
    cpc_tty->pc300dev = pc300dev; IA.7If&k  
DAWF =p]  
    INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work); "%^_.Db>|  
    INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work); W5`pQdk  
     k@|px#kq  
    cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = NULL; wW\@^5  
54>0Dv??H  
    pc300dev->cpc_tty = (void *)cpc_tty; jwE=  
     H2: Zda#  
    aux = strlen(pc300dev->dev->name); q/I( e  
    memcpy(cpc_tty->name, pc300dev->dev->name, aux); *|\bS "  
    memcpy(&cpc_tty->name[aux], "-tty", 5); +39uKOrZ  
     0Pf88'6  
    cpc_open(pc300dev->dev); B?8*-0a'[  
    cpc_tty_signal_off(pc300dev, CTL_DTR); w$f_z*/  
6X h7Bx1  
    CPC_TTY_DBG("%s: Initializing TTY Sync Driver, tty major#%d minor#%i\n", ?|W3RK;  
            cpc_tty->name,CPC_TTY_MAJOR,cpc_tty->tty_minor); ,s 3|  
    return; PL$XXj>|:  
} /K&9c !]$C  
u]Vt>Ywu  
/* )?#K0o[<  
* PC300 TTY OPEN routine 0:[A4S`X  
* {*O+vtir%  
* This routine is called by the tty driver to open the interface mm: TR?^  
* o verify minor zu @|"f^`  
* o allocate buffer to Rx and Tx K a(B&.  
*/ c{y'&3\  
static int cpc_tty_open(struct tty_struct *tty, struct file *flip) )$E){(Aa  
{ U3:|!CC)T  
    int port ; V>)/z|[  
    st_cpc_tty_area *cpc_tty; #`|Nm3b  
G2I%^.s  
    if (!tty) { cK]n"6N[  
        return -ENODEV; v%*don  
    } "0;WYw?  
ma*#*4  
    port = tty->index; mq4Zy3H   
o}KVT%}  
    if ((port < 0) || (port >= CPC_TTY_NPORTS)){ p )JR5z  
        CPC_TTY_DBG("pc300_tty: open invalid port %d\n", port); #btf|\D  
        return -ENODEV; p!:oT1U  
    } ^|Fy!kp  
us|Hb  
    cpc_tty = &cpc_tty_area[port]; sd%)g<t  
     COHBju fmR  
    if (cpc_tty->state == CPC_TTY_ST_IDLE){ Posz|u<x  
        CPC_TTY_DBG("%s: open - invalid interface, port=%d\n", >e6OlIW  
                    cpc_tty->name, tty->index); +0%r@hTv&>  
        return -ENODEV; XTF[4#WO  
    } klQmo30i  
=bD.5,F)  
    if (cpc_tty->num_open == 0) { /* first open of this tty */ oA-,>:}g{  
        if (!cpc_tty_area[port].buf_tx){ l]zQSXip  
            cpc_tty_area[port].buf_tx = kmalloc(CPC_TTY_MAX_MTU,GFP_KERNEL); I[K4/91  
            if (!cpc_tty_area[port].buf_tx) { au50%sA~  
                CPC_TTY_DBG("%s: error in memory allocation\n",cpc_tty->name); bskoi;)u  
                return -ENOMEM; nrev!h  
            } lJFy(^KQG,  
        } ^rq\kf*]  
4pT^ *  
        if (cpc_tty_area[port].buf_rx.first) { Psx"[2iZm  
            unsigned char * aux; sNpA!!\PM  
            while (cpc_tty_area[port].buf_rx.first) { @u/CNx,`X  
                aux = (unsigned char *)cpc_tty_area[port].buf_rx.first; /"La@M37  
                cpc_tty_area[port].buf_rx.first = cpc_tty_area[port].buf_rx.first->next; qdpi-*2  
                kfree(aux); AzJ;E tR  
            } 3^ UoK  
            cpc_tty_area[port].buf_rx.first = NULL; tTTHQ7o*BD  
            cpc_tty_area[port].buf_rx.last = NULL; C=&n1/  
        } *\'t$se+  
z~`X4Segw  
        cpc_tty_area[port].state = CPC_TTY_ST_OPEN; $6UU58>n  
        cpc_tty_area[port].tty = tty; "!vY{9,  
        tty->driver_data = &cpc_tty_area[port]; +=9iq3<yfS  
;[ Dxk$"  
        cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR); J'ce?_\?PY  
    } VV1sadS:S`  
fTR6]i;  
    cpc_tty->num_open++; aG;F=e  
%"(HjanH  
    CPC_TTY_DBG("%s: opening TTY driver\n", cpc_tty->name); cd1-2-4U  
     !YGHJwW:  
    /* avisar driver PC300 */ !Q~>)$Cf^  
    return 0; E]n]_{BN]  
} Vv(buG  
T\p>wiY2|F  
/* O6?{@l  
* PC300 TTY CLOSE routine Q.Nw#r+m  
* /# Jvt  
* This routine is called by the tty driver to close the interface ba G_7>Q9H  
* o call close channel in PC300 driver (cpc_closech) a"YVr'|  
* o free Rx and Tx buffers zOSUYn  
*/ p : z ][I  
ly34aD/p~,  
static void cpc_tty_close(struct tty_struct *tty, struct file *flip) .^=I&X/P  
{ #'KM$l,P  
    st_cpc_tty_area    *cpc_tty; |(W wh$  
    unsigned long flags; R2~y<^.V`Y  
    int res; 3t+{~{Dj  
{G vGV  
    if (!tty || !tty->driver_data ) { /dg?6XT/  
        CPC_TTY_DBG("hdlx-tty: no TTY in close\n"); J/Y9X ,  
        return; T5}3Y3G,6  
    } -E6av|c,F  
x*F- d2D  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; d m"R0>  
\,/ozfJ7dT  
    if ((cpc_tty->tty != tty)|| (cpc_tty->state != CPC_TTY_ST_OPEN)) { yc]_?S>9  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); jEQ_#KKYJ  
        return; f@ |[pT  
    } zP0<4E$M`  
       "zNS6I?rzE  
    if (!cpc_tty->num_open) { .?g=mh79(  
        CPC_TTY_DBG("%s: TTY is closed\n",cpc_tty->name); "2C}Pr ,p8  
        return; yw+]S  
    } ZG H 7_K  
ec#`9w$  
    if (--cpc_tty->num_open > 0) { SbX^DAlB1  
        CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name); rz|Sjtq  
        return; X4:84  
    } viU}  
um$U3'0e  
    cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); dkEbP*y Xg  
}O crA/  
    CPC_TTY_LOCK(cpc_tty->pc300dev->chan->card, flags);  /* lock irq */ `UzH *w@e  
    cpc_tty->tty = NULL; <!G /&T  
    cpc_tty->state = CPC_TTY_ST_INIT; (T2HUmkQ6  
    CPC_TTY_UNLOCK(cpc_tty->pc300dev->chan->card, flags); /* unlock irq */ ) C~#W  
     3)>re&  
    if (cpc_tty->buf_rx.first) { )Rb t0   
        unsigned char * aux; @eBo7#Zr  
        while (cpc_tty->buf_rx.first) { e^~dx}X  
            aux = (unsigned char *)cpc_tty->buf_rx.first; @qcUxu4  
            cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; AFsieJ  
            kfree(aux); J| &aqY  
        } T;Kv<G;  
        cpc_tty->buf_rx.first = NULL; |j'@no_rv  
        cpc_tty->buf_rx.last = NULL; H&*&n}vh5y  
    } tOnOzD  
     * wqR.n?  
    kfree(cpc_tty->buf_tx); 8Wtr,%82  
    cpc_tty->buf_tx = NULL; +K'YVB U}  
]5*H/8Ke7  
    CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name); YSB> WBS-<  
     V+>RF  
    if (!serial_drv.refcount && cpc_tty_unreg_flag) { 0hkYexX73  
        cpc_tty_unreg_flag = 0; ?\4kV*/Cqz  
        CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); ^|h_[>  
        if ((res=tty_unregister_driver(&serial_drv))) { 3VMaD@nYa  
            CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", `r=^{Y  
                            cpc_tty->name,res); :+9. v  
        } *dB3Gu{ +  
    } En-=z`j G  
    return; &~.|9P/45  
} dQH8s  
tD}{/`{_t  
/* kd&~_=Q  
* PC300 TTY WRITE routine TGG=9a]m  
* K( MZ!>{  
* This routine is called by the tty driver to write a series of characters fOSJdX0e|Q  
* to the tty device. The characters may come from user or kernel space. h^IizrqU  
* o verify the DCD signal +  rN#  
* o send characters to board and start the transmission jsV1~1:83  
*/ m>[G-~0?kI  
static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) 1GR|$E  
{ *pS3xit~  
    st_cpc_tty_area    *cpc_tty; h }&dvd  
    pc300ch_t *pc300chan; <uoVGV5N  
    pc300_t *card; DD7D&@As  
    int ch; mDwuJf8}  
    unsigned long flags; ]x& R=)P  
    struct net_device_stats *stats; uW}M1kq?+l  
2" v{  
    if (!tty || !tty->driver_data ) { C)qG<PW.!  
        CPC_TTY_DBG("hdlcX-tty: no TTY in write\n"); S9b=?? M)  
        return -ENODEV; FDBNKQV  
    } lnMU5[g{  
o"N\l{#s  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; !L|VmLqa  
*6_>/!ywI  
    if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { ZW;Re5?DJ  
        CPC_TTY_DBG("%s: TTY is not opened\n", cpc_tty->name); XI ><;#  
        return -ENODEV; .Q</0*sp  
    } W1M Bk[:Q  
_iqaKYT$  
    if (count > CPC_TTY_MAX_MTU) { N1:)Z`r  
        CPC_TTY_DBG("%s: count is invalid\n",cpc_tty->name); tnb'\}Vn  
        return -EINVAL;        /* frame too big */ 8&x&Ou$("V  
    } 2I=4l  
.ArOZ{lKD>  
    CPC_TTY_DBG("%s: cpc_tty_write data len=%i\n",cpc_tty->name,count); Ho%%voJBS  
     !YM:?%B  
    pc300chan = (pc300ch_t *)((pc300dev_t*)cpc_tty->pc300dev)->chan; 2B6y1"B  
    stats = &cpc_tty->pc300dev->dev->stats; {Aj=Rj@  
    card = (pc300_t *) pc300chan->card; X"f]  
    ch = pc300chan->channel; GIkVU6Q}  
nGJ+.z  
    /* verify DCD signal*/ 'OhGSs|  
    if (cpc_readb(card->hw.scabase + M_REG(ST3,ch)) & ST3_DCD) { >^@~}]L  
        /* DCD is OFF */ l~1l~Gx_&n  
        CPC_TTY_DBG("%s : DCD is OFF\n", cpc_tty->name); Fv^>^txh  
        stats->tx_errors++; L[+4/a!HQ  
        stats->tx_carrier_errors++; +OI nf_O  
        CPC_TTY_LOCK(card, flags); mX @xV*  
        cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_BUF_CLR); HXB & 6  
         j3?@p5E(  
        if (card->hw.type == PC300_TE) { /5>A 2y  
            cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, VB+_ kR6Zv  
                cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) & ~^3U@( :  
                ~(CPLD_REG2_FALC_LED1 << (2 *ch))); A(C0/|#V  
        } H7{kl  
o8A(Cg}  
        CPC_TTY_UNLOCK(card, flags); %NhZTmWm  
@C~gU@F  
        return -EINVAL; -?)z@Lc  
    } QcdAg%"yy  
Jd|E 4h~(  
    if (cpc_tty_send_to_card(cpc_tty->pc300dev, (void*)buf, count)) { =@;\9j  
       /* failed to send */ 5G#2#Al(F  
       CPC_TTY_DBG("%s: trasmition error\n", cpc_tty->name); %x^U3"7  
       return 0; A22'qgKm@  
    } B1U7z1<  
    return count; =#I/x=L:  
} nG| NRp  
Q,o"[ &Gp  
/* U]E~7C  
* PC300 TTY Write Room routine ^{O1+7d[.  
* Hq <!&  
* This routine returns the numbers of characteres the tty driver will accept \-Q6z 8  
* for queuing to be written. R{Me~L?  
* o return MTU ?[X^'zz}  
*/ Jj+Hj[(@  
static int cpc_tty_write_room(struct tty_struct *tty) |s !7U  
{ n--s[Kdo8  
    st_cpc_tty_area    *cpc_tty;  OJ# d  
~N+H7T.L  
    if (!tty || !tty->driver_data ) { A9y3B^\*  
        CPC_TTY_DBG("hdlcX-tty: no TTY to write room\n"); Kl :x?"g)  
        return -ENODEV; a7fn{VU8  
    } eC$ Jdf  
Y c>.P  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; MF5o\-&dN  
M+M\3U  
    if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { &UX:KW`=  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); @aWd0e]  
        return -ENODEV; Dgz^s^fxU  
    } E*UE?4FSw|  
       H')8p;~{}  
    CPC_TTY_DBG("%s: write room\n",cpc_tty->name); x?G"58  
     -h&KC{Xab  
    return CPC_TTY_MAX_MTU; CGZ3-OW@E  
} |#O>DdKHT  
zhC5%R &n/  
/* Wtj* Z.=:  
* PC300 TTY chars in buffer routine \hqjk:o  
* `mDCX  
* This routine returns the chars number in the transmission buffer s>e)\9c  
* o returns 0 lD1m<AC  
*/ qL!pDZk  
static int cpc_tty_chars_in_buffer(struct tty_struct *tty) Nb/Z+  
{ z CFXQi  
    st_cpc_tty_area    *cpc_tty; {bO O?pp  
GsNZr=;C  
    if (!tty || !tty->driver_data ) { jtQ}  
        CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n"); ,\ zx4 *  
        return -ENODEV; 43BqNQ0  
    } E Ks4N4k  
LVBE+{P\5?  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; pn aSOyR  
F+m;y  
    if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { ;0:[X+"(  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); X32{y973hT  
        return -ENODEV; 63pd W/\j  
    } !,cfA';S  
   l[b`4  
    return 0; Dq9*il;'  
} Kr@6m80E5  
7) Qq  
static int pc300_tiocmset(struct tty_struct *tty, ')KuLVE}S  
              unsigned int set, unsigned int clear) ~y8KQ-1n"  
{ ?!$:I8T  
    st_cpc_tty_area    *cpc_tty; t,308Z  
[ih^VlZ  
    CPC_TTY_DBG("%s: set:%x clear:%x\n", __func__, set, clear); lWk/vj<5  
R b=q #  
    if (!tty || !tty->driver_data ) { +;N;r/d_i  
           CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n");     'Em633  
        return -ENODEV; _+}#  
    } gH|:=vfYUR  
C?t!Uvs  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; L}pj+xB  
&[y+WrGG  
    if (set & TIOCM_RTS) XWq@47FR  
        cpc_tty_signal_on(cpc_tty->pc300dev, CTL_RTS); 4~z-&>%  
    if (set & TIOCM_DTR) b_a6|  
        cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR); 4* V[^mht  
JO&L1<B{v  
    if (clear & TIOCM_RTS) a<l DT_2b  
        cpc_tty_signal_off(cpc_tty->pc300dev, CTL_RTS); -$cO0RSY  
    if (clear & TIOCM_DTR) O{ |Ug~  
        cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); Oc%W_Gb7  
oR'u&\mB  
    return 0; Nd%j0lj  
} E5g|*M.+f  
QEc4l[^{.B  
static int pc300_tiocmget(struct tty_struct *tty) yUEvva  
{ X v$"B-j  
    unsigned int result; -nDY3$U/  
    unsigned char status; Pd;Gc@'~  
    unsigned long flags; K aNO&%qX  
    st_cpc_tty_area  *cpc_tty = (st_cpc_tty_area *) tty->driver_data; A/88WC$v  
    pc300dev_t *pc300dev = cpc_tty->pc300dev; 1}3tpO;  
    pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; WlmkM?@  
    pc300_t *card = (pc300_t *) pc300chan->card; 9i+`,r  
    int ch = pc300chan->channel; ;={3H_{3  
W7"UhM  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; C!W0L`r  
 N}KL'  
    CPC_TTY_DBG("%s-tty: tiocmget\n", U}DLzn|w  
        ((struct net_device*)(pc300dev->hdlc))->name); )F,z pGG  
'C) v?!19  
    CPC_TTY_LOCK(card, flags); %'.3t|zH  
    status = cpc_readb(card->hw.scabase+M_REG(CTL,ch)); CO`?M,x>  
    CPC_TTY_UNLOCK(card,flags); I*H($ a  
t {H{xd  
    result = ((status & CTL_DTR) ? TIOCM_DTR : 0) | CI^s~M >  
         ((status & CTL_RTS) ? TIOCM_RTS : 0); 1G )I|v9R  
zV8{|-2]No  
    return result; 2BV]@]qB  
} +P%k@w#<Z  
#|=Q5"wU  
/* . Ky)Co  
* PC300 TTY Flush Buffer routine "w3%BbIx  
* moL3GV%]Gq  
* This routine resets the transmission buffer cc0T b  
*/ L5r02VzbD  
static void cpc_tty_flush_buffer(struct tty_struct *tty) 6o4Y]C2W{1  
{ 0G`@^`  
    st_cpc_tty_area    *cpc_tty; HYl~)O>  
     st)qw]Dn;Y  
    if (!tty || !tty->driver_data ) { !wTrWD!  
           CPC_TTY_DBG("hdlcX-tty: no TTY to flush buffer\n");     ]Hg6Mz>Mj  
        return; 8^sh@j2L  
    } P|t2%:_  
B_ bZa  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; 5&qBG@Hw]  
Z?u}?-b1\H  
    if ((cpc_tty->tty != tty) ||  (cpc_tty->state != CPC_TTY_ST_OPEN)) { ^G4@cR.An  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); {@hJPK8  
        return; Uo;a$sR  
    } b>Ea_3T/  
Hb0_QT~  
    CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name); /  QT>"  
3Uej]}c  
    tty_wakeup(tty);     k~)@D| ?  
    return; nf1O8FwRb  
} G|u)eW  
tXcZl!3x  
/* ~BMUea(  
* PC300 TTY Hangup routine TjHt:%7.  
* l+j !CvtI  
* This routine is called by the tty driver to hangup the interface 6sG5 n7E-A  
* o clear DTR signal w)&?9?~  
*/ #4<=Ira5  
\>x1#Vr>#V  
static void cpc_tty_hangup(struct tty_struct *tty) KW$.Yy  
{ FmSE ]et  
    st_cpc_tty_area    *cpc_tty; z_Hkw3?  
    int res; e$/y ~!  
(I/ iD.A  
    if (!tty || !tty->driver_data ) { A]ZQ?- L/  
        CPC_TTY_DBG("hdlcX-tty: no TTY to hangup\n");     ~tn$AtK  
        return ; %xr'96d  
    } 'x5p ?m  
o`G6!  
    cpc_tty = (st_cpc_tty_area *) tty->driver_data; ,&y_^-|d  
&2S-scP  
    if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { H3 -?cy  
        CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); xT(0-o*  
        return ; +\$c_9|C+  
    } z[6avW"q  
    if (!serial_drv.refcount && cpc_tty_unreg_flag) { "!CVm{7[  
        cpc_tty_unreg_flag = 0; &XCP@@T  
        CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); [5ncBY*A7  
        if ((res=tty_unregister_driver(&serial_drv))) { n.t5:SW  
            CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", Mdq|: ^px  
                            cpc_tty->name,res); #<X4RJ  
        } RA?_j$  
    } 6TTu[*0NT  
    cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); :{4C2qK>  
} mE_%  
:,fT^izew  
/* =CO) Q2  
* PC300 TTY RX work routine Bh'!aipk  
* This routine treats RX work ]=9 d'WL  
* o verify read buffer ay|jq "a  
* o call the line disc. read !&:Cp_  
* o free memory rIb~@cR)  
*/ @,7r<6E  
static void cpc_tty_rx_work(struct work_struct *work) /nsBUM[;  
{ ![$`Ivro`  
    st_cpc_tty_area *cpc_tty; % 8wBZ~1-  
    unsigned long port; dm]g:KWg  
    int i, j; Hzj8o3  
    volatile st_cpc_rx_buf *buf; `e fiX^  
    char flags=0,flg_rx=1; p(nO~I2E  
    struct tty_ldisc *ld; #d*0 )w  
-2!S>P Zs  
    if (cpc_tty_cnt == 0) return; Z=Cw7E  
     L>mM6$l  
    for (i=0; (i < 4) && flg_rx ; i++) { -agB ]j  
        flg_rx = 0; 1zCu1'Wv  
'n>44_7L  
        cpc_tty = container_of(work, st_cpc_tty_area, tty_rx_work); ,|A6l?iV  
        port = cpc_tty - cpc_tty_area; o.w/ ?  
8#g}ev@|u  
        for (j=0; j < CPC_TTY_NPORTS; j++) { vq.o;q /  
            cpc_tty = &cpc_tty_area[port]; lJN#_V0qW  
         k=mLcP  
            if ((buf=cpc_tty->buf_rx.first) != NULL) { !L|l(<C  
                if (cpc_tty->tty) { /W`CqJk-*.  
                    ld = tty_ldisc_ref(cpc_tty->tty); ,X1M!'  
                    if (ld) { U;TS7A3  
                        if (ld->ops->receive_buf) { kZo# Ny  
                            CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); w=<E)  
                            ld->ops->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size); UJQTArf  
                        } [s`B0V`04  
                        tty_ldisc_deref(ld); ,A7:zxnc.V  
                    } y z!L:1DG  
                }     EpKZ.lCU  
                cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; %rJDpB{  
                kfree((void *)buf); $]Ix(7@W  
                buf = cpc_tty->buf_rx.first; 8_w6% md  
                flg_rx = 1; 0Ze&GK'Hf  
            } _>]/.w2=  
            if (++port == CPC_TTY_NPORTS) port = 0; )Ute  
        }  B9y5NX  
    } EC0B6!C&7  
} Y:\]d1C  
g!' x5#]n  
/* {5D%<Te  
* PC300 TTY RX work routine DBHHJD/q  
* 0^Vw^]w  
* This routine treats RX interrupt. SP<Sv8Okj  
* o read all frames in card !vRN'/(Vyu  
* o verify the frame size 7Hv 6>z#m  
* o read the frame in rx buffer $xdo=4;|  
*/ Q]GS#n  
static void cpc_tty_rx_disc_frame(pc300ch_t *pc300chan) 1%vE7a>{  
{ t( V 2  
    volatile pcsca_bd_t __iomem * ptdescr; {fDRVnI?  
    volatile unsigned char status; +X+R8  
    pc300_t *card = (pc300_t *)pc300chan->card; H)E,([   
    int ch = pc300chan->channel; {d'B._#i  
"%+||IyW  
    /* dma buf read */ 1 oKY7i$  
    ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + "~EAt$  
                RX_BD_ADDR(ch, pc300chan->rx_first_bd)); Sin)]zG~0  
    while (pc300chan->rx_first_bd != pc300chan->rx_last_bd) { 0sKo NzE  
        status = cpc_readb(&ptdescr->status); Q?LzL(OioN  
        cpc_writeb(&ptdescr->status, 0); k$m'ebrS.~  
        cpc_writeb(&ptdescr->len, 0); 9z{}DBA  
        pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & Lg,ObVt!  
                    (N_DMA_RX_BUF - 1); eN|zD?ba&  
        if (status & DST_EOM) { B8T5?bl  
            break; /* end of message */ qGR1$\]  
        } 8YE4ln  
        ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + cpc_readl(&ptdescr->next)); Fje /;p  
    } Q.7X3A8  
} ~N; dX[@BT  
fV7 k{dR  
void cpc_tty_receive(pc300dev_t *pc300dev) !Sy9v  
{ "QS(4yw?jg  
    st_cpc_tty_area *cpc_tty; +}( ]7du  
    pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; G7,v:dlK   
    pc300_t *card = (pc300_t *)pc300chan->card; uEr.LCAS  
    int ch = pc300chan->channel; .Jg<H %%f  
    volatile pcsca_bd_t  __iomem * ptdescr; s/~pr.>-l  
    struct net_device_stats *stats = &pc300dev->dev->stats; <3tf(?*,k]  
    int rx_len, rx_aux; ow 6\j:$?  
    volatile unsigned char status; z;@<J8I  
    unsigned short first_bd = pc300chan->rx_first_bd; +/%4E %  
    st_cpc_rx_buf *new = NULL; 7^Us  
    unsigned char dsr_rx; s"nntC  
Sh-B!  
    if (pc300dev->cpc_tty == NULL) { n%;tVa  
        return; GmJ \3]{PZ  
    } #')] ~Xa  
;sf'"UnL  
    dsr_rx = cpc_readb(card->hw.scabase + DSR_RX(ch)); !=;Evf  
A>F&b1  
    cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; yGWl8\,j0  
7KRNTnd  
    while (1) { xDekC~ Zq  
        rx_len = 0; H3d|eO4+W  
        ptdescr = (pcsca_bd_t  __iomem *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd)); #z.\pd  
        while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { K^GvU0\  
            rx_len += cpc_readw(&ptdescr->len); Gv8Z  
            first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1); \!uf*=d  
            if (status & DST_EOM) { {i3x\|  
                break; *"F*6+}w"  
            } Qd% (]L[N.  
            ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase+cpc_readl(&ptdescr->next)); TQ/#  
        } X,o ]tgg=  
             d@cyQFX  
        if (!rx_len) { "Ya ;&F.'  
            if (dsr_rx & DSR_BOF) { em^2\*sxpA  
                /* update EDA */ s%> u[-9U  
                cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), r[kHVT8  
                        RX_BD_ADDR(ch, pc300chan->rx_last_bd)); Sqmjf@o$>  
            } hN1 [*cF  
            kfree(new); o 0b\<}  
            return; ci(BPnQ  
        } l{ fL~O  
         b^8"EBo  
        if (rx_len > CPC_TTY_MAX_MTU) { ao2o!-?!t  
            /* Free RX descriptors */ aOoWB^;6  
            CPC_TTY_DBG("%s: frame size is invalid.\n",cpc_tty->name); biffBC:q  
            stats->rx_errors++; }!s$ / Kn  
            stats->rx_frame_errors++; Z,XivU&  
            cpc_tty_rx_disc_frame(pc300chan); ov!L8 9`[u  
            continue; +{)V%"{u:  
        } Wk-. dJ  
         _A]~`/0;`  
        new = kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC); =5%}CbUU)4  
        if (!new) { &|zV Wl  
            cpc_tty_rx_disc_frame(pc300chan); l$!NEOK  
            continue; *;t_V laZ  
        } !a5e{QG0  
         RhjU^,%  
        /* dma buf read */ j=>WWlZ  
        ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + `wLmGv+V  
                RX_BD_ADDR(ch, pc300chan->rx_first_bd)); =E~SaT  
^'sOWIzeiY  
        rx_len = 0;    /* counter frame size */ SnO,-Rg  
         !$o9:[B  
        while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { ,Qe`(vU*s  
            rx_aux = cpc_readw(&ptdescr->len); tE=$#  
            if ((status & (DST_OVR | DST_CRC | DST_RBIT |  DST_SHRT | DST_ABT)) A#79$[>w  
                || (rx_aux > BD_DEF_LEN)) { WPu%{/ [  
                CPC_TTY_DBG("%s: reception error\n", cpc_tty->name); E@="n<uS  
                stats->rx_errors++; ooYs0/,{  
                if (status & DST_OVR) { oX/#Mct{s  
                    stats->rx_fifo_errors++; #: ,X^"w3  
                } ,(#n8|q4  
                if (status & DST_CRC) { d k|X&)xTJ  
                    stats->rx_crc_errors++; 5hiuBf<  
                } jLul:* L  
                if ((status & (DST_RBIT | DST_SHRT | DST_ABT)) || o`ODz[04  
                    (rx_aux > BD_DEF_LEN))    { z]i/hU  
                    stats->rx_frame_errors++; LA837%)  
                } 90$`AMR  
                /* discard remainig descriptors used by the bad frame */ r3Ih]|FK#  
                CPC_TTY_DBG("%s: reception error - discard descriptors", ;wr]_@<~  
                        cpc_tty->name); +G!;:o  
                cpc_tty_rx_disc_frame(pc300chan); 8ax3"G  
                rx_len = 0; :OY7y`hRG  
                kfree(new); sE(mK<{pk  
                new = NULL; FCYZ9L5uF  
                break; /* read next frame - while(1) */ hN:2(x  
            } UDa\*  
TUO#6  
            if (cpc_tty->state != CPC_TTY_ST_OPEN) { =Sn!'@%U]  
                /* Free RX descriptors */ v#KE"m  
                cpc_tty_rx_disc_frame(pc300chan); Aa%ks+1  
                stats->rx_dropped++; Bk1gE((  
                rx_len = 0; C? b_E  
                kfree(new); zB{be_Tw  
                new = NULL; {D&:^f  
                break; /* read next frame - while(1) */ 4\8k~ #  
            } =CO#Q$  
~48mCD  
            /* read the segment of the frame */ * @j#13.  
            if (rx_aux != 0) { }EHmVPe  
                memcpy_fromio((new->data + rx_len), *W<g%j-a  
                    (void __iomem *)(card->hw.rambase + .J|" bs9  
                     cpc_readl(&ptdescr->ptbuf)), rx_aux); }Rq-IRa'  
                rx_len += rx_aux; .gHL(*1P  
            } Ibl==Irk  
            cpc_writeb(&ptdescr->status,0); 5 %aT  
            cpc_writeb(&ptdescr->len, 0); W?auY_+P  
            pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & YJrZ  
                    (N_DMA_RX_BUF -1); "PPn^{bYm  
            if (status & DST_EOM)break; C0Ti9  
             uH!;4@ uI  
            ptdescr = (pcsca_bd_t __iomem *) (card->hw.rambase + ma26|N5  
                    cpc_readl(&ptdescr->next)); y3C$%yv0  
        } LaiUf_W#X  
        /* update pointer */ >@d=\Kyu  
        pc300chan->rx_last_bd = (pc300chan->rx_first_bd - 1) & E%+1^ L  
                    (N_DMA_RX_BUF - 1) ; 4;d9bd)A  
        if (!(dsr_rx & DSR_BOF)) { 1Q$Z'E}SK@  
            /* update EDA */ b$)XS  
            cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), ^?tF'l`  
                    RX_BD_ADDR(ch, pc300chan->rx_last_bd));  kQm\;[R  
        } pfvNVu  
        if (rx_len != 0) { Tp/+{|~  
            stats->rx_bytes += rx_len; $ V"7UA22  
         "eal Yveu  
            if (pc300dev->trace_on) {  i'9  
                cpc_tty_trace(pc300dev, new->data,rx_len, 'R'); ]"M4fA  
            } %.D@{O  
            new->size = rx_len; .Su9fj y%  
            new->next = NULL; Iih~rWJ  
            if (cpc_tty->buf_rx.first == NULL) { &wZ:$lK#o  
                cpc_tty->buf_rx.first = new; SNd]c  
                cpc_tty->buf_rx.last = new; GVp2| \-L  
            } else { dKyX70Zy9  
                cpc_tty->buf_rx.last->next = new; aOj5b>>  
                cpc_tty->buf_rx.last = new; qN_jsJ  
            } z|SLH<~  
            schedule_work(&(cpc_tty->tty_rx_work)); PRCr7f  
            stats->rx_packets++; ghiFI<)VY  
        } q-}J0vu\K  
    } 2FS,B\d  
} S<LHNZu|^A  
N*My2t_+E  
/* |nj%G<  
* PC300 TTY TX work routine Piz/vH6M}  
* T{j&w%(z  
* This routine treats TX interrupt. iffRGnN^e  
* o if need call line discipline wakeup ~>ACMO  
* o call wake_up_interruptible PZ;O pp  
*/ I=pT fkTT  
static void cpc_tty_tx_work(struct work_struct *work) -U=bC   
{ h7  >  
    st_cpc_tty_area *cpc_tty = 0BIH.ZV#  
        container_of(work, st_cpc_tty_area, tty_tx_work); ]ba O{pJi  
    struct tty_struct *tty; ` oYrW0Vm  
W6~B~L  
    CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name); 6?ylSQ]1  
     pUr.<yc&u  
    if ((tty = cpc_tty->tty) == NULL) { avk0pY(n  
        CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name); hun/H4f|  
        return; Y] nY.5irL  
    } o$YL\ <qp  
    tty_wakeup(tty); uV*&a~  
} O&irgc!  
g(MeCoCc  
/* ?!~CX`eMZ  
* PC300 TTY send to card routine ek#{!9-  
* Ut8yA"Y~  
* This routine send data to card. t*^Q`V wQ  
* o clear descriptors vh+Ih Gi  
* o write data to DMA buffers [*#ms=Zdc  
* o start the transmission [:sV;37s  
*/ 0AFjO)  
static int cpc_tty_send_to_card(pc300dev_t *dev,void* buf, int len) BfIGw  
{ K9gfS V>]  
    pc300ch_t *chan = (pc300ch_t *)dev->chan; qI"@ PI!s  
    pc300_t *card = (pc300_t *)chan->card; q?{wRBVVB  
    int ch = chan->channel; a! P?RbW  
    struct net_device_stats *stats = &dev->dev->stats; C jsy1gA  
    unsigned long flags; +dk}$w[ g  
    volatile pcsca_bd_t __iomem *ptdescr; a4L8MgF&$-  
    int i, nchar; FU~ Ip  
    int tosend = len; ]7-*1kL8=~  
    int nbuf = ((len - 1)/BD_DEF_LEN) + 1; $AUC#<*C  
    unsigned char *pdata=buf; o6ec\v!l-  
4l E j/#}  
    CPC_TTY_DBG("%s:cpc_tty_send_to_cars len=%i", BYrj#n5  
            (st_cpc_tty_area *)dev->cpc_tty->name,len);     WeE>4>^  
*<zfe.  
    if (nbuf >= card->chan[ch].nfree_tx_bd) { soXeHjNl  
        return 1; y'pAhdF  
    } p0UR5A>p  
     ?x"<0k1g  
    /* write buffer to DMA buffers */ *obBo6!zM  
    CPC_TTY_DBG("%s: call dma_buf_write\n", 5EIh5Y EU>  
            (st_cpc_tty_area *)dev->cpc_tty->name);     vz*QzVk1  
    for (i = 0 ; i < nbuf ; i++) { @]t}bF]  
        ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + )&<BQIv9/  
            TX_BD_ADDR(ch, card->chan[ch].tx_next_bd)); JV Fn=Mw  
        nchar = (BD_DEF_LEN > tosend) ? tosend : BD_DEF_LEN; m49GCo k+  
        if (cpc_readb(&ptdescr->status) & DST_OSB) { noC ]&4b  
            memcpy_toio((void __iomem *)(card->hw.rambase + Y'`w.+9  
                cpc_readl(&ptdescr->ptbuf)), U`D/~KJ{Y  
                &pdata[len - tosend], Tz]t.]!&E  
                nchar); _K3?0<=4  
            card->chan[ch].nfree_tx_bd--; ogH{   
            if ((i + 1) == nbuf) { AF>J8V  
                /* This must be the last BD to be used */ tpO%)*  
                cpc_writeb(&ptdescr->status, DST_EOM); OW\r }  
            } else { V.6h6B!vB  
                cpc_writeb(&ptdescr->status, 0); B)O{+avu  
            } |vw0:\/ H  
            cpc_writew(&ptdescr->len, nchar); %,E\8{I+  
        } else { >fPa>[_1  
            CPC_TTY_DBG("%s: error in dma_buf_write\n", iVLfAN @  
                    (st_cpc_tty_area *)dev->cpc_tty->name);     N2vSJ\u  
            stats->tx_dropped++; F??})YX  
            return 1; <<W{nSm#  
        } ] hGU.C"(  
        tosend -= nchar; $+!/=8R)  
        card->chan[ch].tx_next_bd = !jGe_xB}~  
            (card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1); -uXf?sTV  
    } V6B`q;lA  
UmcPpZ  
    if (dev->trace_on) { Ds? @ LE|  
        cpc_tty_trace(dev, buf, len,'T'); fgK1+sW  
    } qR/~a  
K>hQls+  
    /* start transmission */ lM~ 3yBy  
    CPC_TTY_DBG("%s: start transmission\n", c"Ddw'?e  
        (st_cpc_tty_area *)dev->cpc_tty->name);     gE]6]L  
     *]NG@^y  
    CPC_TTY_LOCK(card, flags); NKd}g  
    cpc_writeb(card->hw.scabase + DTX_REG(EDAL, ch), E*'sk  
            TX_BD_ADDR(ch, chan->tx_next_bd)); xr}3vJ7  
    cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA); O%L]*vIr  
    cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE); }lt5!u~}  
"`qmeZ$rg  
    if (card->hw.type == PC300_TE) { T^> ST  
        cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, Zvz Zs  
            cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) | SEa'>UG  
            (CPLD_REG2_FALC_LED1 << (2 * ch))); Fcz7   
    } 7ESSx"^B  
    CPC_TTY_UNLOCK(card, flags); o{7wPwQ;*  
    return 0; mQdF+b1o  
} S-l<+O1fy  
^)oBa=jL4  
/* 'c7C*6;a  
*    PC300 TTY trace routine =jXBF.  
* 4zyN>f|  
*  This routine send trace of connection to application. vqO d`_)  
*  o clear descriptors LK\L}<;1V  
*  o write data to DMA buffers M#%l}  
*  o start the transmission 3m%oXT  
*/ 4eH:eCZze  
g2 7 iE  
static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx) ]!CMo+  
{ oGt,^!V1  
    struct sk_buff *skb; 6 G.(o  
'EzKu~*  
    if ((skb = dev_alloc_skb(10 + len)) == NULL) { 9U~fc U6  
        /* out of memory */ !\|_,pSB  
        CPC_TTY_DBG("%s: tty_trace - out of memory\n", dev->dev->name); #&0G$~  
        return; |H-%F?<{  
    } |i_+b@Lul  
_L?MYkD  
    skb_put (skb, 10 + len); j.=&qYc0"  
    skb->dev = dev->dev; >7g #e,d   
    skb->protocol = htons(ETH_P_CUST); e}lF#$  
    skb_reset_mac_header(skb); pmda9V4  
    skb->pkt_type = PACKET_HOST; \Lu aI  
    skb->len = 10 + len; gOiZ8K!  
O-P'Ff"}t  
    skb_copy_to_linear_data(skb, dev->dev->name, 5); 4eVQO%&2  
    skb->data[5] = '['; nA owFdCD  
    skb->data[6] = rxtx; qzon);#7w  
    skb->data[7] = ']'; 0?V{u`*  
    skb->data[8] = ':'; m\zCHX#n  
    skb->data[9] = ' '; D6+^Qmu"p  
    skb_copy_to_linear_data_offset(skb, 10, buf, len); 3CL1Z\8To  
    netif_rx(skb); DVJuX~'|!  
}     TAL,(&[s  
L%S(z)xX3  
/* W%ml/ 4  
*    PC300 TTY unregister service routine M./1.k&@  
*  4,g_$)  
*    This routine unregister one interface. _2Zc?*4  
*/ |P_voht  
void cpc_tty_unregister_service(pc300dev_t *pc300dev) >]{{5oOQ>  
{ r+=%Ag  
    st_cpc_tty_area *cpc_tty; ?)NgODU  
    ulong flags; zv .#9^/y  
    int res; &=f] a  
J497 >w[  
    if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == NULL) { B:)PUBb  
        CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->name); SfSWjq  
        return; W3+;1S$k  
    } d+qeZGg^A  
    CPC_TTY_DBG("%s: cpc_tty_unregister_service", cpc_tty->name); ^O0trM>h-  
C6"{-{H  
    if (cpc_tty->pc300dev != pc300dev) { z`H|]${X  
        CPC_TTY_DBG("%s: invalid tty ptr=%s\n", vzX%x ul  
        pc300dev->dev->name, cpc_tty->name); ]ZR}Pm/CA  
        return; 8Y"R@'~  
    } >//yvkZ9,  
Cl6P,C  
    if (--cpc_tty_cnt == 0) {  "tT68  
        if (serial_drv.refcount) { w`GjQIA  
            CPC_TTY_DBG("%s: unregister is not possible, refcount=%d", :(Ak:  
                            cpc_tty->name, serial_drv.refcount); _ <Ip0?N  
            cpc_tty_cnt++; _|r/* (hh  
            cpc_tty_unreg_flag = 1; ajCe&+  
            return; x)R1aq  
        } else { Prc (  
            CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); 'QSj-  
            if ((res=tty_unregister_driver(&serial_drv))) { ~@#s<a,%;  
                CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", GX+Gqj.  
                                cpc_tty->name,res); V= g u'~  
            } g& ou[_A  
        } i);BTwW)#]  
    } 3mQ3mV:  
    CPC_TTY_LOCK(pc300dev->chan->card,flags); |F4)&xN\  
    cpc_tty->tty = NULL; g '+2bQ  
    CPC_TTY_UNLOCK(pc300dev->chan->card, flags); XE'3p6  
    cpc_tty->tty_minor = 0; s .@Szq  
    cpc_tty->state = CPC_TTY_ST_IDLE; `*o ko[\3  
} /H?) qk  
|Ed?s  
/* U:AB%gr[  
* PC300 TTY trigger poll routine 5d;(D i5z  
* This routine is called by pc300driver to treats Tx interrupt. v4]#Nc$~T  
*/ ], IQ~  
void cpc_tty_trigger_poll(pc300dev_t *pc300dev) CZ!gu Y=  
{ a|5<L  
    st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; 00LL&ot  
    if (!cpc_tty) { mGpBj9jr1  
        return; zh{I;~syh  
    } lDL(,ZZS`  
    schedule_work(&(cpc_tty->tty_tx_work)); x"7PnN|~  
} 6<%b}q9Mo  
Z,-J tl  
/* #Vhr 1;j  
* PC300 TTY reset var routine $azK M,<q  
* This routine is called by pc300driver to init the TTY area. vA{DF{S 4  
*/ QFB2,k6jN  
} rX)A\ g6  
void cpc_tty_reset_var(void) 0h kZ  
{ \j<aFOT(  
    int i ; bw)E;1zo  
D;hJK-Y  
    CPC_TTY_DBG("hdlcX-tty: reset variables\n"); _H@8qR  
    /* reset  the tty_driver structure - serial_drv */ r]'[qaP  
    memset(&serial_drv, 0, sizeof(struct tty_driver)); RA!8AS?  
    for (i=0; i < CPC_TTY_NPORTS; i++){ x6Tpt^N}  
        memset(&cpc_tty_area,0, sizeof(st_cpc_tty_area)); g,G{%dGsk  
    } fo=@ X>S  
} uF ;8B]"  


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

精彩

感动

搞笑

开心

愤怒

一般

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