[j?<9 /*
~qS/90, * pc300_tty.c Cyclades-PC300(tm) TTY Driver.
]CZLaID~
*
W\,lII0 * Author: Regina Kodato <
reginak@cyclades.com>
0'hx w3# *
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 *
SSLshY~d * Revision 3.5 2001/10/31 11:20:05 regina
~It+|X=Kx * automatic pppd starts
Z]TVH8%|k *
0lCd,a2: * 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; *
|/^aLj^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- Hv gK_' #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=TF 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...)
kL PO+lg+ (m3I#L /* data structures */
nL+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];
0bPJEEd } 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<\ 71L\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 */
S4 k^&$; pc300dev_t* pc300dev; /* ptr. to info struct in PC300 driver */
ND e[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;
J I+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);
m0xJ05Zx 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 */
EzzTJ> 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%PCe9 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
pgCd * o init cpc_tty_area struct
#0}Ok98P */
VMaS;)0f@ void cpc_tty_init(pc300dev_t *pc300dev)
9Tqo LX {
?lF mXZy` unsigned long port;
7;^((.]ln int aux;
{d| |q<.- st_cpc_tty_area * cpc_tty;
-<8B, 7rH'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",
$+7 ci~gs pc300dev->dev->name,
cvhlRI%6 CPC_TTY_MAJOR, CPC_TTY_MINOR_START,
+e U`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#SAAu 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::5 W-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 #= }
8 aZ$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);
MMgx|" 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)
wz=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;
jO8k6<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` qp~gP if (cpc_tty_area[port].buf_rx.first) {
y%cO#P@ unsigned char * aux;
\40YGFO while (cpc_tty_area[port].buf_rx.first) {
*#&*`iJ( aux = (unsigned char *)cpc_tty_area[port].buf_rx.first;
'{[),*nC n 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;
Fn|gVR }
R,_d1^|*w K : LL_, /*
=f 7r69I" * 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)
q4k@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:#dl\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 }
~P f5ORoe -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);
d5 j_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"eV4j return -ENODEV;
Ju` [m }
><?BqRm+ tx7~SUr 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;
uV6g[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 3 x*z\VJ if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) {
`x8Bn" 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 + TR vZ /*
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 */
C0C0GqN, 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<