diff options
Diffstat (limited to 'drivers/char/vme_scc.c')
-rw-r--r-- | drivers/char/vme_scc.c | 1145 |
1 files changed, 0 insertions, 1145 deletions
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c deleted file mode 100644 index 12de1202d22c..000000000000 --- a/drivers/char/vme_scc.c +++ /dev/null | |||
@@ -1,1145 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports | ||
3 | * implementation. | ||
4 | * Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk> | ||
5 | * | ||
6 | * Based on atari_SCC.c which was | ||
7 | * Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> | ||
8 | * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o | ||
9 | * | ||
10 | * This file is subject to the terms and conditions of the GNU General Public | ||
11 | * License. See the file COPYING in the main directory of this archive | ||
12 | * for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/kdev_t.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/ioport.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/tty.h> | ||
24 | #include <linux/tty_flip.h> | ||
25 | #include <linux/mm.h> | ||
26 | #include <linux/serial.h> | ||
27 | #include <linux/fcntl.h> | ||
28 | #include <linux/major.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/miscdevice.h> | ||
31 | #include <linux/console.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <asm/setup.h> | ||
34 | #include <asm/bootinfo.h> | ||
35 | |||
36 | #ifdef CONFIG_MVME147_SCC | ||
37 | #include <asm/mvme147hw.h> | ||
38 | #endif | ||
39 | #ifdef CONFIG_MVME162_SCC | ||
40 | #include <asm/mvme16xhw.h> | ||
41 | #endif | ||
42 | #ifdef CONFIG_BVME6000_SCC | ||
43 | #include <asm/bvme6000hw.h> | ||
44 | #endif | ||
45 | |||
46 | #include <linux/generic_serial.h> | ||
47 | #include "scc.h" | ||
48 | |||
49 | |||
50 | #define CHANNEL_A 0 | ||
51 | #define CHANNEL_B 1 | ||
52 | |||
53 | #define SCC_MINOR_BASE 64 | ||
54 | |||
55 | /* Shadows for all SCC write registers */ | ||
56 | static unsigned char scc_shadow[2][16]; | ||
57 | |||
58 | /* Location to access for SCC register access delay */ | ||
59 | static volatile unsigned char *scc_del = NULL; | ||
60 | |||
61 | /* To keep track of STATUS_REG state for detection of Ext/Status int source */ | ||
62 | static unsigned char scc_last_status_reg[2]; | ||
63 | |||
64 | /***************************** Prototypes *****************************/ | ||
65 | |||
66 | /* Function prototypes */ | ||
67 | static void scc_disable_tx_interrupts(void * ptr); | ||
68 | static void scc_enable_tx_interrupts(void * ptr); | ||
69 | static void scc_disable_rx_interrupts(void * ptr); | ||
70 | static void scc_enable_rx_interrupts(void * ptr); | ||
71 | static int scc_carrier_raised(struct tty_port *port); | ||
72 | static void scc_shutdown_port(void * ptr); | ||
73 | static int scc_set_real_termios(void *ptr); | ||
74 | static void scc_hungup(void *ptr); | ||
75 | static void scc_close(void *ptr); | ||
76 | static int scc_chars_in_buffer(void * ptr); | ||
77 | static int scc_open(struct tty_struct * tty, struct file * filp); | ||
78 | static int scc_ioctl(struct tty_struct * tty, struct file * filp, | ||
79 | unsigned int cmd, unsigned long arg); | ||
80 | static void scc_throttle(struct tty_struct *tty); | ||
81 | static void scc_unthrottle(struct tty_struct *tty); | ||
82 | static irqreturn_t scc_tx_int(int irq, void *data); | ||
83 | static irqreturn_t scc_rx_int(int irq, void *data); | ||
84 | static irqreturn_t scc_stat_int(int irq, void *data); | ||
85 | static irqreturn_t scc_spcond_int(int irq, void *data); | ||
86 | static void scc_setsignals(struct scc_port *port, int dtr, int rts); | ||
87 | static int scc_break_ctl(struct tty_struct *tty, int break_state); | ||
88 | |||
89 | static struct tty_driver *scc_driver; | ||
90 | |||
91 | static struct scc_port scc_ports[2]; | ||
92 | |||
93 | /*--------------------------------------------------------------------------- | ||
94 | * Interface from generic_serial.c back here | ||
95 | *--------------------------------------------------------------------------*/ | ||
96 | |||
97 | static struct real_driver scc_real_driver = { | ||
98 | scc_disable_tx_interrupts, | ||
99 | scc_enable_tx_interrupts, | ||
100 | scc_disable_rx_interrupts, | ||
101 | scc_enable_rx_interrupts, | ||
102 | scc_shutdown_port, | ||
103 | scc_set_real_termios, | ||
104 | scc_chars_in_buffer, | ||
105 | scc_close, | ||
106 | scc_hungup, | ||
107 | NULL | ||
108 | }; | ||
109 | |||
110 | |||
111 | static const struct tty_operations scc_ops = { | ||
112 | .open = scc_open, | ||
113 | .close = gs_close, | ||
114 | .write = gs_write, | ||
115 | .put_char = gs_put_char, | ||
116 | .flush_chars = gs_flush_chars, | ||
117 | .write_room = gs_write_room, | ||
118 | .chars_in_buffer = gs_chars_in_buffer, | ||
119 | .flush_buffer = gs_flush_buffer, | ||
120 | .ioctl = scc_ioctl, | ||
121 | .throttle = scc_throttle, | ||
122 | .unthrottle = scc_unthrottle, | ||
123 | .set_termios = gs_set_termios, | ||
124 | .stop = gs_stop, | ||
125 | .start = gs_start, | ||
126 | .hangup = gs_hangup, | ||
127 | .break_ctl = scc_break_ctl, | ||
128 | }; | ||
129 | |||
130 | static const struct tty_port_operations scc_port_ops = { | ||
131 | .carrier_raised = scc_carrier_raised, | ||
132 | }; | ||
133 | |||
134 | /*---------------------------------------------------------------------------- | ||
135 | * vme_scc_init() and support functions | ||
136 | *---------------------------------------------------------------------------*/ | ||
137 | |||
138 | static int __init scc_init_drivers(void) | ||
139 | { | ||
140 | int error; | ||
141 | |||
142 | scc_driver = alloc_tty_driver(2); | ||
143 | if (!scc_driver) | ||
144 | return -ENOMEM; | ||
145 | scc_driver->owner = THIS_MODULE; | ||
146 | scc_driver->driver_name = "scc"; | ||
147 | scc_driver->name = "ttyS"; | ||
148 | scc_driver->major = TTY_MAJOR; | ||
149 | scc_driver->minor_start = SCC_MINOR_BASE; | ||
150 | scc_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
151 | scc_driver->subtype = SERIAL_TYPE_NORMAL; | ||
152 | scc_driver->init_termios = tty_std_termios; | ||
153 | scc_driver->init_termios.c_cflag = | ||
154 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
155 | scc_driver->init_termios.c_ispeed = 9600; | ||
156 | scc_driver->init_termios.c_ospeed = 9600; | ||
157 | scc_driver->flags = TTY_DRIVER_REAL_RAW; | ||
158 | tty_set_operations(scc_driver, &scc_ops); | ||
159 | |||
160 | if ((error = tty_register_driver(scc_driver))) { | ||
161 | printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n", | ||
162 | error); | ||
163 | put_tty_driver(scc_driver); | ||
164 | return 1; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | |||
171 | /* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1). | ||
172 | */ | ||
173 | |||
174 | static void __init scc_init_portstructs(void) | ||
175 | { | ||
176 | struct scc_port *port; | ||
177 | int i; | ||
178 | |||
179 | for (i = 0; i < 2; i++) { | ||
180 | port = scc_ports + i; | ||
181 | tty_port_init(&port->gs.port); | ||
182 | port->gs.port.ops = &scc_port_ops; | ||
183 | port->gs.magic = SCC_MAGIC; | ||
184 | port->gs.close_delay = HZ/2; | ||
185 | port->gs.closing_wait = 30 * HZ; | ||
186 | port->gs.rd = &scc_real_driver; | ||
187 | #ifdef NEW_WRITE_LOCKING | ||
188 | port->gs.port_write_mutex = MUTEX; | ||
189 | #endif | ||
190 | init_waitqueue_head(&port->gs.port.open_wait); | ||
191 | init_waitqueue_head(&port->gs.port.close_wait); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | |||
196 | #ifdef CONFIG_MVME147_SCC | ||
197 | static int __init mvme147_scc_init(void) | ||
198 | { | ||
199 | struct scc_port *port; | ||
200 | int error; | ||
201 | |||
202 | printk(KERN_INFO "SCC: MVME147 Serial Driver\n"); | ||
203 | /* Init channel A */ | ||
204 | port = &scc_ports[0]; | ||
205 | port->channel = CHANNEL_A; | ||
206 | port->ctrlp = (volatile unsigned char *)M147_SCC_A_ADDR; | ||
207 | port->datap = port->ctrlp + 1; | ||
208 | port->port_a = &scc_ports[0]; | ||
209 | port->port_b = &scc_ports[1]; | ||
210 | error = request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, | ||
211 | "SCC-A TX", port); | ||
212 | if (error) | ||
213 | goto fail; | ||
214 | error = request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, | ||
215 | "SCC-A status", port); | ||
216 | if (error) | ||
217 | goto fail_free_a_tx; | ||
218 | error = request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, | ||
219 | "SCC-A RX", port); | ||
220 | if (error) | ||
221 | goto fail_free_a_stat; | ||
222 | error = request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, | ||
223 | IRQF_DISABLED, "SCC-A special cond", port); | ||
224 | if (error) | ||
225 | goto fail_free_a_rx; | ||
226 | |||
227 | { | ||
228 | SCC_ACCESS_INIT(port); | ||
229 | |||
230 | /* disable interrupts for this channel */ | ||
231 | SCCwrite(INT_AND_DMA_REG, 0); | ||
232 | /* Set the interrupt vector */ | ||
233 | SCCwrite(INT_VECTOR_REG, MVME147_IRQ_SCC_BASE); | ||
234 | /* Interrupt parameters: vector includes status, status low */ | ||
235 | SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); | ||
236 | SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); | ||
237 | } | ||
238 | |||
239 | /* Init channel B */ | ||
240 | port = &scc_ports[1]; | ||
241 | port->channel = CHANNEL_B; | ||
242 | port->ctrlp = (volatile unsigned char *)M147_SCC_B_ADDR; | ||
243 | port->datap = port->ctrlp + 1; | ||
244 | port->port_a = &scc_ports[0]; | ||
245 | port->port_b = &scc_ports[1]; | ||
246 | error = request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, | ||
247 | "SCC-B TX", port); | ||
248 | if (error) | ||
249 | goto fail_free_a_spcond; | ||
250 | error = request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, | ||
251 | "SCC-B status", port); | ||
252 | if (error) | ||
253 | goto fail_free_b_tx; | ||
254 | error = request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, | ||
255 | "SCC-B RX", port); | ||
256 | if (error) | ||
257 | goto fail_free_b_stat; | ||
258 | error = request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, | ||
259 | IRQF_DISABLED, "SCC-B special cond", port); | ||
260 | if (error) | ||
261 | goto fail_free_b_rx; | ||
262 | |||
263 | { | ||
264 | SCC_ACCESS_INIT(port); | ||
265 | |||
266 | /* disable interrupts for this channel */ | ||
267 | SCCwrite(INT_AND_DMA_REG, 0); | ||
268 | } | ||
269 | |||
270 | /* Ensure interrupts are enabled in the PCC chip */ | ||
271 | m147_pcc->serial_cntrl=PCC_LEVEL_SERIAL|PCC_INT_ENAB; | ||
272 | |||
273 | /* Initialise the tty driver structures and register */ | ||
274 | scc_init_portstructs(); | ||
275 | scc_init_drivers(); | ||
276 | |||
277 | return 0; | ||
278 | |||
279 | fail_free_b_rx: | ||
280 | free_irq(MVME147_IRQ_SCCB_RX, port); | ||
281 | fail_free_b_stat: | ||
282 | free_irq(MVME147_IRQ_SCCB_STAT, port); | ||
283 | fail_free_b_tx: | ||
284 | free_irq(MVME147_IRQ_SCCB_TX, port); | ||
285 | fail_free_a_spcond: | ||
286 | free_irq(MVME147_IRQ_SCCA_SPCOND, port); | ||
287 | fail_free_a_rx: | ||
288 | free_irq(MVME147_IRQ_SCCA_RX, port); | ||
289 | fail_free_a_stat: | ||
290 | free_irq(MVME147_IRQ_SCCA_STAT, port); | ||
291 | fail_free_a_tx: | ||
292 | free_irq(MVME147_IRQ_SCCA_TX, port); | ||
293 | fail: | ||
294 | return error; | ||
295 | } | ||
296 | #endif | ||
297 | |||
298 | |||
299 | #ifdef CONFIG_MVME162_SCC | ||
300 | static int __init mvme162_scc_init(void) | ||
301 | { | ||
302 | struct scc_port *port; | ||
303 | int error; | ||
304 | |||
305 | if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA)) | ||
306 | return (-ENODEV); | ||
307 | |||
308 | printk(KERN_INFO "SCC: MVME162 Serial Driver\n"); | ||
309 | /* Init channel A */ | ||
310 | port = &scc_ports[0]; | ||
311 | port->channel = CHANNEL_A; | ||
312 | port->ctrlp = (volatile unsigned char *)MVME_SCC_A_ADDR; | ||
313 | port->datap = port->ctrlp + 2; | ||
314 | port->port_a = &scc_ports[0]; | ||
315 | port->port_b = &scc_ports[1]; | ||
316 | error = request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, | ||
317 | "SCC-A TX", port); | ||
318 | if (error) | ||
319 | goto fail; | ||
320 | error = request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, | ||
321 | "SCC-A status", port); | ||
322 | if (error) | ||
323 | goto fail_free_a_tx; | ||
324 | error = request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, | ||
325 | "SCC-A RX", port); | ||
326 | if (error) | ||
327 | goto fail_free_a_stat; | ||
328 | error = request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, | ||
329 | IRQF_DISABLED, "SCC-A special cond", port); | ||
330 | if (error) | ||
331 | goto fail_free_a_rx; | ||
332 | |||
333 | { | ||
334 | SCC_ACCESS_INIT(port); | ||
335 | |||
336 | /* disable interrupts for this channel */ | ||
337 | SCCwrite(INT_AND_DMA_REG, 0); | ||
338 | /* Set the interrupt vector */ | ||
339 | SCCwrite(INT_VECTOR_REG, MVME162_IRQ_SCC_BASE); | ||
340 | /* Interrupt parameters: vector includes status, status low */ | ||
341 | SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); | ||
342 | SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); | ||
343 | } | ||
344 | |||
345 | /* Init channel B */ | ||
346 | port = &scc_ports[1]; | ||
347 | port->channel = CHANNEL_B; | ||
348 | port->ctrlp = (volatile unsigned char *)MVME_SCC_B_ADDR; | ||
349 | port->datap = port->ctrlp + 2; | ||
350 | port->port_a = &scc_ports[0]; | ||
351 | port->port_b = &scc_ports[1]; | ||
352 | error = request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, | ||
353 | "SCC-B TX", port); | ||
354 | if (error) | ||
355 | goto fail_free_a_spcond; | ||
356 | error = request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, | ||
357 | "SCC-B status", port); | ||
358 | if (error) | ||
359 | goto fail_free_b_tx; | ||
360 | error = request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, | ||
361 | "SCC-B RX", port); | ||
362 | if (error) | ||
363 | goto fail_free_b_stat; | ||
364 | error = request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, | ||
365 | IRQF_DISABLED, "SCC-B special cond", port); | ||
366 | if (error) | ||
367 | goto fail_free_b_rx; | ||
368 | |||
369 | { | ||
370 | SCC_ACCESS_INIT(port); /* Either channel will do */ | ||
371 | |||
372 | /* disable interrupts for this channel */ | ||
373 | SCCwrite(INT_AND_DMA_REG, 0); | ||
374 | } | ||
375 | |||
376 | /* Ensure interrupts are enabled in the MC2 chip */ | ||
377 | *(volatile char *)0xfff4201d = 0x14; | ||
378 | |||
379 | /* Initialise the tty driver structures and register */ | ||
380 | scc_init_portstructs(); | ||
381 | scc_init_drivers(); | ||
382 | |||
383 | return 0; | ||
384 | |||
385 | fail_free_b_rx: | ||
386 | free_irq(MVME162_IRQ_SCCB_RX, port); | ||
387 | fail_free_b_stat: | ||
388 | free_irq(MVME162_IRQ_SCCB_STAT, port); | ||
389 | fail_free_b_tx: | ||
390 | free_irq(MVME162_IRQ_SCCB_TX, port); | ||
391 | fail_free_a_spcond: | ||
392 | free_irq(MVME162_IRQ_SCCA_SPCOND, port); | ||
393 | fail_free_a_rx: | ||
394 | free_irq(MVME162_IRQ_SCCA_RX, port); | ||
395 | fail_free_a_stat: | ||
396 | free_irq(MVME162_IRQ_SCCA_STAT, port); | ||
397 | fail_free_a_tx: | ||
398 | free_irq(MVME162_IRQ_SCCA_TX, port); | ||
399 | fail: | ||
400 | return error; | ||
401 | } | ||
402 | #endif | ||
403 | |||
404 | |||
405 | #ifdef CONFIG_BVME6000_SCC | ||
406 | static int __init bvme6000_scc_init(void) | ||
407 | { | ||
408 | struct scc_port *port; | ||
409 | int error; | ||
410 | |||
411 | printk(KERN_INFO "SCC: BVME6000 Serial Driver\n"); | ||
412 | /* Init channel A */ | ||
413 | port = &scc_ports[0]; | ||
414 | port->channel = CHANNEL_A; | ||
415 | port->ctrlp = (volatile unsigned char *)BVME_SCC_A_ADDR; | ||
416 | port->datap = port->ctrlp + 4; | ||
417 | port->port_a = &scc_ports[0]; | ||
418 | port->port_b = &scc_ports[1]; | ||
419 | error = request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, | ||
420 | "SCC-A TX", port); | ||
421 | if (error) | ||
422 | goto fail; | ||
423 | error = request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, | ||
424 | "SCC-A status", port); | ||
425 | if (error) | ||
426 | goto fail_free_a_tx; | ||
427 | error = request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, | ||
428 | "SCC-A RX", port); | ||
429 | if (error) | ||
430 | goto fail_free_a_stat; | ||
431 | error = request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, | ||
432 | IRQF_DISABLED, "SCC-A special cond", port); | ||
433 | if (error) | ||
434 | goto fail_free_a_rx; | ||
435 | |||
436 | { | ||
437 | SCC_ACCESS_INIT(port); | ||
438 | |||
439 | /* disable interrupts for this channel */ | ||
440 | SCCwrite(INT_AND_DMA_REG, 0); | ||
441 | /* Set the interrupt vector */ | ||
442 | SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE); | ||
443 | /* Interrupt parameters: vector includes status, status low */ | ||
444 | SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); | ||
445 | SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); | ||
446 | } | ||
447 | |||
448 | /* Init channel B */ | ||
449 | port = &scc_ports[1]; | ||
450 | port->channel = CHANNEL_B; | ||
451 | port->ctrlp = (volatile unsigned char *)BVME_SCC_B_ADDR; | ||
452 | port->datap = port->ctrlp + 4; | ||
453 | port->port_a = &scc_ports[0]; | ||
454 | port->port_b = &scc_ports[1]; | ||
455 | error = request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, | ||
456 | "SCC-B TX", port); | ||
457 | if (error) | ||
458 | goto fail_free_a_spcond; | ||
459 | error = request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, | ||
460 | "SCC-B status", port); | ||
461 | if (error) | ||
462 | goto fail_free_b_tx; | ||
463 | error = request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, | ||
464 | "SCC-B RX", port); | ||
465 | if (error) | ||
466 | goto fail_free_b_stat; | ||
467 | error = request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, | ||
468 | IRQF_DISABLED, "SCC-B special cond", port); | ||
469 | if (error) | ||
470 | goto fail_free_b_rx; | ||
471 | |||
472 | { | ||
473 | SCC_ACCESS_INIT(port); /* Either channel will do */ | ||
474 | |||
475 | /* disable interrupts for this channel */ | ||
476 | SCCwrite(INT_AND_DMA_REG, 0); | ||
477 | } | ||
478 | |||
479 | /* Initialise the tty driver structures and register */ | ||
480 | scc_init_portstructs(); | ||
481 | scc_init_drivers(); | ||
482 | |||
483 | return 0; | ||
484 | |||
485 | fail: | ||
486 | free_irq(BVME_IRQ_SCCA_STAT, port); | ||
487 | fail_free_a_tx: | ||
488 | free_irq(BVME_IRQ_SCCA_RX, port); | ||
489 | fail_free_a_stat: | ||
490 | free_irq(BVME_IRQ_SCCA_SPCOND, port); | ||
491 | fail_free_a_rx: | ||
492 | free_irq(BVME_IRQ_SCCB_TX, port); | ||
493 | fail_free_a_spcond: | ||
494 | free_irq(BVME_IRQ_SCCB_STAT, port); | ||
495 | fail_free_b_tx: | ||
496 | free_irq(BVME_IRQ_SCCB_RX, port); | ||
497 | fail_free_b_stat: | ||
498 | free_irq(BVME_IRQ_SCCB_SPCOND, port); | ||
499 | fail_free_b_rx: | ||
500 | return error; | ||
501 | } | ||
502 | #endif | ||
503 | |||
504 | |||
505 | static int __init vme_scc_init(void) | ||
506 | { | ||
507 | int res = -ENODEV; | ||
508 | |||
509 | #ifdef CONFIG_MVME147_SCC | ||
510 | if (MACH_IS_MVME147) | ||
511 | res = mvme147_scc_init(); | ||
512 | #endif | ||
513 | #ifdef CONFIG_MVME162_SCC | ||
514 | if (MACH_IS_MVME16x) | ||
515 | res = mvme162_scc_init(); | ||
516 | #endif | ||
517 | #ifdef CONFIG_BVME6000_SCC | ||
518 | if (MACH_IS_BVME6000) | ||
519 | res = bvme6000_scc_init(); | ||
520 | #endif | ||
521 | return res; | ||
522 | } | ||
523 | |||
524 | module_init(vme_scc_init); | ||
525 | |||
526 | |||
527 | /*--------------------------------------------------------------------------- | ||
528 | * Interrupt handlers | ||
529 | *--------------------------------------------------------------------------*/ | ||
530 | |||
531 | static irqreturn_t scc_rx_int(int irq, void *data) | ||
532 | { | ||
533 | unsigned char ch; | ||
534 | struct scc_port *port = data; | ||
535 | struct tty_struct *tty = port->gs.port.tty; | ||
536 | SCC_ACCESS_INIT(port); | ||
537 | |||
538 | ch = SCCread_NB(RX_DATA_REG); | ||
539 | if (!tty) { | ||
540 | printk(KERN_WARNING "scc_rx_int with NULL tty!\n"); | ||
541 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); | ||
542 | return IRQ_HANDLED; | ||
543 | } | ||
544 | tty_insert_flip_char(tty, ch, 0); | ||
545 | |||
546 | /* Check if another character is already ready; in that case, the | ||
547 | * spcond_int() function must be used, because this character may have an | ||
548 | * error condition that isn't signalled by the interrupt vector used! | ||
549 | */ | ||
550 | if (SCCread(INT_PENDING_REG) & | ||
551 | (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) { | ||
552 | scc_spcond_int (irq, data); | ||
553 | return IRQ_HANDLED; | ||
554 | } | ||
555 | |||
556 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); | ||
557 | |||
558 | tty_flip_buffer_push(tty); | ||
559 | return IRQ_HANDLED; | ||
560 | } | ||
561 | |||
562 | |||
563 | static irqreturn_t scc_spcond_int(int irq, void *data) | ||
564 | { | ||
565 | struct scc_port *port = data; | ||
566 | struct tty_struct *tty = port->gs.port.tty; | ||
567 | unsigned char stat, ch, err; | ||
568 | int int_pending_mask = port->channel == CHANNEL_A ? | ||
569 | IPR_A_RX : IPR_B_RX; | ||
570 | SCC_ACCESS_INIT(port); | ||
571 | |||
572 | if (!tty) { | ||
573 | printk(KERN_WARNING "scc_spcond_int with NULL tty!\n"); | ||
574 | SCCwrite(COMMAND_REG, CR_ERROR_RESET); | ||
575 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); | ||
576 | return IRQ_HANDLED; | ||
577 | } | ||
578 | do { | ||
579 | stat = SCCread(SPCOND_STATUS_REG); | ||
580 | ch = SCCread_NB(RX_DATA_REG); | ||
581 | |||
582 | if (stat & SCSR_RX_OVERRUN) | ||
583 | err = TTY_OVERRUN; | ||
584 | else if (stat & SCSR_PARITY_ERR) | ||
585 | err = TTY_PARITY; | ||
586 | else if (stat & SCSR_CRC_FRAME_ERR) | ||
587 | err = TTY_FRAME; | ||
588 | else | ||
589 | err = 0; | ||
590 | |||
591 | tty_insert_flip_char(tty, ch, err); | ||
592 | |||
593 | /* ++TeSche: *All* errors have to be cleared manually, | ||
594 | * else the condition persists for the next chars | ||
595 | */ | ||
596 | if (err) | ||
597 | SCCwrite(COMMAND_REG, CR_ERROR_RESET); | ||
598 | |||
599 | } while(SCCread(INT_PENDING_REG) & int_pending_mask); | ||
600 | |||
601 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); | ||
602 | |||
603 | tty_flip_buffer_push(tty); | ||
604 | return IRQ_HANDLED; | ||
605 | } | ||
606 | |||
607 | |||
608 | static irqreturn_t scc_tx_int(int irq, void *data) | ||
609 | { | ||
610 | struct scc_port *port = data; | ||
611 | SCC_ACCESS_INIT(port); | ||
612 | |||
613 | if (!port->gs.port.tty) { | ||
614 | printk(KERN_WARNING "scc_tx_int with NULL tty!\n"); | ||
615 | SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); | ||
616 | SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); | ||
617 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); | ||
618 | return IRQ_HANDLED; | ||
619 | } | ||
620 | while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) { | ||
621 | if (port->x_char) { | ||
622 | SCCwrite(TX_DATA_REG, port->x_char); | ||
623 | port->x_char = 0; | ||
624 | } | ||
625 | else if ((port->gs.xmit_cnt <= 0) || | ||
626 | port->gs.port.tty->stopped || | ||
627 | port->gs.port.tty->hw_stopped) | ||
628 | break; | ||
629 | else { | ||
630 | SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]); | ||
631 | port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1); | ||
632 | if (--port->gs.xmit_cnt <= 0) | ||
633 | break; | ||
634 | } | ||
635 | } | ||
636 | if ((port->gs.xmit_cnt <= 0) || port->gs.port.tty->stopped || | ||
637 | port->gs.port.tty->hw_stopped) { | ||
638 | /* disable tx interrupts */ | ||
639 | SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); | ||
640 | SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ | ||
641 | port->gs.port.flags &= ~GS_TX_INTEN; | ||
642 | } | ||
643 | if (port->gs.port.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) | ||
644 | tty_wakeup(port->gs.port.tty); | ||
645 | |||
646 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); | ||
647 | return IRQ_HANDLED; | ||
648 | } | ||
649 | |||
650 | |||
651 | static irqreturn_t scc_stat_int(int irq, void *data) | ||
652 | { | ||
653 | struct scc_port *port = data; | ||
654 | unsigned channel = port->channel; | ||
655 | unsigned char last_sr, sr, changed; | ||
656 | SCC_ACCESS_INIT(port); | ||
657 | |||
658 | last_sr = scc_last_status_reg[channel]; | ||
659 | sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG); | ||
660 | changed = last_sr ^ sr; | ||
661 | |||
662 | if (changed & SR_DCD) { | ||
663 | port->c_dcd = !!(sr & SR_DCD); | ||
664 | if (!(port->gs.port.flags & ASYNC_CHECK_CD)) | ||
665 | ; /* Don't report DCD changes */ | ||
666 | else if (port->c_dcd) { | ||
667 | wake_up_interruptible(&port->gs.port.open_wait); | ||
668 | } | ||
669 | else { | ||
670 | if (port->gs.port.tty) | ||
671 | tty_hangup (port->gs.port.tty); | ||
672 | } | ||
673 | } | ||
674 | SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); | ||
675 | SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); | ||
676 | return IRQ_HANDLED; | ||
677 | } | ||
678 | |||
679 | |||
680 | /*--------------------------------------------------------------------------- | ||
681 | * generic_serial.c callback funtions | ||
682 | *--------------------------------------------------------------------------*/ | ||
683 | |||
684 | static void scc_disable_tx_interrupts(void *ptr) | ||
685 | { | ||
686 | struct scc_port *port = ptr; | ||
687 | unsigned long flags; | ||
688 | SCC_ACCESS_INIT(port); | ||
689 | |||
690 | local_irq_save(flags); | ||
691 | SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); | ||
692 | port->gs.port.flags &= ~GS_TX_INTEN; | ||
693 | local_irq_restore(flags); | ||
694 | } | ||
695 | |||
696 | |||
697 | static void scc_enable_tx_interrupts(void *ptr) | ||
698 | { | ||
699 | struct scc_port *port = ptr; | ||
700 | unsigned long flags; | ||
701 | SCC_ACCESS_INIT(port); | ||
702 | |||
703 | local_irq_save(flags); | ||
704 | SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB); | ||
705 | /* restart the transmitter */ | ||
706 | scc_tx_int (0, port); | ||
707 | local_irq_restore(flags); | ||
708 | } | ||
709 | |||
710 | |||
711 | static void scc_disable_rx_interrupts(void *ptr) | ||
712 | { | ||
713 | struct scc_port *port = ptr; | ||
714 | unsigned long flags; | ||
715 | SCC_ACCESS_INIT(port); | ||
716 | |||
717 | local_irq_save(flags); | ||
718 | SCCmod(INT_AND_DMA_REG, | ||
719 | ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0); | ||
720 | local_irq_restore(flags); | ||
721 | } | ||
722 | |||
723 | |||
724 | static void scc_enable_rx_interrupts(void *ptr) | ||
725 | { | ||
726 | struct scc_port *port = ptr; | ||
727 | unsigned long flags; | ||
728 | SCC_ACCESS_INIT(port); | ||
729 | |||
730 | local_irq_save(flags); | ||
731 | SCCmod(INT_AND_DMA_REG, 0xff, | ||
732 | IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL); | ||
733 | local_irq_restore(flags); | ||
734 | } | ||
735 | |||
736 | |||
737 | static int scc_carrier_raised(struct tty_port *port) | ||
738 | { | ||
739 | struct scc_port *sc = container_of(port, struct scc_port, gs.port); | ||
740 | unsigned channel = sc->channel; | ||
741 | |||
742 | return !!(scc_last_status_reg[channel] & SR_DCD); | ||
743 | } | ||
744 | |||
745 | |||
746 | static void scc_shutdown_port(void *ptr) | ||
747 | { | ||
748 | struct scc_port *port = ptr; | ||
749 | |||
750 | port->gs.port.flags &= ~ GS_ACTIVE; | ||
751 | if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) { | ||
752 | scc_setsignals (port, 0, 0); | ||
753 | } | ||
754 | } | ||
755 | |||
756 | |||
757 | static int scc_set_real_termios (void *ptr) | ||
758 | { | ||
759 | /* the SCC has char sizes 5,7,6,8 in that order! */ | ||
760 | static int chsize_map[4] = { 0, 2, 1, 3 }; | ||
761 | unsigned cflag, baud, chsize, channel, brgval = 0; | ||
762 | unsigned long flags; | ||
763 | struct scc_port *port = ptr; | ||
764 | SCC_ACCESS_INIT(port); | ||
765 | |||
766 | if (!port->gs.port.tty || !port->gs.port.tty->termios) return 0; | ||
767 | |||
768 | channel = port->channel; | ||
769 | |||
770 | if (channel == CHANNEL_A) | ||
771 | return 0; /* Settings controlled by boot PROM */ | ||
772 | |||
773 | cflag = port->gs.port.tty->termios->c_cflag; | ||
774 | baud = port->gs.baud; | ||
775 | chsize = (cflag & CSIZE) >> 4; | ||
776 | |||
777 | if (baud == 0) { | ||
778 | /* speed == 0 -> drop DTR */ | ||
779 | local_irq_save(flags); | ||
780 | SCCmod(TX_CTRL_REG, ~TCR_DTR, 0); | ||
781 | local_irq_restore(flags); | ||
782 | return 0; | ||
783 | } | ||
784 | else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) || | ||
785 | (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) || | ||
786 | (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) { | ||
787 | printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud); | ||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | if (cflag & CLOCAL) | ||
792 | port->gs.port.flags &= ~ASYNC_CHECK_CD; | ||
793 | else | ||
794 | port->gs.port.flags |= ASYNC_CHECK_CD; | ||
795 | |||
796 | #ifdef CONFIG_MVME147_SCC | ||
797 | if (MACH_IS_MVME147) | ||
798 | brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; | ||
799 | #endif | ||
800 | #ifdef CONFIG_MVME162_SCC | ||
801 | if (MACH_IS_MVME16x) | ||
802 | brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; | ||
803 | #endif | ||
804 | #ifdef CONFIG_BVME6000_SCC | ||
805 | if (MACH_IS_BVME6000) | ||
806 | brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2; | ||
807 | #endif | ||
808 | /* Now we have all parameters and can go to set them: */ | ||
809 | local_irq_save(flags); | ||
810 | |||
811 | /* receiver's character size and auto-enables */ | ||
812 | SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE), | ||
813 | (chsize_map[chsize] << 6) | | ||
814 | ((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0)); | ||
815 | /* parity and stop bits (both, Tx and Rx), clock mode never changes */ | ||
816 | SCCmod (AUX1_CTRL_REG, | ||
817 | ~(A1CR_PARITY_MASK | A1CR_MODE_MASK), | ||
818 | ((cflag & PARENB | ||
819 | ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN) | ||
820 | : A1CR_PARITY_NONE) | ||
821 | | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1))); | ||
822 | /* sender's character size, set DTR for valid baud rate */ | ||
823 | SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR); | ||
824 | /* clock sources never change */ | ||
825 | /* disable BRG before changing the value */ | ||
826 | SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0); | ||
827 | /* BRG value */ | ||
828 | SCCwrite(TIMER_LOW_REG, brgval & 0xff); | ||
829 | SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff); | ||
830 | /* BRG enable, and clock source never changes */ | ||
831 | SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB); | ||
832 | |||
833 | local_irq_restore(flags); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | |||
839 | static int scc_chars_in_buffer (void *ptr) | ||
840 | { | ||
841 | struct scc_port *port = ptr; | ||
842 | SCC_ACCESS_INIT(port); | ||
843 | |||
844 | return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1; | ||
845 | } | ||
846 | |||
847 | |||
848 | /* Comment taken from sx.c (2.4.0): | ||
849 | I haven't the foggiest why the decrement use count has to happen | ||
850 | here. The whole linux serial drivers stuff needs to be redesigned. | ||
851 | My guess is that this is a hack to minimize the impact of a bug | ||
852 | elsewhere. Thinking about it some more. (try it sometime) Try | ||
853 | running minicom on a serial port that is driven by a modularized | ||
854 | driver. Have the modem hangup. Then remove the driver module. Then | ||
855 | exit minicom. I expect an "oops". -- REW */ | ||
856 | |||
857 | static void scc_hungup(void *ptr) | ||
858 | { | ||
859 | scc_disable_tx_interrupts(ptr); | ||
860 | scc_disable_rx_interrupts(ptr); | ||
861 | } | ||
862 | |||
863 | |||
864 | static void scc_close(void *ptr) | ||
865 | { | ||
866 | scc_disable_tx_interrupts(ptr); | ||
867 | scc_disable_rx_interrupts(ptr); | ||
868 | } | ||
869 | |||
870 | |||
871 | /*--------------------------------------------------------------------------- | ||
872 | * Internal support functions | ||
873 | *--------------------------------------------------------------------------*/ | ||
874 | |||
875 | static void scc_setsignals(struct scc_port *port, int dtr, int rts) | ||
876 | { | ||
877 | unsigned long flags; | ||
878 | unsigned char t; | ||
879 | SCC_ACCESS_INIT(port); | ||
880 | |||
881 | local_irq_save(flags); | ||
882 | t = SCCread(TX_CTRL_REG); | ||
883 | if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR); | ||
884 | if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS); | ||
885 | SCCwrite(TX_CTRL_REG, t); | ||
886 | local_irq_restore(flags); | ||
887 | } | ||
888 | |||
889 | |||
890 | static void scc_send_xchar(struct tty_struct *tty, char ch) | ||
891 | { | ||
892 | struct scc_port *port = tty->driver_data; | ||
893 | |||
894 | port->x_char = ch; | ||
895 | if (ch) | ||
896 | scc_enable_tx_interrupts(port); | ||
897 | } | ||
898 | |||
899 | |||
900 | /*--------------------------------------------------------------------------- | ||
901 | * Driver entrypoints referenced from above | ||
902 | *--------------------------------------------------------------------------*/ | ||
903 | |||
904 | static int scc_open (struct tty_struct * tty, struct file * filp) | ||
905 | { | ||
906 | int line = tty->index; | ||
907 | int retval; | ||
908 | struct scc_port *port = &scc_ports[line]; | ||
909 | int i, channel = port->channel; | ||
910 | unsigned long flags; | ||
911 | SCC_ACCESS_INIT(port); | ||
912 | #if defined(CONFIG_MVME162_SCC) || defined(CONFIG_MVME147_SCC) | ||
913 | static const struct { | ||
914 | unsigned reg, val; | ||
915 | } mvme_init_tab[] = { | ||
916 | /* Values for MVME162 and MVME147 */ | ||
917 | /* no parity, 1 stop bit, async, 1:16 */ | ||
918 | { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, | ||
919 | /* parity error is special cond, ints disabled, no DMA */ | ||
920 | { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, | ||
921 | /* Rx 8 bits/char, no auto enable, Rx off */ | ||
922 | { RX_CTRL_REG, RCR_CHSIZE_8 }, | ||
923 | /* DTR off, Tx 8 bits/char, RTS off, Tx off */ | ||
924 | { TX_CTRL_REG, TCR_CHSIZE_8 }, | ||
925 | /* special features off */ | ||
926 | { AUX2_CTRL_REG, 0 }, | ||
927 | { CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG }, | ||
928 | { DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK }, | ||
929 | /* Start Rx */ | ||
930 | { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, | ||
931 | /* Start Tx */ | ||
932 | { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, | ||
933 | /* Ext/Stat ints: DCD only */ | ||
934 | { INT_CTRL_REG, ICR_ENAB_DCD_INT }, | ||
935 | /* Reset Ext/Stat ints */ | ||
936 | { COMMAND_REG, CR_EXTSTAT_RESET }, | ||
937 | /* ...again */ | ||
938 | { COMMAND_REG, CR_EXTSTAT_RESET }, | ||
939 | }; | ||
940 | #endif | ||
941 | #if defined(CONFIG_BVME6000_SCC) | ||
942 | static const struct { | ||
943 | unsigned reg, val; | ||
944 | } bvme_init_tab[] = { | ||
945 | /* Values for BVME6000 */ | ||
946 | /* no parity, 1 stop bit, async, 1:16 */ | ||
947 | { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, | ||
948 | /* parity error is special cond, ints disabled, no DMA */ | ||
949 | { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, | ||
950 | /* Rx 8 bits/char, no auto enable, Rx off */ | ||
951 | { RX_CTRL_REG, RCR_CHSIZE_8 }, | ||
952 | /* DTR off, Tx 8 bits/char, RTS off, Tx off */ | ||
953 | { TX_CTRL_REG, TCR_CHSIZE_8 }, | ||
954 | /* special features off */ | ||
955 | { AUX2_CTRL_REG, 0 }, | ||
956 | { CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG }, | ||
957 | { DPLL_CTRL_REG, DCR_BRG_ENAB }, | ||
958 | /* Start Rx */ | ||
959 | { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, | ||
960 | /* Start Tx */ | ||
961 | { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, | ||
962 | /* Ext/Stat ints: DCD only */ | ||
963 | { INT_CTRL_REG, ICR_ENAB_DCD_INT }, | ||
964 | /* Reset Ext/Stat ints */ | ||
965 | { COMMAND_REG, CR_EXTSTAT_RESET }, | ||
966 | /* ...again */ | ||
967 | { COMMAND_REG, CR_EXTSTAT_RESET }, | ||
968 | }; | ||
969 | #endif | ||
970 | if (!(port->gs.port.flags & ASYNC_INITIALIZED)) { | ||
971 | local_irq_save(flags); | ||
972 | #if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC) | ||
973 | if (MACH_IS_MVME147 || MACH_IS_MVME16x) { | ||
974 | for (i = 0; i < ARRAY_SIZE(mvme_init_tab); ++i) | ||
975 | SCCwrite(mvme_init_tab[i].reg, mvme_init_tab[i].val); | ||
976 | } | ||
977 | #endif | ||
978 | #if defined(CONFIG_BVME6000_SCC) | ||
979 | if (MACH_IS_BVME6000) { | ||
980 | for (i = 0; i < ARRAY_SIZE(bvme_init_tab); ++i) | ||
981 | SCCwrite(bvme_init_tab[i].reg, bvme_init_tab[i].val); | ||
982 | } | ||
983 | #endif | ||
984 | |||
985 | /* remember status register for detection of DCD and CTS changes */ | ||
986 | scc_last_status_reg[channel] = SCCread(STATUS_REG); | ||
987 | |||
988 | port->c_dcd = 0; /* Prevent initial 1->0 interrupt */ | ||
989 | scc_setsignals (port, 1,1); | ||
990 | local_irq_restore(flags); | ||
991 | } | ||
992 | |||
993 | tty->driver_data = port; | ||
994 | port->gs.port.tty = tty; | ||
995 | port->gs.port.count++; | ||
996 | retval = gs_init_port(&port->gs); | ||
997 | if (retval) { | ||
998 | port->gs.port.count--; | ||
999 | return retval; | ||
1000 | } | ||
1001 | port->gs.port.flags |= GS_ACTIVE; | ||
1002 | retval = gs_block_til_ready(port, filp); | ||
1003 | |||
1004 | if (retval) { | ||
1005 | port->gs.port.count--; | ||
1006 | return retval; | ||
1007 | } | ||
1008 | |||
1009 | port->c_dcd = tty_port_carrier_raised(&port->gs.port); | ||
1010 | |||
1011 | scc_enable_rx_interrupts(port); | ||
1012 | |||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | |||
1017 | static void scc_throttle (struct tty_struct * tty) | ||
1018 | { | ||
1019 | struct scc_port *port = tty->driver_data; | ||
1020 | unsigned long flags; | ||
1021 | SCC_ACCESS_INIT(port); | ||
1022 | |||
1023 | if (tty->termios->c_cflag & CRTSCTS) { | ||
1024 | local_irq_save(flags); | ||
1025 | SCCmod(TX_CTRL_REG, ~TCR_RTS, 0); | ||
1026 | local_irq_restore(flags); | ||
1027 | } | ||
1028 | if (I_IXOFF(tty)) | ||
1029 | scc_send_xchar(tty, STOP_CHAR(tty)); | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | static void scc_unthrottle (struct tty_struct * tty) | ||
1034 | { | ||
1035 | struct scc_port *port = tty->driver_data; | ||
1036 | unsigned long flags; | ||
1037 | SCC_ACCESS_INIT(port); | ||
1038 | |||
1039 | if (tty->termios->c_cflag & CRTSCTS) { | ||
1040 | local_irq_save(flags); | ||
1041 | SCCmod(TX_CTRL_REG, 0xff, TCR_RTS); | ||
1042 | local_irq_restore(flags); | ||
1043 | } | ||
1044 | if (I_IXOFF(tty)) | ||
1045 | scc_send_xchar(tty, START_CHAR(tty)); | ||
1046 | } | ||
1047 | |||
1048 | |||
1049 | static int scc_ioctl(struct tty_struct *tty, struct file *file, | ||
1050 | unsigned int cmd, unsigned long arg) | ||
1051 | { | ||
1052 | return -ENOIOCTLCMD; | ||
1053 | } | ||
1054 | |||
1055 | |||
1056 | static int scc_break_ctl(struct tty_struct *tty, int break_state) | ||
1057 | { | ||
1058 | struct scc_port *port = tty->driver_data; | ||
1059 | unsigned long flags; | ||
1060 | SCC_ACCESS_INIT(port); | ||
1061 | |||
1062 | local_irq_save(flags); | ||
1063 | SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, | ||
1064 | break_state ? TCR_SEND_BREAK : 0); | ||
1065 | local_irq_restore(flags); | ||
1066 | return 0; | ||
1067 | } | ||
1068 | |||
1069 | |||
1070 | /*--------------------------------------------------------------------------- | ||
1071 | * Serial console stuff... | ||
1072 | *--------------------------------------------------------------------------*/ | ||
1073 | |||
1074 | #define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0) | ||
1075 | |||
1076 | static void scc_ch_write (char ch) | ||
1077 | { | ||
1078 | volatile char *p = NULL; | ||
1079 | |||
1080 | #ifdef CONFIG_MVME147_SCC | ||
1081 | if (MACH_IS_MVME147) | ||
1082 | p = (volatile char *)M147_SCC_A_ADDR; | ||
1083 | #endif | ||
1084 | #ifdef CONFIG_MVME162_SCC | ||
1085 | if (MACH_IS_MVME16x) | ||
1086 | p = (volatile char *)MVME_SCC_A_ADDR; | ||
1087 | #endif | ||
1088 | #ifdef CONFIG_BVME6000_SCC | ||
1089 | if (MACH_IS_BVME6000) | ||
1090 | p = (volatile char *)BVME_SCC_A_ADDR; | ||
1091 | #endif | ||
1092 | |||
1093 | do { | ||
1094 | scc_delay(); | ||
1095 | } | ||
1096 | while (!(*p & 4)); | ||
1097 | scc_delay(); | ||
1098 | *p = 8; | ||
1099 | scc_delay(); | ||
1100 | *p = ch; | ||
1101 | } | ||
1102 | |||
1103 | /* The console must be locked when we get here. */ | ||
1104 | |||
1105 | static void scc_console_write (struct console *co, const char *str, unsigned count) | ||
1106 | { | ||
1107 | unsigned long flags; | ||
1108 | |||
1109 | local_irq_save(flags); | ||
1110 | |||
1111 | while (count--) | ||
1112 | { | ||
1113 | if (*str == '\n') | ||
1114 | scc_ch_write ('\r'); | ||
1115 | scc_ch_write (*str++); | ||
1116 | } | ||
1117 | local_irq_restore(flags); | ||
1118 | } | ||
1119 | |||
1120 | static struct tty_driver *scc_console_device(struct console *c, int *index) | ||
1121 | { | ||
1122 | *index = c->index; | ||
1123 | return scc_driver; | ||
1124 | } | ||
1125 | |||
1126 | static struct console sercons = { | ||
1127 | .name = "ttyS", | ||
1128 | .write = scc_console_write, | ||
1129 | .device = scc_console_device, | ||
1130 | .flags = CON_PRINTBUFFER, | ||
1131 | .index = -1, | ||
1132 | }; | ||
1133 | |||
1134 | |||
1135 | static int __init vme_scc_console_init(void) | ||
1136 | { | ||
1137 | if (vme_brdtype == VME_TYPE_MVME147 || | ||
1138 | vme_brdtype == VME_TYPE_MVME162 || | ||
1139 | vme_brdtype == VME_TYPE_MVME172 || | ||
1140 | vme_brdtype == VME_TYPE_BVME4000 || | ||
1141 | vme_brdtype == VME_TYPE_BVME6000) | ||
1142 | register_console(&sercons); | ||
1143 | return 0; | ||
1144 | } | ||
1145 | console_initcall(vme_scc_console_init); | ||