xref: /minix3/minix/kernel/system/do_devio.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1 /* The kernel call implemented in this file:
2  *   m_type:	SYS_DEVIO
3  *
4  * The parameters for this kernel call are:
5  *   m_lsys_krn_sys_devio.request	(request input or output)
6  *   m_lsys_krn_sys_devio.port		(port to read/ write)
7  *   m_lsys_krn_sys_devio.value		(value to write/ return value read)
8  */
9 
10 #include "kernel/system.h"
11 #include <minix/devio.h>
12 #include <minix/endpoint.h>
13 #include <minix/portio.h>
14 
15 #if USE_DEVIO
16 
17 /*===========================================================================*
18  *			        do_devio                                     *
19  *===========================================================================*/
20 int do_devio(struct proc * caller, message * m_ptr)
21 {
22     struct priv *privp;
23     port_t port;
24     struct io_range *iorp;
25     int i, size, nr_io_range;
26     int io_type, io_dir;
27 
28     io_type = m_ptr->m_lsys_krn_sys_devio.request & _DIO_TYPEMASK;
29     io_dir  = m_ptr->m_lsys_krn_sys_devio.request & _DIO_DIRMASK;
30 
31     switch (io_type)
32     {
33 	case _DIO_BYTE: size= 1; break;
34 	case _DIO_WORD: size= 2; break;
35 	case _DIO_LONG: size= 4; break;
36 	default: size= 4; break;	/* Be conservative */
37     }
38 
39     privp= priv(caller);
40     if (!privp)
41     {
42 	printf("no priv structure!\n");
43 	goto doit;
44     }
45     if (privp->s_flags & CHECK_IO_PORT)
46     {
47 	port= m_ptr->m_lsys_krn_sys_devio.port;
48 	nr_io_range= privp->s_nr_io_range;
49 	for (i= 0, iorp= privp->s_io_tab; i<nr_io_range; i++, iorp++)
50 	{
51 		if (port >= iorp->ior_base && port+size-1 <= iorp->ior_limit)
52 			break;
53 	}
54 	if (i >= nr_io_range)
55 	{
56 			printf("do_devio: port 0x%x (size %d) not allowed\n",
57 				m_ptr->m_lsys_krn_sys_devio.port, size);
58 		return EPERM;
59 	}
60     }
61 
62 doit:
63     if (m_ptr->m_lsys_krn_sys_devio.port & (size-1))
64     {
65 		printf("do_devio: unaligned port 0x%x (size %d)\n",
66 			m_ptr->m_lsys_krn_sys_devio.port, size);
67 	return EPERM;
68     }
69 
70 /* Process a single I/O request for byte, word, and long values. */
71     if (io_dir == _DIO_INPUT) {
72       switch (io_type) {
73 	/* maybe "it" should not be called ports */
74         case _DIO_BYTE:
75 		m_ptr->m_krn_lsys_sys_devio.value =
76 			inb(m_ptr->m_lsys_krn_sys_devio.port);
77 		break;
78         case _DIO_WORD:
79 		m_ptr->m_krn_lsys_sys_devio.value =
80 			inw(m_ptr->m_lsys_krn_sys_devio.port);
81 		break;
82         case _DIO_LONG:
83 		m_ptr->m_krn_lsys_sys_devio.value =
84 			inl(m_ptr->m_lsys_krn_sys_devio.port);
85 		break;
86     	default: return(EINVAL);
87       }
88     } else {
89       switch (io_type) {
90 	case _DIO_BYTE:
91 		outb(m_ptr->m_lsys_krn_sys_devio.port,
92 			m_ptr->m_lsys_krn_sys_devio.value);
93 		break;
94 	case _DIO_WORD:
95 		outw(m_ptr->m_lsys_krn_sys_devio.port,
96 			m_ptr->m_lsys_krn_sys_devio.value);
97 		break;
98 	case _DIO_LONG:
99 		outl(m_ptr->m_lsys_krn_sys_devio.port,
100 			m_ptr->m_lsys_krn_sys_devio.value);
101 		break;
102     	default: return(EINVAL);
103       }
104     }
105     return(OK);
106 }
107 
108 #endif /* USE_DEVIO */
109