File: | obj/../device/chario.c |
Location: | line 338, column 13 |
Description: | Function call argument is an uninitialized value |
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); | |||
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 | } |