1 /* The kernel call implemented in this file:
4 * The parameters for this kernel call are:
5 * m_lsys_krn_sys_vdevio.request (request input or output)
6 * m_lsys_krn_sys_vdevio.vec_addr (pointer to port/ value pairs)
7 * m_lsys_krn_sys_vdevio.vec_size (number of ports to read or write)
10 #include "kernel/system.h"
11 #include <minix/devio.h>
12 #include <minix/endpoint.h>
16 /* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */
17 static char vdevio_buf
[VDEVIO_BUF_SIZE
];
18 static pvb_pair_t
* const pvb
= (pvb_pair_t
*) vdevio_buf
;
19 static pvw_pair_t
* const pvw
= (pvw_pair_t
*) vdevio_buf
;
20 static pvl_pair_t
* const pvl
= (pvl_pair_t
*) vdevio_buf
;
22 /*===========================================================================*
24 *===========================================================================*/
25 int do_vdevio(struct proc
* caller
, message
* m_ptr
)
27 /* Perform a series of device I/O on behalf of a non-kernel process. The
28 * I/O addresses and I/O values are fetched from and returned to some buffer
29 * in user space. The actual I/O is wrapped by lock() and unlock() to prevent
30 * that I/O batch from being interrupted.
31 * This is the counterpart of do_devio, which performs a single device I/O.
33 int vec_size
; /* size of vector */
34 int io_in
; /* true if input */
35 size_t bytes
; /* # bytes to be copied */
37 int i
, j
, io_size
, nr_io_range
;
40 struct io_range
*iorp
;
43 /* Get the request, size of the request vector, and check the values. */
44 io_dir
= m_ptr
->m_lsys_krn_sys_vdevio
.request
& _DIO_DIRMASK
;
45 io_type
= m_ptr
->m_lsys_krn_sys_vdevio
.request
& _DIO_TYPEMASK
;
46 if (io_dir
== _DIO_INPUT
) io_in
= TRUE
;
47 else if (io_dir
== _DIO_OUTPUT
) io_in
= FALSE
;
49 if ((vec_size
= m_ptr
->m_lsys_krn_sys_vdevio
.vec_size
) <= 0) return(EINVAL
);
52 bytes
= vec_size
* sizeof(pvb_pair_t
);
53 io_size
= sizeof(u8_t
);
56 bytes
= vec_size
* sizeof(pvw_pair_t
);
57 io_size
= sizeof(u16_t
);
60 bytes
= vec_size
* sizeof(pvl_pair_t
);
61 io_size
= sizeof(u32_t
);
63 default: return(EINVAL
); /* check type once and for all */
65 if (bytes
> sizeof(vdevio_buf
)) return(E2BIG
);
67 /* Copy (port,value)-pairs from user. */
68 if((r
=data_copy(caller
->p_endpoint
, m_ptr
->m_lsys_krn_sys_vdevio
.vec_addr
,
69 KERNEL
, (vir_bytes
) vdevio_buf
, bytes
)) != OK
)
73 if (privp
&& (privp
->s_flags
& CHECK_IO_PORT
))
75 /* Check whether the I/O is allowed */
76 nr_io_range
= privp
->s_nr_io_range
;
77 for (i
=0; i
<vec_size
; i
++)
80 case _DIO_BYTE
: port
= pvb
[i
].port
; break;
81 case _DIO_WORD
: port
= pvw
[i
].port
; break;
82 default: port
= pvl
[i
].port
; break;
84 for (j
= 0, iorp
= privp
->s_io_tab
; j
<nr_io_range
; j
++, iorp
++)
86 if (port
>= iorp
->ior_base
&&
87 port
+io_size
-1 <= iorp
->ior_limit
)
95 "do_vdevio: I/O port check failed for proc %d, port 0x%x\n",
96 caller
->p_endpoint
, port
);
102 /* Perform actual device I/O for byte, word, and long values */
104 case _DIO_BYTE
: /* byte values */
105 if (io_in
) for (i
=0; i
<vec_size
; i
++)
106 pvb
[i
].value
= inb( pvb
[i
].port
);
107 else for (i
=0; i
<vec_size
; i
++)
108 outb( pvb
[i
].port
, pvb
[i
].value
);
110 case _DIO_WORD
: /* word values */
113 for (i
=0; i
<vec_size
; i
++)
116 if (port
& 1) goto bad
;
117 pvw
[i
].value
= inw( pvw
[i
].port
);
122 for (i
=0; i
<vec_size
; i
++)
125 if (port
& 1) goto bad
;
126 outw( pvw
[i
].port
, pvw
[i
].value
);
130 default: /* long values */
133 for (i
=0; i
<vec_size
; i
++)
136 if (port
& 3) goto bad
;
137 pvl
[i
].value
= inl(pvl
[i
].port
);
142 for (i
=0; i
<vec_size
; i
++)
145 if (port
& 3) goto bad
;
146 outl( pvb
[i
].port
, pvl
[i
].value
);
151 /* Almost done, copy back results for input requests. */
153 if((r
=data_copy(KERNEL
, (vir_bytes
) vdevio_buf
,
154 caller
->p_endpoint
, m_ptr
->m_lsys_krn_sys_vdevio
.vec_addr
,
155 (phys_bytes
) bytes
)) != OK
)
160 panic("do_vdevio: unaligned port: %d", port
);
164 #endif /* USE_VDEVIO */