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