| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: fd.c,v 1.74 2010/04/07 13:14:23 tsutsui Exp $ */ | | 1 | /* $NetBSD: fd.c,v 1.75 2010/04/07 13:53:05 tsutsui Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1995 Leo Weppelman. | | 4 | * Copyright (c) 1995 Leo Weppelman. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -34,27 +34,27 @@ | | | @@ -34,27 +34,27 @@ |
34 | * use of some special DMA accessing code. | | 34 | * use of some special DMA accessing code. |
35 | * | | 35 | * |
36 | * Interrupts from the FDC are in fact DMA interrupts which get their | | 36 | * Interrupts from the FDC are in fact DMA interrupts which get their |
37 | * first level handling in 'dma.c' . If the floppy driver is currently | | 37 | * first level handling in 'dma.c' . If the floppy driver is currently |
38 | * using DMA the interrupt is signalled to 'fdcint'. | | 38 | * using DMA the interrupt is signalled to 'fdcint'. |
39 | * | | 39 | * |
40 | * TODO: | | 40 | * TODO: |
41 | * - Test it with 2 drives (I don't have them) | | 41 | * - Test it with 2 drives (I don't have them) |
42 | * - Test it with an HD-drive (Don't have that either) | | 42 | * - Test it with an HD-drive (Don't have that either) |
43 | * - Finish ioctl's | | 43 | * - Finish ioctl's |
44 | */ | | 44 | */ |
45 | | | 45 | |
46 | #include <sys/cdefs.h> | | 46 | #include <sys/cdefs.h> |
47 | __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.74 2010/04/07 13:14:23 tsutsui Exp $"); | | 47 | __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.75 2010/04/07 13:53:05 tsutsui Exp $"); |
48 | | | 48 | |
49 | #include <sys/param.h> | | 49 | #include <sys/param.h> |
50 | #include <sys/systm.h> | | 50 | #include <sys/systm.h> |
51 | #include <sys/callout.h> | | 51 | #include <sys/callout.h> |
52 | #include <sys/kernel.h> | | 52 | #include <sys/kernel.h> |
53 | #include <sys/malloc.h> | | 53 | #include <sys/malloc.h> |
54 | #include <sys/buf.h> | | 54 | #include <sys/buf.h> |
55 | #include <sys/bufq.h> | | 55 | #include <sys/bufq.h> |
56 | #include <sys/proc.h> | | 56 | #include <sys/proc.h> |
57 | #include <sys/device.h> | | 57 | #include <sys/device.h> |
58 | #include <sys/ioctl.h> | | 58 | #include <sys/ioctl.h> |
59 | #include <sys/fcntl.h> | | 59 | #include <sys/fcntl.h> |
60 | #include <sys/conf.h> | | 60 | #include <sys/conf.h> |
| @@ -62,26 +62,28 @@ __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.74 | | | @@ -62,26 +62,28 @@ __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.74 |
62 | #include <sys/disk.h> | | 62 | #include <sys/disk.h> |
63 | #include <sys/dkbad.h> | | 63 | #include <sys/dkbad.h> |
64 | #include <atari/atari/device.h> | | 64 | #include <atari/atari/device.h> |
65 | #include <atari/atari/stalloc.h> | | 65 | #include <atari/atari/stalloc.h> |
66 | #include <machine/disklabel.h> | | 66 | #include <machine/disklabel.h> |
67 | #include <machine/iomap.h> | | 67 | #include <machine/iomap.h> |
68 | #include <machine/mfp.h> | | 68 | #include <machine/mfp.h> |
69 | #include <machine/dma.h> | | 69 | #include <machine/dma.h> |
70 | #include <machine/video.h> | | 70 | #include <machine/video.h> |
71 | #include <machine/cpu.h> | | 71 | #include <machine/cpu.h> |
72 | #include <atari/dev/ym2149reg.h> | | 72 | #include <atari/dev/ym2149reg.h> |
73 | #include <atari/dev/fdreg.h> | | 73 | #include <atari/dev/fdreg.h> |
74 | | | 74 | |
| | | 75 | #include "ioconf.h" |
| | | 76 | |
75 | /* | | 77 | /* |
76 | * Be verbose for debugging | | 78 | * Be verbose for debugging |
77 | */ | | 79 | */ |
78 | /*#define FLP_DEBUG 1 */ | | 80 | /*#define FLP_DEBUG 1 */ |
79 | | | 81 | |
80 | #define FDC_MAX_DMA_AD 0x1000000 /* No DMA possible beyond */ | | 82 | #define FDC_MAX_DMA_AD 0x1000000 /* No DMA possible beyond */ |
81 | | | 83 | |
82 | /* Parameters for the disk drive. */ | | 84 | /* Parameters for the disk drive. */ |
83 | #define SECTOR_SIZE 512 /* physical sector size in bytes */ | | 85 | #define SECTOR_SIZE 512 /* physical sector size in bytes */ |
84 | #define NR_DRIVES 2 /* maximum number of drives */ | | 86 | #define NR_DRIVES 2 /* maximum number of drives */ |
85 | #define NR_TYPES 3 /* number of diskette/drive combinations*/ | | 87 | #define NR_TYPES 3 /* number of diskette/drive combinations*/ |
86 | #define MAX_ERRORS 10 /* how often to try rd/wt before quitting*/ | | 88 | #define MAX_ERRORS 10 /* how often to try rd/wt before quitting*/ |
87 | #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */ | | 89 | #define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */ |
| @@ -111,52 +113,52 @@ __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.74 | | | @@ -111,52 +113,52 @@ __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.74 |
111 | #define FLP_HD 1 /* High density */ | | 113 | #define FLP_HD 1 /* High density */ |
112 | | | 114 | |
113 | | | 115 | |
114 | #define b_block b_resid /* FIXME: this is not the place */ | | 116 | #define b_block b_resid /* FIXME: this is not the place */ |
115 | | | 117 | |
116 | /* | | 118 | /* |
117 | * Global data for all physical floppy devices | | 119 | * Global data for all physical floppy devices |
118 | */ | | 120 | */ |
119 | static short selected = 0; /* drive/head currently selected*/ | | 121 | static short selected = 0; /* drive/head currently selected*/ |
120 | static short motoron = 0; /* motor is spinning */ | | 122 | static short motoron = 0; /* motor is spinning */ |
121 | static short nopens = 0; /* Number of opens executed */ | | 123 | static short nopens = 0; /* Number of opens executed */ |
122 | | | 124 | |
123 | static short fd_state = FLP_IDLE; /* Current driver state */ | | 125 | static short fd_state = FLP_IDLE; /* Current driver state */ |
124 | static int lock_stat= 0; /* DMA locking status */ | | 126 | static int lock_stat = 0; /* DMA locking status */ |
125 | static short fd_cmd = 0; /* command being executed */ | | 127 | static short fd_cmd = 0; /* command being executed */ |
126 | static const char *fd_error= NULL; /* error from fd_xfer_ok() */ | | 128 | static const char *fd_error = NULL; /* error from fd_xfer_ok() */ |
127 | | | 129 | |
128 | /* | | 130 | /* |
129 | * Private per device data | | 131 | * Private per device data |
130 | */ | | 132 | */ |
131 | struct fd_softc { | | 133 | struct fd_softc { |
132 | device_t sc_dev; /* generic device info */ | | 134 | device_t sc_dev; /* generic device info */ |
133 | struct disk dkdev; /* generic disk info */ | | 135 | struct disk dkdev; /* generic disk info */ |
134 | struct bufq_state *bufq; /* queue of buf's */ | | 136 | struct bufq_state *bufq; /* queue of buf's */ |
135 | struct callout sc_motor_ch; | | 137 | struct callout sc_motor_ch; |
136 | int unit; /* unit for atari controlling hw*/ | | 138 | int unit; /* unit for atari controlling hw*/ |
137 | int nheads; /* number of heads in use */ | | 139 | int nheads; /* number of heads in use */ |
138 | int nsectors; /* number of sectors/track */ | | 140 | int nsectors; /* number of sectors/track */ |
139 | int density; /* density code */ | | 141 | int density; /* density code */ |
140 | int nblocks; /* number of blocks on disk */ | | 142 | int nblocks; /* number of blocks on disk */ |
141 | int curtrk; /* track head positioned on */ | | 143 | int curtrk; /* track head positioned on */ |
142 | short flags; /* misc flags */ | | 144 | short flags; /* misc flags */ |
143 | short part; /* Current open partition */ | | 145 | short part; /* Current open partition */ |
144 | int sector; /* logical sector for I/O */ | | 146 | int sector; /* logical sector for I/O */ |
145 | char *io_data; /* KVA for data transfer */ | | 147 | uint8_t *io_data; /* KVA for data transfer */ |
146 | int io_bytes; /* bytes left for I/O */ | | 148 | int io_bytes; /* bytes left for I/O */ |
147 | int io_dir; /* B_READ/B_WRITE */ | | 149 | int io_dir; /* B_READ/B_WRITE */ |
148 | int errcnt; /* current error count */ | | 150 | int errcnt; /* current error count */ |
149 | u_char *bounceb; /* Bounce buffer */ | | 151 | uint8_t *bounceb; /* Bounce buffer */ |
150 | | | 152 | |
151 | }; | | 153 | }; |
152 | | | 154 | |
153 | /* | | 155 | /* |
154 | * Flags in fd_softc: | | 156 | * Flags in fd_softc: |
155 | */ | | 157 | */ |
156 | #define FLPF_NOTRESP 0x001 /* Unit not responding */ | | 158 | #define FLPF_NOTRESP 0x001 /* Unit not responding */ |
157 | #define FLPF_ISOPEN 0x002 /* Unit is open */ | | 159 | #define FLPF_ISOPEN 0x002 /* Unit is open */ |
158 | #define FLPF_SPARE 0x004 /* Not used */ | | 160 | #define FLPF_SPARE 0x004 /* Not used */ |
159 | #define FLPF_HAVELAB 0x008 /* We have a valid label */ | | 161 | #define FLPF_HAVELAB 0x008 /* We have a valid label */ |
160 | #define FLPF_BOUNCE 0x010 /* Now using the bounce buffer */ | | 162 | #define FLPF_BOUNCE 0x010 /* Now using the bounce buffer */ |
161 | #define FLPF_WRTPROT 0x020 /* Unit is write-protected */ | | 163 | #define FLPF_WRTPROT 0x020 /* Unit is write-protected */ |
162 | #define FLPF_EMPTY 0x040 /* Unit is empty */ | | 164 | #define FLPF_EMPTY 0x040 /* Unit is empty */ |
| @@ -207,644 +209,655 @@ static void fdstatus(struct fd_softc *); | | | @@ -207,644 +209,655 @@ static void fdstatus(struct fd_softc *); |
207 | static void fd_xfer(struct fd_softc *); | | 209 | static void fd_xfer(struct fd_softc *); |
208 | static void fdcint(struct fd_softc *); | | 210 | static void fdcint(struct fd_softc *); |
209 | static int fd_xfer_ok(struct fd_softc *); | | 211 | static int fd_xfer_ok(struct fd_softc *); |
210 | static void fdmotoroff(struct fd_softc *); | | 212 | static void fdmotoroff(struct fd_softc *); |
211 | static void fdminphys(struct buf *); | | 213 | static void fdminphys(struct buf *); |
212 | static void fdtestdrv(struct fd_softc *); | | 214 | static void fdtestdrv(struct fd_softc *); |
213 | static void fdgetdefaultlabel(struct fd_softc *, struct disklabel *, | | 215 | static void fdgetdefaultlabel(struct fd_softc *, struct disklabel *, |
214 | int); | | 216 | int); |
215 | static int fdgetdisklabel(struct fd_softc *, dev_t); | | 217 | static int fdgetdisklabel(struct fd_softc *, dev_t); |
216 | static int fdselect(int, int, int); | | 218 | static int fdselect(int, int, int); |
217 | static void fddeselect(void); | | 219 | static void fddeselect(void); |
218 | static void fdmoff(struct fd_softc *); | | 220 | static void fdmoff(struct fd_softc *); |
219 | | | 221 | |
220 | static inline u_char read_fdreg(u_short); | | 222 | static u_short rd_cfg_switch(void); |
| | | 223 | |
| | | 224 | static inline uint8_t read_fdreg(u_short); |
221 | static inline void write_fdreg(u_short, u_short); | | 225 | static inline void write_fdreg(u_short, u_short); |
222 | static inline u_char read_dmastat(void); | | 226 | static inline uint8_t read_dmastat(void); |
223 | | | 227 | |
224 | static inline u_char read_fdreg(u_short regno) | | 228 | static inline |
| | | 229 | uint8_t read_fdreg(u_short regno) |
225 | { | | 230 | { |
| | | 231 | |
226 | DMA->dma_mode = regno; | | 232 | DMA->dma_mode = regno; |
227 | return(DMA->dma_data); | | 233 | return DMA->dma_data; |
228 | } | | 234 | } |
229 | | | 235 | |
230 | static inline void write_fdreg(u_short regno, u_short val) | | 236 | static inline |
| | | 237 | void write_fdreg(u_short regno, u_short val) |
231 | { | | 238 | { |
| | | 239 | |
232 | DMA->dma_mode = regno; | | 240 | DMA->dma_mode = regno; |
233 | DMA->dma_data = val; | | 241 | DMA->dma_data = val; |
234 | } | | 242 | } |
235 | | | 243 | |
236 | static inline u_char read_dmastat(void) | | 244 | static inline |
| | | 245 | uint8_t read_dmastat(void) |
237 | { | | 246 | { |
| | | 247 | |
238 | DMA->dma_mode = FDC_CS | DMA_SCREG; | | 248 | DMA->dma_mode = FDC_CS | DMA_SCREG; |
239 | return(DMA->dma_stat); | | 249 | return DMA->dma_stat; |
240 | } | | 250 | } |
241 | | | 251 | |
242 | /* | | 252 | /* |
243 | * Config switch stuff. Used only for the floppy type for now. That's | | 253 | * Config switch stuff. Used only for the floppy type for now. That's |
244 | * why it's here... | | 254 | * why it's here... |
245 | * XXX: If needed in more places, it should be moved to it's own include file. | | 255 | * XXX: If needed in more places, it should be moved to it's own include file. |
246 | * Note: This location _must_ be read as an u_short. Failure to do so | | 256 | * Note: This location _must_ be read as an u_short. Failure to do so |
247 | * will return garbage! | | 257 | * will return garbage! |
248 | */ | | 258 | */ |
249 | static u_short rd_cfg_switch(void); | | 259 | static u_short |
250 | static u_short rd_cfg_switch(void) | | 260 | rd_cfg_switch(void) |
251 | { | | 261 | { |
252 | return(*((volatile u_short *)AD_CFG_SWITCH)); | | 262 | |
| | | 263 | return *(volatile u_short *)AD_CFG_SWITCH; |
253 | } | | 264 | } |
254 | | | 265 | |
255 | /* | | 266 | /* |
256 | * Switch definitions. | | 267 | * Switch definitions. |
257 | * Note: ON reads as a zero bit! | | 268 | * Note: ON reads as a zero bit! |
258 | */ | | 269 | */ |
259 | #define CFG_SWITCH_NOHD 0x4000 | | 270 | #define CFG_SWITCH_NOHD 0x4000 |
260 | | | 271 | |
261 | /* | | 272 | /* |
262 | * Autoconfig stuff.... | | 273 | * Autoconfig stuff.... |
263 | */ | | 274 | */ |
264 | extern struct cfdriver fd_cd; | | | |
265 | | | | |
266 | static int fdcmatch(device_t, cfdata_t, void *); | | 275 | static int fdcmatch(device_t, cfdata_t, void *); |
267 | static int fdcprint(void *, const char *); | | 276 | static int fdcprint(void *, const char *); |
268 | static void fdcattach(device_t, device_t, void *); | | 277 | static void fdcattach(device_t, device_t, void *); |
269 | | | 278 | |
270 | CFATTACH_DECL_NEW(fdc, 0, | | 279 | CFATTACH_DECL_NEW(fdc, 0, |
271 | fdcmatch, fdcattach, NULL, NULL); | | 280 | fdcmatch, fdcattach, NULL, NULL); |
272 | | | 281 | |
273 | const struct bdevsw fd_bdevsw = { | | 282 | const struct bdevsw fd_bdevsw = { |
274 | fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK | | 283 | fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK |
275 | }; | | 284 | }; |
276 | | | 285 | |
277 | const struct cdevsw fd_cdevsw = { | | 286 | const struct cdevsw fd_cdevsw = { |
278 | fdopen, fdclose, fdread, fdwrite, fdioctl, | | 287 | fdopen, fdclose, fdread, fdwrite, fdioctl, |
279 | nostop, notty, nopoll, nommap, nokqfilter, D_DISK | | 288 | nostop, notty, nopoll, nommap, nokqfilter, D_DISK |
280 | }; | | 289 | }; |
281 | | | 290 | |
282 | static int | | 291 | static int |
283 | fdcmatch(device_t parent, cfdata_t match, void *aux) | | 292 | fdcmatch(device_t parent, cfdata_t match, void *aux) |
284 | { | | 293 | { |
285 | static int fdc_matched = 0; | | 294 | static int fdc_matched = 0; |
286 | | | 295 | |
287 | /* Match only once */ | | 296 | /* Match only once */ |
288 | if(strcmp("fdc", aux) || fdc_matched) | | 297 | if (strcmp("fdc", aux) || fdc_matched) |
289 | return(0); | | 298 | return 0; |
290 | fdc_matched = 1; | | 299 | fdc_matched = 1; |
291 | return(1); | | 300 | return 1; |
292 | } | | 301 | } |
293 | | | 302 | |
294 | static void | | 303 | static void |
295 | fdcattach(device_t parent, device_t self, void *aux) | | 304 | fdcattach(device_t parent, device_t self, void *aux) |
296 | { | | 305 | { |
297 | struct fd_softc fdsoftc; | | 306 | struct fd_softc fdsoftc; |
298 | int i, nfound, first_found; | | 307 | int i, nfound, first_found; |
299 | | | 308 | |
300 | nfound = first_found = 0; | | 309 | nfound = first_found = 0; |
301 | printf("\n"); | | 310 | printf("\n"); |
302 | fddeselect(); | | 311 | fddeselect(); |
303 | for(i = 0; i < NR_DRIVES; i++) { | | 312 | for (i = 0; i < NR_DRIVES; i++) { |
304 | | | 313 | |
305 | /* | | 314 | /* |
306 | * Test if unit is present | | 315 | * Test if unit is present |
307 | */ | | 316 | */ |
308 | fdsoftc.unit = i; | | 317 | fdsoftc.unit = i; |
309 | fdsoftc.flags = 0; | | 318 | fdsoftc.flags = 0; |
310 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdtestdrv, &fdsoftc, | | 319 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdtestdrv, &fdsoftc, |
311 | &lock_stat, 0); | | 320 | &lock_stat, 0); |
312 | st_dmafree(&fdsoftc, &lock_stat); | | 321 | st_dmafree(&fdsoftc, &lock_stat); |
313 | | | 322 | |
314 | if(!(fdsoftc.flags & FLPF_NOTRESP)) { | | 323 | if ((fdsoftc.flags & FLPF_NOTRESP) == 0) { |
315 | if(!nfound) | | 324 | if (nfound == 0) |
316 | first_found = i; | | 325 | first_found = i; |
317 | nfound++; | | 326 | nfound++; |
318 | config_found(self, (void*)i, fdcprint); | | 327 | config_found(self, (void *)i, fdcprint); |
319 | } | | 328 | } |
320 | } | | 329 | } |
321 | | | 330 | |
322 | if(nfound) { | | 331 | if (nfound != 0) { |
323 | struct fd_softc *fdsc = | | 332 | struct fd_softc *fdsc = |
324 | device_lookup_private(&fd_cd, first_found); | | 333 | device_lookup_private(&fd_cd, first_found); |
325 | | | 334 | |
326 | /* | | 335 | /* |
327 | * Make sure motor will be turned of when a floppy is | | 336 | * Make sure motor will be turned of when a floppy is |
328 | * inserted in the first selected drive. | | 337 | * inserted in the first selected drive. |
329 | */ | | 338 | */ |
330 | fdselect(first_found, 0, FLP_DD); | | 339 | fdselect(first_found, 0, FLP_DD); |
331 | fd_state = FLP_MON; | | 340 | fd_state = FLP_MON; |
332 | callout_reset(&fdsc->sc_motor_ch, 0, (FPV)fdmotoroff, fdsc); | | 341 | callout_reset(&fdsc->sc_motor_ch, 0, (FPV)fdmotoroff, fdsc); |
333 | | | 342 | |
334 | /* | | 343 | /* |
335 | * enable disk related interrupts | | 344 | * enable disk related interrupts |
336 | */ | | 345 | */ |
337 | MFP->mf_ierb |= IB_DINT; | | 346 | MFP->mf_ierb |= IB_DINT; |
338 | MFP->mf_iprb = (u_int8_t)~IB_DINT; | | 347 | MFP->mf_iprb = (uint8_t)~IB_DINT; |
339 | MFP->mf_imrb |= IB_DINT; | | 348 | MFP->mf_imrb |= IB_DINT; |
340 | } | | 349 | } |
341 | } | | 350 | } |
342 | | | 351 | |
343 | static int | | 352 | static int |
344 | fdcprint(void *aux, const char *pnp) | | 353 | fdcprint(void *aux, const char *pnp) |
345 | { | | 354 | { |
| | | 355 | |
346 | if (pnp != NULL) | | 356 | if (pnp != NULL) |
347 | aprint_normal("fd%d at %s:", (int)aux, pnp); | | 357 | aprint_normal("fd%d at %s:", (int)aux, pnp); |
348 | | | 358 | |
349 | return(UNCONF); | | 359 | return UNCONF; |
350 | } | | 360 | } |
351 | | | 361 | |
352 | static int fdmatch(device_t, cfdata_t, void *); | | 362 | static int fdmatch(device_t, cfdata_t, void *); |
353 | static void fdattach(device_t, device_t, void *); | | 363 | static void fdattach(device_t, device_t, void *); |
354 | | | 364 | |
355 | struct dkdriver fddkdriver = { fdstrategy }; | | 365 | struct dkdriver fddkdriver = { fdstrategy }; |
356 | | | 366 | |
357 | CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc), | | 367 | CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc), |
358 | fdmatch, fdattach, NULL, NULL); | | 368 | fdmatch, fdattach, NULL, NULL); |
359 | | | 369 | |
360 | extern struct cfdriver fd_cd; | | | |
361 | | | | |
362 | static int | | 370 | static int |
363 | fdmatch(device_t parent, cfdata_t match, void *aux) | | 371 | fdmatch(device_t parent, cfdata_t match, void *aux) |
364 | { | | 372 | { |
365 | return(1); | | 373 | |
| | | 374 | return 1; |
366 | } | | 375 | } |
367 | | | 376 | |
368 | static void | | 377 | static void |
369 | fdattach(device_t parent, device_t self, void *aux) | | 378 | fdattach(device_t parent, device_t self, void *aux) |
370 | { | | 379 | { |
371 | struct fd_softc *sc; | | 380 | struct fd_softc *sc; |
372 | struct fd_types *type; | | 381 | struct fd_types *type; |
373 | u_short swtch; | | 382 | u_short swtch; |
374 | | | 383 | |
375 | sc = device_private(self); | | 384 | sc = device_private(self); |
376 | sc->sc_dev = self; | | 385 | sc->sc_dev = self; |
377 | | | 386 | |
378 | callout_init(&sc->sc_motor_ch, 0); | | 387 | callout_init(&sc->sc_motor_ch, 0); |
379 | | | 388 | |
380 | /* | | 389 | /* |
381 | * Find out if an Ajax chip might be installed. Set the default | | 390 | * Find out if an Ajax chip might be installed. Set the default |
382 | * floppy type accordingly. | | 391 | * floppy type accordingly. |
383 | */ | | 392 | */ |
384 | swtch = rd_cfg_switch(); | | 393 | swtch = rd_cfg_switch(); |
385 | def_type = (swtch & CFG_SWITCH_NOHD) ? FLP_TYPE_720 : FLP_TYPE_144; | | 394 | def_type = (swtch & CFG_SWITCH_NOHD) ? FLP_TYPE_720 : FLP_TYPE_144; |
386 | type = &fdtypes[def_type]; | | 395 | type = &fdtypes[def_type]; |
387 | | | 396 | |
388 | aprint_normal(": %s %d cyl, %d head, %d sec\n", type->descr, | | 397 | aprint_normal(": %s %d cyl, %d head, %d sec\n", type->descr, |
389 | type->nblocks / (type->nsectors * type->nheads), type->nheads, | | 398 | type->nblocks / (type->nsectors * type->nheads), type->nheads, |
390 | type->nsectors); | | 399 | type->nsectors); |
391 | | | 400 | |
392 | /* | | 401 | /* |
393 | * Initialize and attach the disk structure. | | 402 | * Initialize and attach the disk structure. |
394 | */ | | 403 | */ |
395 | disk_init(&sc->dkdev, device_xname(sc->sc_dev), &fddkdriver); | | 404 | disk_init(&sc->dkdev, device_xname(sc->sc_dev), &fddkdriver); |
396 | disk_attach(&sc->dkdev); | | 405 | disk_attach(&sc->dkdev); |
397 | } | | 406 | } |
398 | | | 407 | |
399 | int | | 408 | int |
400 | fdioctl(dev_t dev, u_long cmd, void * addr, int flag, struct lwp *l) | | 409 | fdioctl(dev_t dev, u_long cmd, void * addr, int flag, struct lwp *l) |
401 | { | | 410 | { |
402 | struct fd_softc *sc; | | 411 | struct fd_softc *sc; |
403 | | | 412 | |
404 | sc = device_lookup_private(&fd_cd, DISKUNIT(dev)); | | 413 | sc = device_lookup_private(&fd_cd, DISKUNIT(dev)); |
405 | | | 414 | |
406 | if((sc->flags & FLPF_HAVELAB) == 0) | | 415 | if ((sc->flags & FLPF_HAVELAB) == 0) |
407 | return(EBADF); | | 416 | return EBADF; |
408 | | | 417 | |
409 | switch(cmd) { | | 418 | switch (cmd) { |
410 | case DIOCSBAD: | | 419 | case DIOCSBAD: |
411 | return(EINVAL); | | 420 | return EINVAL; |
412 | case DIOCGDINFO: | | 421 | case DIOCGDINFO: |
413 | *(struct disklabel *)addr = *(sc->dkdev.dk_label); | | 422 | *(struct disklabel *)addr = *(sc->dkdev.dk_label); |
414 | return(0); | | 423 | return 0; |
415 | case DIOCGPART: | | 424 | case DIOCGPART: |
416 | ((struct partinfo *)addr)->disklab = | | 425 | ((struct partinfo *)addr)->disklab = sc->dkdev.dk_label; |
417 | sc->dkdev.dk_label; | | 426 | ((struct partinfo *)addr)->part = |
418 | ((struct partinfo *)addr)->part = | | 427 | &sc->dkdev.dk_label->d_partitions[RAW_PART]; |
419 | &sc->dkdev.dk_label->d_partitions[RAW_PART]; | | 428 | return 0; |
420 | return(0); | | | |
421 | #ifdef notyet /* XXX LWP */ | | 429 | #ifdef notyet /* XXX LWP */ |
422 | case DIOCSRETRIES: | | 430 | case DIOCSRETRIES: |
423 | case DIOCSSTEP: | | 431 | case DIOCSSTEP: |
424 | case DIOCSDINFO: | | 432 | case DIOCSDINFO: |
425 | case DIOCWDINFO: | | 433 | case DIOCWDINFO: |
426 | case DIOCWLABEL: | | 434 | case DIOCWLABEL: |
427 | break; | | 435 | break; |
428 | #endif /* notyet */ | | 436 | #endif /* notyet */ |
429 | case DIOCGDEFLABEL: | | 437 | case DIOCGDEFLABEL: |
430 | fdgetdefaultlabel(sc, (struct disklabel *)addr, | | 438 | fdgetdefaultlabel(sc, (struct disklabel *)addr, RAW_PART); |
431 | RAW_PART); | | 439 | return 0; |
432 | return(0); | | | |
433 | } | | 440 | } |
434 | return(ENOTTY); | | 441 | return ENOTTY; |
435 | } | | 442 | } |
436 | | | 443 | |
437 | /* | | 444 | /* |
438 | * Open the device. If this is the first open on both the floppy devices, | | 445 | * Open the device. If this is the first open on both the floppy devices, |
439 | * intialize the controller. | | 446 | * intialize the controller. |
440 | * Note that partition info on the floppy device is used to distinguise | | 447 | * Note that partition info on the floppy device is used to distinguise |
441 | * between 780Kb and 360Kb floppy's. | | 448 | * between 780Kb and 360Kb floppy's. |
442 | * partition 0: 360Kb | | 449 | * partition 0: 360Kb |
443 | * partition 1: 780Kb | | 450 | * partition 1: 780Kb |
444 | */ | | 451 | */ |
445 | int | | 452 | int |
446 | fdopen(dev_t dev, int flags, int devtype, struct lwp *l) | | 453 | fdopen(dev_t dev, int flags, int devtype, struct lwp *l) |
447 | { | | 454 | { |
448 | struct fd_softc *sc; | | 455 | struct fd_softc *sc; |
449 | int sps; | | 456 | int s; |
450 | | | 457 | |
451 | #ifdef FLP_DEBUG | | 458 | #ifdef FLP_DEBUG |
452 | printf("fdopen dev=0x%x\n", dev); | | 459 | printf("fdopen dev=0x%x\n", dev); |
453 | #endif | | 460 | #endif |
454 | | | 461 | |
455 | if(FLP_TYPE(dev) >= NR_TYPES) | | 462 | if (FLP_TYPE(dev) >= NR_TYPES) |
456 | return(ENXIO); | | 463 | return ENXIO; |
457 | | | 464 | |
458 | if((sc = device_lookup_private(&fd_cd, DISKUNIT(dev))) == NULL) | | 465 | if ((sc = device_lookup_private(&fd_cd, DISKUNIT(dev))) == NULL) |
459 | return(ENXIO); | | 466 | return ENXIO; |
460 | | | 467 | |
461 | /* | | 468 | /* |
462 | * If no floppy currently open, reset the controller and select | | 469 | * If no floppy currently open, reset the controller and select |
463 | * floppy type. | | 470 | * floppy type. |
464 | */ | | 471 | */ |
465 | if(!nopens) { | | 472 | if (nopens == 0) { |
466 | | | 473 | |
467 | #ifdef FLP_DEBUG | | 474 | #ifdef FLP_DEBUG |
468 | printf("fdopen device not yet open\n"); | | 475 | printf("fdopen device not yet open\n"); |
469 | #endif | | 476 | #endif |
470 | nopens++; | | 477 | nopens++; |
471 | write_fdreg(FDC_CS, IRUPT); | | 478 | write_fdreg(FDC_CS, IRUPT); |
472 | delay(40); | | 479 | delay(40); |
473 | } | | 480 | } |
474 | | | 481 | |
475 | /* | | 482 | /* |
476 | * Sleep while other process is opening the device | | 483 | * Sleep while other process is opening the device |
477 | */ | | 484 | */ |
478 | sps = splbio(); | | 485 | s = splbio(); |
479 | while(sc->flags & FLPF_INOPEN) | | 486 | while (sc->flags & FLPF_INOPEN) |
480 | tsleep((void *)sc, PRIBIO, "fdopen", 0); | | 487 | tsleep((void *)sc, PRIBIO, "fdopen", 0); |
481 | splx(sps); | | 488 | splx(s); |
482 | | | 489 | |
483 | if(!(sc->flags & FLPF_ISOPEN)) { | | 490 | if((sc->flags & FLPF_ISOPEN) == 0) { |
484 | /* | | 491 | /* |
485 | * Initialise some driver values. | | 492 | * Initialise some driver values. |
486 | */ | | 493 | */ |
487 | int type; | | 494 | int type; |
488 | void *addr; | | 495 | void *addr; |
489 | | | 496 | |
490 | type = FLP_TYPE(dev); | | 497 | type = FLP_TYPE(dev); |
491 | | | 498 | |
492 | bufq_alloc(&sc->bufq, "disksort", BUFQ_SORT_RAWBLOCK); | | 499 | bufq_alloc(&sc->bufq, "disksort", BUFQ_SORT_RAWBLOCK); |
493 | sc->unit = DISKUNIT(dev); | | 500 | sc->unit = DISKUNIT(dev); |
494 | sc->part = RAW_PART; | | 501 | sc->part = RAW_PART; |
495 | sc->nheads = fdtypes[type].nheads; | | 502 | sc->nheads = fdtypes[type].nheads; |
496 | sc->nsectors = fdtypes[type].nsectors; | | 503 | sc->nsectors = fdtypes[type].nsectors; |
497 | sc->nblocks = fdtypes[type].nblocks; | | 504 | sc->nblocks = fdtypes[type].nblocks; |
498 | sc->density = fdtypes[type].density; | | 505 | sc->density = fdtypes[type].density; |
499 | sc->curtrk = INV_TRK; | | 506 | sc->curtrk = INV_TRK; |
500 | sc->sector = 0; | | 507 | sc->sector = 0; |
501 | sc->errcnt = 0; | | 508 | sc->errcnt = 0; |
502 | sc->bounceb = (u_char*)alloc_stmem(SECTOR_SIZE, &addr); | | 509 | sc->bounceb = alloc_stmem(SECTOR_SIZE, &addr); |
503 | if(sc->bounceb == NULL) | | 510 | if (sc->bounceb == NULL) |
504 | return(ENOMEM); /* XXX */ | | 511 | return ENOMEM; /* XXX */ |
505 | | | 512 | |
506 | /* | | 513 | /* |
507 | * Go get write protect + loaded status | | 514 | * Go get write protect + loaded status |
508 | */ | | 515 | */ |
509 | sc->flags |= FLPF_INOPEN|FLPF_GETSTAT; | | 516 | sc->flags |= FLPF_INOPEN|FLPF_GETSTAT; |
510 | sps = splbio(); | | 517 | s = splbio(); |
511 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdstatus, sc, | | 518 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdstatus, sc, |
512 | &lock_stat, 0); | | 519 | &lock_stat, 0); |
513 | while(sc->flags & FLPF_GETSTAT) | | 520 | while ((sc->flags & FLPF_GETSTAT) != 0) |
514 | tsleep((void *)sc, PRIBIO, "fdopen", 0); | | 521 | tsleep((void *)sc, PRIBIO, "fdopen", 0); |
515 | splx(sps); | | 522 | splx(s); |
516 | wakeup((void *)sc); | | 523 | wakeup((void *)sc); |
517 | | | 524 | |
518 | if((sc->flags & FLPF_WRTPROT) && (flags & FWRITE)) { | | 525 | if ((sc->flags & FLPF_WRTPROT) != 0 && |
| | | 526 | (flags & FWRITE) != 0) { |
519 | sc->flags = 0; | | 527 | sc->flags = 0; |
520 | return(EPERM); | | 528 | return EPERM; |
521 | } | | 529 | } |
522 | if(sc->flags & FLPF_EMPTY) { | | 530 | if ((sc->flags & FLPF_EMPTY) != 0) { |
523 | sc->flags = 0; | | 531 | sc->flags = 0; |
524 | return(ENXIO); | | 532 | return ENXIO; |
525 | } | | 533 | } |
526 | sc->flags &= ~(FLPF_INOPEN|FLPF_GETSTAT); | | 534 | sc->flags &= ~(FLPF_INOPEN|FLPF_GETSTAT); |
527 | sc->flags |= FLPF_ISOPEN; | | 535 | sc->flags |= FLPF_ISOPEN; |
528 | } | | 536 | } else { |
529 | else { | | | |
530 | /* | | 537 | /* |
531 | * Multiply opens are granted when accessing the same type of | | 538 | * Multiply opens are granted when accessing the same type of |
532 | * floppy (eq. the same partition). | | 539 | * floppy (eq. the same partition). |
533 | */ | | 540 | */ |
534 | if(sc->density != fdtypes[DISKPART(dev)].density) | | 541 | if (sc->density != fdtypes[DISKPART(dev)].density) |
535 | return(ENXIO); /* XXX temporarely out of business */ | | 542 | return ENXIO; /* XXX temporarely out of business */ |
536 | } | | 543 | } |
537 | fdgetdisklabel(sc, dev); | | 544 | fdgetdisklabel(sc, dev); |
538 | #ifdef FLP_DEBUG | | 545 | #ifdef FLP_DEBUG |
539 | printf("fdopen open succeeded on type %d\n", sc->part); | | 546 | printf("fdopen open succeeded on type %d\n", sc->part); |
540 | #endif | | 547 | #endif |
541 | return (0); | | 548 | return 0; |
542 | } | | 549 | } |
543 | | | 550 | |
544 | int | | 551 | int |
545 | fdclose(dev_t dev, int flags, int devtype, struct lwp *l) | | 552 | fdclose(dev_t dev, int flags, int devtype, struct lwp *l) |
546 | { | | 553 | { |
547 | struct fd_softc *sc; | | 554 | struct fd_softc *sc; |
548 | | | 555 | |
549 | sc = device_lookup_private(&fd_cd, DISKUNIT(dev)); | | 556 | sc = device_lookup_private(&fd_cd, DISKUNIT(dev)); |
550 | free_stmem(sc->bounceb); | | 557 | free_stmem(sc->bounceb); |
551 | sc->flags = 0; | | 558 | sc->flags = 0; |
552 | nopens--; | | 559 | nopens--; |
553 | | | 560 | |
554 | #ifdef FLP_DEBUG | | 561 | #ifdef FLP_DEBUG |
555 | printf("Closed floppy device -- nopens: %d\n", nopens); | | 562 | printf("Closed floppy device -- nopens: %d\n", nopens); |
556 | #endif | | 563 | #endif |
557 | return(0); | | 564 | return 0; |
558 | } | | 565 | } |
559 | | | 566 | |
560 | void | | 567 | void |
561 | fdstrategy(struct buf *bp) | | 568 | fdstrategy(struct buf *bp) |
562 | { | | 569 | { |
563 | struct fd_softc *sc; | | 570 | struct fd_softc *sc; |
564 | struct disklabel *lp; | | 571 | struct disklabel *lp; |
565 | int sps, sz; | | 572 | int s, sz; |
566 | | | 573 | |
567 | sc = device_lookup_private(&fd_cd, DISKUNIT(bp->b_dev)); | | 574 | sc = device_lookup_private(&fd_cd, DISKUNIT(bp->b_dev)); |
568 | | | 575 | |
569 | #ifdef FLP_DEBUG | | 576 | #ifdef FLP_DEBUG |
570 | printf("fdstrategy: %p, b_bcount: %ld\n", bp, bp->b_bcount); | | 577 | printf("fdstrategy: %p, b_bcount: %ld\n", bp, bp->b_bcount); |
571 | #endif | | 578 | #endif |
572 | | | 579 | |
573 | /* | | 580 | /* |
574 | * check for valid partition and bounds | | 581 | * check for valid partition and bounds |
575 | */ | | 582 | */ |
576 | lp = sc->dkdev.dk_label; | | 583 | lp = sc->dkdev.dk_label; |
577 | if ((sc->flags & FLPF_HAVELAB) == 0) { | | 584 | if ((sc->flags & FLPF_HAVELAB) == 0) { |
578 | bp->b_error = EIO; | | 585 | bp->b_error = EIO; |
579 | goto done; | | 586 | goto done; |
580 | } | | 587 | } |
581 | if (bp->b_blkno < 0 || (bp->b_bcount % SECTOR_SIZE)) { | | 588 | if (bp->b_blkno < 0 || (bp->b_bcount % SECTOR_SIZE) != 0) { |
582 | bp->b_error = EINVAL; | | 589 | bp->b_error = EINVAL; |
583 | goto done; | | 590 | goto done; |
584 | } | | 591 | } |
585 | if (bp->b_bcount == 0) | | 592 | if (bp->b_bcount == 0) |
586 | goto done; | | 593 | goto done; |
587 | | | 594 | |
588 | sz = howmany(bp->b_bcount, SECTOR_SIZE); | | 595 | sz = howmany(bp->b_bcount, SECTOR_SIZE); |
589 | | | 596 | |
590 | if (bp->b_blkno + sz > sc->nblocks) { | | 597 | if (bp->b_blkno + sz > sc->nblocks) { |
591 | sz = sc->nblocks - bp->b_blkno; | | 598 | sz = sc->nblocks - bp->b_blkno; |
592 | if (sz == 0) /* Exactly at EndOfDisk */ | | 599 | if (sz == 0) /* Exactly at EndOfDisk */ |
593 | goto done; | | 600 | goto done; |
594 | if (sz < 0) { /* Past EndOfDisk */ | | 601 | if (sz < 0) { /* Past EndOfDisk */ |
595 | bp->b_error = EINVAL; | | 602 | bp->b_error = EINVAL; |
596 | goto done; | | 603 | goto done; |
597 | } | | 604 | } |
598 | /* Trucate it */ | | 605 | /* Trucate it */ |
599 | if (bp->b_flags & B_RAW) | | 606 | if (bp->b_flags & B_RAW) |
600 | bp->b_bcount = sz << DEV_BSHIFT; | | 607 | bp->b_bcount = sz << DEV_BSHIFT; |
601 | else bp->b_bcount = sz * lp->d_secsize; | | 608 | else |
| | | 609 | bp->b_bcount = sz * lp->d_secsize; |
602 | } | | 610 | } |
603 | | | 611 | |
604 | /* No partition translation. */ | | 612 | /* No partition translation. */ |
605 | bp->b_rawblkno = bp->b_blkno; | | 613 | bp->b_rawblkno = bp->b_blkno; |
606 | | | 614 | |
607 | /* | | 615 | /* |
608 | * queue the buf and kick the low level code | | 616 | * queue the buf and kick the low level code |
609 | */ | | 617 | */ |
610 | sps = splbio(); | | 618 | s = splbio(); |
611 | bufq_put(sc->bufq, bp); /* XXX disksort_cylinder */ | | 619 | bufq_put(sc->bufq, bp); /* XXX disksort_cylinder */ |
612 | if (!lock_stat) { | | 620 | if (!lock_stat) { |
613 | if (fd_state & FLP_MON) | | 621 | if (fd_state & FLP_MON) |
614 | callout_stop(&sc->sc_motor_ch); | | 622 | callout_stop(&sc->sc_motor_ch); |
615 | fd_state = FLP_IDLE; | | 623 | fd_state = FLP_IDLE; |
616 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc, | | 624 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc, |
617 | &lock_stat, 0); | | 625 | &lock_stat, 0); |
618 | } | | 626 | } |
619 | splx(sps); | | 627 | splx(s); |
620 | | | 628 | |
621 | return; | | 629 | return; |
622 | done: | | 630 | done: |
623 | bp->b_resid = bp->b_bcount; | | 631 | bp->b_resid = bp->b_bcount; |
624 | biodone(bp); | | 632 | biodone(bp); |
625 | } | | 633 | } |
626 | | | 634 | |
627 | int | | 635 | int |
628 | fdread(dev_t dev, struct uio *uio, int flags) | | 636 | fdread(dev_t dev, struct uio *uio, int flags) |
629 | { | | 637 | { |
630 | return(physio(fdstrategy, NULL, dev, B_READ, fdminphys, uio)); | | 638 | |
| | | 639 | return physio(fdstrategy, NULL, dev, B_READ, fdminphys, uio); |
631 | } | | 640 | } |
632 | | | 641 | |
633 | int | | 642 | int |
634 | fdwrite(dev_t dev, struct uio *uio, int flags) | | 643 | fdwrite(dev_t dev, struct uio *uio, int flags) |
635 | { | | 644 | { |
636 | return(physio(fdstrategy, NULL, dev, B_WRITE, fdminphys, uio)); | | 645 | |
| | | 646 | return physio(fdstrategy, NULL, dev, B_WRITE, fdminphys, uio); |
637 | } | | 647 | } |
638 | | | 648 | |
639 | /* | | 649 | /* |
640 | * Called through DMA-dispatcher, get status. | | 650 | * Called through DMA-dispatcher, get status. |
641 | */ | | 651 | */ |
642 | static void | | 652 | static void |
643 | fdstatus(struct fd_softc *sc) | | 653 | fdstatus(struct fd_softc *sc) |
644 | { | | 654 | { |
| | | 655 | |
645 | #ifdef FLP_DEBUG | | 656 | #ifdef FLP_DEBUG |
646 | printf("fdstatus\n"); | | 657 | printf("fdstatus\n"); |
647 | #endif | | 658 | #endif |
648 | sc->errcnt = 0; | | 659 | sc->errcnt = 0; |
649 | fd_state = FLP_STAT; | | 660 | fd_state = FLP_STAT; |
650 | fd_xfer(sc); | | 661 | fd_xfer(sc); |
651 | } | | 662 | } |
652 | | | 663 | |
653 | /* | | 664 | /* |
654 | * Called through the DMA-dispatcher. So we know we are the only ones | | 665 | * Called through the DMA-dispatcher. So we know we are the only ones |
655 | * messing with the floppy-controller. | | 666 | * messing with the floppy-controller. |
656 | * Initialize some fields in the fdsoftc for the state-machine and get | | 667 | * Initialize some fields in the fdsoftc for the state-machine and get |
657 | * it going. | | 668 | * it going. |
658 | */ | | 669 | */ |
659 | static void | | 670 | static void |
660 | fdstart(struct fd_softc *sc) | | 671 | fdstart(struct fd_softc *sc) |
661 | { | | 672 | { |
662 | struct buf *bp; | | 673 | struct buf *bp; |
663 | | | 674 | |
664 | bp = bufq_peek(sc->bufq); | | 675 | bp = bufq_peek(sc->bufq); |
665 | sc->sector = bp->b_blkno; /* Start sector for I/O */ | | 676 | sc->sector = bp->b_blkno; /* Start sector for I/O */ |
666 | sc->io_data = bp->b_data; /* KVA base for I/O */ | | 677 | sc->io_data = bp->b_data; /* KVA base for I/O */ |
667 | sc->io_bytes = bp->b_bcount; /* Transfer size in bytes */ | | 678 | sc->io_bytes = bp->b_bcount; /* Transfer size in bytes */ |
668 | sc->io_dir = bp->b_flags & B_READ;/* Direction of transfer */ | | 679 | sc->io_dir = bp->b_flags & B_READ;/* Direction of transfer */ |
669 | sc->errcnt = 0; /* No errors yet */ | | 680 | sc->errcnt = 0; /* No errors yet */ |
670 | fd_state = FLP_XFER; /* Yes, we're going to transfer */ | | 681 | fd_state = FLP_XFER; /* Yes, we're going to transfer */ |
671 | | | 682 | |
672 | /* Instrumentation. */ | | 683 | /* Instrumentation. */ |
673 | disk_busy(&sc->dkdev); | | 684 | disk_busy(&sc->dkdev); |
674 | | | 685 | |
675 | fd_xfer(sc); | | 686 | fd_xfer(sc); |
676 | } | | 687 | } |
677 | | | 688 | |
678 | /* | | 689 | /* |
679 | * The current transaction is finished (for good or bad). Let go of | | 690 | * The current transaction is finished (for good or bad). Let go of |
680 | * the DMA-resources. Call biodone() to finish the transaction. | | 691 | * the DMA-resources. Call biodone() to finish the transaction. |
681 | * Find a new transaction to work on. | | 692 | * Find a new transaction to work on. |
682 | */ | | 693 | */ |
683 | static void | | 694 | static void |
684 | fddone(register struct fd_softc *sc) | | 695 | fddone(register struct fd_softc *sc) |
685 | { | | 696 | { |
686 | struct buf *bp; | | 697 | struct buf *bp; |
687 | struct fd_softc *sc1; | | 698 | struct fd_softc *sc1; |
688 | int i, sps; | | 699 | int i, s; |
689 | | | 700 | |
690 | /* | | 701 | /* |
691 | * Give others a chance to use the DMA. | | 702 | * Give others a chance to use the DMA. |
692 | */ | | 703 | */ |
693 | st_dmafree(sc, &lock_stat); | | 704 | st_dmafree(sc, &lock_stat); |
694 | | | 705 | |
695 | | | 706 | |
696 | if(fd_state != FLP_STAT) { | | 707 | if (fd_state != FLP_STAT) { |
697 | /* | | 708 | /* |
698 | * Finish current transaction. | | 709 | * Finish current transaction. |
699 | */ | | 710 | */ |
700 | sps = splbio(); | | 711 | s = splbio(); |
701 | bp = bufq_get(sc->bufq); | | 712 | bp = bufq_get(sc->bufq); |
702 | if (bp == NULL) | | 713 | if (bp == NULL) |
703 | panic("fddone"); | | 714 | panic("fddone"); |
704 | splx(sps); | | 715 | splx(s); |
705 | | | 716 | |
706 | #ifdef FLP_DEBUG | | 717 | #ifdef FLP_DEBUG |
707 | printf("fddone: unit: %d, buf: %p, resid: %d\n",sc->unit,bp, | | 718 | printf("fddone: unit: %d, buf: %p, resid: %d\n",sc->unit, bp, |
708 | sc->io_bytes); | | 719 | sc->io_bytes); |
709 | #endif | | 720 | #endif |
710 | bp->b_resid = sc->io_bytes; | | 721 | bp->b_resid = sc->io_bytes; |
711 | | | 722 | |
712 | disk_unbusy(&sc->dkdev, (bp->b_bcount - bp->b_resid), | | 723 | disk_unbusy(&sc->dkdev, (bp->b_bcount - bp->b_resid), |
713 | (bp->b_flags & B_READ)); | | 724 | (bp->b_flags & B_READ)); |
714 | | | 725 | |
715 | biodone(bp); | | 726 | biodone(bp); |
716 | } | | 727 | } |
717 | fd_state = FLP_MON; | | 728 | fd_state = FLP_MON; |
718 | | | 729 | |
719 | if(lock_stat) | | 730 | if (lock_stat) |
720 | return; /* XXX Is this possible? */ | | 731 | return; /* XXX Is this possible? */ |
721 | | | 732 | |
722 | /* | | 733 | /* |
723 | * Find a new transaction on round-robin basis. | | 734 | * Find a new transaction on round-robin basis. |
724 | */ | | 735 | */ |
725 | for(i = sc->unit + 1; ;i++) { | | 736 | for (i = sc->unit + 1;; i++) { |
726 | if(i >= fd_cd.cd_ndevs) | | 737 | if (i >= fd_cd.cd_ndevs) |
727 | i = 0; | | 738 | i = 0; |
728 | if((sc1 = device_lookup_private(&fd_cd, i)) == NULL) | | 739 | if ((sc1 = device_lookup_private(&fd_cd, i)) == NULL) |
729 | continue; | | 740 | continue; |
730 | if (bufq_peek(sc1->bufq) != NULL) | | 741 | if (bufq_peek(sc1->bufq) != NULL) |
731 | break; | | 742 | break; |
732 | if(i == sc->unit) { | | 743 | if (i == sc->unit) { |
733 | callout_reset(&sc->sc_motor_ch, FLP_MONDELAY, | | 744 | callout_reset(&sc->sc_motor_ch, FLP_MONDELAY, |
734 | (FPV)fdmotoroff, sc); | | 745 | (FPV)fdmotoroff, sc); |
735 | #ifdef FLP_DEBUG | | 746 | #ifdef FLP_DEBUG |
736 | printf("fddone: Nothing to do\n"); | | 747 | printf("fddone: Nothing to do\n"); |
737 | #endif | | 748 | #endif |
738 | return; /* No work */ | | 749 | return; /* No work */ |
739 | } | | 750 | } |
740 | } | | 751 | } |
741 | fd_state = FLP_IDLE; | | 752 | fd_state = FLP_IDLE; |
742 | #ifdef FLP_DEBUG | | 753 | #ifdef FLP_DEBUG |
743 | printf("fddone: Staring job on unit %d\n", sc1->unit); | | 754 | printf("fddone: Staring job on unit %d\n", sc1->unit); |
744 | #endif | | 755 | #endif |
745 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc1, &lock_stat, 0); | | 756 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc1, &lock_stat, 0); |
746 | } | | 757 | } |
747 | | | 758 | |
748 | static int | | 759 | static int |
749 | fdselect(int drive, int head, int dense) | | 760 | fdselect(int drive, int head, int dense) |
750 | { | | 761 | { |
751 | int i, spinning; | | 762 | int i, spinning; |
| | | 763 | |
752 | #ifdef FLP_DEBUG | | 764 | #ifdef FLP_DEBUG |
753 | printf("fdselect: drive=%d, head=%d, dense=%d\n", drive, head, dense); | | 765 | printf("fdselect: drive=%d, head=%d, dense=%d\n", drive, head, dense); |
754 | #endif | | 766 | #endif |
755 | i = ((drive == 1) ? PA_FLOP1 : PA_FLOP0) | head; | | 767 | i = ((drive == 1) ? PA_FLOP1 : PA_FLOP0) | head; |
756 | spinning = motoron; | | 768 | spinning = motoron; |
757 | motoron = 1; | | 769 | motoron = 1; |
758 | | | 770 | |
759 | switch(dense) { | | 771 | switch (dense) { |
760 | case FLP_DD: | | 772 | case FLP_DD: |
761 | DMA->dma_drvmode = 0; | | 773 | DMA->dma_drvmode = 0; |
762 | break; | | 774 | break; |
763 | case FLP_HD: | | 775 | case FLP_HD: |
764 | DMA->dma_drvmode = (FDC_HDSET|FDC_HDSIG); | | 776 | DMA->dma_drvmode = (FDC_HDSET|FDC_HDSIG); |
765 | break; | | 777 | break; |
766 | default: | | 778 | default: |
767 | panic("fdselect: unknown density code"); | | 779 | panic("fdselect: unknown density code"); |
768 | } | | 780 | } |
769 | if(i != selected) { | | 781 | if (i != selected) { |
770 | selected = i; | | 782 | selected = i; |
771 | ym2149_fd_select((i ^ PA_FDSEL)); | | 783 | ym2149_fd_select((i ^ PA_FDSEL)); |
772 | } | | 784 | } |
773 | return(spinning); | | 785 | return spinning; |
774 | } | | 786 | } |
775 | | | 787 | |
776 | static void | | 788 | static void |
777 | fddeselect(void) | | 789 | fddeselect(void) |
778 | { | | 790 | { |
| | | 791 | |
779 | ym2149_fd_select(PA_FDSEL); | | 792 | ym2149_fd_select(PA_FDSEL); |
780 | motoron = selected = 0; | | 793 | motoron = selected = 0; |
781 | DMA->dma_drvmode = 0; | | 794 | DMA->dma_drvmode = 0; |
782 | } | | 795 | } |
783 | | | 796 | |
784 | /**************************************************************************** | | 797 | /**************************************************************************** |
785 | * The following functions assume to be running as a result of a * | | 798 | * The following functions assume to be running as a result of a * |
786 | * disk-interrupt (e.q. spl = splbio). * | | 799 | * disk-interrupt (e.q. spl = splbio). * |
787 | * They form the finit-state machine, the actual driver. * | | 800 | * They form the finit-state machine, the actual driver. * |
788 | * * | | 801 | * * |
789 | * fdstart()/ --> fd_xfer() -> activate hardware * | | 802 | * fdstart()/ --> fd_xfer() -> activate hardware * |
790 | * fdopen() ^ * | | 803 | * fdopen() ^ * |
791 | * | * | | 804 | * | * |
792 | * +-- not ready -<------------+ * | | 805 | * +-- not ready -<------------+ * |
793 | * | * | | 806 | * | * |
794 | * fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+ * | | 807 | * fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+ * |
795 | * h/w interrupt | * | | 808 | * h/w interrupt | * |
796 | * \|/ * | | 809 | * \|/ * |
797 | * finished ---> fdone() * | | 810 | * finished ---> fdone() * |
798 | * * | | 811 | * * |
799 | ****************************************************************************/ | | 812 | ****************************************************************************/ |
800 | static void | | 813 | static void |
801 | fd_xfer(struct fd_softc *sc) | | 814 | fd_xfer(struct fd_softc *sc) |
802 | { | | 815 | { |
803 | register int head; | | 816 | int head; |
804 | register int track, sector, hbit; | | 817 | int track, sector, hbit; |
805 | u_long phys_addr; | | 818 | paddr_t phys_addr; |
806 | | | 819 | |
807 | head = track = 0; | | 820 | head = track = 0; |
808 | switch(fd_state) { | | 821 | switch (fd_state) { |
809 | case FLP_XFER: | | 822 | case FLP_XFER: |
810 | /* | | 823 | /* |
811 | * Calculate head/track values | | 824 | * Calculate head/track values |
812 | */ | | 825 | */ |
813 | track = sc->sector / sc->nsectors; | | 826 | track = sc->sector / sc->nsectors; |
814 | head = track % sc->nheads; | | 827 | head = track % sc->nheads; |
815 | track = track / sc->nheads; | | 828 | track = track / sc->nheads; |
816 | #ifdef FLP_DEBUG | | 829 | #ifdef FLP_DEBUG |
817 | printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head, | | 830 | printf("fd_xfer: sector:%d,head:%d,track:%d\n", |
818 | track); | | 831 | sc->sector, head, track); |
819 | #endif | | 832 | #endif |
820 | break; | | 833 | break; |
821 | | | 834 | |
822 | case FLP_STAT: | | 835 | case FLP_STAT: |
823 | /* | | 836 | /* |
824 | * FLP_STAT only wants to recalibrate | | 837 | * FLP_STAT only wants to recalibrate |
825 | */ | | 838 | */ |
826 | sc->curtrk = INV_TRK; | | 839 | sc->curtrk = INV_TRK; |
827 | break; | | 840 | break; |
828 | default: | | 841 | default: |
829 | panic("fd_xfer: wrong state (0x%x)", fd_state); | | 842 | panic("fd_xfer: wrong state (0x%x)", fd_state); |
830 | } | | 843 | } |
831 | | | 844 | |
832 | /* | | 845 | /* |
833 | * Select the drive. | | 846 | * Select the drive. |
834 | */ | | 847 | */ |
835 | hbit = fdselect(sc->unit, head, sc->density) ? HBIT : 0; | | 848 | hbit = fdselect(sc->unit, head, sc->density) ? HBIT : 0; |
836 | | | 849 | |
837 | if(sc->curtrk == INV_TRK) { | | 850 | if (sc->curtrk == INV_TRK) { |
838 | /* | | 851 | /* |
839 | * Recalibrate, since we lost track of head positioning. | | 852 | * Recalibrate, since we lost track of head positioning. |
840 | * The floppy disk controller has no way of determining its | | 853 | * The floppy disk controller has no way of determining its |
841 | * absolute arm position (track). Instead, it steps the | | 854 | * absolute arm position (track). Instead, it steps the |
842 | * arm a track at a time and keeps track of where it | | 855 | * arm a track at a time and keeps track of where it |
843 | * thinks it is (in software). However, after a SEEK, the | | 856 | * thinks it is (in software). However, after a SEEK, the |
844 | * hardware reads information from the diskette telling | | 857 | * hardware reads information from the diskette telling |
845 | * where the arm actually is. If the arm is in the wrong place, | | 858 | * where the arm actually is. If the arm is in the wrong place, |
846 | * a recalibration is done, which forces the arm to track 0. | | 859 | * a recalibration is done, which forces the arm to track 0. |
847 | * This way the controller can get back into sync with reality. | | 860 | * This way the controller can get back into sync with reality. |
848 | */ | | 861 | */ |
849 | fd_cmd = RESTORE; | | 862 | fd_cmd = RESTORE; |
850 | write_fdreg(FDC_CS, RESTORE|VBIT|hbit); | | 863 | write_fdreg(FDC_CS, RESTORE|VBIT|hbit); |
| @@ -853,337 +866,339 @@ fd_xfer(struct fd_softc *sc) | | | @@ -853,337 +866,339 @@ fd_xfer(struct fd_softc *sc) |
853 | | | 866 | |
854 | #ifdef FLP_DEBUG | | 867 | #ifdef FLP_DEBUG |
855 | printf("fd_xfer:Recalibrating drive %d\n", sc->unit); | | 868 | printf("fd_xfer:Recalibrating drive %d\n", sc->unit); |
856 | #endif | | 869 | #endif |
857 | return; | | 870 | return; |
858 | } | | 871 | } |
859 | | | 872 | |
860 | write_fdreg(FDC_TR, sc->curtrk); | | 873 | write_fdreg(FDC_TR, sc->curtrk); |
861 | | | 874 | |
862 | /* | | 875 | /* |
863 | * Issue a SEEK command on the indicated drive unless the arm is | | 876 | * Issue a SEEK command on the indicated drive unless the arm is |
864 | * already positioned on the correct track. | | 877 | * already positioned on the correct track. |
865 | */ | | 878 | */ |
866 | if(track != sc->curtrk) { | | 879 | if (track != sc->curtrk) { |
867 | sc->curtrk = track; /* be optimistic */ | | 880 | sc->curtrk = track; /* be optimistic */ |
868 | write_fdreg(FDC_DR, track); | | 881 | write_fdreg(FDC_DR, track); |
869 | write_fdreg(FDC_CS, SEEK|RATE6|VBIT|hbit); | | 882 | write_fdreg(FDC_CS, SEEK|RATE6|VBIT|hbit); |
870 | callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY, | | 883 | callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY, |
871 | (FPV)fdmotoroff, sc); | | 884 | (FPV)fdmotoroff, sc); |
872 | fd_cmd = SEEK; | | 885 | fd_cmd = SEEK; |
873 | #ifdef FLP_DEBUG | | 886 | #ifdef FLP_DEBUG |
874 | printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit); | | 887 | printf("fd_xfer:Seek to track %d on drive %d\n", |
| | | 888 | track, sc->unit); |
875 | #endif | | 889 | #endif |
876 | return; | | 890 | return; |
877 | } | | 891 | } |
878 | | | 892 | |
879 | /* | | 893 | /* |
880 | * The drive is now on the proper track. Read or write 1 block. | | 894 | * The drive is now on the proper track. Read or write 1 block. |
881 | */ | | 895 | */ |
882 | sector = sc->sector % sc->nsectors; | | 896 | sector = sc->sector % sc->nsectors; |
883 | sector++; /* start numbering at 1 */ | | 897 | sector++; /* start numbering at 1 */ |
884 | | | 898 | |
885 | write_fdreg(FDC_SR, sector); | | 899 | write_fdreg(FDC_SR, sector); |
886 | | | 900 | |
887 | phys_addr = (u_long)kvtop(sc->io_data); | | 901 | phys_addr = (paddr_t)kvtop(sc->io_data); |
888 | if(phys_addr >= FDC_MAX_DMA_AD) { | | 902 | if (phys_addr >= FDC_MAX_DMA_AD) { |
889 | /* | | 903 | /* |
890 | * We _must_ bounce this address | | 904 | * We _must_ bounce this address |
891 | */ | | 905 | */ |
892 | phys_addr = (u_long)kvtop(sc->bounceb); | | 906 | phys_addr = (paddr_t)kvtop(sc->bounceb); |
893 | if(sc->io_dir == B_WRITE) | | 907 | if (sc->io_dir == B_WRITE) |
894 | memcpy(sc->bounceb, sc->io_data, SECTOR_SIZE); | | 908 | memcpy(sc->bounceb, sc->io_data, SECTOR_SIZE); |
895 | sc->flags |= FLPF_BOUNCE; | | 909 | sc->flags |= FLPF_BOUNCE; |
896 | } | | 910 | } |
897 | st_dmaaddr_set((void *)phys_addr); /* DMA address setup */ | | 911 | st_dmaaddr_set((void *)phys_addr); /* DMA address setup */ |
898 | | | 912 | |
899 | #ifdef FLP_DEBUG | | 913 | #ifdef FLP_DEBUG |
900 | printf("fd_xfer:Start io (io_addr:%lx)\n", (u_long)kvtop(sc->io_data)); | | 914 | printf("fd_xfer:Start io (io_addr:%lx)\n", (u_long)kvtop(sc->io_data)); |
901 | #endif | | 915 | #endif |
902 | | | 916 | |
903 | if(sc->io_dir == B_READ) { | | 917 | if (sc->io_dir == B_READ) { |
904 | /* Issue the command */ | | 918 | /* Issue the command */ |
905 | st_dmacomm(DMA_FDC | DMA_SCREG, 1); | | 919 | st_dmacomm(DMA_FDC | DMA_SCREG, 1); |
906 | write_fdreg(FDC_CS, F_READ|hbit); | | 920 | write_fdreg(FDC_CS, F_READ|hbit); |
907 | fd_cmd = F_READ; | | 921 | fd_cmd = F_READ; |
908 | } | | 922 | } else { |
909 | else { | | | |
910 | /* Issue the command */ | | 923 | /* Issue the command */ |
911 | st_dmacomm(DMA_WRBIT | DMA_FDC | DMA_SCREG, 1); | | 924 | st_dmacomm(DMA_WRBIT | DMA_FDC | DMA_SCREG, 1); |
912 | write_fdreg(DMA_WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT); | | 925 | write_fdreg(DMA_WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT); |
913 | fd_cmd = F_WRITE; | | 926 | fd_cmd = F_WRITE; |
914 | } | | 927 | } |
915 | callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY, (FPV)fdmotoroff, sc); | | 928 | callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY, (FPV)fdmotoroff, sc); |
916 | } | | 929 | } |
917 | | | 930 | |
918 | /* return values of fd_xfer_ok(): */ | | 931 | /* return values of fd_xfer_ok(): */ |
919 | #define X_OK 0 | | 932 | #define X_OK 0 |
920 | #define X_AGAIN 1 | | 933 | #define X_AGAIN 1 |
921 | #define X_ERROR 2 | | 934 | #define X_ERROR 2 |
922 | #define X_FAIL 3 | | 935 | #define X_FAIL 3 |
923 | | | 936 | |
924 | /* | | 937 | /* |
925 | * Hardware interrupt function. | | 938 | * Hardware interrupt function. |
926 | */ | | 939 | */ |
927 | static void | | 940 | static void |
928 | fdcint(struct fd_softc *sc) | | 941 | fdcint(struct fd_softc *sc) |
929 | { | | 942 | { |
930 | struct buf *bp; | | 943 | struct buf *bp; |
931 | | | 944 | |
932 | #ifdef FLP_DEBUG | | 945 | #ifdef FLP_DEBUG |
933 | printf("fdcint: unit = %d\n", sc->unit); | | 946 | printf("fdcint: unit = %d\n", sc->unit); |
934 | #endif | | 947 | #endif |
935 | | | 948 | |
936 | /* | | 949 | /* |
937 | * Cancel timeout (we made it, didn't we) | | 950 | * Cancel timeout (we made it, didn't we) |
938 | */ | | 951 | */ |
939 | callout_stop(&sc->sc_motor_ch); | | 952 | callout_stop(&sc->sc_motor_ch); |
940 | | | 953 | |
941 | switch(fd_xfer_ok(sc)) { | | 954 | switch (fd_xfer_ok(sc)) { |
942 | case X_ERROR : | | 955 | case X_ERROR: |
943 | if(++(sc->errcnt) < MAX_ERRORS) { | | 956 | if (++sc->errcnt < MAX_ERRORS) { |
944 | /* | | | |
945 | * Command failed but still retries left. | | | |
946 | */ | | | |
947 | break; | | | |
948 | } | | | |
949 | /* FALL THROUGH */ | | | |
950 | case X_FAIL : | | | |
951 | /* | | 957 | /* |
952 | * Non recoverable error. Fall back to motor-on | | 958 | * Command failed but still retries left. |
953 | * idle-state. | | | |
954 | */ | | 959 | */ |
955 | if(fd_error != NULL) { | | 960 | break; |
956 | printf("Floppy error: %s\n", fd_error); | | 961 | } |
957 | fd_error = NULL; | | 962 | /* FALL THROUGH */ |
958 | } | | 963 | case X_FAIL: |
959 | | | 964 | /* |
960 | if(fd_state == FLP_STAT) { | | 965 | * Non recoverable error. Fall back to motor-on |
961 | sc->flags |= FLPF_EMPTY; | | 966 | * idle-state. |
962 | sc->flags &= ~FLPF_GETSTAT; | | 967 | */ |
963 | wakeup((void *)sc); | | 968 | if (fd_error != NULL) { |
964 | fddone(sc); | | 969 | printf("Floppy error: %s\n", fd_error); |
965 | return; | | 970 | fd_error = NULL; |
966 | } | | 971 | } |
967 | | | 972 | |
968 | bp = bufq_peek(sc->bufq); | | 973 | if (fd_state == FLP_STAT) { |
| | | 974 | sc->flags |= FLPF_EMPTY; |
| | | 975 | sc->flags &= ~FLPF_GETSTAT; |
| | | 976 | wakeup((void *)sc); |
| | | 977 | fddone(sc); |
| | | 978 | return; |
| | | 979 | } |
969 | | | 980 | |
970 | bp->b_error = EIO; | | 981 | bp = bufq_peek(sc->bufq); |
971 | fd_state = FLP_MON; | | | |
972 | | | 982 | |
973 | break; | | 983 | bp->b_error = EIO; |
974 | case X_AGAIN: | | 984 | fd_state = FLP_MON; |
975 | /* | | 985 | |
976 | * Start next part of state machine. | | 986 | break; |
977 | */ | | 987 | case X_AGAIN: |
978 | break; | | 988 | /* |
979 | case X_OK: | | 989 | * Start next part of state machine. |
980 | /* | | 990 | */ |
981 | * Command ok and finished. Reset error-counter. | | 991 | break; |
982 | * If there are no more bytes to transfer fall back | | 992 | case X_OK: |
983 | * to motor-on idle state. | | 993 | /* |
984 | */ | | 994 | * Command ok and finished. Reset error-counter. |
985 | sc->errcnt = 0; | | 995 | * If there are no more bytes to transfer fall back |
| | | 996 | * to motor-on idle state. |
| | | 997 | */ |
| | | 998 | sc->errcnt = 0; |
986 | | | 999 | |
987 | if(fd_state == FLP_STAT) { | | 1000 | if (fd_state == FLP_STAT) { |
988 | sc->flags &= ~FLPF_GETSTAT; | | 1001 | sc->flags &= ~FLPF_GETSTAT; |
989 | wakeup((void *)sc); | | 1002 | wakeup((void *)sc); |
990 | fddone(sc); | | 1003 | fddone(sc); |
991 | return; | | 1004 | return; |
992 | } | | 1005 | } |
993 | | | 1006 | |
994 | if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ)) | | 1007 | if ((sc->flags & FLPF_BOUNCE) != 0 && |
995 | memcpy(sc->io_data, sc->bounceb, SECTOR_SIZE); | | 1008 | sc->io_dir == B_READ) |
996 | sc->flags &= ~FLPF_BOUNCE; | | 1009 | memcpy(sc->io_data, sc->bounceb, SECTOR_SIZE); |
997 | | | 1010 | sc->flags &= ~FLPF_BOUNCE; |
998 | sc->sector++; | | 1011 | |
999 | sc->io_data += SECTOR_SIZE; | | 1012 | sc->sector++; |
1000 | sc->io_bytes -= SECTOR_SIZE; | | 1013 | sc->io_data += SECTOR_SIZE; |
1001 | if(sc->io_bytes <= 0) | | 1014 | sc->io_bytes -= SECTOR_SIZE; |
1002 | fd_state = FLP_MON; | | 1015 | if (sc->io_bytes <= 0) |
| | | 1016 | fd_state = FLP_MON; |
1003 | } | | 1017 | } |
1004 | if(fd_state == FLP_MON) | | 1018 | if (fd_state == FLP_MON) |
1005 | fddone(sc); | | 1019 | fddone(sc); |
1006 | else fd_xfer(sc); | | 1020 | else |
| | | 1021 | fd_xfer(sc); |
1007 | } | | 1022 | } |
1008 | | | 1023 | |
1009 | /* | | 1024 | /* |
1010 | * Determine status of last command. Should only be called through | | 1025 | * Determine status of last command. Should only be called through |
1011 | * 'fdcint()'. | | 1026 | * 'fdcint()'. |
1012 | * Returns: | | 1027 | * Returns: |
1013 | * X_ERROR : Error on command; might succeed next time. | | 1028 | * X_ERROR : Error on command; might succeed next time. |
1014 | * X_FAIL : Error on command; will never succeed. | | 1029 | * X_FAIL : Error on command; will never succeed. |
1015 | * X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete. | | 1030 | * X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete. |
1016 | * X_OK : Command succeeded and is complete. | | 1031 | * X_OK : Command succeeded and is complete. |
1017 | * | | 1032 | * |
1018 | * This function only affects sc->curtrk. | | 1033 | * This function only affects sc->curtrk. |
1019 | */ | | 1034 | */ |
1020 | static int | | 1035 | static int |
1021 | fd_xfer_ok(register struct fd_softc *sc) | | 1036 | fd_xfer_ok(register struct fd_softc *sc) |
1022 | { | | 1037 | { |
1023 | register int status; | | 1038 | int status; |
1024 | | | 1039 | |
1025 | #ifdef FLP_DEBUG | | 1040 | #ifdef FLP_DEBUG |
1026 | printf("fd_xfer_ok: cmd: 0x%x, state: 0x%x\n", fd_cmd, fd_state); | | 1041 | printf("fd_xfer_ok: cmd: 0x%x, state: 0x%x\n", fd_cmd, fd_state); |
1027 | #endif | | 1042 | #endif |
1028 | switch(fd_cmd) { | | 1043 | switch (fd_cmd) { |
1029 | case IRUPT: | | 1044 | case IRUPT: |
1030 | /* | | 1045 | /* |
1031 | * Timeout. Force a recalibrate before we try again. | | 1046 | * Timeout. Force a recalibrate before we try again. |
1032 | */ | | 1047 | */ |
1033 | status = read_fdreg(FDC_CS); | | 1048 | status = read_fdreg(FDC_CS); |
1034 | | | 1049 | |
1035 | fd_error = "Timeout"; | | 1050 | fd_error = "Timeout"; |
1036 | sc->curtrk = INV_TRK; | | 1051 | sc->curtrk = INV_TRK; |
1037 | return(X_ERROR); | | 1052 | return X_ERROR; |
1038 | case F_READ: | | 1053 | case F_READ: |
1039 | /* | | 1054 | /* |
1040 | * Test for DMA error | | 1055 | * Test for DMA error |
1041 | */ | | 1056 | */ |
1042 | status = read_dmastat(); | | 1057 | status = read_dmastat(); |
1043 | if(!(status & DMAOK)) { | | 1058 | if ((status & DMAOK) == 0) { |
1044 | fd_error = "DMA error"; | | 1059 | fd_error = "DMA error"; |
1045 | return(X_ERROR); | | 1060 | return X_ERROR; |
1046 | } | | 1061 | } |
1047 | /* | | 1062 | /* |
1048 | * Get controller status and check for errors. | | 1063 | * Get controller status and check for errors. |
1049 | */ | | 1064 | */ |
1050 | status = read_fdreg(FDC_CS); | | 1065 | status = read_fdreg(FDC_CS); |
1051 | if(status & (RNF | CRCERR | LD_T00)) { | | 1066 | if ((status & (RNF | CRCERR | LD_T00)) != 0) { |
1052 | fd_error = "Read error"; | | 1067 | fd_error = "Read error"; |
1053 | if(status & RNF) | | 1068 | if ((status & RNF) != 0) |
1054 | sc->curtrk = INV_TRK; | | | |
1055 | return(X_ERROR); | | | |
1056 | } | | | |
1057 | break; | | | |
1058 | case F_WRITE: | | | |
1059 | /* | | | |
1060 | * Test for DMA error | | | |
1061 | */ | | | |
1062 | status = read_dmastat(); | | | |
1063 | if(!(status & DMAOK)) { | | | |
1064 | fd_error = "DMA error"; | | | |
1065 | return(X_ERROR); | | | |
1066 | } | | | |
1067 | /* | | | |
1068 | * Get controller status and check for errors. | | | |
1069 | */ | | | |
1070 | status = read_fdreg(FDC_CS); | | | |
1071 | if(status & WRI_PRO) { | | | |
1072 | fd_error = "Write protected"; | | | |
1073 | return(X_FAIL); | | | |
1074 | } | | | |
1075 | if(status & (RNF | CRCERR | LD_T00)) { | | | |
1076 | fd_error = "Write error"; | | | |
1077 | sc->curtrk = INV_TRK; | | 1069 | sc->curtrk = INV_TRK; |
1078 | return(X_ERROR); | | 1070 | return X_ERROR; |
1079 | } | | 1071 | } |
| | | 1072 | break; |
| | | 1073 | case F_WRITE: |
| | | 1074 | /* |
| | | 1075 | * Test for DMA error |
| | | 1076 | */ |
| | | 1077 | status = read_dmastat(); |
| | | 1078 | if ((status & DMAOK) == 0) { |
| | | 1079 | fd_error = "DMA error"; |
| | | 1080 | return X_ERROR; |
| | | 1081 | } |
| | | 1082 | /* |
| | | 1083 | * Get controller status and check for errors. |
| | | 1084 | */ |
| | | 1085 | status = read_fdreg(FDC_CS); |
| | | 1086 | if ((status & WRI_PRO) != 0) { |
| | | 1087 | fd_error = "Write protected"; |
| | | 1088 | return X_FAIL; |
| | | 1089 | } |
| | | 1090 | if ((status & (RNF | CRCERR | LD_T00)) != 0) { |
| | | 1091 | fd_error = "Write error"; |
| | | 1092 | sc->curtrk = INV_TRK; |
| | | 1093 | return X_ERROR; |
| | | 1094 | } |
| | | 1095 | break; |
| | | 1096 | case SEEK: |
| | | 1097 | status = read_fdreg(FDC_CS); |
| | | 1098 | if ((status & (RNF | CRCERR)) != 0) { |
| | | 1099 | fd_error = "Seek error"; |
| | | 1100 | sc->curtrk = INV_TRK; |
| | | 1101 | return X_ERROR; |
| | | 1102 | } |
| | | 1103 | return X_AGAIN; |
| | | 1104 | case RESTORE: |
| | | 1105 | /* |
| | | 1106 | * Determine if the recalibration succeeded. |
| | | 1107 | */ |
| | | 1108 | status = read_fdreg(FDC_CS); |
| | | 1109 | if ((status & RNF) != 0) { |
| | | 1110 | fd_error = "Recalibrate error"; |
| | | 1111 | /* reset controller */ |
| | | 1112 | write_fdreg(FDC_CS, IRUPT); |
| | | 1113 | sc->curtrk = INV_TRK; |
| | | 1114 | return X_ERROR; |
| | | 1115 | } |
| | | 1116 | sc->curtrk = 0; |
| | | 1117 | if (fd_state == FLP_STAT) { |
| | | 1118 | if ((status & WRI_PRO) != 0) |
| | | 1119 | sc->flags |= FLPF_WRTPROT; |
1080 | break; | | 1120 | break; |
1081 | case SEEK: | | 1121 | } |
1082 | status = read_fdreg(FDC_CS); | | 1122 | return X_AGAIN; |
1083 | if(status & (RNF | CRCERR)) { | | 1123 | default: |
1084 | fd_error = "Seek error"; | | 1124 | fd_error = "Driver error: fd_xfer_ok : Unknown state"; |
1085 | sc->curtrk = INV_TRK; | | 1125 | return X_FAIL; |
1086 | return(X_ERROR); | | | |
1087 | } | | | |
1088 | return(X_AGAIN); | | | |
1089 | case RESTORE: | | | |
1090 | /* | | | |
1091 | * Determine if the recalibration succeeded. | | | |
1092 | */ | | | |
1093 | status = read_fdreg(FDC_CS); | | | |
1094 | if(status & RNF) { | | | |
1095 | fd_error = "Recalibrate error"; | | | |
1096 | /* reset controller */ | | | |
1097 | write_fdreg(FDC_CS, IRUPT); | | | |
1098 | sc->curtrk = INV_TRK; | | | |
1099 | return(X_ERROR); | | | |
1100 | } | | | |
1101 | sc->curtrk = 0; | | | |
1102 | if(fd_state == FLP_STAT) { | | | |
1103 | if(status & WRI_PRO) | | | |
1104 | sc->flags |= FLPF_WRTPROT; | | | |
1105 | break; | | | |
1106 | } | | | |
1107 | return(X_AGAIN); | | | |
1108 | default: | | | |
1109 | fd_error = "Driver error: fd_xfer_ok : Unknown state"; | | | |
1110 | return(X_FAIL); | | | |
1111 | } | | 1126 | } |
1112 | return(X_OK); | | 1127 | return X_OK; |
1113 | } | | 1128 | } |
1114 | | | 1129 | |
1115 | /* | | 1130 | /* |
1116 | * All timeouts will call this function. | | 1131 | * All timeouts will call this function. |
1117 | */ | | 1132 | */ |
1118 | static void | | 1133 | static void |
1119 | fdmotoroff(struct fd_softc *sc) | | 1134 | fdmotoroff(struct fd_softc *sc) |
1120 | { | | 1135 | { |
1121 | int sps; | | 1136 | int s; |
1122 | | | 1137 | |
1123 | /* | | 1138 | /* |
1124 | * Get at harware interrupt level | | 1139 | * Get at harware interrupt level |
1125 | */ | | 1140 | */ |
1126 | sps = splbio(); | | 1141 | s = splbio(); |
1127 | | | 1142 | |
1128 | #if FLP_DEBUG | | 1143 | #if FLP_DEBUG |
1129 | printf("fdmotoroff, state = 0x%x\n", fd_state); | | 1144 | printf("fdmotoroff, state = 0x%x\n", fd_state); |
1130 | #endif | | 1145 | #endif |
1131 | | | 1146 | |
1132 | switch(fd_state) { | | 1147 | switch (fd_state) { |
1133 | case FLP_STAT : | | 1148 | case FLP_STAT: |
1134 | case FLP_XFER : | | 1149 | case FLP_XFER: |
1135 | /* | | 1150 | /* |
1136 | * Timeout during a transfer; cancel transaction | | 1151 | * Timeout during a transfer; cancel transaction |
1137 | * set command to 'IRUPT'. | | 1152 | * set command to 'IRUPT'. |
1138 | * A drive-interrupt is simulated to trigger the state | | 1153 | * A drive-interrupt is simulated to trigger the state |
1139 | * machine. | | 1154 | * machine. |
1140 | */ | | 1155 | */ |
1141 | /* | | 1156 | /* |
1142 | * Cancel current transaction | | 1157 | * Cancel current transaction |
1143 | */ | | 1158 | */ |
1144 | fd_cmd = IRUPT; | | 1159 | fd_cmd = IRUPT; |
1145 | write_fdreg(FDC_CS, IRUPT); | | 1160 | write_fdreg(FDC_CS, IRUPT); |
1146 | delay(20); | | 1161 | delay(20); |
1147 | (void)read_fdreg(FDC_CS); | | 1162 | (void)read_fdreg(FDC_CS); |
1148 | write_fdreg(FDC_CS, RESTORE); | | 1163 | write_fdreg(FDC_CS, RESTORE); |
1149 | break; | | 1164 | break; |
1150 | | | 1165 | |
1151 | case FLP_MON : | | 1166 | case FLP_MON: |
1152 | /* | | 1167 | /* |
1153 | * Turn motor off. | | 1168 | * Turn motor off. |
1154 | */ | | 1169 | */ |
1155 | if(selected) { | | 1170 | if (selected) { |
1156 | int tmp; | | 1171 | int tmp; |
1157 | | | 1172 | |
1158 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdmoff, | | 1173 | st_dmagrab((dma_farg)fdcint, (dma_farg)fdmoff, sc, |
1159 | sc, &tmp, 0); | | 1174 | &tmp, 0); |
1160 | } | | 1175 | } else |
1161 | else fd_state = FLP_IDLE; | | 1176 | fd_state = FLP_IDLE; |
1162 | break; | | 1177 | break; |
1163 | } | | 1178 | } |
1164 | splx(sps); | | 1179 | splx(s); |
1165 | } | | 1180 | } |
1166 | | | 1181 | |
1167 | /* | | 1182 | /* |
1168 | * min byte count to whats left of the track in question | | 1183 | * min byte count to whats left of the track in question |
1169 | */ | | 1184 | */ |
1170 | static void | | 1185 | static void |
1171 | fdminphys(struct buf *bp) | | 1186 | fdminphys(struct buf *bp) |
1172 | { | | 1187 | { |
1173 | struct fd_softc *sc; | | 1188 | struct fd_softc *sc; |
1174 | int sec, toff, tsz; | | 1189 | int sec, toff, tsz; |
1175 | | | 1190 | |
1176 | if((sc = device_lookup_private(&fd_cd, DISKUNIT(bp->b_dev))) == NULL) | | 1191 | if ((sc = device_lookup_private(&fd_cd, DISKUNIT(bp->b_dev))) == NULL) |
1177 | panic("fdminphys: couldn't get softc"); | | 1192 | panic("fdminphys: couldn't get softc"); |
1178 | | | 1193 | |
1179 | sec = bp->b_blkno % (sc->nsectors * sc->nheads); | | 1194 | sec = bp->b_blkno % (sc->nsectors * sc->nheads); |
1180 | toff = sec * SECTOR_SIZE; | | 1195 | toff = sec * SECTOR_SIZE; |
1181 | tsz = sc->nsectors * sc->nheads * SECTOR_SIZE; | | 1196 | tsz = sc->nsectors * sc->nheads * SECTOR_SIZE; |
1182 | | | 1197 | |
1183 | #ifdef FLP_DEBUG | | 1198 | #ifdef FLP_DEBUG |
1184 | printf("fdminphys: before %ld", bp->b_bcount); | | 1199 | printf("fdminphys: before %ld", bp->b_bcount); |
1185 | #endif | | 1200 | #endif |
1186 | | | 1201 | |
1187 | bp->b_bcount = min(bp->b_bcount, tsz - toff); | | 1202 | bp->b_bcount = min(bp->b_bcount, tsz - toff); |
1188 | | | 1203 | |
1189 | #ifdef FLP_DEBUG | | 1204 | #ifdef FLP_DEBUG |
| @@ -1202,66 +1217,65 @@ fdminphys(struct buf *bp) | | | @@ -1202,66 +1217,65 @@ fdminphys(struct buf *bp) |
1202 | * drive motor is really off before deselecting the drive. The FDC only | | 1217 | * drive motor is really off before deselecting the drive. The FDC only |
1203 | * turns off the drive motor after having seen 10 index-pulses. You only | | 1218 | * turns off the drive motor after having seen 10 index-pulses. You only |
1204 | * get index-pulses when a drive is selected....This means that if the | | 1219 | * get index-pulses when a drive is selected....This means that if the |
1205 | * drive is deselected when the motor is still spinning, it will continue | | 1220 | * drive is deselected when the motor is still spinning, it will continue |
1206 | * to spin _even_ when you insert a floppy later on... | | 1221 | * to spin _even_ when you insert a floppy later on... |
1207 | */ | | 1222 | */ |
1208 | static void | | 1223 | static void |
1209 | fdmoff(struct fd_softc *fdsoftc) | | 1224 | fdmoff(struct fd_softc *fdsoftc) |
1210 | { | | 1225 | { |
1211 | int tmp; | | 1226 | int tmp; |
1212 | | | 1227 | |
1213 | if ((fd_state == FLP_MON) && selected) { | | 1228 | if ((fd_state == FLP_MON) && selected) { |
1214 | tmp = read_fdreg(FDC_CS); | | 1229 | tmp = read_fdreg(FDC_CS); |
1215 | if (!(tmp & MOTORON)) { | | 1230 | if ((tmp & MOTORON) == 0) { |
1216 | fddeselect(); | | 1231 | fddeselect(); |
1217 | fd_state = FLP_IDLE; | | 1232 | fd_state = FLP_IDLE; |
1218 | } | | 1233 | } else |
1219 | else | | 1234 | callout_reset(&fdsoftc->sc_motor_ch, 10 * FLP_MONDELAY, |
1220 | callout_reset(&fdsoftc->sc_motor_ch, 10*FLP_MONDELAY, | | | |
1221 | (FPV)fdmotoroff, fdsoftc); | | 1235 | (FPV)fdmotoroff, fdsoftc); |
1222 | } | | 1236 | } |
1223 | st_dmafree(fdsoftc, &tmp); | | 1237 | st_dmafree(fdsoftc, &tmp); |
1224 | } | | 1238 | } |
1225 | | | 1239 | |
1226 | /* | | 1240 | /* |
1227 | * Used to find out wich drives are actually connected. We do this by issuing | | 1241 | * Used to find out wich drives are actually connected. We do this by issuing |
1228 | * is 'RESTORE' command and check if the 'track-0' bit is set. This also works | | 1242 | * is 'RESTORE' command and check if the 'track-0' bit is set. This also works |
1229 | * if the drive is present but no floppy is inserted. | | 1243 | * if the drive is present but no floppy is inserted. |
1230 | */ | | 1244 | */ |
1231 | static void | | 1245 | static void |
1232 | fdtestdrv(struct fd_softc *fdsoftc) | | 1246 | fdtestdrv(struct fd_softc *fdsoftc) |
1233 | { | | 1247 | { |
1234 | int status; | | 1248 | int status; |
1235 | | | 1249 | |
1236 | /* | | 1250 | /* |
1237 | * Select the right unit and head. | | 1251 | * Select the right unit and head. |
1238 | */ | | 1252 | */ |
1239 | fdselect(fdsoftc->unit, 0, FLP_DD); | | 1253 | fdselect(fdsoftc->unit, 0, FLP_DD); |
1240 | | | 1254 | |
1241 | write_fdreg(FDC_CS, RESTORE|HBIT); | | 1255 | write_fdreg(FDC_CS, RESTORE|HBIT); |
1242 | | | 1256 | |
1243 | /* | | 1257 | /* |
1244 | * Wait for about 2 seconds. | | 1258 | * Wait for about 2 seconds. |
1245 | */ | | 1259 | */ |
1246 | delay(2000000); | | 1260 | delay(2000000); |
1247 | | | 1261 | |
1248 | status = read_fdreg(FDC_CS); | | 1262 | status = read_fdreg(FDC_CS); |
1249 | if(status & (RNF|BUSY)) { | | 1263 | if ((status & (RNF|BUSY)) != 0) { |
1250 | write_fdreg(FDC_CS, IRUPT); /* reset controller */ | | 1264 | write_fdreg(FDC_CS, IRUPT); /* reset controller */ |
1251 | delay(40); | | 1265 | delay(40); |
1252 | } | | 1266 | } |
1253 | | | 1267 | |
1254 | if(!(status & LD_T00)) | | 1268 | if ((status & LD_T00) == 0) |
1255 | fdsoftc->flags |= FLPF_NOTRESP; | | 1269 | fdsoftc->flags |= FLPF_NOTRESP; |
1256 | | | 1270 | |
1257 | fddeselect(); | | 1271 | fddeselect(); |
1258 | } | | 1272 | } |
1259 | | | 1273 | |
1260 | static void | | 1274 | static void |
1261 | fdgetdefaultlabel(struct fd_softc *sc, struct disklabel *lp, int part) | | 1275 | fdgetdefaultlabel(struct fd_softc *sc, struct disklabel *lp, int part) |
1262 | { | | 1276 | { |
1263 | | | 1277 | |
1264 | memset(lp, 0, sizeof(struct disklabel)); | | 1278 | memset(lp, 0, sizeof(struct disklabel)); |
1265 | | | 1279 | |
1266 | lp->d_secsize = SECTOR_SIZE; | | 1280 | lp->d_secsize = SECTOR_SIZE; |
1267 | lp->d_ntracks = sc->nheads; | | 1281 | lp->d_ntracks = sc->nheads; |
| @@ -1283,33 +1297,33 @@ fdgetdefaultlabel(struct fd_softc *sc, s | | | @@ -1283,33 +1297,33 @@ fdgetdefaultlabel(struct fd_softc *sc, s |
1283 | lp->d_partitions[part].p_size = lp->d_secperunit; | | 1297 | lp->d_partitions[part].p_size = lp->d_secperunit; |
1284 | lp->d_partitions[part].p_fstype = FS_UNUSED; | | 1298 | lp->d_partitions[part].p_fstype = FS_UNUSED; |
1285 | lp->d_partitions[part].p_fsize = 1024; | | 1299 | lp->d_partitions[part].p_fsize = 1024; |
1286 | lp->d_partitions[part].p_frag = 8; | | 1300 | lp->d_partitions[part].p_frag = 8; |
1287 | } | | 1301 | } |
1288 | | | 1302 | |
1289 | /* | | 1303 | /* |
1290 | * Build disk label. For now we only create a label from what we know | | 1304 | * Build disk label. For now we only create a label from what we know |
1291 | * from 'sc'. | | 1305 | * from 'sc'. |
1292 | */ | | 1306 | */ |
1293 | static int | | 1307 | static int |
1294 | fdgetdisklabel(struct fd_softc *sc, dev_t dev) | | 1308 | fdgetdisklabel(struct fd_softc *sc, dev_t dev) |
1295 | { | | 1309 | { |
1296 | struct disklabel *lp; | | 1310 | struct disklabel *lp; |
1297 | int part; | | 1311 | int part; |
1298 | | | 1312 | |
1299 | /* | | 1313 | /* |
1300 | * If we already got one, get out. | | 1314 | * If we already got one, get out. |
1301 | */ | | 1315 | */ |
1302 | if(sc->flags & FLPF_HAVELAB) | | 1316 | if ((sc->flags & FLPF_HAVELAB) != 0) |
1303 | return(0); | | 1317 | return 0; |
1304 | | | 1318 | |
1305 | #ifdef FLP_DEBUG | | 1319 | #ifdef FLP_DEBUG |
1306 | printf("fdgetdisklabel()\n"); | | 1320 | printf("fdgetdisklabel()\n"); |
1307 | #endif | | 1321 | #endif |
1308 | | | 1322 | |
1309 | part = RAW_PART; | | 1323 | part = RAW_PART; |
1310 | lp = sc->dkdev.dk_label; | | 1324 | lp = sc->dkdev.dk_label; |
1311 | fdgetdefaultlabel(sc, lp, part); | | 1325 | fdgetdefaultlabel(sc, lp, part); |
1312 | sc->flags |= FLPF_HAVELAB; | | 1326 | sc->flags |= FLPF_HAVELAB; |
1313 | | | 1327 | |
1314 | return(0); | | 1328 | return 0; |
1315 | } | | 1329 | } |