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