Commit | Line | Data |
---|---|---|
3f3a34c3 | 1 | /* dz.c 4.10 %G% */ |
5074fa57 | 2 | |
66b4fb09 | 3 | #include "dz.h" |
a5cc519e | 4 | #if NDZ11 > 0 |
5074fa57 BJ |
5 | /* |
6 | * DZ-11 Driver | |
7 | */ | |
8 | #include "../h/param.h" | |
9 | #include "../h/systm.h" | |
10 | #include "../h/tty.h" | |
11 | #include "../h/dir.h" | |
12 | #include "../h/user.h" | |
13 | #include "../h/map.h" | |
14 | #include "../h/pte.h" | |
3f3a34c3 | 15 | #include "../h/buf.h" |
5074fa57 BJ |
16 | #include "../h/uba.h" |
17 | #include "../h/conf.h" | |
18 | #include "../h/pdma.h" | |
771d8988 | 19 | #include "../h/bk.h" |
cc343d94 | 20 | #include "../h/file.h" |
1b05b375 | 21 | #include "../h/mx.h" |
d3ebf5ee BJ |
22 | |
23 | /* | |
24 | * When running dz's using only SAE (silo alarm) on input | |
25 | * it is necessary to call dzrint() at clock interrupt time. | |
26 | * This is unsafe unless spl5()s in tty code are changed to | |
27 | * spl6()s to block clock interrupts. Note that the dh driver | |
28 | * currently in use works the same way as the dz, even though | |
29 | * we could try to more intelligently manage its silo. | |
30 | * Thus don't take this out if you have no dz's unless you | |
31 | * change clock.c and dhtimer(). | |
3f3a34c3 BJ |
32 | * |
33 | * SHOULD RATHER QUEUE SOFTWARE INTERRUPT AT CLOCK TIME. | |
d3ebf5ee BJ |
34 | */ |
35 | #define spl5 spl6 | |
5074fa57 | 36 | |
3f3a34c3 BJ |
37 | int dzcntrlr(), dzslave(), dzrint(); |
38 | struct uba_dinfo *dzinfo[NDZ11]; | |
39 | u_short dzstd[] = { 0 }; | |
40 | int (*dzivec[])() = { dzrint, 0 }; /* omit dzxint so we can do it here */ | |
41 | struct uba_driver dzdriver = | |
42 | { dzcntrlr, dzslave, (int (*)())0, 0, 0, dzstd, dzinfo, dzivec }; | |
43 | ||
3f988b2a | 44 | #define NDZ (NDZ11*8) |
5074fa57 BJ |
45 | |
46 | #define BITS7 020 | |
47 | #define BITS8 030 | |
48 | #define TWOSB 040 | |
49 | #define PENABLE 0100 | |
50 | #define OPAR 0200 | |
51 | #define MSE 040 /* Master Scan Enable */ | |
52 | #define RIE 0100 /* Receiver Interrupt Enable */ | |
9dca4f86 BJ |
53 | #define SAE 010000 /* Silo Alarm Enable */ |
54 | #define TIE 040000 /* Transmit Interrupt Enable */ | |
55 | #define DZ_IEN (MSE+RIE+TIE+SAE) | |
5074fa57 BJ |
56 | #define PERROR 010000 |
57 | #define FRERROR 020000 | |
9dca4f86 | 58 | #define OVERRUN 040000 |
5074fa57 BJ |
59 | #define SSPEED 7 /* std speed = 300 baud */ |
60 | ||
5074fa57 BJ |
61 | #define dzlpr dzrbuf |
62 | #define dzmsr dzbrk | |
63 | #define ON 1 | |
64 | #define OFF 0 | |
65 | ||
66 | int dzstart(); | |
67 | int dzxint(); | |
3f3a34c3 | 68 | int dzdma(); |
771d8988 | 69 | int ttrstrt(); |
5074fa57 BJ |
70 | struct tty dz_tty[NDZ]; |
71 | int dz_cnt = { NDZ }; | |
9dca4f86 | 72 | int dzact; |
5074fa57 BJ |
73 | |
74 | struct device { | |
75 | short dzcsr; | |
76 | short dzrbuf; | |
77 | char dztcr; | |
78 | char dzdtr; | |
79 | char dztbuf; | |
80 | char dzbrk; | |
81 | }; | |
82 | ||
3f3a34c3 | 83 | struct pdma dzpdma[NDZ]; |
5074fa57 | 84 | char dz_timer; |
3f3a34c3 BJ |
85 | char dz_speeds[] = |
86 | { 0,020,021,022,023,024,0,025,026,027,030,032,034,036,0,0 }; | |
87 | char dz_brk[NDZ11]; | |
5074fa57 | 88 | |
3f3a34c3 BJ |
89 | dzcntrlr(ui, reg) |
90 | struct uba_dinfo *ui; | |
91 | caddr_t reg; | |
92 | { | |
93 | ||
94 | ((struct device *)reg)->dzcsr |= IENABLE; | |
95 | /* get it to interrupt */ | |
96 | } | |
97 | ||
98 | dzslave(ui, reg, slaveno, uban) | |
99 | register struct uba_dinfo *ui; | |
100 | caddr_t reg; | |
101 | { | |
102 | register struct pdma *pdp = &dzpdma[ui->ui_unit*8]; | |
103 | register struct tty *tp = &dz_tty[ui->ui_unit*8]; | |
104 | register int cnt; | |
105 | register int *urk = (int *)(® - 24); /* white magic */ | |
106 | caddr_t cp; | |
107 | int urk2; | |
108 | ||
109 | for (cnt = 0; cnt < 8; cnt++) { | |
110 | pdp->p_addr = (struct device *)reg; | |
111 | pdp->p_arg = (int)tp; | |
112 | pdp->p_fcn = dzxint; | |
113 | pdp++, tp++; | |
114 | } | |
115 | if ((cp = calloc(12)) == 0) | |
116 | panic("dz iv nm\n"); | |
117 | uba_hd[uban].uh_vec[*urk] = (int (*)())cp; /* more white magic */ | |
118 | *cp++ = 0xbb; *cp++ = 0xff; *cp++ = 0xd0; /* black magic */ | |
119 | *cp++ = ui->ui_unit&0x3f; *cp++ = 0x50; | |
120 | *cp++ = 0x17; *cp++ = 0x9f; | |
121 | urk2 = (int)dzdma; | |
122 | for (cnt = 0; cnt < 4; cnt++) | |
123 | *cp++ = urk2, urk2 >>= 4; /* the spell ends */ | |
124 | return (1); | |
125 | } | |
126 | ||
5074fa57 | 127 | /*ARGSUSED*/ |
3f3a34c3 BJ |
128 | dzopen(dev, flag) |
129 | dev_t dev; | |
5074fa57 BJ |
130 | { |
131 | register struct tty *tp; | |
3f3a34c3 | 132 | register int unit; |
5074fa57 BJ |
133 | extern dzscan(); |
134 | ||
3f3a34c3 BJ |
135 | unit = minor(dev); |
136 | if (unit >= dz_cnt || dzpdma[unit].p_addr == 0) { | |
5074fa57 BJ |
137 | u.u_error = ENXIO; |
138 | return; | |
139 | } | |
140 | if (dz_timer == 0) { | |
141 | dz_timer++; | |
142 | timeout(dzscan, (caddr_t)0, 60); | |
143 | } | |
3f3a34c3 BJ |
144 | tp = &dz_tty[unit]; |
145 | tp->t_addr = (caddr_t)&dzpdma[unit]; | |
5074fa57 BJ |
146 | tp->t_oproc = dzstart; |
147 | tp->t_iproc = NULL; | |
148 | tp->t_state |= WOPEN; | |
149 | if ((tp->t_state & ISOPEN) == 0) { | |
150 | ttychars(tp); | |
151 | tp->t_ospeed = tp->t_ispeed = SSPEED; | |
152 | tp->t_flags = ODDP|EVENP|ECHO; | |
153 | /*tp->t_state |= HUPCLS;*/ | |
3f3a34c3 | 154 | dzparam(unit); |
5074fa57 BJ |
155 | } else if (tp->t_state&XCLUDE && u.u_uid != 0) { |
156 | u.u_error = EBUSY; | |
157 | return; | |
158 | } | |
3f3a34c3 | 159 | dzmodem(unit, ON); |
771d8988 | 160 | (void) spl5(); |
5074fa57 BJ |
161 | while ((tp->t_state & CARR_ON) == 0) { |
162 | tp->t_state |= WOPEN; | |
163 | sleep((caddr_t)&tp->t_rawq, TTIPRI); | |
164 | } | |
771d8988 | 165 | (void) spl0(); |
3f3a34c3 | 166 | (*linesw[tp->t_line].l_open)(dev, tp); |
5074fa57 BJ |
167 | } |
168 | ||
3f3a34c3 BJ |
169 | /*ARGSUSED*/ |
170 | dzclose(dev, flag) | |
171 | dev_t dev; | |
5074fa57 BJ |
172 | { |
173 | register struct tty *tp; | |
3f3a34c3 BJ |
174 | register int unit; |
175 | int dz; | |
5074fa57 | 176 | |
3f3a34c3 BJ |
177 | unit = minor(dev); |
178 | dz = unit >> 3; | |
179 | tp = &dz_tty[unit]; | |
5074fa57 | 180 | (*linesw[tp->t_line].l_close)(tp); |
e60fc718 | 181 | ((struct pdma *)(tp->t_addr))->p_addr->dzbrk = |
3f3a34c3 | 182 | (dz_brk[dz] &= ~(1 << (unit&07))); |
5074fa57 | 183 | if (tp->t_state & HUPCLS) |
3f3a34c3 | 184 | dzmodem(unit, OFF); |
5074fa57 BJ |
185 | ttyclose(tp); |
186 | } | |
187 | ||
3f3a34c3 BJ |
188 | dzread(dev) |
189 | dev_t dev; | |
5074fa57 BJ |
190 | { |
191 | register struct tty *tp; | |
192 | ||
3f3a34c3 | 193 | tp = &dz_tty[minor(dev)]; |
5074fa57 BJ |
194 | (*linesw[tp->t_line].l_read)(tp); |
195 | } | |
196 | ||
3f3a34c3 BJ |
197 | dzwrite(dev) |
198 | dev_t dev; | |
5074fa57 BJ |
199 | { |
200 | register struct tty *tp; | |
201 | ||
3f3a34c3 | 202 | tp = &dz_tty[minor(dev)]; |
5074fa57 BJ |
203 | (*linesw[tp->t_line].l_write)(tp); |
204 | } | |
205 | ||
9dca4f86 | 206 | /*ARGSUSED*/ |
3f3a34c3 BJ |
207 | dzrint(dz) |
208 | int dz; | |
5074fa57 BJ |
209 | { |
210 | register struct tty *tp; | |
211 | register int c; | |
212 | register struct device *dzaddr; | |
9dca4f86 | 213 | register struct tty *tp0; |
3f3a34c3 | 214 | register int unit; |
5c6adb3e | 215 | int s; |
5074fa57 | 216 | |
5c6adb3e | 217 | s = spl6(); /* see comment in clock.c */ |
9dca4f86 | 218 | /* as long as we are here, service them all */ |
3f3a34c3 BJ |
219 | for (unit = 0; unit < NDZ; unit += 8) { |
220 | if ((dzact & (1<<(unit>>3))) == 0) | |
5074fa57 | 221 | continue; |
3f3a34c3 BJ |
222 | dzaddr = dzpdma[unit].p_addr; |
223 | tp0 = &dz_tty[unit]; | |
9dca4f86 BJ |
224 | while ((c = dzaddr->dzrbuf) < 0) { /* char present */ |
225 | tp = tp0 + ((c>>8)&07); | |
226 | if (tp >= &dz_tty[dz_cnt]) | |
5074fa57 | 227 | continue; |
9dca4f86 BJ |
228 | if ((tp->t_state & ISOPEN) == 0) { |
229 | wakeup((caddr_t)&tp->t_rawq); | |
230 | continue; | |
231 | } | |
232 | if (c&FRERROR) | |
233 | /* framing error = break */ | |
234 | if (tp->t_flags & RAW) | |
235 | c = 0; /* null for getty */ | |
236 | else | |
dc44829a BJ |
237 | #ifdef IIASA |
238 | continue; | |
239 | #else | |
1c17c385 | 240 | c = tun.t_intrc; |
dc44829a | 241 | #endif |
9dca4f86 BJ |
242 | if (c&OVERRUN) |
243 | printf("o"); | |
244 | if (c&PERROR) | |
245 | /* parity error */ | |
246 | if (((tp->t_flags & (EVENP|ODDP)) == EVENP) | |
247 | || ((tp->t_flags & (EVENP|ODDP)) == ODDP)) | |
248 | continue; | |
5c6adb3e | 249 | if (tp->t_line == NETLDISC) { |
771d8988 | 250 | c &= 0177; |
dc44829a | 251 | BKINPUT(c, tp); |
771d8988 | 252 | } else |
771d8988 | 253 | (*linesw[tp->t_line].l_rint)(c, tp); |
9dca4f86 | 254 | } |
5074fa57 | 255 | } |
5c6adb3e | 256 | splx(s); |
5074fa57 BJ |
257 | } |
258 | ||
259 | /*ARGSUSED*/ | |
260 | dzioctl(dev, cmd, addr, flag) | |
3f3a34c3 BJ |
261 | dev_t dev; |
262 | caddr_t addr; | |
5074fa57 BJ |
263 | { |
264 | register struct tty *tp; | |
3f3a34c3 BJ |
265 | register int unit = minor(dev); |
266 | register int dz = unit >> 3; | |
5074fa57 | 267 | |
3f3a34c3 | 268 | tp = &dz_tty[unit]; |
771d8988 BJ |
269 | cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); |
270 | if (cmd == 0) | |
271 | return; | |
c3277147 | 272 | if (ttioctl(tp, cmd, addr, flag)) { |
5074fa57 | 273 | if (cmd==TIOCSETP || cmd==TIOCSETN) |
3f3a34c3 | 274 | dzparam(unit); |
dc44829a | 275 | } else switch(cmd) { |
3f3a34c3 | 276 | |
dc44829a | 277 | case TIOCSBRK: |
3f988b2a | 278 | ((struct pdma *)(tp->t_addr))->p_addr->dzbrk = |
3f3a34c3 | 279 | (dz_brk[dz] |= 1 << (unit&07)); |
dc44829a BJ |
280 | break; |
281 | case TIOCCBRK: | |
3f988b2a | 282 | ((struct pdma *)(tp->t_addr))->p_addr->dzbrk = |
3f3a34c3 | 283 | (dz_brk[dz] &= ~(1 << (unit&07))); |
dc44829a BJ |
284 | break; |
285 | case TIOCSDTR: | |
3f3a34c3 | 286 | dzmodem(unit, ON); |
dc44829a BJ |
287 | break; |
288 | case TIOCCDTR: | |
3f3a34c3 | 289 | dzmodem(unit, OFF); |
dc44829a BJ |
290 | break; |
291 | default: | |
5074fa57 | 292 | u.u_error = ENOTTY; |
dc44829a | 293 | } |
5074fa57 BJ |
294 | } |
295 | ||
3f3a34c3 BJ |
296 | dzparam(unit) |
297 | register int unit; | |
5074fa57 BJ |
298 | { |
299 | register struct tty *tp; | |
300 | register struct device *dzaddr; | |
3f3a34c3 | 301 | register int lpr; |
5074fa57 | 302 | |
3f3a34c3 BJ |
303 | tp = &dz_tty[unit]; |
304 | dzaddr = dzpdma[unit].p_addr; | |
5074fa57 | 305 | dzaddr->dzcsr = DZ_IEN; |
3f3a34c3 | 306 | dzact |= (1<<(unit>>3)); |
5074fa57 | 307 | if (tp->t_ispeed == 0) { |
3f3a34c3 | 308 | dzmodem(unit, OFF); /* hang up line */ |
5074fa57 BJ |
309 | return; |
310 | } | |
3f3a34c3 | 311 | lpr = (dz_speeds[tp->t_ispeed]<<8) | (unit & 07); |
3f988b2a | 312 | #ifndef IIASA |
be5b7974 | 313 | if ((tp->t_local&LLITOUT) || (tp->t_flags&RAW)) |
5074fa57 BJ |
314 | lpr |= BITS8; |
315 | else | |
316 | lpr |= (BITS7|PENABLE); | |
317 | if ((tp->t_flags & EVENP) == 0) | |
318 | lpr |= OPAR; | |
3f988b2a BJ |
319 | #else IIASA |
320 | if ((tp->t_flags & (EVENP|ODDP)) == (EVENP|ODDP)) | |
321 | lpr |= BITS8; | |
322 | else if (tp->t_flags & EVENP) | |
323 | lpr |= (BITS7|PENABLE); | |
324 | else if (tp->t_flags & ODDP) | |
325 | lpr |= (BITS7|OPAR|PENABLE); | |
326 | else | |
327 | lpr |= BITS7; | |
328 | #endif IIASA | |
5074fa57 BJ |
329 | if (tp->t_ispeed == 3) |
330 | lpr |= TWOSB; /* 110 baud: 2 stop bits */ | |
331 | dzaddr->dzlpr = lpr; | |
332 | } | |
333 | ||
334 | dzxint(tp) | |
3f3a34c3 | 335 | register struct tty *tp; |
5074fa57 BJ |
336 | { |
337 | register struct pdma *dp; | |
d3ebf5ee BJ |
338 | register s; |
339 | s = spl6(); /* block the clock */ | |
5074fa57 | 340 | |
3f3a34c3 | 341 | dp = (struct pdma *)tp->t_addr; |
5074fa57 BJ |
342 | tp->t_state &= ~BUSY; |
343 | if (tp->t_state & FLUSH) | |
344 | tp->t_state &= ~FLUSH; | |
345 | else | |
46014098 | 346 | ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf); |
5074fa57 BJ |
347 | if (tp->t_line) |
348 | (*linesw[tp->t_line].l_start)(tp); | |
349 | else | |
350 | dzstart(tp); | |
351 | if (tp->t_outq.c_cc == 0 || (tp->t_state&BUSY)==0) | |
3f3a34c3 | 352 | dp->p_addr->dztcr &= ~(1 << (minor(tp->t_dev)&07)); |
d3ebf5ee | 353 | splx(s); |
5074fa57 BJ |
354 | } |
355 | ||
356 | dzstart(tp) | |
3f3a34c3 | 357 | register struct tty *tp; |
5074fa57 BJ |
358 | { |
359 | register struct pdma *dp; | |
360 | register struct device *dzaddr; | |
3f3a34c3 BJ |
361 | register int cc; |
362 | int s; | |
5074fa57 | 363 | |
3f3a34c3 | 364 | dp = (struct pdma *)tp->t_addr; |
5074fa57 | 365 | dzaddr = dp->p_addr; |
3f3a34c3 | 366 | s = spl5(); |
5074fa57 BJ |
367 | if (tp->t_state & (TIMEOUT|BUSY|TTSTOP)) |
368 | goto out; | |
b25a5292 | 369 | if (tp->t_state&ASLEEP && tp->t_outq.c_cc <= TTLOWAT(tp)) { |
5074fa57 BJ |
370 | tp->t_state &= ~ASLEEP; |
371 | if (tp->t_chan) | |
372 | mcstart(tp->t_chan, (caddr_t)&tp->t_outq); | |
373 | else | |
374 | wakeup((caddr_t)&tp->t_outq); | |
375 | } | |
376 | if (tp->t_outq.c_cc == 0) | |
377 | goto out; | |
378 | if (tp->t_flags&RAW) | |
379 | cc = ndqb(&tp->t_outq, 0); | |
380 | else { | |
381 | cc = ndqb(&tp->t_outq, 0200); | |
382 | if (cc == 0) { | |
383 | cc = getc(&tp->t_outq); | |
384 | timeout(ttrstrt, (caddr_t)tp, (cc&0177) + 6); | |
385 | tp->t_state |= TIMEOUT; | |
386 | goto out; | |
387 | } | |
388 | } | |
389 | tp->t_state |= BUSY; | |
390 | dp->p_end = dp->p_mem = tp->t_outq.c_cf; | |
391 | dp->p_end += cc; | |
3f3a34c3 BJ |
392 | dzaddr->dztcr |= 1 << (minor(tp->t_dev) & 07); |
393 | out: | |
394 | splx(s); | |
5074fa57 BJ |
395 | } |
396 | ||
397 | /* | |
398 | * Stop output on a line. | |
399 | * Assume call is made at spl6. | |
400 | */ | |
401 | /*ARGSUSED*/ | |
402 | dzstop(tp, flag) | |
3f3a34c3 | 403 | register struct tty *tp; |
5074fa57 BJ |
404 | { |
405 | register struct pdma *dp; | |
406 | register int s; | |
407 | ||
3f3a34c3 | 408 | dp = (struct pdma *)tp->t_addr; |
5074fa57 BJ |
409 | s = spl6(); |
410 | if (tp->t_state & BUSY) { | |
411 | dp->p_end = dp->p_mem; | |
3f3a34c3 | 412 | if ((tp->t_state&TTSTOP)==0) |
5074fa57 | 413 | tp->t_state |= FLUSH; |
5074fa57 BJ |
414 | } |
415 | splx(s); | |
416 | } | |
417 | ||
3f3a34c3 BJ |
418 | dzmodem(unit, flag) |
419 | register int unit; | |
5074fa57 BJ |
420 | { |
421 | register struct device *dzaddr; | |
422 | register char bit; | |
423 | ||
3f3a34c3 BJ |
424 | dzaddr = dzpdma[unit].p_addr; |
425 | bit = 1<<(unit&07); | |
5074fa57 BJ |
426 | if (flag == OFF) |
427 | dzaddr->dzdtr &= ~bit; | |
428 | else | |
429 | dzaddr->dzdtr |= bit; | |
430 | } | |
431 | ||
432 | dzscan() | |
433 | { | |
434 | register i; | |
435 | register struct device *dzaddr; | |
436 | register bit; | |
437 | register struct tty *tp; | |
438 | ||
439 | for (i = 0; i < dz_cnt ; i++) { | |
440 | dzaddr = dzpdma[i].p_addr; | |
441 | tp = &dz_tty[i]; | |
442 | bit = 1<<(i&07); | |
0ff318b2 | 443 | if (dzaddr->dzmsr & bit || (i == 6 || i == 7)) { |
5074fa57 BJ |
444 | /* carrier present */ |
445 | if ((tp->t_state & CARR_ON) == 0) { | |
446 | wakeup((caddr_t)&tp->t_rawq); | |
447 | tp->t_state |= CARR_ON; | |
448 | } | |
449 | } else { | |
3f3a34c3 | 450 | if ((tp->t_state&CARR_ON) && (tp->t_local&LNOHANG)==0) { |
5074fa57 | 451 | /* carrier lost */ |
3f988b2a | 452 | if (tp->t_state&ISOPEN) { |
dc44829a | 453 | gsignal(tp->t_pgrp, SIGHUP); |
160cf9ed | 454 | gsignal(tp->t_pgrp, SIGCONT); |
dc44829a | 455 | dzaddr->dzdtr &= ~bit; |
cc343d94 | 456 | flushtty(tp, FREAD|FWRITE); |
dc44829a BJ |
457 | } |
458 | tp->t_state &= ~CARR_ON; | |
5074fa57 | 459 | } |
5074fa57 BJ |
460 | } |
461 | } | |
462 | timeout(dzscan, (caddr_t)0, 2*HZ); | |
463 | } | |
9dca4f86 BJ |
464 | |
465 | dztimer() | |
466 | { | |
467 | ||
468 | dzrint(0); | |
469 | } | |
46014098 BJ |
470 | |
471 | /* | |
472 | * Reset state of driver if UBA reset was necessary. | |
0072a3c2 | 473 | * Reset parameters and restart transmission on open lines. |
46014098 | 474 | */ |
3f3a34c3 | 475 | dzreset(uban) |
46014098 | 476 | { |
3f3a34c3 | 477 | register int unit; |
46014098 BJ |
478 | register struct tty *tp; |
479 | ||
3f3a34c3 BJ |
480 | /*** WE SHOULD LOOK TO SEE IF WE CARE ABOUT UBA BEING RESET ***/ |
481 | ||
46014098 | 482 | printf(" dz"); |
3f3a34c3 BJ |
483 | for (unit = 0; unit < NDZ; unit++) { |
484 | tp = &dz_tty[unit]; | |
46014098 | 485 | if (tp->t_state & (ISOPEN|WOPEN)) { |
3f3a34c3 BJ |
486 | dzparam(unit); |
487 | dzmodem(unit, ON); | |
0072a3c2 BJ |
488 | tp->t_state &= ~BUSY; |
489 | dzstart(tp); | |
46014098 BJ |
490 | } |
491 | } | |
492 | dztimer(); | |
46014098 | 493 | } |
a5cc519e | 494 | #endif |