1 /* The kernel call implemented in this file:
4 * The parameters for this kernel call are:
5 * m2_i3: DIO_REQUEST (request input or output)
6 * m2_p1: DIO_VEC_ADDR (pointer to port/ value pairs)
7 * m2_i2: DIO_VEC_SIZE (number of ports to read or write)
10 #include "kernel/system.h"
11 #include <minix/devio.h>
12 #include <minix/endpoint.h>
13 #include <minix/portio.h>
17 /* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */
18 static char vdevio_buf
[VDEVIO_BUF_SIZE
];
19 static pvb_pair_t
* const pvb
= (pvb_pair_t
*) vdevio_buf
;
20 static pvw_pair_t
* const pvw
= (pvw_pair_t
*) vdevio_buf
;
21 static pvl_pair_t
* const pvl
= (pvl_pair_t
*) vdevio_buf
;
23 /*===========================================================================*
25 *===========================================================================*/
26 int do_vdevio(struct proc
* caller
, message
* m_ptr
)
28 /* Perform a series of device I/O on behalf of a non-kernel process. The
29 * I/O addresses and I/O values are fetched from and returned to some buffer
30 * in user space. The actual I/O is wrapped by lock() and unlock() to prevent
31 * that I/O batch from being interrrupted.
32 * This is the counterpart of do_devio, which performs a single device I/O.
34 int vec_size
; /* size of vector */
35 int io_in
; /* true if input */
36 size_t bytes
; /* # bytes to be copied */
38 int i
, j
, io_size
, nr_io_range
;
41 struct io_range
*iorp
;
44 /* Get the request, size of the request vector, and check the values. */
45 io_dir
= m_ptr
->DIO_REQUEST
& _DIO_DIRMASK
;
46 io_type
= m_ptr
->DIO_REQUEST
& _DIO_TYPEMASK
;
47 if (io_dir
== _DIO_INPUT
) io_in
= TRUE
;
48 else if (io_dir
== _DIO_OUTPUT
) io_in
= FALSE
;
50 if ((vec_size
= m_ptr
->DIO_VEC_SIZE
) <= 0) return(EINVAL
);
53 bytes
= vec_size
* sizeof(pvb_pair_t
);
54 io_size
= sizeof(u8_t
);
57 bytes
= vec_size
* sizeof(pvw_pair_t
);
58 io_size
= sizeof(u16_t
);
61 bytes
= vec_size
* sizeof(pvl_pair_t
);
62 io_size
= sizeof(u32_t
);
64 default: return(EINVAL
); /* check type once and for all */
66 if (bytes
> sizeof(vdevio_buf
)) return(E2BIG
);
68 /* Copy (port,value)-pairs from user. */
69 if((r
=data_copy(caller
->p_endpoint
, (vir_bytes
) m_ptr
->DIO_VEC_ADDR
,
70 KERNEL
, (vir_bytes
) vdevio_buf
, bytes
)) != OK
)
74 if (privp
&& (privp
->s_flags
& CHECK_IO_PORT
))
76 /* Check whether the I/O is allowed */
77 nr_io_range
= privp
->s_nr_io_range
;
78 for (i
=0; i
<vec_size
; i
++)
81 case _DIO_BYTE
: port
= pvb
[i
].port
; break;
82 case _DIO_WORD
: port
= pvw
[i
].port
; break;
83 default: port
= pvl
[i
].port
; break;
85 for (j
= 0, iorp
= privp
->s_io_tab
; j
<nr_io_range
; j
++, iorp
++)
87 if (port
>= iorp
->ior_base
&&
88 port
+io_size
-1 <= iorp
->ior_limit
)
96 "do_vdevio: I/O port check failed for proc %d, port 0x%x\n",
97 caller
->p_endpoint
, port
);
103 /* Perform actual device I/O for byte, word, and long values */
105 case _DIO_BYTE
: /* byte values */
106 if (io_in
) for (i
=0; i
<vec_size
; i
++)
107 pvb
[i
].value
= inb( pvb
[i
].port
);
108 else for (i
=0; i
<vec_size
; i
++)
109 outb( pvb
[i
].port
, pvb
[i
].value
);
111 case _DIO_WORD
: /* word values */
114 for (i
=0; i
<vec_size
; i
++)
117 if (port
& 1) goto bad
;
118 pvw
[i
].value
= inw( pvw
[i
].port
);
123 for (i
=0; i
<vec_size
; i
++)
126 if (port
& 1) goto bad
;
127 outw( pvw
[i
].port
, pvw
[i
].value
);
131 default: /* long values */
134 for (i
=0; i
<vec_size
; i
++)
137 if (port
& 3) goto bad
;
138 pvl
[i
].value
= inl(pvl
[i
].port
);
143 for (i
=0; i
<vec_size
; i
++)
146 if (port
& 3) goto bad
;
147 outl( pvb
[i
].port
, pvl
[i
].value
);
152 /* Almost done, copy back results for input requests. */
154 if((r
=data_copy(KERNEL
, (vir_bytes
) vdevio_buf
,
155 caller
->p_endpoint
, (vir_bytes
) m_ptr
->DIO_VEC_ADDR
,
156 (phys_bytes
) bytes
)) != OK
)
161 panic("do_vdevio: unaligned port: %d", port
);
165 #endif /* USE_VDEVIO */