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
netdriver_portb(struct netdriver_data * data,size_t off,long port,size_t size,int portin)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
netdriver_portinb(struct netdriver_data * data,size_t off,long port,size_t size)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
netdriver_portoutb(struct netdriver_data * data,size_t off,long port,size_t size)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
netdriver_portinw(struct netdriver_data * data,size_t off,long port,size_t size)68 netdriver_portinw(struct netdriver_data * data, size_t off, long port,
69 size_t size)
70 {
71 uint16_t buf;
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,
89 (vir_bytes)&((char *)&buf)[1], 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 buf = (uint16_t)value;
113
114 if ((r = sys_safecopyto(data->endpt,
115 data->iovec[i].iov_grant, off,
116 (vir_bytes)&((char *)&buf)[0], 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
netdriver_portoutw(struct netdriver_data * data,size_t off,long port,size_t size)131 netdriver_portoutw(struct netdriver_data * data, size_t off, long port,
132 size_t size)
133 {
134 uint16_t buf;
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,
151 (vir_bytes)&((char *)&buf)[1], 1)) != OK)
152 panic("netdriver: unable to copy data: %d", r);
153
154 if ((r = sys_outw(port, 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,
177 (vir_bytes)&((char *)&buf)[0], 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 ((char *)&buf)[1] = 0;
189
190 if ((r = sys_outw(port, buf)) != OK)
191 panic("netdriver: port output failed: %d", r);
192 }
193 }
194