Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.16-rc2 1394 lines 39 kB view raw
1/* 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) 132 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 1143static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo) 1144{ 1145 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; 1150 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, 1200 .getgeo = mfm_getgeo, 1201}; 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");