ash: default to an editing mode
[minix.git] / kernel / system / do_vdevio.c
blob8292e129518d17dc0fec77c3f5935cc1a251e8a0
1 /* The kernel call implemented in this file:
2 * m_type: SYS_VDEVIO
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)
8 */
10 #include "kernel/system.h"
11 #include <minix/devio.h>
12 #include <minix/endpoint.h>
13 #include <minix/portio.h>
15 #if USE_VDEVIO
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 /*===========================================================================*
24 * do_vdevio *
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.
33 */
34 int vec_size; /* size of vector */
35 int io_in; /* true if input */
36 size_t bytes; /* # bytes to be copied */
37 port_t port;
38 int i, j, io_size, nr_io_range;
39 int io_dir, io_type;
40 struct priv *privp;
41 struct io_range *iorp;
42 int r;
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;
49 else return(EINVAL);
50 if ((vec_size = m_ptr->DIO_VEC_SIZE) <= 0) return(EINVAL);
51 switch (io_type) {
52 case _DIO_BYTE:
53 bytes = vec_size * sizeof(pvb_pair_t);
54 io_size= sizeof(u8_t);
55 break;
56 case _DIO_WORD:
57 bytes = vec_size * sizeof(pvw_pair_t);
58 io_size= sizeof(u16_t);
59 break;
60 case _DIO_LONG:
61 bytes = vec_size * sizeof(pvl_pair_t);
62 io_size= sizeof(u32_t);
63 break;
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)
71 return r;
73 privp= priv(caller);
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++)
80 switch (io_type) {
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)
90 break;
93 if (j >= nr_io_range)
95 printf(
96 "do_vdevio: I/O port check failed for proc %d, port 0x%x\n",
97 caller->p_endpoint, port);
98 return EPERM;
103 /* Perform actual device I/O for byte, word, and long values */
104 switch (io_type) {
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);
110 break;
111 case _DIO_WORD: /* word values */
112 if (io_in)
114 for (i=0; i<vec_size; i++)
116 port= pvw[i].port;
117 if (port & 1) goto bad;
118 pvw[i].value = inw( pvw[i].port);
121 else
123 for (i=0; i<vec_size; i++)
125 port= pvw[i].port;
126 if (port & 1) goto bad;
127 outw( pvw[i].port, pvw[i].value);
130 break;
131 default: /* long values */
132 if (io_in)
134 for (i=0; i<vec_size; i++)
136 port= pvl[i].port;
137 if (port & 3) goto bad;
138 pvl[i].value = inl(pvl[i].port);
141 else
143 for (i=0; i<vec_size; i++)
145 port= pvl[i].port;
146 if (port & 3) goto bad;
147 outl( pvb[i].port, pvl[i].value);
152 /* Almost done, copy back results for input requests. */
153 if (io_in)
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)
157 return r;
158 return(OK);
160 bad:
161 panic("do_vdevio: unaligned port: %d", port);
162 return EPERM;
165 #endif /* USE_VDEVIO */