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