diff options
Diffstat (limited to 'arch/ia64/hp/sim/simserial.c')
-rw-r--r-- | arch/ia64/hp/sim/simserial.c | 705 |
1 files changed, 147 insertions, 558 deletions
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index bff0824cf8a4..c34785dca92b 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c | |||
@@ -4,16 +4,11 @@ | |||
4 | * This driver is mostly used for bringup purposes and will go away. | 4 | * This driver is mostly used for bringup purposes and will go away. |
5 | * It has a strong dependency on the system console. All outputs | 5 | * It has a strong dependency on the system console. All outputs |
6 | * are rerouted to the same facility as the one used by printk which, in our | 6 | * are rerouted to the same facility as the one used by printk which, in our |
7 | * case means sys_sim.c console (goes via the simulator). The code hereafter | 7 | * case means sys_sim.c console (goes via the simulator). |
8 | * is completely leveraged from the serial.c driver. | ||
9 | * | 8 | * |
10 | * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co | 9 | * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co |
11 | * Stephane Eranian <eranian@hpl.hp.com> | 10 | * Stephane Eranian <eranian@hpl.hp.com> |
12 | * David Mosberger-Tang <davidm@hpl.hp.com> | 11 | * David Mosberger-Tang <davidm@hpl.hp.com> |
13 | * | ||
14 | * 02/04/00 D. Mosberger Merged in serial.c bug fixes in rs_close(). | ||
15 | * 02/25/00 D. Mosberger Synced up with 2.3.99pre-5 version of serial.c. | ||
16 | * 07/30/02 D. Mosberger Replace sti()/cli() with explicit spinlocks & local irq masking | ||
17 | */ | 12 | */ |
18 | 13 | ||
19 | #include <linux/init.h> | 14 | #include <linux/init.h> |
@@ -27,15 +22,17 @@ | |||
27 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
28 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
29 | #include <linux/capability.h> | 24 | #include <linux/capability.h> |
25 | #include <linux/circ_buf.h> | ||
30 | #include <linux/console.h> | 26 | #include <linux/console.h> |
27 | #include <linux/irq.h> | ||
31 | #include <linux/module.h> | 28 | #include <linux/module.h> |
32 | #include <linux/serial.h> | 29 | #include <linux/serial.h> |
33 | #include <linux/serialP.h> | ||
34 | #include <linux/sysrq.h> | 30 | #include <linux/sysrq.h> |
31 | #include <linux/uaccess.h> | ||
32 | |||
33 | #include <asm/hpsim.h> | ||
35 | 34 | ||
36 | #include <asm/irq.h> | 35 | #include "hpsim_ssc.h" |
37 | #include <asm/hw_irq.h> | ||
38 | #include <asm/uaccess.h> | ||
39 | 36 | ||
40 | #undef SIMSERIAL_DEBUG /* define this to get some debug information */ | 37 | #undef SIMSERIAL_DEBUG /* define this to get some debug information */ |
41 | 38 | ||
@@ -43,118 +40,44 @@ | |||
43 | 40 | ||
44 | #define NR_PORTS 1 /* only one port for now */ | 41 | #define NR_PORTS 1 /* only one port for now */ |
45 | 42 | ||
46 | #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) | 43 | struct serial_state { |
47 | 44 | struct tty_port port; | |
48 | #define SSC_GETCHAR 21 | 45 | struct circ_buf xmit; |
49 | 46 | int irq; | |
50 | extern long ia64_ssc (long, long, long, long, int); | 47 | int x_char; |
51 | extern void ia64_ssc_connect_irq (long intr, long irq); | ||
52 | |||
53 | static char *serial_name = "SimSerial driver"; | ||
54 | static char *serial_version = "0.6"; | ||
55 | |||
56 | /* | ||
57 | * This has been extracted from asm/serial.h. We need one eventually but | ||
58 | * I don't know exactly what we're going to put in it so just fake one | ||
59 | * for now. | ||
60 | */ | ||
61 | #define BASE_BAUD ( 1843200 / 16 ) | ||
62 | |||
63 | #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) | ||
64 | |||
65 | /* | ||
66 | * Most of the values here are meaningless to this particular driver. | ||
67 | * However some values must be preserved for the code (leveraged from serial.c | ||
68 | * to work correctly). | ||
69 | * port must not be 0 | ||
70 | * type must not be UNKNOWN | ||
71 | * So I picked arbitrary (guess from where?) values instead | ||
72 | */ | ||
73 | static struct serial_state rs_table[NR_PORTS]={ | ||
74 | /* UART CLK PORT IRQ FLAGS */ | ||
75 | { 0, BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS,0,PORT_16550 } /* ttyS0 */ | ||
76 | }; | 48 | }; |
77 | 49 | ||
78 | /* | 50 | static struct serial_state rs_table[NR_PORTS]; |
79 | * Just for the fun of it ! | ||
80 | */ | ||
81 | static struct serial_uart_config uart_config[] = { | ||
82 | { "unknown", 1, 0 }, | ||
83 | { "8250", 1, 0 }, | ||
84 | { "16450", 1, 0 }, | ||
85 | { "16550", 1, 0 }, | ||
86 | { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, | ||
87 | { "cirrus", 1, 0 }, | ||
88 | { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, | ||
89 | { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | | ||
90 | UART_STARTECH }, | ||
91 | { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, | ||
92 | { NULL, 0} | ||
93 | }; | ||
94 | 51 | ||
95 | struct tty_driver *hp_simserial_driver; | 52 | struct tty_driver *hp_simserial_driver; |
96 | 53 | ||
97 | static struct async_struct *IRQ_ports[NR_IRQS]; | ||
98 | |||
99 | static struct console *console; | 54 | static struct console *console; |
100 | 55 | ||
101 | static unsigned char *tmp_buf; | 56 | static void receive_chars(struct tty_struct *tty) |
102 | |||
103 | extern struct console *console_drivers; /* from kernel/printk.c */ | ||
104 | |||
105 | /* | ||
106 | * ------------------------------------------------------------ | ||
107 | * rs_stop() and rs_start() | ||
108 | * | ||
109 | * This routines are called before setting or resetting tty->stopped. | ||
110 | * They enable or disable transmitter interrupts, as necessary. | ||
111 | * ------------------------------------------------------------ | ||
112 | */ | ||
113 | static void rs_stop(struct tty_struct *tty) | ||
114 | { | ||
115 | #ifdef SIMSERIAL_DEBUG | ||
116 | printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n", | ||
117 | tty->stopped, tty->hw_stopped, tty->flow_stopped); | ||
118 | #endif | ||
119 | |||
120 | } | ||
121 | |||
122 | static void rs_start(struct tty_struct *tty) | ||
123 | { | ||
124 | #ifdef SIMSERIAL_DEBUG | ||
125 | printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n", | ||
126 | tty->stopped, tty->hw_stopped, tty->flow_stopped); | ||
127 | #endif | ||
128 | } | ||
129 | |||
130 | static void receive_chars(struct tty_struct *tty) | ||
131 | { | 57 | { |
132 | unsigned char ch; | 58 | unsigned char ch; |
133 | static unsigned char seen_esc = 0; | 59 | static unsigned char seen_esc = 0; |
134 | 60 | ||
135 | while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { | 61 | while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { |
136 | if ( ch == 27 && seen_esc == 0 ) { | 62 | if (ch == 27 && seen_esc == 0) { |
137 | seen_esc = 1; | 63 | seen_esc = 1; |
138 | continue; | 64 | continue; |
139 | } else { | 65 | } else if (seen_esc == 1 && ch == 'O') { |
140 | if ( seen_esc==1 && ch == 'O' ) { | 66 | seen_esc = 2; |
141 | seen_esc = 2; | 67 | continue; |
142 | continue; | 68 | } else if (seen_esc == 2) { |
143 | } else if ( seen_esc == 2 ) { | 69 | if (ch == 'P') /* F1 */ |
144 | if ( ch == 'P' ) /* F1 */ | 70 | show_state(); |
145 | show_state(); | ||
146 | #ifdef CONFIG_MAGIC_SYSRQ | 71 | #ifdef CONFIG_MAGIC_SYSRQ |
147 | if ( ch == 'S' ) { /* F4 */ | 72 | if (ch == 'S') { /* F4 */ |
148 | do | 73 | do { |
149 | ch = ia64_ssc(0, 0, 0, 0, | 74 | ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); |
150 | SSC_GETCHAR); | 75 | } while (!ch); |
151 | while (!ch); | 76 | handle_sysrq(ch); |
152 | handle_sysrq(ch); | ||
153 | } | ||
154 | #endif | ||
155 | seen_esc = 0; | ||
156 | continue; | ||
157 | } | 77 | } |
78 | #endif | ||
79 | seen_esc = 0; | ||
80 | continue; | ||
158 | } | 81 | } |
159 | seen_esc = 0; | 82 | seen_esc = 0; |
160 | 83 | ||
@@ -169,22 +92,19 @@ static void receive_chars(struct tty_struct *tty) | |||
169 | */ | 92 | */ |
170 | static irqreturn_t rs_interrupt_single(int irq, void *dev_id) | 93 | static irqreturn_t rs_interrupt_single(int irq, void *dev_id) |
171 | { | 94 | { |
172 | struct async_struct * info; | 95 | struct serial_state *info = dev_id; |
96 | struct tty_struct *tty = tty_port_tty_get(&info->port); | ||
173 | 97 | ||
174 | /* | 98 | if (!tty) { |
175 | * I don't know exactly why they don't use the dev_id opaque data | 99 | printk(KERN_INFO "%s: tty=0 problem\n", __func__); |
176 | * pointer instead of this extra lookup table | ||
177 | */ | ||
178 | info = IRQ_ports[irq]; | ||
179 | if (!info || !info->tty) { | ||
180 | printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info); | ||
181 | return IRQ_NONE; | 100 | return IRQ_NONE; |
182 | } | 101 | } |
183 | /* | 102 | /* |
184 | * pretty simple in our case, because we only get interrupts | 103 | * pretty simple in our case, because we only get interrupts |
185 | * on inbound traffic | 104 | * on inbound traffic |
186 | */ | 105 | */ |
187 | receive_chars(info->tty); | 106 | receive_chars(tty); |
107 | tty_kref_put(tty); | ||
188 | return IRQ_HANDLED; | 108 | return IRQ_HANDLED; |
189 | } | 109 | } |
190 | 110 | ||
@@ -194,17 +114,12 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) | |||
194 | * ------------------------------------------------------------------- | 114 | * ------------------------------------------------------------------- |
195 | */ | 115 | */ |
196 | 116 | ||
197 | static void do_softint(struct work_struct *private_) | ||
198 | { | ||
199 | printk(KERN_ERR "simserial: do_softint called\n"); | ||
200 | } | ||
201 | |||
202 | static int rs_put_char(struct tty_struct *tty, unsigned char ch) | 117 | static int rs_put_char(struct tty_struct *tty, unsigned char ch) |
203 | { | 118 | { |
204 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 119 | struct serial_state *info = tty->driver_data; |
205 | unsigned long flags; | 120 | unsigned long flags; |
206 | 121 | ||
207 | if (!tty || !info->xmit.buf) | 122 | if (!info->xmit.buf) |
208 | return 0; | 123 | return 0; |
209 | 124 | ||
210 | local_irq_save(flags); | 125 | local_irq_save(flags); |
@@ -218,12 +133,12 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) | |||
218 | return 1; | 133 | return 1; |
219 | } | 134 | } |
220 | 135 | ||
221 | static void transmit_chars(struct async_struct *info, int *intr_done) | 136 | static void transmit_chars(struct tty_struct *tty, struct serial_state *info, |
137 | int *intr_done) | ||
222 | { | 138 | { |
223 | int count; | 139 | int count; |
224 | unsigned long flags; | 140 | unsigned long flags; |
225 | 141 | ||
226 | |||
227 | local_irq_save(flags); | 142 | local_irq_save(flags); |
228 | 143 | ||
229 | if (info->x_char) { | 144 | if (info->x_char) { |
@@ -231,16 +146,16 @@ static void transmit_chars(struct async_struct *info, int *intr_done) | |||
231 | 146 | ||
232 | console->write(console, &c, 1); | 147 | console->write(console, &c, 1); |
233 | 148 | ||
234 | info->state->icount.tx++; | ||
235 | info->x_char = 0; | 149 | info->x_char = 0; |
236 | 150 | ||
237 | goto out; | 151 | goto out; |
238 | } | 152 | } |
239 | 153 | ||
240 | if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { | 154 | if (info->xmit.head == info->xmit.tail || tty->stopped || |
155 | tty->hw_stopped) { | ||
241 | #ifdef SIMSERIAL_DEBUG | 156 | #ifdef SIMSERIAL_DEBUG |
242 | printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", | 157 | printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", |
243 | info->xmit.head, info->xmit.tail, info->tty->stopped); | 158 | info->xmit.head, info->xmit.tail, tty->stopped); |
244 | #endif | 159 | #endif |
245 | goto out; | 160 | goto out; |
246 | } | 161 | } |
@@ -272,24 +187,24 @@ out: | |||
272 | 187 | ||
273 | static void rs_flush_chars(struct tty_struct *tty) | 188 | static void rs_flush_chars(struct tty_struct *tty) |
274 | { | 189 | { |
275 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 190 | struct serial_state *info = tty->driver_data; |
276 | 191 | ||
277 | if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped || | 192 | if (info->xmit.head == info->xmit.tail || tty->stopped || |
278 | !info->xmit.buf) | 193 | tty->hw_stopped || !info->xmit.buf) |
279 | return; | 194 | return; |
280 | 195 | ||
281 | transmit_chars(info, NULL); | 196 | transmit_chars(tty, info, NULL); |
282 | } | 197 | } |
283 | 198 | ||
284 | |||
285 | static int rs_write(struct tty_struct * tty, | 199 | static int rs_write(struct tty_struct * tty, |
286 | const unsigned char *buf, int count) | 200 | const unsigned char *buf, int count) |
287 | { | 201 | { |
202 | struct serial_state *info = tty->driver_data; | ||
288 | int c, ret = 0; | 203 | int c, ret = 0; |
289 | struct async_struct *info = (struct async_struct *)tty->driver_data; | ||
290 | unsigned long flags; | 204 | unsigned long flags; |
291 | 205 | ||
292 | if (!tty || !info->xmit.buf || !tmp_buf) return 0; | 206 | if (!info->xmit.buf) |
207 | return 0; | ||
293 | 208 | ||
294 | local_irq_save(flags); | 209 | local_irq_save(flags); |
295 | while (1) { | 210 | while (1) { |
@@ -310,30 +225,30 @@ static int rs_write(struct tty_struct * tty, | |||
310 | /* | 225 | /* |
311 | * Hey, we transmit directly from here in our case | 226 | * Hey, we transmit directly from here in our case |
312 | */ | 227 | */ |
313 | if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) | 228 | if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) && |
314 | && !tty->stopped && !tty->hw_stopped) { | 229 | !tty->stopped && !tty->hw_stopped) |
315 | transmit_chars(info, NULL); | 230 | transmit_chars(tty, info, NULL); |
316 | } | 231 | |
317 | return ret; | 232 | return ret; |
318 | } | 233 | } |
319 | 234 | ||
320 | static int rs_write_room(struct tty_struct *tty) | 235 | static int rs_write_room(struct tty_struct *tty) |
321 | { | 236 | { |
322 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 237 | struct serial_state *info = tty->driver_data; |
323 | 238 | ||
324 | return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); | 239 | return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); |
325 | } | 240 | } |
326 | 241 | ||
327 | static int rs_chars_in_buffer(struct tty_struct *tty) | 242 | static int rs_chars_in_buffer(struct tty_struct *tty) |
328 | { | 243 | { |
329 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 244 | struct serial_state *info = tty->driver_data; |
330 | 245 | ||
331 | return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); | 246 | return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); |
332 | } | 247 | } |
333 | 248 | ||
334 | static void rs_flush_buffer(struct tty_struct *tty) | 249 | static void rs_flush_buffer(struct tty_struct *tty) |
335 | { | 250 | { |
336 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 251 | struct serial_state *info = tty->driver_data; |
337 | unsigned long flags; | 252 | unsigned long flags; |
338 | 253 | ||
339 | local_irq_save(flags); | 254 | local_irq_save(flags); |
@@ -349,7 +264,7 @@ static void rs_flush_buffer(struct tty_struct *tty) | |||
349 | */ | 264 | */ |
350 | static void rs_send_xchar(struct tty_struct *tty, char ch) | 265 | static void rs_send_xchar(struct tty_struct *tty, char ch) |
351 | { | 266 | { |
352 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 267 | struct serial_state *info = tty->driver_data; |
353 | 268 | ||
354 | info->x_char = ch; | 269 | info->x_char = ch; |
355 | if (ch) { | 270 | if (ch) { |
@@ -357,7 +272,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) | |||
357 | * I guess we could call console->write() directly but | 272 | * I guess we could call console->write() directly but |
358 | * let's do that for now. | 273 | * let's do that for now. |
359 | */ | 274 | */ |
360 | transmit_chars(info, NULL); | 275 | transmit_chars(tty, info, NULL); |
361 | } | 276 | } |
362 | } | 277 | } |
363 | 278 | ||
@@ -371,14 +286,15 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) | |||
371 | */ | 286 | */ |
372 | static void rs_throttle(struct tty_struct * tty) | 287 | static void rs_throttle(struct tty_struct * tty) |
373 | { | 288 | { |
374 | if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); | 289 | if (I_IXOFF(tty)) |
290 | rs_send_xchar(tty, STOP_CHAR(tty)); | ||
375 | 291 | ||
376 | printk(KERN_INFO "simrs_throttle called\n"); | 292 | printk(KERN_INFO "simrs_throttle called\n"); |
377 | } | 293 | } |
378 | 294 | ||
379 | static void rs_unthrottle(struct tty_struct * tty) | 295 | static void rs_unthrottle(struct tty_struct * tty) |
380 | { | 296 | { |
381 | struct async_struct *info = (struct async_struct *)tty->driver_data; | 297 | struct serial_state *info = tty->driver_data; |
382 | 298 | ||
383 | if (I_IXOFF(tty)) { | 299 | if (I_IXOFF(tty)) { |
384 | if (info->x_char) | 300 | if (info->x_char) |
@@ -389,7 +305,6 @@ static void rs_unthrottle(struct tty_struct * tty) | |||
389 | printk(KERN_INFO "simrs_unthrottle called\n"); | 305 | printk(KERN_INFO "simrs_unthrottle called\n"); |
390 | } | 306 | } |
391 | 307 | ||
392 | |||
393 | static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) | 308 | static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) |
394 | { | 309 | { |
395 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | 310 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && |
@@ -400,48 +315,21 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) | |||
400 | } | 315 | } |
401 | 316 | ||
402 | switch (cmd) { | 317 | switch (cmd) { |
403 | case TIOCGSERIAL: | 318 | case TIOCGSERIAL: |
404 | printk(KERN_INFO "simrs_ioctl TIOCGSERIAL called\n"); | 319 | case TIOCSSERIAL: |
405 | return 0; | 320 | case TIOCSERGSTRUCT: |
406 | case TIOCSSERIAL: | 321 | case TIOCMIWAIT: |
407 | printk(KERN_INFO "simrs_ioctl TIOCSSERIAL called\n"); | 322 | return 0; |
408 | return 0; | 323 | case TIOCSERCONFIG: |
409 | case TIOCSERCONFIG: | 324 | case TIOCSERGETLSR: /* Get line status register */ |
410 | printk(KERN_INFO "rs_ioctl: TIOCSERCONFIG called\n"); | 325 | return -EINVAL; |
411 | return -EINVAL; | 326 | case TIOCSERGWILD: |
412 | 327 | case TIOCSERSWILD: | |
413 | case TIOCSERGETLSR: /* Get line status register */ | 328 | /* "setserial -W" is called in Debian boot */ |
414 | printk(KERN_INFO "rs_ioctl: TIOCSERGETLSR called\n"); | 329 | printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); |
415 | return -EINVAL; | 330 | return 0; |
416 | 331 | } | |
417 | case TIOCSERGSTRUCT: | 332 | return -ENOIOCTLCMD; |
418 | printk(KERN_INFO "rs_ioctl: TIOCSERGSTRUCT called\n"); | ||
419 | #if 0 | ||
420 | if (copy_to_user((struct async_struct *) arg, | ||
421 | info, sizeof(struct async_struct))) | ||
422 | return -EFAULT; | ||
423 | #endif | ||
424 | return 0; | ||
425 | |||
426 | /* | ||
427 | * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change | ||
428 | * - mask passed in arg for lines of interest | ||
429 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | ||
430 | * Caller should use TIOCGICOUNT to see which one it was | ||
431 | */ | ||
432 | case TIOCMIWAIT: | ||
433 | printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n"); | ||
434 | return 0; | ||
435 | case TIOCSERGWILD: | ||
436 | case TIOCSERSWILD: | ||
437 | /* "setserial -W" is called in Debian boot */ | ||
438 | printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n"); | ||
439 | return 0; | ||
440 | |||
441 | default: | ||
442 | return -ENOIOCTLCMD; | ||
443 | } | ||
444 | return 0; | ||
445 | } | 333 | } |
446 | 334 | ||
447 | #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) | 335 | #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) |
@@ -452,220 +340,50 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | |||
452 | if ((old_termios->c_cflag & CRTSCTS) && | 340 | if ((old_termios->c_cflag & CRTSCTS) && |
453 | !(tty->termios->c_cflag & CRTSCTS)) { | 341 | !(tty->termios->c_cflag & CRTSCTS)) { |
454 | tty->hw_stopped = 0; | 342 | tty->hw_stopped = 0; |
455 | rs_start(tty); | ||
456 | } | 343 | } |
457 | } | 344 | } |
458 | /* | 345 | /* |
459 | * This routine will shutdown a serial port; interrupts are disabled, and | 346 | * This routine will shutdown a serial port; interrupts are disabled, and |
460 | * DTR is dropped if the hangup on close termio flag is on. | 347 | * DTR is dropped if the hangup on close termio flag is on. |
461 | */ | 348 | */ |
462 | static void shutdown(struct async_struct * info) | 349 | static void shutdown(struct tty_port *port) |
463 | { | 350 | { |
464 | unsigned long flags; | 351 | struct serial_state *info = container_of(port, struct serial_state, |
465 | struct serial_state *state; | 352 | port); |
466 | int retval; | 353 | unsigned long flags; |
467 | |||
468 | if (!(info->flags & ASYNC_INITIALIZED)) return; | ||
469 | |||
470 | state = info->state; | ||
471 | |||
472 | #ifdef SIMSERIAL_DEBUG | ||
473 | printk("Shutting down serial port %d (irq %d)....", info->line, | ||
474 | state->irq); | ||
475 | #endif | ||
476 | 354 | ||
477 | local_irq_save(flags); | 355 | local_irq_save(flags); |
478 | { | 356 | if (info->irq) |
479 | /* | 357 | free_irq(info->irq, info); |
480 | * First unlink the serial port from the IRQ chain... | ||
481 | */ | ||
482 | if (info->next_port) | ||
483 | info->next_port->prev_port = info->prev_port; | ||
484 | if (info->prev_port) | ||
485 | info->prev_port->next_port = info->next_port; | ||
486 | else | ||
487 | IRQ_ports[state->irq] = info->next_port; | ||
488 | |||
489 | /* | ||
490 | * Free the IRQ, if necessary | ||
491 | */ | ||
492 | if (state->irq && (!IRQ_ports[state->irq] || | ||
493 | !IRQ_ports[state->irq]->next_port)) { | ||
494 | if (IRQ_ports[state->irq]) { | ||
495 | free_irq(state->irq, NULL); | ||
496 | retval = request_irq(state->irq, rs_interrupt_single, | ||
497 | IRQ_T(info), "serial", NULL); | ||
498 | |||
499 | if (retval) | ||
500 | printk(KERN_ERR "serial shutdown: request_irq: error %d" | ||
501 | " Couldn't reacquire IRQ.\n", retval); | ||
502 | } else | ||
503 | free_irq(state->irq, NULL); | ||
504 | } | ||
505 | |||
506 | if (info->xmit.buf) { | ||
507 | free_page((unsigned long) info->xmit.buf); | ||
508 | info->xmit.buf = NULL; | ||
509 | } | ||
510 | |||
511 | if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); | ||
512 | 358 | ||
513 | info->flags &= ~ASYNC_INITIALIZED; | 359 | if (info->xmit.buf) { |
360 | free_page((unsigned long) info->xmit.buf); | ||
361 | info->xmit.buf = NULL; | ||
514 | } | 362 | } |
515 | local_irq_restore(flags); | 363 | local_irq_restore(flags); |
516 | } | 364 | } |
517 | 365 | ||
518 | /* | ||
519 | * ------------------------------------------------------------ | ||
520 | * rs_close() | ||
521 | * | ||
522 | * This routine is called when the serial port gets closed. First, we | ||
523 | * wait for the last remaining data to be sent. Then, we unlink its | ||
524 | * async structure from the interrupt chain if necessary, and we free | ||
525 | * that IRQ if nothing is left in the chain. | ||
526 | * ------------------------------------------------------------ | ||
527 | */ | ||
528 | static void rs_close(struct tty_struct *tty, struct file * filp) | 366 | static void rs_close(struct tty_struct *tty, struct file * filp) |
529 | { | 367 | { |
530 | struct async_struct * info = (struct async_struct *)tty->driver_data; | 368 | struct serial_state *info = tty->driver_data; |
531 | struct serial_state *state; | ||
532 | unsigned long flags; | ||
533 | |||
534 | if (!info ) return; | ||
535 | |||
536 | state = info->state; | ||
537 | |||
538 | local_irq_save(flags); | ||
539 | if (tty_hung_up_p(filp)) { | ||
540 | #ifdef SIMSERIAL_DEBUG | ||
541 | printk("rs_close: hung_up\n"); | ||
542 | #endif | ||
543 | local_irq_restore(flags); | ||
544 | return; | ||
545 | } | ||
546 | #ifdef SIMSERIAL_DEBUG | ||
547 | printk("rs_close ttys%d, count = %d\n", info->line, state->count); | ||
548 | #endif | ||
549 | if ((tty->count == 1) && (state->count != 1)) { | ||
550 | /* | ||
551 | * Uh, oh. tty->count is 1, which means that the tty | ||
552 | * structure will be freed. state->count should always | ||
553 | * be one in these conditions. If it's greater than | ||
554 | * one, we've got real problems, since it means the | ||
555 | * serial port won't be shutdown. | ||
556 | */ | ||
557 | printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, " | ||
558 | "state->count is %d\n", state->count); | ||
559 | state->count = 1; | ||
560 | } | ||
561 | if (--state->count < 0) { | ||
562 | printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", | ||
563 | info->line, state->count); | ||
564 | state->count = 0; | ||
565 | } | ||
566 | if (state->count) { | ||
567 | local_irq_restore(flags); | ||
568 | return; | ||
569 | } | ||
570 | info->flags |= ASYNC_CLOSING; | ||
571 | local_irq_restore(flags); | ||
572 | 369 | ||
573 | /* | 370 | tty_port_close(&info->port, tty, filp); |
574 | * Now we wait for the transmit buffer to clear; and we notify | ||
575 | * the line discipline to only process XON/XOFF characters. | ||
576 | */ | ||
577 | shutdown(info); | ||
578 | rs_flush_buffer(tty); | ||
579 | tty_ldisc_flush(tty); | ||
580 | info->event = 0; | ||
581 | info->tty = NULL; | ||
582 | if (info->blocked_open) { | ||
583 | if (info->close_delay) | ||
584 | schedule_timeout_interruptible(info->close_delay); | ||
585 | wake_up_interruptible(&info->open_wait); | ||
586 | } | ||
587 | info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); | ||
588 | wake_up_interruptible(&info->close_wait); | ||
589 | } | 371 | } |
590 | 372 | ||
591 | /* | ||
592 | * rs_wait_until_sent() --- wait until the transmitter is empty | ||
593 | */ | ||
594 | static void rs_wait_until_sent(struct tty_struct *tty, int timeout) | ||
595 | { | ||
596 | } | ||
597 | |||
598 | |||
599 | /* | ||
600 | * rs_hangup() --- called by tty_hangup() when a hangup is signaled. | ||
601 | */ | ||
602 | static void rs_hangup(struct tty_struct *tty) | 373 | static void rs_hangup(struct tty_struct *tty) |
603 | { | 374 | { |
604 | struct async_struct * info = (struct async_struct *)tty->driver_data; | 375 | struct serial_state *info = tty->driver_data; |
605 | struct serial_state *state = info->state; | ||
606 | |||
607 | #ifdef SIMSERIAL_DEBUG | ||
608 | printk("rs_hangup: called\n"); | ||
609 | #endif | ||
610 | |||
611 | state = info->state; | ||
612 | 376 | ||
613 | rs_flush_buffer(tty); | 377 | rs_flush_buffer(tty); |
614 | if (info->flags & ASYNC_CLOSING) | 378 | tty_port_hangup(&info->port); |
615 | return; | ||
616 | shutdown(info); | ||
617 | |||
618 | info->event = 0; | ||
619 | state->count = 0; | ||
620 | info->flags &= ~ASYNC_NORMAL_ACTIVE; | ||
621 | info->tty = NULL; | ||
622 | wake_up_interruptible(&info->open_wait); | ||
623 | } | 379 | } |
624 | 380 | ||
625 | 381 | static int activate(struct tty_port *port, struct tty_struct *tty) | |
626 | static int get_async_struct(int line, struct async_struct **ret_info) | ||
627 | { | 382 | { |
628 | struct async_struct *info; | 383 | struct serial_state *state = container_of(port, struct serial_state, |
629 | struct serial_state *sstate; | 384 | port); |
630 | 385 | unsigned long flags, page; | |
631 | sstate = rs_table + line; | 386 | int retval = 0; |
632 | sstate->count++; | ||
633 | if (sstate->info) { | ||
634 | *ret_info = sstate->info; | ||
635 | return 0; | ||
636 | } | ||
637 | info = kzalloc(sizeof(struct async_struct), GFP_KERNEL); | ||
638 | if (!info) { | ||
639 | sstate->count--; | ||
640 | return -ENOMEM; | ||
641 | } | ||
642 | init_waitqueue_head(&info->open_wait); | ||
643 | init_waitqueue_head(&info->close_wait); | ||
644 | init_waitqueue_head(&info->delta_msr_wait); | ||
645 | info->magic = SERIAL_MAGIC; | ||
646 | info->port = sstate->port; | ||
647 | info->flags = sstate->flags; | ||
648 | info->xmit_fifo_size = sstate->xmit_fifo_size; | ||
649 | info->line = line; | ||
650 | INIT_WORK(&info->work, do_softint); | ||
651 | info->state = sstate; | ||
652 | if (sstate->info) { | ||
653 | kfree(info); | ||
654 | *ret_info = sstate->info; | ||
655 | return 0; | ||
656 | } | ||
657 | *ret_info = sstate->info = info; | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static int | ||
662 | startup(struct async_struct *info) | ||
663 | { | ||
664 | unsigned long flags; | ||
665 | int retval=0; | ||
666 | irq_handler_t handler; | ||
667 | struct serial_state *state= info->state; | ||
668 | unsigned long page; | ||
669 | 387 | ||
670 | page = get_zeroed_page(GFP_KERNEL); | 388 | page = get_zeroed_page(GFP_KERNEL); |
671 | if (!page) | 389 | if (!page) |
@@ -673,86 +391,31 @@ startup(struct async_struct *info) | |||
673 | 391 | ||
674 | local_irq_save(flags); | 392 | local_irq_save(flags); |
675 | 393 | ||
676 | if (info->flags & ASYNC_INITIALIZED) { | 394 | if (state->xmit.buf) |
677 | free_page(page); | ||
678 | goto errout; | ||
679 | } | ||
680 | |||
681 | if (!state->port || !state->type) { | ||
682 | if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); | ||
683 | free_page(page); | ||
684 | goto errout; | ||
685 | } | ||
686 | if (info->xmit.buf) | ||
687 | free_page(page); | 395 | free_page(page); |
688 | else | 396 | else |
689 | info->xmit.buf = (unsigned char *) page; | 397 | state->xmit.buf = (unsigned char *) page; |
690 | |||
691 | #ifdef SIMSERIAL_DEBUG | ||
692 | printk("startup: ttys%d (irq %d)...", info->line, state->irq); | ||
693 | #endif | ||
694 | 398 | ||
695 | /* | 399 | if (state->irq) { |
696 | * Allocate the IRQ if necessary | 400 | retval = request_irq(state->irq, rs_interrupt_single, 0, |
697 | */ | 401 | "simserial", state); |
698 | if (state->irq && (!IRQ_ports[state->irq] || | 402 | if (retval) |
699 | !IRQ_ports[state->irq]->next_port)) { | ||
700 | if (IRQ_ports[state->irq]) { | ||
701 | retval = -EBUSY; | ||
702 | goto errout; | ||
703 | } else | ||
704 | handler = rs_interrupt_single; | ||
705 | |||
706 | retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL); | ||
707 | if (retval) { | ||
708 | if (capable(CAP_SYS_ADMIN)) { | ||
709 | if (info->tty) | ||
710 | set_bit(TTY_IO_ERROR, | ||
711 | &info->tty->flags); | ||
712 | retval = 0; | ||
713 | } | ||
714 | goto errout; | 403 | goto errout; |
715 | } | ||
716 | } | 404 | } |
717 | 405 | ||
718 | /* | 406 | state->xmit.head = state->xmit.tail = 0; |
719 | * Insert serial port into IRQ chain. | ||
720 | */ | ||
721 | info->prev_port = NULL; | ||
722 | info->next_port = IRQ_ports[state->irq]; | ||
723 | if (info->next_port) | ||
724 | info->next_port->prev_port = info; | ||
725 | IRQ_ports[state->irq] = info; | ||
726 | |||
727 | if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); | ||
728 | |||
729 | info->xmit.head = info->xmit.tail = 0; | ||
730 | |||
731 | #if 0 | ||
732 | /* | ||
733 | * Set up serial timers... | ||
734 | */ | ||
735 | timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; | ||
736 | timer_active |= 1 << RS_TIMER; | ||
737 | #endif | ||
738 | 407 | ||
739 | /* | 408 | /* |
740 | * Set up the tty->alt_speed kludge | 409 | * Set up the tty->alt_speed kludge |
741 | */ | 410 | */ |
742 | if (info->tty) { | 411 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) |
743 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | 412 | tty->alt_speed = 57600; |
744 | info->tty->alt_speed = 57600; | 413 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) |
745 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | 414 | tty->alt_speed = 115200; |
746 | info->tty->alt_speed = 115200; | 415 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) |
747 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) | 416 | tty->alt_speed = 230400; |
748 | info->tty->alt_speed = 230400; | 417 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) |
749 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) | 418 | tty->alt_speed = 460800; |
750 | info->tty->alt_speed = 460800; | ||
751 | } | ||
752 | |||
753 | info->flags |= ASYNC_INITIALIZED; | ||
754 | local_irq_restore(flags); | ||
755 | return 0; | ||
756 | 419 | ||
757 | errout: | 420 | errout: |
758 | local_irq_restore(flags); | 421 | local_irq_restore(flags); |
@@ -768,56 +431,11 @@ errout: | |||
768 | */ | 431 | */ |
769 | static int rs_open(struct tty_struct *tty, struct file * filp) | 432 | static int rs_open(struct tty_struct *tty, struct file * filp) |
770 | { | 433 | { |
771 | struct async_struct *info; | 434 | struct serial_state *info = rs_table + tty->index; |
772 | int retval, line; | 435 | struct tty_port *port = &info->port; |
773 | unsigned long page; | ||
774 | 436 | ||
775 | line = tty->index; | ||
776 | if ((line < 0) || (line >= NR_PORTS)) | ||
777 | return -ENODEV; | ||
778 | retval = get_async_struct(line, &info); | ||
779 | if (retval) | ||
780 | return retval; | ||
781 | tty->driver_data = info; | 437 | tty->driver_data = info; |
782 | info->tty = tty; | 438 | tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
783 | |||
784 | #ifdef SIMSERIAL_DEBUG | ||
785 | printk("rs_open %s, count = %d\n", tty->name, info->state->count); | ||
786 | #endif | ||
787 | info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
788 | |||
789 | if (!tmp_buf) { | ||
790 | page = get_zeroed_page(GFP_KERNEL); | ||
791 | if (!page) | ||
792 | return -ENOMEM; | ||
793 | if (tmp_buf) | ||
794 | free_page(page); | ||
795 | else | ||
796 | tmp_buf = (unsigned char *) page; | ||
797 | } | ||
798 | |||
799 | /* | ||
800 | * If the port is the middle of closing, bail out now | ||
801 | */ | ||
802 | if (tty_hung_up_p(filp) || | ||
803 | (info->flags & ASYNC_CLOSING)) { | ||
804 | if (info->flags & ASYNC_CLOSING) | ||
805 | interruptible_sleep_on(&info->close_wait); | ||
806 | #ifdef SERIAL_DO_RESTART | ||
807 | return ((info->flags & ASYNC_HUP_NOTIFY) ? | ||
808 | -EAGAIN : -ERESTARTSYS); | ||
809 | #else | ||
810 | return -EAGAIN; | ||
811 | #endif | ||
812 | } | ||
813 | |||
814 | /* | ||
815 | * Start up serial port | ||
816 | */ | ||
817 | retval = startup(info); | ||
818 | if (retval) { | ||
819 | return retval; | ||
820 | } | ||
821 | 439 | ||
822 | /* | 440 | /* |
823 | * figure out which console to use (should be one already) | 441 | * figure out which console to use (should be one already) |
@@ -828,30 +446,21 @@ static int rs_open(struct tty_struct *tty, struct file * filp) | |||
828 | console = console->next; | 446 | console = console->next; |
829 | } | 447 | } |
830 | 448 | ||
831 | #ifdef SIMSERIAL_DEBUG | 449 | return tty_port_open(port, tty, filp); |
832 | printk("rs_open ttys%d successful\n", info->line); | ||
833 | #endif | ||
834 | return 0; | ||
835 | } | 450 | } |
836 | 451 | ||
837 | /* | 452 | /* |
838 | * /proc fs routines.... | 453 | * /proc fs routines.... |
839 | */ | 454 | */ |
840 | 455 | ||
841 | static inline void line_info(struct seq_file *m, struct serial_state *state) | ||
842 | { | ||
843 | seq_printf(m, "%d: uart:%s port:%lX irq:%d\n", | ||
844 | state->line, uart_config[state->type].name, | ||
845 | state->port, state->irq); | ||
846 | } | ||
847 | |||
848 | static int rs_proc_show(struct seq_file *m, void *v) | 456 | static int rs_proc_show(struct seq_file *m, void *v) |
849 | { | 457 | { |
850 | int i; | 458 | int i; |
851 | 459 | ||
852 | seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version); | 460 | seq_printf(m, "simserinfo:1.0\n"); |
853 | for (i = 0; i < NR_PORTS; i++) | 461 | for (i = 0; i < NR_PORTS; i++) |
854 | line_info(m, &rs_table[i]); | 462 | seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n", |
463 | i, rs_table[i].irq); | ||
855 | return 0; | 464 | return 0; |
856 | } | 465 | } |
857 | 466 | ||
@@ -868,25 +477,6 @@ static const struct file_operations rs_proc_fops = { | |||
868 | .release = single_release, | 477 | .release = single_release, |
869 | }; | 478 | }; |
870 | 479 | ||
871 | /* | ||
872 | * --------------------------------------------------------------------- | ||
873 | * rs_init() and friends | ||
874 | * | ||
875 | * rs_init() is called at boot-time to initialize the serial driver. | ||
876 | * --------------------------------------------------------------------- | ||
877 | */ | ||
878 | |||
879 | /* | ||
880 | * This routine prints out the appropriate serial driver version | ||
881 | * number, and identifies which options were configured into this | ||
882 | * driver. | ||
883 | */ | ||
884 | static inline void show_serial_version(void) | ||
885 | { | ||
886 | printk(KERN_INFO "%s version %s with", serial_name, serial_version); | ||
887 | printk(KERN_INFO " no serial options enabled\n"); | ||
888 | } | ||
889 | |||
890 | static const struct tty_operations hp_ops = { | 480 | static const struct tty_operations hp_ops = { |
891 | .open = rs_open, | 481 | .open = rs_open, |
892 | .close = rs_close, | 482 | .close = rs_close, |
@@ -901,34 +491,31 @@ static const struct tty_operations hp_ops = { | |||
901 | .unthrottle = rs_unthrottle, | 491 | .unthrottle = rs_unthrottle, |
902 | .send_xchar = rs_send_xchar, | 492 | .send_xchar = rs_send_xchar, |
903 | .set_termios = rs_set_termios, | 493 | .set_termios = rs_set_termios, |
904 | .stop = rs_stop, | ||
905 | .start = rs_start, | ||
906 | .hangup = rs_hangup, | 494 | .hangup = rs_hangup, |
907 | .wait_until_sent = rs_wait_until_sent, | ||
908 | .proc_fops = &rs_proc_fops, | 495 | .proc_fops = &rs_proc_fops, |
909 | }; | 496 | }; |
910 | 497 | ||
911 | /* | 498 | static const struct tty_port_operations hp_port_ops = { |
912 | * The serial driver boot-time initialization code! | 499 | .activate = activate, |
913 | */ | 500 | .shutdown = shutdown, |
914 | static int __init | 501 | }; |
915 | simrs_init (void) | 502 | |
503 | static int __init simrs_init(void) | ||
916 | { | 504 | { |
917 | int i, rc; | 505 | struct serial_state *state; |
918 | struct serial_state *state; | 506 | int retval; |
919 | 507 | ||
920 | if (!ia64_platform_is("hpsim")) | 508 | if (!ia64_platform_is("hpsim")) |
921 | return -ENODEV; | 509 | return -ENODEV; |
922 | 510 | ||
923 | hp_simserial_driver = alloc_tty_driver(1); | 511 | hp_simserial_driver = alloc_tty_driver(NR_PORTS); |
924 | if (!hp_simserial_driver) | 512 | if (!hp_simserial_driver) |
925 | return -ENOMEM; | 513 | return -ENOMEM; |
926 | 514 | ||
927 | show_serial_version(); | 515 | printk(KERN_INFO "SimSerial driver with no serial options enabled\n"); |
928 | 516 | ||
929 | /* Initialize the tty_driver structure */ | 517 | /* Initialize the tty_driver structure */ |
930 | 518 | ||
931 | hp_simserial_driver->owner = THIS_MODULE; | ||
932 | hp_simserial_driver->driver_name = "simserial"; | 519 | hp_simserial_driver->driver_name = "simserial"; |
933 | hp_simserial_driver->name = "ttyS"; | 520 | hp_simserial_driver->name = "ttyS"; |
934 | hp_simserial_driver->major = TTY_MAJOR; | 521 | hp_simserial_driver->major = TTY_MAJOR; |
@@ -941,31 +528,33 @@ simrs_init (void) | |||
941 | hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; | 528 | hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; |
942 | tty_set_operations(hp_simserial_driver, &hp_ops); | 529 | tty_set_operations(hp_simserial_driver, &hp_ops); |
943 | 530 | ||
944 | /* | 531 | state = rs_table; |
945 | * Let's have a little bit of fun ! | 532 | tty_port_init(&state->port); |
946 | */ | 533 | state->port.ops = &hp_port_ops; |
947 | for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { | 534 | state->port.close_delay = 0; /* XXX really 0? */ |
948 | 535 | ||
949 | if (state->type == PORT_UNKNOWN) continue; | 536 | retval = hpsim_get_irq(KEYBOARD_INTR); |
537 | if (retval < 0) { | ||
538 | printk(KERN_ERR "%s: out of interrupt vectors!\n", | ||
539 | __func__); | ||
540 | goto err_free_tty; | ||
541 | } | ||
950 | 542 | ||
951 | if (!state->irq) { | 543 | state->irq = retval; |
952 | if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0) | ||
953 | panic("%s: out of interrupt vectors!\n", | ||
954 | __func__); | ||
955 | state->irq = rc; | ||
956 | ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq); | ||
957 | } | ||
958 | 544 | ||
959 | printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n", | 545 | /* the port is imaginary */ |
960 | state->line, | 546 | printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq); |
961 | state->port, state->irq, | ||
962 | uart_config[state->type].name); | ||
963 | } | ||
964 | 547 | ||
965 | if (tty_register_driver(hp_simserial_driver)) | 548 | retval = tty_register_driver(hp_simserial_driver); |
966 | panic("Couldn't register simserial driver\n"); | 549 | if (retval) { |
550 | printk(KERN_ERR "Couldn't register simserial driver\n"); | ||
551 | goto err_free_tty; | ||
552 | } | ||
967 | 553 | ||
968 | return 0; | 554 | return 0; |
555 | err_free_tty: | ||
556 | put_tty_driver(hp_simserial_driver); | ||
557 | return retval; | ||
969 | } | 558 | } |
970 | 559 | ||
971 | #ifndef MODULE | 560 | #ifndef MODULE |