File: | obj/../device/chario.c |
Location: | line 1016, column 3 |
Description: | Value stored to 'count' is never read |
1 | /* |
2 | * Mach Operating System |
3 | * Copyright (c) 1993-1988 Carnegie Mellon University |
4 | * All Rights Reserved. |
5 | * |
6 | * Permission to use, copy, modify and distribute this software and its |
7 | * documentation is hereby granted, provided that both the copyright |
8 | * notice and this permission notice appear in all copies of the |
9 | * software, derivative works or modified versions, and any portions |
10 | * thereof, and that both notices appear in supporting documentation. |
11 | * |
12 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
13 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR |
14 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. |
15 | * |
16 | * Carnegie Mellon requests users of this software to return to |
17 | * |
18 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
19 | * School of Computer Science |
20 | * Carnegie Mellon University |
21 | * Pittsburgh PA 15213-3890 |
22 | * |
23 | * any improvements or extensions that they make and grant Carnegie Mellon |
24 | * the rights to redistribute these changes. |
25 | */ |
26 | /* |
27 | * Author: David B. Golub, Carnegie Mellon University |
28 | * Date: 8/88 |
29 | * |
30 | * TTY io. |
31 | * Compatibility with old TTY device drivers. |
32 | */ |
33 | |
34 | #include <mach/kern_return.h> |
35 | #include <mach/mig_errors.h> |
36 | #include <mach/vm_param.h> |
37 | #include <machine/machspl.h> /* spl definitions */ |
38 | |
39 | #include <ipc/ipc_port.h> |
40 | |
41 | #include <kern/lock.h> |
42 | #include <kern/queue.h> |
43 | |
44 | #include <vm/vm_map.h> |
45 | #include <vm/vm_kern.h> |
46 | #include <vm/vm_user.h> |
47 | |
48 | #include <device/device_types.h> |
49 | #include <device/io_req.h> |
50 | #include <device/ds_routines.h> |
51 | #include <device/device_reply.user.h> |
52 | |
53 | #include <device/tty.h> |
54 | |
55 | /* If you change these, check that tty_outq_size and tty_inq_size |
56 | * is greater than largest tthiwat entry. |
57 | */ |
58 | short tthiwat[NSPEEDS18] = |
59 | { 100,100,100,100,100,100,100,200,200,400,400,400,650,650,1300,2000, |
60 | 2000,2000 }; |
61 | short ttlowat[NSPEEDS18] = |
62 | { 30, 30, 30, 30, 30, 30, 30, 50, 50,120,120,120,125,125, 125, 125, |
63 | 125,125 }; |
64 | |
65 | /* |
66 | * forward declarations |
67 | */ |
68 | void queue_delayed_reply( |
69 | queue_t, io_req_t, boolean_t (*)(io_req_t)); |
70 | void tty_output(struct tty *); |
71 | boolean_t char_open_done(io_req_t); |
72 | boolean_t char_read_done(io_req_t); |
73 | boolean_t char_write_done(io_req_t); |
74 | |
75 | /* |
76 | * Fake 'line discipline' switch for the benefit of old code |
77 | * that wants to call through it. |
78 | */ |
79 | struct ldisc_switch linesw[] = { |
80 | { |
81 | char_read, |
82 | char_write, |
83 | ttyinput, |
84 | ttymodem, |
85 | tty_output |
86 | } |
87 | }; |
88 | |
89 | /* |
90 | * Sizes for input and output circular buffers. |
91 | */ |
92 | const int tty_inq_size = 4096; /* big nuf */ |
93 | const int tty_outq_size = 2048; /* Must be bigger that tthiwat */ |
94 | int pdma_default = 1; /* turn pseudo dma on by default */ |
95 | |
96 | /* |
97 | * compute pseudo-dma tables |
98 | */ |
99 | |
100 | int pdma_timeouts[NSPEEDS18]; /* how many ticks in timeout */ |
101 | int pdma_water_mark[NSPEEDS18]; |
102 | |
103 | |
104 | void chario_init(void) |
105 | { |
106 | /* the basic idea with the timeouts is two allow enough |
107 | time for a character to show up if data is coming in at full data rate |
108 | plus a little slack. 2 ticks is considered slack |
109 | Below 300 baud we just glob a character at a time */ |
110 | #define _PR(x)(0.20 * x) ((hz/x) + 2) |
111 | |
112 | int i; |
113 | |
114 | for (i = B00; i < B3007; i++) |
115 | pdma_timeouts[i] = 0; |
116 | |
117 | pdma_timeouts[B3007] = _PR(30)(0.20 * 30); |
118 | pdma_timeouts[B6008] = _PR(60)(0.20 * 60); |
119 | pdma_timeouts[B12009] = _PR(120)(0.20 * 120); |
120 | pdma_timeouts[B180010] = _PR(180)(0.20 * 180); |
121 | pdma_timeouts[B240011] = _PR(240)(0.20 * 240); |
122 | pdma_timeouts[B480012] = _PR(480)(0.20 * 480); |
123 | pdma_timeouts[B960013] = _PR(960)(0.20 * 960); |
124 | pdma_timeouts[EXTA14] = _PR(1440)(0.20 * 1440); /* >14400 baud */ |
125 | pdma_timeouts[EXTB15] = _PR(1920)(0.20 * 1920); /* >19200 baud */ |
126 | pdma_timeouts[B5760016] = _PR(5760)(0.20 * 5760); |
127 | pdma_timeouts[B11520017] = _PR(11520)(0.20 * 11520); |
128 | |
129 | for (i = B00; i < B3007; i++) |
130 | pdma_water_mark[i] = 0; |
131 | |
132 | /* for the slow speeds, we try to buffer 0.02 of the baud rate |
133 | (20% of the character rate). For the faster lines, |
134 | we try to buffer 1/2 the input queue size */ |
135 | |
136 | #undef _PR |
137 | #define _PR(x)(0.20 * x) (0.20 * x) |
138 | |
139 | pdma_water_mark[B3007] = _PR(120)(0.20 * 120); |
140 | pdma_water_mark[B6008] = _PR(120)(0.20 * 120); |
141 | pdma_water_mark[B12009] = _PR(120)(0.20 * 120); |
142 | pdma_water_mark[B180010] = _PR(180)(0.20 * 180); |
143 | pdma_water_mark[B240011] = _PR(240)(0.20 * 240); |
144 | pdma_water_mark[B480012] = _PR(480)(0.20 * 480); |
145 | i = tty_inq_size/2; |
146 | pdma_water_mark[B960013] = i; |
147 | pdma_water_mark[EXTA14] = i; /* >14400 baud */ |
148 | pdma_water_mark[EXTB15] = i; /* >19200 baud */ |
149 | pdma_water_mark[B5760016] = i; |
150 | pdma_water_mark[B11520017] = i; |
151 | |
152 | return; |
153 | } |
154 | |
155 | /* |
156 | * Open TTY, waiting for CARR_ON. |
157 | * No locks may be held. |
158 | * May run on any CPU. |
159 | */ |
160 | io_return_t char_open( |
161 | int dev, |
162 | struct tty * tp, |
163 | dev_mode_t mode, |
164 | io_req_t ior) |
165 | { |
166 | spl_t s; |
167 | io_return_t rc = D_SUCCESS0; |
168 | |
169 | s = spltty(); |
170 | simple_lock(&tp->t_lock); |
171 | |
172 | tp->t_dev = dev; |
173 | |
174 | if (tp->t_mctl) |
175 | (*tp->t_mctl)(tp, TM_DTR0x0002, DMSET0); |
176 | |
177 | if (pdma_default) |
178 | tp->t_state |= TS_MIN0x00004000; |
179 | |
180 | if ((tp->t_state & TS_CARR_ON0x00000020) == 0) { |
181 | /* |
182 | * No carrier. |
183 | */ |
184 | if (mode & D_NODELAY0x4) { |
185 | tp->t_state |= TS_ONDELAY0x00002000; |
186 | } |
187 | else { |
188 | /* |
189 | * Don`t return from open until carrier detected. |
190 | */ |
191 | tp->t_state |= TS_WOPEN0x00000004; |
192 | |
193 | ior->io_dev_ptr = (char *)tp; |
194 | |
195 | queue_delayed_reply(&tp->t_delayed_open, ior, char_open_done); |
196 | rc = D_IO_QUEUED(-1); |
197 | goto out; |
198 | } |
199 | } |
200 | tp->t_state |= TS_ISOPEN0x00000008; |
201 | if (tp->t_mctl) |
202 | (*tp->t_mctl)(tp, TM_RTS0x0004, DMBIS1); |
203 | out: |
204 | simple_unlock(&tp->t_lock); |
205 | splx(s); |
206 | return rc; |
207 | } |
208 | |
209 | /* |
210 | * Retry wait for CARR_ON for open. |
211 | * No locks may be held. |
212 | * May run on any CPU. |
213 | */ |
214 | boolean_t char_open_done( |
215 | io_req_t ior) |
216 | { |
217 | struct tty *tp = (struct tty *)ior->io_dev_ptr; |
218 | spl_t s = spltty(); |
219 | |
220 | simple_lock(&tp->t_lock); |
221 | if ((tp->t_state & TS_ISOPEN0x00000008) == 0) { |
222 | queue_delayed_reply(&tp->t_delayed_open, ior, char_open_done); |
223 | simple_unlock(&tp->t_lock); |
224 | splx(s); |
225 | return FALSE((boolean_t) 0); |
226 | } |
227 | |
228 | tp->t_state |= TS_ISOPEN0x00000008; |
229 | tp->t_state &= ~TS_WOPEN0x00000004; |
230 | |
231 | if (tp->t_mctl) |
232 | (*tp->t_mctl)(tp, TM_RTS0x0004, DMBIS1); |
233 | |
234 | simple_unlock(&tp->t_lock); |
235 | splx(s); |
236 | |
237 | ior->io_error = D_SUCCESS0; |
238 | (void) ds_open_done(ior); |
239 | return TRUE((boolean_t) 1); |
240 | } |
241 | |
242 | boolean_t tty_close_open_reply( |
243 | io_req_t ior) |
244 | { |
245 | ior->io_error = D_DEVICE_DOWN2504; |
246 | (void) ds_open_done(ior); |
247 | return TRUE((boolean_t) 1); |
248 | } |
249 | |
250 | /* |
251 | * Write to TTY. |
252 | * No locks may be held. |
253 | * Calls device start routine; must already be on master if |
254 | * device needs to run on master. |
255 | */ |
256 | io_return_t char_write( |
257 | struct tty * tp, |
258 | io_req_t ior) |
259 | { |
260 | spl_t s; |
261 | int count; |
262 | char *data; |
263 | vm_offset_t addr; |
264 | io_return_t rc = D_SUCCESS0; |
265 | |
266 | data = ior->io_dataio_un.data; |
267 | count = ior->io_count; |
268 | if (count == 0) |
269 | return rc; |
270 | |
271 | if (!(ior->io_op & IO_INBAND0x00004000)) { |
272 | /* |
273 | * Copy out-of-line data into kernel address space. |
274 | * Since data is copied as page list, it will be |
275 | * accessible. |
276 | */ |
277 | vm_map_copy_t copy = (vm_map_copy_t) data; |
278 | kern_return_t kr; |
279 | |
280 | kr = vm_map_copyout(device_io_map, &addr, copy); |
281 | if (kr != KERN_SUCCESS0) |
282 | return kr; |
283 | data = (char *) addr; |
284 | } |
285 | |
286 | /* |
287 | * Check for tty operating. |
288 | */ |
289 | s = spltty(); |
290 | simple_lock(&tp->t_lock); |
291 | |
292 | if ((tp->t_state & TS_CARR_ON0x00000020) == 0) { |
293 | |
294 | if ((tp->t_state & TS_ONDELAY0x00002000) == 0) { |
295 | /* |
296 | * No delayed writes - tell caller that device is down |
297 | */ |
298 | rc = D_IO_ERROR2500; |
299 | goto out; |
300 | } |
301 | |
302 | if (ior->io_mode & D_NOWAIT0x8) { |
303 | rc = D_WOULD_BLOCK2501; |
304 | goto out; |
305 | } |
306 | } |
307 | |
308 | /* |
309 | * Copy data into the output buffer. |
310 | * Report the amount not copied. |
311 | */ |
312 | |
313 | ior->io_residual = b_to_q(data, count, &tp->t_outq); |
314 | |
315 | /* |
316 | * Start hardware output. |
317 | */ |
318 | |
319 | tp->t_state &= ~TS_TTSTOP0x00000100; |
320 | tty_output(tp); |
321 | |
322 | if (tp->t_outq.c_cc > TTHIWAT(tp)tthiwat[(tp)->t_ospeed] || |
323 | (tp->t_state & TS_CARR_ON0x00000020) == 0) { |
324 | |
325 | /* |
326 | * Do not send reply until some characters have been sent. |
327 | */ |
328 | ior->io_dev_ptr = (char *)tp; |
329 | queue_delayed_reply(&tp->t_delayed_write, ior, char_write_done); |
330 | |
331 | rc = D_IO_QUEUED(-1); |
332 | } |
333 | out: |
334 | simple_unlock(&tp->t_lock); |
335 | splx(s); |
336 | |
337 | if (!(ior->io_op & IO_INBAND0x00004000)) |
338 | (void) vm_deallocate(device_io_map, addr, ior->io_count); |
339 | return rc; |
340 | } |
341 | |
342 | /* |
343 | * Retry wait for output queue emptied, for write. |
344 | * No locks may be held. |
345 | * May run on any CPU. |
346 | */ |
347 | boolean_t char_write_done( |
348 | io_req_t ior) |
349 | { |
350 | struct tty *tp = (struct tty *)ior->io_dev_ptr; |
351 | spl_t s = spltty(); |
352 | |
353 | simple_lock(&tp->t_lock); |
354 | if (tp->t_outq.c_cc > TTHIWAT(tp)tthiwat[(tp)->t_ospeed] || |
355 | (tp->t_state & TS_CARR_ON0x00000020) == 0) { |
356 | |
357 | queue_delayed_reply(&tp->t_delayed_write, ior, char_write_done); |
358 | simple_unlock(&tp->t_lock); |
359 | splx(s); |
360 | return FALSE((boolean_t) 0); |
361 | } |
362 | simple_unlock(&tp->t_lock); |
363 | splx(s); |
364 | |
365 | if (IP_VALID(ior->io_reply_port)(((&(ior->io_reply_port)->ip_target.ipt_object) != ( (ipc_object_t) 0)) && ((&(ior->io_reply_port)-> ip_target.ipt_object) != ((ipc_object_t) -1)))) { |
366 | (void) (*((ior->io_op & IO_INBAND0x00004000) ? |
367 | ds_device_write_reply_inband : |
368 | ds_device_write_reply))(ior->io_reply_port, |
369 | ior->io_reply_port_type, |
370 | ior->io_error, |
371 | (int) (ior->io_total - |
372 | ior->io_residual)); |
373 | } |
374 | mach_device_deallocate(ior->io_device); |
375 | return TRUE((boolean_t) 1); |
376 | } |
377 | |
378 | boolean_t tty_close_write_reply( |
379 | io_req_t ior) |
380 | { |
381 | ior->io_residual = ior->io_count; |
382 | ior->io_error = D_DEVICE_DOWN2504; |
383 | (void) ds_write_done(ior); |
384 | return TRUE((boolean_t) 1); |
385 | } |
386 | |
387 | /* |
388 | * Read from TTY. |
389 | * No locks may be held. |
390 | * May run on any CPU - does not talk to device driver. |
391 | */ |
392 | io_return_t char_read( |
393 | struct tty *tp, |
394 | io_req_t ior) |
395 | { |
396 | spl_t s; |
397 | kern_return_t rc; |
398 | |
399 | /* |
400 | * Allocate memory for read buffer. |
401 | */ |
402 | rc = device_read_alloc(ior, (vm_size_t)ior->io_count); |
403 | if (rc != KERN_SUCCESS0) |
404 | return rc; |
405 | |
406 | s = spltty(); |
407 | simple_lock(&tp->t_lock); |
408 | if ((tp->t_state & TS_CARR_ON0x00000020) == 0) { |
409 | |
410 | if ((tp->t_state & TS_ONDELAY0x00002000) == 0) { |
411 | /* |
412 | * No delayed writes - tell caller that device is down |
413 | */ |
414 | rc = D_IO_ERROR2500; |
415 | goto out; |
416 | } |
417 | |
418 | if (ior->io_mode & D_NOWAIT0x8) { |
419 | rc = D_WOULD_BLOCK2501; |
420 | goto out; |
421 | } |
422 | |
423 | } |
424 | |
425 | if (tp->t_inq.c_cc <= 0 || |
426 | (tp->t_state & TS_CARR_ON0x00000020) == 0) { |
427 | |
428 | ior->io_dev_ptr = (char *)tp; |
429 | queue_delayed_reply(&tp->t_delayed_read, ior, char_read_done); |
430 | rc = D_IO_QUEUED(-1); |
431 | goto out; |
432 | } |
433 | |
434 | ior->io_residual = ior->io_count - q_to_b(&tp->t_inq, |
435 | ior->io_dataio_un.data, |
436 | (int)ior->io_count); |
437 | if (tp->t_state & TS_RTS_DOWN0x00020000) { |
438 | (*tp->t_mctl)(tp, TM_RTS0x0004, DMBIS1); |
439 | tp->t_state &= ~TS_RTS_DOWN0x00020000; |
440 | } |
441 | |
442 | out: |
443 | simple_unlock(&tp->t_lock); |
444 | splx(s); |
445 | return rc; |
446 | } |
447 | |
448 | /* |
449 | * Retry wait for characters, for read. |
450 | * No locks may be held. |
451 | * May run on any CPU - does not talk to device driver. |
452 | */ |
453 | boolean_t char_read_done( |
454 | io_req_t ior) |
455 | { |
456 | struct tty *tp = (struct tty *)ior->io_dev_ptr; |
457 | spl_t s = spltty(); |
458 | |
459 | simple_lock(&tp->t_lock); |
460 | |
461 | if (tp->t_inq.c_cc <= 0 || |
462 | (tp->t_state & TS_CARR_ON0x00000020) == 0) { |
463 | |
464 | queue_delayed_reply(&tp->t_delayed_read, ior, char_read_done); |
465 | simple_unlock(&tp->t_lock); |
466 | splx(s); |
467 | return FALSE((boolean_t) 0); |
468 | } |
469 | |
470 | ior->io_residual = ior->io_count - q_to_b(&tp->t_inq, |
471 | ior->io_dataio_un.data, |
472 | (int)ior->io_count); |
473 | if (tp->t_state & TS_RTS_DOWN0x00020000) { |
474 | (*tp->t_mctl)(tp, TM_RTS0x0004, DMBIS1); |
475 | tp->t_state &= ~TS_RTS_DOWN0x00020000; |
476 | } |
477 | |
478 | simple_unlock(&tp->t_lock); |
479 | splx(s); |
480 | |
481 | (void) ds_read_done(ior); |
482 | return TRUE((boolean_t) 1); |
483 | } |
484 | |
485 | boolean_t tty_close_read_reply( |
486 | io_req_t ior) |
487 | { |
488 | ior->io_residual = ior->io_count; |
489 | ior->io_error = D_DEVICE_DOWN2504; |
490 | (void) ds_read_done(ior); |
491 | return TRUE((boolean_t) 1); |
492 | } |
493 | |
494 | /* |
495 | * Close the tty. |
496 | * Tty must be locked (at spltty). |
497 | * Iff modem control should run on master. |
498 | */ |
499 | void ttyclose( |
500 | struct tty *tp) |
501 | { |
502 | io_req_t ior; |
503 | |
504 | /* |
505 | * Flush the read and write queues. Signal |
506 | * the open queue so that those waiting for open |
507 | * to complete will see that the tty is closed. |
508 | */ |
509 | while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_read)) != 0) { |
510 | ior->io_done = tty_close_read_reply; |
511 | iodone(ior); |
512 | } |
513 | while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_write)) != 0) { |
514 | ior->io_done = tty_close_write_reply; |
515 | iodone(ior); |
516 | } |
517 | while ((ior = (io_req_t)dequeue_head(&tp->t_delayed_open)) != 0) { |
518 | ior->io_done = tty_close_open_reply; |
519 | iodone(ior); |
520 | } |
521 | |
522 | /* Close down modem */ |
523 | if (tp->t_mctl) { |
524 | (*tp->t_mctl)(tp, TM_BRK0x0200|TM_RTS0x0004, DMBIC2); |
525 | if ((tp->t_state&(TS_HUPCLS0x00000200|TS_WOPEN0x00000004)) || (tp->t_state&TS_ISOPEN0x00000008)==0) |
526 | (*tp->t_mctl)(tp, TM_HUP0x0000, DMSET0); |
527 | } |
528 | |
529 | /* only save buffering bit, and carrier */ |
530 | tp->t_state = tp->t_state & (TS_MIN0x00004000|TS_CARR_ON0x00000020); |
531 | } |
532 | |
533 | /* |
534 | * Port-death routine to clean up reply messages. |
535 | */ |
536 | boolean_t |
537 | tty_queue_clean( |
538 | queue_t q, |
539 | ipc_port_t port, |
540 | boolean_t (*routine)(io_req_t) ) |
541 | { |
542 | io_req_t ior; |
543 | |
544 | ior = (io_req_t)queue_first(q)((q)->next); |
545 | while (!queue_end(q, (queue_entry_t)ior)((q) == ((queue_entry_t)ior))) { |
546 | if (ior->io_reply_port == port) { |
547 | remqueue(q, (queue_entry_t)ior); |
548 | ior->io_done = routine; |
549 | iodone(ior); |
550 | return TRUE((boolean_t) 1); |
551 | } |
552 | ior = ior->io_next; |
553 | } |
554 | return FALSE((boolean_t) 0); |
555 | } |
556 | |
557 | /* |
558 | * Handle port-death (dead reply port) for tty. |
559 | * No locks may be held. |
560 | * May run on any CPU. |
561 | */ |
562 | boolean_t |
563 | tty_portdeath( |
564 | struct tty * tp, |
565 | ipc_port_t port) |
566 | { |
567 | spl_t spl = spltty(); |
568 | boolean_t result; |
569 | |
570 | simple_lock(&tp->t_lock); |
571 | |
572 | /* |
573 | * The queues may never have been initialized |
574 | */ |
575 | if (tp->t_delayed_read.next == 0) { |
576 | result = FALSE((boolean_t) 0); |
577 | } |
578 | else { |
579 | result = |
580 | tty_queue_clean(&tp->t_delayed_read, port, |
581 | tty_close_read_reply) |
582 | || tty_queue_clean(&tp->t_delayed_write, port, |
583 | tty_close_write_reply) |
584 | || tty_queue_clean(&tp->t_delayed_open, port, |
585 | tty_close_open_reply); |
586 | } |
587 | simple_unlock(&tp->t_lock); |
588 | splx(spl); |
589 | |
590 | return result; |
591 | } |
592 | |
593 | /* |
594 | * Get TTY status. |
595 | * No locks may be held. |
596 | * May run on any CPU. |
597 | */ |
598 | io_return_t tty_get_status( |
599 | struct tty *tp, |
600 | dev_flavor_t flavor, |
601 | int * data, /* pointer to OUT array */ |
602 | natural_t *count) /* out */ |
603 | { |
604 | spl_t s; |
605 | |
606 | switch (flavor) { |
607 | case TTY_STATUS(dev_flavor_t)(('t'<<16) + 1): |
608 | { |
609 | struct tty_status *tsp = |
610 | (struct tty_status *) data; |
611 | |
612 | if (*count < TTY_STATUS_COUNT(sizeof(struct tty_status)/sizeof(int))) |
613 | return (D_INVALID_OPERATION2505); |
614 | |
615 | s = spltty(); |
616 | simple_lock(&tp->t_lock); |
617 | |
618 | tsp->tt_ispeed = tp->t_ispeed; |
619 | tsp->tt_ospeed = tp->t_ospeed; |
620 | tsp->tt_breakc = tp->t_breakc; |
621 | tsp->tt_flags = tp->t_flags; |
622 | if (tp->t_state & TS_HUPCLS0x00000200) |
623 | tsp->tt_flags |= TF_HUPCLS0x00000040; |
624 | |
625 | simple_unlock(&tp->t_lock); |
626 | splx(s); |
627 | |
628 | *count = TTY_STATUS_COUNT(sizeof(struct tty_status)/sizeof(int)); |
629 | break; |
630 | |
631 | } |
632 | default: |
633 | return D_INVALID_OPERATION2505; |
634 | } |
635 | return D_SUCCESS0; |
636 | } |
637 | |
638 | /* |
639 | * Set TTY status. |
640 | * No locks may be held. |
641 | * Calls device start or stop routines; must already be on master if |
642 | * device needs to run on master. |
643 | */ |
644 | io_return_t tty_set_status( |
645 | struct tty *tp, |
646 | dev_flavor_t flavor, |
647 | int * data, |
648 | natural_t count) |
649 | { |
650 | int s; |
651 | |
652 | switch (flavor) { |
653 | case TTY_FLUSH(dev_flavor_t)(('t'<<16) + 3): |
654 | { |
655 | int flags; |
656 | if (count < TTY_FLUSH_COUNT(1)) |
657 | return D_INVALID_OPERATION2505; |
658 | |
659 | flags = *data; |
660 | if (flags == 0) |
661 | flags = D_READ0x1 | D_WRITE0x2; |
662 | |
663 | s = spltty(); |
664 | simple_lock(&tp->t_lock); |
665 | tty_flush(tp, flags); |
666 | simple_unlock(&tp->t_lock); |
667 | splx(s); |
668 | |
669 | break; |
670 | } |
671 | case TTY_STOP(dev_flavor_t)(('t'<<16) + 4): |
672 | /* stop output */ |
673 | s = spltty(); |
674 | simple_lock(&tp->t_lock); |
675 | if ((tp->t_state & TS_TTSTOP0x00000100) == 0) { |
676 | tp->t_state |= TS_TTSTOP0x00000100; |
677 | (*tp->t_stop)(tp, 0); |
678 | } |
679 | simple_unlock(&tp->t_lock); |
680 | splx(s); |
681 | break; |
682 | |
683 | case TTY_START(dev_flavor_t)(('t'<<16) + 5): |
684 | /* start output */ |
685 | s = spltty(); |
686 | simple_lock(&tp->t_lock); |
687 | if (tp->t_state & TS_TTSTOP0x00000100) { |
688 | tp->t_state &= ~TS_TTSTOP0x00000100; |
689 | tty_output(tp); |
690 | } |
691 | simple_unlock(&tp->t_lock); |
692 | splx(s); |
693 | break; |
694 | |
695 | case TTY_STATUS(dev_flavor_t)(('t'<<16) + 1): |
696 | /* set special characters and speed */ |
697 | { |
698 | struct tty_status *tsp; |
699 | |
700 | if (count < TTY_STATUS_COUNT(sizeof(struct tty_status)/sizeof(int))) |
701 | return D_INVALID_OPERATION2505; |
702 | |
703 | tsp = (struct tty_status *)data; |
704 | |
705 | if (tsp->tt_ispeed < 0 || |
706 | tsp->tt_ispeed >= NSPEEDS18 || |
707 | tsp->tt_ospeed < 0 || |
708 | tsp->tt_ospeed >= NSPEEDS18) |
709 | { |
710 | return D_INVALID_OPERATION2505; |
711 | } |
712 | |
713 | s = spltty(); |
714 | simple_lock(&tp->t_lock); |
715 | |
716 | tp->t_ispeed = tsp->tt_ispeed; |
717 | tp->t_ospeed = tsp->tt_ospeed; |
718 | tp->t_breakc = tsp->tt_breakc; |
719 | tp->t_flags = tsp->tt_flags & ~TF_HUPCLS0x00000040; |
720 | if (tsp->tt_flags & TF_HUPCLS0x00000040) |
721 | tp->t_state |= TS_HUPCLS0x00000200; |
722 | |
723 | simple_unlock(&tp->t_lock); |
724 | splx(s); |
725 | break; |
726 | } |
727 | default: |
728 | return D_INVALID_OPERATION2505; |
729 | } |
730 | return D_SUCCESS0; |
731 | } |
732 | |
733 | |
734 | /* |
735 | * [internal] |
736 | * Queue IOR on reply queue, to wait for TTY operation. |
737 | * TTY must be locked (at spltty). |
738 | */ |
739 | void queue_delayed_reply( |
740 | queue_t qh, |
741 | io_req_t ior, |
742 | boolean_t (*io_done)(io_req_t) ) |
743 | { |
744 | ior->io_done = io_done; |
745 | enqueue_tail(qh, (queue_entry_t)ior); |
746 | } |
747 | |
748 | /* |
749 | * Retry delayed IO operations for TTY. |
750 | * TTY containing queue must be locked (at spltty). |
751 | */ |
752 | void tty_queue_completion( |
753 | queue_t qh) |
754 | { |
755 | io_req_t ior; |
756 | |
757 | while ((ior = (io_req_t)dequeue_head(qh)) != 0) { |
758 | iodone(ior); |
759 | } |
760 | } |
761 | |
762 | /* |
763 | * Set the default special characters. |
764 | * Since this routine is called whenever a tty has never been opened, |
765 | * we can initialize the queues here. |
766 | */ |
767 | void ttychars( |
768 | struct tty *tp) |
769 | { |
770 | if ((tp->t_flags & TS_INIT0x00000001) == 0) { |
771 | /* |
772 | * Initialize queues |
773 | */ |
774 | queue_init(&tp->t_delayed_open)((&tp->t_delayed_open)->next = (&tp->t_delayed_open )->prev = &tp->t_delayed_open); |
775 | queue_init(&tp->t_delayed_read)((&tp->t_delayed_read)->next = (&tp->t_delayed_read )->prev = &tp->t_delayed_read); |
776 | queue_init(&tp->t_delayed_write)((&tp->t_delayed_write)->next = (&tp->t_delayed_write )->prev = &tp->t_delayed_write); |
777 | |
778 | /* |
779 | * Initialize character buffers |
780 | */ |
781 | cb_alloc(&tp->t_inq, tty_inq_size); |
782 | |
783 | /* if we might do modem flow control */ |
784 | if (tp->t_mctl && tp->t_inq.c_hog > 30) |
785 | tp->t_inq.c_hog -= 30; |
786 | |
787 | cb_alloc(&tp->t_outq, tty_outq_size); |
788 | |
789 | /* |
790 | * Mark initialized |
791 | */ |
792 | tp->t_state |= TS_INIT0x00000001; |
793 | } |
794 | |
795 | tp->t_breakc = 0; |
796 | } |
797 | |
798 | /* |
799 | * Flush all TTY queues. |
800 | * Called at spltty, tty already locked. |
801 | * Calls device STOP routine; must already be on master if |
802 | * device needs to run on master. |
803 | */ |
804 | void tty_flush( |
805 | struct tty *tp, |
806 | int rw) |
807 | { |
808 | if (rw & D_READ0x1) { |
809 | cb_clear(&tp->t_inq); |
810 | tty_queue_completion(&tp->t_delayed_read); |
811 | } |
812 | if (rw & D_WRITE0x2) { |
813 | tp->t_state &= ~TS_TTSTOP0x00000100; |
814 | (*tp->t_stop)(tp, rw); |
815 | cb_clear(&tp->t_outq); |
816 | tty_queue_completion(&tp->t_delayed_write); |
817 | } |
818 | } |
819 | |
820 | /* |
821 | * Restart character output after a delay timeout. |
822 | * Calls device start routine - must be on master CPU. |
823 | * |
824 | * Timeout routines are called only on master CPU. |
825 | * What if device runs on a different CPU? |
826 | */ |
827 | void ttrstrt( |
828 | struct tty *tp) |
829 | { |
830 | spl_t s; |
831 | |
832 | s = spltty(); |
833 | simple_lock(&tp->t_lock); |
834 | |
835 | tp->t_state &= ~TS_TIMEOUT0x00000002; |
836 | ttstart (tp); |
837 | |
838 | simple_unlock(&tp->t_lock); |
839 | splx(s); |
840 | } |
841 | |
842 | /* |
843 | * Start output on the typewriter. It is used from the top half |
844 | * after some characters have been put on the output queue, |
845 | * from the interrupt routine to transmit the next |
846 | * character, and after a timeout has finished. |
847 | * |
848 | * Called at spltty, tty already locked. |
849 | * Must be on master CPU if device runs on master. |
850 | */ |
851 | void ttstart(tp) |
852 | struct tty *tp; |
853 | { |
854 | if ((tp->t_state & (TS_TIMEOUT0x00000002|TS_TTSTOP0x00000100|TS_BUSY0x00000040)) == 0) { |
855 | /* |
856 | * Start up the hardware again |
857 | */ |
858 | (*tp->t_start)(tp); |
859 | |
860 | /* |
861 | * Wake up those waiting for write completion. |
862 | */ |
863 | if (tp->t_outq.c_cc <= TTLOWAT(tp)ttlowat[(tp)->t_ospeed]) |
864 | tty_queue_completion(&tp->t_delayed_write); |
865 | } |
866 | } |
867 | |
868 | /* |
869 | * Start character output, if the device is not busy or |
870 | * stopped or waiting for a timeout. |
871 | * |
872 | * Called at spltty, tty already locked. |
873 | * Must be on master CPU if device runs on master. |
874 | */ |
875 | void tty_output( |
876 | struct tty *tp) |
877 | { |
878 | if ((tp->t_state & (TS_TIMEOUT0x00000002|TS_TTSTOP0x00000100|TS_BUSY0x00000040)) == 0) { |
879 | /* |
880 | * Not busy. Start output. |
881 | */ |
882 | (*tp->t_start)(tp); |
883 | |
884 | /* |
885 | * Wake up those waiting for write completion. |
886 | */ |
887 | if (tp->t_outq.c_cc <= TTLOWAT(tp)ttlowat[(tp)->t_ospeed]) |
888 | tty_queue_completion(&tp->t_delayed_write); |
889 | } |
890 | } |
891 | |
892 | /* |
893 | * Send any buffered recvd chars up to user |
894 | */ |
895 | void ttypush( |
896 | void * _tp) |
897 | { |
898 | struct tty *tp = _tp; |
899 | spl_t s = spltty(); |
900 | int state; |
901 | |
902 | simple_lock(&tp->t_lock); |
903 | |
904 | /* |
905 | The pdma timeout has gone off. |
906 | If no character has been received since the timeout |
907 | was set, push any pending characters up. |
908 | If any characters were received in the last interval |
909 | then just reset the timeout and the character received bit. |
910 | */ |
911 | |
912 | state = tp->t_state; |
913 | |
914 | if (state & TS_MIN_TO0x00008000) |
915 | { |
916 | if (state & TS_MIN_TO_RCV0x00400000) |
917 | { /* a character was received */ |
918 | tp->t_state = state & ~TS_MIN_TO_RCV0x00400000; |
919 | timeout(ttypush,tp,pdma_timeouts[tp->t_ispeed]); |
920 | } |
921 | else |
922 | { |
923 | tp->t_state = state & ~TS_MIN_TO0x00008000; |
924 | if (tp->t_inq.c_cc) /* pending characters */ |
925 | tty_queue_completion(&tp->t_delayed_read); |
926 | } |
927 | } |
928 | else |
929 | { |
930 | tp->t_state = state & ~TS_MIN_TO_RCV0x00400000;/* sanity */ |
931 | } |
932 | |
933 | simple_unlock(&tp->t_lock); |
934 | splx(s); |
935 | } |
936 | |
937 | /* |
938 | * Put input character on input queue. |
939 | * |
940 | * Called at spltty, tty already locked. |
941 | */ |
942 | void ttyinput( |
943 | unsigned int c, |
944 | struct tty *tp) |
945 | { |
946 | if (tp->t_inq.c_cc >= tp->t_inq.c_hog) { |
947 | /* |
948 | * Do not want to overflow input queue |
949 | */ |
950 | if (tp->t_mctl) { |
951 | (*tp->t_mctl)(tp, TM_RTS0x0004, DMBIC2); |
952 | tp->t_state |= TS_RTS_DOWN0x00020000; |
953 | } |
954 | tty_queue_completion(&tp->t_delayed_read); |
955 | return; |
956 | |
957 | } |
958 | |
959 | c &= 0xff; |
960 | |
961 | (void) putc(c, &tp->t_inq); |
962 | if ((tp->t_state & TS_MIN0x00004000) == 0 || |
963 | tp->t_inq.c_cc > pdma_water_mark[tp->t_ispeed]) |
964 | { |
965 | /* |
966 | * No input buffering, or input minimum exceeded. |
967 | * Grab a request from input queue and queue it |
968 | * to io_done thread. |
969 | */ |
970 | if (tp->t_state & TS_MIN_TO0x00008000) { |
971 | tp->t_state &= ~(TS_MIN_TO0x00008000|TS_MIN_TO_RCV0x00400000); |
972 | untimeout(ttypush, tp); |
973 | } |
974 | tty_queue_completion(&tp->t_delayed_read); |
975 | } |
976 | else { |
977 | /* |
978 | * Not enough characters. |
979 | * If no timeout is set, initiate the timeout |
980 | * Otherwise set the character received during timeout interval |
981 | * flag. |
982 | * One alternative approach would be just to reset the timeout |
983 | * into the future, but this involves making a timeout/untimeout |
984 | * call on every character. |
985 | */ |
986 | int ptime = pdma_timeouts[tp->t_ispeed]; |
987 | if (ptime > 0) |
988 | { |
989 | if ((tp->t_state & TS_MIN_TO0x00008000) == 0) |
990 | { |
991 | tp->t_state |= TS_MIN_TO0x00008000; |
992 | timeout(ttypush, tp, ptime); |
993 | } |
994 | else |
995 | { |
996 | tp->t_state |= TS_MIN_TO_RCV0x00400000; |
997 | } |
998 | } |
999 | } |
1000 | } |
1001 | |
1002 | /* |
1003 | * Put many characters on input queue. |
1004 | * |
1005 | * Called at spltty, tty already locked. |
1006 | */ |
1007 | void ttyinput_many( |
1008 | struct tty *tp, |
1009 | char *chars, |
1010 | int count) |
1011 | { |
1012 | /* |
1013 | * Do not want to overflow input queue |
1014 | */ |
1015 | if (tp->t_inq.c_cc < tp->t_inq.c_hog) |
1016 | count -= b_to_q( chars, count, &tp->t_inq); |
Value stored to 'count' is never read | |
1017 | |
1018 | tty_queue_completion(&tp->t_delayed_read); |
1019 | } |
1020 | |
1021 | |
1022 | /* |
1023 | * Handle modem control transition on a tty. |
1024 | * Flag indicates new state of carrier. |
1025 | * Returns FALSE if the line should be turned off. |
1026 | * |
1027 | * Called at spltty, tty already locked. |
1028 | */ |
1029 | boolean_t ttymodem( |
1030 | struct tty * tp, |
1031 | boolean_t carrier_up) |
1032 | { |
1033 | if ((tp->t_state&TS_WOPEN0x00000004) == 0 && (tp->t_flags & MDMBUF0x00000010)) { |
1034 | /* |
1035 | * Flow control by carrier. Carrier down stops |
1036 | * output; carrier up restarts output. |
1037 | */ |
1038 | if (carrier_up) { |
1039 | tp->t_state &= ~TS_TTSTOP0x00000100; |
1040 | tty_output(tp); |
1041 | } |
1042 | else if ((tp->t_state&TS_TTSTOP0x00000100) == 0) { |
1043 | tp->t_state |= TS_TTSTOP0x00000100; |
1044 | (*tp->t_stop)(tp, 0); |
1045 | } |
1046 | } |
1047 | else if (carrier_up) { |
1048 | /* |
1049 | * Carrier now on. |
1050 | */ |
1051 | tp->t_state |= TS_CARR_ON0x00000020; |
1052 | tt_open_wakeup(tp)(tty_queue_completion(&(tp)->t_delayed_open)); |
1053 | } |
1054 | else { |
1055 | /* |
1056 | * Lost carrier. |
1057 | */ |
1058 | tp->t_state &= ~TS_CARR_ON0x00000020; |
1059 | if (tp->t_state & TS_ISOPEN0x00000008 && |
1060 | (tp->t_flags & NOHANG0x00000020) == 0) |
1061 | { |
1062 | /* |
1063 | * Hang up TTY if carrier drops. |
1064 | * Need to alert users, somehow... |
1065 | */ |
1066 | tty_flush(tp, D_READ0x1|D_WRITE0x2); |
1067 | return FALSE((boolean_t) 0); |
1068 | } |
1069 | } |
1070 | return TRUE((boolean_t) 1); |
1071 | } |
1072 | |
1073 | /* |
1074 | * Similarly, handle transitions on the ClearToSend |
1075 | * signal. Nowadays, it is used by many modems as |
1076 | * a flow-control device: they turn it down to stop |
1077 | * us from sending more chars. We do the same with |
1078 | * the RequestToSend signal. [Yes, that is exactly |
1079 | * why those signals are defined in the standard.] |
1080 | * |
1081 | * Tty must be locked and on master. |
1082 | */ |
1083 | void |
1084 | tty_cts( |
1085 | struct tty * tp, |
1086 | boolean_t cts_up) |
1087 | { |
1088 | if (tp->t_state & TS_ISOPEN0x00000008){ |
1089 | if (cts_up) { |
1090 | tp->t_state &= ~(TS_TTSTOP0x00000100|TS_BUSY0x00000040); |
1091 | tty_output(tp); |
1092 | } else { |
1093 | tp->t_state |= (TS_TTSTOP0x00000100|TS_BUSY0x00000040); |
1094 | (*tp->t_stop)(tp, D_WRITE0x2); |
1095 | } |
1096 | } |
1097 | } |