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