2 * Driver for the SWIM (Super Woz Integrated Machine) IOP
3 * floppy controller on the Macintosh IIfx and Quadra 900/950
5 * Written by Joshua M. Thompson (funaho@jurai.org)
6 * based on the SWIM3 driver (c) 1996 by Paul Mackerras.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
13 * 1999-06-12 (jmt) - Initial implementation.
21 * Since the SWIM IOP is message-driven we implement a simple request queue
22 * system. One outstanding request may be queued at any given time (this is
23 * an IOP limitation); only when that request has completed can a new request
27 /* This has to be defined before some of the #includes below */
29 #define MAJOR_NR FLOPPY_MAJOR
31 #include <linux/stddef.h>
32 #include <linux/kernel.h>
33 #include <linux/sched.h>
34 #include <linux/timer.h>
35 #include <linux/delay.h>
37 #include <linux/blk.h>
38 #include <linux/ioctl.h>
40 #include <asm/uaccess.h>
41 #include <asm/mac_iop.h>
42 #include <asm/swim_iop.h>
44 #define DRIVER_VERSION "Version 0.1 (1999-06-12)"
46 #define MAX_FLOPPIES 4
57 enum swim_state state
;
58 int drive_num
; /* device number */
59 int secpercyl
; /* disk geometry information */
62 int write_prot
; /* 1 if write-protected, 0 if not, -1 dunno */
64 struct timer_list timeout
;
66 struct wait_queue
*wait
;
75 struct floppy_state
*fs
;
76 void (*done
)(struct swim_iop_req
*);
79 static struct swim_iop_req
*current_req
;
80 static int floppy_count
;
82 static struct floppy_state floppy_states
[MAX_FLOPPIES
];
84 static int floppy_blocksizes
[2] = {512,512};
85 static int floppy_sizes
[2] = {2880,2880};
87 static char *drive_names
[7] = {
88 "not installed", /* DRV_NONE */
89 "unknown (1)", /* DRV_UNKNOWN */
90 "a 400K drive", /* DRV_400K */
91 "an 800K drive" /* DRV_800K */
92 "unknown (4)", /* ???? */
93 "an FDHD", /* DRV_FDHD */
94 "unknown (6)", /* ???? */
95 "an Apple HD20" /* DRV_HD20 */
98 int swimiop_init(void);
99 static void swimiop_init_request(struct swim_iop_req
*);
100 static int swimiop_send_request(struct swim_iop_req
*);
101 static void swimiop_receive(struct iop_msg
*, struct pt_regs
*);
102 static void swimiop_status_update(int, struct swim_drvstatus
*);
103 static int swimiop_eject(struct floppy_state
*fs
);
105 static int floppy_ioctl(struct inode
*inode
, struct file
*filp
,
106 unsigned int cmd
, unsigned long param
);
107 static int floppy_open(struct inode
*inode
, struct file
*filp
);
108 static int floppy_release(struct inode
*inode
, struct file
*filp
);
109 static int floppy_check_change(kdev_t dev
);
110 static int floppy_revalidate(kdev_t dev
);
111 static int grab_drive(struct floppy_state
*fs
, enum swim_state state
,
113 static void release_drive(struct floppy_state
*fs
);
114 static void set_timeout(struct floppy_state
*fs
, int nticks
,
115 void (*proc
)(unsigned long));
116 static void fd_request_timeout(unsigned long);
117 static void do_fd_request(request_queue_t
* q
);
118 static void start_request(struct floppy_state
*fs
);
120 static struct block_device_operations floppy_fops
= {
122 release
: floppy_release
,
124 check_media_change
: floppy_check_change
,
125 revalidate
: floppy_revalidate
,
129 * SWIM IOP initialization
132 int swimiop_init(void)
134 volatile struct swim_iop_req req
;
135 struct swimcmd_status
*cmd
= (struct swimcmd_status
*) &req
.command
[0];
136 struct swim_drvstatus
*ds
= &cmd
->status
;
137 struct floppy_state
*fs
;
143 if (!iop_ism_present
) return -ENODEV
;
145 if (register_blkdev(MAJOR_NR
, "fd", &floppy_fops
)) {
146 printk(KERN_ERR
"SWIM-IOP: Unable to get major %d for floppy\n",
150 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
), DEVICE_REQUEST
);
151 blksize_size
[MAJOR_NR
] = floppy_blocksizes
;
152 blk_size
[MAJOR_NR
] = floppy_sizes
;
154 printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n",
157 if (iop_listen(SWIM_IOP
, SWIM_CHAN
, swimiop_receive
, "SWIM") != 0) {
158 printk(KERN_ERR
"SWIM-IOP: IOP channel already in use; can't initialize.\n");
162 printk(KERN_ERR
"SWIM_IOP: probing for installed drives.\n");
164 for (i
= 0 ; i
< MAX_FLOPPIES
; i
++) {
165 memset(&floppy_states
[i
], 0, sizeof(struct floppy_state
));
166 fs
= &floppy_states
[floppy_count
];
168 swimiop_init_request(&req
);
169 cmd
->code
= CMD_STATUS
;
170 cmd
->drive_num
= i
+ 1;
171 if (swimiop_send_request(&req
) != 0) continue;
172 while (!req
.complete
);
173 if (cmd
->error
!= 0) {
174 printk(KERN_ERR
"SWIM-IOP: probe on drive %d returned error %d\n", i
, (uint
) cmd
->error
);
177 if (ds
->installed
!= 0x01) continue;
178 printk("SWIM-IOP: drive %d is %s (%s, %s, %s, %s)\n", i
,
179 drive_names
[ds
->info
.type
],
180 ds
->info
.external
? "ext" : "int",
181 ds
->info
.scsi
? "scsi" : "floppy",
182 ds
->info
.fixed
? "fixed" : "removable",
183 ds
->info
.secondary
? "secondary" : "primary");
184 swimiop_status_update(floppy_count
, ds
);
187 init_timer(&fs
->timeout
);
190 printk("SWIM-IOP: detected %d installed drives.\n", floppy_count
);
197 static void swimiop_init_request(struct swim_iop_req
*req
)
204 static int swimiop_send_request(struct swim_iop_req
*req
)
206 unsigned long cpu_flags
;
209 /* It's doubtful an interrupt routine would try to send */
210 /* a SWIM request, but I'd rather play it safe here. */
212 save_flags(cpu_flags
);
215 if (current_req
!= NULL
) {
216 restore_flags(cpu_flags
);
222 /* Interrupts should be back on for iop_send_message() */
224 restore_flags(cpu_flags
);
226 err
= iop_send_message(SWIM_IOP
, SWIM_CHAN
, (void *) req
,
227 sizeof(req
->command
), (__u8
*) &req
->command
[0],
230 /* No race condition here; we own current_req at this point */
241 * Receive a SWIM message from the IOP.
243 * This will be called in two cases:
245 * 1. A message has been successfully sent to the IOP.
246 * 2. An unsolicited message was received from the IOP.
249 void swimiop_receive(struct iop_msg
*msg
, struct pt_regs
*regs
)
251 struct swim_iop_req
*req
;
252 struct swimmsg_status
*sm
;
253 struct swim_drvstatus
*ds
;
257 switch(msg
->status
) {
258 case IOP_MSGSTATUS_COMPLETE
:
259 memcpy(&req
->command
[0], &msg
->reply
[0], sizeof(req
->command
));
261 if (req
->done
) (*req
->done
)(req
);
264 case IOP_MSGSTATUS_UNSOL
:
265 sm
= (struct swimmsg_status
*) &msg
->message
[0];
267 swimiop_status_update(sm
->drive_num
, ds
);
268 iop_complete_message(msg
);
273 static void swimiop_status_update(int drive_num
, struct swim_drvstatus
*ds
)
275 struct floppy_state
*fs
= &floppy_states
[drive_num
];
277 fs
->write_prot
= (ds
->write_prot
== 0x80);
278 if ((ds
->disk_in_drive
!= 0x01) && (ds
->disk_in_drive
!= 0x02)) {
283 switch(ds
->info
.type
) {
286 fs
->secpertrack
= 10;
287 fs
->total_secs
= 800;
291 fs
->secpertrack
= 10;
292 fs
->total_secs
= 1600;
296 fs
->secpertrack
= 18;
297 fs
->total_secs
= 2880;
307 static int swimiop_eject(struct floppy_state
*fs
)
310 struct swim_iop_req req
;
311 struct swimcmd_eject
*cmd
= (struct swimcmd_eject
*) &req
.command
[0];
313 err
= grab_drive(fs
, ejecting
, 1);
316 swimiop_init_request(&req
);
317 cmd
->code
= CMD_EJECT
;
318 cmd
->drive_num
= fs
->drive_num
;
319 err
= swimiop_send_request(&req
);
324 for (n
= 2*HZ
; n
> 0; --n
) {
325 if (req
.complete
) break;
326 if (signal_pending(current
)) {
330 current
->state
= TASK_INTERRUPTIBLE
;
337 static struct floppy_struct floppy_type
=
338 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL
}; /* 7 1.44MB 3.5" */
340 static int floppy_ioctl(struct inode
*inode
, struct file
*filp
,
341 unsigned int cmd
, unsigned long param
)
343 struct floppy_state
*fs
;
345 int devnum
= MINOR(inode
->i_rdev
);
347 if (devnum
>= floppy_count
)
350 if ((cmd
& 0x80) && !suser())
353 fs
= &floppy_states
[devnum
];
357 if (fs
->ref_count
!= 1)
359 err
= swimiop_eject(fs
);
362 err
= copy_to_user((void *) param
, (void *) &floppy_type
,
363 sizeof(struct floppy_struct
));
369 static int floppy_open(struct inode
*inode
, struct file
*filp
)
371 struct floppy_state
*fs
;
373 int devnum
= MINOR(inode
->i_rdev
);
375 if (devnum
>= floppy_count
)
380 fs
= &floppy_states
[devnum
];
382 if (fs
->ref_count
== -1 || filp
->f_flags
& O_EXCL
) return -EBUSY
;
384 if (err
== 0 && (filp
->f_flags
& O_NDELAY
) == 0
385 && (filp
->f_mode
& 3)) {
386 check_disk_change(inode
->i_rdev
);
391 if (err
== 0 && (filp
->f_mode
& 2)) {
398 if (filp
->f_flags
& O_EXCL
)
406 static int floppy_release(struct inode
*inode
, struct file
*filp
)
408 struct floppy_state
*fs
;
409 int devnum
= MINOR(inode
->i_rdev
);
411 if (devnum
>= floppy_count
)
414 fs
= &floppy_states
[devnum
];
415 if (fs
->ref_count
> 0) fs
->ref_count
--;
419 static int floppy_check_change(kdev_t dev
)
421 struct floppy_state
*fs
;
422 int devnum
= MINOR(dev
);
424 if (MAJOR(dev
) != MAJOR_NR
|| (devnum
>= floppy_count
))
427 fs
= &floppy_states
[devnum
];
431 static int floppy_revalidate(kdev_t dev
)
433 struct floppy_state
*fs
;
434 int devnum
= MINOR(dev
);
436 if (MAJOR(dev
) != MAJOR_NR
|| (devnum
>= floppy_count
))
439 fs
= &floppy_states
[devnum
];
441 grab_drive(fs
, revalidating
, 0);
448 static void floppy_off(unsigned int nr
)
452 static int grab_drive(struct floppy_state
*fs
, enum swim_state state
,
459 if (fs
->state
!= idle
) {
461 while (fs
->state
!= available
) {
462 if (interruptible
&& signal_pending(current
)) {
464 restore_flags(flags
);
467 interruptible_sleep_on(&fs
->wait
);
472 restore_flags(flags
);
476 static void release_drive(struct floppy_state
*fs
)
484 restore_flags(flags
);
487 static void set_timeout(struct floppy_state
*fs
, int nticks
,
488 void (*proc
)(unsigned long))
492 save_flags(flags
); cli();
493 if (fs
->timeout_pending
)
494 del_timer(&fs
->timeout
);
495 fs
->timeout
.expires
= jiffies
+ nticks
;
496 fs
->timeout
.function
= proc
;
497 fs
->timeout
.data
= (unsigned long) fs
;
498 add_timer(&fs
->timeout
);
499 fs
->timeout_pending
= 1;
500 restore_flags(flags
);
503 static void do_fd_request(request_queue_t
* q
)
507 for (i
= 0 ; i
< floppy_count
; i
++) {
508 start_request(&floppy_states
[i
]);
512 static void fd_request_complete(struct swim_iop_req
*req
)
514 struct floppy_state
*fs
= req
->fs
;
515 struct swimcmd_rw
*cmd
= (struct swimcmd_rw
*) &req
->command
[0];
517 del_timer(&fs
->timeout
);
518 fs
->timeout_pending
= 0;
521 printk(KERN_ERR
"SWIM-IOP: error %d on read/write request.\n", cmd
->error
);
524 CURRENT
->sector
+= cmd
->num_blocks
;
525 CURRENT
->current_nr_sectors
-= cmd
->num_blocks
;
526 if (CURRENT
->current_nr_sectors
<= 0) {
534 static void fd_request_timeout(unsigned long data
)
536 struct floppy_state
*fs
= (struct floppy_state
*) data
;
538 fs
->timeout_pending
= 0;
543 static void start_request(struct floppy_state
*fs
)
545 volatile struct swim_iop_req req
;
546 struct swimcmd_rw
*cmd
= (struct swimcmd_rw
*) &req
.command
[0];
548 if (fs
->state
== idle
&& fs
->wanted
) {
549 fs
->state
= available
;
553 while (!QUEUE_EMPTY
&& fs
->state
== idle
) {
554 if (MAJOR(CURRENT
->rq_dev
) != MAJOR_NR
)
555 panic(DEVICE_NAME
": request list destroyed");
556 if (CURRENT
->bh
&& !buffer_locked(CURRENT
->bh
))
557 panic(DEVICE_NAME
": block not locked");
559 printk("do_fd_req: dev=%x cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
560 kdev_t_to_nr(CURRENT
->rq_dev
), CURRENT
->cmd
,
561 CURRENT
->sector
, CURRENT
->nr_sectors
, CURRENT
->buffer
);
562 printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n",
563 CURRENT
->rq_status
, CURRENT
->errors
, CURRENT
->current_nr_sectors
);
566 if (CURRENT
->sector
< 0 || CURRENT
->sector
>= fs
->total_secs
) {
570 if (CURRENT
->current_nr_sectors
== 0) {
579 swimiop_init_request(&req
);
581 req
.done
= fd_request_complete
;
583 if (CURRENT
->cmd
== WRITE
) {
584 if (fs
->write_prot
) {
588 cmd
->code
= CMD_WRITE
;
590 cmd
->code
= CMD_READ
;
593 cmd
->drive_num
= fs
->drive_num
;
594 cmd
->buffer
= CURRENT
->buffer
;
595 cmd
->first_block
= CURRENT
->sector
;
596 cmd
->num_blocks
= CURRENT
->current_nr_sectors
;
598 if (swimiop_send_request(&req
)) {
603 set_timeout(fs
, HZ
*CURRENT
->current_nr_sectors
,
606 fs
->state
= transferring
;