1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * low-level functions for the SWIM floppy controller
4  *
5  * needs assembly language because is very timing dependent
6  * this controller exists only on macintosh 680x0 based
7  *
8  * Copyright (C) 2004,2008 Laurent Vivier <Laurent@lvivier.info>
9  *
10  * based on Alastair Bridgewater SWIM analysis, 2001
11  * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath.
12  *
13  * 2004-08-21 (lv) - Initial implementation
14  * 2008-11-05 (lv) - add get_swim_mode
15  */
16 
17 	.equ	write_data,	0x0000
18 	.equ	write_mark,	0x0200
19 	.equ	write_CRC,	0x0400
20 	.equ	write_parameter,0x0600
21 	.equ	write_phase,	0x0800
22 	.equ	write_setup,	0x0a00
23 	.equ	write_mode0,	0x0c00
24 	.equ	write_mode1,	0x0e00
25 	.equ	read_data,	0x1000
26 	.equ	read_mark,	0x1200
27 	.equ	read_error,	0x1400
28 	.equ	read_parameter,	0x1600
29 	.equ	read_phase,	0x1800
30 	.equ	read_setup,	0x1a00
31 	.equ	read_status,	0x1c00
32 	.equ	read_handshake,	0x1e00
33 
34 	.equ	o_side, 0
35 	.equ	o_track, 1
36 	.equ	o_sector, 2
37 	.equ	o_size, 3
38 	.equ	o_crc0, 4
39 	.equ	o_crc1, 5
40 
41 	.equ	seek_time, 30000
42 	.equ	max_retry, 40
43 	.equ	sector_size, 512
44 
45 	.global swim_read_sector_header
46 swim_read_sector_header:
47 	link	%a6, #0
48 	moveml	%d1-%d5/%a0-%a4,%sp@-
49 	movel	%a6@(0x0c), %a4
50 	bsr	mfm_read_addrmark
51 	moveml	%sp@+, %d1-%d5/%a0-%a4
52 	unlk	%a6
53 	rts
54 
55 sector_address_mark:
56 	.byte	0xa1, 0xa1, 0xa1, 0xfe
57 sector_data_mark:
58 	.byte	0xa1, 0xa1, 0xa1, 0xfb
59 
60 mfm_read_addrmark:
61 	movel	%a6@(0x08), %a3
62 	lea	%a3@(read_handshake), %a2
63 	lea	%a3@(read_mark), %a3
64 	moveq	#-1, %d0
65 	movew	#seek_time, %d2
66 
67 wait_header_init:
68 	tstb	%a3@(read_error - read_mark)
69 	moveb	#0x18, %a3@(write_mode0 - read_mark)
70 	moveb	#0x01, %a3@(write_mode1 - read_mark)
71 	moveb	#0x01, %a3@(write_mode0 - read_mark)
72 	tstb	%a3@(read_error - read_mark)
73 	moveb	#0x08, %a3@(write_mode1 - read_mark)
74 
75 	lea	sector_address_mark, %a0
76 	moveq	#3, %d1
77 
78 wait_addr_mark_byte:
79 
80 	tstb	%a2@
81 	dbmi	%d2, wait_addr_mark_byte
82 	bpl	header_exit
83 
84 	moveb	%a3@, %d3
85 	cmpb	%a0@+, %d3
86 	dbne	%d1, wait_addr_mark_byte
87 	bne	wait_header_init
88 
89 	moveq	#max_retry, %d2
90 
91 amark0:	tstb	%a2@
92 	dbmi	%d2, amark0
93 	bpl	signal_nonyb
94 
95 	moveb	%a3@, %a4@(o_track)
96 
97 	moveq	#max_retry, %d2
98 
99 amark1:	tstb	%a2@
100 	dbmi	%d2, amark1
101 	bpl	signal_nonyb
102 
103 	moveb	%a3@, %a4@(o_side)
104 
105 	moveq	#max_retry, %d2
106 
107 amark2:	tstb	%a2@
108 	dbmi	%d2, amark2
109 	bpl	signal_nonyb
110 
111 	moveb	%a3@, %a4@(o_sector)
112 
113 	moveq	#max_retry, %d2
114 
115 amark3:	tstb	%a2@
116 	dbmi	%d2, amark3
117 	bpl	signal_nonyb
118 
119 	moveb	%a3@, %a4@(o_size)
120 
121 	moveq	#max_retry, %d2
122 
123 crc0:	tstb	%a2@
124 	dbmi	%d2, crc0
125 	bpl	signal_nonyb
126 
127 	moveb	%a3@, %a4@(o_crc0)
128 
129 	moveq	#max_retry, %d2
130 
131 crc1:	tstb	%a2@
132 	dbmi	%d2, crc1
133 	bpl	signal_nonyb
134 
135 	moveb	%a3@, %a4@(o_crc1)
136 
137 	tstb	%a3@(read_error - read_mark)
138 
139 header_exit:
140 	moveq	#0, %d0
141 	moveb	#0x18, %a3@(write_mode0 - read_mark)
142 	rts
143 signal_nonyb:
144 	moveq	#-1, %d0
145 	moveb	#0x18, %a3@(write_mode0 - read_mark)
146 	rts
147 
148 	.global swim_read_sector_data
149 swim_read_sector_data:
150 	link	%a6, #0
151 	moveml	%d1-%d5/%a0-%a5,%sp@-
152 	movel	%a6@(0x0c), %a4
153 	bsr	mfm_read_data
154 	moveml	%sp@+, %d1-%d5/%a0-%a5
155 	unlk	%a6
156 	rts
157 
158 mfm_read_data:
159 	movel	%a6@(0x08), %a3
160 	lea	%a3@(read_handshake), %a2
161 	lea	%a3@(read_data), %a5
162 	lea	%a3@(read_mark), %a3
163 	movew	#seek_time, %d2
164 
165 wait_data_init:
166 	tstb	%a3@(read_error - read_mark)
167 	moveb	#0x18, %a3@(write_mode0 - read_mark)
168 	moveb	#0x01, %a3@(write_mode1 - read_mark)
169 	moveb	#0x01, %a3@(write_mode0 - read_mark)
170 	tstb	%a3@(read_error - read_mark)
171 	moveb	#0x08, %a3@(write_mode1 - read_mark)
172 
173 	lea	sector_data_mark, %a0
174 	moveq	#3, %d1
175 
176 	/* wait data address mark */
177 
178 wait_data_mark_byte:
179 
180 	tstb	%a2@
181 	dbmi	%d2, wait_data_mark_byte
182 	bpl	data_exit
183 
184 	moveb	%a3@, %d3
185 	cmpb	%a0@+, %d3
186 	dbne	%d1, wait_data_mark_byte
187 	bne	wait_data_init
188 
189 	/* read data */
190 
191 	tstb	%a3@(read_error - read_mark)
192 
193 	movel	#sector_size-1, %d4		/* sector size */
194 read_new_data:
195 	movew	#max_retry, %d2
196 read_data_loop:
197 	moveb	%a2@, %d5
198 	andb	#0xc0, %d5
199 	dbne	%d2, read_data_loop
200 	beq	data_exit
201 	moveb	%a5@, %a4@+
202 	andb	#0x40, %d5
203 	dbne	%d4, read_new_data
204 	beq	exit_loop
205 	moveb	%a5@, %a4@+
206 	dbra	%d4, read_new_data
207 exit_loop:
208 
209 	/* read CRC */
210 
211 	movew	#max_retry, %d2
212 data_crc0:
213 
214 	tstb	%a2@
215 	dbmi	%d2, data_crc0
216 	bpl	data_exit
217 
218 	moveb	%a3@, %d5
219 
220 	moveq	#max_retry, %d2
221 
222 data_crc1:
223 
224 	tstb	%a2@
225 	dbmi	%d2, data_crc1
226 	bpl	data_exit
227 
228 	moveb	%a3@, %d5
229 
230 	tstb	%a3@(read_error - read_mark)
231 
232 	moveb	#0x18, %a3@(write_mode0 - read_mark)
233 
234 	/* return number of bytes read */
235 
236 	movel	#sector_size, %d0
237 	addw	#1, %d4
238 	subl	%d4, %d0
239 	rts
240 data_exit:
241 	moveb	#0x18, %a3@(write_mode0 - read_mark)
242 	moveq	#-1, %d0
243 	rts
244