1 /* This file contains device independent device driver interface.
2 *
3 * Changes:
4 * Jul 25, 2005 added SYS_SIG type for signals (Jorrit N. Herder)
5 * Sep 15, 2004 added SYN_ALARM type for timeouts (Jorrit N. Herder)
6 * Jul 23, 2004 removed kernel dependencies (Jorrit N. Herder)
7 * Apr 02, 1992 constructed from AT wini and floppy driver (Kees J. Bot)
8 *
9 *
10 * The drivers support the following operations (using message format m2):
11 *
12 * m_type DEVICE PROC_NR COUNT POSITION ADRRESS
13 * ----------------------------------------------------------------
14 * | DEV_OPEN | device | proc nr | | | |
15 * |------------+---------+---------+---------+---------+---------|
16 * | DEV_CLOSE | device | proc nr | | | |
17 * |------------+---------+---------+---------+---------+---------|
18 * | DEV_READ | device | proc nr | bytes | offset | buf ptr |
19 * |------------+---------+---------+---------+---------+---------|
20 * | DEV_WRITE | device | proc nr | bytes | offset | buf ptr |
21 * |------------+---------+---------+---------+---------+---------|
22 * | DEV_GATHER | device | proc nr | iov len | offset | iov ptr |
23 * |------------+---------+---------+---------+---------+---------|
24 * | DEV_SCATTER| device | proc nr | iov len | offset | iov ptr |
25 * |------------+---------+---------+---------+---------+---------|
26 * | DEV_IOCTL | device | proc nr |func code| | buf ptr |
27 * |------------+---------+---------+---------+---------+---------|
28 * | CANCEL | device | proc nr | r/w | | |
29 * |------------+---------+---------+---------+---------+---------|
30 * | HARD_STOP | | | | | |
31 * ----------------------------------------------------------------
32 *
33 * The file contains one entry point:
34 *
35 * driver_task: called by the device dependent task entry
36 */
37
38 #include "../drivers.h"
39 #include <sys/ioc_disk.h>
40 #include "driver.h"
41
42 #if (CHIP == INTEL)
43
44 #if USE_EXTRA_DMA_BUF && DMA_BUF_SIZE < 2048
45 /* A bit extra scratch for the Adaptec driver. */
46 #define BUF_EXTRA (2048 - DMA_BUF_SIZE)
47 #else
48 #define BUF_EXTRA 0
49 #endif
50
51 /* Claim space for variables. */
52 PRIVATE u8_t buffer[(unsigned) 2 * DMA_BUF_SIZE + BUF_EXTRA];
53 u8_t *tmp_buf; /* the DMA buffer eventually */
54 phys_bytes tmp_phys; /* phys address of DMA buffer */
55
56 #else /* CHIP != INTEL */
57
58 /* Claim space for variables. */
59 u8_t tmp_buf[DMA_BUF_SIZE]; /* the DMA buffer */
60 phys_bytes tmp_phys; /* phys address of DMA buffer */
61
62 #endif /* CHIP != INTEL */
63
64 FORWARD _PROTOTYPE( void init_buffer, (void) );
65 FORWARD _PROTOTYPE( int do_rdwt, (struct driver *dr, message *mp) );
66 FORWARD _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *mp) );
67
68 int device_caller;
69
70 /*===========================================================================*
71 * driver_task *
72 *===========================================================================*/
73 PUBLIC void driver_task(dp)
74 struct driver *dp; /* Device dependent entry points. */
75 {
76 /* Main program of any device driver task. */
77
78 int r, proc_nr;
79 message mess;
80
81 /* Get a DMA buffer. */
82 init_buffer();
83
84 /* Here is the main loop of the disk task. It waits for a message, carries
85 * it out, and sends a reply.
86 */
87 while (TRUE) {
88
89 /* Wait for a request to read or write a disk block. */
90 if (receive(ANY, &mess) != OK) continue;
91
92 device_caller = mess.m_source;
93 proc_nr = mess.PROC_NR;
94
95 /* Now carry out the work. */
96 switch(mess.m_type) {
97 case DEV_OPEN: r = (*dp->dr_open)(dp, &mess); break;
98 case DEV_CLOSE: r = (*dp->dr_close)(dp, &mess); break;
99 case DEV_IOCTL: r = (*dp->dr_ioctl)(dp, &mess); break;
100 case CANCEL: r = (*dp->dr_cancel)(dp, &mess);break;
101 case DEV_SELECT: r = (*dp->dr_select)(dp, &mess);break;
102 case DEV_READ:
103 case DEV_WRITE: r = do_rdwt(dp, &mess); break;
104 case DEV_GATHER:
105 case DEV_SCATTER: r = do_vrdwt(dp, &mess); break;
106
107 case HARD_INT: /* leftover interrupt or expired timer. */
108 if(dp->dr_hw_int) {
109 (*dp->dr_hw_int)(dp, &mess);
110 }
111 continue;
112 case SYS_SIG: (*dp->dr_signal)(dp, &mess);
113 continue; /* don't reply */
114 case SYN_ALARM: (*dp->dr_alarm)(dp, &mess);
115 continue; /* don't reply */
116 case DEV_PING: notify(mess.m_source);
117 continue;
118 default:
119 if(dp->dr_other)
120 r = (*dp->dr_other)(dp, &mess);
121 else
122 r = EINVAL;
123 break;
124 }
125
126 /* Clean up leftover state. */
127 (*dp->dr_cleanup)();
128
129 /* Finally, prepare and send the reply message. */
130 if (r != EDONTREPLY) {
131 mess.m_type = TASK_REPLY;
132 mess.REP_PROC_NR = proc_nr;
133 /* Status is # of bytes transferred or error code. */
134 mess.REP_STATUS = r;
135 send(device_caller, &mess);
136 }
137 }
138 }
139
140
141 /*===========================================================================*
142 * init_buffer *
143 *===========================================================================*/
144 PRIVATE void init_buffer()
145 {
146 /* Select a buffer that can safely be used for DMA transfers. It may also
147 * be used to read partition tables and such. Its absolute address is
148 * 'tmp_phys', the normal address is 'tmp_buf'.
149 */
150
151 #if (CHIP == INTEL)
152 unsigned left;
153
154 tmp_buf = buffer;
155 sys_umap(SELF, D, (vir_bytes)buffer, (phys_bytes)sizeof(buffer), &tmp_phys);
156
157 if ((left = dma_bytes_left(tmp_phys)) < DMA_BUF_SIZE) {
158 /* First half of buffer crosses a 64K boundary, can't DMA into that */
159 tmp_buf += left;
160 tmp_phys += left;
161 }
162 #endif /* CHIP == INTEL */
163 }
164
165 /*===========================================================================*
166 * do_rdwt *
167 *===========================================================================*/
168 PRIVATE int do_rdwt(dp, mp)
169 struct driver *dp; /* device dependent entry points */
170 message *mp; /* pointer to read or write message */
171 {
172 /* Carry out a single read or write request. */
173 iovec_t iovec1;
174 int r, opcode;
175 phys_bytes phys_addr;
176
177 /* Disk address? Address and length of the user buffer? */
178 if (mp->COUNT < 0) return(EINVAL);
179
180 /* Check the user buffer. */
181 sys_umap(mp->PROC_NR, D, (vir_bytes) mp->ADDRESS, mp->COUNT, &phys_addr);
182 if (phys_addr == 0) return(EFAULT);
183
184 /* Prepare for I/O. */
185 if ((*dp->dr_prepare)(mp->DEVICE) == NIL_DEV) return(ENXIO);
186
187 /* Create a one element scatter/gather vector for the buffer. */
188 opcode = mp->m_type == DEV_READ ? DEV_GATHER : DEV_SCATTER;
189 iovec1.iov_addr = (vir_bytes) mp->ADDRESS;
190 iovec1.iov_size = mp->COUNT;
191
192 /* Transfer bytes from/to the device. */
193 r = (*dp->dr_transfer)(mp->PROC_NR, opcode, mp->POSITION, &iovec1, 1);
194
195 /* Return the number of bytes transferred or an error code. */
196 return(r == OK ? (mp->COUNT - iovec1.iov_size) : r);
197 }
198
199 /*==========================================================================*
200 * do_vrdwt *
201 *==========================================================================*/
202 PRIVATE int do_vrdwt(dp, mp)
203 struct driver *dp; /* device dependent entry points */
204 message *mp; /* pointer to read or write message */
205 {
206 /* Carry out an device read or write to/from a vector of user addresses.
207 * The "user addresses" are assumed to be safe, i.e. FS transferring to/from
208 * its own buffers, so they are not checked.
209 */
210 static iovec_t iovec[NR_IOREQS];
211 iovec_t *iov;
212 phys_bytes iovec_size;
213 unsigned nr_req;
214 int r;
215
216 nr_req = mp->COUNT; /* Length of I/O vector */
217
218 if (mp->m_source < 0) {
219 /* Called by a task, no need to copy vector. */
220 iov = (iovec_t *) mp->ADDRESS;
221 } else {
222 /* Copy the vector from the caller to kernel space. */
223 if (nr_req > NR_IOREQS) nr_req = NR_IOREQS;
224 iovec_size = (phys_bytes) (nr_req * sizeof(iovec[0]));
225
226 if (OK != sys_datacopy(mp->m_source, (vir_bytes) mp->ADDRESS,
227 SELF, (vir_bytes) iovec, iovec_size))
228 panic((*dp->dr_name)(),"bad I/O vector by", mp->m_source);
229 iov = iovec;
230 }
231
232 /* Prepare for I/O. */
233 if ((*dp->dr_prepare)(mp->DEVICE) == NIL_DEV) return(ENXIO);
234
235 /* Transfer bytes from/to the device. */
236 r = (*dp->dr_transfer)(mp->PROC_NR, mp->m_type, mp->POSITION, iov, nr_req);
237
238 /* Copy the I/O vector back to the caller. */
239 if (mp->m_source >= 0) {
240 sys_datacopy(SELF, (vir_bytes) iovec,
241 mp->m_source, (vir_bytes) mp->ADDRESS, iovec_size);
242 }
243 return(r);
244 }
245
246 /*===========================================================================*
247 * no_name *
248 *===========================================================================*/
249 PUBLIC char *no_name()
250 {
251 /* Use this default name if there is no specific name for the device. This was
252 * originally done by fetching the name from the task table for this process:
253 * "return(tasktab[proc_number(proc_ptr) + NR_TASKS].name);", but currently a
254 * real "noname" is returned. Perhaps, some system information service can be
255 * queried for a name at a later time.
256 */
257 static char name[] = "noname";
258 return name;
259 }
260
261 /*============================================================================*
262 * do_nop *
263 *============================================================================*/
264 PUBLIC int do_nop(dp, mp)
265 struct driver *dp;
266 message *mp;
267 {
268 /* Nothing there, or nothing to do. */
269
270 switch (mp->m_type) {
271 case DEV_OPEN: return(ENODEV);
272 case DEV_CLOSE: return(OK);
273 case DEV_IOCTL: return(ENOTTY);
274 default: return(EIO);
275 }
276 }
277
278 /*============================================================================*
279 * nop_signal *
280 *============================================================================*/
281 PUBLIC void nop_signal(dp, mp)
282 struct driver *dp;
283 message *mp;
284 {
285 /* Default action for signal is to ignore. */
286 }
287
288 /*============================================================================*
289 * nop_alarm *
290 *============================================================================*/
291 PUBLIC void nop_alarm(dp, mp)
292 struct driver *dp;
293 message *mp;
294 {
295 /* Ignore the leftover alarm. */
296 }
297
298 /*===========================================================================*
299 * nop_prepare *
300 *===========================================================================*/
301 PUBLIC struct device *nop_prepare(device)
302 {
303 /* Nothing to prepare for. */
304 return(NIL_DEV);
305 }
306
307 /*===========================================================================*
308 * nop_cleanup *
309 *===========================================================================*/
310 PUBLIC void nop_cleanup()
311 {
312 /* Nothing to clean up. */
313 }
314
315 /*===========================================================================*
316 * nop_cancel *
317 *===========================================================================*/
318 PUBLIC int nop_cancel(struct driver *dr, message *m)
319 {
320 /* Nothing to do for cancel. */
321 return(OK);
322 }
323
324 /*===========================================================================*
325 * nop_select *
326 *===========================================================================*/
327 PUBLIC int nop_select(struct driver *dr, message *m)
328 {
329 /* Nothing to do for select. */
330 return(OK);
331 }
332
333 /*============================================================================*
334 * do_diocntl *
335 *============================================================================*/
336 PUBLIC int do_diocntl(dp, mp)
337 struct driver *dp;
338 message *mp; /* pointer to ioctl request */
339 {
340 /* Carry out a partition setting/getting request. */
341 struct device *dv;
342 struct partition entry;
343 int s;
344
345 if (mp->REQUEST != DIOCSETP && mp->REQUEST != DIOCGETP) {
346 if(dp->dr_other) {
347 return dp->dr_other(dp, mp);
348 } else return(ENOTTY);
349 }
350
351 /* Decode the message parameters. */
352 if ((dv = (*dp->dr_prepare)(mp->DEVICE)) == NIL_DEV) return(ENXIO);
353
354 if (mp->REQUEST == DIOCSETP) {
355 /* Copy just this one partition table entry. */
356 if (OK != (s=sys_datacopy(mp->PROC_NR, (vir_bytes) mp->ADDRESS,
357 SELF, (vir_bytes) &entry, sizeof(entry))))
358 return s;
359 dv->dv_base = entry.base;
360 dv->dv_size = entry.size;
361 } else {
362 /* Return a partition table entry and the geometry of the drive. */
363 entry.base = dv->dv_base;
364 entry.size = dv->dv_size;
365 (*dp->dr_geometry)(&entry);
366 if (OK != (s=sys_datacopy(SELF, (vir_bytes) &entry,
367 mp->PROC_NR, (vir_bytes) mp->ADDRESS, sizeof(entry))))
368 return s;
369 }
370 return(OK);
371 }
Cache object: 692dc8a553541265270185ff63711368
|