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_i1: DIO_TYPE (flag indicating byte, word, or long)
7 * m2_p1: DIO_VEC_ADDR (pointer to port/ value pairs)
8 * m2_i2: DIO_VEC_SIZE (number of ports to read or write)
11 #include "../system.h"
12 #include <minix/devio.h>
13 #include <minix/endpoint.h>
14 #include <minix/portio.h>
18 /* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */
19 PRIVATE
char vdevio_buf
[VDEVIO_BUF_SIZE
];
20 PRIVATE pvb_pair_t
*pvb
= (pvb_pair_t
*) vdevio_buf
;
21 PRIVATE pvw_pair_t
*pvw
= (pvw_pair_t
*) vdevio_buf
;
22 PRIVATE pvl_pair_t
*pvl
= (pvl_pair_t
*) vdevio_buf
;
24 /*===========================================================================*
26 *===========================================================================*/
27 PUBLIC
int do_vdevio(m_ptr
)
28 register message
*m_ptr
; /* pointer to request message */
30 /* Perform a series of device I/O on behalf of a non-kernel process. The
31 * I/O addresses and I/O values are fetched from and returned to some buffer
32 * in user space. The actual I/O is wrapped by lock() and unlock() to prevent
33 * that I/O batch from being interrrupted.
34 * This is the counterpart of do_devio, which performs a single device I/O.
36 int vec_size
; /* size of vector */
37 int io_in
; /* true if input */
38 size_t bytes
; /* # bytes to be copied */
39 vir_bytes caller_vir
; /* virtual address at caller */
40 phys_bytes caller_phys
; /* physical address at caller */
42 int i
, j
, io_size
, nr_io_range
;
46 struct io_range
*iorp
;
48 /* Get the request, size of the request vector, and check the values. */
49 io_dir
= m_ptr
->DIO_REQUEST
& _DIO_DIRMASK
;
50 io_type
= m_ptr
->DIO_REQUEST
& _DIO_TYPEMASK
;
51 if (io_dir
== _DIO_INPUT
) io_in
= TRUE
;
52 else if (io_dir
== _DIO_OUTPUT
) io_in
= FALSE
;
54 if ((vec_size
= m_ptr
->DIO_VEC_SIZE
) <= 0) return(EINVAL
);
57 bytes
= vec_size
* sizeof(pvb_pair_t
);
58 io_size
= sizeof(u8_t
);
61 bytes
= vec_size
* sizeof(pvw_pair_t
);
62 io_size
= sizeof(u16_t
);
65 bytes
= vec_size
* sizeof(pvl_pair_t
);
66 io_size
= sizeof(u32_t
);
68 default: return(EINVAL
); /* check type once and for all */
70 if (bytes
> sizeof(vdevio_buf
)) return(E2BIG
);
72 /* Calculate physical addresses and copy (port,value)-pairs from user. */
73 caller_vir
= (vir_bytes
) m_ptr
->DIO_VEC_ADDR
;
74 caller_phys
= umap_local(proc_addr(who_p
), D
, caller_vir
, bytes
);
75 if (0 == caller_phys
) return(EFAULT
);
76 phys_copy(caller_phys
, vir2phys(vdevio_buf
), (phys_bytes
) bytes
);
80 if (privp
&& (privp
->s_flags
& CHECK_IO_PORT
))
82 /* Check whether the I/O is allowed */
83 nr_io_range
= privp
->s_nr_io_range
;
84 for (i
=0; i
<vec_size
; i
++)
87 case _DIO_BYTE
: port
= pvb
[i
].port
; break;
88 case _DIO_WORD
: port
= pvw
[i
].port
; break;
89 default: port
= pvl
[i
].port
; break;
91 for (j
= 0, iorp
= privp
->s_io_tab
; j
<nr_io_range
; j
++, iorp
++)
93 if (port
>= iorp
->ior_base
&&
94 port
+io_size
-1 <= iorp
->ior_limit
)
102 "do_vdevio: I/O port check failed for proc %d, port 0x%x\n",
103 m_ptr
->m_source
, port
);
109 /* Perform actual device I/O for byte, word, and long values. Note that
110 * the entire switch is wrapped in lock() and unlock() to prevent the I/O
111 * batch from being interrupted.
113 lock(13, "do_vdevio");
115 case _DIO_BYTE
: /* byte values */
116 if (io_in
) for (i
=0; i
<vec_size
; i
++)
117 pvb
[i
].value
= inb( pvb
[i
].port
);
118 else for (i
=0; i
<vec_size
; i
++)
119 outb( pvb
[i
].port
, pvb
[i
].value
);
121 case _DIO_WORD
: /* word values */
122 if (io_in
) for (i
=0; i
<vec_size
; i
++)
123 pvw
[i
].value
= inw( pvw
[i
].port
);
124 else for (i
=0; i
<vec_size
; i
++)
125 outw( pvw
[i
].port
, pvw
[i
].value
);
127 default: /* long values */
128 if (io_in
) for (i
=0; i
<vec_size
; i
++)
129 pvl
[i
].value
= inl(pvl
[i
].port
);
130 else for (i
=0; i
<vec_size
; i
++)
131 outl( pvb
[i
].port
, pvl
[i
].value
);
135 /* Almost done, copy back results for input requests. */
136 if (io_in
) phys_copy(vir2phys(vdevio_buf
), caller_phys
, (phys_bytes
) bytes
);
140 #endif /* USE_VDEVIO */