forked from EtchedPixels/FUZIX
-
Notifications
You must be signed in to change notification settings - Fork 1
/
devfd.c
131 lines (110 loc) · 3.08 KB
/
devfd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <kernel.h>
#include <kdata.h>
#include <printf.h>
#include <devfd.h>
/*
* TODO: Debug, low density is half the sectors/track,
* what to do about 80 v 40 track ?
*
*/
/* Two drives but minors 2,3 are single density mode */
#define MAX_FD 4
#define OPDIR_NONE 0
#define OPDIR_READ 1
#define OPDIR_WRITE 2
#define FD_READ 0x88 /* 2797 needs 0x88, 1797 needs 0x80 */
#define FD_WRITE 0xA8 /* Likewise A8 v A0 */
static uint8_t motorct;
static uint8_t fd_selected = 0xFF;
static uint8_t fd_tab[MAX_FD] = { 0xFF, 0xFF };
void fd_motor_timer(void)
{
if (motorct) {
motorct--;
if (motorct == 0) {
fd_motor_off();
fd_selected = 0xFF;
}
}
}
/*
* We only support normal block I/O not swap.
*/
static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
{
uint16_t nb = 0;
int tries;
uint8_t err = 0;
uint8_t *driveptr = &fd_tab[minor & 1];
irqflags_t irq;
if(rawflag == 1 && d_blkoff(BLKSHIFT))
return -1;
udata.u_nblock *= 2;
if (rawflag == 2)
goto bad2;
irq = di();
if (fd_selected != minor) {
uint8_t err = fd_motor_on(minor|(minor > 1 ? 0: 0x10));
if (err)
goto bad;
motorct = 150; /* 3 seconds */
}
irqrestore(irq);
// kprintf("Issue command: %c drive %d block %d for %d\n", "wr"[is_read], minor, udata.u_block, udata.u_nblock);
fd_cmd[0] = rawflag;
fd_cmd[1] = is_read ? FD_READ : FD_WRITE;
/* There are 16 256 byte sectors for DSDD. These are organised so that we
switch head then step.
Sectors 0-15 (our block 0-7) Track 0, side 0
Sectors 16-31 (our block 8-15) Track 0, side 1
etc */
fd_cmd[2] = udata.u_block / 16; /* Get the track we need */
fd_cmd[3] = ((udata.u_block & 15) << 1); /* 0 - 1 base is corrected in asm */
fd_cmd[4] = is_read ? OPDIR_READ: OPDIR_WRITE;
fd_data = (uint16_t)udata.u_dptr;
while (udata.u_nblock--) {
for (tries = 0; tries < 4 ; tries++) {
// kprintf("Sector: %d Head: %d Track %d\n", (fd_cmd[3]&15)+1, fd_cmd[3]>>4, fd_cmd[2]);
err = fd_operation(driveptr);
if (err == 0)
break;
if (tries > 1)
fd_reset(driveptr);
}
/* FIXME: should we try the other half and then bale out ? */
if (tries == 3)
goto bad;
fd_data += 256;
fd_cmd[3]++; /* Next sector for next block */
if (fd_cmd[3] == 32) { /* Next track */
fd_cmd[3] = 0;
fd_cmd[2]++;
}
nb++;
}
return nb << (BLKSHIFT - 1);
bad:
kprintf("fd%d: error %x\n", minor, err);
bad2:
udata.u_error = EIO;
return -1;
}
int fd_open(uint8_t minor, uint16_t flag)
{
flag;
if(minor >= MAX_FD) {
udata.u_error = ENODEV;
return -1;
}
return 0;
}
int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
{
flag;
return fd_transfer(minor, true, rawflag);
}
int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
{
flag;
return fd_transfer(minor, false, rawflag);
}