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