Linux Audio

Check our new training course

In-person Linux kernel drivers training

Jun 16-20, 2025
Register
Loading...
  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
 46swim_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
 55sector_address_mark:
 56	.byte	0xa1, 0xa1, 0xa1, 0xfe
 57sector_data_mark:
 58	.byte	0xa1, 0xa1, 0xa1, 0xfb
 59
 60mfm_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
 67wait_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
 78wait_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
 91amark0:	tstb	%a2@
 92	dbmi	%d2, amark0
 93	bpl	signal_nonyb
 94
 95	moveb	%a3@, %a4@(o_track)
 96
 97	moveq	#max_retry, %d2
 98
 99amark1:	tstb	%a2@
100	dbmi	%d2, amark1
101	bpl	signal_nonyb
102
103	moveb	%a3@, %a4@(o_side)
104
105	moveq	#max_retry, %d2
106
107amark2:	tstb	%a2@
108	dbmi	%d2, amark2
109	bpl	signal_nonyb
110
111	moveb	%a3@, %a4@(o_sector)
112
113	moveq	#max_retry, %d2
114
115amark3:	tstb	%a2@
116	dbmi	%d2, amark3
117	bpl	signal_nonyb
118
119	moveb	%a3@, %a4@(o_size)
120
121	moveq	#max_retry, %d2
122
123crc0:	tstb	%a2@
124	dbmi	%d2, crc0
125	bpl	signal_nonyb
126
127	moveb	%a3@, %a4@(o_crc0)
128
129	moveq	#max_retry, %d2
130
131crc1:	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
139header_exit:
140	moveq	#0, %d0
141	moveb	#0x18, %a3@(write_mode0 - read_mark)
142	rts
143signal_nonyb:
144	moveq	#-1, %d0
145	moveb	#0x18, %a3@(write_mode0 - read_mark)
146	rts
147
148	.global swim_read_sector_data
149swim_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
158mfm_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
165wait_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
178wait_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 */
194read_new_data:
195	movew	#max_retry, %d2
196read_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
207exit_loop:
208
209	/* read CRC */
210
211	movew	#max_retry, %d2
212data_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
222data_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
240data_exit:
241	moveb	#0x18, %a3@(write_mode0 - read_mark)
242	moveq	#-1, %d0
243	rts