| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * | 
|  | 3 |  | 
|  | 4 | Copyright (C) 1993,1994 Jon Tombs. | 
|  | 5 |  | 
|  | 6 | This program is distributed in the hope that it will be useful, | 
|  | 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 9 | GNU General Public License for more details. | 
|  | 10 |  | 
|  | 11 | The entire guts of this program was written by dosemu, modified to | 
|  | 12 | record reads and writes to the ports in the 0x180-0x188 address space, | 
|  | 13 | while running the CMS program TAPE.EXE V2.0.5 supplied with the drive. | 
|  | 14 |  | 
|  | 15 | Modified to use an array of addresses and generally cleaned up (made | 
|  | 16 | much shorter) 4 June 94, dosemu isn't that good at writing short code it | 
|  | 17 | would seem :-). Made independent of 0x180, but I doubt it will work | 
|  | 18 | at any other address. | 
|  | 19 |  | 
|  | 20 | Modified for distribution with ftape source. 21 June 94, SJL. | 
|  | 21 |  | 
|  | 22 | Modifications on 20 October 95, by Daniel Cohen (catman@wpi.edu): | 
|  | 23 | Modified to support different DMA, IRQ, and IO Ports.  Borland's | 
|  | 24 | Turbo Debugger in virtual 8086 mode (TD386.EXE with hardware breakpoints | 
|  | 25 | provided by the TDH386.SYS Device Driver) was used on the CMS program | 
|  | 26 | TAPE V4.0.5.  I set breakpoints on I/O to ports 0x180-0x187.  Note that | 
|  | 27 | CMS's program will not successfully configure the tape drive if you set | 
|  | 28 | breakpoints on IO Reads, but you can set them on IO Writes without problems. | 
|  | 29 | Known problems: | 
|  | 30 | - You can not use DMA Channels 5 or 7. | 
|  | 31 |  | 
|  | 32 | Modification on 29 January 96, by Daniel Cohen (catman@wpi.edu): | 
|  | 33 | Modified to only accept IRQs 3 - 7, or 9.  Since we can only send a 3 bit | 
|  | 34 | number representing the IRQ to the card, special handling is required when | 
|  | 35 | IRQ 9 is selected.  IRQ 2 and 9 are the same, and we should request IRQ 9 | 
|  | 36 | from the kernel while telling the card to use IRQ 2.  Thanks to Greg | 
|  | 37 | Crider (gcrider@iclnet.org) for finding and locating this bug, as well as | 
|  | 38 | testing the patch. | 
|  | 39 |  | 
|  | 40 | Modification on 11 December 96, by Claus Heine (claus@momo.math.rwth-aachen.de): | 
|  | 41 | Modified a little to use variahle ft_fdc_base, ft_fdc_irq, ft_fdc_dma | 
|  | 42 | instead of preprocessor symbols. Thus we can compile this into the module | 
|  | 43 | or kernel and let the user specify the options as command line arguments. | 
|  | 44 |  | 
|  | 45 | * | 
|  | 46 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.c,v $ | 
|  | 47 | * $Revision: 1.2 $ | 
|  | 48 | * $Date: 1997/10/05 19:18:04 $ | 
|  | 49 | * | 
|  | 50 | *      This file contains code for the CMS FC-10/FC-20 card. | 
|  | 51 | */ | 
|  | 52 |  | 
|  | 53 | #include <asm/io.h> | 
|  | 54 | #include <linux/ftape.h> | 
|  | 55 | #include "../lowlevel/ftape-tracing.h" | 
|  | 56 | #include "../lowlevel/fdc-io.h" | 
|  | 57 | #include "../lowlevel/fc-10.h" | 
|  | 58 |  | 
|  | 59 | static __u16 inbs_magic[] = { | 
|  | 60 | 0x3, 0x3, 0x0, 0x4, 0x7, 0x2, 0x5, 0x3, 0x1, 0x4, | 
|  | 61 | 0x3, 0x5, 0x2, 0x0, 0x3, 0x7, 0x4, 0x2, | 
|  | 62 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 | 
|  | 63 | }; | 
|  | 64 |  | 
|  | 65 | static __u16 fc10_ports[] = { | 
|  | 66 | 0x180, 0x210, 0x2A0, 0x300, 0x330, 0x340, 0x370 | 
|  | 67 | }; | 
|  | 68 |  | 
|  | 69 | int fc10_enable(void) | 
|  | 70 | { | 
|  | 71 | int i; | 
|  | 72 | __u8 cardConfig = 0x00; | 
|  | 73 | __u8 x; | 
|  | 74 | TRACE_FUN(ft_t_flow); | 
|  | 75 |  | 
|  | 76 | /*  This code will only work if the FC-10 (or FC-20) is set to | 
|  | 77 | *  use DMA channels 1, 2, or 3.  DMA channels 5 and 7 seem to be | 
|  | 78 | *  initialized by the same command as channels 1 and 3, respectively. | 
|  | 79 | */ | 
|  | 80 | if (ft_fdc_dma > 3) { | 
|  | 81 | TRACE_ABORT(0, ft_t_err, | 
|  | 82 | "Error: The FC-10/20 must be set to use DMA channels 1, 2, or 3!"); | 
|  | 83 | } | 
|  | 84 | /*  Only allow the FC-10/20 to use IRQ 3-7, or 9.  Note that CMS's program | 
|  | 85 | *  only accepts IRQ's 2-7, but in linux, IRQ 2 is the same as IRQ 9. | 
|  | 86 | */ | 
|  | 87 | if (ft_fdc_irq < 3 || ft_fdc_irq == 8 || ft_fdc_irq > 9) { | 
|  | 88 | TRACE_ABORT(0, ft_t_err, | 
|  | 89 | "Error: The FC-10/20 must be set to use IRQ levels 3 - 7, or 9!\n" | 
|  | 90 | KERN_INFO "Note: IRQ 9 is the same as IRQ 2"); | 
|  | 91 | } | 
|  | 92 | /*  Clear state machine ??? | 
|  | 93 | */ | 
|  | 94 | for (i = 0; i < NR_ITEMS(inbs_magic); i++) { | 
|  | 95 | inb(ft_fdc_base + inbs_magic[i]); | 
|  | 96 | } | 
|  | 97 | outb(0x0, ft_fdc_base); | 
|  | 98 |  | 
|  | 99 | x = inb(ft_fdc_base); | 
|  | 100 | if (x == 0x13 || x == 0x93) { | 
|  | 101 | for (i = 1; i < 8; i++) { | 
|  | 102 | if (inb(ft_fdc_base + i) != x) { | 
|  | 103 | TRACE_EXIT 0; | 
|  | 104 | } | 
|  | 105 | } | 
|  | 106 | } else { | 
|  | 107 | TRACE_EXIT 0; | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | outb(0x8, ft_fdc_base); | 
|  | 111 |  | 
|  | 112 | for (i = 0; i < 8; i++) { | 
|  | 113 | if (inb(ft_fdc_base + i) != 0x0) { | 
|  | 114 | TRACE_EXIT 0; | 
|  | 115 | } | 
|  | 116 | } | 
|  | 117 | outb(0x10, ft_fdc_base); | 
|  | 118 |  | 
|  | 119 | for (i = 0; i < 8; i++) { | 
|  | 120 | if (inb(ft_fdc_base + i) != 0xff) { | 
|  | 121 | TRACE_EXIT 0; | 
|  | 122 | } | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | /*  Okay, we found a FC-10 card ! ??? | 
|  | 126 | */ | 
|  | 127 | outb(0x0, fdc.ccr); | 
|  | 128 |  | 
|  | 129 | /*  Clear state machine again ??? | 
|  | 130 | */ | 
|  | 131 | for (i = 0; i < NR_ITEMS(inbs_magic); i++) { | 
|  | 132 | inb(ft_fdc_base + inbs_magic[i]); | 
|  | 133 | } | 
|  | 134 | /* Send io port */ | 
|  | 135 | for (i = 0; i < NR_ITEMS(fc10_ports); i++) | 
|  | 136 | if (ft_fdc_base == fc10_ports[i]) | 
|  | 137 | cardConfig = i + 1; | 
|  | 138 | if (cardConfig == 0) { | 
|  | 139 | TRACE_EXIT 0;	/* Invalid I/O Port */ | 
|  | 140 | } | 
|  | 141 | /* and IRQ - If using IRQ 9, tell the FC card it is actually IRQ 2 */ | 
|  | 142 | if (ft_fdc_irq != 9) | 
|  | 143 | cardConfig |= ft_fdc_irq << 3; | 
|  | 144 | else | 
|  | 145 | cardConfig |= 2 << 3; | 
|  | 146 |  | 
|  | 147 | /* and finally DMA Channel */ | 
|  | 148 | cardConfig |= ft_fdc_dma << 6; | 
|  | 149 | outb(cardConfig, ft_fdc_base);	/* DMA [2 bits]/IRQ [3 bits]/BASE [3 bits] */ | 
|  | 150 |  | 
|  | 151 | /*  Enable FC-10 ??? | 
|  | 152 | */ | 
|  | 153 | outb(0, fdc.ccr); | 
|  | 154 | outb(0, fdc.dor2); | 
|  | 155 | outb(FDC_DMA_MODE /* 8 */, fdc.dor); | 
|  | 156 | outb(FDC_DMA_MODE /* 8 */, fdc.dor); | 
|  | 157 | outb(1, fdc.dor2); | 
|  | 158 |  | 
|  | 159 | /************************************* | 
|  | 160 | * | 
|  | 161 | * cH: why the hell should this be necessary? This is done | 
|  | 162 | *     by fdc_reset()!!! | 
|  | 163 | * | 
|  | 164 | *************************************/ | 
|  | 165 | /*  Initialize fdc, select drive B: | 
|  | 166 | */ | 
|  | 167 | outb(FDC_DMA_MODE, fdc.dor);	/* assert reset, dma & irq enabled */ | 
|  | 168 | /*       0x08    */ | 
|  | 169 | outb(FDC_DMA_MODE|FDC_RESET_NOT, fdc.dor);	/* release reset */ | 
|  | 170 | /*       0x08    |   0x04   = 0x0c */ | 
|  | 171 | outb(FDC_DMA_MODE|FDC_RESET_NOT|FDC_MOTOR_1|FTAPE_SEL_B, fdc.dor); | 
|  | 172 | /*       0x08    |   0x04      |  0x20     |  0x01  = 0x2d */ | 
|  | 173 | /* select drive 1 */ /* why not drive 0 ???? */ | 
|  | 174 | TRACE_EXIT (x == 0x93) ? 2 : 1; | 
|  | 175 | } |