summaryrefslogtreecommitdiffstats
path: root/drivers/char/ftape/lowlevel/fc-10.c
blob: 9bc1cddade765a00a71467515319ce25516f6f5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 *

   Copyright (C) 1993,1994 Jon Tombs.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   The entire guts of this program was written by dosemu, modified to
   record reads and writes to the ports in the 0x180-0x188 address space,
   while running the CMS program TAPE.EXE V2.0.5 supplied with the drive.

   Modified to use an array of addresses and generally cleaned up (made
   much shorter) 4 June 94, dosemu isn't that good at writing short code it
   would seem :-). Made independent of 0x180, but I doubt it will work
   at any other address.

   Modified for distribution with ftape source. 21 June 94, SJL.

   Modifications on 20 October 95, by Daniel Cohen (catman@wpi.edu):
   Modified to support different DMA, IRQ, and IO Ports.  Borland's
   Turbo Debugger in virtual 8086 mode (TD386.EXE with hardware breakpoints
   provided by the TDH386.SYS Device Driver) was used on the CMS program
   TAPE V4.0.5.  I set breakpoints on I/O to ports 0x180-0x187.  Note that
   CMS's program will not successfully configure the tape drive if you set
   breakpoints on IO Reads, but you can set them on IO Writes without problems.
   Known problems:
   - You can not use DMA Channels 5 or 7.

   Modification on 29 January 96, by Daniel Cohen (catman@wpi.edu):
   Modified to only accept IRQs 3 - 7, or 9.  Since we can only send a 3 bit
   number representing the IRQ to the card, special handling is required when
   IRQ 9 is selected.  IRQ 2 and 9 are the same, and we should request IRQ 9
   from the kernel while telling the card to use IRQ 2.  Thanks to Greg
   Crider (gcrider@iclnet.org) for finding and locating this bug, as well as
   testing the patch.

   Modification on 11 December 96, by Claus Heine (claus@momo.math.rwth-aachen.de):
   Modified a little to use variahle ft_fdc_base, ft_fdc_irq, ft_fdc_dma 
   instead of preprocessor symbols. Thus we can compile this into the module
   or kernel and let the user specify the options as command line arguments.

 *
 * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fc-10.c,v $
 * $Revision: 1.2 $
 * $Date: 1997/10/05 19:18:04 $
 *
 *      This file contains code for the CMS FC-10/FC-20 card.
 */

#include <asm/io.h>
#include <linux/ftape.h>
#include "../lowlevel/ftape-tracing.h"
#include "../lowlevel/fdc-io.h"
#include "../lowlevel/fc-10.h"

static __u16 inbs_magic[] = {
	0x3, 0x3, 0x0, 0x4, 0x7, 0x2, 0x5, 0x3, 0x1, 0x4,
	0x3, 0x5, 0x2, 0x0, 0x3, 0x7, 0x4, 0x2,
	0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7
};

static __u16 fc10_ports[] = {
	0x180, 0x210, 0x2A0, 0x300, 0x330, 0x340, 0x370
};

int fc10_enable(void)
{
	int i;
	__u8 cardConfig = 0x00;
	__u8 x;
	TRACE_FUN(ft_t_flow);

/*  This code will only work if the FC-10 (or FC-20) is set to
 *  use DMA channels 1, 2, or 3.  DMA channels 5 and 7 seem to be 
 *  initialized by the same command as channels 1 and 3, respectively.
 */
	if (ft_fdc_dma > 3) {
		TRACE_ABORT(0, ft_t_err,
"Error: The FC-10/20 must be set to use DMA channels 1, 2, or 3!");
	}
/*  Only allow the FC-10/20 to use IRQ 3-7, or 9.  Note that CMS's program
 *  only accepts IRQ's 2-7, but in linux, IRQ 2 is the same as IRQ 9.
 */
	if (ft_fdc_irq < 3 || ft_fdc_irq == 8 || ft_fdc_irq > 9) {
		TRACE_ABORT(0, ft_t_err, 
"Error: The FC-10/20 must be set to use IRQ levels 3 - 7, or 9!\n"
KERN_INFO "Note: IRQ 9 is the same as IRQ 2");
	}
	/*  Clear state machine ???
	 */
	for (i = 0; i < NR_ITEMS(inbs_magic); i++) {
		inb(ft_fdc_base + inbs_magic[i]);
	}
	outb(0x0, ft_fdc_base);

	x = inb(ft_fdc_base);
	if (x == 0x13 || x == 0x93) {
		for (i = 1; i < 8; i++) {
			if (inb(ft_fdc_base + i) != x) {
				TRACE_EXIT 0;
			}
		}
	} else {
		TRACE_EXIT 0;
	}

	outb(0x8, ft_fdc_base);

	for (i = 0; i < 8; i++) {
		if (inb(ft_fdc_base + i) != 0x0) {
			TRACE_EXIT 0;
		}
	}
	outb(0x10, ft_fdc_base);

	for (i = 0; i < 8; i++) {
		if (inb(ft_fdc_base + i) != 0xff) {
			TRACE_EXIT 0;
		}
	}

	/*  Okay, we found a FC-10 card ! ???
	 */
	outb(0x0, fdc.ccr);

	/*  Clear state machine again ???
	 */
	for (i = 0; i < NR_ITEMS(inbs_magic); i++) {
		inb(ft_fdc_base + inbs_magic[i]);
	}
	/* Send io port */
	for (i = 0; i < NR_ITEMS(fc10_ports); i++)
		if (ft_fdc_base == fc10_ports[i])
			cardConfig = i + 1;
	if (cardConfig == 0) {
		TRACE_EXIT 0;	/* Invalid I/O Port */
	}
	/* and IRQ - If using IRQ 9, tell the FC card it is actually IRQ 2 */
	if (ft_fdc_irq != 9)
		cardConfig |= ft_fdc_irq << 3;
	else
		cardConfig |= 2 << 3;

	/* and finally DMA Channel */
	cardConfig |= ft_fdc_dma << 6;
	outb(cardConfig, ft_fdc_base);	/* DMA [2 bits]/IRQ [3 bits]/BASE [3 bits] */

	/*  Enable FC-10 ???
	 */
	outb(0, fdc.ccr);
	outb(0, fdc.dor2);
	outb(FDC_DMA_MODE /* 8 */, fdc.dor);
	outb(FDC_DMA_MODE /* 8 */, fdc.dor);
	outb(1, fdc.dor2);

	/*************************************
	 *
	 * cH: why the hell should this be necessary? This is done 
	 *     by fdc_reset()!!!
	 *
	 *************************************/
	/*  Initialize fdc, select drive B:
	 */
	outb(FDC_DMA_MODE, fdc.dor);	/* assert reset, dma & irq enabled */
	/*       0x08    */
	outb(FDC_DMA_MODE|FDC_RESET_NOT, fdc.dor);	/* release reset */
	/*       0x08    |   0x04   = 0x0c */
	outb(FDC_DMA_MODE|FDC_RESET_NOT|FDC_MOTOR_1|FTAPE_SEL_B, fdc.dor);
	/*       0x08    |   0x04      |  0x20     |  0x01  = 0x2d */    
	/* select drive 1 */ /* why not drive 0 ???? */
	TRACE_EXIT (x == 0x93) ? 2 : 1;
}