fd.c revision 1.2 1 1.1 chopps /*
2 1.1 chopps * Copyright (c) 1994 Brad Pepers
3 1.1 chopps * All rights reserved.
4 1.1 chopps *
5 1.1 chopps * This code is derived from software contributed to Berkeley by
6 1.1 chopps * Brad Pepers.
7 1.1 chopps *
8 1.1 chopps * Redistribution and use in source and binary forms, with or without
9 1.1 chopps * modification, are permitted provided that the following conditions
10 1.1 chopps * are met:
11 1.1 chopps * 1. Redistributions of source code must retain the above copyright
12 1.1 chopps * notice, this list of conditions and the following disclaimer.
13 1.1 chopps * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 chopps * notice, this list of conditions and the following disclaimer in the
15 1.1 chopps * documentation and/or other materials provided with the distribution.
16 1.1 chopps * 3. All advertising materials mentioning features or use of this software
17 1.1 chopps * must display the following acknowledgement:
18 1.1 chopps * This product includes software developed by the University of
19 1.1 chopps * California, Berkeley and its contributors.
20 1.1 chopps * 4. Neither the name of the University nor the names of its contributors
21 1.1 chopps * may be used to endorse or promote products derived from this software
22 1.1 chopps * without specific prior written permission.
23 1.1 chopps *
24 1.1 chopps * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 1.1 chopps * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 chopps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 chopps * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 1.1 chopps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 chopps * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 chopps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 chopps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 chopps * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 chopps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 chopps * SUCH DAMAGE.
35 1.1 chopps *
36 1.1 chopps */
37 1.1 chopps
38 1.1 chopps /*
39 1.1 chopps * floppy interface
40 1.1 chopps */
41 1.1 chopps
42 1.1 chopps #include "fd.h"
43 1.1 chopps #if NFD > 0
44 1.1 chopps
45 1.1 chopps #include <sys/param.h>
46 1.1 chopps #include <sys/systm.h>
47 1.1 chopps #include <sys/buf.h>
48 1.1 chopps #include <sys/dkstat.h>
49 1.1 chopps #include <sys/disklabel.h>
50 1.1 chopps #include <sys/malloc.h>
51 1.1 chopps #include <sys/proc.h>
52 1.1 chopps #include <sys/reboot.h>
53 1.1 chopps #include <sys/file.h>
54 1.1 chopps #include <sys/ioctl.h>
55 1.1 chopps
56 1.1 chopps #include <amiga/dev/device.h>
57 1.1 chopps #include <amiga/amiga/cia.h>
58 1.1 chopps #include <amiga/amiga/custom.h>
59 1.1 chopps
60 1.1 chopps #define UNIT(x) (minor(x) & 3)
61 1.1 chopps #define b_cylin b_resid
62 1.1 chopps #define FDBLK 512
63 1.1 chopps #define MAX_SECTS 22
64 1.1 chopps #define IMMED_WRITE 0
65 1.1 chopps
66 1.1 chopps int fdattach();
67 1.1 chopps struct driver fddriver = {
68 1.1 chopps fdattach, "fd",
69 1.1 chopps };
70 1.1 chopps
71 1.1 chopps /* defines */
72 1.1 chopps #define MFM_SYNC 0x4489
73 1.1 chopps #define DSKLEN_DMAEN (1<<15)
74 1.1 chopps #define DSKLEN_WRITE (1<<14)
75 1.1 chopps
76 1.1 chopps /* drive type values */
77 1.1 chopps #define FD_NONE 0x00000000
78 1.1 chopps #define FD_DD_3 0xffffffff /* double-density 3.5" (880K) */
79 1.1 chopps #define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) */
80 1.1 chopps
81 1.1 chopps struct fd_type {
82 1.1 chopps int id;
83 1.1 chopps char *name;
84 1.1 chopps int tracks;
85 1.1 chopps int heads;
86 1.1 chopps int read_size;
87 1.1 chopps int write_size;
88 1.1 chopps int sect_mult;
89 1.1 chopps int precomp1;
90 1.1 chopps int precomp2;
91 1.1 chopps int step_delay;
92 1.1 chopps int side_time;
93 1.1 chopps int settle_time;
94 1.1 chopps };
95 1.1 chopps
96 1.1 chopps struct fd_type drive_types[] = {
97 1.1 chopps /* id name tr he rdsz wrsz sm pc1 pc2 sd st st */
98 1.1 chopps { FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80, 161, 3, 18, 1 },
99 1.1 chopps { FD_HD_3, "HD 3.5", 80, 2, 29432, 27260, 2, 80, 161, 3, 18, 1 },
100 1.1 chopps { FD_NONE, "No Drive", 0, }
101 1.1 chopps };
102 1.1 chopps int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
103 1.1 chopps
104 1.1 chopps /*
105 1.1 chopps * Per drive structure.
106 1.1 chopps * N per controller (presently 4) (DRVS_PER_CTLR)
107 1.1 chopps */
108 1.1 chopps #define DRVS_PER_CTLR 4
109 1.1 chopps struct fd_data {
110 1.1 chopps int fdu; /* This unit number */
111 1.1 chopps struct buf head; /* Head of buf chain */
112 1.1 chopps struct buf rhead; /* Raw head of buf chain */
113 1.1 chopps int type; /* Drive type */
114 1.1 chopps struct fd_type *ft; /* Pointer to type descriptor */
115 1.1 chopps int flags;
116 1.1 chopps #define FDF_OPEN 0x01 /* it's open */
117 1.1 chopps int skip;
118 1.1 chopps int sects; /* number of sectors in a track */
119 1.1 chopps int size; /* size of disk in sectors */
120 1.1 chopps int side; /* current side disk is on */
121 1.1 chopps int dir; /* current direction of stepping */
122 1.1 chopps int cyl; /* current cylinder disk is on */
123 1.1 chopps int buf_track;
124 1.1 chopps int buf_dirty;
125 1.1 chopps char *buf_data;
126 1.1 chopps char *buf_labels;
127 1.1 chopps int write_cnt;
128 1.1 chopps };
129 1.1 chopps
130 1.1 chopps /*
131 1.1 chopps * Per controller structure.
132 1.1 chopps */
133 1.1 chopps struct fdc_data
134 1.1 chopps {
135 1.1 chopps int fdcu; /* our unit number */
136 1.1 chopps struct fd_data *fd; /* drive we are currently doing work for */
137 1.1 chopps int motor_fdu; /* drive that has its motor on */
138 1.1 chopps int state;
139 1.1 chopps int saved;
140 1.1 chopps int retry;
141 1.1 chopps struct fd_data fd_data[DRVS_PER_CTLR];
142 1.1 chopps };
143 1.1 chopps struct fdc_data fdc_data[NFD];
144 1.1 chopps
145 1.1 chopps /*
146 1.1 chopps * Throughout this file the following conventions will be used:
147 1.1 chopps *
148 1.1 chopps * fd is a pointer to the fd_data struct for the drive in question
149 1.1 chopps * fdc is a pointer to the fdc_data struct for the controller
150 1.1 chopps * fdu is the floppy drive unit number
151 1.1 chopps * fdcu is the floppy controller unit number
152 1.1 chopps * fdsu is the floppy drive unit number on that controller. (sub-unit)
153 1.1 chopps */
154 1.1 chopps typedef int fdu_t;
155 1.1 chopps typedef int fdcu_t;
156 1.1 chopps typedef int fdsu_t;
157 1.1 chopps typedef struct fd_data *fd_p;
158 1.1 chopps typedef struct fdc_data *fdc_p;
159 1.1 chopps
160 1.1 chopps /*
161 1.1 chopps * protos.
162 1.1 chopps */
163 1.1 chopps static int delay __P((int));
164 1.1 chopps void encode __P((u_long, u_long *, u_long *));
165 1.1 chopps void fd_step __P((void));
166 1.1 chopps void fd_seek __P((fd_p, int));
167 1.1 chopps void correct __P((u_long *));
168 1.1 chopps void fd_probe __P((fd_p));
169 1.1 chopps void fd_turnon __P((fdc_p, fdu_t));
170 1.1 chopps void fd_turnoff __P((fdc_p));
171 1.1 chopps void track_read __P((fdc_p, fd_p, int));
172 1.1 chopps void fd_timeout __P((fdc_p));
173 1.1 chopps void fd_motor_to __P((fdcu_t));
174 1.1 chopps void fd_motor_on __P((fdc_p, fdu_t));
175 1.1 chopps void track_write __P((fdc_p, fd_p));
176 1.1 chopps void amiga_write __P((fd_p));
177 1.1 chopps void fd_calibrate __P((fd_p));
178 1.1 chopps void encode_block __P((u_long *, u_char *, int, u_long *));
179 1.1 chopps void fd_select_dir __P((fd_p, int));
180 1.1 chopps void fd_pseudointr __P((fdc_p));
181 1.1 chopps void fd_select_side __P((fd_p, int));
182 1.1 chopps
183 1.1 chopps u_long scan_sync __P((u_long, u_long, int));
184 1.1 chopps u_long encode_long __P((u_long, u_long *));
185 1.1 chopps u_long loop_read_id __P((int));
186 1.1 chopps u_long get_drive_id __P((int));
187 1.1 chopps
188 1.1 chopps int fdstate __P((fdc_p));
189 1.1 chopps int retrier __P((fdc_p));
190 1.1 chopps int amiga_read __P((fd_p));
191 1.1 chopps int get_drive_type __P((u_long));
192 1.1 chopps
193 1.1 chopps /* device routines */
194 1.1 chopps int Fdopen __P((dev_t, int));
195 1.1 chopps int fdsize __P((dev_t));
196 1.1 chopps int fdioctl __P((dev_t, int, caddr_t, int, struct proc *));
197 1.1 chopps int fdclose __P((dev_t, int));
198 1.1 chopps int fdattach __P((struct amiga_device *));
199 1.1 chopps
200 1.1 chopps void fdintr __P((fdcu_t));
201 1.1 chopps void fdstart __P((fdc_p));
202 1.1 chopps void fdstrategy __P((struct buf *bp));
203 1.1 chopps
204 1.1 chopps #define DEVIDLE 0
205 1.1 chopps #define FINDWORK 1
206 1.1 chopps #define DOSEEK 2
207 1.1 chopps #define DO_IO 3
208 1.1 chopps #define DONE_IO 4
209 1.1 chopps #define WAIT_READ 5
210 1.1 chopps #define WAIT_WRITE 6
211 1.1 chopps #define DELAY_WRITE 7
212 1.1 chopps #define RECALCOMPLETE 8
213 1.1 chopps #define STARTRECAL 9
214 1.1 chopps #define RESETCTLR 10
215 1.1 chopps #define SEEKWAIT 11
216 1.1 chopps #define RECALWAIT 12
217 1.1 chopps #define MOTORWAIT 13
218 1.1 chopps
219 1.1 chopps #undef DEBUG
220 1.1 chopps
221 1.1 chopps #ifdef DEBUG
222 1.1 chopps
223 1.1 chopps char *fdstates[] =
224 1.1 chopps {
225 1.1 chopps "DEVIDLE",
226 1.1 chopps "FINDWORK",
227 1.1 chopps "DOSEEK",
228 1.1 chopps "DO_IO",
229 1.1 chopps "DONE_IO",
230 1.1 chopps "WAIT_READ",
231 1.1 chopps "WAIT_WRITE",
232 1.1 chopps "DELAY_WRITE",
233 1.1 chopps "RECALCOMPLETE",
234 1.1 chopps "STARTRECAL",
235 1.1 chopps "RESETCTLR",
236 1.1 chopps "SEEKWAIT",
237 1.1 chopps "RECALWAIT",
238 1.1 chopps "MOTORWAIT",
239 1.1 chopps };
240 1.1 chopps
241 1.1 chopps #define TRACE0(arg) if (fd_debug == 1) printf(arg)
242 1.1 chopps #define TRACE1(arg1,arg2) if (fd_debug == 1) printf(arg1,arg2)
243 1.1 chopps
244 1.1 chopps #else /* !DEBUG */
245 1.1 chopps
246 1.1 chopps #define TRACE0(arg)
247 1.1 chopps #define TRACE1(arg1,arg2)
248 1.1 chopps
249 1.1 chopps #endif /* !DEBUG */
250 1.1 chopps
251 1.1 chopps extern int hz;
252 1.1 chopps
253 1.1 chopps unsigned char *raw_buf = NULL;
254 1.1 chopps #ifdef DEBUG
255 1.1 chopps int fd_debug = 1;
256 1.1 chopps #else
257 1.1 chopps int fd_debug = 0;
258 1.1 chopps #endif
259 1.1 chopps
260 1.1 chopps /*
261 1.1 chopps * Floppy Support Routines
262 1.1 chopps */
263 1.1 chopps #define MOTOR_ON (ciab.prb &= ~CIAB_PRB_MTR)
264 1.1 chopps #define MOTOR_OFF (ciab.prb |= CIAB_PRB_MTR)
265 1.1 chopps #define SELECT(mask) (ciab.prb &= ~mask)
266 1.1 chopps #define DESELECT(mask) (ciab.prb |= mask)
267 1.1 chopps #define SELMASK(drive) (1 << (3 + (drive & 3)))
268 1.1 chopps
269 1.1 chopps /*
270 1.1 chopps * Delay for a number of milliseconds
271 1.1 chopps * - tried ciab.tod but seems to miss values and screw up
272 1.1 chopps * - stupid busy loop for now
273 1.1 chopps */
274 1.1 chopps static int
275 1.1 chopps delay(delay_ms)
276 1.1 chopps int delay_ms;
277 1.1 chopps {
278 1.1 chopps long cnt, inner;
279 1.1 chopps int val;
280 1.1 chopps
281 1.1 chopps for (cnt = 0; cnt < delay_ms; cnt++)
282 1.1 chopps for (inner = 0; inner < 500; inner++)
283 1.1 chopps val += inner * cnt;
284 1.1 chopps return(val);
285 1.1 chopps }
286 1.1 chopps
287 1.1 chopps /*
288 1.1 chopps * motor control stuff
289 1.1 chopps */
290 1.1 chopps void
291 1.1 chopps fd_motor_to(fdcu)
292 1.1 chopps fdcu_t fdcu;
293 1.1 chopps {
294 1.1 chopps printf("timeout starting motor\n"); /* XXXX */
295 1.1 chopps fdc_data[fdcu].motor_fdu = -2;
296 1.1 chopps }
297 1.1 chopps
298 1.1 chopps void
299 1.1 chopps fd_motor_on(fdc, fdu)
300 1.1 chopps fdc_p fdc;
301 1.1 chopps fdu_t fdu;
302 1.1 chopps {
303 1.1 chopps int i;
304 1.1 chopps int cnt; /* XXXX not used? */
305 1.1 chopps
306 1.1 chopps cnt = 0; /* XXXX not used? */
307 1.1 chopps
308 1.1 chopps /* deselect all drives */
309 1.1 chopps for (i = 0; i < DRVS_PER_CTLR; i++)
310 1.1 chopps DESELECT(SELMASK(i));
311 1.1 chopps
312 1.1 chopps /* turn on the unit's motor */
313 1.1 chopps MOTOR_ON;
314 1.1 chopps SELECT(SELMASK(fdu));
315 1.1 chopps
316 1.1 chopps timeout((timeout_t)fd_motor_to, (caddr_t)fdc->fdcu, hz);
317 1.1 chopps while (ciaa.pra & CIAA_PRA_RDY)
318 1.1 chopps ;
319 1.1 chopps untimeout((timeout_t)fd_motor_to, (caddr_t)fdc->fdcu);
320 1.1 chopps fdc->motor_fdu = fdu;
321 1.1 chopps }
322 1.1 chopps
323 1.1 chopps void
324 1.1 chopps fd_turnoff(fdc)
325 1.1 chopps fdc_p fdc;
326 1.1 chopps {
327 1.1 chopps int i;
328 1.1 chopps
329 1.1 chopps if (fdc->motor_fdu != -1) {
330 1.1 chopps /* deselect all drives */
331 1.1 chopps for (i = 0; i < DRVS_PER_CTLR; i++)
332 1.1 chopps DESELECT(SELMASK(i));
333 1.1 chopps
334 1.1 chopps /* turn off the unit's motor */
335 1.1 chopps MOTOR_OFF;
336 1.1 chopps SELECT(SELMASK(fdc->motor_fdu));
337 1.1 chopps MOTOR_ON;
338 1.1 chopps DESELECT(SELMASK(fdc->motor_fdu));
339 1.1 chopps }
340 1.1 chopps
341 1.1 chopps fdc->motor_fdu = -1;
342 1.1 chopps }
343 1.1 chopps
344 1.1 chopps void
345 1.1 chopps fd_turnon(fdc, fdu)
346 1.1 chopps fdc_p fdc;
347 1.1 chopps fdu_t fdu;
348 1.1 chopps {
349 1.1 chopps if (fdc->motor_fdu == fdu)
350 1.1 chopps return;
351 1.1 chopps
352 1.1 chopps fd_turnoff(fdc);
353 1.1 chopps fd_motor_on(fdc, fdu);
354 1.1 chopps }
355 1.1 chopps
356 1.1 chopps /*
357 1.1 chopps * Step the drive once in its current direction
358 1.1 chopps */
359 1.1 chopps void
360 1.1 chopps fd_step()
361 1.1 chopps {
362 1.1 chopps ciab.prb &= ~CIAB_PRB_STEP;
363 1.1 chopps ciab.prb |= CIAB_PRB_STEP;
364 1.1 chopps }
365 1.1 chopps
366 1.1 chopps /*
367 1.1 chopps * Select the side to use for a particular drive.
368 1.1 chopps * The drive must have been calibrated at some point before this.
369 1.1 chopps * The drive must also be active and the motor must be running.
370 1.1 chopps */
371 1.1 chopps void
372 1.1 chopps fd_select_side(fd, side)
373 1.1 chopps fd_p fd;
374 1.1 chopps int side;
375 1.1 chopps {
376 1.1 chopps if (fd->side == side)
377 1.1 chopps return;
378 1.1 chopps
379 1.1 chopps /* select the requested side */
380 1.1 chopps if (side == 0)
381 1.1 chopps ciab.prb &= ~CIAB_PRB_SIDE;
382 1.1 chopps else
383 1.1 chopps ciab.prb |= CIAB_PRB_SIDE;
384 1.1 chopps delay(fd->ft->side_time);
385 1.1 chopps fd->side = side;
386 1.1 chopps }
387 1.1 chopps
388 1.1 chopps /*
389 1.1 chopps * Select the direction to use for the current particular drive.
390 1.1 chopps */
391 1.1 chopps void
392 1.1 chopps fd_select_dir(fd, dir)
393 1.1 chopps fd_p fd;
394 1.1 chopps int dir;
395 1.1 chopps {
396 1.1 chopps if (fd->dir == dir)
397 1.1 chopps return;
398 1.1 chopps
399 1.1 chopps /* select the requested direction */
400 1.1 chopps if (dir == 0)
401 1.1 chopps ciab.prb &= ~CIAB_PRB_DIR;
402 1.1 chopps else
403 1.1 chopps ciab.prb |= CIAB_PRB_DIR;
404 1.1 chopps delay(fd->ft->settle_time);
405 1.1 chopps fd->dir = dir;
406 1.1 chopps }
407 1.1 chopps
408 1.1 chopps /*
409 1.1 chopps * Seek the drive to track 0.
410 1.1 chopps * The drive must be active and the motor must be running.
411 1.1 chopps * Returns standard floppy error code. /* XXXX doesn't return anything
412 1.1 chopps */
413 1.1 chopps void
414 1.1 chopps fd_calibrate(fd)
415 1.1 chopps fd_p fd;
416 1.1 chopps {
417 1.1 chopps fd_select_dir(fd, 1);
418 1.1 chopps
419 1.1 chopps /* loop until we hit track 0 */
420 1.1 chopps while (ciaa.pra & CIAA_PRA_TK0) {
421 1.1 chopps fd_step();
422 1.1 chopps delay(4);
423 1.1 chopps }
424 1.1 chopps
425 1.1 chopps /* set known values */
426 1.1 chopps fd->cyl = 0;
427 1.1 chopps }
428 1.1 chopps
429 1.1 chopps /*
430 1.1 chopps * Seek the drive to the requested track.
431 1.1 chopps * The drive must be active and the motor must be running.
432 1.1 chopps */
433 1.1 chopps void
434 1.1 chopps fd_seek(fd, track)
435 1.1 chopps fd_p fd;
436 1.1 chopps int track;
437 1.1 chopps {
438 1.1 chopps int cyl, side;
439 1.1 chopps int dir, cnt;
440 1.1 chopps int delay_time;
441 1.1 chopps
442 1.1 chopps cyl = track >> 1;
443 1.1 chopps side = (track % 2) ^ 1;
444 1.1 chopps
445 1.1 chopps if (fd->cyl == -1)
446 1.1 chopps fd_calibrate(fd);
447 1.1 chopps
448 1.1 chopps fd_select_side(fd, side);
449 1.1 chopps
450 1.1 chopps if (cyl < fd->cyl) {
451 1.1 chopps dir = 1;
452 1.1 chopps cnt = fd->cyl - cyl;
453 1.1 chopps } else {
454 1.1 chopps dir = 0;
455 1.1 chopps cnt = cyl - fd->cyl;
456 1.1 chopps }
457 1.1 chopps
458 1.1 chopps fd_select_dir(fd, dir);
459 1.1 chopps
460 1.1 chopps if (cnt) {
461 1.1 chopps while (cnt) {
462 1.1 chopps delay_time = fd->ft->step_delay;
463 1.1 chopps if (dir != fd->dir)
464 1.1 chopps delay_time += fd->ft->settle_time;
465 1.1 chopps fd_step();
466 1.1 chopps delay(delay_time);
467 1.1 chopps --cnt;
468 1.1 chopps }
469 1.1 chopps delay(fd->ft->settle_time);
470 1.1 chopps }
471 1.1 chopps
472 1.1 chopps fd->cyl = cyl;
473 1.1 chopps }
474 1.1 chopps
475 1.1 chopps void
476 1.1 chopps encode(data, dest, csum)
477 1.1 chopps u_long data;
478 1.1 chopps u_long *dest, *csum;
479 1.1 chopps {
480 1.1 chopps u_long data2;
481 1.1 chopps
482 1.1 chopps data &= 0x55555555;
483 1.1 chopps data2 = data ^ 0x55555555;
484 1.1 chopps data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
485 1.1 chopps
486 1.1 chopps if (*(dest - 1) & 0x00000001)
487 1.1 chopps data &= 0x7FFFFFFF;
488 1.1 chopps
489 1.1 chopps *csum ^= data;
490 1.1 chopps *dest = data;
491 1.1 chopps }
492 1.1 chopps
493 1.1 chopps u_long
494 1.1 chopps encode_long(data, dest)
495 1.1 chopps u_long data;
496 1.1 chopps u_long *dest;
497 1.1 chopps {
498 1.1 chopps u_long csum;
499 1.1 chopps
500 1.1 chopps csum = 0;
501 1.1 chopps
502 1.1 chopps encode(data >> 1, dest, &csum);
503 1.1 chopps encode(data, dest + 1, &csum);
504 1.1 chopps
505 1.1 chopps return(csum & 0x55555555);
506 1.1 chopps }
507 1.1 chopps
508 1.1 chopps void
509 1.1 chopps encode_block(dest, from, len, csum)
510 1.1 chopps u_long *dest, *csum;
511 1.1 chopps u_char *from;
512 1.1 chopps int len;
513 1.1 chopps {
514 1.1 chopps int cnt, to_cnt = 0;
515 1.1 chopps u_long data, *src;
516 1.1 chopps
517 1.1 chopps to_cnt = 0;
518 1.1 chopps src = (u_long *)from;
519 1.1 chopps
520 1.1 chopps /* odd bits */
521 1.1 chopps for (cnt = 0; cnt < len / 4; cnt++) {
522 1.1 chopps data = src[cnt] >> 1;
523 1.1 chopps encode(data, dest + to_cnt++, csum);
524 1.1 chopps }
525 1.1 chopps
526 1.1 chopps /* even bits */
527 1.1 chopps for (cnt = 0; cnt < len / 4; cnt++) {
528 1.1 chopps data = src[cnt];
529 1.1 chopps encode(data, dest + to_cnt++, csum);
530 1.1 chopps }
531 1.1 chopps
532 1.1 chopps *csum &= 0x55555555;
533 1.1 chopps }
534 1.1 chopps
535 1.1 chopps void
536 1.1 chopps correct(raw)
537 1.1 chopps u_long *raw;
538 1.1 chopps {
539 1.1 chopps u_char data, *ptr;
540 1.1 chopps
541 1.1 chopps ptr = (u_char *)raw;
542 1.1 chopps
543 1.1 chopps data = *ptr;
544 1.1 chopps if (*(ptr - 1) & 0x01) { /* XXXX will choke on old GVP's */
545 1.1 chopps *ptr = data & 0x7f;
546 1.1 chopps return;
547 1.1 chopps }
548 1.1 chopps
549 1.1 chopps if (data & 0x40)
550 1.1 chopps return;
551 1.1 chopps
552 1.1 chopps *ptr |= 0x80;
553 1.1 chopps }
554 1.1 chopps
555 1.1 chopps /*
556 1.1 chopps * amiga_write converts track/labels data to raw track data
557 1.1 chopps */
558 1.1 chopps void
559 1.1 chopps amiga_write(fd)
560 1.1 chopps fd_p fd;
561 1.1 chopps {
562 1.1 chopps u_long *raw, csum, format;
563 1.1 chopps u_char *data, *labels;
564 1.1 chopps int cnt, track;
565 1.1 chopps
566 1.1 chopps raw = (u_long *)raw_buf; /* XXXX never used while intr? */
567 1.1 chopps /* XXXX never waits after here? */
568 1.1 chopps data = fd->buf_data;
569 1.1 chopps labels = fd->buf_labels;
570 1.1 chopps track = fd->buf_track;
571 1.1 chopps
572 1.1 chopps /* gap space */
573 1.1 chopps for (cnt = 0; cnt < 414; cnt++)
574 1.1 chopps *raw++ = 0xaaaaaaaa;
575 1.1 chopps
576 1.1 chopps /* sectors */
577 1.1 chopps for (cnt = 0; cnt < 11; cnt++) {
578 1.1 chopps *raw = 0xaaaaaaaa;
579 1.1 chopps correct(raw);
580 1.1 chopps ++raw;
581 1.1 chopps
582 1.1 chopps *raw++ = 0x44894489;
583 1.1 chopps
584 1.1 chopps format = 0xff000000 | (track << 16) | (cnt << 8) | (11 - cnt);
585 1.1 chopps csum = encode_long(format,raw);
586 1.1 chopps raw += 2;
587 1.1 chopps
588 1.1 chopps encode_block(raw, labels + cnt * 16, 16, &csum);
589 1.1 chopps raw += 8;
590 1.1 chopps csum = encode_long(csum, raw);
591 1.1 chopps raw += 2;
592 1.1 chopps
593 1.1 chopps csum = 0;
594 1.1 chopps encode_block(raw+2, data + cnt * 512, 512, &csum);
595 1.1 chopps csum = encode_long(csum, raw);
596 1.1 chopps raw += 256 + 2;
597 1.1 chopps }
598 1.1 chopps }
599 1.1 chopps
600 1.1 chopps #define get_word(raw) (*(u_short *)(raw))
601 1.1 chopps #define get_long(raw) (*(u_long *)(raw))
602 1.1 chopps
603 1.1 chopps #define decode_long(raw) \
604 1.1 chopps (((get_long(raw) & 0x55555555) << 1) | \
605 1.1 chopps (get_long((raw)+4) & 0x55555555))
606 1.1 chopps
607 1.1 chopps #define MFM_NOSYNC 1
608 1.1 chopps #define MFM_HEADER 2
609 1.1 chopps #define MFM_DATA 3
610 1.1 chopps #define MFM_TRACK 4
611 1.1 chopps
612 1.1 chopps /*
613 1.1 chopps * scan_sync - looks for the next start of sector marked by a sync. When
614 1.1 chopps * sector = 10, can't be certain of a starting sync.
615 1.1 chopps */
616 1.1 chopps u_long
617 1.1 chopps scan_sync(raw, end, sect)
618 1.1 chopps u_long raw, end;
619 1.1 chopps int sect;
620 1.1 chopps {
621 1.1 chopps u_short data;
622 1.1 chopps
623 1.1 chopps if (sect != 10) {
624 1.1 chopps while (raw < end) {
625 1.1 chopps data = get_word(raw);
626 1.1 chopps if (data == 0x4489)
627 1.1 chopps break;
628 1.1 chopps raw += 2;
629 1.1 chopps }
630 1.1 chopps if (raw > end)
631 1.1 chopps return(0);
632 1.1 chopps }
633 1.1 chopps
634 1.1 chopps while (raw < end) {
635 1.1 chopps data = get_word(raw);
636 1.1 chopps if (data != 0x4489)
637 1.1 chopps break;
638 1.1 chopps raw += 2;
639 1.1 chopps }
640 1.1 chopps if (raw > end)
641 1.1 chopps return(0);
642 1.1 chopps return(raw);
643 1.1 chopps }
644 1.1 chopps
645 1.1 chopps /*
646 1.1 chopps * amiga_read reads a raw track of data into a track buffer
647 1.1 chopps */
648 1.1 chopps int
649 1.1 chopps amiga_read(fd)
650 1.1 chopps fd_p fd;
651 1.1 chopps {
652 1.1 chopps u_char *track_data, *label_data;
653 1.1 chopps u_long raw, end, val1, val2, csum, data_csum;
654 1.1 chopps u_long *data, *labels;
655 1.1 chopps int scnt, cnt, format, tnum, sect, snext;
656 1.1 chopps
657 1.1 chopps track_data = fd->buf_data;
658 1.1 chopps label_data = fd->buf_labels;
659 1.1 chopps raw = (u_long)raw_buf; /* XXXX see above about glb */
660 1.1 chopps
661 1.1 chopps end = raw + fd->ft->read_size;
662 1.1 chopps
663 1.1 chopps for (scnt = fd->sects-1; scnt >= 0; scnt--) {
664 1.1 chopps if ((raw = scan_sync(raw, end, scnt)) == 0) {
665 1.1 chopps /* XXXX */
666 1.1 chopps printf("can't find sync for sector %d\n", scnt);
667 1.1 chopps return(1);
668 1.1 chopps }
669 1.1 chopps
670 1.1 chopps val1 = decode_long(raw);
671 1.1 chopps
672 1.1 chopps format = (val1 >> 24) & 0xFF;
673 1.1 chopps tnum = (val1 >> 16) & 0xFF;
674 1.1 chopps sect = (val1 >> 8) & 0xFF;
675 1.1 chopps snext = (val1) & 0xFF;
676 1.1 chopps
677 1.1 chopps labels = (u_long *)(label_data + (sect << 4));
678 1.1 chopps
679 1.1 chopps csum = 0;
680 1.1 chopps val1 = get_long(raw);
681 1.1 chopps raw += 4;
682 1.1 chopps csum ^= val1;
683 1.1 chopps val1 = get_long(raw);
684 1.1 chopps raw += 4;
685 1.1 chopps csum ^= val1;
686 1.1 chopps
687 1.1 chopps for (cnt = 0; cnt < 4; cnt++) {
688 1.1 chopps val1 = get_long(raw+16);
689 1.1 chopps csum ^= val1;
690 1.1 chopps val1 &= 0x55555555;
691 1.1 chopps val2 = get_long(raw);
692 1.1 chopps raw += 4;
693 1.1 chopps csum ^= val2;
694 1.1 chopps val2 &= 0x55555555;
695 1.1 chopps val2 = val2 << 1;
696 1.1 chopps val1 |= val2;
697 1.1 chopps *labels++ = val1;
698 1.1 chopps }
699 1.1 chopps
700 1.1 chopps csum &= 0x55555555;
701 1.1 chopps raw += 16;
702 1.1 chopps val1 = decode_long(raw);
703 1.1 chopps raw += 8;
704 1.1 chopps if (val1 != csum) {
705 1.1 chopps /* XXXX */
706 1.1 chopps printf("MFM_HEADER %d: %08x,%08x\n", scnt,
707 1.1 chopps val1, csum);
708 1.1 chopps return(MFM_HEADER);
709 1.1 chopps }
710 1.1 chopps
711 1.1 chopps /* verify track */
712 1.1 chopps if (tnum != fd->buf_track) {
713 1.1 chopps /* XXXX */
714 1.1 chopps printf("MFM_TRACK %d: %d, %d\n", scnt, tnum,
715 1.1 chopps fd->buf_track);
716 1.1 chopps return(MFM_TRACK);
717 1.1 chopps }
718 1.1 chopps
719 1.1 chopps data_csum = decode_long(raw);
720 1.1 chopps raw += 8;
721 1.1 chopps data = (u_long *)(track_data + (sect << 9));
722 1.1 chopps
723 1.1 chopps csum = 0;
724 1.1 chopps for (cnt = 0; cnt < 128; cnt++) {
725 1.1 chopps val1 = get_long(raw + 512);
726 1.1 chopps csum ^= val1;
727 1.1 chopps val1 &= 0x55555555;
728 1.1 chopps val2 = get_long(raw);
729 1.1 chopps raw += 4;
730 1.1 chopps csum ^= val2;
731 1.1 chopps val2 &= 0x55555555;
732 1.1 chopps val2 = val2 << 1;
733 1.1 chopps val1 |= val2;
734 1.1 chopps *data++ = val1;
735 1.1 chopps }
736 1.1 chopps
737 1.1 chopps csum &= 0x55555555;
738 1.1 chopps raw += 512;
739 1.1 chopps
740 1.1 chopps if (data_csum != csum) {
741 1.1 chopps printf(
742 1.1 chopps "MFM_DATA: f=%d t=%d s=%d sn=%d sc=%d %ld, %ld\n",
743 1.1 chopps format, tnum, sect, snext, scnt, data_csum, csum);
744 1.1 chopps return(MFM_DATA);
745 1.1 chopps }
746 1.1 chopps }
747 1.1 chopps return(0);
748 1.1 chopps }
749 1.1 chopps
750 1.1 chopps /*
751 1.1 chopps * Return unit ID number of given disk
752 1.1 chopps * XXXX This function doesn't return anything.
753 1.1 chopps */
754 1.1 chopps u_long
755 1.1 chopps loop_read_id(unit)
756 1.1 chopps int unit;
757 1.1 chopps {
758 1.1 chopps u_long id;
759 1.1 chopps int i;
760 1.1 chopps
761 1.1 chopps id = 0;
762 1.1 chopps
763 1.1 chopps /* loop and read disk ID */
764 1.1 chopps for (i = 0; i < 32; i++) {
765 1.1 chopps SELECT(SELMASK(unit));
766 1.1 chopps
767 1.1 chopps /* read and store value of DSKRDY */
768 1.1 chopps id <<= 1; /* XXXX 0 << 1? */
769 1.1 chopps id |= (ciaa.pra & CIAA_PRA_RDY) ? 0 : 1;
770 1.1 chopps
771 1.1 chopps DESELECT(SELMASK(unit));
772 1.1 chopps }
773 1.1 chopps }
774 1.1 chopps
775 1.1 chopps u_long
776 1.1 chopps get_drive_id(unit)
777 1.1 chopps int unit;
778 1.1 chopps {
779 1.1 chopps int i, t;
780 1.1 chopps u_long id;
781 1.1 chopps u_char mask1, mask2;
782 1.1 chopps volatile u_char *a_ptr;
783 1.1 chopps volatile u_char *b_ptr;
784 1.1 chopps
785 1.1 chopps id = 0;
786 1.1 chopps a_ptr = &ciaa.pra;
787 1.1 chopps b_ptr = &ciab.prb;
788 1.1 chopps mask1 = ~(1 << (3 + unit));
789 1.1 chopps mask2 = 1 << (3 + unit);
790 1.1 chopps
791 1.1 chopps *b_ptr &= ~CIAB_PRB_MTR;
792 1.1 chopps *b_ptr &= mask1;
793 1.1 chopps *b_ptr |= mask2;
794 1.1 chopps *b_ptr |= CIAB_PRB_MTR;
795 1.1 chopps *b_ptr &= mask1;
796 1.1 chopps *b_ptr |= mask2;
797 1.1 chopps
798 1.1 chopps for (i = 0; i < 32; i++) {
799 1.1 chopps *b_ptr &= mask1;
800 1.1 chopps t = (*a_ptr) & CIAA_PRA_RDY;
801 1.1 chopps id = (id << 1) | (t ? 0 : 1);
802 1.1 chopps *b_ptr |= mask2;
803 1.1 chopps }
804 1.2 chopps
805 1.2 chopps /* all amigas have internal drives at 0. */
806 1.2 chopps if (unit == 0 && id == FD_NONE)
807 1.2 chopps return(FD_DD_3);
808 1.1 chopps return(id);
809 1.1 chopps #if 0
810 1.1 chopps /* set up for ID */
811 1.1 chopps MOTOR_ON;
812 1.1 chopps SELECT(SELMASK(unit));
813 1.1 chopps DESELECT(SELMASK(unit));
814 1.1 chopps MOTOR_OFF;
815 1.1 chopps SELECT(SELMASK(unit));
816 1.1 chopps DESELECT(SELMASK(unit));
817 1.1 chopps
818 1.1 chopps return loop_read_id(unit); /* XXXX gotta fix loop_read_id() if use */
819 1.1 chopps #endif
820 1.1 chopps }
821 1.1 chopps
822 1.1 chopps int
823 1.1 chopps get_drive_type(u_long id)
824 1.1 chopps {
825 1.1 chopps int type;
826 1.1 chopps
827 1.1 chopps for (type = 0; type < num_dr_types; type++)
828 1.1 chopps if (drive_types[type].id == id)
829 1.1 chopps return(type);
830 1.1 chopps return(-1);
831 1.1 chopps }
832 1.1 chopps
833 1.1 chopps void
834 1.1 chopps fd_probe(fd)
835 1.1 chopps fd_p fd;
836 1.1 chopps {
837 1.1 chopps u_long id;
838 1.1 chopps int type, data;
839 1.1 chopps
840 1.1 chopps fd->ft = NULL;
841 1.1 chopps
842 1.1 chopps id = get_drive_id(fd->fdu);
843 1.1 chopps type = get_drive_type(id);
844 1.1 chopps
845 1.1 chopps if (type == -1) {
846 1.1 chopps /* XXXX */
847 1.1 chopps printf("fd_probe: unsupported drive type %08x found\n", id);
848 1.1 chopps return;
849 1.1 chopps }
850 1.1 chopps
851 1.1 chopps fd->type = type;
852 1.1 chopps fd->ft = &drive_types[type];
853 1.1 chopps if (fd->ft->tracks == 0) {
854 1.1 chopps /* XXXX */
855 1.1 chopps printf("no drive type %d\n", type);
856 1.1 chopps }
857 1.1 chopps fd->side = -1;
858 1.1 chopps fd->dir = -1;
859 1.1 chopps fd->cyl = -1;
860 1.1 chopps
861 1.1 chopps fd->sects = 11 * drive_types[type].sect_mult;
862 1.1 chopps fd->size = fd->sects *
863 1.1 chopps drive_types[type].tracks *
864 1.1 chopps drive_types[type].heads;
865 1.1 chopps fd->flags = 0;
866 1.1 chopps }
867 1.1 chopps
868 1.1 chopps void
869 1.1 chopps track_read(fdc, fd, track)
870 1.1 chopps fdc_p fdc;
871 1.1 chopps fd_p fd;
872 1.1 chopps int track;
873 1.1 chopps {
874 1.1 chopps u_long len;
875 1.1 chopps
876 1.1 chopps fd->buf_track = track;
877 1.1 chopps fdc->state = WAIT_READ;
878 1.1 chopps timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
879 1.1 chopps
880 1.1 chopps fd_seek(fd, track);
881 1.1 chopps
882 1.1 chopps len = fd->ft->read_size >> 1;
883 1.1 chopps
884 1.1 chopps /* setup adkcon bits correctly */
885 1.1 chopps custom.adkcon = ADKF_MSBSYNC;
886 1.1 chopps custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC | ADKF_FAST;
887 1.1 chopps
888 1.1 chopps custom.dsksync = MFM_SYNC;
889 1.1 chopps
890 1.1 chopps custom.dsklen = 0;
891 1.1 chopps delay(fd->ft->side_time);
892 1.1 chopps
893 1.1 chopps custom.dskpt = (u_char *)kvtop(raw_buf);
894 1.1 chopps custom.dsklen = len | DSKLEN_DMAEN;
895 1.1 chopps custom.dsklen = len | DSKLEN_DMAEN;
896 1.1 chopps }
897 1.1 chopps
898 1.1 chopps void
899 1.1 chopps track_write(fdc, fd)
900 1.1 chopps fdc_p fdc;
901 1.1 chopps fd_p fd;
902 1.1 chopps {
903 1.1 chopps int track;
904 1.1 chopps u_long len;
905 1.1 chopps u_short adk;
906 1.1 chopps
907 1.1 chopps amiga_write(fd);
908 1.1 chopps
909 1.1 chopps track = fd->buf_track;
910 1.1 chopps fd->write_cnt += 1;
911 1.1 chopps
912 1.1 chopps fdc->saved = fdc->state;
913 1.1 chopps fdc->state = WAIT_WRITE;
914 1.1 chopps timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
915 1.1 chopps
916 1.1 chopps fd_seek(fd, track);
917 1.1 chopps
918 1.1 chopps len = fd->ft->write_size >> 1;
919 1.1 chopps
920 1.1 chopps if ((ciaa.pra & CIAA_PRA_WPRO) == 0)
921 1.1 chopps return;
922 1.1 chopps
923 1.1 chopps /* clear adkcon bits */
924 1.1 chopps custom.adkcon = ADKF_PRECOMP1 | ADKF_PRECOMP0 | ADKF_WORDSYNC |
925 1.1 chopps ADKF_MSBSYNC;
926 1.1 chopps
927 1.1 chopps /* set appropriate adkcon bits */
928 1.1 chopps adk = ADKF_SETCLR | ADKF_FAST;
929 1.1 chopps if (track >= fd->ft->precomp2)
930 1.1 chopps adk |= ADKF_PRECOMP1;
931 1.1 chopps else if (track >= fd->ft->precomp1)
932 1.1 chopps adk |= ADKF_PRECOMP0;
933 1.1 chopps custom.adkcon = adk;
934 1.1 chopps
935 1.1 chopps custom.dsklen = DSKLEN_WRITE;
936 1.1 chopps delay(fd->ft->side_time);
937 1.1 chopps
938 1.1 chopps custom.dskpt = (u_char *)kvtop(raw_buf); /* XXXX again raw */
939 1.1 chopps custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE;
940 1.1 chopps custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE;
941 1.1 chopps }
942 1.1 chopps
943 1.1 chopps /*
944 1.1 chopps * Floppy Device Code
945 1.1 chopps */
946 1.1 chopps int
947 1.1 chopps fdattach(ad)
948 1.1 chopps struct amiga_device *ad;
949 1.1 chopps {
950 1.1 chopps int fdcu = 0;
951 1.1 chopps fdc_p fdc = fdc_data + fdcu;
952 1.1 chopps int i;
953 1.1 chopps unsigned long id;
954 1.1 chopps int type;
955 1.1 chopps
956 1.1 chopps fdc->fdcu = fdcu;
957 1.1 chopps fdc->state = FINDWORK;
958 1.1 chopps fdc->fd = NULL;
959 1.1 chopps fdc->motor_fdu = -1;
960 1.1 chopps
961 1.1 chopps for (i = 0; i < DRVS_PER_CTLR; i++) {
962 1.1 chopps fdc->fd_data[i].fdu = i;
963 1.1 chopps fdc->fd_data[i].flags = 0;
964 1.1 chopps
965 1.1 chopps fdc->fd_data[i].buf_track = -1;
966 1.1 chopps fdc->fd_data[i].buf_dirty = 0;
967 1.1 chopps fdc->fd_data[i].buf_data =
968 1.1 chopps malloc(MAX_SECTS * 512, M_DEVBUF, 0);
969 1.1 chopps fdc->fd_data[i].buf_labels =
970 1.1 chopps malloc(MAX_SECTS * 16, M_DEVBUF, 0);
971 1.1 chopps
972 1.1 chopps if (fdc->fd_data[i].buf_data == NULL ||
973 1.1 chopps fdc->fd_data[i].buf_labels == NULL) {
974 1.1 chopps printf("Cannot alloc buffer memory for fd device\n");
975 1.1 chopps return(0);
976 1.1 chopps }
977 1.1 chopps
978 1.1 chopps id = get_drive_id(i);
979 1.1 chopps type = get_drive_type(id);
980 1.1 chopps
981 1.1 chopps if (type != -1 && drive_types[type].tracks != 0) {
982 1.1 chopps printf("floppy drive %d: %s\n", i,
983 1.1 chopps drive_types[type].name);
984 1.1 chopps }
985 1.1 chopps }
986 1.1 chopps
987 1.1 chopps raw_buf = (char *)alloc_chipmem(30000);
988 1.1 chopps if (raw_buf == NULL) {
989 1.1 chopps printf("Cannot alloc chipmem for fd device\n");
990 1.1 chopps return 0;
991 1.1 chopps }
992 1.1 chopps
993 1.1 chopps /* enable disk DMA */
994 1.1 chopps custom.dmacon = DMAF_SETCLR | DMAF_DISK;
995 1.1 chopps
996 1.1 chopps /* enable interrupts for IRQ_DSKBLK */
997 1.1 chopps ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
998 1.1 chopps custom.intena = INTF_SETCLR | INTF_SOFTINT;
999 1.1 chopps
1000 1.1 chopps /* enable disk block interrupts */
1001 1.1 chopps custom.intena = INTF_SETCLR | INTF_DSKBLK;
1002 1.1 chopps
1003 1.1 chopps return(1);
1004 1.1 chopps }
1005 1.1 chopps
1006 1.1 chopps int
1007 1.1 chopps Fdopen(dev, flags)
1008 1.1 chopps dev_t dev;
1009 1.1 chopps int flags;
1010 1.1 chopps {
1011 1.1 chopps fdcu_t fdcu;
1012 1.1 chopps fdc_p fdc;
1013 1.1 chopps fdu_t fdu;
1014 1.1 chopps fd_p fd;
1015 1.1 chopps
1016 1.1 chopps fdcu = 0;
1017 1.1 chopps fdc = fdc_data + fdcu;
1018 1.1 chopps fdu = UNIT(dev);
1019 1.1 chopps fd = fdc->fd_data + fdu;
1020 1.1 chopps
1021 1.1 chopps /* check bounds */
1022 1.1 chopps if (fdu >= DRVS_PER_CTLR)
1023 1.1 chopps return(ENXIO);
1024 1.1 chopps
1025 1.1 chopps fd_probe(fd);
1026 1.1 chopps if (fd->ft == NULL || fd->ft->tracks == 0)
1027 1.1 chopps return(ENXIO);
1028 1.1 chopps
1029 1.1 chopps fd->flags |= FDF_OPEN;
1030 1.1 chopps fd->write_cnt = 0;
1031 1.1 chopps
1032 1.1 chopps return(0);
1033 1.1 chopps }
1034 1.1 chopps
1035 1.1 chopps int
1036 1.1 chopps fdclose(dev, flags)
1037 1.1 chopps dev_t dev;
1038 1.1 chopps int flags;
1039 1.1 chopps {
1040 1.1 chopps struct buf *dp,*bp;
1041 1.1 chopps fdcu_t fdcu;
1042 1.1 chopps fdc_p fdc;
1043 1.1 chopps fdu_t fdu;
1044 1.1 chopps fd_p fd;
1045 1.1 chopps
1046 1.1 chopps fdcu = 0;
1047 1.1 chopps fdc = fdc_data + fdcu;
1048 1.1 chopps fdu = UNIT(dev);
1049 1.1 chopps fd = fdc->fd_data + fdu;
1050 1.1 chopps
1051 1.1 chopps
1052 1.1 chopps /* wait until activity is done for this drive */
1053 1.1 chopps /* XXXX ACK! sleep.. */
1054 1.1 chopps do {
1055 1.1 chopps dp = &(fd->head);
1056 1.1 chopps bp = dp->b_actf;
1057 1.1 chopps } while (bp);
1058 1.1 chopps
1059 1.1 chopps /* XXXX */
1060 1.1 chopps printf("wrote %d tracks (%d)\n", fd->write_cnt, fd->buf_dirty);
1061 1.1 chopps
1062 1.1 chopps fd->buf_track = -1;
1063 1.1 chopps fd->buf_dirty = 0;
1064 1.1 chopps fd->flags &= ~FDF_OPEN;
1065 1.1 chopps
1066 1.1 chopps return(0);
1067 1.1 chopps }
1068 1.1 chopps
1069 1.1 chopps int
1070 1.1 chopps fdioctl(dev, cmd, data, flag, p)
1071 1.1 chopps dev_t dev;
1072 1.1 chopps int cmd, flag;
1073 1.1 chopps caddr_t data;
1074 1.1 chopps struct proc *p;
1075 1.1 chopps {
1076 1.1 chopps struct disklabel *fd_label;
1077 1.1 chopps fdcu_t fdcu;
1078 1.1 chopps fdc_p fdc;
1079 1.1 chopps fdu_t fdu;
1080 1.1 chopps fd_p fd;
1081 1.1 chopps int error;
1082 1.1 chopps
1083 1.1 chopps fdcu = 0;
1084 1.1 chopps fdc = fdc_data + fdcu;
1085 1.1 chopps fdu = UNIT(dev);
1086 1.1 chopps fd = fdc->fd_data + fdu;
1087 1.1 chopps error = 0;
1088 1.1 chopps
1089 1.1 chopps if (cmd != DIOCGDINFO)
1090 1.1 chopps return (EINVAL);
1091 1.1 chopps
1092 1.1 chopps fd_label = (struct disklabel *)data;
1093 1.1 chopps
1094 1.1 chopps bzero(fd_label, sizeof(fd_label));
1095 1.1 chopps fd_label->d_magic = DISKMAGIC;
1096 1.1 chopps fd_label->d_type = DTYPE_FLOPPY;
1097 1.1 chopps strncpy(fd_label->d_typename, "fd", sizeof(fd_label->d_typename) - 1);
1098 1.1 chopps strcpy(fd_label->d_packname, "some pack");
1099 1.1 chopps
1100 1.1 chopps fd_label->d_secsize = 512;
1101 1.1 chopps fd_label->d_nsectors = 11;
1102 1.1 chopps fd_label->d_ntracks = 2;
1103 1.1 chopps fd_label->d_ncylinders = 80;
1104 1.1 chopps fd_label->d_secpercyl = fd_label->d_nsectors * fd_label->d_ntracks;
1105 1.1 chopps fd_label->d_secperunit= fd_label->d_ncylinders * fd_label->d_secpercyl;
1106 1.1 chopps
1107 1.1 chopps fd_label->d_magic2 = DISKMAGIC;
1108 1.1 chopps fd_label->d_partitions[0].p_offset = 0;
1109 1.1 chopps fd_label->d_partitions[0].p_size = fd_label->d_secperunit;
1110 1.1 chopps fd_label->d_partitions[0].p_fstype = FS_UNUSED;
1111 1.1 chopps fd_label->d_npartitions = 1;
1112 1.1 chopps
1113 1.1 chopps fd_label->d_checksum = 0;
1114 1.1 chopps fd_label->d_checksum = dkcksum(fd_label);
1115 1.1 chopps
1116 1.1 chopps return(0);
1117 1.1 chopps }
1118 1.1 chopps
1119 1.1 chopps int
1120 1.1 chopps fdsize(dev)
1121 1.1 chopps dev_t dev;
1122 1.1 chopps {
1123 1.1 chopps /* check UNIT? */
1124 1.1 chopps return((fdc_data + 0)->fd_data[UNIT(dev)].size);
1125 1.1 chopps }
1126 1.1 chopps
1127 1.1 chopps void
1128 1.1 chopps fdstrategy(bp)
1129 1.1 chopps struct buf *bp;
1130 1.1 chopps {
1131 1.1 chopps fdcu_t fdcu;
1132 1.1 chopps fdc_p fdc;
1133 1.1 chopps fdu_t fdu;
1134 1.1 chopps fd_p fd;
1135 1.1 chopps long nblocks, blknum;
1136 1.1 chopps struct buf *dp;
1137 1.1 chopps int s;
1138 1.1 chopps
1139 1.1 chopps fdcu = 0;
1140 1.1 chopps fdc = fdc_data + fdcu;
1141 1.1 chopps fdu = UNIT(bp->b_dev);
1142 1.1 chopps fd = fdc->fd_data + fdu;
1143 1.1 chopps
1144 1.1 chopps if (bp->b_blkno < 0) {
1145 1.1 chopps /* XXXX */
1146 1.1 chopps printf("fdstrat error: fdu = %d, blkno = %d, bcount = %d\n",
1147 1.1 chopps fdu, bp->b_blkno, bp->b_bcount);
1148 1.1 chopps bp->b_error = EINVAL;
1149 1.1 chopps bp->b_flags |= B_ERROR;
1150 1.1 chopps biodone(bp);
1151 1.1 chopps return;
1152 1.1 chopps }
1153 1.1 chopps
1154 1.1 chopps /*
1155 1.1 chopps * Set up block calculations.
1156 1.1 chopps */
1157 1.1 chopps blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / FDBLK;
1158 1.1 chopps nblocks = fd->sects * fd->ft->tracks * fd->ft->heads;
1159 1.1 chopps if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
1160 1.1 chopps /* XXXX */
1161 1.1 chopps printf("at end of disk\n");
1162 1.1 chopps bp->b_error = ENOSPC;
1163 1.1 chopps bp->b_flags |= B_ERROR;
1164 1.1 chopps biodone(bp);
1165 1.1 chopps return;
1166 1.1 chopps }
1167 1.1 chopps
1168 1.1 chopps bp->b_cylin = blknum; /* set here for disksort */
1169 1.1 chopps dp = &(fd->head);
1170 1.1 chopps
1171 1.1 chopps s = splbio();
1172 1.1 chopps disksort(dp, bp);
1173 1.1 chopps untimeout((timeout_t)fd_turnoff, (caddr_t)fdc); /* a good idea */
1174 1.1 chopps fdstart(fdc);
1175 1.1 chopps splx(s);
1176 1.1 chopps }
1177 1.1 chopps
1178 1.1 chopps /*
1179 1.1 chopps * We have just queued something.. if the controller is not busy
1180 1.1 chopps * then simulate the case where it has just finished a command
1181 1.1 chopps * So that it (the interrupt routine) looks on the queue for more
1182 1.1 chopps * work to do and picks up what we just added.
1183 1.1 chopps * If the controller is already busy, we need do nothing, as it
1184 1.1 chopps * will pick up our work when the present work completes
1185 1.1 chopps */
1186 1.1 chopps void
1187 1.1 chopps fdstart(fdc)
1188 1.1 chopps fdc_p fdc;
1189 1.1 chopps {
1190 1.1 chopps int s;
1191 1.1 chopps
1192 1.1 chopps s = splbio();
1193 1.1 chopps if (fdc->state == FINDWORK)
1194 1.1 chopps fdintr(fdc->fdcu);
1195 1.1 chopps splx(s);
1196 1.1 chopps }
1197 1.1 chopps
1198 1.1 chopps /*
1199 1.1 chopps * just ensure it has the right spl
1200 1.1 chopps */
1201 1.1 chopps void
1202 1.1 chopps fd_pseudointr(fdc)
1203 1.1 chopps fdc_p fdc;
1204 1.1 chopps {
1205 1.1 chopps int s;
1206 1.1 chopps
1207 1.1 chopps s = splbio();
1208 1.1 chopps fdintr(fdc->fdcu);
1209 1.1 chopps splx(s);
1210 1.1 chopps }
1211 1.1 chopps
1212 1.1 chopps void
1213 1.1 chopps fd_timeout(fdc)
1214 1.1 chopps fdc_p fdc;
1215 1.1 chopps {
1216 1.1 chopps struct buf *dp,*bp;
1217 1.1 chopps fd_p fd;
1218 1.1 chopps
1219 1.1 chopps fd = fdc->fd;
1220 1.1 chopps dp = &fd->head;
1221 1.1 chopps bp = dp->b_actf;
1222 1.1 chopps
1223 1.1 chopps /* XXXX */
1224 1.1 chopps printf("fd%d: Operation timeout\n", fd->fdu);
1225 1.1 chopps if (bp) {
1226 1.1 chopps retrier(fdc);
1227 1.1 chopps fdc->state = DONE_IO;
1228 1.1 chopps if (fdc->retry < 6)
1229 1.1 chopps fdc->retry = 6;
1230 1.1 chopps } else {
1231 1.1 chopps fdc->fd = NULL;
1232 1.1 chopps fdc->state = FINDWORK;
1233 1.1 chopps }
1234 1.1 chopps
1235 1.1 chopps fd_pseudointr(fdc);
1236 1.1 chopps }
1237 1.1 chopps
1238 1.1 chopps /*
1239 1.1 chopps * keep calling the state machine until it returns a 0
1240 1.1 chopps * ALWAYS called at SPLBIO
1241 1.1 chopps */
1242 1.1 chopps void
1243 1.1 chopps fdintr(fdcu)
1244 1.1 chopps fdcu_t fdcu;
1245 1.1 chopps {
1246 1.1 chopps fdc_p fdc;
1247 1.1 chopps
1248 1.1 chopps fdc = fdc_data + fdcu;
1249 1.1 chopps while (fdstate(fdc))
1250 1.1 chopps ;
1251 1.1 chopps }
1252 1.1 chopps
1253 1.1 chopps /*
1254 1.1 chopps * The controller state machine.
1255 1.1 chopps * if it returns a non zero value, it should be called again immediatly
1256 1.1 chopps */
1257 1.1 chopps int
1258 1.1 chopps fdstate(fdc)
1259 1.1 chopps fdc_p fdc;
1260 1.1 chopps {
1261 1.1 chopps struct buf *dp,*bp;
1262 1.1 chopps int track, read, sec, i;
1263 1.1 chopps u_long blknum;
1264 1.1 chopps fd_p fd;
1265 1.1 chopps
1266 1.1 chopps fd = fdc->fd;
1267 1.1 chopps
1268 1.1 chopps if (fd == NULL) {
1269 1.1 chopps /* search for a unit do work with */
1270 1.1 chopps for (i = 0; i < DRVS_PER_CTLR; i++) {
1271 1.1 chopps fd = fdc->fd_data + i;
1272 1.1 chopps dp = &(fd->head);
1273 1.1 chopps bp = dp->b_actf;
1274 1.1 chopps if (bp) {
1275 1.1 chopps fdc->fd = fd;
1276 1.1 chopps break;
1277 1.1 chopps }
1278 1.1 chopps }
1279 1.1 chopps
1280 1.1 chopps if (fdc->fd)
1281 1.1 chopps return(1);
1282 1.1 chopps
1283 1.1 chopps fdc->state = FINDWORK;
1284 1.1 chopps TRACE1("[fdc%d IDLE]\n", fdc->fdcu);
1285 1.1 chopps return(0);
1286 1.1 chopps }
1287 1.1 chopps
1288 1.1 chopps dp = &(fd->head);
1289 1.1 chopps bp = dp->b_actf;
1290 1.1 chopps
1291 1.1 chopps blknum = (u_long)bp->b_blkno * DEV_BSIZE / FDBLK + fd->skip / FDBLK;
1292 1.1 chopps track = blknum / fd->sects;
1293 1.1 chopps sec = blknum % fd->sects;
1294 1.1 chopps
1295 1.1 chopps read = bp->b_flags & B_READ;
1296 1.1 chopps TRACE1("fd%d", fd->fdu);
1297 1.1 chopps TRACE1("[%s]", fdstates[fdc->state]);
1298 1.1 chopps TRACE1("(0x%x) ", fd->flags);
1299 1.1 chopps TRACE1("%d\n", fd->buf_track);
1300 1.1 chopps
1301 1.1 chopps untimeout((timeout_t)fd_turnoff, (caddr_t)fdc);
1302 1.1 chopps timeout((timeout_t)fd_turnoff, (caddr_t)fdc, 4 * hz);
1303 1.1 chopps
1304 1.1 chopps switch (fdc->state) {
1305 1.1 chopps case FINDWORK:
1306 1.1 chopps if (!bp) {
1307 1.1 chopps if (fd->buf_dirty) {
1308 1.1 chopps track_write(fdc, fd);
1309 1.1 chopps return(0);
1310 1.1 chopps }
1311 1.1 chopps fdc->fd = NULL;
1312 1.1 chopps return(1);
1313 1.1 chopps }
1314 1.1 chopps
1315 1.1 chopps fdc->state = DOSEEK;
1316 1.1 chopps fdc->retry = 0;
1317 1.1 chopps fd->skip = 0;
1318 1.1 chopps return(1);
1319 1.1 chopps case DOSEEK:
1320 1.1 chopps fd_turnon(fdc, fd->fdu);
1321 1.1 chopps
1322 1.1 chopps /*
1323 1.1 chopps * If not started, error starting it
1324 1.1 chopps */
1325 1.1 chopps if (fdc->motor_fdu != fd->fdu) {
1326 1.1 chopps /* XXXX */
1327 1.1 chopps printf("motor not on!\n");
1328 1.1 chopps }
1329 1.1 chopps
1330 1.1 chopps /*
1331 1.1 chopps * If track not in buffer, read it in
1332 1.1 chopps */
1333 1.1 chopps if (fd->buf_track != track) {
1334 1.1 chopps TRACE1("do track %d\n", track);
1335 1.1 chopps
1336 1.1 chopps if (fd->buf_dirty)
1337 1.1 chopps track_write(fdc, fd);
1338 1.1 chopps else
1339 1.1 chopps track_read(fdc, fd, track);
1340 1.1 chopps return(0);
1341 1.1 chopps }
1342 1.1 chopps
1343 1.1 chopps fdc->state = DO_IO;
1344 1.1 chopps return(1);
1345 1.1 chopps case DO_IO:
1346 1.1 chopps if (read)
1347 1.1 chopps bcopy(&fd->buf_data[sec * FDBLK],
1348 1.1 chopps bp->b_un.b_addr + fd->skip, FDBLK);
1349 1.1 chopps else {
1350 1.1 chopps bcopy(bp->b_un.b_addr + fd->skip,
1351 1.1 chopps &fd->buf_data[sec * FDBLK], FDBLK);
1352 1.1 chopps fd->buf_dirty = 1;
1353 1.1 chopps if (IMMED_WRITE) {
1354 1.1 chopps fdc->state = DONE_IO;
1355 1.1 chopps track_write(fdc, fd);
1356 1.1 chopps return(0);
1357 1.1 chopps }
1358 1.1 chopps }
1359 1.1 chopps case DONE_IO:
1360 1.1 chopps fd->skip += FDBLK;
1361 1.1 chopps if (fd->skip < bp->b_bcount)
1362 1.1 chopps fdc->state = DOSEEK;
1363 1.1 chopps else {
1364 1.1 chopps fd->skip = 0;
1365 1.1 chopps bp->b_resid = 0;
1366 1.1 chopps dp->b_actf = bp->b_actf;
1367 1.1 chopps biodone(bp);
1368 1.1 chopps fdc->state = FINDWORK;
1369 1.1 chopps }
1370 1.1 chopps return(1);
1371 1.1 chopps case WAIT_READ:
1372 1.1 chopps untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
1373 1.1 chopps custom.dsklen = 0;
1374 1.1 chopps amiga_read(fd);
1375 1.1 chopps fdc->state = DO_IO;
1376 1.1 chopps return(1);
1377 1.1 chopps case WAIT_WRITE:
1378 1.1 chopps untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
1379 1.1 chopps custom.dsklen = 0;
1380 1.1 chopps fdc->state = fdc->saved;
1381 1.1 chopps fd->buf_dirty = 0;
1382 1.1 chopps return(1);
1383 1.1 chopps default:
1384 1.1 chopps /* XXXX */
1385 1.1 chopps printf("Unexpected FD int->%d\n", fdc->state);
1386 1.1 chopps return 0;
1387 1.1 chopps }
1388 1.1 chopps
1389 1.1 chopps /* Come back immediatly to new state */
1390 1.1 chopps return(1);
1391 1.1 chopps }
1392 1.1 chopps
1393 1.1 chopps int
1394 1.1 chopps retrier(fdc)
1395 1.1 chopps fdc_p fdc;
1396 1.1 chopps {
1397 1.1 chopps struct buf *dp,*bp;
1398 1.1 chopps fd_p fd;
1399 1.1 chopps
1400 1.1 chopps fd = fdc->fd;
1401 1.1 chopps dp = &(fd->head);
1402 1.1 chopps bp = dp->b_actf;
1403 1.1 chopps
1404 1.1 chopps #if 0
1405 1.1 chopps switch(fdc->retry) {
1406 1.1 chopps case 0:
1407 1.1 chopps case 1:
1408 1.1 chopps case 2:
1409 1.1 chopps fdc->state = SEEKCOMPLETE;
1410 1.1 chopps break;
1411 1.1 chopps case 3:
1412 1.1 chopps case 4:
1413 1.1 chopps case 5:
1414 1.1 chopps fdc->state = STARTRECAL;
1415 1.1 chopps break;
1416 1.1 chopps case 6:
1417 1.1 chopps fdc->state = RESETCTLR;
1418 1.1 chopps break;
1419 1.1 chopps case 7:
1420 1.1 chopps break;
1421 1.1 chopps default:
1422 1.1 chopps #endif
1423 1.1 chopps /* XXXX */
1424 1.1 chopps printf("fd%d: hard error\n", fd->fdu);
1425 1.1 chopps
1426 1.1 chopps bp->b_flags |= B_ERROR;
1427 1.1 chopps bp->b_error = EIO;
1428 1.1 chopps bp->b_resid = bp->b_bcount - fd->skip;
1429 1.1 chopps dp->b_actf = bp->b_actf;
1430 1.1 chopps fd->skip = 0;
1431 1.1 chopps biodone(bp);
1432 1.1 chopps fdc->state = FINDWORK;
1433 1.1 chopps return(1);
1434 1.1 chopps #if 0
1435 1.1 chopps fdc->retry++;
1436 1.1 chopps return(1);
1437 1.1 chopps #endif
1438 1.1 chopps }
1439 1.1 chopps
1440 1.1 chopps #endif
1441