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/serial/jsm/jsm_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/serial/jsm/jsm_tty.c')
-rw-r--r-- | drivers/serial/jsm/jsm_tty.c | 1038 |
1 files changed, 1038 insertions, 0 deletions
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c new file mode 100644 index 000000000000..7fb7cc07074b --- /dev/null +++ b/drivers/serial/jsm/jsm_tty.c | |||
@@ -0,0 +1,1038 @@ | |||
1 | /************************************************************************ | ||
2 | * Copyright 2003 Digi International (www.digi.com) | ||
3 | * | ||
4 | * Copyright (C) 2004 IBM Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the | ||
13 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
14 | * PURPOSE. See the GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 * Temple Place - Suite 330, Boston, | ||
19 | * MA 02111-1307, USA. | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * Scott H Kilau <Scott_Kilau@digi.com> | ||
23 | * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com> | ||
24 | * | ||
25 | ***********************************************************************/ | ||
26 | #include <linux/tty.h> | ||
27 | #include <linux/tty_flip.h> | ||
28 | #include <linux/serial_reg.h> | ||
29 | #include <linux/delay.h> /* For udelay */ | ||
30 | #include <linux/pci.h> | ||
31 | |||
32 | #include "jsm.h" | ||
33 | |||
34 | static inline int jsm_get_mstat(struct jsm_channel *ch) | ||
35 | { | ||
36 | unsigned char mstat; | ||
37 | unsigned result; | ||
38 | |||
39 | jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n"); | ||
40 | |||
41 | mstat = (ch->ch_mostat | ch->ch_mistat); | ||
42 | |||
43 | result = 0; | ||
44 | |||
45 | if (mstat & UART_MCR_DTR) | ||
46 | result |= TIOCM_DTR; | ||
47 | if (mstat & UART_MCR_RTS) | ||
48 | result |= TIOCM_RTS; | ||
49 | if (mstat & UART_MSR_CTS) | ||
50 | result |= TIOCM_CTS; | ||
51 | if (mstat & UART_MSR_DSR) | ||
52 | result |= TIOCM_DSR; | ||
53 | if (mstat & UART_MSR_RI) | ||
54 | result |= TIOCM_RI; | ||
55 | if (mstat & UART_MSR_DCD) | ||
56 | result |= TIOCM_CD; | ||
57 | |||
58 | jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); | ||
59 | return result; | ||
60 | } | ||
61 | |||
62 | static unsigned int jsm_tty_tx_empty(struct uart_port *port) | ||
63 | { | ||
64 | return TIOCSER_TEMT; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Return modem signals to ld. | ||
69 | */ | ||
70 | static unsigned int jsm_tty_get_mctrl(struct uart_port *port) | ||
71 | { | ||
72 | int result; | ||
73 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
74 | |||
75 | jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); | ||
76 | |||
77 | result = jsm_get_mstat(channel); | ||
78 | |||
79 | if (result < 0) | ||
80 | return -ENXIO; | ||
81 | |||
82 | jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); | ||
83 | |||
84 | return result; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * jsm_set_modem_info() | ||
89 | * | ||
90 | * Set modem signals, called by ld. | ||
91 | */ | ||
92 | static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
93 | { | ||
94 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
95 | |||
96 | jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); | ||
97 | |||
98 | if (mctrl & TIOCM_RTS) | ||
99 | channel->ch_mostat |= UART_MCR_RTS; | ||
100 | else | ||
101 | channel->ch_mostat &= ~UART_MCR_RTS; | ||
102 | |||
103 | if (mctrl & TIOCM_DTR) | ||
104 | channel->ch_mostat |= UART_MCR_DTR; | ||
105 | else | ||
106 | channel->ch_mostat &= ~UART_MCR_DTR; | ||
107 | |||
108 | channel->ch_bd->bd_ops->assert_modem_signals(channel); | ||
109 | |||
110 | jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); | ||
111 | udelay(10); | ||
112 | } | ||
113 | |||
114 | static void jsm_tty_start_tx(struct uart_port *port, unsigned int tty_start) | ||
115 | { | ||
116 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
117 | |||
118 | jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); | ||
119 | |||
120 | channel->ch_flags &= ~(CH_STOP); | ||
121 | jsm_tty_write(port); | ||
122 | |||
123 | jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); | ||
124 | } | ||
125 | |||
126 | static void jsm_tty_stop_tx(struct uart_port *port, unsigned int tty_stop) | ||
127 | { | ||
128 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
129 | |||
130 | jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); | ||
131 | |||
132 | channel->ch_flags |= (CH_STOP); | ||
133 | |||
134 | jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); | ||
135 | } | ||
136 | |||
137 | static void jsm_tty_send_xchar(struct uart_port *port, char ch) | ||
138 | { | ||
139 | unsigned long lock_flags; | ||
140 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
141 | |||
142 | spin_lock_irqsave(&port->lock, lock_flags); | ||
143 | if (ch == port->info->tty->termios->c_cc[VSTART]) | ||
144 | channel->ch_bd->bd_ops->send_start_character(channel); | ||
145 | |||
146 | if (ch == port->info->tty->termios->c_cc[VSTOP]) | ||
147 | channel->ch_bd->bd_ops->send_stop_character(channel); | ||
148 | spin_unlock_irqrestore(&port->lock, lock_flags); | ||
149 | } | ||
150 | |||
151 | static void jsm_tty_stop_rx(struct uart_port *port) | ||
152 | { | ||
153 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
154 | |||
155 | channel->ch_bd->bd_ops->disable_receiver(channel); | ||
156 | } | ||
157 | |||
158 | static void jsm_tty_break(struct uart_port *port, int break_state) | ||
159 | { | ||
160 | unsigned long lock_flags; | ||
161 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
162 | |||
163 | spin_lock_irqsave(&port->lock, lock_flags); | ||
164 | if (break_state == -1) | ||
165 | channel->ch_bd->bd_ops->send_break(channel); | ||
166 | else | ||
167 | channel->ch_bd->bd_ops->clear_break(channel, 0); | ||
168 | |||
169 | spin_unlock_irqrestore(&port->lock, lock_flags); | ||
170 | } | ||
171 | |||
172 | static int jsm_tty_open(struct uart_port *port) | ||
173 | { | ||
174 | struct jsm_board *brd; | ||
175 | int rc = 0; | ||
176 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
177 | |||
178 | /* Get board pointer from our array of majors we have allocated */ | ||
179 | brd = channel->ch_bd; | ||
180 | |||
181 | /* | ||
182 | * Allocate channel buffers for read/write/error. | ||
183 | * Set flag, so we don't get trounced on. | ||
184 | */ | ||
185 | channel->ch_flags |= (CH_OPENING); | ||
186 | |||
187 | /* Drop locks, as malloc with GFP_KERNEL can sleep */ | ||
188 | |||
189 | if (!channel->ch_rqueue) { | ||
190 | channel->ch_rqueue = (u8 *) kmalloc(RQUEUESIZE, GFP_KERNEL); | ||
191 | if (!channel->ch_rqueue) { | ||
192 | jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, | ||
193 | "unable to allocate read queue buf"); | ||
194 | return -ENOMEM; | ||
195 | } | ||
196 | memset(channel->ch_rqueue, 0, RQUEUESIZE); | ||
197 | } | ||
198 | if (!channel->ch_equeue) { | ||
199 | channel->ch_equeue = (u8 *) kmalloc(EQUEUESIZE, GFP_KERNEL); | ||
200 | if (!channel->ch_equeue) { | ||
201 | jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, | ||
202 | "unable to allocate error queue buf"); | ||
203 | return -ENOMEM; | ||
204 | } | ||
205 | memset(channel->ch_equeue, 0, EQUEUESIZE); | ||
206 | } | ||
207 | if (!channel->ch_wqueue) { | ||
208 | channel->ch_wqueue = (u8 *) kmalloc(WQUEUESIZE, GFP_KERNEL); | ||
209 | if (!channel->ch_wqueue) { | ||
210 | jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, | ||
211 | "unable to allocate write queue buf"); | ||
212 | return -ENOMEM; | ||
213 | } | ||
214 | memset(channel->ch_wqueue, 0, WQUEUESIZE); | ||
215 | } | ||
216 | |||
217 | channel->ch_flags &= ~(CH_OPENING); | ||
218 | /* | ||
219 | * Initialize if neither terminal is open. | ||
220 | */ | ||
221 | jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, | ||
222 | "jsm_open: initializing channel in open...\n"); | ||
223 | |||
224 | /* | ||
225 | * Flush input queues. | ||
226 | */ | ||
227 | channel->ch_r_head = channel->ch_r_tail = 0; | ||
228 | channel->ch_e_head = channel->ch_e_tail = 0; | ||
229 | channel->ch_w_head = channel->ch_w_tail = 0; | ||
230 | |||
231 | brd->bd_ops->flush_uart_write(channel); | ||
232 | brd->bd_ops->flush_uart_read(channel); | ||
233 | |||
234 | channel->ch_flags = 0; | ||
235 | channel->ch_cached_lsr = 0; | ||
236 | channel->ch_stops_sent = 0; | ||
237 | |||
238 | channel->ch_c_cflag = port->info->tty->termios->c_cflag; | ||
239 | channel->ch_c_iflag = port->info->tty->termios->c_iflag; | ||
240 | channel->ch_c_oflag = port->info->tty->termios->c_oflag; | ||
241 | channel->ch_c_lflag = port->info->tty->termios->c_lflag; | ||
242 | channel->ch_startc = port->info->tty->termios->c_cc[VSTART]; | ||
243 | channel->ch_stopc = port->info->tty->termios->c_cc[VSTOP]; | ||
244 | |||
245 | /* Tell UART to init itself */ | ||
246 | brd->bd_ops->uart_init(channel); | ||
247 | |||
248 | /* | ||
249 | * Run param in case we changed anything | ||
250 | */ | ||
251 | brd->bd_ops->param(channel); | ||
252 | |||
253 | jsm_carrier(channel); | ||
254 | |||
255 | channel->ch_open_count++; | ||
256 | |||
257 | jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n"); | ||
258 | return rc; | ||
259 | } | ||
260 | |||
261 | static void jsm_tty_close(struct uart_port *port) | ||
262 | { | ||
263 | struct jsm_board *bd; | ||
264 | struct termios *ts; | ||
265 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
266 | |||
267 | jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); | ||
268 | |||
269 | bd = channel->ch_bd; | ||
270 | ts = channel->uart_port.info->tty->termios; | ||
271 | |||
272 | channel->ch_flags &= ~(CH_STOPI); | ||
273 | |||
274 | channel->ch_open_count--; | ||
275 | |||
276 | /* | ||
277 | * If we have HUPCL set, lower DTR and RTS | ||
278 | */ | ||
279 | if (channel->ch_c_cflag & HUPCL) { | ||
280 | jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, | ||
281 | "Close. HUPCL set, dropping DTR/RTS\n"); | ||
282 | |||
283 | /* Drop RTS/DTR */ | ||
284 | channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS); | ||
285 | bd->bd_ops->assert_modem_signals(channel); | ||
286 | } | ||
287 | |||
288 | channel->ch_old_baud = 0; | ||
289 | |||
290 | /* Turn off UART interrupts for this port */ | ||
291 | channel->ch_bd->bd_ops->uart_off(channel); | ||
292 | |||
293 | jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n"); | ||
294 | } | ||
295 | |||
296 | static void jsm_tty_set_termios(struct uart_port *port, | ||
297 | struct termios *termios, | ||
298 | struct termios *old_termios) | ||
299 | { | ||
300 | unsigned long lock_flags; | ||
301 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
302 | |||
303 | spin_lock_irqsave(&port->lock, lock_flags); | ||
304 | channel->ch_c_cflag = termios->c_cflag; | ||
305 | channel->ch_c_iflag = termios->c_iflag; | ||
306 | channel->ch_c_oflag = termios->c_oflag; | ||
307 | channel->ch_c_lflag = termios->c_lflag; | ||
308 | channel->ch_startc = termios->c_cc[VSTART]; | ||
309 | channel->ch_stopc = termios->c_cc[VSTOP]; | ||
310 | |||
311 | channel->ch_bd->bd_ops->param(channel); | ||
312 | jsm_carrier(channel); | ||
313 | spin_unlock_irqrestore(&port->lock, lock_flags); | ||
314 | } | ||
315 | |||
316 | static const char *jsm_tty_type(struct uart_port *port) | ||
317 | { | ||
318 | return "jsm"; | ||
319 | } | ||
320 | |||
321 | static void jsm_tty_release_port(struct uart_port *port) | ||
322 | { | ||
323 | } | ||
324 | |||
325 | static int jsm_tty_request_port(struct uart_port *port) | ||
326 | { | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static void jsm_config_port(struct uart_port *port, int flags) | ||
331 | { | ||
332 | port->type = PORT_JSM; | ||
333 | } | ||
334 | |||
335 | static struct uart_ops jsm_ops = { | ||
336 | .tx_empty = jsm_tty_tx_empty, | ||
337 | .set_mctrl = jsm_tty_set_mctrl, | ||
338 | .get_mctrl = jsm_tty_get_mctrl, | ||
339 | .stop_tx = jsm_tty_stop_tx, | ||
340 | .start_tx = jsm_tty_start_tx, | ||
341 | .send_xchar = jsm_tty_send_xchar, | ||
342 | .stop_rx = jsm_tty_stop_rx, | ||
343 | .break_ctl = jsm_tty_break, | ||
344 | .startup = jsm_tty_open, | ||
345 | .shutdown = jsm_tty_close, | ||
346 | .set_termios = jsm_tty_set_termios, | ||
347 | .type = jsm_tty_type, | ||
348 | .release_port = jsm_tty_release_port, | ||
349 | .request_port = jsm_tty_request_port, | ||
350 | .config_port = jsm_config_port, | ||
351 | }; | ||
352 | |||
353 | /* | ||
354 | * jsm_tty_init() | ||
355 | * | ||
356 | * Init the tty subsystem. Called once per board after board has been | ||
357 | * downloaded and init'ed. | ||
358 | */ | ||
359 | int jsm_tty_init(struct jsm_board *brd) | ||
360 | { | ||
361 | int i; | ||
362 | void __iomem *vaddr; | ||
363 | struct jsm_channel *ch; | ||
364 | |||
365 | if (!brd) | ||
366 | return -ENXIO; | ||
367 | |||
368 | jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); | ||
369 | |||
370 | /* | ||
371 | * Initialize board structure elements. | ||
372 | */ | ||
373 | |||
374 | brd->nasync = brd->maxports; | ||
375 | |||
376 | /* | ||
377 | * Allocate channel memory that might not have been allocated | ||
378 | * when the driver was first loaded. | ||
379 | */ | ||
380 | for (i = 0; i < brd->nasync; i++) { | ||
381 | if (!brd->channels[i]) { | ||
382 | |||
383 | /* | ||
384 | * Okay to malloc with GFP_KERNEL, we are not at | ||
385 | * interrupt context, and there are no locks held. | ||
386 | */ | ||
387 | brd->channels[i] = kmalloc(sizeof(struct jsm_channel), GFP_KERNEL); | ||
388 | if (!brd->channels[i]) { | ||
389 | jsm_printk(CORE, ERR, &brd->pci_dev, | ||
390 | "%s:%d Unable to allocate memory for channel struct\n", | ||
391 | __FILE__, __LINE__); | ||
392 | } | ||
393 | memset(brd->channels[i], 0, sizeof(struct jsm_channel)); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | ch = brd->channels[0]; | ||
398 | vaddr = brd->re_map_membase; | ||
399 | |||
400 | /* Set up channel variables */ | ||
401 | for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { | ||
402 | |||
403 | if (!brd->channels[i]) | ||
404 | continue; | ||
405 | |||
406 | spin_lock_init(&ch->ch_lock); | ||
407 | |||
408 | if (brd->bd_uart_offset == 0x200) | ||
409 | ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i); | ||
410 | |||
411 | ch->ch_bd = brd; | ||
412 | ch->ch_portnum = i; | ||
413 | |||
414 | /* .25 second delay */ | ||
415 | ch->ch_close_delay = 250; | ||
416 | |||
417 | init_waitqueue_head(&ch->ch_flags_wait); | ||
418 | } | ||
419 | |||
420 | jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | int jsm_uart_port_init(struct jsm_board *brd) | ||
425 | { | ||
426 | int i; | ||
427 | struct jsm_channel *ch; | ||
428 | |||
429 | if (!brd) | ||
430 | return -ENXIO; | ||
431 | |||
432 | jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); | ||
433 | |||
434 | /* | ||
435 | * Initialize board structure elements. | ||
436 | */ | ||
437 | |||
438 | brd->nasync = brd->maxports; | ||
439 | |||
440 | /* Set up channel variables */ | ||
441 | for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { | ||
442 | |||
443 | if (!brd->channels[i]) | ||
444 | continue; | ||
445 | |||
446 | brd->channels[i]->uart_port.irq = brd->irq; | ||
447 | brd->channels[i]->uart_port.type = PORT_JSM; | ||
448 | brd->channels[i]->uart_port.iotype = UPIO_MEM; | ||
449 | brd->channels[i]->uart_port.membase = brd->re_map_membase; | ||
450 | brd->channels[i]->uart_port.fifosize = 16; | ||
451 | brd->channels[i]->uart_port.ops = &jsm_ops; | ||
452 | brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2; | ||
453 | if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) | ||
454 | printk(KERN_INFO "Added device failed\n"); | ||
455 | else | ||
456 | printk(KERN_INFO "Added device \n"); | ||
457 | } | ||
458 | |||
459 | jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | int jsm_remove_uart_port(struct jsm_board *brd) | ||
464 | { | ||
465 | int i; | ||
466 | struct jsm_channel *ch; | ||
467 | |||
468 | if (!brd) | ||
469 | return -ENXIO; | ||
470 | |||
471 | jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); | ||
472 | |||
473 | /* | ||
474 | * Initialize board structure elements. | ||
475 | */ | ||
476 | |||
477 | brd->nasync = brd->maxports; | ||
478 | |||
479 | /* Set up channel variables */ | ||
480 | for (i = 0; i < brd->nasync; i++) { | ||
481 | |||
482 | if (!brd->channels[i]) | ||
483 | continue; | ||
484 | |||
485 | ch = brd->channels[i]; | ||
486 | |||
487 | uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); | ||
488 | } | ||
489 | |||
490 | jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | void jsm_input(struct jsm_channel *ch) | ||
495 | { | ||
496 | struct jsm_board *bd; | ||
497 | struct tty_struct *tp; | ||
498 | u32 rmask; | ||
499 | u16 head; | ||
500 | u16 tail; | ||
501 | int data_len; | ||
502 | unsigned long lock_flags; | ||
503 | int flip_len; | ||
504 | int len = 0; | ||
505 | int n = 0; | ||
506 | char *buf = NULL; | ||
507 | char *buf2 = NULL; | ||
508 | int s = 0; | ||
509 | int i = 0; | ||
510 | |||
511 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); | ||
512 | |||
513 | if (!ch) | ||
514 | return; | ||
515 | |||
516 | tp = ch->uart_port.info->tty; | ||
517 | |||
518 | bd = ch->ch_bd; | ||
519 | if(!bd) | ||
520 | return; | ||
521 | |||
522 | spin_lock_irqsave(&ch->ch_lock, lock_flags); | ||
523 | |||
524 | /* | ||
525 | *Figure the number of characters in the buffer. | ||
526 | *Exit immediately if none. | ||
527 | */ | ||
528 | |||
529 | rmask = RQUEUEMASK; | ||
530 | |||
531 | head = ch->ch_r_head & rmask; | ||
532 | tail = ch->ch_r_tail & rmask; | ||
533 | |||
534 | data_len = (head - tail) & rmask; | ||
535 | if (data_len == 0) { | ||
536 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
537 | return; | ||
538 | } | ||
539 | |||
540 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); | ||
541 | |||
542 | /* | ||
543 | *If the device is not open, or CREAD is off, flush | ||
544 | *input data and return immediately. | ||
545 | */ | ||
546 | if (!tp || | ||
547 | !(tp->termios->c_cflag & CREAD) ) { | ||
548 | |||
549 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
550 | "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum); | ||
551 | ch->ch_r_head = tail; | ||
552 | |||
553 | /* Force queue flow control to be released, if needed */ | ||
554 | jsm_check_queue_flow_control(ch); | ||
555 | |||
556 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
557 | return; | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * If we are throttled, simply don't read any data. | ||
562 | */ | ||
563 | if (ch->ch_flags & CH_STOPI) { | ||
564 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
565 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
566 | "Port %d throttled, not reading any data. head: %x tail: %x\n", | ||
567 | ch->ch_portnum, head, tail); | ||
568 | return; | ||
569 | } | ||
570 | |||
571 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n"); | ||
572 | |||
573 | /* | ||
574 | * If the rxbuf is empty and we are not throttled, put as much | ||
575 | * as we can directly into the linux TTY flip buffer. | ||
576 | * The jsm_rawreadok case takes advantage of carnal knowledge that | ||
577 | * the char_buf and the flag_buf are next to each other and | ||
578 | * are each of (2 * TTY_FLIPBUF_SIZE) size. | ||
579 | * | ||
580 | * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf | ||
581 | *actually still uses the flag buffer, so you can't | ||
582 | *use it for input data | ||
583 | */ | ||
584 | if (jsm_rawreadok) { | ||
585 | if (tp->real_raw) | ||
586 | flip_len = MYFLIPLEN; | ||
587 | else | ||
588 | flip_len = 2 * TTY_FLIPBUF_SIZE; | ||
589 | } else | ||
590 | flip_len = TTY_FLIPBUF_SIZE - tp->flip.count; | ||
591 | |||
592 | len = min(data_len, flip_len); | ||
593 | len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt); | ||
594 | |||
595 | if (len <= 0) { | ||
596 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
597 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n"); | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | /* | ||
602 | * If we're bypassing flip buffers on rx, we can blast it | ||
603 | * right into the beginning of the buffer. | ||
604 | */ | ||
605 | if (jsm_rawreadok) { | ||
606 | if (tp->real_raw) { | ||
607 | if (ch->ch_flags & CH_FLIPBUF_IN_USE) { | ||
608 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
609 | "JSM - FLIPBUF in use. delaying input\n"); | ||
610 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
611 | return; | ||
612 | } | ||
613 | ch->ch_flags |= CH_FLIPBUF_IN_USE; | ||
614 | buf = ch->ch_bd->flipbuf; | ||
615 | buf2 = NULL; | ||
616 | } else { | ||
617 | buf = tp->flip.char_buf; | ||
618 | buf2 = tp->flip.flag_buf; | ||
619 | } | ||
620 | } else { | ||
621 | buf = tp->flip.char_buf_ptr; | ||
622 | buf2 = tp->flip.flag_buf_ptr; | ||
623 | } | ||
624 | |||
625 | n = len; | ||
626 | |||
627 | /* | ||
628 | * n now contains the most amount of data we can copy, | ||
629 | * bounded either by the flip buffer size or the amount | ||
630 | * of data the card actually has pending... | ||
631 | */ | ||
632 | while (n) { | ||
633 | s = ((head >= tail) ? head : RQUEUESIZE) - tail; | ||
634 | s = min(s, n); | ||
635 | |||
636 | if (s <= 0) | ||
637 | break; | ||
638 | |||
639 | memcpy(buf, ch->ch_rqueue + tail, s); | ||
640 | |||
641 | /* buf2 is only set when port isn't raw */ | ||
642 | if (buf2) | ||
643 | memcpy(buf2, ch->ch_equeue + tail, s); | ||
644 | |||
645 | tail += s; | ||
646 | buf += s; | ||
647 | if (buf2) | ||
648 | buf2 += s; | ||
649 | n -= s; | ||
650 | /* Flip queue if needed */ | ||
651 | tail &= rmask; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * In high performance mode, we don't have to update | ||
656 | * flag_buf or any of the counts or pointers into flip buf. | ||
657 | */ | ||
658 | if (!jsm_rawreadok) { | ||
659 | if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { | ||
660 | for (i = 0; i < len; i++) { | ||
661 | /* | ||
662 | * Give the Linux ld the flags in the | ||
663 | * format it likes. | ||
664 | */ | ||
665 | if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI) | ||
666 | tp->flip.flag_buf_ptr[i] = TTY_BREAK; | ||
667 | else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE) | ||
668 | tp->flip.flag_buf_ptr[i] = TTY_PARITY; | ||
669 | else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE) | ||
670 | tp->flip.flag_buf_ptr[i] = TTY_FRAME; | ||
671 | else | ||
672 | tp->flip.flag_buf_ptr[i] = TTY_NORMAL; | ||
673 | } | ||
674 | } else { | ||
675 | memset(tp->flip.flag_buf_ptr, 0, len); | ||
676 | } | ||
677 | |||
678 | tp->flip.char_buf_ptr += len; | ||
679 | tp->flip.flag_buf_ptr += len; | ||
680 | tp->flip.count += len; | ||
681 | } | ||
682 | else if (!tp->real_raw) { | ||
683 | if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { | ||
684 | for (i = 0; i < len; i++) { | ||
685 | /* | ||
686 | * Give the Linux ld the flags in the | ||
687 | * format it likes. | ||
688 | */ | ||
689 | if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI) | ||
690 | tp->flip.flag_buf_ptr[i] = TTY_BREAK; | ||
691 | else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE) | ||
692 | tp->flip.flag_buf_ptr[i] = TTY_PARITY; | ||
693 | else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE) | ||
694 | tp->flip.flag_buf_ptr[i] = TTY_FRAME; | ||
695 | else | ||
696 | tp->flip.flag_buf_ptr[i] = TTY_NORMAL; | ||
697 | } | ||
698 | } else | ||
699 | memset(tp->flip.flag_buf, 0, len); | ||
700 | } | ||
701 | |||
702 | /* | ||
703 | * If we're doing raw reads, jam it right into the | ||
704 | * line disc bypassing the flip buffers. | ||
705 | */ | ||
706 | if (jsm_rawreadok) { | ||
707 | if (tp->real_raw) { | ||
708 | ch->ch_r_tail = tail & rmask; | ||
709 | ch->ch_e_tail = tail & rmask; | ||
710 | |||
711 | jsm_check_queue_flow_control(ch); | ||
712 | |||
713 | /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */ | ||
714 | |||
715 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
716 | |||
717 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
718 | "jsm_input. %d real_raw len:%d calling receive_buf for board %d\n", | ||
719 | __LINE__, len, ch->ch_bd->boardnum); | ||
720 | tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len); | ||
721 | |||
722 | /* Allow use of channel flip buffer again */ | ||
723 | spin_lock_irqsave(&ch->ch_lock, lock_flags); | ||
724 | ch->ch_flags &= ~CH_FLIPBUF_IN_USE; | ||
725 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
726 | |||
727 | } else { | ||
728 | ch->ch_r_tail = tail & rmask; | ||
729 | ch->ch_e_tail = tail & rmask; | ||
730 | |||
731 | jsm_check_queue_flow_control(ch); | ||
732 | |||
733 | /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */ | ||
734 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
735 | |||
736 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
737 | "jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n", | ||
738 | __LINE__, len, ch->ch_bd->boardnum); | ||
739 | |||
740 | tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len); | ||
741 | } | ||
742 | } else { | ||
743 | ch->ch_r_tail = tail & rmask; | ||
744 | ch->ch_e_tail = tail & rmask; | ||
745 | |||
746 | jsm_check_queue_flow_control(ch); | ||
747 | |||
748 | spin_unlock_irqrestore(&ch->ch_lock, lock_flags); | ||
749 | |||
750 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
751 | "jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__); | ||
752 | tty_schedule_flip(tp); | ||
753 | } | ||
754 | |||
755 | jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); | ||
756 | } | ||
757 | |||
758 | void jsm_carrier(struct jsm_channel *ch) | ||
759 | { | ||
760 | struct jsm_board *bd; | ||
761 | |||
762 | int virt_carrier = 0; | ||
763 | int phys_carrier = 0; | ||
764 | |||
765 | jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n"); | ||
766 | if (!ch) | ||
767 | return; | ||
768 | |||
769 | bd = ch->ch_bd; | ||
770 | |||
771 | if (!bd) | ||
772 | return; | ||
773 | |||
774 | if (ch->ch_mistat & UART_MSR_DCD) { | ||
775 | jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, | ||
776 | "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD); | ||
777 | phys_carrier = 1; | ||
778 | } | ||
779 | |||
780 | if (ch->ch_c_cflag & CLOCAL) | ||
781 | virt_carrier = 1; | ||
782 | |||
783 | jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, | ||
784 | "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier); | ||
785 | |||
786 | /* | ||
787 | * Test for a VIRTUAL carrier transition to HIGH. | ||
788 | */ | ||
789 | if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { | ||
790 | |||
791 | /* | ||
792 | * When carrier rises, wake any threads waiting | ||
793 | * for carrier in the open routine. | ||
794 | */ | ||
795 | |||
796 | jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, | ||
797 | "carrier: virt DCD rose\n"); | ||
798 | |||
799 | if (waitqueue_active(&(ch->ch_flags_wait))) | ||
800 | wake_up_interruptible(&ch->ch_flags_wait); | ||
801 | } | ||
802 | |||
803 | /* | ||
804 | * Test for a PHYSICAL carrier transition to HIGH. | ||
805 | */ | ||
806 | if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { | ||
807 | |||
808 | /* | ||
809 | * When carrier rises, wake any threads waiting | ||
810 | * for carrier in the open routine. | ||
811 | */ | ||
812 | |||
813 | jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, | ||
814 | "carrier: physical DCD rose\n"); | ||
815 | |||
816 | if (waitqueue_active(&(ch->ch_flags_wait))) | ||
817 | wake_up_interruptible(&ch->ch_flags_wait); | ||
818 | } | ||
819 | |||
820 | /* | ||
821 | * Test for a PHYSICAL transition to low, so long as we aren't | ||
822 | * currently ignoring physical transitions (which is what "virtual | ||
823 | * carrier" indicates). | ||
824 | * | ||
825 | * The transition of the virtual carrier to low really doesn't | ||
826 | * matter... it really only means "ignore carrier state", not | ||
827 | * "make pretend that carrier is there". | ||
828 | */ | ||
829 | if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) | ||
830 | && (phys_carrier == 0)) { | ||
831 | /* | ||
832 | * When carrier drops: | ||
833 | * | ||
834 | * Drop carrier on all open units. | ||
835 | * | ||
836 | * Flush queues, waking up any task waiting in the | ||
837 | * line discipline. | ||
838 | * | ||
839 | * Send a hangup to the control terminal. | ||
840 | * | ||
841 | * Enable all select calls. | ||
842 | */ | ||
843 | if (waitqueue_active(&(ch->ch_flags_wait))) | ||
844 | wake_up_interruptible(&ch->ch_flags_wait); | ||
845 | } | ||
846 | |||
847 | /* | ||
848 | * Make sure that our cached values reflect the current reality. | ||
849 | */ | ||
850 | if (virt_carrier == 1) | ||
851 | ch->ch_flags |= CH_FCAR; | ||
852 | else | ||
853 | ch->ch_flags &= ~CH_FCAR; | ||
854 | |||
855 | if (phys_carrier == 1) | ||
856 | ch->ch_flags |= CH_CD; | ||
857 | else | ||
858 | ch->ch_flags &= ~CH_CD; | ||
859 | } | ||
860 | |||
861 | |||
862 | void jsm_check_queue_flow_control(struct jsm_channel *ch) | ||
863 | { | ||
864 | int qleft = 0; | ||
865 | |||
866 | /* Store how much space we have left in the queue */ | ||
867 | if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0) | ||
868 | qleft += RQUEUEMASK + 1; | ||
869 | |||
870 | /* | ||
871 | * Check to see if we should enforce flow control on our queue because | ||
872 | * the ld (or user) isn't reading data out of our queue fast enuf. | ||
873 | * | ||
874 | * NOTE: This is done based on what the current flow control of the | ||
875 | * port is set for. | ||
876 | * | ||
877 | * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt. | ||
878 | * This will cause the UART's FIFO to back up, and force | ||
879 | * the RTS signal to be dropped. | ||
880 | * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to | ||
881 | * the other side, in hopes it will stop sending data to us. | ||
882 | * 3) NONE - Nothing we can do. We will simply drop any extra data | ||
883 | * that gets sent into us when the queue fills up. | ||
884 | */ | ||
885 | if (qleft < 256) { | ||
886 | /* HWFLOW */ | ||
887 | if (ch->ch_c_cflag & CRTSCTS) { | ||
888 | if(!(ch->ch_flags & CH_RECEIVER_OFF)) { | ||
889 | ch->ch_bd->bd_ops->disable_receiver(ch); | ||
890 | ch->ch_flags |= (CH_RECEIVER_OFF); | ||
891 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
892 | "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n", | ||
893 | qleft); | ||
894 | } | ||
895 | } | ||
896 | /* SWFLOW */ | ||
897 | else if (ch->ch_c_iflag & IXOFF) { | ||
898 | if (ch->ch_stops_sent <= MAX_STOPS_SENT) { | ||
899 | ch->ch_bd->bd_ops->send_stop_character(ch); | ||
900 | ch->ch_stops_sent++; | ||
901 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
902 | "Sending stop char! Times sent: %x\n", ch->ch_stops_sent); | ||
903 | } | ||
904 | } | ||
905 | } | ||
906 | |||
907 | /* | ||
908 | * Check to see if we should unenforce flow control because | ||
909 | * ld (or user) finally read enuf data out of our queue. | ||
910 | * | ||
911 | * NOTE: This is done based on what the current flow control of the | ||
912 | * port is set for. | ||
913 | * | ||
914 | * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt. | ||
915 | * This will cause the UART's FIFO to raise RTS back up, | ||
916 | * which will allow the other side to start sending data again. | ||
917 | * 2) SWFLOW (IXOFF) - Send a start character to | ||
918 | * the other side, so it will start sending data to us again. | ||
919 | * 3) NONE - Do nothing. Since we didn't do anything to turn off the | ||
920 | * other side, we don't need to do anything now. | ||
921 | */ | ||
922 | if (qleft > (RQUEUESIZE / 2)) { | ||
923 | /* HWFLOW */ | ||
924 | if (ch->ch_c_cflag & CRTSCTS) { | ||
925 | if (ch->ch_flags & CH_RECEIVER_OFF) { | ||
926 | ch->ch_bd->bd_ops->enable_receiver(ch); | ||
927 | ch->ch_flags &= ~(CH_RECEIVER_OFF); | ||
928 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, | ||
929 | "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n", | ||
930 | qleft); | ||
931 | } | ||
932 | } | ||
933 | /* SWFLOW */ | ||
934 | else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) { | ||
935 | ch->ch_stops_sent = 0; | ||
936 | ch->ch_bd->bd_ops->send_start_character(ch); | ||
937 | jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n"); | ||
938 | } | ||
939 | } | ||
940 | } | ||
941 | |||
942 | /* | ||
943 | * jsm_tty_write() | ||
944 | * | ||
945 | * Take data from the user or kernel and send it out to the FEP. | ||
946 | * In here exists all the Transparent Print magic as well. | ||
947 | */ | ||
948 | int jsm_tty_write(struct uart_port *port) | ||
949 | { | ||
950 | int bufcount = 0, n = 0; | ||
951 | int data_count = 0,data_count1 =0; | ||
952 | u16 head; | ||
953 | u16 tail; | ||
954 | u16 tmask; | ||
955 | u32 remain; | ||
956 | int temp_tail = port->info->xmit.tail; | ||
957 | struct jsm_channel *channel = (struct jsm_channel *)port; | ||
958 | |||
959 | tmask = WQUEUEMASK; | ||
960 | head = (channel->ch_w_head) & tmask; | ||
961 | tail = (channel->ch_w_tail) & tmask; | ||
962 | |||
963 | if ((bufcount = tail - head - 1) < 0) | ||
964 | bufcount += WQUEUESIZE; | ||
965 | |||
966 | n = bufcount; | ||
967 | |||
968 | n = min(n, 56); | ||
969 | remain = WQUEUESIZE - head; | ||
970 | |||
971 | data_count = 0; | ||
972 | if (n >= remain) { | ||
973 | n -= remain; | ||
974 | while ((port->info->xmit.head != temp_tail) && | ||
975 | (data_count < remain)) { | ||
976 | channel->ch_wqueue[head++] = | ||
977 | port->info->xmit.buf[temp_tail]; | ||
978 | |||
979 | temp_tail++; | ||
980 | temp_tail &= (UART_XMIT_SIZE - 1); | ||
981 | data_count++; | ||
982 | } | ||
983 | if (data_count == remain) head = 0; | ||
984 | } | ||
985 | |||
986 | data_count1 = 0; | ||
987 | if (n > 0) { | ||
988 | remain = n; | ||
989 | while ((port->info->xmit.head != temp_tail) && | ||
990 | (data_count1 < remain)) { | ||
991 | channel->ch_wqueue[head++] = | ||
992 | port->info->xmit.buf[temp_tail]; | ||
993 | |||
994 | temp_tail++; | ||
995 | temp_tail &= (UART_XMIT_SIZE - 1); | ||
996 | data_count1++; | ||
997 | |||
998 | } | ||
999 | } | ||
1000 | |||
1001 | port->info->xmit.tail = temp_tail; | ||
1002 | |||
1003 | data_count += data_count1; | ||
1004 | if (data_count) { | ||
1005 | head &= tmask; | ||
1006 | channel->ch_w_head = head; | ||
1007 | } | ||
1008 | |||
1009 | if (data_count) { | ||
1010 | channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel); | ||
1011 | } | ||
1012 | |||
1013 | return data_count; | ||
1014 | } | ||
1015 | |||
1016 | static ssize_t jsm_driver_version_show(struct device_driver *ddp, char *buf) | ||
1017 | { | ||
1018 | return snprintf(buf, PAGE_SIZE, "%s\n", JSM_VERSION); | ||
1019 | } | ||
1020 | static DRIVER_ATTR(version, S_IRUSR, jsm_driver_version_show, NULL); | ||
1021 | |||
1022 | static ssize_t jsm_driver_state_show(struct device_driver *ddp, char *buf) | ||
1023 | { | ||
1024 | return snprintf(buf, PAGE_SIZE, "%s\n", jsm_driver_state_text[jsm_driver_state]); | ||
1025 | } | ||
1026 | static DRIVER_ATTR(state, S_IRUSR, jsm_driver_state_show, NULL); | ||
1027 | |||
1028 | void jsm_create_driver_sysfiles(struct device_driver *driverfs) | ||
1029 | { | ||
1030 | driver_create_file(driverfs, &driver_attr_version); | ||
1031 | driver_create_file(driverfs, &driver_attr_state); | ||
1032 | } | ||
1033 | |||
1034 | void jsm_remove_driver_sysfiles(struct device_driver *driverfs) | ||
1035 | { | ||
1036 | driver_remove_file(driverfs, &driver_attr_version); | ||
1037 | driver_remove_file(driverfs, &driver_attr_state); | ||
1038 | } | ||