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 | } |