ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/cwcbm/catweasel.c
Revision: 1.1
Committed: 2004-01-07T15:37:45Z (20 years, 2 months ago) by cebix
Content type: text/plain
Branch point for: MAIN, cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.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     }