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 #include <linux/stddef.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/timer.h>
31 #include <linux/delay.h>
33 #include <linux/ioctl.h>
34 #include <linux/blkdev.h>
36 #include <asm/uaccess.h>
37 #include <asm/mac_iop.h>
38 #include <asm/swim_iop.h>
40 #define DRIVER_VERSION "Version 0.1 (1999-06-12)"
42 #define MAX_FLOPPIES 4
53 enum swim_state state
;
54 int drive_num
; /* device number */
55 int secpercyl
; /* disk geometry information */
58 int write_prot
; /* 1 if write-protected, 0 if not, -1 dunno */
60 struct timer_list timeout
;
62 struct wait_queue
*wait
;
71 struct floppy_state
*fs
;
72 void (*done
)(struct swim_iop_req
*);
75 static struct swim_iop_req
*current_req
;
76 static int floppy_count
;
78 static struct floppy_state floppy_states
[MAX_FLOPPIES
];
79 static DEFINE_SPINLOCK(swim_iop_lock
);
81 #define CURRENT elv_next_request(swim_queue)
83 static char *drive_names
[7] = {
84 "not installed", /* DRV_NONE */
85 "unknown (1)", /* DRV_UNKNOWN */
86 "a 400K drive", /* DRV_400K */
87 "an 800K drive" /* DRV_800K */
88 "unknown (4)", /* ???? */
89 "an FDHD", /* DRV_FDHD */
90 "unknown (6)", /* ???? */
91 "an Apple HD20" /* DRV_HD20 */
94 int swimiop_init(void);
95 static void swimiop_init_request(struct swim_iop_req
*);
96 static int swimiop_send_request(struct swim_iop_req
*);
97 static void swimiop_receive(struct iop_msg
*, struct pt_regs
*);
98 static void swimiop_status_update(int, struct swim_drvstatus
*);
99 static int swimiop_eject(struct floppy_state
*fs
);
101 static int floppy_ioctl(struct inode
*inode
, struct file
*filp
,
102 unsigned int cmd
, unsigned long param
);
103 static int floppy_open(struct inode
*inode
, struct file
*filp
);
104 static int floppy_release(struct inode
*inode
, struct file
*filp
);
105 static int floppy_check_change(struct gendisk
*disk
);
106 static int floppy_revalidate(struct gendisk
*disk
);
107 static int grab_drive(struct floppy_state
*fs
, enum swim_state state
,
109 static void release_drive(struct floppy_state
*fs
);
110 static void set_timeout(struct floppy_state
*fs
, int nticks
,
111 void (*proc
)(unsigned long));
112 static void fd_request_timeout(unsigned long);
113 static void do_fd_request(request_queue_t
* q
);
114 static void start_request(struct floppy_state
*fs
);
116 static struct block_device_operations floppy_fops
= {
118 .release
= floppy_release
,
119 .ioctl
= floppy_ioctl
,
120 .media_changed
= floppy_check_change
,
121 .revalidate_disk
= floppy_revalidate
,
124 static struct request_queue
*swim_queue
;
126 * SWIM IOP initialization
129 int swimiop_init(void)
131 volatile struct swim_iop_req req
;
132 struct swimcmd_status
*cmd
= (struct swimcmd_status
*) &req
.command
[0];
133 struct swim_drvstatus
*ds
= &cmd
->status
;
134 struct floppy_state
*fs
;
140 if (!iop_ism_present
)
143 if (register_blkdev(FLOPPY_MAJOR
, "fd"))
146 swim_queue
= blk_init_queue(do_fd_request
, &swim_iop_lock
);
148 unregister_blkdev(FLOPPY_MAJOR
, "fd");
152 printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n",
155 if (iop_listen(SWIM_IOP
, SWIM_CHAN
, swimiop_receive
, "SWIM") != 0) {
156 printk(KERN_ERR
"SWIM-IOP: IOP channel already in use; can't initialize.\n");
157 unregister_blkdev(FLOPPY_MAJOR
, "fd");
158 blk_cleanup_queue(swim_queue
);
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
);
192 for (i
= 0; i
< floppy_count
; i
++) {
193 struct gendisk
*disk
= alloc_disk(1);
196 disk
->major
= FLOPPY_MAJOR
;
197 disk
->first_minor
= i
;
198 disk
->fops
= &floppy_fops
;
199 sprintf(disk
->disk_name
, "fd%d", i
);
200 disk
->private_data
= &floppy_states
[i
];
201 disk
->queue
= swim_queue
;
202 set_capacity(disk
, 2880 * 2);
209 static void swimiop_init_request(struct swim_iop_req
*req
)
216 static int swimiop_send_request(struct swim_iop_req
*req
)
221 /* It's doubtful an interrupt routine would try to send */
222 /* a SWIM request, but I'd rather play it safe here. */
224 local_irq_save(flags
);
226 if (current_req
!= NULL
) {
227 local_irq_restore(flags
);
233 /* Interrupts should be back on for iop_send_message() */
235 local_irq_restore(flags
);
237 err
= iop_send_message(SWIM_IOP
, SWIM_CHAN
, (void *) req
,
238 sizeof(req
->command
), (__u8
*) &req
->command
[0],
241 /* No race condition here; we own current_req at this point */
252 * Receive a SWIM message from the IOP.
254 * This will be called in two cases:
256 * 1. A message has been successfully sent to the IOP.
257 * 2. An unsolicited message was received from the IOP.
260 void swimiop_receive(struct iop_msg
*msg
, struct pt_regs
*regs
)
262 struct swim_iop_req
*req
;
263 struct swimmsg_status
*sm
;
264 struct swim_drvstatus
*ds
;
268 switch(msg
->status
) {
269 case IOP_MSGSTATUS_COMPLETE
:
270 memcpy(&req
->command
[0], &msg
->reply
[0], sizeof(req
->command
));
272 if (req
->done
) (*req
->done
)(req
);
275 case IOP_MSGSTATUS_UNSOL
:
276 sm
= (struct swimmsg_status
*) &msg
->message
[0];
278 swimiop_status_update(sm
->drive_num
, ds
);
279 iop_complete_message(msg
);
284 static void swimiop_status_update(int drive_num
, struct swim_drvstatus
*ds
)
286 struct floppy_state
*fs
= &floppy_states
[drive_num
];
288 fs
->write_prot
= (ds
->write_prot
== 0x80);
289 if ((ds
->disk_in_drive
!= 0x01) && (ds
->disk_in_drive
!= 0x02)) {
294 switch(ds
->info
.type
) {
297 fs
->secpertrack
= 10;
298 fs
->total_secs
= 800;
302 fs
->secpertrack
= 10;
303 fs
->total_secs
= 1600;
307 fs
->secpertrack
= 18;
308 fs
->total_secs
= 2880;
318 static int swimiop_eject(struct floppy_state
*fs
)
321 struct swim_iop_req req
;
322 struct swimcmd_eject
*cmd
= (struct swimcmd_eject
*) &req
.command
[0];
324 err
= grab_drive(fs
, ejecting
, 1);
327 swimiop_init_request(&req
);
328 cmd
->code
= CMD_EJECT
;
329 cmd
->drive_num
= fs
->drive_num
;
330 err
= swimiop_send_request(&req
);
335 for (n
= 2*HZ
; n
> 0; --n
) {
336 if (req
.complete
) break;
337 if (signal_pending(current
)) {
341 current
->state
= TASK_INTERRUPTIBLE
;
348 static struct floppy_struct floppy_type
=
349 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL
}; /* 7 1.44MB 3.5" */
351 static int floppy_ioctl(struct inode
*inode
, struct file
*filp
,
352 unsigned int cmd
, unsigned long param
)
354 struct floppy_state
*fs
= inode
->i_bdev
->bd_disk
->private_data
;
357 if ((cmd
& 0x80) && !capable(CAP_SYS_ADMIN
))
362 if (fs
->ref_count
!= 1)
364 err
= swimiop_eject(fs
);
367 if (copy_to_user((void *) param
, (void *) &floppy_type
,
368 sizeof(struct floppy_struct
)))
375 static int floppy_open(struct inode
*inode
, struct file
*filp
)
377 struct floppy_state
*fs
= inode
->i_bdev
->bd_disk
->private_data
;
379 if (fs
->ref_count
== -1 || filp
->f_flags
& O_EXCL
)
382 if ((filp
->f_flags
& O_NDELAY
) == 0 && (filp
->f_mode
& 3)) {
383 check_disk_change(inode
->i_bdev
);
388 if ((filp
->f_mode
& 2) && fs
->write_prot
)
391 if (filp
->f_flags
& O_EXCL
)
399 static int floppy_release(struct inode
*inode
, struct file
*filp
)
401 struct floppy_state
*fs
= inode
->i_bdev
->bd_disk
->private_data
;
402 if (fs
->ref_count
> 0)
407 static int floppy_check_change(struct gendisk
*disk
)
409 struct floppy_state
*fs
= disk
->private_data
;
413 static int floppy_revalidate(struct gendisk
*disk
)
415 struct floppy_state
*fs
= disk
->private_data
;
416 grab_drive(fs
, revalidating
, 0);
422 static void floppy_off(unsigned int nr
)
426 static int grab_drive(struct floppy_state
*fs
, enum swim_state state
,
431 local_irq_save(flags
);
432 if (fs
->state
!= idle
) {
434 while (fs
->state
!= available
) {
435 if (interruptible
&& signal_pending(current
)) {
437 local_irq_restore(flags
);
440 interruptible_sleep_on(&fs
->wait
);
445 local_irq_restore(flags
);
449 static void release_drive(struct floppy_state
*fs
)
453 local_irq_save(flags
);
456 local_irq_restore(flags
);
459 static void set_timeout(struct floppy_state
*fs
, int nticks
,
460 void (*proc
)(unsigned long))
464 local_irq_save(flags
);
465 if (fs
->timeout_pending
)
466 del_timer(&fs
->timeout
);
467 init_timer(&fs
->timeout
);
468 fs
->timeout
.expires
= jiffies
+ nticks
;
469 fs
->timeout
.function
= proc
;
470 fs
->timeout
.data
= (unsigned long) fs
;
471 add_timer(&fs
->timeout
);
472 fs
->timeout_pending
= 1;
473 local_irq_restore(flags
);
476 static void do_fd_request(request_queue_t
* q
)
480 for (i
= 0 ; i
< floppy_count
; i
++) {
481 start_request(&floppy_states
[i
]);
485 static void fd_request_complete(struct swim_iop_req
*req
)
487 struct floppy_state
*fs
= req
->fs
;
488 struct swimcmd_rw
*cmd
= (struct swimcmd_rw
*) &req
->command
[0];
490 del_timer(&fs
->timeout
);
491 fs
->timeout_pending
= 0;
494 printk(KERN_ERR
"SWIM-IOP: error %d on read/write request.\n", cmd
->error
);
495 end_request(CURRENT
, 0);
497 CURRENT
->sector
+= cmd
->num_blocks
;
498 CURRENT
->current_nr_sectors
-= cmd
->num_blocks
;
499 if (CURRENT
->current_nr_sectors
<= 0) {
500 end_request(CURRENT
, 1);
507 static void fd_request_timeout(unsigned long data
)
509 struct floppy_state
*fs
= (struct floppy_state
*) data
;
511 fs
->timeout_pending
= 0;
512 end_request(CURRENT
, 0);
516 static void start_request(struct floppy_state
*fs
)
518 volatile struct swim_iop_req req
;
519 struct swimcmd_rw
*cmd
= (struct swimcmd_rw
*) &req
.command
[0];
521 if (fs
->state
== idle
&& fs
->wanted
) {
522 fs
->state
= available
;
526 while (CURRENT
&& fs
->state
== idle
) {
527 if (CURRENT
->bh
&& !buffer_locked(CURRENT
->bh
))
528 panic("floppy: block not locked");
530 printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
531 CURRENT
->rq_disk
->disk_name
, CURRENT
->cmd
,
532 CURRENT
->sector
, CURRENT
->nr_sectors
, CURRENT
->buffer
);
533 printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n",
534 CURRENT
->rq_status
, CURRENT
->errors
, CURRENT
->current_nr_sectors
);
537 if (CURRENT
->sector
< 0 || CURRENT
->sector
>= fs
->total_secs
) {
538 end_request(CURRENT
, 0);
541 if (CURRENT
->current_nr_sectors
== 0) {
542 end_request(CURRENT
, 1);
546 end_request(CURRENT
, 0);
550 swimiop_init_request(&req
);
552 req
.done
= fd_request_complete
;
554 if (CURRENT
->cmd
== WRITE
) {
555 if (fs
->write_prot
) {
556 end_request(CURRENT
, 0);
559 cmd
->code
= CMD_WRITE
;
561 cmd
->code
= CMD_READ
;
564 cmd
->drive_num
= fs
->drive_num
;
565 cmd
->buffer
= CURRENT
->buffer
;
566 cmd
->first_block
= CURRENT
->sector
;
567 cmd
->num_blocks
= CURRENT
->current_nr_sectors
;
569 if (swimiop_send_request(&req
)) {
570 end_request(CURRENT
, 0);
574 set_timeout(fs
, HZ
*CURRENT
->current_nr_sectors
,
577 fs
->state
= transferring
;