ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/cwcbm/catweasel.c
Revision: 1.1.1.1 (vendor branch)
Committed: 2004-01-07T15:37:45Z (20 years, 10 months ago) by cebix
Content type: text/plain
Branch: MAIN, cebix
CVS Tags: start, HEAD
Changes since 1.1: +0 -0 lines
Error occurred while calculating annotation data.
Log Message:
imported sources

File Contents

# Content
1
2 /*
3 * Catweasel -- Advanced Floppy Controller
4 * Linux device driver
5 * Low-level routines
6 *
7 * Copyright (C) 1998-2002 Michael Krause
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 #include <asm/io.h>
25
26 #include "catweasel.h"
27
28 static __inline__ void CWSetCReg(catweasel_contr *c, unsigned char clear, unsigned char set)
29 {
30 c->control_register = (c->control_register & ~clear) | set;
31 outb(c->control_register, c->io_sr);
32 }
33
34 static void CWTriggerStep(catweasel_contr *c)
35 {
36 CWSetCReg(c, c->crm_step, 0);
37 c->msdelay(5);
38 CWSetCReg(c, 0, c->crm_step);
39 c->msdelay(5);
40 }
41
42 void catweasel_init_controller(catweasel_contr *c)
43 {
44 int i, j;
45
46 if(!c->iobase)
47 return;
48
49 switch(c->type) {
50 case CATWEASEL_TYPE_MK1:
51 c->crm_sel0 = 1 << 5;
52 c->crm_sel1 = 1 << 4;
53 c->crm_mot0 = 1 << 3;
54 c->crm_mot1 = 1 << 7;
55 c->crm_dir = 1 << 1;
56 c->crm_step = 1 << 0;
57 c->srm_trk0 = 1 << 4;
58 c->srm_dchg = 1 << 5;
59 c->srm_writ = 1 << 1;
60 c->io_sr = c->iobase + 2;
61 c->io_mem = c->iobase;
62 break;
63 case CATWEASEL_TYPE_MK3:
64 c->crm_sel0 = 1 << 2;
65 c->crm_sel1 = 1 << 3;
66 c->crm_mot0 = 1 << 1;
67 c->crm_mot1 = 1 << 5;
68 c->crm_dir = 1 << 4;
69 c->crm_step = 1 << 7;
70 c->srm_trk0 = 1 << 2;
71 c->srm_dchg = 1 << 5;
72 c->srm_writ = 1 << 6;
73 c->io_sr = c->iobase + 0xe8;
74 c->io_mem = c->iobase + 0xe0;
75 break;
76 default:
77 return;
78 }
79
80 c->control_register = 255;
81
82 /* select all drives, step inside */
83 CWSetCReg(c, c->crm_dir | c->crm_sel0 | c->crm_sel1, 0);
84 for(i=0;i<3;i++)
85 CWTriggerStep(c);
86
87 for(i=0;i<2;i++) {
88 c->drives[i].number = i;
89 c->drives[i].contr = c;
90 c->drives[i].diskindrive = 0;
91
92 /* select only the respective drive, step to track 0 */
93 if(i == 0) {
94 CWSetCReg(c, c->crm_sel0, c->crm_dir | c->crm_sel1);
95 } else {
96 CWSetCReg(c, c->crm_sel1, c->crm_dir | c->crm_sel0);
97 }
98
99 for(j = 0; j < 86 && (inb(c->io_sr) & c->srm_trk0); j++)
100 CWTriggerStep(c);
101
102 if(j < 86) {
103 c->drives[i].type = 1;
104 c->drives[i].track = 0;
105 } else {
106 c->drives[i].type = 0;
107 }
108 }
109
110 CWSetCReg(c, 0, c->crm_sel0 | c->crm_sel1); /* deselect all drives */
111 }
112
113 void catweasel_free_controller(catweasel_contr *c)
114 {
115 if(!c->iobase)
116 return;
117
118 /* all motors off, deselect all drives */
119 CWSetCReg(c, 0, c->crm_mot0 | c->crm_mot1 | c->crm_sel0 | c->crm_sel1);
120 }
121
122 void catweasel_select(catweasel_contr *c, int dr0, int dr1)
123 {
124 CWSetCReg(c, dr0*c->crm_sel0 | dr1*c->crm_sel1, (!dr0)*c->crm_sel0 | (!dr1)*c->crm_sel1);
125 }
126
127 void catweasel_set_motor(catweasel_drive *d, int on)
128 {
129 if(d->number == 0) {
130 CWSetCReg(d->contr, on*d->contr->crm_mot0, (!on)*d->contr->crm_mot0);
131 } else {
132 CWSetCReg(d->contr, on*d->contr->crm_mot1, (!on)*d->contr->crm_mot1);
133 }
134 }
135
136 int catweasel_seek(catweasel_drive *d, int t)
137 {
138 int x;
139
140 if(t == 0) {
141 /* Recalibrate using explicit Track 0 sensing */
142 catweasel_contr *c = d->contr;
143 CWSetCReg(c, c->crm_dir, 0);
144 for(x = 0; x < 3; x++)
145 CWTriggerStep(c);
146 CWSetCReg(c, 0, c->crm_dir);
147
148 for(x = 0; x < 86 && (inb(c->io_sr) & c->srm_trk0); x++)
149 CWTriggerStep(c);
150
151 if(x == 86) {
152 return 0;
153 }
154
155 d->track = 0;
156 return 1;
157 }
158
159 if(t >= 80) {
160 return 0;
161 }
162
163 x = t - d->track;
164 if(!x)
165 return 1;
166
167 if(x >= 0) {
168 CWSetCReg(d->contr, d->contr->crm_dir, 0);
169 } else {
170 CWSetCReg(d->contr, 0, d->contr->crm_dir);
171 x = -x;
172 }
173
174 while(x--)
175 CWTriggerStep(d->contr);
176
177 d->track = t;
178 return 1;
179 }
180
181 int catweasel_disk_changed(catweasel_drive *d)
182 {
183 int ot, t, changed = 0;
184
185 if(inb(d->contr->io_sr) & d->contr->srm_dchg) {
186 if(!d->diskindrive) {
187 /* first usage of this drive, issue disk change */
188 d->diskindrive = 1;
189 changed = 1;
190 } else {
191 /* there's still a disk in there, no change detected. */
192 }
193 } else {
194 ot = d->track;
195 if(ot == 79)
196 t = 78;
197 else
198 t = ot + 1;
199
200 catweasel_seek(d, t);
201 catweasel_seek(d, ot);
202
203 if(!(inb(d->contr->io_sr) & d->contr->srm_dchg)) {
204 if(!d->diskindrive) {
205 /* drive still empty, nothing has happened */
206 } else {
207 /* disk has been removed */
208 d->diskindrive = 0;
209 changed = 1;
210 }
211 } else {
212 /* disk has been inserted */
213 d->diskindrive = 1;
214 changed = 1;
215 }
216 }
217
218 return changed;
219 }
220
221 int catweasel_write_protected(catweasel_drive *d)
222 {
223 return !(inb(d->contr->io_sr) & 8);
224 }
225
226 int catweasel_read(catweasel_drive *d, int side, int clock, int time)
227 {
228 int iobase = d->contr->iobase;
229
230 if(!(inb(d->contr->io_sr) & d->contr->srm_dchg))
231 return 0;
232
233 if(d->contr->type == CATWEASEL_TYPE_MK1) {
234 CWSetCReg(d->contr, 1<<2, (!side)<<2); /* set disk side */
235
236 inb(iobase+1); /* ra reset */
237 outb(clock*128, iobase+3);
238
239 inb(iobase+1);
240 inb(iobase+0);
241 inb(iobase+0);
242 outb(0, iobase+3); /* don't store index pulse */
243
244 inb(iobase+1);
245
246 inb(iobase+7); /* start reading */
247 d->contr->msdelay(time); /* wait for one rotation */
248 outb(0, iobase+1); /* stop reading, don't reset RAM pointer */
249
250 outb(128, iobase+0); /* add data end mark */
251 outb(128, iobase+0);
252
253 inb(iobase+1); /* Reset RAM pointer */
254 } else {
255 CWSetCReg(d->contr, 1<<6, (!side)<<6); /* set disk side */
256
257 outb(0, iobase + 0xe4); /* Reset memory pointer */
258 switch(clock) {
259 case 0: /* 28MHz */
260 outb(128, iobase + 0xec);
261 break;
262 case 1: /* 14MHz */
263 outb(0, iobase + 0xec);
264 break;
265 }
266 inb(iobase + 0xe0);
267 inb(iobase + 0xe0);
268 outb(0, iobase + 0xec); /* no IRQs, no MFM predecode */
269 inb(iobase + 0xe0);
270 outb(0, iobase + 0xec); /* don't store index pulse */
271
272 outb(0, iobase + 0xe4); /* Reset memory pointer */
273 inb(iobase + 0xf0); /* start reading */
274 d->contr->msdelay(time); /* wait for one rotation */
275 inb(iobase + 0xe4); /* stop reading, don't reset RAM pointer */
276
277 outb(128, iobase + 0xe0); /* add data end mark */
278 outb(0, iobase + 0xe4); /* Reset memory pointer */
279 }
280
281 return 1;
282 }
283
284 static void
285 catweasel_wait_for_writing_flag (catweasel_drive *d,
286 int status, /* Wait for this specified 'status' */
287 int timeout_ms)
288 {
289 while(((inb(d->contr->io_sr) & d->contr->srm_writ) ? 1 : 0) != status && timeout_ms > 0) {
290 d->contr->msdelay(20);
291 timeout_ms -= 20;
292 }
293 }
294
295 int
296 catweasel_write (catweasel_drive *d,
297 int side,
298 int clock,
299 int time)
300 {
301 int iobase = d->contr->iobase;
302
303 if(!(inb(d->contr->io_sr) & d->contr->srm_dchg))
304 return 0;
305
306 if(d->contr->type == CATWEASEL_TYPE_MK1) {
307 CWSetCReg(d->contr, 1<<2, (!side)<<2); /* set disk side */
308
309 inb(iobase+1);
310 outb(clock*128, iobase+3);
311 inb(iobase);
312 outb(128, iobase+3); /* write enable */
313 inb(iobase);
314 inb(iobase);
315 inb(iobase);
316 inb(iobase);
317 inb(iobase);
318 inb(iobase);
319
320 if(time > 0) {
321 outb(0, iobase+5);
322 d->contr->msdelay(time);
323 } else {
324 outb(0, iobase+7);
325 catweasel_wait_for_writing_flag(d, 0, 300);
326 d->contr->msdelay(190);
327 catweasel_wait_for_writing_flag(d, 1, 50);
328 }
329
330 inb(iobase+1);
331 } else {
332 CWSetCReg(d->contr, 1<<6, (!side)<<6); /* set disk side */
333
334 outb(0, iobase + 0xe4); /* Reset memory pointer */
335 switch(clock) {
336 case 0: /* 28MHz */
337 outb(128, iobase + 0xec);
338 break;
339 case 1: /* 14MHz */
340 outb(0, iobase + 0xec);
341 break;
342 }
343 inb(iobase + 0xe0);
344 outb(128, iobase + 0xec); /* write enable */
345 inb(iobase + 0xe0);
346 inb(iobase + 0xe0);
347 inb(iobase + 0xe0);
348 inb(iobase + 0xe0);
349 inb(iobase + 0xe0);
350 inb(iobase + 0xe0);
351
352 if(time > 0) {
353 outb(0, iobase + 0xf4); /* unconditional write START */
354 d->contr->msdelay(time);
355 } else {
356 outb(0, iobase + 0xf0); /* ?????? indexed write START */
357 catweasel_wait_for_writing_flag(d, 0, 300);
358 d->contr->msdelay(190);
359 catweasel_wait_for_writing_flag(d, 1, 50);
360 }
361
362 inb(iobase + 0xe4); /* Abort writing */
363 inb(iobase + 0xe4); /* Reset memory pointer */
364 }
365
366 return 1;
367 }