ioctl —
how to implement a new ioctl call to access device drivers
ioctl are internally defined as
  - #define FOOIOCTL fun(t,n,pt)
-  
where the different variables and functions are:
  - FOOIOCTL
- the name which will later be given in the
      ioctl(2) system call as
      second argument, e.g.,
    ioctl(s, FOOIOCTL,
      ...).
 
- fun()
- a macro which can be one of
    
      - _IO
- the call is a simple message to the kernel by itself. It does not copy
          anything into the kernel, nor does it want anything back.
- _IOR
- the call only reads parameters from the kernel and does not pass any
          to it
- _IOW
- the call only writes parameters to the kernel, but does not want
          anything back
- _IOWR
- the call writes data to the kernel and wants information back.
 
- t
- This integer describes to which subsystem the ioctl applies.
      t can be one of
    
      - '1'
- pulse-per-second interface
- 'a'
- ISO networking
- 'A'
- ac devices (hp300)
- 'A'
- Advanced Power Management (hpcmips, i386, sparc), see
          apm(4)
- 'A'
- ADB devices (mac68k, macppc)
- 'A'
- audio(4)
- 'b'
- tb(4)
- 'b'
- Bluetooth HCI sockets, see
          bluetooth(4)
- 'b'
- Bluetooth Hub Control, see
          bthub(4)
- 'b'
- Bluetooth SCO audio driver, see
          btsco(4)
- 'B'
- bell device (x68k)
- 'B'
- bpf(4)
- 'c'
- coda
- 'c'
- cd(4)
- 'c'
- ch(4)
- 'C'
- clock devices (amiga, atari, hp300, x68k)
- 'd'
- the disk subsystem
- 'E'
- envsys(4)
- 'f'
- files
- 'F'
- Sun-compatible framebuffers
- 'F'
- ccd(4) and
          vnd(4)
- 'g'
- qdss framebuffers
- 'G'
- grf devices (amiga, atari, hp300, mac68k, x68k)
- 'h'
- HIL devices (hp300)
- 'H'
- HIL devices (hp300)
- 'H'
- HPc framebuffers
- 'i'
- a (pseudo) interface
- 'I'
- ite(4) (mac68k)
- 'J'
- ISA joystick interface
- 'k'
- Sun-compatible (and other) keyboards
- 'l'
- leo devices (atari)
- 'm'
- mtio(4)
- 'M'
- mouse devices (atari)
- 'M'
- mlx(4)
- 'n'
- virtual console device (arm32)
- 'n'
- SMB networking
- 'O'
- OpenPROM and OpenFirmware
- 'p'
- power control (x68k)
- 'P'
- parallel port (amiga, x68k)
- 'P'
- profiling (arm32)
- 'P'
- printer/plotter interface (hp300)
- 'P'
- pci(4)
- 'P'
- compat/ossaudio and soundcard.h
- 'P'
- magma(4) bpp (sparc)
- 'q'
- altq(9)
- 'q'
- pmax graphics devices
- 'Q'
- altq(9)
- 'Q'
- raw SCSI commands
- 'r'
- the routing subsystem
- 'r'
- md(4)
- 'R'
- rnd(4)
- 's'
- the socket layer
- 'S'
- SCSI disks (arc, hp300, pmax)
- 'S'
- watchdog devices (sh3)
- 'S'
- ISA speaker devices
- 'S'
- stic devices
- 'S'
- scanners
- 't'
- the tty layer
- 'u'
- user defined ???
- 'U'
- scsibus (see scsi(4))
- 'v'
- Sun-compatible “firm events”
- 'V'
- view device (amiga, atari)
- 'V'
- sram device (x68k)
- 'w'
- watchdog devices
- 'W'
- wt devices
- 'W'
- wscons devices
- 'x'
- bt8xx devices
- 'Z'
- ite devices (amiga, atari, x68k)
- 'Z'
- passthrough ioctls
 
- n
- This numbers the ioctl within the group. There may be only one
      n for a given t. This is an
      unsigned 8 bit number.
- pt
- This specifies the type of the passed parameter. This one gets internally
      transformed to the size of the parameter, so for example, if you want to
      pass a structure, then you have to specify that structure and not a
      pointer to it or sizeof(struct foo)
In order for the new ioctl to be known to the system it is
    installed in either ⟨sys/ioctl.h⟩ or
    one of the files that are reached from
    ⟨sys/ioctl.h⟩.
All ioctl() routines should return either 0 or a defined
  error code. The use of magic numbers such as -1, to indicate that a given
  ioctl code was not handled is strongly discouraged. The value -1 coincides
  with the historic value for ERESTART which was shown
  to produce user space code that never returned from a call to
  ioctl(2).
For ioctl codes that are not handled by a given routine, the
    pseudo error value EPASSTHROUGH is provided.
    EPASSTHROUGH indicates that no error occurred during
    processing (it did not fail), but neither was anything processed (it did not
    succeed). This supersedes the use of either ENOTTY
    (which is an explicit failure) or -1 (which has no contextual meaning) as a
    return value. ENOTTY will get passed directly back
    to user space and bypass any further processing by other ioctl layers. Only
    code that wishes to suppress possible further processing of an ioctl code
    (e.g., the tty line discipline code) should return
    ENOTTY. All other code should return
    EPASSTHROUGH, even if it knows that no other layers
    will be called upon.
If the value EPASSTHROUGH is returned to
    sys_ioctl(), then it will there be changed to
    ENOTTY to be returned to user space, thereby
    providing the proper error notification to the application.
#define	FOOIOCTL	_IOWR('i', 23, int)
int a = 3;
error = ioctl(s, FOOICTL, &a);
 
Within the
    ioctl()-routine of the
    driver, it can be then accessed like
driver_ioctl(..., u_long cmd, void *data)
{
	...
	switch (cmd) {
	case FOOIOCTL:
		int *a = (int *)data;
		printf(" Value passed: %d\n", *a);
		break;
	}
}
 
Note that if you for example try to read information from an ethernet driver
  where the name of the card is included in the third argument (e.g., ioctl(s,
  READFROMETH, struct ifreq *)), then you have to use the
  _IOWR() form not the _IOR(),
  as passing the name of the card to the kernel already consists of writing
  data.