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