diff options
Diffstat (limited to 'drivers/net/wan/pc300_tty.c')
-rw-r--r-- | drivers/net/wan/pc300_tty.c | 1097 |
1 files changed, 1097 insertions, 0 deletions
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c new file mode 100644 index 00000000000..d47d2cd1047 --- /dev/null +++ b/drivers/net/wan/pc300_tty.c | |||
@@ -0,0 +1,1097 @@ | |||
1 | /* | ||
2 | * pc300_tty.c Cyclades-PC300(tm) TTY Driver. | ||
3 | * | ||
4 | * Author: Regina Kodato <reginak@cyclades.com> | ||
5 | * | ||
6 | * Copyright: (c) 1999-2002 Cyclades Corp. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * $Log: pc300_tty.c,v $ | ||
14 | * Revision 3.7 2002/03/07 14:17:09 henrique | ||
15 | * License data fixed | ||
16 | * | ||
17 | * Revision 3.6 2001/12/10 12:29:42 regina | ||
18 | * Fix the MLPPP bug | ||
19 | * | ||
20 | * Revision 3.5 2001/10/31 11:20:05 regina | ||
21 | * automatic pppd starts | ||
22 | * | ||
23 | * Revision 3.4 2001/08/06 12:01:51 regina | ||
24 | * problem in DSR_DE bit | ||
25 | * | ||
26 | * Revision 3.3 2001/07/26 22:58:41 regina | ||
27 | * update EDA value | ||
28 | * | ||
29 | * Revision 3.2 2001/07/12 13:11:20 regina | ||
30 | * bug fix - DCD-OFF in pc300 tty driver | ||
31 | * | ||
32 | * DMA transmission bug fix | ||
33 | * | ||
34 | * Revision 3.1 2001/06/22 13:13:02 regina | ||
35 | * MLPPP implementation | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/module.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/errno.h> | ||
42 | #include <linux/string.h> | ||
43 | #include <linux/init.h> | ||
44 | #include <linux/netdevice.h> | ||
45 | #include <linux/spinlock.h> | ||
46 | #include <linux/slab.h> | ||
47 | #include <linux/if.h> | ||
48 | #include <linux/skbuff.h> | ||
49 | /* TTY includes */ | ||
50 | #include <linux/tty.h> | ||
51 | #include <linux/tty_flip.h> | ||
52 | #include <linux/serial.h> | ||
53 | |||
54 | #include <asm/io.h> | ||
55 | #include <asm/uaccess.h> | ||
56 | |||
57 | #include "pc300.h" | ||
58 | |||
59 | /* defines and macros */ | ||
60 | /* TTY Global definitions */ | ||
61 | #define CPC_TTY_NPORTS 8 /* maximum number of the sync tty connections */ | ||
62 | #define CPC_TTY_MAJOR CYCLADES_MAJOR | ||
63 | #define CPC_TTY_MINOR_START 240 /* minor of the first PC300 interface */ | ||
64 | |||
65 | #define CPC_TTY_MAX_MTU 2000 | ||
66 | |||
67 | /* tty interface state */ | ||
68 | #define CPC_TTY_ST_IDLE 0 | ||
69 | #define CPC_TTY_ST_INIT 1 /* configured with MLPPP and up */ | ||
70 | #define CPC_TTY_ST_OPEN 2 /* opened by application */ | ||
71 | |||
72 | #define CPC_TTY_LOCK(card,flags)\ | ||
73 | do {\ | ||
74 | spin_lock_irqsave(&card->card_lock, flags); \ | ||
75 | } while (0) | ||
76 | |||
77 | #define CPC_TTY_UNLOCK(card,flags) \ | ||
78 | do {\ | ||
79 | spin_unlock_irqrestore(&card->card_lock, flags); \ | ||
80 | } while (0) | ||
81 | |||
82 | //#define CPC_TTY_DBG(format,a...) printk(format,##a) | ||
83 | #define CPC_TTY_DBG(format,a...) | ||
84 | |||
85 | /* data structures */ | ||
86 | typedef struct _st_cpc_rx_buf { | ||
87 | struct _st_cpc_rx_buf *next; | ||
88 | int size; | ||
89 | unsigned char data[1]; | ||
90 | } st_cpc_rx_buf; | ||
91 | |||
92 | struct st_cpc_rx_list { | ||
93 | st_cpc_rx_buf *first; | ||
94 | st_cpc_rx_buf *last; | ||
95 | }; | ||
96 | |||
97 | typedef struct _st_cpc_tty_area { | ||
98 | int state; /* state of the TTY interface */ | ||
99 | int num_open; | ||
100 | unsigned int tty_minor; /* minor this interface */ | ||
101 | volatile struct st_cpc_rx_list buf_rx; /* ptr. to reception buffer */ | ||
102 | unsigned char* buf_tx; /* ptr. to transmission buffer */ | ||
103 | pc300dev_t* pc300dev; /* ptr. to info struct in PC300 driver */ | ||
104 | unsigned char name[20]; /* interf. name + "-tty" */ | ||
105 | struct tty_struct *tty; | ||
106 | struct work_struct tty_tx_work; /* tx work - tx interrupt */ | ||
107 | struct work_struct tty_rx_work; /* rx work - rx interrupt */ | ||
108 | } st_cpc_tty_area; | ||
109 | |||
110 | /* TTY data structures */ | ||
111 | static struct tty_driver serial_drv; | ||
112 | |||
113 | /* local variables */ | ||
114 | static st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS]; | ||
115 | |||
116 | static int cpc_tty_cnt = 0; /* number of intrfaces configured with MLPPP */ | ||
117 | static int cpc_tty_unreg_flag = 0; | ||
118 | |||
119 | /* TTY functions prototype */ | ||
120 | static int cpc_tty_open(struct tty_struct *tty, struct file *flip); | ||
121 | static void cpc_tty_close(struct tty_struct *tty, struct file *flip); | ||
122 | static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count); | ||
123 | static int cpc_tty_write_room(struct tty_struct *tty); | ||
124 | static int cpc_tty_chars_in_buffer(struct tty_struct *tty); | ||
125 | static void cpc_tty_flush_buffer(struct tty_struct *tty); | ||
126 | static void cpc_tty_hangup(struct tty_struct *tty); | ||
127 | static void cpc_tty_rx_work(struct work_struct *work); | ||
128 | static void cpc_tty_tx_work(struct work_struct *work); | ||
129 | static int cpc_tty_send_to_card(pc300dev_t *dev,void *buf, int len); | ||
130 | static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx); | ||
131 | static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char); | ||
132 | static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char); | ||
133 | |||
134 | static int pc300_tiocmset(struct tty_struct *, unsigned int, unsigned int); | ||
135 | static int pc300_tiocmget(struct tty_struct *); | ||
136 | |||
137 | /* functions called by PC300 driver */ | ||
138 | void cpc_tty_init(pc300dev_t *dev); | ||
139 | void cpc_tty_unregister_service(pc300dev_t *pc300dev); | ||
140 | void cpc_tty_receive(pc300dev_t *pc300dev); | ||
141 | void cpc_tty_trigger_poll(pc300dev_t *pc300dev); | ||
142 | void cpc_tty_reset_var(void); | ||
143 | |||
144 | /* | ||
145 | * PC300 TTY clear "signal" | ||
146 | */ | ||
147 | static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char signal) | ||
148 | { | ||
149 | pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; | ||
150 | pc300_t *card = (pc300_t *) pc300chan->card; | ||
151 | int ch = pc300chan->channel; | ||
152 | unsigned long flags; | ||
153 | |||
154 | CPC_TTY_DBG("%s-tty: Clear signal %x\n", | ||
155 | pc300dev->dev->name, signal); | ||
156 | CPC_TTY_LOCK(card, flags); | ||
157 | cpc_writeb(card->hw.scabase + M_REG(CTL,ch), | ||
158 | cpc_readb(card->hw.scabase+M_REG(CTL,ch))& signal); | ||
159 | CPC_TTY_UNLOCK(card,flags); | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * PC300 TTY set "signal" to ON | ||
164 | */ | ||
165 | static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char signal) | ||
166 | { | ||
167 | pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; | ||
168 | pc300_t *card = (pc300_t *) pc300chan->card; | ||
169 | int ch = pc300chan->channel; | ||
170 | unsigned long flags; | ||
171 | |||
172 | CPC_TTY_DBG("%s-tty: Set signal %x\n", | ||
173 | pc300dev->dev->name, signal); | ||
174 | CPC_TTY_LOCK(card, flags); | ||
175 | cpc_writeb(card->hw.scabase + M_REG(CTL,ch), | ||
176 | cpc_readb(card->hw.scabase+M_REG(CTL,ch))& ~signal); | ||
177 | CPC_TTY_UNLOCK(card,flags); | ||
178 | } | ||
179 | |||
180 | |||
181 | static const struct tty_operations pc300_ops = { | ||
182 | .open = cpc_tty_open, | ||
183 | .close = cpc_tty_close, | ||
184 | .write = cpc_tty_write, | ||
185 | .write_room = cpc_tty_write_room, | ||
186 | .chars_in_buffer = cpc_tty_chars_in_buffer, | ||
187 | .tiocmset = pc300_tiocmset, | ||
188 | .tiocmget = pc300_tiocmget, | ||
189 | .flush_buffer = cpc_tty_flush_buffer, | ||
190 | .hangup = cpc_tty_hangup, | ||
191 | }; | ||
192 | |||
193 | |||
194 | /* | ||
195 | * PC300 TTY initialization routine | ||
196 | * | ||
197 | * This routine is called by the PC300 driver during board configuration | ||
198 | * (ioctl=SIOCSP300CONF). At this point the adapter is completely | ||
199 | * initialized. | ||
200 | * o verify kernel version (only 2.4.x) | ||
201 | * o register TTY driver | ||
202 | * o init cpc_tty_area struct | ||
203 | */ | ||
204 | void cpc_tty_init(pc300dev_t *pc300dev) | ||
205 | { | ||
206 | unsigned long port; | ||
207 | int aux; | ||
208 | st_cpc_tty_area * cpc_tty; | ||
209 | |||
210 | /* hdlcX - X=interface number */ | ||
211 | port = pc300dev->dev->name[4] - '0'; | ||
212 | if (port >= CPC_TTY_NPORTS) { | ||
213 | printk("%s-tty: invalid interface selected (0-%i): %li", | ||
214 | pc300dev->dev->name, | ||
215 | CPC_TTY_NPORTS-1,port); | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | if (cpc_tty_cnt == 0) { /* first TTY connection -> register driver */ | ||
220 | CPC_TTY_DBG("%s-tty: driver init, major:%i, minor range:%i=%i\n", | ||
221 | pc300dev->dev->name, | ||
222 | CPC_TTY_MAJOR, CPC_TTY_MINOR_START, | ||
223 | CPC_TTY_MINOR_START+CPC_TTY_NPORTS); | ||
224 | /* initialize tty driver struct */ | ||
225 | memset(&serial_drv,0,sizeof(struct tty_driver)); | ||
226 | serial_drv.magic = TTY_DRIVER_MAGIC; | ||
227 | serial_drv.owner = THIS_MODULE; | ||
228 | serial_drv.driver_name = "pc300_tty"; | ||
229 | serial_drv.name = "ttyCP"; | ||
230 | serial_drv.major = CPC_TTY_MAJOR; | ||
231 | serial_drv.minor_start = CPC_TTY_MINOR_START; | ||
232 | serial_drv.num = CPC_TTY_NPORTS; | ||
233 | serial_drv.type = TTY_DRIVER_TYPE_SERIAL; | ||
234 | serial_drv.subtype = SERIAL_TYPE_NORMAL; | ||
235 | |||
236 | serial_drv.init_termios = tty_std_termios; | ||
237 | serial_drv.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; | ||
238 | serial_drv.flags = TTY_DRIVER_REAL_RAW; | ||
239 | |||
240 | /* interface routines from the upper tty layer to the tty driver */ | ||
241 | tty_set_operations(&serial_drv, &pc300_ops); | ||
242 | |||
243 | /* register the TTY driver */ | ||
244 | if (tty_register_driver(&serial_drv)) { | ||
245 | printk("%s-tty: Failed to register serial driver! ", | ||
246 | pc300dev->dev->name); | ||
247 | return; | ||
248 | } | ||
249 | |||
250 | memset((void *)cpc_tty_area, 0, | ||
251 | sizeof(st_cpc_tty_area) * CPC_TTY_NPORTS); | ||
252 | } | ||
253 | |||
254 | cpc_tty = &cpc_tty_area[port]; | ||
255 | |||
256 | if (cpc_tty->state != CPC_TTY_ST_IDLE) { | ||
257 | CPC_TTY_DBG("%s-tty: TTY port %i, already in use.\n", | ||
258 | pc300dev->dev->name, port); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | cpc_tty_cnt++; | ||
263 | cpc_tty->state = CPC_TTY_ST_INIT; | ||
264 | cpc_tty->num_open= 0; | ||
265 | cpc_tty->tty_minor = port + CPC_TTY_MINOR_START; | ||
266 | cpc_tty->pc300dev = pc300dev; | ||
267 | |||
268 | INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work); | ||
269 | INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work); | ||
270 | |||
271 | cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = NULL; | ||
272 | |||
273 | pc300dev->cpc_tty = (void *)cpc_tty; | ||
274 | |||
275 | aux = strlen(pc300dev->dev->name); | ||
276 | memcpy(cpc_tty->name, pc300dev->dev->name, aux); | ||
277 | memcpy(&cpc_tty->name[aux], "-tty", 5); | ||
278 | |||
279 | cpc_open(pc300dev->dev); | ||
280 | cpc_tty_signal_off(pc300dev, CTL_DTR); | ||
281 | |||
282 | CPC_TTY_DBG("%s: Initializing TTY Sync Driver, tty major#%d minor#%i\n", | ||
283 | cpc_tty->name,CPC_TTY_MAJOR,cpc_tty->tty_minor); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * PC300 TTY OPEN routine | ||
289 | * | ||
290 | * This routine is called by the tty driver to open the interface | ||
291 | * o verify minor | ||
292 | * o allocate buffer to Rx and Tx | ||
293 | */ | ||
294 | static int cpc_tty_open(struct tty_struct *tty, struct file *flip) | ||
295 | { | ||
296 | int port ; | ||
297 | st_cpc_tty_area *cpc_tty; | ||
298 | |||
299 | if (!tty) { | ||
300 | return -ENODEV; | ||
301 | } | ||
302 | |||
303 | port = tty->index; | ||
304 | |||
305 | if ((port < 0) || (port >= CPC_TTY_NPORTS)){ | ||
306 | CPC_TTY_DBG("pc300_tty: open invalid port %d\n", port); | ||
307 | return -ENODEV; | ||
308 | } | ||
309 | |||
310 | cpc_tty = &cpc_tty_area[port]; | ||
311 | |||
312 | if (cpc_tty->state == CPC_TTY_ST_IDLE){ | ||
313 | CPC_TTY_DBG("%s: open - invalid interface, port=%d\n", | ||
314 | cpc_tty->name, tty->index); | ||
315 | return -ENODEV; | ||
316 | } | ||
317 | |||
318 | if (cpc_tty->num_open == 0) { /* first open of this tty */ | ||
319 | if (!cpc_tty_area[port].buf_tx){ | ||
320 | cpc_tty_area[port].buf_tx = kmalloc(CPC_TTY_MAX_MTU,GFP_KERNEL); | ||
321 | if (!cpc_tty_area[port].buf_tx) { | ||
322 | CPC_TTY_DBG("%s: error in memory allocation\n",cpc_tty->name); | ||
323 | return -ENOMEM; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | if (cpc_tty_area[port].buf_rx.first) { | ||
328 | unsigned char * aux; | ||
329 | while (cpc_tty_area[port].buf_rx.first) { | ||
330 | aux = (unsigned char *)cpc_tty_area[port].buf_rx.first; | ||
331 | cpc_tty_area[port].buf_rx.first = cpc_tty_area[port].buf_rx.first->next; | ||
332 | kfree(aux); | ||
333 | } | ||
334 | cpc_tty_area[port].buf_rx.first = NULL; | ||
335 | cpc_tty_area[port].buf_rx.last = NULL; | ||
336 | } | ||
337 | |||
338 | cpc_tty_area[port].state = CPC_TTY_ST_OPEN; | ||
339 | cpc_tty_area[port].tty = tty; | ||
340 | tty->driver_data = &cpc_tty_area[port]; | ||
341 | |||
342 | cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR); | ||
343 | } | ||
344 | |||
345 | cpc_tty->num_open++; | ||
346 | |||
347 | CPC_TTY_DBG("%s: opening TTY driver\n", cpc_tty->name); | ||
348 | |||
349 | /* avisar driver PC300 */ | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * PC300 TTY CLOSE routine | ||
355 | * | ||
356 | * This routine is called by the tty driver to close the interface | ||
357 | * o call close channel in PC300 driver (cpc_closech) | ||
358 | * o free Rx and Tx buffers | ||
359 | */ | ||
360 | |||
361 | static void cpc_tty_close(struct tty_struct *tty, struct file *flip) | ||
362 | { | ||
363 | st_cpc_tty_area *cpc_tty; | ||
364 | unsigned long flags; | ||
365 | int res; | ||
366 | |||
367 | if (!tty || !tty->driver_data ) { | ||
368 | CPC_TTY_DBG("hdlx-tty: no TTY in close\n"); | ||
369 | return; | ||
370 | } | ||
371 | |||
372 | cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
373 | |||
374 | if ((cpc_tty->tty != tty)|| (cpc_tty->state != CPC_TTY_ST_OPEN)) { | ||
375 | CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); | ||
376 | return; | ||
377 | } | ||
378 | |||
379 | if (!cpc_tty->num_open) { | ||
380 | CPC_TTY_DBG("%s: TTY is closed\n",cpc_tty->name); | ||
381 | return; | ||
382 | } | ||
383 | |||
384 | if (--cpc_tty->num_open > 0) { | ||
385 | CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name); | ||
386 | return; | ||
387 | } | ||
388 | |||
389 | cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); | ||
390 | |||
391 | CPC_TTY_LOCK(cpc_tty->pc300dev->chan->card, flags); /* lock irq */ | ||
392 | cpc_tty->tty = NULL; | ||
393 | cpc_tty->state = CPC_TTY_ST_INIT; | ||
394 | CPC_TTY_UNLOCK(cpc_tty->pc300dev->chan->card, flags); /* unlock irq */ | ||
395 | |||
396 | if (cpc_tty->buf_rx.first) { | ||
397 | unsigned char * aux; | ||
398 | while (cpc_tty->buf_rx.first) { | ||
399 | aux = (unsigned char *)cpc_tty->buf_rx.first; | ||
400 | cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; | ||
401 | kfree(aux); | ||
402 | } | ||
403 | cpc_tty->buf_rx.first = NULL; | ||
404 | cpc_tty->buf_rx.last = NULL; | ||
405 | } | ||
406 | |||
407 | kfree(cpc_tty->buf_tx); | ||
408 | cpc_tty->buf_tx = NULL; | ||
409 | |||
410 | CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name); | ||
411 | |||
412 | if (!serial_drv.refcount && cpc_tty_unreg_flag) { | ||
413 | cpc_tty_unreg_flag = 0; | ||
414 | CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); | ||
415 | if ((res=tty_unregister_driver(&serial_drv))) { | ||
416 | CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", | ||
417 | cpc_tty->name,res); | ||
418 | } | ||
419 | } | ||
420 | return; | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * PC300 TTY WRITE routine | ||
425 | * | ||
426 | * This routine is called by the tty driver to write a series of characters | ||
427 | * to the tty device. The characters may come from user or kernel space. | ||
428 | * o verify the DCD signal | ||
429 | * o send characters to board and start the transmission | ||
430 | */ | ||
431 | static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) | ||
432 | { | ||
433 | st_cpc_tty_area *cpc_tty; | ||
434 | pc300ch_t *pc300chan; | ||
435 | pc300_t *card; | ||
436 | int ch; | ||
437 | unsigned long flags; | ||
438 | struct net_device_stats *stats; | ||
439 | |||
440 | if (!tty || !tty->driver_data ) { | ||
441 | CPC_TTY_DBG("hdlcX-tty: no TTY in write\n"); | ||
442 | return -ENODEV; | ||
443 | } | ||
444 | |||
445 | cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
446 | |||
447 | if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { | ||
448 | CPC_TTY_DBG("%s: TTY is not opened\n", cpc_tty->name); | ||
449 | return -ENODEV; | ||
450 | } | ||
451 | |||
452 | if (count > CPC_TTY_MAX_MTU) { | ||
453 | CPC_TTY_DBG("%s: count is invalid\n",cpc_tty->name); | ||
454 | return -EINVAL; /* frame too big */ | ||
455 | } | ||
456 | |||
457 | CPC_TTY_DBG("%s: cpc_tty_write data len=%i\n",cpc_tty->name,count); | ||
458 | |||
459 | pc300chan = (pc300ch_t *)((pc300dev_t*)cpc_tty->pc300dev)->chan; | ||
460 | stats = &cpc_tty->pc300dev->dev->stats; | ||
461 | card = (pc300_t *) pc300chan->card; | ||
462 | ch = pc300chan->channel; | ||
463 | |||
464 | /* verify DCD signal*/ | ||
465 | if (cpc_readb(card->hw.scabase + M_REG(ST3,ch)) & ST3_DCD) { | ||
466 | /* DCD is OFF */ | ||
467 | CPC_TTY_DBG("%s : DCD is OFF\n", cpc_tty->name); | ||
468 | stats->tx_errors++; | ||
469 | stats->tx_carrier_errors++; | ||
470 | CPC_TTY_LOCK(card, flags); | ||
471 | cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_BUF_CLR); | ||
472 | |||
473 | if (card->hw.type == PC300_TE) { | ||
474 | cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, | ||
475 | cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) & | ||
476 | ~(CPLD_REG2_FALC_LED1 << (2 *ch))); | ||
477 | } | ||
478 | |||
479 | CPC_TTY_UNLOCK(card, flags); | ||
480 | |||
481 | return -EINVAL; | ||
482 | } | ||
483 | |||
484 | if (cpc_tty_send_to_card(cpc_tty->pc300dev, (void*)buf, count)) { | ||
485 | /* failed to send */ | ||
486 | CPC_TTY_DBG("%s: trasmition error\n", cpc_tty->name); | ||
487 | return 0; | ||
488 | } | ||
489 | return count; | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * PC300 TTY Write Room routine | ||
494 | * | ||
495 | * This routine returns the numbers of characteres the tty driver will accept | ||
496 | * for queuing to be written. | ||
497 | * o return MTU | ||
498 | */ | ||
499 | static int cpc_tty_write_room(struct tty_struct *tty) | ||
500 | { | ||
501 | st_cpc_tty_area *cpc_tty; | ||
502 | |||
503 | if (!tty || !tty->driver_data ) { | ||
504 | CPC_TTY_DBG("hdlcX-tty: no TTY to write room\n"); | ||
505 | return -ENODEV; | ||
506 | } | ||
507 | |||
508 | cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
509 | |||
510 | if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { | ||
511 | CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); | ||
512 | return -ENODEV; | ||
513 | } | ||
514 | |||
515 | CPC_TTY_DBG("%s: write room\n",cpc_tty->name); | ||
516 | |||
517 | return CPC_TTY_MAX_MTU; | ||
518 | } | ||
519 | |||
520 | /* | ||
521 | * PC300 TTY chars in buffer routine | ||
522 | * | ||
523 | * This routine returns the chars number in the transmission buffer | ||
524 | * o returns 0 | ||
525 | */ | ||
526 | static int cpc_tty_chars_in_buffer(struct tty_struct *tty) | ||
527 | { | ||
528 | st_cpc_tty_area *cpc_tty; | ||
529 | |||
530 | if (!tty || !tty->driver_data ) { | ||
531 | CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n"); | ||
532 | return -ENODEV; | ||
533 | } | ||
534 | |||
535 | cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
536 | |||
537 | if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { | ||
538 | CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); | ||
539 | return -ENODEV; | ||
540 | } | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int pc300_tiocmset(struct tty_struct *tty, | ||
546 | unsigned int set, unsigned int clear) | ||
547 | { | ||
548 | st_cpc_tty_area *cpc_tty; | ||
549 | |||
550 | CPC_TTY_DBG("%s: set:%x clear:%x\n", __func__, set, clear); | ||
551 | |||
552 | if (!tty || !tty->driver_data ) { | ||
553 | CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n"); | ||
554 | return -ENODEV; | ||
555 | } | ||
556 | |||
557 | cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
558 | |||
559 | if (set & TIOCM_RTS) | ||
560 | cpc_tty_signal_on(cpc_tty->pc300dev, CTL_RTS); | ||
561 | if (set & TIOCM_DTR) | ||
562 | cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR); | ||
563 | |||
564 | if (clear & TIOCM_RTS) | ||
565 | cpc_tty_signal_off(cpc_tty->pc300dev, CTL_RTS); | ||
566 | if (clear & TIOCM_DTR) | ||
567 | cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static int pc300_tiocmget(struct tty_struct *tty) | ||
573 | { | ||
574 | unsigned int result; | ||
575 | unsigned char status; | ||
576 | unsigned long flags; | ||
577 | st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
578 | pc300dev_t *pc300dev = cpc_tty->pc300dev; | ||
579 | pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; | ||
580 | pc300_t *card = (pc300_t *) pc300chan->card; | ||
581 | int ch = pc300chan->channel; | ||
582 | |||
583 | cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
584 | |||
585 | CPC_TTY_DBG("%s-tty: tiocmget\n", | ||
586 | ((struct net_device*)(pc300dev->hdlc))->name); | ||
587 | |||
588 | CPC_TTY_LOCK(card, flags); | ||
589 | status = cpc_readb(card->hw.scabase+M_REG(CTL,ch)); | ||
590 | CPC_TTY_UNLOCK(card,flags); | ||
591 | |||
592 | result = ((status & CTL_DTR) ? TIOCM_DTR : 0) | | ||
593 | ((status & CTL_RTS) ? TIOCM_RTS : 0); | ||
594 | |||
595 | return result; | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * PC300 TTY Flush Buffer routine | ||
600 | * | ||
601 | * This routine resets the transmission buffer | ||
602 | */ | ||
603 | static void cpc_tty_flush_buffer(struct tty_struct *tty) | ||
604 | { | ||
605 | st_cpc_tty_area *cpc_tty; | ||
606 | |||
607 | if (!tty || !tty->driver_data ) { | ||
608 | CPC_TTY_DBG("hdlcX-tty: no TTY to flush buffer\n"); | ||
609 | return; | ||
610 | } | ||
611 | |||
612 | cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
613 | |||
614 | if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { | ||
615 | CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); | ||
616 | return; | ||
617 | } | ||
618 | |||
619 | CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name); | ||
620 | |||
621 | tty_wakeup(tty); | ||
622 | return; | ||
623 | } | ||
624 | |||
625 | /* | ||
626 | * PC300 TTY Hangup routine | ||
627 | * | ||
628 | * This routine is called by the tty driver to hangup the interface | ||
629 | * o clear DTR signal | ||
630 | */ | ||
631 | |||
632 | static void cpc_tty_hangup(struct tty_struct *tty) | ||
633 | { | ||
634 | st_cpc_tty_area *cpc_tty; | ||
635 | int res; | ||
636 | |||
637 | if (!tty || !tty->driver_data ) { | ||
638 | CPC_TTY_DBG("hdlcX-tty: no TTY to hangup\n"); | ||
639 | return ; | ||
640 | } | ||
641 | |||
642 | cpc_tty = (st_cpc_tty_area *) tty->driver_data; | ||
643 | |||
644 | if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) { | ||
645 | CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name); | ||
646 | return ; | ||
647 | } | ||
648 | if (!serial_drv.refcount && cpc_tty_unreg_flag) { | ||
649 | cpc_tty_unreg_flag = 0; | ||
650 | CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); | ||
651 | if ((res=tty_unregister_driver(&serial_drv))) { | ||
652 | CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", | ||
653 | cpc_tty->name,res); | ||
654 | } | ||
655 | } | ||
656 | cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR); | ||
657 | } | ||
658 | |||
659 | /* | ||
660 | * PC300 TTY RX work routine | ||
661 | * This routine treats RX work | ||
662 | * o verify read buffer | ||
663 | * o call the line disc. read | ||
664 | * o free memory | ||
665 | */ | ||
666 | static void cpc_tty_rx_work(struct work_struct *work) | ||
667 | { | ||
668 | st_cpc_tty_area *cpc_tty; | ||
669 | unsigned long port; | ||
670 | int i, j; | ||
671 | volatile st_cpc_rx_buf *buf; | ||
672 | char flags=0,flg_rx=1; | ||
673 | struct tty_ldisc *ld; | ||
674 | |||
675 | if (cpc_tty_cnt == 0) return; | ||
676 | |||
677 | for (i=0; (i < 4) && flg_rx ; i++) { | ||
678 | flg_rx = 0; | ||
679 | |||
680 | cpc_tty = container_of(work, st_cpc_tty_area, tty_rx_work); | ||
681 | port = cpc_tty - cpc_tty_area; | ||
682 | |||
683 | for (j=0; j < CPC_TTY_NPORTS; j++) { | ||
684 | cpc_tty = &cpc_tty_area[port]; | ||
685 | |||
686 | if ((buf=cpc_tty->buf_rx.first) != NULL) { | ||
687 | if (cpc_tty->tty) { | ||
688 | ld = tty_ldisc_ref(cpc_tty->tty); | ||
689 | if (ld) { | ||
690 | if (ld->ops->receive_buf) { | ||
691 | CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); | ||
692 | ld->ops->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size); | ||
693 | } | ||
694 | tty_ldisc_deref(ld); | ||
695 | } | ||
696 | } | ||
697 | cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; | ||
698 | kfree((void *)buf); | ||
699 | buf = cpc_tty->buf_rx.first; | ||
700 | flg_rx = 1; | ||
701 | } | ||
702 | if (++port == CPC_TTY_NPORTS) port = 0; | ||
703 | } | ||
704 | } | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | * PC300 TTY RX work routine | ||
709 | * | ||
710 | * This routine treats RX interrupt. | ||
711 | * o read all frames in card | ||
712 | * o verify the frame size | ||
713 | * o read the frame in rx buffer | ||
714 | */ | ||
715 | static void cpc_tty_rx_disc_frame(pc300ch_t *pc300chan) | ||
716 | { | ||
717 | volatile pcsca_bd_t __iomem * ptdescr; | ||
718 | volatile unsigned char status; | ||
719 | pc300_t *card = (pc300_t *)pc300chan->card; | ||
720 | int ch = pc300chan->channel; | ||
721 | |||
722 | /* dma buf read */ | ||
723 | ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + | ||
724 | RX_BD_ADDR(ch, pc300chan->rx_first_bd)); | ||
725 | while (pc300chan->rx_first_bd != pc300chan->rx_last_bd) { | ||
726 | status = cpc_readb(&ptdescr->status); | ||
727 | cpc_writeb(&ptdescr->status, 0); | ||
728 | cpc_writeb(&ptdescr->len, 0); | ||
729 | pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & | ||
730 | (N_DMA_RX_BUF - 1); | ||
731 | if (status & DST_EOM) { | ||
732 | break; /* end of message */ | ||
733 | } | ||
734 | ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + cpc_readl(&ptdescr->next)); | ||
735 | } | ||
736 | } | ||
737 | |||
738 | void cpc_tty_receive(pc300dev_t *pc300dev) | ||
739 | { | ||
740 | st_cpc_tty_area *cpc_tty; | ||
741 | pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan; | ||
742 | pc300_t *card = (pc300_t *)pc300chan->card; | ||
743 | int ch = pc300chan->channel; | ||
744 | volatile pcsca_bd_t __iomem * ptdescr; | ||
745 | struct net_device_stats *stats = &pc300dev->dev->stats; | ||
746 | int rx_len, rx_aux; | ||
747 | volatile unsigned char status; | ||
748 | unsigned short first_bd = pc300chan->rx_first_bd; | ||
749 | st_cpc_rx_buf *new = NULL; | ||
750 | unsigned char dsr_rx; | ||
751 | |||
752 | if (pc300dev->cpc_tty == NULL) { | ||
753 | return; | ||
754 | } | ||
755 | |||
756 | dsr_rx = cpc_readb(card->hw.scabase + DSR_RX(ch)); | ||
757 | |||
758 | cpc_tty = pc300dev->cpc_tty; | ||
759 | |||
760 | while (1) { | ||
761 | rx_len = 0; | ||
762 | ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd)); | ||
763 | while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { | ||
764 | rx_len += cpc_readw(&ptdescr->len); | ||
765 | first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1); | ||
766 | if (status & DST_EOM) { | ||
767 | break; | ||
768 | } | ||
769 | ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase+cpc_readl(&ptdescr->next)); | ||
770 | } | ||
771 | |||
772 | if (!rx_len) { | ||
773 | if (dsr_rx & DSR_BOF) { | ||
774 | /* update EDA */ | ||
775 | cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), | ||
776 | RX_BD_ADDR(ch, pc300chan->rx_last_bd)); | ||
777 | } | ||
778 | kfree(new); | ||
779 | return; | ||
780 | } | ||
781 | |||
782 | if (rx_len > CPC_TTY_MAX_MTU) { | ||
783 | /* Free RX descriptors */ | ||
784 | CPC_TTY_DBG("%s: frame size is invalid.\n",cpc_tty->name); | ||
785 | stats->rx_errors++; | ||
786 | stats->rx_frame_errors++; | ||
787 | cpc_tty_rx_disc_frame(pc300chan); | ||
788 | continue; | ||
789 | } | ||
790 | |||
791 | new = kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC); | ||
792 | if (!new) { | ||
793 | cpc_tty_rx_disc_frame(pc300chan); | ||
794 | continue; | ||
795 | } | ||
796 | |||
797 | /* dma buf read */ | ||
798 | ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + | ||
799 | RX_BD_ADDR(ch, pc300chan->rx_first_bd)); | ||
800 | |||
801 | rx_len = 0; /* counter frame size */ | ||
802 | |||
803 | while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { | ||
804 | rx_aux = cpc_readw(&ptdescr->len); | ||
805 | if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT)) | ||
806 | || (rx_aux > BD_DEF_LEN)) { | ||
807 | CPC_TTY_DBG("%s: reception error\n", cpc_tty->name); | ||
808 | stats->rx_errors++; | ||
809 | if (status & DST_OVR) { | ||
810 | stats->rx_fifo_errors++; | ||
811 | } | ||
812 | if (status & DST_CRC) { | ||
813 | stats->rx_crc_errors++; | ||
814 | } | ||
815 | if ((status & (DST_RBIT | DST_SHRT | DST_ABT)) || | ||
816 | (rx_aux > BD_DEF_LEN)) { | ||
817 | stats->rx_frame_errors++; | ||
818 | } | ||
819 | /* discard remainig descriptors used by the bad frame */ | ||
820 | CPC_TTY_DBG("%s: reception error - discard descriptors", | ||
821 | cpc_tty->name); | ||
822 | cpc_tty_rx_disc_frame(pc300chan); | ||
823 | rx_len = 0; | ||
824 | kfree(new); | ||
825 | new = NULL; | ||
826 | break; /* read next frame - while(1) */ | ||
827 | } | ||
828 | |||
829 | if (cpc_tty->state != CPC_TTY_ST_OPEN) { | ||
830 | /* Free RX descriptors */ | ||
831 | cpc_tty_rx_disc_frame(pc300chan); | ||
832 | stats->rx_dropped++; | ||
833 | rx_len = 0; | ||
834 | kfree(new); | ||
835 | new = NULL; | ||
836 | break; /* read next frame - while(1) */ | ||
837 | } | ||
838 | |||
839 | /* read the segment of the frame */ | ||
840 | if (rx_aux != 0) { | ||
841 | memcpy_fromio((new->data + rx_len), | ||
842 | (void __iomem *)(card->hw.rambase + | ||
843 | cpc_readl(&ptdescr->ptbuf)), rx_aux); | ||
844 | rx_len += rx_aux; | ||
845 | } | ||
846 | cpc_writeb(&ptdescr->status,0); | ||
847 | cpc_writeb(&ptdescr->len, 0); | ||
848 | pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) & | ||
849 | (N_DMA_RX_BUF -1); | ||
850 | if (status & DST_EOM)break; | ||
851 | |||
852 | ptdescr = (pcsca_bd_t __iomem *) (card->hw.rambase + | ||
853 | cpc_readl(&ptdescr->next)); | ||
854 | } | ||
855 | /* update pointer */ | ||
856 | pc300chan->rx_last_bd = (pc300chan->rx_first_bd - 1) & | ||
857 | (N_DMA_RX_BUF - 1) ; | ||
858 | if (!(dsr_rx & DSR_BOF)) { | ||
859 | /* update EDA */ | ||
860 | cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), | ||
861 | RX_BD_ADDR(ch, pc300chan->rx_last_bd)); | ||
862 | } | ||
863 | if (rx_len != 0) { | ||
864 | stats->rx_bytes += rx_len; | ||
865 | |||
866 | if (pc300dev->trace_on) { | ||
867 | cpc_tty_trace(pc300dev, new->data,rx_len, 'R'); | ||
868 | } | ||
869 | new->size = rx_len; | ||
870 | new->next = NULL; | ||
871 | if (cpc_tty->buf_rx.first == NULL) { | ||
872 | cpc_tty->buf_rx.first = new; | ||
873 | cpc_tty->buf_rx.last = new; | ||
874 | } else { | ||
875 | cpc_tty->buf_rx.last->next = new; | ||
876 | cpc_tty->buf_rx.last = new; | ||
877 | } | ||
878 | schedule_work(&(cpc_tty->tty_rx_work)); | ||
879 | stats->rx_packets++; | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | |||
884 | /* | ||
885 | * PC300 TTY TX work routine | ||
886 | * | ||
887 | * This routine treats TX interrupt. | ||
888 | * o if need call line discipline wakeup | ||
889 | * o call wake_up_interruptible | ||
890 | */ | ||
891 | static void cpc_tty_tx_work(struct work_struct *work) | ||
892 | { | ||
893 | st_cpc_tty_area *cpc_tty = | ||
894 | container_of(work, st_cpc_tty_area, tty_tx_work); | ||
895 | struct tty_struct *tty; | ||
896 | |||
897 | CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name); | ||
898 | |||
899 | if ((tty = cpc_tty->tty) == NULL) { | ||
900 | CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name); | ||
901 | return; | ||
902 | } | ||
903 | tty_wakeup(tty); | ||
904 | } | ||
905 | |||
906 | /* | ||
907 | * PC300 TTY send to card routine | ||
908 | * | ||
909 | * This routine send data to card. | ||
910 | * o clear descriptors | ||
911 | * o write data to DMA buffers | ||
912 | * o start the transmission | ||
913 | */ | ||
914 | static int cpc_tty_send_to_card(pc300dev_t *dev,void* buf, int len) | ||
915 | { | ||
916 | pc300ch_t *chan = (pc300ch_t *)dev->chan; | ||
917 | pc300_t *card = (pc300_t *)chan->card; | ||
918 | int ch = chan->channel; | ||
919 | struct net_device_stats *stats = &dev->dev->stats; | ||
920 | unsigned long flags; | ||
921 | volatile pcsca_bd_t __iomem *ptdescr; | ||
922 | int i, nchar; | ||
923 | int tosend = len; | ||
924 | int nbuf = ((len - 1)/BD_DEF_LEN) + 1; | ||
925 | unsigned char *pdata=buf; | ||
926 | |||
927 | CPC_TTY_DBG("%s:cpc_tty_send_to_cars len=%i", | ||
928 | (st_cpc_tty_area *)dev->cpc_tty->name,len); | ||
929 | |||
930 | if (nbuf >= card->chan[ch].nfree_tx_bd) { | ||
931 | return 1; | ||
932 | } | ||
933 | |||
934 | /* write buffer to DMA buffers */ | ||
935 | CPC_TTY_DBG("%s: call dma_buf_write\n", | ||
936 | (st_cpc_tty_area *)dev->cpc_tty->name); | ||
937 | for (i = 0 ; i < nbuf ; i++) { | ||
938 | ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + | ||
939 | TX_BD_ADDR(ch, card->chan[ch].tx_next_bd)); | ||
940 | nchar = (BD_DEF_LEN > tosend) ? tosend : BD_DEF_LEN; | ||
941 | if (cpc_readb(&ptdescr->status) & DST_OSB) { | ||
942 | memcpy_toio((void __iomem *)(card->hw.rambase + | ||
943 | cpc_readl(&ptdescr->ptbuf)), | ||
944 | &pdata[len - tosend], | ||
945 | nchar); | ||
946 | card->chan[ch].nfree_tx_bd--; | ||
947 | if ((i + 1) == nbuf) { | ||
948 | /* This must be the last BD to be used */ | ||
949 | cpc_writeb(&ptdescr->status, DST_EOM); | ||
950 | } else { | ||
951 | cpc_writeb(&ptdescr->status, 0); | ||
952 | } | ||
953 | cpc_writew(&ptdescr->len, nchar); | ||
954 | } else { | ||
955 | CPC_TTY_DBG("%s: error in dma_buf_write\n", | ||
956 | (st_cpc_tty_area *)dev->cpc_tty->name); | ||
957 | stats->tx_dropped++; | ||
958 | return 1; | ||
959 | } | ||
960 | tosend -= nchar; | ||
961 | card->chan[ch].tx_next_bd = | ||
962 | (card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1); | ||
963 | } | ||
964 | |||
965 | if (dev->trace_on) { | ||
966 | cpc_tty_trace(dev, buf, len,'T'); | ||
967 | } | ||
968 | |||
969 | /* start transmission */ | ||
970 | CPC_TTY_DBG("%s: start transmission\n", | ||
971 | (st_cpc_tty_area *)dev->cpc_tty->name); | ||
972 | |||
973 | CPC_TTY_LOCK(card, flags); | ||
974 | cpc_writeb(card->hw.scabase + DTX_REG(EDAL, ch), | ||
975 | TX_BD_ADDR(ch, chan->tx_next_bd)); | ||
976 | cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA); | ||
977 | cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE); | ||
978 | |||
979 | if (card->hw.type == PC300_TE) { | ||
980 | cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2, | ||
981 | cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) | | ||
982 | (CPLD_REG2_FALC_LED1 << (2 * ch))); | ||
983 | } | ||
984 | CPC_TTY_UNLOCK(card, flags); | ||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | /* | ||
989 | * PC300 TTY trace routine | ||
990 | * | ||
991 | * This routine send trace of connection to application. | ||
992 | * o clear descriptors | ||
993 | * o write data to DMA buffers | ||
994 | * o start the transmission | ||
995 | */ | ||
996 | |||
997 | static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx) | ||
998 | { | ||
999 | struct sk_buff *skb; | ||
1000 | |||
1001 | if ((skb = dev_alloc_skb(10 + len)) == NULL) { | ||
1002 | /* out of memory */ | ||
1003 | CPC_TTY_DBG("%s: tty_trace - out of memory\n", dev->dev->name); | ||
1004 | return; | ||
1005 | } | ||
1006 | |||
1007 | skb_put (skb, 10 + len); | ||
1008 | skb->dev = dev->dev; | ||
1009 | skb->protocol = htons(ETH_P_CUST); | ||
1010 | skb_reset_mac_header(skb); | ||
1011 | skb->pkt_type = PACKET_HOST; | ||
1012 | skb->len = 10 + len; | ||
1013 | |||
1014 | skb_copy_to_linear_data(skb, dev->dev->name, 5); | ||
1015 | skb->data[5] = '['; | ||
1016 | skb->data[6] = rxtx; | ||
1017 | skb->data[7] = ']'; | ||
1018 | skb->data[8] = ':'; | ||
1019 | skb->data[9] = ' '; | ||
1020 | skb_copy_to_linear_data_offset(skb, 10, buf, len); | ||
1021 | netif_rx(skb); | ||
1022 | } | ||
1023 | |||
1024 | /* | ||
1025 | * PC300 TTY unregister service routine | ||
1026 | * | ||
1027 | * This routine unregister one interface. | ||
1028 | */ | ||
1029 | void cpc_tty_unregister_service(pc300dev_t *pc300dev) | ||
1030 | { | ||
1031 | st_cpc_tty_area *cpc_tty; | ||
1032 | ulong flags; | ||
1033 | int res; | ||
1034 | |||
1035 | if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == NULL) { | ||
1036 | CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->name); | ||
1037 | return; | ||
1038 | } | ||
1039 | CPC_TTY_DBG("%s: cpc_tty_unregister_service", cpc_tty->name); | ||
1040 | |||
1041 | if (cpc_tty->pc300dev != pc300dev) { | ||
1042 | CPC_TTY_DBG("%s: invalid tty ptr=%s\n", | ||
1043 | pc300dev->dev->name, cpc_tty->name); | ||
1044 | return; | ||
1045 | } | ||
1046 | |||
1047 | if (--cpc_tty_cnt == 0) { | ||
1048 | if (serial_drv.refcount) { | ||
1049 | CPC_TTY_DBG("%s: unregister is not possible, refcount=%d", | ||
1050 | cpc_tty->name, serial_drv.refcount); | ||
1051 | cpc_tty_cnt++; | ||
1052 | cpc_tty_unreg_flag = 1; | ||
1053 | return; | ||
1054 | } else { | ||
1055 | CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name); | ||
1056 | if ((res=tty_unregister_driver(&serial_drv))) { | ||
1057 | CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", | ||
1058 | cpc_tty->name,res); | ||
1059 | } | ||
1060 | } | ||
1061 | } | ||
1062 | CPC_TTY_LOCK(pc300dev->chan->card,flags); | ||
1063 | cpc_tty->tty = NULL; | ||
1064 | CPC_TTY_UNLOCK(pc300dev->chan->card, flags); | ||
1065 | cpc_tty->tty_minor = 0; | ||
1066 | cpc_tty->state = CPC_TTY_ST_IDLE; | ||
1067 | } | ||
1068 | |||
1069 | /* | ||
1070 | * PC300 TTY trigger poll routine | ||
1071 | * This routine is called by pc300driver to treats Tx interrupt. | ||
1072 | */ | ||
1073 | void cpc_tty_trigger_poll(pc300dev_t *pc300dev) | ||
1074 | { | ||
1075 | st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty; | ||
1076 | if (!cpc_tty) { | ||
1077 | return; | ||
1078 | } | ||
1079 | schedule_work(&(cpc_tty->tty_tx_work)); | ||
1080 | } | ||
1081 | |||
1082 | /* | ||
1083 | * PC300 TTY reset var routine | ||
1084 | * This routine is called by pc300driver to init the TTY area. | ||
1085 | */ | ||
1086 | |||
1087 | void cpc_tty_reset_var(void) | ||
1088 | { | ||
1089 | int i ; | ||
1090 | |||
1091 | CPC_TTY_DBG("hdlcX-tty: reset variables\n"); | ||
1092 | /* reset the tty_driver structure - serial_drv */ | ||
1093 | memset(&serial_drv, 0, sizeof(struct tty_driver)); | ||
1094 | for (i=0; i < CPC_TTY_NPORTS; i++){ | ||
1095 | memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area)); | ||
1096 | } | ||
1097 | } | ||