blob: 7fde8f4daebfff867e688e275c09a735634c9292 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Uwe Zeisbergerf30c2262006-10-03 23:01:26 +02002 * linux/drivers/acorn/block/mfmhd.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk)
5 *
6 * MFM hard drive code [experimental]
7 */
8
9/*
10 * Change list:
11 *
12 * 3/2/96:DAG: Started a change list :-)
13 * Set the hardsect_size pointers up since we are running 256 byte
14 * sectors
15 * Added DMA code, put it into the rw_intr
16 * Moved RCAL out of generic interrupt code - don't want to do it
17 * while DMA'ing - its now in individual handlers.
18 * Took interrupt handlers off task queue lists and called
19 * directly - not sure of implications.
20 *
21 * 18/2/96:DAG: Well its reading OK I think, well enough for image file code
22 * to find the image file; but now I've discovered that I actually
23 * have to put some code in for image files.
24 *
25 * Added stuff for image files; seems to work, but I've not
26 * got a multisegment image file (I don't think!).
27 * Put in a hack (yep a real hack) for multiple cylinder reads.
28 * Not convinced its working.
29 *
30 * 5/4/96:DAG: Added asm/hardware.h and use IOC_ macros
31 * Rewrote dma code in mfm.S (again!) - now takes a word at a time
32 * from main RAM for speed; still doesn't feel speedy!
33 *
34 * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding
35 * things up, I've finally figured out why its so damn slow.
36 * Linux is only reading a block at a time, and so you never
37 * get more than 1K per disc revoloution ~=60K/second.
38 *
39 * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to
40 * join adjacent blocks together. Everything falls flat on its
41 * face.
42 * Four hours of debugging later; I hadn't realised that
43 * ll_rw_blk would be so generous as to join blocks whose
44 * results aren't going into consecutive buffers.
45 *
46 * OK; severe rehacking of mfm_rw_interrupt; now end_request's
47 * as soon as its DMA'd each request. Odd thing is that
48 * we are sometimes getting interrupts where we are not transferring
49 * any data; why? Is that what happens when you miss? I doubt
50 * it; are we too fast? No - its just at command ends. Got 240K/s
51 * better than before, but RiscOS hits 480K/s
52 *
53 * 25/6/96:RMK: Fixed init code to allow the MFM podule to work. Increased the
54 * number of errors for my Miniscribe drive (8425).
55 *
56 * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off
57 * - so in request_done just before it clears Busy it sends a
58 * check drive 0 - and the LEDs go off!!!!
59 *
60 * Added test for mainboard controller. - Removes need for separate
61 * define.
62 *
63 * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make
64 * IM drivers work.
65 * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO
66 * error.)
67 *
68 * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents
69 * gone :-( Hand modified afterwards.
70 * Took out last remains of the older image map system.
71 *
72 * 22/9/96:DAG: Changed mfm.S so it will carry on DMA'ing til; BSY is dropped
73 * Changed mfm_rw_intr so that it doesn't follow the error
74 * code until BSY is dropped. Nope - still broke. Problem
75 * may revolve around when it reads the results for the error
76 * number?
77 *
78 *16/11/96:DAG: Modified for 2.0.18; request_irq changed
79 *
80 *17/12/96:RMK: Various cleanups, reorganisation, and the changes for new IO system.
81 * Improved probe for onboard MFM chip - it was hanging on my A5k.
82 * Added autodetect CHS code such that we don't rely on the presence
83 * of an ADFS boot block. Added ioport resource manager calls so
84 * that we don't clash with already-running hardware (eg. RiscPC Ether
85 * card slots if someone tries this)!
86 *
87 * 17/1/97:RMK: Upgraded to 2.1 kernels.
88 *
89 * 4/3/98:RMK: Changed major number to 21.
90 *
91 * 27/6/98:RMK: Changed asm/delay.h to linux/delay.h for mdelay().
92 */
93
94/*
95 * Possible enhancements:
96 * Multi-thread the code so that it is possible that while one drive
97 * is seeking, the other one can be reading data/seeking as well.
98 * This would be a performance boost with dual drive systems.
99 */
100
101#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102#include <linux/sched.h>
103#include <linux/fs.h>
104#include <linux/interrupt.h>
105#include <linux/kernel.h>
106#include <linux/timer.h>
107#include <linux/mm.h>
108#include <linux/errno.h>
109#include <linux/genhd.h>
110#include <linux/major.h>
111#include <linux/ioport.h>
112#include <linux/delay.h>
113#include <linux/blkpg.h>
114
115#include <asm/system.h>
116#include <asm/io.h>
117#include <asm/irq.h>
118#include <asm/uaccess.h>
119#include <asm/dma.h>
120#include <asm/hardware.h>
121#include <asm/ecard.h>
122#include <asm/hardware/ioc.h>
123
124static void (*do_mfm)(void) = NULL;
125static struct request_queue *mfm_queue;
126static DEFINE_SPINLOCK(mfm_lock);
127
128#define MAJOR_NR MFM_ACORN_MAJOR
129#define QUEUE (mfm_queue)
130#define CURRENT elv_next_request(mfm_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132/*
133 * Configuration section
134 *
135 * This is the maximum number of drives that we accept
136 */
137#define MFM_MAXDRIVES 2
138/*
139 * Linux I/O address of onboard MFM controller or 0 to disable this
140 */
141#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000)
142/*
143 * Uncomment this to enable debugging in the MFM driver...
144 */
145#ifndef DEBUG
146/*#define DEBUG */
147#endif
148/*
149 * End of configuration
150 */
151
152
153/*
154 * This structure contains all information to do with a particular physical
155 * device.
156 */
157struct mfm_info {
158 unsigned char sectors;
159 unsigned char heads;
160 unsigned short cylinders;
161 unsigned short lowcurrent;
162 unsigned short precomp;
163#define NO_TRACK -1
164#define NEED_1_RECAL -2
165#define NEED_2_RECAL -3
166 int cylinder;
167 struct {
168 char recal;
169 char report;
170 char abort;
171 } errors;
172} mfm_info[MFM_MAXDRIVES];
173
174#define MFM_DRV_INFO mfm_info[raw_cmd.dev]
175
176/* Stuff from the assembly routines */
177extern unsigned int hdc63463_baseaddress; /* Controller base address */
178extern unsigned int hdc63463_irqpolladdress; /* Address to read to test for int */
179extern unsigned int hdc63463_irqpollmask; /* Mask for irq register */
180extern unsigned int hdc63463_dataptr; /* Pointer to kernel data space to DMA */
181extern int hdc63463_dataleft; /* Number of bytes left to transfer */
182
183
184
185
186static int lastspecifieddrive;
187static unsigned Busy;
188
189static unsigned int PartFragRead; /* The number of sectors which have been read
190 during a partial read split over two
191 cylinders. If 0 it means a partial
192 read did not occur. */
193
194static unsigned int PartFragRead_RestartBlock; /* Where to restart on a split access */
195static unsigned int PartFragRead_SectorsLeft; /* Where to restart on a split access */
196
197static int Sectors256LeftInCurrent; /* i.e. 256 byte sectors left in current */
198static int SectorsLeftInRequest; /* i.e. blocks left in the thing mfm_request was called for */
199static int Copy_Sector; /* The 256 byte sector we are currently at - fragments need to know
200 where to take over */
201static char *Copy_buffer;
202
203
204static void mfm_seek(void);
205static void mfm_rerequest(void);
206static void mfm_request(void);
207static void mfm_specify (void);
208static void issue_request(unsigned int block, unsigned int nsect,
209 struct request *req);
210
211static unsigned int mfm_addr; /* Controller address */
212static unsigned int mfm_IRQPollLoc; /* Address to read for IRQ information */
213static unsigned int mfm_irqenable; /* Podule IRQ enable location */
214static unsigned char mfm_irq; /* Interrupt number */
215static int mfm_drives = 0; /* drives available */
216static int mfm_status = 0; /* interrupt status */
217static int *errors;
218
219static struct rawcmd {
220 unsigned int dev;
221 unsigned int cylinder;
222 unsigned int head;
223 unsigned int sector;
224 unsigned int cmdtype;
225 unsigned int cmdcode;
226 unsigned char cmddata[16];
227 unsigned int cmdlen;
228} raw_cmd;
229
230static unsigned char result[16];
231
232static struct cont {
233 void (*interrupt) (void); /* interrupt handler */
234 void (*error) (void); /* error handler */
235 void (*redo) (void); /* redo handler */
236 void (*done) (int st); /* done handler */
237} *cont = NULL;
238
239#if 0
240static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
241#endif
242
243int number_mfm_drives = 1;
244
245/* ------------------------------------------------------------------------------------------ */
246/*
247 * From the HD63463 data sheet from Hitachi Ltd.
248 */
249
250#define MFM_COMMAND (mfm_addr + 0)
251#define MFM_DATAOUT (mfm_addr + 1)
252#define MFM_STATUS (mfm_addr + 8)
253#define MFM_DATAIN (mfm_addr + 9)
254
255#define CMD_ABT 0xF0 /* Abort */
256#define CMD_SPC 0xE8 /* Specify */
257#define CMD_TST 0xE0 /* Test */
258#define CMD_RCLB 0xC8 /* Recalibrate */
259#define CMD_SEK 0xC0 /* Seek */
260#define CMD_WFS 0xAB /* Write Format Skew */
261#define CMD_WFM 0xA3 /* Write Format */
262#define CMD_MTB 0x90 /* Memory to buffer */
263#define CMD_CMPD 0x88 /* Compare data */
264#define CMD_WD 0x87 /* Write data */
265#define CMD_RED 0x70 /* Read erroneous data */
266#define CMD_RIS 0x68 /* Read ID skew */
267#define CMD_FID 0x61 /* Find ID */
268#define CMD_RID 0x60 /* Read ID */
269#define CMD_BTM 0x50 /* Buffer to memory */
270#define CMD_CKD 0x48 /* Check data */
271#define CMD_RD 0x40 /* Read data */
272#define CMD_OPBW 0x38 /* Open buffer write */
273#define CMD_OPBR 0x30 /* Open buffer read */
274#define CMD_CKV 0x28 /* Check drive */
275#define CMD_CKE 0x20 /* Check ECC */
276#define CMD_POD 0x18 /* Polling disable */
277#define CMD_POL 0x10 /* Polling enable */
278#define CMD_RCAL 0x08 /* Recall */
279
280#define STAT_BSY 0x8000 /* Busy */
281#define STAT_CPR 0x4000 /* Command Parameter Rejection */
282#define STAT_CED 0x2000 /* Command end */
283#define STAT_SED 0x1000 /* Seek end */
284#define STAT_DER 0x0800 /* Drive error */
285#define STAT_ABN 0x0400 /* Abnormal end */
286#define STAT_POL 0x0200 /* Polling */
287
288/* ------------------------------------------------------------------------------------------ */
289#ifdef DEBUG
290static void console_printf(const char *fmt,...)
291{
292 static char buffer[2048]; /* Arbitary! */
293 extern void console_print(const char *);
294 unsigned long flags;
295 va_list ap;
296
297 local_irq_save(flags);
298
299 va_start(ap, fmt);
300 vsprintf(buffer, fmt, ap);
301 console_print(buffer);
302 va_end(fmt);
303
304 local_irq_restore(flags);
305}; /* console_printf */
306
307#define DBG(x...) console_printf(x)
308#else
309#define DBG(x...)
310#endif
311
312static void print_status(void)
313{
314 char *error;
315 static char *errors[] = {
316 "no error",
317 "command aborted",
318 "invalid command",
319 "parameter error",
320 "not initialised",
321 "rejected TEST",
322 "no useld",
323 "write fault",
324 "not ready",
325 "no scp",
326 "in seek",
327 "invalid NCA",
328 "invalid step rate",
329 "seek error",
330 "over run",
331 "invalid PHA",
332 "data field EEC error",
333 "data field CRC error",
334 "error corrected",
335 "data field fatal error",
336 "no data am",
337 "not hit",
338 "ID field CRC error",
339 "time over",
340 "no ID am",
341 "not writable"
342 };
343 if (result[1] < 0x65)
344 error = errors[result[1] >> 2];
345 else
346 error = "unknown";
347 printk("(");
348 if (mfm_status & STAT_BSY) printk("BSY ");
349 if (mfm_status & STAT_CPR) printk("CPR ");
350 if (mfm_status & STAT_CED) printk("CED ");
351 if (mfm_status & STAT_SED) printk("SED ");
352 if (mfm_status & STAT_DER) printk("DER ");
353 if (mfm_status & STAT_ABN) printk("ABN ");
354 if (mfm_status & STAT_POL) printk("POL ");
355 printk(") SSB = %X (%s)\n", result[1], error);
356
357}
358
359/* ------------------------------------------------------------------------------------- */
360
361static void issue_command(int command, unsigned char *cmdb, int len)
362{
363 int status;
364#ifdef DEBUG
365 int i;
366 console_printf("issue_command: %02X: ", command);
367 for (i = 0; i < len; i++)
368 console_printf("%02X ", cmdb[i]);
369 console_printf("\n");
370#endif
371
372 do {
373 status = inw(MFM_STATUS);
374 } while (status & (STAT_BSY | STAT_POL));
375 DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8);
376
377 if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) {
378 outw(CMD_RCAL, MFM_COMMAND);
379 while (inw(MFM_STATUS) & STAT_BSY);
380 }
381 status = inw(MFM_STATUS);
382 DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8);
383
384 while (len > 0) {
385 outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
386 len -= 2;
387 cmdb += 2;
388 }
389 status = inw(MFM_STATUS);
390 DBG("issue_command: status before command issue: %02X:\n ", status >> 8);
391
392 outw(command, MFM_COMMAND);
393 status = inw(MFM_STATUS);
394 DBG("issue_command: status immediately after command issue: %02X:\n ", status >> 8);
395}
396
397static void wait_for_completion(void)
398{
399 while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
400}
401
402static void wait_for_command_end(void)
403{
404 int i;
405
406 while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED));
407
408 for (i = 0; i < 16;) {
409 int in;
410 in = inw(MFM_DATAIN);
411 result[i++] = in >> 8;
412 result[i++] = in;
413 }
414 outw (CMD_RCAL, MFM_COMMAND);
415}
416
417/* ------------------------------------------------------------------------------------- */
418
419static void mfm_rw_intr(void)
420{
421 int old_status; /* Holds status on entry, we read to see if the command just finished */
422#ifdef DEBUG
423 console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
424 print_status();
425#endif
426
427 /* Now don't handle the error until BSY drops */
428 if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) {
429 /* Something has gone wrong - let's try that again */
430 outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
431 if (cont) {
432 DBG("mfm_rw_intr: DER/ABN err\n");
433 cont->error();
434 cont->redo();
435 };
436 return;
437 };
438
439 /* OK so what ever happened it's not an error, now I reckon we are left between
440 a choice of command end or some data which is ready to be collected */
441 /* I think we have to transfer data while the interrupt line is on and its
442 not any other type of interrupt */
443 if (CURRENT->cmd == WRITE) {
444 extern void hdc63463_writedma(void);
445 if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
446 printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
447 if (cont) {
448 cont->error();
449 cont->redo();
450 };
451 return;
452 };
453 hdc63463_writedma();
454 } else {
455 extern void hdc63463_readdma(void);
456 if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
457 printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n");
458 if (cont) {
459 cont->error();
460 cont->redo();
461 };
462 return;
463 };
464 DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);
465 hdc63463_readdma();
466 }; /* Read */
467
468 if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
469 /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */
470 /* Ah - well looking at the status its just when we get command end; so no problem */
471 /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",
472 hdc63463_dataptr,Copy_buffer+256);
473 print_status(); */
474 } else {
475 Sectors256LeftInCurrent--;
476 Copy_buffer += 256;
477 Copy_Sector++;
478
479 /* We have come to the end of this request */
480 if (!Sectors256LeftInCurrent) {
481 DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",
482 CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);
483
484 CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
485 CURRENT->sector += CURRENT->current_nr_sectors;
486 SectorsLeftInRequest -= CURRENT->current_nr_sectors;
487
488 end_request(CURRENT, 1);
489 if (SectorsLeftInRequest) {
490 hdc63463_dataptr = (unsigned int) CURRENT->buffer;
491 Copy_buffer = CURRENT->buffer;
492 Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
493 errors = &(CURRENT->errors);
494 /* These should match the present calculations of the next logical sector
495 on the device
496 Copy_Sector=CURRENT->sector*2; */
497
498 if (Copy_Sector != CURRENT->sector * 2)
499#ifdef DEBUG
500 /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",
501 Copy_Sector, CURRENT->sector * 2);
502#else
503 printk("mfm: Copy_Sector mismatch! Eek!\n");
504#endif
505 }; /* CURRENT */
506 }; /* Sectors256LeftInCurrent */
507 };
508
509 old_status = mfm_status;
510 mfm_status = inw(MFM_STATUS);
511 if (mfm_status & (STAT_DER | STAT_ABN)) {
512 /* Something has gone wrong - let's try that again */
513 if (cont) {
514 DBG("mfm_rw_intr: DER/ABN error\n");
515 cont->error();
516 cont->redo();
517 };
518 return;
519 };
520
521 /* If this code wasn't entered due to command_end but there is
522 now a command end we must read the command results out. If it was
523 entered like this then mfm_interrupt_handler would have done the
524 job. */
525 if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&
526 ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {
527 int len = 0;
528 while (len < 16) {
529 int in;
530 in = inw(MFM_DATAIN);
531 result[len++] = in >> 8;
532 result[len++] = in;
533 };
534 }; /* Result read */
535
536 /*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */
537
538 /* If end of command move on */
539 if (mfm_status & (STAT_CED)) {
540 outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
541 /* End of command - trigger the next command */
542 if (cont) {
543 cont->done(1);
544 }
545 DBG("mfm_rw_intr: returned from cont->done\n");
546 } else {
547 /* Its going to generate another interrupt */
548 do_mfm = mfm_rw_intr;
549 };
550}
551
552static void mfm_setup_rw(void)
553{
554 DBG("setting up for rw...\n");
555
556 do_mfm = mfm_rw_intr;
557 issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
558}
559
560static void mfm_recal_intr(void)
561{
562#ifdef DEBUG
563 console_printf("recal intr - status = ");
564 print_status();
565#endif
566 outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
567 if (mfm_status & (STAT_DER | STAT_ABN)) {
568 printk("recal failed\n");
569 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
570 if (cont) {
571 cont->error();
572 cont->redo();
573 }
574 return;
575 }
576 /* Thats seek end - we are finished */
577 if (mfm_status & STAT_SED) {
578 issue_command(CMD_POD, NULL, 0);
579 MFM_DRV_INFO.cylinder = 0;
580 mfm_seek();
581 return;
582 }
583 /* Command end without seek end (see data sheet p.20) for parallel seek
584 - we have to send a POL command to wait for the seek */
585 if (mfm_status & STAT_CED) {
586 do_mfm = mfm_recal_intr;
587 issue_command(CMD_POL, NULL, 0);
588 return;
589 }
590 printk("recal: unknown status\n");
591}
592
593static void mfm_seek_intr(void)
594{
595#ifdef DEBUG
596 console_printf("seek intr - status = ");
597 print_status();
598#endif
599 outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
600 if (mfm_status & (STAT_DER | STAT_ABN)) {
601 printk("seek failed\n");
602 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
603 if (cont) {
604 cont->error();
605 cont->redo();
606 }
607 return;
608 }
609 if (mfm_status & STAT_SED) {
610 issue_command(CMD_POD, NULL, 0);
611 MFM_DRV_INFO.cylinder = raw_cmd.cylinder;
612 mfm_seek();
613 return;
614 }
615 if (mfm_status & STAT_CED) {
616 do_mfm = mfm_seek_intr;
617 issue_command(CMD_POL, NULL, 0);
618 return;
619 }
620 printk("seek: unknown status\n");
621}
622
623/* IDEA2 seems to work better - its what RiscOS sets my
624 * disc to - on its SECOND call to specify!
625 */
626#define IDEA2
627#ifndef IDEA2
628#define SPEC_SL 0x16
629#define SPEC_SH 0xa9 /* Step pulse high=21, Record Length=001 (256 bytes) */
630#else
631#define SPEC_SL 0x00 /* OM2 - SL - step pulse low */
632#define SPEC_SH 0x21 /* Step pulse high=4, Record Length=001 (256 bytes) */
633#endif
634
635static void mfm_setupspecify (int drive, unsigned char *cmdb)
636{
637 cmdb[0] = 0x1f; /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */
638 cmdb[1] = 0xc3; /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */
639 cmdb[2] = SPEC_SL; /* OM2 - SL - step pulse low */
640 cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06; /* 1 or 2 drives */
641 cmdb[4] = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */
642 cmdb[5] = mfm_info[drive].cylinders - 1; /* low part of number of cylinders */
643 cmdb[6] = mfm_info[drive].heads - 1; /* Number of heads */
644 cmdb[7] = mfm_info[drive].sectors - 1; /* Number of sectors */
645 cmdb[8] = SPEC_SH;
646 cmdb[9] = 0x0a; /* gap length 1 */
647 cmdb[10] = 0x0d; /* gap length 2 */
648 cmdb[11] = 0x0c; /* gap length 3 */
649 cmdb[12] = (mfm_info[drive].precomp - 1) >> 8; /* pre comp cylinder */
650 cmdb[13] = mfm_info[drive].precomp - 1;
651 cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8; /* Low current cylinder */
652 cmdb[15] = mfm_info[drive].lowcurrent - 1;
653}
654
655static void mfm_specify (void)
656{
657 unsigned char cmdb[16];
658
659 DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);
660 mfm_setupspecify (raw_cmd.dev, cmdb);
661
662 issue_command (CMD_SPC, cmdb, 16);
663 /* Ensure that we will do another specify if we move to the other drive */
664 lastspecifieddrive = raw_cmd.dev;
665 wait_for_completion();
666}
667
668static void mfm_seek(void)
669{
670 unsigned char cmdb[4];
671
672 DBG("seeking...\n");
673 if (MFM_DRV_INFO.cylinder < 0) {
674 do_mfm = mfm_recal_intr;
675 DBG("mfm_seek: about to call specify\n");
676 mfm_specify (); /* DAG added this */
677
678 cmdb[0] = raw_cmd.dev + 1;
679 cmdb[1] = 0;
680
681 issue_command(CMD_RCLB, cmdb, 2);
682 return;
683 }
684 if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) {
685 cmdb[0] = raw_cmd.dev + 1;
686 cmdb[1] = 0; /* raw_cmd.head; DAG: My data sheet says this should be 0 */
687 cmdb[2] = raw_cmd.cylinder >> 8;
688 cmdb[3] = raw_cmd.cylinder;
689
690 do_mfm = mfm_seek_intr;
691 issue_command(CMD_SEK, cmdb, 4);
692 } else
693 mfm_setup_rw();
694}
695
696static void mfm_initialise(void)
697{
698 DBG("init...\n");
699 mfm_seek();
700}
701
702static void request_done(int uptodate)
703{
704 DBG("mfm:request_done\n");
705 if (uptodate) {
706 unsigned char block[2] = {0, 0};
707
708 /* Apparently worked - let's check bytes left to DMA */
709 if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {
710 printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);
711 end_request(CURRENT, 0);
712 Busy = 0;
713 };
714 /* Potentially this means that we've done; but we might be doing
715 a partial access, (over two cylinders) or we may have a number
716 of fragments in an image file. First let's deal with partial accesss
717 */
718 if (PartFragRead) {
719 /* Yep - a partial access */
720
721 /* and issue the remainder */
722 issue_request(PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
723 return;
724 }
725
726 /* ah well - perhaps there is another fragment to go */
727
728 /* Increment pointers/counts to start of next fragment */
729 if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
730
731 /* No - its the end of the line */
732 /* end_request's should have happened at the end of sector DMAs */
733 /* Turns Drive LEDs off - may slow it down? */
734 if (!elv_next_request(QUEUE))
735 issue_command(CMD_CKV, block, 2);
736
737 Busy = 0;
738 DBG("request_done: About to mfm_request\n");
739 /* Next one please */
740 mfm_request(); /* Moved from mfm_rw_intr */
741 DBG("request_done: returned from mfm_request\n");
742 } else {
743 printk("mfm:request_done: update=0\n");
744 end_request(CURRENT, 0);
745 Busy = 0;
746 }
747}
748
749static void error_handler(void)
750{
751 printk("error detected... status = ");
752 print_status();
753 (*errors)++;
754 if (*errors > MFM_DRV_INFO.errors.abort)
755 cont->done(0);
756 if (*errors > MFM_DRV_INFO.errors.recal)
757 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
758}
759
760static void rw_interrupt(void)
761{
762 printk("rw_interrupt\n");
763}
764
765static struct cont rw_cont =
766{
767 rw_interrupt,
768 error_handler,
769 mfm_rerequest,
770 request_done
771};
772
773/*
774 * Actually gets round to issuing the request - note everything at this
775 * point is in 256 byte sectors not Linux 512 byte blocks
776 */
777static void issue_request(unsigned int block, unsigned int nsect,
778 struct request *req)
779{
780 struct gendisk *disk = req->rq_disk;
781 struct mfm_info *p = disk->private_data;
782 int track, start_head, start_sector;
783 int sectors_to_next_cyl;
784 dev = p - mfm_info;
785
786 track = block / p->sectors;
787 start_sector = block % p->sectors;
788 start_head = track % p->heads;
789
790 /* First get the number of whole tracks which are free before the next
791 track */
792 sectors_to_next_cyl = (p->heads - (start_head + 1)) * p->sectors;
793 /* Then add in the number of sectors left on this track */
794 sectors_to_next_cyl += (p->sectors - start_sector);
795
796 DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", p->sectors, track);
797
798 raw_cmd.dev = dev;
799 raw_cmd.sector = start_sector;
800 raw_cmd.head = start_head;
801 raw_cmd.cylinder = track / p->heads;
802 raw_cmd.cmdtype = CURRENT->cmd;
803 raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
804 raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */
805 raw_cmd.cmddata[1] = raw_cmd.head;
806 raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
807 raw_cmd.cmddata[3] = raw_cmd.cylinder;
808 raw_cmd.cmddata[4] = raw_cmd.head;
809 raw_cmd.cmddata[5] = raw_cmd.sector;
810
811 /* Was == and worked - how the heck??? */
812 if (lastspecifieddrive != raw_cmd.dev)
813 mfm_specify ();
814
815 if (nsect <= sectors_to_next_cyl) {
816 raw_cmd.cmddata[6] = nsect >> 8;
817 raw_cmd.cmddata[7] = nsect;
818 PartFragRead = 0; /* All in one */
819 PartFragRead_SectorsLeft = 0; /* Must set this - used in DMA calcs */
820 } else {
821 raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;
822 raw_cmd.cmddata[7] = sectors_to_next_cyl;
823 PartFragRead = sectors_to_next_cyl; /* only do this many this time */
824 PartFragRead_RestartBlock = block + sectors_to_next_cyl; /* Where to restart from */
825 PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
826 }
827 raw_cmd.cmdlen = 8;
828
829 /* Setup DMA pointers */
830 hdc63463_dataptr = (unsigned int) Copy_buffer;
831 hdc63463_dataleft = nsect * 256; /* Better way? */
832
833 DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
834 raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ",
835 raw_cmd.cylinder,
836 raw_cmd.head,
837 raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
838
839 cont = &rw_cont;
840 errors = &(CURRENT->errors);
841#if 0
842 mfm_tq.routine = (void (*)(void *)) mfm_initialise;
843 queue_task(&mfm_tq, &tq_immediate);
844 mark_bh(IMMEDIATE_BH);
845#else
846 mfm_initialise();
847#endif
848} /* issue_request */
849
850/*
851 * Called when an error has just happened - need to trick mfm_request
852 * into thinking we weren't busy
853 *
854 * Turn off ints - mfm_request expects them this way
855 */
856static void mfm_rerequest(void)
857{
858 DBG("mfm_rerequest\n");
859 cli();
860 Busy = 0;
861 mfm_request();
862}
863
864static struct gendisk *mfm_gendisk[2];
865
866static void mfm_request(void)
867{
868 DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
869
870 /* If we are still processing then return; we will get called again */
871 if (Busy) {
872 /* Again seems to be common in 1.3.45 */
873 /*DBG*/printk("mfm_request: Exiting due to busy\n");
874 return;
875 }
876 Busy = 1;
877
878 while (1) {
879 unsigned int block, nsect;
880 struct gendisk *disk;
881
882 DBG("mfm_request: loop start\n");
883 sti();
884
885 DBG("mfm_request: before !CURRENT\n");
886
887 if (!CURRENT) {
888 printk("mfm_request: Exiting due to empty queue (pre)\n");
889 do_mfm = NULL;
890 Busy = 0;
891 return;
892 }
893
894 DBG("mfm_request: before arg extraction\n");
895
896 disk = CURRENT->rq_disk;
897 block = CURRENT->sector;
898 nsect = CURRENT->nr_sectors;
899 if (block >= get_capacity(disk) ||
900 block+nsect > get_capacity(disk)) {
901 printk("%s: bad access: block=%d, count=%d, nr_sects=%ld\n",
902 disk->disk_name, block, nsect, get_capacity(disk));
903 printk("mfm: continue 1\n");
904 end_request(CURRENT, 0);
905 Busy = 0;
906 continue;
907 }
908
909 /* DAG: Linux doesn't cope with this - even though it has an array telling
910 it the hardware block size - silly */
911 block <<= 1; /* Now in 256 byte sectors */
912 nsect <<= 1; /* Ditto */
913
914 SectorsLeftInRequest = nsect >> 1;
915 Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
916 Copy_buffer = CURRENT->buffer;
917 Copy_Sector = CURRENT->sector << 1;
918
919 DBG("mfm_request: block after offset=%d\n", block);
920
921 if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) {
922 printk("unknown mfm-command %d\n", CURRENT->cmd);
923 end_request(CURRENT, 0);
924 Busy = 0;
925 printk("mfm: continue 4\n");
926 continue;
927 }
928 issue_request(block, nsect, CURRENT);
929
930 break;
931 }
932 DBG("mfm_request: Dropping out bottom\n");
933}
934
935static void do_mfm_request(request_queue_t *q)
936{
937 DBG("do_mfm_request: about to mfm_request\n");
938 mfm_request();
939}
940
David Howells7d12e782006-10-05 14:55:46 +0100941static void mfm_interrupt_handler(int unused, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942{
943 void (*handler) (void) = do_mfm;
944
945 do_mfm = NULL;
946
947 DBG("mfm_interrupt_handler (handler=0x%p)\n", handler);
948
949 mfm_status = inw(MFM_STATUS);
950
951 /* If CPR (Command Parameter Reject) and not busy it means that the command
952 has some return message to give us */
953 if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {
954 int len = 0;
955 while (len < 16) {
956 int in;
957 in = inw(MFM_DATAIN);
958 result[len++] = in >> 8;
959 result[len++] = in;
960 }
961 }
962 if (handler) {
963 handler();
964 return;
965 }
966 outw (CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */
967 printk ("mfm: unexpected interrupt - status = ");
968 print_status ();
969 while (1);
970}
971
972
973
974
975
976/*
977 * Tell the user about the drive if we decided it exists.
978 */
979static void mfm_geometry(int drive)
980{
981 struct mfm_info *p = mfm_info + drive;
982 struct gendisk *disk = mfm_gendisk[drive];
983 disk->private_data = p;
984 if (p->cylinders)
985 printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n",
986 disk->disk_name,
987 p->cylinders * p->heads * p->sectors / 4096,
988 p->cylinders, p->heads, p->sectors,
989 p->lowcurrent, p->precomp);
990 set_capacity(disk, p->cylinders * p->heads * p->sectors / 2);
991}
992
993#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
994/*
995 * Attempt to detect a drive and find its geometry. The drive has already been
996 * specified...
997 *
998 * We first recalibrate the disk, then try to probe sectors, heads and then
999 * cylinders. NOTE! the cylinder probe may break drives. The xd disk driver
1000 * does something along these lines, so I assume that most drives are up to
1001 * this mistreatment...
1002 */
1003static int mfm_detectdrive (int drive)
1004{
1005 unsigned int mingeo[3], maxgeo[3];
1006 unsigned int attribute, need_recal = 1;
1007 unsigned char cmdb[8];
1008
1009 memset (mingeo, 0, sizeof (mingeo));
1010 maxgeo[0] = mfm_info[drive].sectors;
1011 maxgeo[1] = mfm_info[drive].heads;
1012 maxgeo[2] = mfm_info[drive].cylinders;
1013
1014 cmdb[0] = drive + 1;
1015 cmdb[6] = 0;
1016 cmdb[7] = 1;
1017 for (attribute = 0; attribute < 3; attribute++) {
1018 while (mingeo[attribute] != maxgeo[attribute]) {
1019 unsigned int variable;
1020
1021 variable = (maxgeo[attribute] + mingeo[attribute]) >> 1;
1022 cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0;
1023
1024 if (need_recal) {
1025 int tries = 5;
1026
1027 do {
1028 issue_command (CMD_RCLB, cmdb, 2);
1029 wait_for_completion ();
1030 wait_for_command_end ();
1031 if (result[1] == 0x20)
1032 break;
1033 } while (result[1] && --tries);
1034 if (result[1]) {
1035 outw (CMD_RCAL, MFM_COMMAND);
1036 return 0;
1037 }
1038 need_recal = 0;
1039 }
1040
1041 switch (attribute) {
1042 case 0:
1043 cmdb[5] = variable;
1044 issue_command (CMD_CMPD, cmdb, 8);
1045 break;
1046 case 1:
1047 cmdb[1] = variable;
1048 cmdb[4] = variable;
1049 issue_command (CMD_CMPD, cmdb, 8);
1050 break;
1051 case 2:
1052 cmdb[2] = variable >> 8;
1053 cmdb[3] = variable;
1054 issue_command (CMD_SEK, cmdb, 4);
1055 break;
1056 }
1057 wait_for_completion ();
1058 wait_for_command_end ();
1059
1060 switch (result[1]) {
1061 case 0x00:
1062 case 0x50:
1063 mingeo[attribute] = variable + 1;
1064 break;
1065
1066 case 0x20:
1067 outw (CMD_RCAL, MFM_COMMAND);
1068 return 0;
1069
1070 case 0x24:
1071 need_recal = 1;
1072 default:
1073 maxgeo[attribute] = variable;
1074 break;
1075 }
1076 }
1077 }
1078 mfm_info[drive].cylinders = mingeo[2];
1079 mfm_info[drive].lowcurrent = mingeo[2];
1080 mfm_info[drive].precomp = mingeo[2] / 2;
1081 mfm_info[drive].heads = mingeo[1];
1082 mfm_info[drive].sectors = mingeo[0];
1083 outw (CMD_RCAL, MFM_COMMAND);
1084 return 1;
1085}
1086#endif
1087
1088/*
1089 * Initialise all drive information for this controller.
1090 */
1091static int mfm_initdrives(void)
1092{
1093 int drive;
1094
1095 if (number_mfm_drives > MFM_MAXDRIVES) {
1096 number_mfm_drives = MFM_MAXDRIVES;
1097 printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n");
1098 }
1099
1100 for (drive = 0; drive < number_mfm_drives; drive++) {
1101 mfm_info[drive].lowcurrent = 1;
1102 mfm_info[drive].precomp = 1;
1103 mfm_info[drive].cylinder = -1;
1104 mfm_info[drive].errors.recal = 0;
1105 mfm_info[drive].errors.report = 0;
1106 mfm_info[drive].errors.abort = 4;
1107
1108#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
1109 mfm_info[drive].cylinders = 1024;
1110 mfm_info[drive].heads = 8;
1111 mfm_info[drive].sectors = 64;
1112 {
1113 unsigned char cmdb[16];
1114
1115 mfm_setupspecify (drive, cmdb);
1116 cmdb[1] &= ~0x81;
1117 issue_command (CMD_SPC, cmdb, 16);
1118 wait_for_completion ();
1119 if (!mfm_detectdrive (drive)) {
1120 mfm_info[drive].cylinders = 0;
1121 mfm_info[drive].heads = 0;
1122 mfm_info[drive].sectors = 0;
1123 }
1124 cmdb[0] = cmdb[1] = 0;
1125 issue_command (CMD_CKV, cmdb, 2);
1126 }
1127#else
1128 mfm_info[drive].cylinders = 1; /* its going to have to figure it out from the partition info */
1129 mfm_info[drive].heads = 4;
1130 mfm_info[drive].sectors = 32;
1131#endif
1132 }
1133 return number_mfm_drives;
1134}
1135
1136
1137
1138/*
1139 * The 'front' end of the mfm driver follows...
1140 */
1141
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001142static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001144 struct mfm_info *p = bdev->bd_disk->private_data;
1145
1146 geo->heads = p->heads;
1147 geo->sectors = p->sectors;
1148 geo->cylinders = p->cylinders;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return 0;
1150}
1151
1152/*
1153 * This is to handle various kernel command line parameters
1154 * specific to this driver.
1155 */
1156void mfm_setup(char *str, int *ints)
1157{
1158 return;
1159}
1160
1161/*
1162 * Set the CHS from the ADFS boot block if it is present. This is not ideal
1163 * since if there are any non-ADFS partitions on the disk, this won't work!
1164 * Hence, I want to get rid of this...
1165 */
1166void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
1167 unsigned char heads, unsigned int secsize)
1168{
1169 struct mfm_info *p = bdev->bd_disk->private_data;
1170 int drive = p - mfm_info;
1171 unsigned long disksize = bdev->bd_inode->i_size;
1172
1173 if (p->cylinders == 1) {
1174 p->sectors = secsptrack;
1175 p->heads = heads;
1176 p->cylinders = discsize / (secsptrack * heads * secsize);
1177
1178 if ((heads < 1) || (p->cylinders > 1024)) {
1179 printk("%s: Insane disc shape! Setting to 512/4/32\n",
1180 bdev->bd_disk->disk_name);
1181
1182 /* These values are fairly arbitary, but are there so that if your
1183 * lucky you can pick apart your disc to find out what is going on -
1184 * I reckon these figures won't hurt MOST drives
1185 */
1186 p->sectors = 32;
1187 p->heads = 4;
1188 p->cylinders = 512;
1189 }
1190 if (raw_cmd.dev == drive)
1191 mfm_specify ();
1192 mfm_geometry (drive);
1193 }
1194}
1195
1196static struct block_device_operations mfm_fops =
1197{
1198 .owner = THIS_MODULE,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08001199 .getgeo = mfm_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200};
1201
1202/*
1203 * See if there is a controller at the address presently at mfm_addr
1204 *
1205 * We check to see if the controller is busy - if it is, we abort it first,
1206 * and check that the chip is no longer busy after at least 180 clock cycles.
1207 * We then issue a command and check that the BSY or CPR bits are set.
1208 */
1209static int mfm_probecontroller (unsigned int mfm_addr)
1210{
1211 if (inw (MFM_STATUS) & STAT_BSY) {
1212 outw (CMD_ABT, MFM_COMMAND);
1213 udelay (50);
1214 if (inw (MFM_STATUS) & STAT_BSY)
1215 return 0;
1216 }
1217
1218 if (inw (MFM_STATUS) & STAT_CED)
1219 outw (CMD_RCAL, MFM_COMMAND);
1220
1221 outw (CMD_SEK, MFM_COMMAND);
1222
1223 if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) {
1224 unsigned int count = 2000;
1225 while (inw (MFM_STATUS) & STAT_BSY) {
1226 udelay (500);
1227 if (!--count)
1228 return 0;
1229 }
1230
1231 outw (CMD_RCAL, MFM_COMMAND);
1232 }
1233 return 1;
1234}
1235
1236static int mfm_do_init(unsigned char irqmask)
1237{
1238 int i, ret;
1239
1240 printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
1241
1242 ret = -EBUSY;
1243 if (!request_region (mfm_addr, 10, "mfm"))
1244 goto out1;
1245
1246 ret = register_blkdev(MAJOR_NR, "mfm");
1247 if (ret)
1248 goto out2;
1249
1250 /* Stuff for the assembler routines to get to */
1251 hdc63463_baseaddress = ioaddr(mfm_addr);
1252 hdc63463_irqpolladdress = mfm_IRQPollLoc;
1253 hdc63463_irqpollmask = irqmask;
1254
1255 mfm_queue = blk_init_queue(do_mfm_request, &mfm_lock);
1256 if (!mfm_queue)
1257 goto out2a;
1258
1259 Busy = 0;
1260 lastspecifieddrive = -1;
1261
1262 mfm_drives = mfm_initdrives();
1263 if (!mfm_drives) {
1264 ret = -ENODEV;
1265 goto out3;
1266 }
1267
1268 for (i = 0; i < mfm_drives; i++) {
1269 struct gendisk *disk = alloc_disk(64);
1270 if (!disk)
1271 goto Enomem;
1272 disk->major = MAJOR_NR;
1273 disk->first_minor = i << 6;
1274 disk->fops = &mfm_fops;
1275 sprintf(disk->disk_name, "mfm%c", 'a'+i);
1276 mfm_gendisk[i] = disk;
1277 }
1278
1279 printk("mfm: detected %d hard drive%s\n", mfm_drives,
1280 mfm_drives == 1 ? "" : "s");
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001281 ret = request_irq(mfm_irq, mfm_interrupt_handler, IRQF_DISABLED, "MFM harddisk", NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (ret) {
1283 printk("mfm: unable to get IRQ%d\n", mfm_irq);
1284 goto out4;
1285 }
1286
1287 if (mfm_irqenable)
1288 outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */
1289
1290 for (i = 0; i < mfm_drives; i++) {
1291 mfm_geometry(i);
1292 mfm_gendisk[i]->queue = mfm_queue;
1293 add_disk(mfm_gendisk[i]);
1294 }
1295 return 0;
1296
1297out4:
1298 for (i = 0; i < mfm_drives; i++)
1299 put_disk(mfm_gendisk[i]);
1300out3:
1301 blk_cleanup_queue(mfm_queue);
1302out2a:
1303 unregister_blkdev(MAJOR_NR, "mfm");
1304out2:
1305 release_region(mfm_addr, 10);
1306out1:
1307 return ret;
1308Enomem:
1309 while (i--)
1310 put_disk(mfm_gendisk[i]);
1311 goto out3;
1312}
1313
1314static void mfm_do_exit(void)
1315{
1316 int i;
1317
1318 free_irq(mfm_irq, NULL);
1319 for (i = 0; i < mfm_drives; i++) {
1320 del_gendisk(mfm_gendisk[i]);
1321 put_disk(mfm_gendisk[i]);
1322 }
1323 blk_cleanup_queue(mfm_queue);
1324 unregister_blkdev(MAJOR_NR, "mfm");
1325 if (mfm_addr)
1326 release_region(mfm_addr, 10);
1327}
1328
1329static int __devinit mfm_probe(struct expansion_card *ec, struct ecard_id *id)
1330{
1331 if (mfm_addr)
1332 return -EBUSY;
1333
1334 mfm_addr = ecard_address(ec, ECARD_IOC, ECARD_MEDIUM) + 0x800;
1335 mfm_IRQPollLoc = ioaddr(mfm_addr + 0x400);
1336 mfm_irqenable = mfm_IRQPollLoc;
1337 mfm_irq = ec->irq;
1338
1339 return mfm_do_init(0x08);
1340}
1341
1342static void __devexit mfm_remove(struct expansion_card *ec)
1343{
1344 outw (0, mfm_irqenable); /* Required to enable IRQs from MFM podule */
1345 mfm_do_exit();
1346}
1347
1348static const struct ecard_id mfm_cids[] = {
1349 { MANU_ACORN, PROD_ACORN_MFM },
1350 { 0xffff, 0xffff },
1351};
1352
1353static struct ecard_driver mfm_driver = {
1354 .probe = mfm_probe,
1355 .remove = __devexit(mfm_remove),
1356 .id_table = mfm_cids,
1357 .drv = {
1358 .name = "mfm",
1359 },
1360};
1361
1362/*
1363 * Look for a MFM controller - first check the motherboard, then the podules
1364 * The podules have an extra interrupt enable that needs to be played with
1365 *
1366 * The HDC is accessed at MEDIUM IOC speeds.
1367 */
1368static int __init mfm_init (void)
1369{
1370 unsigned char irqmask;
1371
1372 if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {
1373 mfm_addr = ONBOARD_MFM_ADDRESS;
1374 mfm_IRQPollLoc = IOC_IRQSTATB;
1375 mfm_irqenable = 0;
1376 mfm_irq = IRQ_HARDDISK;
1377 return mfm_do_init(0x08); /* IL3 pin */
1378 } else {
1379 return ecard_register_driver(&mfm_driver);
1380 }
1381}
1382
1383static void __exit mfm_exit(void)
1384{
1385 if (mfm_addr == ONBOARD_MFM_ADDRESS)
1386 mfm_do_exit();
1387 else
1388 ecard_unregister_driver(&mfm_driver);
1389}
1390
1391module_init(mfm_init)
1392module_exit(mfm_exit)
1393MODULE_LICENSE("GPL");