1
2 #include "inc.h"
3
4 #include <dev/pci/pciio.h>
5
6 #include <minix/fb.h>
7 #include <minix/i2c.h>
8 #include <minix/keymap.h>
9 #include <minix/sound.h>
10
11 #include <sys/fcntl.h>
12 #include <sys/ioctl.h>
13 #include <sys/kbdio.h>
14 #include <sys/termios.h>
15 #include <sys/time.h>
16
17 const char *
char_ioctl_name(unsigned long req)18 char_ioctl_name(unsigned long req)
19 {
20
21 switch (req) {
22 NAME(MINIX_I2C_IOCTL_EXEC);
23 NAME(FBIOGET_VSCREENINFO);
24 NAME(FBIOPUT_VSCREENINFO);
25 NAME(FBIOGET_FSCREENINFO); /* TODO: print argument */
26 NAME(FBIOPAN_DISPLAY);
27 NAME(DSPIORATE);
28 NAME(DSPIOSTEREO);
29 NAME(DSPIOSIZE);
30 NAME(DSPIOBITS);
31 NAME(DSPIOSIGN);
32 NAME(DSPIOMAX);
33 NAME(DSPIORESET); /* no argument */
34 NAME(DSPIOFREEBUF);
35 NAME(DSPIOSAMPLESINBUF);
36 NAME(DSPIOPAUSE); /* no argument */
37 NAME(DSPIORESUME); /* no argument */
38 NAME(MIXIOGETVOLUME);
39 NAME(MIXIOGETINPUTLEFT);
40 NAME(MIXIOGETINPUTRIGHT);
41 NAME(MIXIOGETOUTPUT);
42 NAME(MIXIOSETVOLUME);
43 NAME(MIXIOSETINPUTLEFT);
44 NAME(MIXIOSETINPUTRIGHT);
45 NAME(MIXIOSETOUTPUT);
46 NAME(TIOCEXCL); /* no argument */
47 NAME(TIOCNXCL); /* no argument */
48 NAME(TIOCFLUSH);
49 NAME(TIOCGETA);
50 NAME(TIOCSETA);
51 NAME(TIOCSETAW);
52 NAME(TIOCSETAF);
53 NAME(TIOCGETD);
54 NAME(TIOCSETD);
55 NAME(TIOCGLINED);
56 NAME(TIOCSLINED);
57 NAME(TIOCSBRK); /* no argument */
58 NAME(TIOCCBRK); /* no argument */
59 NAME(TIOCSDTR); /* no argument */
60 NAME(TIOCCDTR); /* no argument */
61 NAME(TIOCGPGRP);
62 NAME(TIOCSPGRP);
63 NAME(TIOCOUTQ);
64 NAME(TIOCSTI);
65 NAME(TIOCNOTTY); /* no argument */
66 NAME(TIOCPKT);
67 NAME(TIOCSTOP); /* no argument */
68 NAME(TIOCSTART); /* no argument */
69 NAME(TIOCMSET); /* TODO: print argument */
70 NAME(TIOCMBIS); /* TODO: print argument */
71 NAME(TIOCMBIC); /* TODO: print argument */
72 NAME(TIOCMGET); /* TODO: print argument */
73 NAME(TIOCREMOTE);
74 NAME(TIOCGWINSZ);
75 NAME(TIOCSWINSZ);
76 NAME(TIOCUCNTL);
77 NAME(TIOCSTAT);
78 NAME(TIOCGSID);
79 NAME(TIOCCONS);
80 NAME(TIOCSCTTY); /* no argument */
81 NAME(TIOCEXT);
82 NAME(TIOCSIG); /* no argument */
83 NAME(TIOCDRAIN); /* no argument */
84 NAME(TIOCGFLAGS); /* TODO: print argument */
85 NAME(TIOCSFLAGS); /* TODO: print argument */
86 NAME(TIOCDCDTIMESTAMP); /* TODO: print argument */
87 NAME(TIOCRCVFRAME); /* TODO: print argument */
88 NAME(TIOCXMTFRAME); /* TODO: print argument */
89 NAME(TIOCPTMGET); /* TODO: print argument */
90 NAME(TIOCGRANTPT); /* no argument */
91 NAME(TIOCPTSNAME); /* TODO: print argument */
92 NAME(TIOCSQSIZE);
93 NAME(TIOCGQSIZE);
94 NAME(TIOCSFON); /* big IOCTL, not printing argument */
95 NAME(KIOCBELL);
96 NAME(KIOCSLEDS);
97 NAME(KIOCSMAP); /* not worth interpreting */
98 NAME(PCI_IOC_CFGREAD);
99 NAME(PCI_IOC_CFGWRITE);
100 NAME(PCI_IOC_BDF_CFGREAD);
101 NAME(PCI_IOC_BDF_CFGWRITE);
102 NAME(PCI_IOC_BUSINFO);
103 NAME(PCI_IOC_MAP);
104 NAME(PCI_IOC_UNMAP);
105 NAME(PCI_IOC_RESERVE);
106 NAME(PCI_IOC_RELEASE);
107 }
108
109 return NULL;
110 }
111
112 static void
put_i2c_op(struct trace_proc * proc,const char * name,i2c_op_t op)113 put_i2c_op(struct trace_proc * proc, const char *name, i2c_op_t op)
114 {
115 const char *text = NULL;
116
117 if (!valuesonly) {
118 switch (op) {
119 TEXT(I2C_OP_READ);
120 TEXT(I2C_OP_READ_WITH_STOP);
121 TEXT(I2C_OP_WRITE);
122 TEXT(I2C_OP_WRITE_WITH_STOP);
123 TEXT(I2C_OP_READ_BLOCK);
124 TEXT(I2C_OP_WRITE_BLOCK);
125 }
126 }
127
128 if (text != NULL)
129 put_field(proc, name, text);
130 else
131 put_value(proc, name, "%d", op);
132 }
133
134 static void
put_sound_device(struct trace_proc * proc,const char * name,int device)135 put_sound_device(struct trace_proc * proc, const char * name, int device)
136 {
137 const char *text = NULL;
138
139 if (!valuesonly) {
140 switch (device) {
141 TEXT(Master);
142 TEXT(Dac);
143 TEXT(Fm);
144 TEXT(Cd);
145 TEXT(Line);
146 TEXT(Mic);
147 TEXT(Speaker);
148 TEXT(Treble);
149 TEXT(Bass);
150 }
151 }
152
153 if (text != NULL)
154 put_field(proc, name, text);
155 else
156 put_value(proc, name, "%d", device);
157 }
158
159 static void
put_sound_state(struct trace_proc * proc,const char * name,int state)160 put_sound_state(struct trace_proc * proc, const char * name, int state)
161 {
162
163 if (!valuesonly && state == ON)
164 put_field(proc, name, "ON");
165 else if (!valuesonly && state == OFF)
166 put_field(proc, name, "OFF");
167 else
168 put_value(proc, name, "%d", state);
169 }
170
171 static const struct flags flush_flags[] = {
172 FLAG(FREAD),
173 FLAG(FWRITE),
174 };
175
176 static const struct flags tc_iflags[] = {
177 FLAG(IGNBRK),
178 FLAG(BRKINT),
179 FLAG(IGNPAR),
180 FLAG(PARMRK),
181 FLAG(INPCK),
182 FLAG(ISTRIP),
183 FLAG(INLCR),
184 FLAG(IGNCR),
185 FLAG(ICRNL),
186 FLAG(IXON),
187 FLAG(IXOFF),
188 FLAG(IXANY),
189 FLAG(IMAXBEL),
190 };
191
192 static const struct flags tc_oflags[] = {
193 FLAG(OPOST),
194 FLAG(ONLCR),
195 FLAG(OXTABS),
196 FLAG(ONOEOT),
197 FLAG(OCRNL),
198 FLAG(ONOCR),
199 FLAG(ONLRET),
200 };
201
202 static const struct flags tc_cflags[] = {
203 FLAG(CIGNORE),
204 FLAG_MASK(CSIZE, CS5),
205 FLAG_MASK(CSIZE, CS6),
206 FLAG_MASK(CSIZE, CS7),
207 FLAG_MASK(CSIZE, CS8),
208 FLAG(CSTOPB),
209 FLAG(CREAD),
210 FLAG(PARENB),
211 FLAG(PARODD),
212 FLAG(HUPCL),
213 FLAG(CLOCAL),
214 FLAG(CRTSCTS),
215 FLAG(CDTRCTS),
216 FLAG(MDMBUF),
217 };
218
219 static const struct flags tc_lflags[] = {
220 FLAG(ECHOKE),
221 FLAG(ECHOE),
222 FLAG(ECHOK),
223 FLAG(ECHO),
224 FLAG(ECHONL),
225 FLAG(ECHOPRT),
226 FLAG(ECHOCTL),
227 FLAG(ISIG),
228 FLAG(ICANON),
229 FLAG(ALTWERASE),
230 FLAG(IEXTEN),
231 FLAG(EXTPROC),
232 FLAG(TOSTOP),
233 FLAG(FLUSHO),
234 FLAG(NOKERNINFO),
235 FLAG(PENDIN),
236 FLAG(NOFLSH),
237 };
238
239 static void
put_tty_disc(struct trace_proc * proc,const char * name,int disc)240 put_tty_disc(struct trace_proc * proc, const char * name, int disc)
241 {
242 const char *text = NULL;
243
244 if (!valuesonly) {
245 switch (disc) {
246 TEXT(TTYDISC);
247 TEXT(TABLDISC);
248 TEXT(SLIPDISC);
249 TEXT(PPPDISC);
250 TEXT(STRIPDISC);
251 TEXT(HDLCDISC);
252 }
253 }
254
255 if (text != NULL)
256 put_field(proc, name, text);
257 else
258 put_value(proc, name, "%d", disc);
259 }
260
261 static const struct flags kbd_leds[] = {
262 FLAG(KBD_LEDS_NUM),
263 FLAG(KBD_LEDS_CAPS),
264 FLAG(KBD_LEDS_SCROLL),
265 };
266
267 int
char_ioctl_arg(struct trace_proc * proc,unsigned long req,void * ptr,int dir)268 char_ioctl_arg(struct trace_proc * proc, unsigned long req, void * ptr,
269 int dir)
270 {
271 minix_i2c_ioctl_exec_t *iie;
272 struct fb_var_screeninfo *fbvs;
273 struct volume_level *level;
274 struct inout_ctrl *inout;
275 struct termios *tc;
276 struct ptmget *pm;
277 struct winsize *ws;
278 struct kio_bell *bell;
279 struct kio_leds *leds;
280 struct pciio_cfgreg *pci_cfgreg;
281 struct pciio_bdf_cfgreg *pci_bdf_cfgreg;
282 struct pciio_businfo *pci_businfo;
283 struct pciio_map *pci_iomap;
284 struct pciio_acl *pci_acl;
285
286 switch (req) {
287 case MINIX_I2C_IOCTL_EXEC:
288 if ((iie = (minix_i2c_ioctl_exec_t *)ptr) == NULL)
289 return IF_OUT; /* we print only the request for now */
290
291 put_i2c_op(proc, "iie_op", iie->iie_op);
292 put_value(proc, "iie_addr", "0x%04x", iie->iie_addr);
293 return 0; /* TODO: print command/data/result */
294
295 case FBIOGET_VSCREENINFO:
296 if ((fbvs = (struct fb_var_screeninfo *)ptr) == NULL)
297 return IF_IN;
298
299 put_value(proc, "xres", "%"PRIu32, fbvs->xres);
300 put_value(proc, "yres", "%"PRIu32, fbvs->yres);
301 put_value(proc, "xres_virtual", "%"PRIu32, fbvs->xres_virtual);
302 put_value(proc, "yres_virtual", "%"PRIu32, fbvs->yres_virtual);
303 put_value(proc, "xoffset", "%"PRIu32, fbvs->xoffset);
304 put_value(proc, "yoffset", "%"PRIu32, fbvs->yoffset);
305 put_value(proc, "bits_per_pixel", "%"PRIu32,
306 fbvs->bits_per_pixel);
307 return 0;
308
309 case FBIOPUT_VSCREENINFO:
310 case FBIOPAN_DISPLAY:
311 if ((fbvs = (struct fb_var_screeninfo *)ptr) == NULL)
312 return IF_OUT;
313
314 put_value(proc, "xoffset", "%"PRIu32, fbvs->xoffset);
315 put_value(proc, "yoffset", "%"PRIu32, fbvs->yoffset);
316 return 0;
317
318 case DSPIORATE:
319 case DSPIOSTEREO:
320 case DSPIOSIZE:
321 case DSPIOBITS:
322 case DSPIOSIGN:
323 case DSPIOMAX:
324 case DSPIOFREEBUF:
325 case DSPIOSAMPLESINBUF:
326 if (ptr == NULL)
327 return dir;
328
329 put_value(proc, NULL, "%u", *(unsigned int *)ptr);
330 return IF_ALL;
331
332 case MIXIOGETVOLUME:
333 if ((level = (struct volume_level *)ptr) == NULL)
334 return dir;
335
336 if (dir == IF_OUT)
337 put_sound_device(proc, "device", level->device);
338 else {
339 put_value(proc, "left", "%d", level->left);
340 put_value(proc, "right", "%d", level->right);
341 }
342 return IF_ALL;
343
344 case MIXIOSETVOLUME:
345 /* Print the corrected volume levels only with verbosity on. */
346 if ((level = (struct volume_level *)ptr) == NULL)
347 return IF_OUT | ((verbose > 0) ? IF_IN : 0);
348
349 if (dir == IF_OUT)
350 put_sound_device(proc, "device", level->device);
351 put_value(proc, "left", "%d", level->left);
352 put_value(proc, "right", "%d", level->right);
353 return IF_ALL;
354
355 case MIXIOGETINPUTLEFT:
356 case MIXIOGETINPUTRIGHT:
357 case MIXIOGETOUTPUT:
358 if ((inout = (struct inout_ctrl *)ptr) == NULL)
359 return dir;
360
361 if (dir == IF_OUT)
362 put_sound_device(proc, "device", inout->device);
363 else {
364 put_sound_state(proc, "left", inout->left);
365 put_sound_state(proc, "right", inout->right);
366 }
367 return IF_ALL;
368
369 case MIXIOSETINPUTLEFT:
370 case MIXIOSETINPUTRIGHT:
371 case MIXIOSETOUTPUT:
372 if ((inout = (struct inout_ctrl *)ptr) == NULL)
373 return IF_OUT;
374
375 put_sound_device(proc, "device", inout->device);
376 put_sound_state(proc, "left", inout->left);
377 put_sound_state(proc, "right", inout->right);
378 return IF_ALL;
379
380 case TIOCFLUSH:
381 if (ptr == NULL)
382 return IF_OUT;
383
384 put_flags(proc, NULL, flush_flags, COUNT(flush_flags), "0x%x",
385 *(int *)ptr);
386 return IF_ALL;
387
388 case TIOCGETA:
389 case TIOCSETA:
390 case TIOCSETAW:
391 case TIOCSETAF:
392 if ((tc = (struct termios *)ptr) == NULL)
393 return dir;
394
395 /*
396 * These are fairly common IOCTLs, so printing everything by
397 * default would create a lot of noise. By default we limit
398 * ourselves to printing the field that contains what I
399 * consider to be the most important flag: ICANON.
400 * TODO: see if we can come up with a decent format for
401 * selectively printing (relatively important) flags.
402 */
403 if (verbose > 0) {
404 put_flags(proc, "c_iflag", tc_iflags, COUNT(tc_iflags),
405 "0x%x", tc->c_iflag);
406 put_flags(proc, "c_oflag", tc_oflags, COUNT(tc_oflags),
407 "0x%x", tc->c_oflag);
408 put_flags(proc, "c_cflag", tc_cflags, COUNT(tc_cflags),
409 "0x%x", tc->c_cflag);
410 }
411 put_flags(proc, "c_lflag", tc_lflags, COUNT(tc_lflags), "0x%x",
412 tc->c_lflag);
413 if (verbose > 0) {
414 put_value(proc, "c_ispeed", "%d", tc->c_ispeed);
415 put_value(proc, "c_ospeed", "%d", tc->c_ospeed);
416 }
417 return 0; /* TODO: print the c_cc fields */
418
419 case TIOCGETD:
420 case TIOCSETD:
421 if (ptr == NULL)
422 return dir;
423
424 put_tty_disc(proc, NULL, *(int *)ptr);
425 return IF_ALL;
426
427 case TIOCGLINED:
428 case TIOCSLINED:
429 if (ptr == NULL)
430 return dir;
431
432 put_buf(proc, NULL, PF_LOCADDR | PF_STRING, (vir_bytes)ptr,
433 sizeof(linedn_t));
434 return IF_ALL;
435
436 case TIOCGPGRP:
437 case TIOCSPGRP:
438 case TIOCOUTQ:
439 case TIOCPKT:
440 case TIOCREMOTE:
441 case TIOCUCNTL:
442 case TIOCSTAT: /* argument seems unused? */
443 case TIOCGSID:
444 case TIOCCONS: /* argument seems unused? */
445 case TIOCEXT:
446 case TIOCSQSIZE:
447 case TIOCGQSIZE:
448 /* Print a simple integer. */
449 if (ptr == NULL)
450 return dir;
451
452 put_value(proc, NULL, "%d", *(int *)ptr);
453 return IF_ALL;
454
455 case TIOCPTSNAME:
456 if ((pm = (struct ptmget *)ptr) == NULL)
457 return IF_IN;
458
459 put_buf(proc, "sn", PF_LOCADDR | PF_STRING, (vir_bytes)pm->sn,
460 sizeof(pm->sn));
461 return IF_ALL;
462
463 case TIOCSTI:
464 if (ptr == NULL)
465 return dir;
466
467 if (!valuesonly)
468 put_value(proc, NULL, "'%s'",
469 get_escape(*(char *)ptr));
470 else
471 put_value(proc, NULL, "%u", *(char *)ptr);
472 return IF_ALL;
473
474 case TIOCGWINSZ:
475 case TIOCSWINSZ:
476 if ((ws = (struct winsize *)ptr) == NULL)
477 return dir;
478
479 /* This is a stupid order, but we follow the struct layout. */
480 put_value(proc, "ws_row", "%u", ws->ws_row);
481 put_value(proc, "ws_col", "%u", ws->ws_col);
482 if (verbose > 0) {
483 put_value(proc, "ws_xpixel", "%u", ws->ws_xpixel);
484 put_value(proc, "ws_ypixel", "%u", ws->ws_ypixel);
485 }
486 return (verbose > 0) ? IF_ALL : 0;
487
488 case KIOCBELL:
489 if ((bell = (struct kio_bell *)ptr) == NULL)
490 return IF_OUT;
491
492 put_value(proc, "kb_pitch", "%u", bell->kb_pitch);
493 put_value(proc, "kb_volume", "%lu", bell->kb_volume);
494 put_struct_timeval(proc, "kb_duration", PF_LOCADDR,
495 (vir_bytes)&bell->kb_duration);
496
497 return IF_ALL;
498
499 case KIOCSLEDS:
500 if ((leds = (struct kio_leds *)ptr) == NULL)
501 return IF_OUT;
502
503 put_flags(proc, "kl_bits", kbd_leds, COUNT(kbd_leds), "0x%x",
504 leds->kl_bits);
505 return IF_ALL;
506
507 case PCI_IOC_CFGREAD:
508 if ((pci_cfgreg = (struct pciio_cfgreg *)ptr) == NULL)
509 return IF_IN;
510
511 put_ptr(proc, "reg", (vir_bytes)pci_cfgreg->reg);
512 put_value(proc, "val", "%08x", pci_cfgreg->val);
513 return IF_ALL;
514
515 case PCI_IOC_CFGWRITE:
516 if ((pci_cfgreg = (struct pciio_cfgreg *)ptr) == NULL)
517 return IF_OUT;
518
519 put_ptr(proc, "reg", (vir_bytes)pci_cfgreg->reg);
520 put_value(proc, "val", "%08x", pci_cfgreg->val);
521 return IF_ALL;
522
523 case PCI_IOC_BDF_CFGREAD:
524 if ((pci_bdf_cfgreg = (struct pciio_bdf_cfgreg *)ptr) == NULL)
525 return IF_IN;
526
527 put_value(proc, "bus", "%u", pci_bdf_cfgreg->bus);
528 put_value(proc, "device", "%u", pci_bdf_cfgreg->device);
529 put_value(proc, "function", "%u", pci_bdf_cfgreg->function);
530 put_ptr(proc, "cfgreg.reg", (vir_bytes)pci_bdf_cfgreg->cfgreg.reg);
531 put_value(proc, "cfgreg.val", "%08x", pci_bdf_cfgreg->cfgreg.val);
532 return IF_ALL;
533
534 case PCI_IOC_BDF_CFGWRITE:
535 if ((pci_bdf_cfgreg = (struct pciio_bdf_cfgreg *)ptr) == NULL)
536 return IF_OUT;
537
538 put_value(proc, "bus", "%u", pci_bdf_cfgreg->bus);
539 put_value(proc, "device", "%u", pci_bdf_cfgreg->device);
540 put_value(proc, "function", "%u", pci_bdf_cfgreg->function);
541 put_ptr(proc, "cfgreg.reg", (vir_bytes)pci_bdf_cfgreg->cfgreg.reg);
542 put_value(proc, "cfgreg.val", "%08x", pci_bdf_cfgreg->cfgreg.val);
543 return IF_ALL;
544
545 case PCI_IOC_BUSINFO:
546 if ((pci_businfo = (struct pciio_businfo *)ptr) == NULL)
547 return IF_IN;
548
549 put_value(proc, "busno", "%u", pci_businfo->busno);
550 put_value(proc, "maxdevs", "%u", pci_businfo->maxdevs);
551 return IF_ALL;
552
553 case PCI_IOC_MAP:
554 if ((pci_iomap = (struct pciio_map *)ptr) == NULL)
555 return IF_OUT|IF_IN;
556
557 put_value(proc, "flags", "%x", pci_iomap->flags);
558 put_value(proc, "phys_offset", "%08x", pci_iomap->phys_offset);
559 put_value(proc, "size", "%zu", pci_iomap->size);
560 put_value(proc, "readonly", "%x", pci_iomap->readonly);
561
562 if (IF_IN == dir)
563 put_ptr(proc, "vaddr_ret", (vir_bytes)pci_iomap->vaddr_ret);
564
565 return IF_ALL;
566
567 case PCI_IOC_UNMAP:
568 if ((pci_iomap = (struct pciio_map *)ptr) == NULL)
569 return IF_OUT;
570
571 put_ptr(proc, "vaddr", (vir_bytes)pci_iomap->vaddr);
572
573 return IF_ALL;
574
575 case PCI_IOC_RESERVE:
576 if ((pci_acl = (struct pciio_acl *)ptr) == NULL)
577 return IF_OUT;
578
579 put_value(proc, "domain", "%u", pci_acl->domain);
580 put_value(proc, "bus", "%u", pci_acl->bus);
581 put_value(proc, "device", "%u", pci_acl->device);
582 put_value(proc, "function", "%u", pci_acl->function);
583
584 return IF_ALL;
585 case PCI_IOC_RELEASE:
586 if ((pci_acl = (struct pciio_acl *)ptr) == NULL)
587 return IF_OUT;
588
589 put_value(proc, "domain", "%u", pci_acl->domain);
590 put_value(proc, "bus", "%u", pci_acl->bus);
591 put_value(proc, "device", "%u", pci_acl->device);
592 put_value(proc, "function", "%u", pci_acl->function);
593
594 return IF_ALL;
595
596 default:
597 return 0;
598 }
599 }
600