xref: /minix/minix/lib/libnetdriver/portio.c (revision e3b78ef1)
1 /*
2  * Port-based I/O routines.  These are in a separate module because most
3  * drivers will not use them, and system services are statically linked.
4  */
5 #include <minix/drivers.h>
6 #include <minix/netdriver.h>
7 #include <assert.h>
8 
9 #include "netdriver.h"
10 
11 /*
12  * Port-based I/O byte sequence copy routine.
13  */
14 static void
15 netdriver_portb(struct netdriver_data * data, size_t off, long port,
16 	size_t size, int portin)
17 {
18 	size_t chunk;
19 	unsigned int i;
20 	int r, req;
21 
22 	off = netdriver_prepare_copy(data, off, size, &i);
23 
24 	req = portin ? DIO_SAFE_INPUT_BYTE : DIO_SAFE_OUTPUT_BYTE;
25 
26 	while (size > 0) {
27 		chunk = data->iovec[i].iov_size - off;
28 		if (chunk > size)
29 			chunk = size;
30 		assert(chunk > 0);
31 
32 		if ((r = sys_sdevio(req, port, data->endpt,
33 		    (void *)data->iovec[i].iov_grant, chunk, off)) != OK)
34 			panic("netdriver: port I/O failed: %d", r);
35 
36 		i++;
37 		off = 0;
38 		size -= chunk;
39 	}
40 }
41 
42 /*
43  * Transfer bytes from hardware to a destination buffer using port-based I/O.
44  */
45 void
46 netdriver_portinb(struct netdriver_data * data, size_t off, long port,
47 	size_t size)
48 {
49 
50 	return netdriver_portb(data, off, port, size, TRUE /*portin*/);
51 }
52 
53 /*
54  * Transfer bytes from a source buffer to hardware using port-based I/O.
55  */
56 void
57 netdriver_portoutb(struct netdriver_data * data, size_t off, long port,
58 	size_t size)
59 {
60 
61 	return netdriver_portb(data, off, port, size, FALSE /*portin*/);
62 }
63 
64 /*
65  * Transfer words from hardware to a destination buffer using port-based I/O.
66  */
67 void
68 netdriver_portinw(struct netdriver_data * data, size_t off, long port,
69 	size_t size)
70 {
71 	uint8_t buf[2];
72 	uint32_t value;
73 	size_t chunk;
74 	unsigned int i;
75 	int r, odd_byte;
76 
77 	off = netdriver_prepare_copy(data, off, size, &i);
78 
79 	odd_byte = 0;
80 	while (size > 0) {
81 		chunk = data->iovec[i].iov_size - off;
82 		if (chunk > size)
83 			chunk = size;
84 		assert(chunk > 0);
85 
86 		if (odd_byte) {
87 			if ((r = sys_safecopyto(data->endpt,
88 			    data->iovec[i].iov_grant, off, (vir_bytes)&buf[1],
89 			    1)) != OK)
90 				panic("netdriver: unable to copy data: %d", r);
91 
92 			off++;
93 			size--;
94 			chunk--;
95 		}
96 
97 		odd_byte = chunk & 1;
98 		chunk -= odd_byte;
99 
100 		if (chunk > 0) {
101 			if ((r = sys_safe_insw(port, data->endpt,
102 			    data->iovec[i].iov_grant, off, chunk)) != OK)
103 				panic("netdriver: port input failed: %d", r);
104 
105 			off += chunk;
106 			size -= chunk;
107 		}
108 
109 		if (odd_byte) {
110 			if ((r = sys_inw(port, &value)) != OK)
111 				panic("netdriver: port input failed: %d", r);
112 			*(uint16_t *)buf = (uint16_t)value;
113 
114 			if ((r = sys_safecopyto(data->endpt,
115 			    data->iovec[i].iov_grant, off, (vir_bytes)&buf[0],
116 			    1)) != OK)
117 				panic("netdriver: unable to copy data: %d", r);
118 
119 			size--;
120 		}
121 
122 		i++;
123 		off = 0;
124 	}
125 }
126 
127 /*
128  * Transfer words from a source buffer to hardware using port-based I/O.
129  */
130 void
131 netdriver_portoutw(struct netdriver_data * data, size_t off, long port,
132 	size_t size)
133 {
134 	uint8_t buf[2];
135 	size_t chunk;
136 	unsigned int i;
137 	int r, odd_byte;
138 
139 	off = netdriver_prepare_copy(data, off, size, &i);
140 
141 	odd_byte = 0;
142 	while (size > 0) {
143 		chunk = data->iovec[i].iov_size - off;
144 		if (chunk > size)
145 			chunk = size;
146 		assert(chunk > 0);
147 
148 		if (odd_byte) {
149 			if ((r = sys_safecopyfrom(data->endpt,
150 			    data->iovec[i].iov_grant, off, (vir_bytes)&buf[1],
151 			    1)) != OK)
152 				panic("netdriver: unable to copy data: %d", r);
153 
154 			if ((r = sys_outw(port, *(uint16_t *)buf)) != OK)
155 				panic("netdriver: port output failed: %d", r);
156 
157 			off++;
158 			size--;
159 			chunk--;
160 		}
161 
162 		odd_byte = chunk & 1;
163 		chunk -= odd_byte;
164 
165 		if (chunk > 0) {
166 			if ((r = sys_safe_outsw(port, data->endpt,
167 			    data->iovec[i].iov_grant, off, chunk)) != OK)
168 				panic("netdriver: port output failed: %d", r);
169 
170 			off += chunk;
171 			size -= chunk;
172 		}
173 
174 		if (odd_byte) {
175 			if ((r = sys_safecopyfrom(data->endpt,
176 			    data->iovec[i].iov_grant, off, (vir_bytes)&buf[0],
177 			    1)) != OK)
178 				panic("netdriver: unable to copy data: %d", r);
179 
180 			size--;
181 		}
182 
183 		i++;
184 		off = 0;
185 	}
186 
187 	if (odd_byte) {
188 		buf[1] = 0;
189 
190 		if ((r = sys_outw(port, *(uint16_t *)buf)) != OK)
191 			panic("netdriver: port output failed: %d", r);
192 	}
193 }
194