1
/*
2
* QEMU Floppy disk emulator ( Intel 82078 )
ths
authored
18 years ago
3
*
4
* Copyright ( c ) 2003 , 2007 Jocelyn Mayer
5
* Copyright ( c ) 2008 Herv é Poussineau
ths
authored
18 years ago
6
*
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the "Software" ), to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
25
26
27
28
/*
* The controller is used in Sun4m systems in a slightly different
* way . There are changes in DOR register and DMA is not available .
*/
29
30
31
32
33
34
# include "hw.h"
# include "fdc.h"
# include "block.h"
# include "qemu-timer.h"
# include "isa.h"
35
# include "sysbus.h"
36
# include "qdev-addr.h"
37
38
39
40
41
42
/********************************************************/
/* debug Floppy devices */
// # define DEBUG_FLOPPY
# ifdef DEBUG_FLOPPY
43
44
# define FLOPPY_DPRINTF ( fmt , ...) \
do { printf ( "FLOPPY: " fmt , ## __VA_ARGS__ ); } while ( 0 )
45
# else
46
# define FLOPPY_DPRINTF ( fmt , ...)
47
48
# endif
49
50
# define FLOPPY_ERROR ( fmt , ...) \
do { printf ( "FLOPPY ERROR: %s: " fmt , __func__ , ## __VA_ARGS__ ); } while ( 0 )
51
52
53
54
/********************************************************/
/* Floppy drive emulation */
55
56
57
# define GET_CUR_DRV ( fdctrl ) (( fdctrl ) -> cur_drv )
# define SET_CUR_DRV ( fdctrl , drive ) (( fdctrl ) -> cur_drv = ( drive ))
58
/* Will always be a fixed parameter for us */
59
60
61
# define FD_SECTOR_LEN 512
# define FD_SECTOR_SC 2 /* Sector size code */
# define FD_RESET_SENSEI_COUNT 4 /* Number of sense interrupts on RESET */
62
63
64
65
66
67
/* Floppy disk drive emulation */
typedef enum fdisk_type_t {
FDRIVE_DISK_288 = 0x01 , /* 2.88 MB disk */
FDRIVE_DISK_144 = 0x02 , /* 1.44 MB disk */
FDRIVE_DISK_720 = 0x03 , /* 720 kB disk */
68
69
FDRIVE_DISK_USER = 0x04 , /* User defined geometry */
FDRIVE_DISK_NONE = 0x05 , /* No disk */
70
71
72
73
74
75
76
77
78
} fdisk_type_t ;
typedef enum fdrive_type_t {
FDRIVE_DRV_144 = 0x00 , /* 1.44 MB 3"5 drive */
FDRIVE_DRV_288 = 0x01 , /* 2.88 MB 3"5 drive */
FDRIVE_DRV_120 = 0x02 , /* 1.2 MB 5"25 drive */
FDRIVE_DRV_NONE = 0x03 , /* No drive connected */
} fdrive_type_t ;
79
80
81
82
typedef enum fdisk_flags_t {
FDISK_DBL_SIDES = 0x01 ,
} fdisk_flags_t ;
83
84
85
86
87
88
89
90
91
92
typedef struct fdrive_t {
BlockDriverState * bs ;
/* Drive status */
fdrive_type_t drive ;
uint8_t perpendicular ; /* 2.88 MB access mode */
/* Position */
uint8_t head ;
uint8_t track ;
uint8_t sect ;
/* Media */
93
fdisk_flags_t flags ;
94
95
uint8_t last_sect ; /* Nb sector per track */
uint8_t max_track ; /* Nb of tracks */
96
uint16_t bps ; /* Bytes per sector */
97
98
99
uint8_t ro ; /* Is read-only */
} fdrive_t ;
100
static void fd_init ( fdrive_t * drv , BlockDriverState * bs )
101
102
{
/* Drive */
103
drv -> bs = bs ;
104
drv -> drive = FDRIVE_DRV_NONE ;
105
106
drv -> perpendicular = 0 ;
/* Disk */
107
drv -> last_sect = 0 ;
108
109
110
111
drv -> max_track = 0 ;
}
static int _fd_sector ( uint8_t head , uint8_t track ,
112
uint8_t sect , uint8_t last_sect )
113
114
115
116
117
118
119
120
121
122
{
return ((( track * 2 ) + head ) * last_sect ) + sect - 1 ;
}
/* Returns current position, in sectors, for given drive */
static int fd_sector ( fdrive_t * drv )
{
return _fd_sector ( drv -> head , drv -> track , drv -> sect , drv -> last_sect );
}
123
124
125
126
127
128
129
/* Seek to a new position :
* returns 0 if already on right track
* returns 1 if track changed
* returns 2 if track is invalid
* returns 3 if sector is invalid
* returns 4 if seek is disabled
*/
130
131
132
133
static int fd_seek ( fdrive_t * drv , uint8_t head , uint8_t track , uint8_t sect ,
int enable_seek )
{
uint32_t sector ;
134
135
136
int ret ;
if ( track > drv -> max_track ||
137
( head != 0 && ( drv -> flags & FDISK_DBL_SIDES ) == 0 )) {
138
139
140
141
FLOPPY_DPRINTF ( "try to read %d %02x %02x (max=%d %d %02x %02x) \n " ,
head , track , sect , 1 ,
( drv -> flags & FDISK_DBL_SIDES ) == 0 ? 0 : 1 ,
drv -> max_track , drv -> last_sect );
142
143
144
return 2 ;
}
if ( sect > drv -> last_sect ) {
145
146
147
148
FLOPPY_DPRINTF ( "try to read %d %02x %02x (max=%d %d %02x %02x) \n " ,
head , track , sect , 1 ,
( drv -> flags & FDISK_DBL_SIDES ) == 0 ? 0 : 1 ,
drv -> max_track , drv -> last_sect );
149
150
151
return 3 ;
}
sector = _fd_sector ( head , track , sect , drv -> last_sect );
152
ret = 0 ;
153
154
155
156
157
158
159
160
161
if ( sector != fd_sector ( drv )) {
# if 0
if ( ! enable_seek ) {
FLOPPY_ERROR ( "no implicit seek %d %02x %02x (max=%d %02x %02x) \n " ,
head , track , sect , 1 , drv -> max_track , drv -> last_sect );
return 4 ;
}
# endif
drv -> head = head ;
162
163
if ( drv -> track != track )
ret = 1 ;
164
165
166
167
drv -> track = track ;
drv -> sect = sect ;
}
168
return ret ;
169
170
171
172
173
174
175
176
177
178
179
}
/* Set drive back to track 0 */
static void fd_recalibrate ( fdrive_t * drv )
{
FLOPPY_DPRINTF ( "recalibrate \n " );
drv -> head = 0 ;
drv -> track = 0 ;
drv -> sect = 1 ;
}
180
181
182
183
184
185
186
/* Recognize floppy formats */
typedef struct fd_format_t {
fdrive_type_t drive ;
fdisk_type_t disk ;
uint8_t last_sect ;
uint8_t max_track ;
uint8_t max_head ;
ths
authored
17 years ago
187
const char * str ;
188
189
} fd_format_t ;
190
static const fd_format_t fd_formats [] = {
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/* First entry is default format */
/* 1.44 MB 3"1/2 floppy disks */
{ FDRIVE_DRV_144 , FDRIVE_DISK_144 , 18 , 80 , 1 , "1.44 MB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_144 , 20 , 80 , 1 , "1.6 MB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_144 , 21 , 80 , 1 , "1.68 MB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_144 , 21 , 82 , 1 , "1.72 MB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_144 , 21 , 83 , 1 , "1.74 MB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_144 , 22 , 80 , 1 , "1.76 MB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_144 , 23 , 80 , 1 , "1.84 MB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_144 , 24 , 80 , 1 , "1.92 MB 3 \" 1/2" , },
/* 2.88 MB 3"1/2 floppy disks */
{ FDRIVE_DRV_288 , FDRIVE_DISK_288 , 36 , 80 , 1 , "2.88 MB 3 \" 1/2" , },
{ FDRIVE_DRV_288 , FDRIVE_DISK_288 , 39 , 80 , 1 , "3.12 MB 3 \" 1/2" , },
{ FDRIVE_DRV_288 , FDRIVE_DISK_288 , 40 , 80 , 1 , "3.2 MB 3 \" 1/2" , },
{ FDRIVE_DRV_288 , FDRIVE_DISK_288 , 44 , 80 , 1 , "3.52 MB 3 \" 1/2" , },
{ FDRIVE_DRV_288 , FDRIVE_DISK_288 , 48 , 80 , 1 , "3.84 MB 3 \" 1/2" , },
/* 720 kB 3"1/2 floppy disks */
{ FDRIVE_DRV_144 , FDRIVE_DISK_720 , 9 , 80 , 1 , "720 kB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_720 , 10 , 80 , 1 , "800 kB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_720 , 10 , 82 , 1 , "820 kB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_720 , 10 , 83 , 1 , "830 kB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_720 , 13 , 80 , 1 , "1.04 MB 3 \" 1/2" , },
{ FDRIVE_DRV_144 , FDRIVE_DISK_720 , 14 , 80 , 1 , "1.12 MB 3 \" 1/2" , },
/* 1.2 MB 5"1/4 floppy disks */
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 15 , 80 , 1 , "1.2 kB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 18 , 80 , 1 , "1.44 MB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 18 , 82 , 1 , "1.48 MB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 18 , 83 , 1 , "1.49 MB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 20 , 80 , 1 , "1.6 MB 5 \" 1/4" , },
/* 720 kB 5"1/4 floppy disks */
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 9 , 80 , 1 , "720 kB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 11 , 80 , 1 , "880 kB 5 \" 1/4" , },
/* 360 kB 5"1/4 floppy disks */
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 9 , 40 , 1 , "360 kB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 9 , 40 , 0 , "180 kB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 10 , 41 , 1 , "410 kB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 10 , 42 , 1 , "420 kB 5 \" 1/4" , },
ths
authored
18 years ago
228
/* 320 kB 5"1/4 floppy disks */
229
230
231
232
233
234
235
236
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 8 , 40 , 1 , "320 kB 5 \" 1/4" , },
{ FDRIVE_DRV_120 , FDRIVE_DISK_288 , 8 , 40 , 0 , "160 kB 5 \" 1/4" , },
/* 360 kB must match 5"1/4 better than 3"1/2... */
{ FDRIVE_DRV_144 , FDRIVE_DISK_720 , 9 , 80 , 0 , "360 kB 3 \" 1/2" , },
/* end */
{ FDRIVE_DRV_NONE , FDRIVE_DISK_NONE , - 1 , - 1 , 0 , NULL , },
};
237
/* Revalidate a disk drive after a disk change */
238
static void fd_revalidate ( fdrive_t * drv )
239
{
240
const fd_format_t * parse ;
ths
authored
17 years ago
241
uint64_t nb_sectors , size ;
242
int i , first_match , match ;
243
int nb_heads , max_track , last_sect , ro ;
244
245
FLOPPY_DPRINTF ( "revalidate \n " );
246
if ( drv -> bs != NULL && bdrv_is_inserted ( drv -> bs )) {
247
248
249
250
ro = bdrv_is_read_only ( drv -> bs );
bdrv_get_geometry_hint ( drv -> bs , & nb_heads , & max_track , & last_sect );
if ( nb_heads != 0 && max_track != 0 && last_sect != 0 ) {
FLOPPY_DPRINTF ( "User defined disk (%d %d %d)" ,
251
nb_heads - 1 , max_track , last_sect );
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
} else {
bdrv_get_geometry ( drv -> bs , & nb_sectors );
match = - 1 ;
first_match = - 1 ;
for ( i = 0 ;; i ++ ) {
parse = & fd_formats [ i ];
if ( parse -> drive == FDRIVE_DRV_NONE )
break ;
if ( drv -> drive == parse -> drive ||
drv -> drive == FDRIVE_DRV_NONE ) {
size = ( parse -> max_head + 1 ) * parse -> max_track *
parse -> last_sect ;
if ( nb_sectors == size ) {
match = i ;
break ;
}
if ( first_match == - 1 )
first_match = i ;
}
}
if ( match == - 1 ) {
if ( first_match == - 1 )
match = 1 ;
else
match = first_match ;
parse = & fd_formats [ match ];
}
nb_heads = parse -> max_head + 1 ;
max_track = parse -> max_track ;
last_sect = parse -> last_sect ;
drv -> drive = parse -> drive ;
FLOPPY_DPRINTF ( "%s floppy disk (%d h %d t %d s) %s \n " , parse -> str ,
284
nb_heads , max_track , last_sect , ro ? "ro" : "rw" );
285
286
287
288
289
290
291
292
293
}
if ( nb_heads == 1 ) {
drv -> flags &= ~ FDISK_DBL_SIDES ;
} else {
drv -> flags |= FDISK_DBL_SIDES ;
}
drv -> max_track = max_track ;
drv -> last_sect = last_sect ;
drv -> ro = ro ;
294
} else {
295
FLOPPY_DPRINTF ( "No disk in drive \n " );
296
drv -> last_sect = 0 ;
297
298
drv -> max_track = 0 ;
drv -> flags &= ~ FDISK_DBL_SIDES ;
299
}
300
301
}
302
/********************************************************/
303
/* Intel 82078 floppy disk controller emulation */
304
305
306
static void fdctrl_reset ( fdctrl_t * fdctrl , int do_irq );
static void fdctrl_reset_fifo ( fdctrl_t * fdctrl );
307
308
static int fdctrl_transfer_handler ( void * opaque , int nchan ,
int dma_pos , int dma_len );
309
static void fdctrl_raise_irq ( fdctrl_t * fdctrl , uint8_t status0 );
310
311
static uint32_t fdctrl_read_statusA ( fdctrl_t * fdctrl );
312
313
314
315
316
317
318
319
320
321
static uint32_t fdctrl_read_statusB ( fdctrl_t * fdctrl );
static uint32_t fdctrl_read_dor ( fdctrl_t * fdctrl );
static void fdctrl_write_dor ( fdctrl_t * fdctrl , uint32_t value );
static uint32_t fdctrl_read_tape ( fdctrl_t * fdctrl );
static void fdctrl_write_tape ( fdctrl_t * fdctrl , uint32_t value );
static uint32_t fdctrl_read_main_status ( fdctrl_t * fdctrl );
static void fdctrl_write_rate ( fdctrl_t * fdctrl , uint32_t value );
static uint32_t fdctrl_read_data ( fdctrl_t * fdctrl );
static void fdctrl_write_data ( fdctrl_t * fdctrl , uint32_t value );
static uint32_t fdctrl_read_dir ( fdctrl_t * fdctrl );
322
323
324
325
326
327
328
329
330
331
enum {
FD_DIR_WRITE = 0 ,
FD_DIR_READ = 1 ,
FD_DIR_SCANE = 2 ,
FD_DIR_SCANL = 3 ,
FD_DIR_SCANH = 4 ,
};
enum {
332
333
334
FD_STATE_MULTI = 0x01 , /* multi track flag */
FD_STATE_FORMAT = 0x02 , /* format flag */
FD_STATE_SEEK = 0x04 , /* seek flag */
335
336
};
337
enum {
338
339
FD_REG_SRA = 0x00 ,
FD_REG_SRB = 0x01 ,
340
341
342
343
344
345
346
347
348
FD_REG_DOR = 0x02 ,
FD_REG_TDR = 0x03 ,
FD_REG_MSR = 0x04 ,
FD_REG_DSR = 0x04 ,
FD_REG_FIFO = 0x05 ,
FD_REG_DIR = 0x07 ,
};
enum {
349
FD_CMD_READ_TRACK = 0x02 ,
350
351
FD_CMD_SPECIFY = 0x03 ,
FD_CMD_SENSE_DRIVE_STATUS = 0x04 ,
352
353
FD_CMD_WRITE = 0x05 ,
FD_CMD_READ = 0x06 ,
354
355
FD_CMD_RECALIBRATE = 0x07 ,
FD_CMD_SENSE_INTERRUPT_STATUS = 0x08 ,
356
357
358
359
FD_CMD_WRITE_DELETED = 0x09 ,
FD_CMD_READ_ID = 0x0a ,
FD_CMD_READ_DELETED = 0x0c ,
FD_CMD_FORMAT_TRACK = 0x0d ,
360
361
362
FD_CMD_DUMPREG = 0x0e ,
FD_CMD_SEEK = 0x0f ,
FD_CMD_VERSION = 0x10 ,
363
FD_CMD_SCAN_EQUAL = 0x11 ,
364
365
FD_CMD_PERPENDICULAR_MODE = 0x12 ,
FD_CMD_CONFIGURE = 0x13 ,
366
367
FD_CMD_LOCK = 0x14 ,
FD_CMD_VERIFY = 0x16 ,
368
369
FD_CMD_POWERDOWN_MODE = 0x17 ,
FD_CMD_PART_ID = 0x18 ,
370
371
FD_CMD_SCAN_LOW_OR_EQUAL = 0x19 ,
FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d ,
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
FD_CMD_SAVE = 0x2c ,
FD_CMD_OPTION = 0x33 ,
FD_CMD_RESTORE = 0x4c ,
FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e ,
FD_CMD_RELATIVE_SEEK_OUT = 0x8f ,
FD_CMD_FORMAT_AND_WRITE = 0xcd ,
FD_CMD_RELATIVE_SEEK_IN = 0xcf ,
};
enum {
FD_CONFIG_PRETRK = 0xff , /* Pre-compensation set to track 0 */
FD_CONFIG_FIFOTHR = 0x0f , /* FIFO threshold set to 1 byte */
FD_CONFIG_POLL = 0x10 , /* Poll enabled */
FD_CONFIG_EFIFO = 0x20 , /* FIFO disabled */
FD_CONFIG_EIS = 0x40 , /* No implied seeks */
};
enum {
FD_SR0_EQPMT = 0x10 ,
FD_SR0_SEEK = 0x20 ,
FD_SR0_ABNTERM = 0x40 ,
FD_SR0_INVCMD = 0x80 ,
FD_SR0_RDYCHG = 0xc0 ,
};
enum {
398
399
400
401
402
403
404
405
406
FD_SR1_EC = 0x80 , /* End of cylinder */
};
enum {
FD_SR2_SNS = 0x04 , /* Scan not satisfied */
FD_SR2_SEH = 0x08 , /* Scan equal hit */
};
enum {
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
FD_SRA_DIR = 0x01 ,
FD_SRA_nWP = 0x02 ,
FD_SRA_nINDX = 0x04 ,
FD_SRA_HDSEL = 0x08 ,
FD_SRA_nTRK0 = 0x10 ,
FD_SRA_STEP = 0x20 ,
FD_SRA_nDRV2 = 0x40 ,
FD_SRA_INTPEND = 0x80 ,
};
enum {
FD_SRB_MTR0 = 0x01 ,
FD_SRB_MTR1 = 0x02 ,
FD_SRB_WGATE = 0x04 ,
FD_SRB_RDATA = 0x08 ,
FD_SRB_WDATA = 0x10 ,
FD_SRB_DR0 = 0x20 ,
};
enum {
427
428
429
# if MAX_FD == 4
FD_DOR_SELMASK = 0x03 ,
# else
430
FD_DOR_SELMASK = 0x01 ,
431
# endif
432
433
434
435
436
437
438
439
440
FD_DOR_nRESET = 0x04 ,
FD_DOR_DMAEN = 0x08 ,
FD_DOR_MOTEN0 = 0x10 ,
FD_DOR_MOTEN1 = 0x20 ,
FD_DOR_MOTEN2 = 0x40 ,
FD_DOR_MOTEN3 = 0x80 ,
};
enum {
441
# if MAX_FD == 4
442
FD_TDR_BOOTSEL = 0x0c ,
443
444
445
# else
FD_TDR_BOOTSEL = 0x04 ,
# endif
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
};
enum {
FD_DSR_DRATEMASK = 0x03 ,
FD_DSR_PWRDOWN = 0x40 ,
FD_DSR_SWRESET = 0x80 ,
};
enum {
FD_MSR_DRV0BUSY = 0x01 ,
FD_MSR_DRV1BUSY = 0x02 ,
FD_MSR_DRV2BUSY = 0x04 ,
FD_MSR_DRV3BUSY = 0x08 ,
FD_MSR_CMDBUSY = 0x10 ,
FD_MSR_NONDMA = 0x20 ,
FD_MSR_DIO = 0x40 ,
FD_MSR_RQM = 0x80 ,
};
enum {
FD_DIR_DSKCHG = 0x80 ,
};
469
470
# define FD_MULTI_TRACK ( state ) (( state ) & FD_STATE_MULTI )
# define FD_DID_SEEK ( state ) (( state ) & FD_STATE_SEEK )
471
# define FD_FORMAT_CMD ( state ) (( state ) & FD_STATE_FORMAT )
472
473
struct fdctrl_t {
474
SysBusDevice busdev ;
475
/* Controller's identification */
476
477
uint8_t version ;
/* HW */
478
qemu_irq irq ;
479
int dma_chann ;
480
/* Controller state */
481
QEMUTimer * result_timer ;
482
483
uint8_t sra ;
uint8_t srb ;
484
uint8_t dor ;
485
uint8_t tdr ;
486
uint8_t dsr ;
487
uint8_t msr ;
488
uint8_t cur_drv ;
489
490
491
uint8_t status0 ;
uint8_t status1 ;
uint8_t status2 ;
492
/* Command FIFO */
493
uint8_t * fifo ;
494
495
496
497
uint32_t data_pos ;
uint32_t data_len ;
uint8_t data_state ;
uint8_t data_dir ;
498
uint8_t eot ; /* last wanted sector */
499
500
501
502
503
504
505
506
507
508
/* States kept only to be returned back */
/* Timers state */
uint8_t timer0 ;
uint8_t timer1 ;
/* precompensation */
uint8_t precomp_trk ;
uint8_t config ;
uint8_t lock ;
/* Power down config (also with status regB access mode */
uint8_t pwrd ;
509
/* Sun4m quirks? */
510
int sun4m ;
511
/* Floppy drives */
512
fdrive_t drives [ MAX_FD ];
513
int reset_sensei ;
514
515
516
517
518
519
520
};
static uint32_t fdctrl_read ( void * opaque , uint32_t reg )
{
fdctrl_t * fdctrl = opaque ;
uint32_t retval ;
521
switch ( reg ) {
522
523
case FD_REG_SRA :
retval = fdctrl_read_statusA ( fdctrl );
524
break ;
525
case FD_REG_SRB :
526
527
retval = fdctrl_read_statusB ( fdctrl );
break ;
528
case FD_REG_DOR :
529
530
retval = fdctrl_read_dor ( fdctrl );
break ;
531
case FD_REG_TDR :
532
retval = fdctrl_read_tape ( fdctrl );
533
break ;
534
case FD_REG_MSR :
535
retval = fdctrl_read_main_status ( fdctrl );
536
break ;
537
case FD_REG_FIFO :
538
retval = fdctrl_read_data ( fdctrl );
539
break ;
540
case FD_REG_DIR :
541
retval = fdctrl_read_dir ( fdctrl );
542
break ;
543
default :
544
545
retval = ( uint32_t )( - 1 );
break ;
546
}
547
FLOPPY_DPRINTF ( "read reg%d: 0x%02x \n " , reg & 7 , retval );
548
549
550
551
552
553
554
555
return retval ;
}
static void fdctrl_write ( void * opaque , uint32_t reg , uint32_t value )
{
fdctrl_t * fdctrl = opaque ;
556
557
FLOPPY_DPRINTF ( "write reg%d: 0x%02x \n " , reg & 7 , value );
558
switch ( reg ) {
559
case FD_REG_DOR :
560
561
fdctrl_write_dor ( fdctrl , value );
break ;
562
case FD_REG_TDR :
563
fdctrl_write_tape ( fdctrl , value );
564
break ;
565
case FD_REG_DSR :
566
fdctrl_write_rate ( fdctrl , value );
567
break ;
568
case FD_REG_FIFO :
569
fdctrl_write_data ( fdctrl , value );
570
break ;
571
default :
572
break ;
573
}
574
575
}
576
577
578
579
580
581
582
583
584
585
static uint32_t fdctrl_read_port ( void * opaque , uint32_t reg )
{
return fdctrl_read ( opaque , reg & 7 );
}
static void fdctrl_write_port ( void * opaque , uint32_t reg , uint32_t value )
{
fdctrl_write ( opaque , reg & 7 , value );
}
586
587
static uint32_t fdctrl_read_mem ( void * opaque , target_phys_addr_t reg )
{
588
return fdctrl_read ( opaque , ( uint32_t ) reg );
589
590
}
ths
authored
18 years ago
591
static void fdctrl_write_mem ( void * opaque ,
592
593
target_phys_addr_t reg , uint32_t value )
{
594
fdctrl_write ( opaque , ( uint32_t ) reg , value );
595
596
}
597
static CPUReadMemoryFunc * fdctrl_mem_read [ 3 ] = {
598
599
600
fdctrl_read_mem ,
fdctrl_read_mem ,
fdctrl_read_mem ,
601
602
603
};
static CPUWriteMemoryFunc * fdctrl_mem_write [ 3 ] = {
604
605
606
fdctrl_write_mem ,
fdctrl_write_mem ,
fdctrl_write_mem ,
607
608
};
609
610
611
612
613
614
615
616
617
618
619
620
static CPUReadMemoryFunc * fdctrl_mem_read_strict [ 3 ] = {
fdctrl_read_mem ,
NULL ,
NULL ,
};
static CPUWriteMemoryFunc * fdctrl_mem_write_strict [ 3 ] = {
fdctrl_write_mem ,
NULL ,
NULL ,
};
621
622
623
624
625
626
627
628
629
630
static void fd_save ( QEMUFile * f , fdrive_t * fd )
{
qemu_put_8s ( f , & fd -> head );
qemu_put_8s ( f , & fd -> track );
qemu_put_8s ( f , & fd -> sect );
}
static void fdc_save ( QEMUFile * f , void * opaque )
{
fdctrl_t * s = opaque ;
631
632
uint8_t tmp ;
int i ;
633
uint8_t dor = s -> dor | GET_CUR_DRV ( s );
634
635
636
637
/* Controller state */
qemu_put_8s ( f , & s -> sra );
qemu_put_8s ( f , & s -> srb );
638
qemu_put_8s ( f , & dor );
639
qemu_put_8s ( f , & s -> tdr );
640
641
642
643
644
645
qemu_put_8s ( f , & s -> dsr );
qemu_put_8s ( f , & s -> msr );
qemu_put_8s ( f , & s -> status0 );
qemu_put_8s ( f , & s -> status1 );
qemu_put_8s ( f , & s -> status2 );
/* Command FIFO */
646
647
648
649
650
651
qemu_put_buffer ( f , s -> fifo , FD_SECTOR_LEN );
qemu_put_be32s ( f , & s -> data_pos );
qemu_put_be32s ( f , & s -> data_len );
qemu_put_8s ( f , & s -> data_state );
qemu_put_8s ( f , & s -> data_dir );
qemu_put_8s ( f , & s -> eot );
652
/* States kept only to be returned back */
653
654
655
656
657
658
qemu_put_8s ( f , & s -> timer0 );
qemu_put_8s ( f , & s -> timer1 );
qemu_put_8s ( f , & s -> precomp_trk );
qemu_put_8s ( f , & s -> config );
qemu_put_8s ( f , & s -> lock );
qemu_put_8s ( f , & s -> pwrd );
659
660
661
662
663
tmp = MAX_FD ;
qemu_put_8s ( f , & tmp );
for ( i = 0 ; i < MAX_FD ; i ++ )
fd_save ( f , & s -> drives [ i ]);
664
665
666
667
668
669
670
671
672
673
674
675
676
677
}
static int fd_load ( QEMUFile * f , fdrive_t * fd )
{
qemu_get_8s ( f , & fd -> head );
qemu_get_8s ( f , & fd -> track );
qemu_get_8s ( f , & fd -> sect );
return 0 ;
}
static int fdc_load ( QEMUFile * f , void * opaque , int version_id )
{
fdctrl_t * s = opaque ;
678
679
int i , ret = 0 ;
uint8_t n ;
680
681
if ( version_id != 2 )
682
683
return - EINVAL ;
684
685
686
/* Controller state */
qemu_get_8s ( f , & s -> sra );
qemu_get_8s ( f , & s -> srb );
687
688
689
qemu_get_8s ( f , & s -> dor );
SET_CUR_DRV ( s , s -> dor & FD_DOR_SELMASK );
s -> dor &= ~ FD_DOR_SELMASK ;
690
qemu_get_8s ( f , & s -> tdr );
691
692
693
694
695
696
qemu_get_8s ( f , & s -> dsr );
qemu_get_8s ( f , & s -> msr );
qemu_get_8s ( f , & s -> status0 );
qemu_get_8s ( f , & s -> status1 );
qemu_get_8s ( f , & s -> status2 );
/* Command FIFO */
697
698
699
700
701
702
qemu_get_buffer ( f , s -> fifo , FD_SECTOR_LEN );
qemu_get_be32s ( f , & s -> data_pos );
qemu_get_be32s ( f , & s -> data_len );
qemu_get_8s ( f , & s -> data_state );
qemu_get_8s ( f , & s -> data_dir );
qemu_get_8s ( f , & s -> eot );
703
/* States kept only to be returned back */
704
705
706
707
708
709
qemu_get_8s ( f , & s -> timer0 );
qemu_get_8s ( f , & s -> timer1 );
qemu_get_8s ( f , & s -> precomp_trk );
qemu_get_8s ( f , & s -> config );
qemu_get_8s ( f , & s -> lock );
qemu_get_8s ( f , & s -> pwrd );
710
qemu_get_8s ( f , & n );
711
712
713
714
715
716
717
718
719
if ( n > MAX_FD )
return - EINVAL ;
for ( i = 0 ; i < n ; i ++ ) {
ret = fd_load ( f , & s -> drives [ i ]);
if ( ret != 0 )
break ;
}
720
721
722
723
724
725
726
727
728
729
730
return ret ;
}
static void fdctrl_external_reset ( void * opaque )
{
fdctrl_t * s = opaque ;
fdctrl_reset ( s , 0 );
}
731
732
733
734
735
736
737
738
739
740
static void fdctrl_handle_tc ( void * opaque , int irq , int level )
{
// fdctrl_t * s = opaque ;
if ( level ) {
// XXX
FLOPPY_DPRINTF ( "TC pulsed \n " );
}
}
741
742
/* XXX: may change if moved to bdrv */
int fdctrl_get_drive_type ( fdctrl_t * fdctrl , int drive_num )
743
{
744
return fdctrl -> drives [ drive_num ]. drive ;
745
746
747
}
/* Change IRQ state */
748
static void fdctrl_reset_irq ( fdctrl_t * fdctrl )
749
{
750
751
if ( ! ( fdctrl -> sra & FD_SRA_INTPEND ))
return ;
752
FLOPPY_DPRINTF ( "Reset interrupt \n " );
753
qemu_set_irq ( fdctrl -> irq , 0 );
754
fdctrl -> sra &= ~ FD_SRA_INTPEND ;
755
756
}
757
static void fdctrl_raise_irq ( fdctrl_t * fdctrl , uint8_t status0 )
758
{
759
760
761
762
763
/* Sparc mutation */
if ( fdctrl -> sun4m && ( fdctrl -> msr & FD_MSR_CMDBUSY )) {
/* XXX: not sure */
fdctrl -> msr &= ~ FD_MSR_CMDBUSY ;
fdctrl -> msr |= FD_MSR_RQM | FD_MSR_DIO ;
764
fdctrl -> status0 = status0 ;
765
return ;
766
}
767
if ( ! ( fdctrl -> sra & FD_SRA_INTPEND )) {
768
qemu_set_irq ( fdctrl -> irq , 1 );
769
fdctrl -> sra |= FD_SRA_INTPEND ;
770
}
771
fdctrl -> reset_sensei = 0 ;
772
773
fdctrl -> status0 = status0 ;
FLOPPY_DPRINTF ( "Set interrupt status to 0x%02x \n " , fdctrl -> status0 );
774
775
}
776
/* Reset controller */
777
static void fdctrl_reset ( fdctrl_t * fdctrl , int do_irq )
778
779
780
{
int i ;
781
FLOPPY_DPRINTF ( "reset controller \n " );
782
fdctrl_reset_irq ( fdctrl );
783
/* Initialise controller */
784
785
786
787
fdctrl -> sra = 0 ;
fdctrl -> srb = 0xc0 ;
if ( ! fdctrl -> drives [ 1 ]. bs )
fdctrl -> sra |= FD_SRA_nDRV2 ;
788
fdctrl -> cur_drv = 0 ;
789
fdctrl -> dor = FD_DOR_nRESET ;
790
fdctrl -> dor |= ( fdctrl -> dma_chann != - 1 ) ? FD_DOR_DMAEN : 0 ;
791
fdctrl -> msr = FD_MSR_RQM ;
792
/* FIFO state */
793
794
fdctrl -> data_pos = 0 ;
fdctrl -> data_len = 0 ;
795
fdctrl -> data_state = 0 ;
796
fdctrl -> data_dir = FD_DIR_WRITE ;
797
for ( i = 0 ; i < MAX_FD ; i ++ )
798
fd_recalibrate ( & fdctrl -> drives [ i ]);
799
fdctrl_reset_fifo ( fdctrl );
800
if ( do_irq ) {
801
fdctrl_raise_irq ( fdctrl , FD_SR0_RDYCHG );
802
fdctrl -> reset_sensei = FD_RESET_SENSEI_COUNT ;
803
}
804
805
806
807
}
static inline fdrive_t * drv0 ( fdctrl_t * fdctrl )
{
808
return & fdctrl -> drives [( fdctrl -> tdr & FD_TDR_BOOTSEL ) >> 2 ];
809
810
811
812
}
static inline fdrive_t * drv1 ( fdctrl_t * fdctrl )
{
813
814
815
816
if (( fdctrl -> tdr & FD_TDR_BOOTSEL ) < ( 1 << 2 ))
return & fdctrl -> drives [ 1 ];
else
return & fdctrl -> drives [ 0 ];
817
818
}
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
# if MAX_FD == 4
static inline fdrive_t * drv2 ( fdctrl_t * fdctrl )
{
if (( fdctrl -> tdr & FD_TDR_BOOTSEL ) < ( 2 << 2 ))
return & fdctrl -> drives [ 2 ];
else
return & fdctrl -> drives [ 1 ];
}
static inline fdrive_t * drv3 ( fdctrl_t * fdctrl )
{
if (( fdctrl -> tdr & FD_TDR_BOOTSEL ) < ( 3 << 2 ))
return & fdctrl -> drives [ 3 ];
else
return & fdctrl -> drives [ 2 ];
}
# endif
837
838
static fdrive_t * get_cur_drv ( fdctrl_t * fdctrl )
{
839
840
841
842
843
844
845
846
847
switch ( fdctrl -> cur_drv ) {
case 0 : return drv0 ( fdctrl );
case 1 : return drv1 ( fdctrl );
# if MAX_FD == 4
case 2 : return drv2 ( fdctrl );
case 3 : return drv3 ( fdctrl );
# endif
default : return NULL ;
}
848
849
}
850
851
852
853
854
855
856
857
858
859
/* Status A register : 0x00 (read-only) */
static uint32_t fdctrl_read_statusA ( fdctrl_t * fdctrl )
{
uint32_t retval = fdctrl -> sra ;
FLOPPY_DPRINTF ( "status register A: 0x%02x \n " , retval );
return retval ;
}
860
/* Status B register : 0x01 (read-only) */
861
static uint32_t fdctrl_read_statusB ( fdctrl_t * fdctrl )
862
{
863
864
865
866
867
uint32_t retval = fdctrl -> srb ;
FLOPPY_DPRINTF ( "status register B: 0x%02x \n " , retval );
return retval ;
868
869
870
}
/* Digital output register : 0x02 */
871
static uint32_t fdctrl_read_dor ( fdctrl_t * fdctrl )
872
{
873
uint32_t retval = fdctrl -> dor ;
874
875
/* Selected drive */
876
retval |= fdctrl -> cur_drv ;
877
878
879
880
881
FLOPPY_DPRINTF ( "digital output register: 0x%02x \n " , retval );
return retval ;
}
882
static void fdctrl_write_dor ( fdctrl_t * fdctrl , uint32_t value )
883
884
{
FLOPPY_DPRINTF ( "digital output register set to 0x%02x \n " , value );
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
/* Motors */
if ( value & FD_DOR_MOTEN0 )
fdctrl -> srb |= FD_SRB_MTR0 ;
else
fdctrl -> srb &= ~ FD_SRB_MTR0 ;
if ( value & FD_DOR_MOTEN1 )
fdctrl -> srb |= FD_SRB_MTR1 ;
else
fdctrl -> srb &= ~ FD_SRB_MTR1 ;
/* Drive */
if ( value & 1 )
fdctrl -> srb |= FD_SRB_DR0 ;
else
fdctrl -> srb &= ~ FD_SRB_DR0 ;
902
/* Reset */
903
if ( ! ( value & FD_DOR_nRESET )) {
904
if ( fdctrl -> dor & FD_DOR_nRESET ) {
905
FLOPPY_DPRINTF ( "controller enter RESET state \n " );
906
907
}
} else {
908
if ( ! ( fdctrl -> dor & FD_DOR_nRESET )) {
909
FLOPPY_DPRINTF ( "controller out of RESET state \n " );
910
fdctrl_reset ( fdctrl , 1 );
911
fdctrl -> dsr &= ~ FD_DSR_PWRDOWN ;
912
913
914
}
}
/* Selected drive */
915
fdctrl -> cur_drv = value & FD_DOR_SELMASK ;
916
917
fdctrl -> dor = value ;
918
919
920
}
/* Tape drive register : 0x03 */
921
static uint32_t fdctrl_read_tape ( fdctrl_t * fdctrl )
922
{
923
uint32_t retval = fdctrl -> tdr ;
924
925
926
927
928
929
FLOPPY_DPRINTF ( "tape drive register: 0x%02x \n " , retval );
return retval ;
}
930
static void fdctrl_write_tape ( fdctrl_t * fdctrl , uint32_t value )
931
932
{
/* Reset mode */
933
if ( ! ( fdctrl -> dor & FD_DOR_nRESET )) {
934
FLOPPY_DPRINTF ( "Floppy controller in RESET state ! \n " );
935
936
937
938
return ;
}
FLOPPY_DPRINTF ( "tape drive register set to 0x%02x \n " , value );
/* Disk boot selection indicator */
939
fdctrl -> tdr = value & FD_TDR_BOOTSEL ;
940
941
942
943
/* Tape indicators: never allow */
}
/* Main status register : 0x04 (read) */
944
static uint32_t fdctrl_read_main_status ( fdctrl_t * fdctrl )
945
{
946
uint32_t retval = fdctrl -> msr ;
947
948
fdctrl -> dsr &= ~ FD_DSR_PWRDOWN ;
949
fdctrl -> dor |= FD_DOR_nRESET ;
950
951
952
953
954
955
956
FLOPPY_DPRINTF ( "main status register: 0x%02x \n " , retval );
return retval ;
}
/* Data select rate register : 0x04 (write) */
957
static void fdctrl_write_rate ( fdctrl_t * fdctrl , uint32_t value )
958
959
{
/* Reset mode */
960
if ( ! ( fdctrl -> dor & FD_DOR_nRESET )) {
961
962
963
FLOPPY_DPRINTF ( "Floppy controller in RESET state ! \n " );
return ;
}
964
965
FLOPPY_DPRINTF ( "select rate register set to 0x%02x \n " , value );
/* Reset: autoclear */
966
if ( value & FD_DSR_SWRESET ) {
967
fdctrl -> dor &= ~ FD_DOR_nRESET ;
968
fdctrl_reset ( fdctrl , 1 );
969
fdctrl -> dor |= FD_DOR_nRESET ;
970
}
971
if ( value & FD_DSR_PWRDOWN ) {
972
fdctrl_reset ( fdctrl , 1 );
973
}
974
fdctrl -> dsr = value ;
975
976
}
977
978
979
static int fdctrl_media_changed ( fdrive_t * drv )
{
int ret ;
980
ths
authored
18 years ago
981
if ( ! drv -> bs )
982
983
984
985
986
987
988
989
return 0 ;
ret = bdrv_media_changed ( drv -> bs );
if ( ret ) {
fd_revalidate ( drv );
}
return ret ;
}
990
/* Digital input register : 0x07 (read-only) */
991
static uint32_t fdctrl_read_dir ( fdctrl_t * fdctrl )
992
993
994
{
uint32_t retval = 0 ;
995
996
997
998
999
1000
1001
if ( fdctrl_media_changed ( drv0 ( fdctrl ))
|| fdctrl_media_changed ( drv1 ( fdctrl ))
# if MAX_FD == 4
|| fdctrl_media_changed ( drv2 ( fdctrl ))
|| fdctrl_media_changed ( drv3 ( fdctrl ))
# endif
)
1002
retval |= FD_DIR_DSKCHG ;
1003
if ( retval != 0 )
1004
FLOPPY_DPRINTF ( "Floppy digital input register: 0x%02x \n " , retval );
1005
1006
1007
1008
1009
return retval ;
}
/* FIFO state control */
1010
static void fdctrl_reset_fifo ( fdctrl_t * fdctrl )
1011
{
1012
1013
fdctrl -> data_dir = FD_DIR_WRITE ;
fdctrl -> data_pos = 0 ;
1014
fdctrl -> msr &= ~ ( FD_MSR_CMDBUSY | FD_MSR_DIO );
1015
1016
1017
}
/* Set FIFO status for the host to read */
1018
static void fdctrl_set_fifo ( fdctrl_t * fdctrl , int fifo_len , int do_irq )
1019
{
1020
1021
1022
fdctrl -> data_dir = FD_DIR_READ ;
fdctrl -> data_len = fifo_len ;
fdctrl -> data_pos = 0 ;
1023
fdctrl -> msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO ;
1024
if ( do_irq )
1025
fdctrl_raise_irq ( fdctrl , 0x00 );
1026
1027
1028
}
/* Set an error: unimplemented/unknown command */
1029
static void fdctrl_unimplemented ( fdctrl_t * fdctrl , int direction )
1030
{
1031
FLOPPY_ERROR ( "unimplemented command 0x%02x \n " , fdctrl -> fifo [ 0 ]);
1032
fdctrl -> fifo [ 0 ] = FD_SR0_INVCMD ;
1033
fdctrl_set_fifo ( fdctrl , 1 , 0 );
1034
1035
}
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
/* Seek to next sector */
static int fdctrl_seek_to_next_sect ( fdctrl_t * fdctrl , fdrive_t * cur_drv )
{
FLOPPY_DPRINTF ( "seek to next sector (%d %02x %02x => %d) \n " ,
cur_drv -> head , cur_drv -> track , cur_drv -> sect ,
fd_sector ( cur_drv ));
/* XXX : cur_drv -> sect >= cur_drv -> last_sect should be an
error in fact */
if ( cur_drv -> sect >= cur_drv -> last_sect ||
cur_drv -> sect == fdctrl -> eot ) {
cur_drv -> sect = 1 ;
if ( FD_MULTI_TRACK ( fdctrl -> data_state )) {
if ( cur_drv -> head == 0 &&
( cur_drv -> flags & FDISK_DBL_SIDES ) != 0 ) {
cur_drv -> head = 1 ;
} else {
cur_drv -> head = 0 ;
cur_drv -> track ++ ;
if (( cur_drv -> flags & FDISK_DBL_SIDES ) == 0 )
return 0 ;
}
} else {
cur_drv -> track ++ ;
return 0 ;
}
FLOPPY_DPRINTF ( "seek to next track (%d %02x %02x => %d) \n " ,
cur_drv -> head , cur_drv -> track ,
cur_drv -> sect , fd_sector ( cur_drv ));
} else {
cur_drv -> sect ++ ;
}
return 1 ;
}
1070
/* Callback for transfer end (stop or abort) */
1071
static void fdctrl_stop_transfer ( fdctrl_t * fdctrl , uint8_t status0 ,
1072
uint8_t status1 , uint8_t status2 )
1073
{
1074
fdrive_t * cur_drv ;
1075
1076
cur_drv = get_cur_drv ( fdctrl );
1077
1078
FLOPPY_DPRINTF ( "transfer status: %02x %02x %02x (%02x) \n " ,
status0 , status1 , status2 ,
1079
1080
status0 | ( cur_drv -> head << 2 ) | GET_CUR_DRV ( fdctrl ));
fdctrl -> fifo [ 0 ] = status0 | ( cur_drv -> head << 2 ) | GET_CUR_DRV ( fdctrl );
1081
1082
1083
1084
1085
1086
1087
fdctrl -> fifo [ 1 ] = status1 ;
fdctrl -> fifo [ 2 ] = status2 ;
fdctrl -> fifo [ 3 ] = cur_drv -> track ;
fdctrl -> fifo [ 4 ] = cur_drv -> head ;
fdctrl -> fifo [ 5 ] = cur_drv -> sect ;
fdctrl -> fifo [ 6 ] = FD_SECTOR_SC ;
fdctrl -> data_dir = FD_DIR_READ ;
1088
if ( ! ( fdctrl -> msr & FD_MSR_NONDMA )) {
1089
DMA_release_DREQ ( fdctrl -> dma_chann );
1090
}
1091
fdctrl -> msr |= FD_MSR_RQM | FD_MSR_DIO ;
1092
fdctrl -> msr &= ~ FD_MSR_NONDMA ;
1093
fdctrl_set_fifo ( fdctrl , 7 , 1 );
1094
1095
1096
}
/* Prepare a data transfer (either DMA or FIFO) */
1097
static void fdctrl_start_transfer ( fdctrl_t * fdctrl , int direction )
1098
{
1099
fdrive_t * cur_drv ;
1100
uint8_t kh , kt , ks ;
1101
int did_seek = 0 ;
1102
1103
SET_CUR_DRV ( fdctrl , fdctrl -> fifo [ 1 ] & FD_DOR_SELMASK );
1104
1105
1106
1107
cur_drv = get_cur_drv ( fdctrl );
kt = fdctrl -> fifo [ 2 ];
kh = fdctrl -> fifo [ 3 ];
ks = fdctrl -> fifo [ 4 ];
1108
FLOPPY_DPRINTF ( "Start transfer at %d %d %02x %02x (%d) \n " ,
1109
GET_CUR_DRV ( fdctrl ), kh , kt , ks ,
1110
_fd_sector ( kh , kt , ks , cur_drv -> last_sect ));
1111
switch ( fd_seek ( cur_drv , kh , kt , ks , fdctrl -> config & FD_CONFIG_EIS )) {
1112
1113
case 2 :
/* sect too big */
1114
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM , 0x00 , 0x00 );
1115
1116
1117
fdctrl -> fifo [ 3 ] = kt ;
fdctrl -> fifo [ 4 ] = kh ;
fdctrl -> fifo [ 5 ] = ks ;
1118
1119
1120
return ;
case 3 :
/* track too big */
1121
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM , FD_SR1_EC , 0x00 );
1122
1123
1124
fdctrl -> fifo [ 3 ] = kt ;
fdctrl -> fifo [ 4 ] = kh ;
fdctrl -> fifo [ 5 ] = ks ;
1125
1126
1127
return ;
case 4 :
/* No seek enabled */
1128
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM , 0x00 , 0x00 );
1129
1130
1131
fdctrl -> fifo [ 3 ] = kt ;
fdctrl -> fifo [ 4 ] = kh ;
fdctrl -> fifo [ 5 ] = ks ;
1132
1133
1134
1135
1136
1137
1138
return ;
case 1 :
did_seek = 1 ;
break ;
default :
break ;
}
1139
1140
/* Set the FIFO state */
1141
1142
fdctrl -> data_dir = direction ;
fdctrl -> data_pos = 0 ;
1143
fdctrl -> msr |= FD_MSR_CMDBUSY ;
1144
1145
1146
1147
if ( fdctrl -> fifo [ 0 ] & 0x80 )
fdctrl -> data_state |= FD_STATE_MULTI ;
else
fdctrl -> data_state &= ~ FD_STATE_MULTI ;
1148
if ( did_seek )
1149
1150
1151
1152
1153
1154
fdctrl -> data_state |= FD_STATE_SEEK ;
else
fdctrl -> data_state &= ~ FD_STATE_SEEK ;
if ( fdctrl -> fifo [ 5 ] == 00 ) {
fdctrl -> data_len = fdctrl -> fifo [ 8 ];
} else {
1155
int tmp ;
ths
authored
18 years ago
1156
fdctrl -> data_len = 128 << ( fdctrl -> fifo [ 5 ] > 7 ? 7 : fdctrl -> fifo [ 5 ]);
1157
tmp = ( fdctrl -> fifo [ 6 ] - ks + 1 );
1158
if ( fdctrl -> fifo [ 0 ] & 0x80 )
1159
tmp += fdctrl -> fifo [ 6 ];
1160
fdctrl -> data_len *= tmp ;
1161
}
1162
fdctrl -> eot = fdctrl -> fifo [ 6 ];
1163
if ( fdctrl -> dor & FD_DOR_DMAEN ) {
1164
1165
int dma_mode ;
/* DMA transfer are enabled. Check if DMA channel is well programmed */
1166
dma_mode = DMA_get_channel_mode ( fdctrl -> dma_chann );
1167
dma_mode = ( dma_mode >> 2 ) & 3 ;
1168
FLOPPY_DPRINTF ( "dma_mode=%d direction=%d (%d - %d) \n " ,
1169
dma_mode , direction ,
1170
( 128 << fdctrl -> fifo [ 5 ]) *
1171
( cur_drv -> last_sect - ks + 1 ), fdctrl -> data_len );
1172
1173
1174
1175
1176
if ((( direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
direction == FD_DIR_SCANH ) && dma_mode == 0 ) ||
( direction == FD_DIR_WRITE && dma_mode == 2 ) ||
( direction == FD_DIR_READ && dma_mode == 1 )) {
/* No access is allowed until DMA transfer has completed */
1177
fdctrl -> msr &= ~ FD_MSR_RQM ;
1178
/* Now , we just have to wait for the DMA controller to
1179
1180
* recall us ...
*/
1181
1182
DMA_hold_DREQ ( fdctrl -> dma_chann );
DMA_schedule ( fdctrl -> dma_chann );
1183
return ;
1184
} else {
1185
FLOPPY_ERROR ( "dma_mode=%d direction=%d \n " , dma_mode , direction );
1186
1187
1188
}
}
FLOPPY_DPRINTF ( "start non-DMA transfer \n " );
1189
fdctrl -> msr |= FD_MSR_NONDMA ;
1190
1191
if ( direction != FD_DIR_WRITE )
fdctrl -> msr |= FD_MSR_DIO ;
1192
/* IO based transfer: calculate len */
1193
fdctrl_raise_irq ( fdctrl , 0x00 );
1194
1195
1196
1197
1198
return ;
}
/* Prepare a transfer of deleted data */
1199
static void fdctrl_start_transfer_del ( fdctrl_t * fdctrl , int direction )
1200
{
1201
1202
FLOPPY_ERROR ( "fdctrl_start_transfer_del() unimplemented \n " );
1203
1204
1205
/* We don ' t handle deleted data ,
* so we don ' t return * ANYTHING *
*/
1206
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM | FD_SR0_SEEK , 0x00 , 0x00 );
1207
1208
1209
}
/* handlers for DMA transfers */
1210
1211
static int fdctrl_transfer_handler ( void * opaque , int nchan ,
int dma_pos , int dma_len )
1212
{
1213
1214
1215
fdctrl_t * fdctrl ;
fdrive_t * cur_drv ;
int len , start_pos , rel_pos ;
1216
1217
uint8_t status0 = 0x00 , status1 = 0x00 , status2 = 0x00 ;
1218
fdctrl = opaque ;
1219
if ( fdctrl -> msr & FD_MSR_RQM ) {
1220
1221
1222
FLOPPY_DPRINTF ( "Not in DMA transfer mode ! \n " );
return 0 ;
}
1223
1224
1225
cur_drv = get_cur_drv ( fdctrl );
if ( fdctrl -> data_dir == FD_DIR_SCANE || fdctrl -> data_dir == FD_DIR_SCANL ||
fdctrl -> data_dir == FD_DIR_SCANH )
1226
status2 = FD_SR2_SNS ;
1227
1228
if ( dma_len > fdctrl -> data_len )
dma_len = fdctrl -> data_len ;
1229
if ( cur_drv -> bs == NULL ) {
1230
if ( fdctrl -> data_dir == FD_DIR_WRITE )
1231
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM | FD_SR0_SEEK , 0x00 , 0x00 );
1232
else
1233
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM , 0x00 , 0x00 );
1234
len = 0 ;
1235
1236
goto transfer_error ;
}
1237
rel_pos = fdctrl -> data_pos % FD_SECTOR_LEN ;
1238
1239
for ( start_pos = fdctrl -> data_pos ; fdctrl -> data_pos < dma_len ;) {
len = dma_len - fdctrl -> data_pos ;
1240
1241
if ( len + rel_pos > FD_SECTOR_LEN )
len = FD_SECTOR_LEN - rel_pos ;
1242
1243
FLOPPY_DPRINTF ( "copy %d bytes (%d %d %d) %d pos %d %02x "
"(%d-0x%08x 0x%08x) \n " , len , dma_len , fdctrl -> data_pos ,
1244
fdctrl -> data_len , GET_CUR_DRV ( fdctrl ), cur_drv -> head ,
1245
cur_drv -> track , cur_drv -> sect , fd_sector ( cur_drv ),
1246
fd_sector ( cur_drv ) * FD_SECTOR_LEN );
1247
if ( fdctrl -> data_dir != FD_DIR_WRITE ||
1248
len < FD_SECTOR_LEN || rel_pos != 0 ) {
1249
1250
/* READ & SCAN commands and realign to a sector for WRITE */
if ( bdrv_read ( cur_drv -> bs , fd_sector ( cur_drv ),
1251
fdctrl -> fifo , 1 ) < 0 ) {
1252
1253
1254
FLOPPY_DPRINTF ( "Floppy: error getting sector %d \n " ,
fd_sector ( cur_drv ));
/* Sure, image size is too small... */
1255
memset ( fdctrl -> fifo , 0 , FD_SECTOR_LEN );
1256
}
1257
}
1258
1259
1260
switch ( fdctrl -> data_dir ) {
case FD_DIR_READ :
/* READ commands */
1261
1262
DMA_write_memory ( nchan , fdctrl -> fifo + rel_pos ,
fdctrl -> data_pos , len );
1263
1264
break ;
case FD_DIR_WRITE :
1265
/* WRITE commands */
1266
1267
DMA_read_memory ( nchan , fdctrl -> fifo + rel_pos ,
fdctrl -> data_pos , len );
1268
if ( bdrv_write ( cur_drv -> bs , fd_sector ( cur_drv ),
1269
fdctrl -> fifo , 1 ) < 0 ) {
1270
FLOPPY_ERROR ( "writing sector %d \n " , fd_sector ( cur_drv ));
1271
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM | FD_SR0_SEEK , 0x00 , 0x00 );
1272
goto transfer_error ;
1273
}
1274
1275
1276
break ;
default :
/* SCAN commands */
1277
{
1278
uint8_t tmpbuf [ FD_SECTOR_LEN ];
1279
int ret ;
1280
DMA_read_memory ( nchan , tmpbuf , fdctrl -> data_pos , len );
1281
ret = memcmp ( tmpbuf , fdctrl -> fifo + rel_pos , len );
1282
if ( ret == 0 ) {
1283
status2 = FD_SR2_SEH ;
1284
1285
goto end_transfer ;
}
1286
1287
if (( ret < 0 && fdctrl -> data_dir == FD_DIR_SCANL ) ||
( ret > 0 && fdctrl -> data_dir == FD_DIR_SCANH )) {
1288
1289
1290
1291
status2 = 0x00 ;
goto end_transfer ;
}
}
1292
break ;
1293
}
1294
1295
fdctrl -> data_pos += len ;
rel_pos = fdctrl -> data_pos % FD_SECTOR_LEN ;
1296
if ( rel_pos == 0 ) {
1297
/* Seek to next sector */
1298
1299
if ( ! fdctrl_seek_to_next_sect ( fdctrl , cur_drv ))
break ;
1300
1301
}
}
1302
end_transfer :
1303
1304
len = fdctrl -> data_pos - start_pos ;
FLOPPY_DPRINTF ( "end transfer %d %d %d \n " ,
1305
fdctrl -> data_pos , len , fdctrl -> data_len );
1306
1307
1308
if ( fdctrl -> data_dir == FD_DIR_SCANE ||
fdctrl -> data_dir == FD_DIR_SCANL ||
fdctrl -> data_dir == FD_DIR_SCANH )
1309
status2 = FD_SR2_SEH ;
1310
if ( FD_DID_SEEK ( fdctrl -> data_state ))
1311
status0 |= FD_SR0_SEEK ;
1312
fdctrl -> data_len -= len ;
1313
fdctrl_stop_transfer ( fdctrl , status0 , status1 , status2 );
1314
transfer_error :
1315
1316
return len ;
1317
1318
1319
}
/* Data register : 0x05 */
1320
static uint32_t fdctrl_read_data ( fdctrl_t * fdctrl )
1321
{
1322
fdrive_t * cur_drv ;
1323
uint32_t retval = 0 ;
1324
int pos ;
1325
1326
cur_drv = get_cur_drv ( fdctrl );
1327
1328
1329
fdctrl -> dsr &= ~ FD_DSR_PWRDOWN ;
if ( ! ( fdctrl -> msr & FD_MSR_RQM ) || ! ( fdctrl -> msr & FD_MSR_DIO )) {
FLOPPY_ERROR ( "controller not ready for reading \n " );
1330
1331
return 0 ;
}
1332
pos = fdctrl -> data_pos ;
1333
if ( fdctrl -> msr & FD_MSR_NONDMA ) {
1334
1335
pos %= FD_SECTOR_LEN ;
if ( pos == 0 ) {
1336
1337
1338
1339
1340
1341
if ( fdctrl -> data_pos != 0 )
if ( ! fdctrl_seek_to_next_sect ( fdctrl , cur_drv )) {
FLOPPY_DPRINTF ( "error seeking to next sector %d \n " ,
fd_sector ( cur_drv ));
return 0 ;
}
1342
1343
1344
1345
1346
1347
if ( bdrv_read ( cur_drv -> bs , fd_sector ( cur_drv ), fdctrl -> fifo , 1 ) < 0 ) {
FLOPPY_DPRINTF ( "error getting sector %d \n " ,
fd_sector ( cur_drv ));
/* Sure, image size is too small... */
memset ( fdctrl -> fifo , 0 , FD_SECTOR_LEN );
}
1348
1349
}
}
1350
1351
1352
retval = fdctrl -> fifo [ pos ];
if ( ++ fdctrl -> data_pos == fdctrl -> data_len ) {
fdctrl -> data_pos = 0 ;
1353
/* Switch from transfer mode to status mode
1354
1355
* then from status mode to command mode
*/
1356
if ( fdctrl -> msr & FD_MSR_NONDMA ) {
1357
fdctrl_stop_transfer ( fdctrl , FD_SR0_SEEK , 0x00 , 0x00 );
1358
} else {
1359
fdctrl_reset_fifo ( fdctrl );
1360
1361
fdctrl_reset_irq ( fdctrl );
}
1362
1363
1364
1365
1366
1367
}
FLOPPY_DPRINTF ( "data register: 0x%02x \n " , retval );
return retval ;
}
1368
static void fdctrl_format_sector ( fdctrl_t * fdctrl )
1369
{
1370
1371
fdrive_t * cur_drv ;
uint8_t kh , kt , ks ;
1372
1373
SET_CUR_DRV ( fdctrl , fdctrl -> fifo [ 1 ] & FD_DOR_SELMASK );
1374
1375
1376
1377
1378
cur_drv = get_cur_drv ( fdctrl );
kt = fdctrl -> fifo [ 6 ];
kh = fdctrl -> fifo [ 7 ];
ks = fdctrl -> fifo [ 8 ];
FLOPPY_DPRINTF ( "format sector at %d %d %02x %02x (%d) \n " ,
1379
GET_CUR_DRV ( fdctrl ), kh , kt , ks ,
1380
_fd_sector ( kh , kt , ks , cur_drv -> last_sect ));
1381
switch ( fd_seek ( cur_drv , kh , kt , ks , fdctrl -> config & FD_CONFIG_EIS )) {
1382
1383
case 2 :
/* sect too big */
1384
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM , 0x00 , 0x00 );
1385
1386
1387
1388
1389
1390
fdctrl -> fifo [ 3 ] = kt ;
fdctrl -> fifo [ 4 ] = kh ;
fdctrl -> fifo [ 5 ] = ks ;
return ;
case 3 :
/* track too big */
1391
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM , FD_SR1_EC , 0x00 );
1392
1393
1394
1395
1396
1397
fdctrl -> fifo [ 3 ] = kt ;
fdctrl -> fifo [ 4 ] = kh ;
fdctrl -> fifo [ 5 ] = ks ;
return ;
case 4 :
/* No seek enabled */
1398
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM , 0x00 , 0x00 );
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
fdctrl -> fifo [ 3 ] = kt ;
fdctrl -> fifo [ 4 ] = kh ;
fdctrl -> fifo [ 5 ] = ks ;
return ;
case 1 :
fdctrl -> data_state |= FD_STATE_SEEK ;
break ;
default :
break ;
}
memset ( fdctrl -> fifo , 0 , FD_SECTOR_LEN );
if ( cur_drv -> bs == NULL ||
bdrv_write ( cur_drv -> bs , fd_sector ( cur_drv ), fdctrl -> fifo , 1 ) < 0 ) {
ths
authored
18 years ago
1412
FLOPPY_ERROR ( "formatting sector %d \n " , fd_sector ( cur_drv ));
1413
fdctrl_stop_transfer ( fdctrl , FD_SR0_ABNTERM | FD_SR0_SEEK , 0x00 , 0x00 );
1414
} else {
1415
1416
1417
1418
if ( cur_drv -> sect == cur_drv -> last_sect ) {
fdctrl -> data_state &= ~ FD_STATE_FORMAT ;
/* Last sector done */
if ( FD_DID_SEEK ( fdctrl -> data_state ))
1419
fdctrl_stop_transfer ( fdctrl , FD_SR0_SEEK , 0x00 , 0x00 );
1420
1421
1422
1423
1424
1425
1426
else
fdctrl_stop_transfer ( fdctrl , 0x00 , 0x00 , 0x00 );
} else {
/* More to do */
fdctrl -> data_pos = 0 ;
fdctrl -> data_len = 4 ;
}
1427
1428
1429
}
}
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
static void fdctrl_handle_lock ( fdctrl_t * fdctrl , int direction )
{
fdctrl -> lock = ( fdctrl -> fifo [ 0 ] & 0x80 ) ? 1 : 0 ;
fdctrl -> fifo [ 0 ] = fdctrl -> lock << 4 ;
fdctrl_set_fifo ( fdctrl , 1 , fdctrl -> lock );
}
static void fdctrl_handle_dumpreg ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv = get_cur_drv ( fdctrl );
/* Drives position */
fdctrl -> fifo [ 0 ] = drv0 ( fdctrl ) -> track ;
fdctrl -> fifo [ 1 ] = drv1 ( fdctrl ) -> track ;
1444
1445
1446
1447
# if MAX_FD == 4
fdctrl -> fifo [ 2 ] = drv2 ( fdctrl ) -> track ;
fdctrl -> fifo [ 3 ] = drv3 ( fdctrl ) -> track ;
# else
1448
1449
fdctrl -> fifo [ 2 ] = 0 ;
fdctrl -> fifo [ 3 ] = 0 ;
1450
# endif
1451
1452
/* timers */
fdctrl -> fifo [ 4 ] = fdctrl -> timer0 ;
1453
fdctrl -> fifo [ 5 ] = ( fdctrl -> timer1 << 1 ) | ( fdctrl -> dor & FD_DOR_DMAEN ? 1 : 0 );
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
fdctrl -> fifo [ 6 ] = cur_drv -> last_sect ;
fdctrl -> fifo [ 7 ] = ( fdctrl -> lock << 7 ) |
( cur_drv -> perpendicular << 2 );
fdctrl -> fifo [ 8 ] = fdctrl -> config ;
fdctrl -> fifo [ 9 ] = fdctrl -> precomp_trk ;
fdctrl_set_fifo ( fdctrl , 10 , 0 );
}
static void fdctrl_handle_version ( fdctrl_t * fdctrl , int direction )
{
/* Controller's version */
fdctrl -> fifo [ 0 ] = fdctrl -> version ;
fdctrl_set_fifo ( fdctrl , 1 , 1 );
}
static void fdctrl_handle_partid ( fdctrl_t * fdctrl , int direction )
{
fdctrl -> fifo [ 0 ] = 0x41 ; /* Stepping 1 */
fdctrl_set_fifo ( fdctrl , 1 , 0 );
}
static void fdctrl_handle_restore ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv = get_cur_drv ( fdctrl );
/* Drives position */
drv0 ( fdctrl ) -> track = fdctrl -> fifo [ 3 ];
drv1 ( fdctrl ) -> track = fdctrl -> fifo [ 4 ];
1482
1483
1484
1485
# if MAX_FD == 4
drv2 ( fdctrl ) -> track = fdctrl -> fifo [ 5 ];
drv3 ( fdctrl ) -> track = fdctrl -> fifo [ 6 ];
# endif
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
/* timers */
fdctrl -> timer0 = fdctrl -> fifo [ 7 ];
fdctrl -> timer1 = fdctrl -> fifo [ 8 ];
cur_drv -> last_sect = fdctrl -> fifo [ 9 ];
fdctrl -> lock = fdctrl -> fifo [ 10 ] >> 7 ;
cur_drv -> perpendicular = ( fdctrl -> fifo [ 10 ] >> 2 ) & 0xF ;
fdctrl -> config = fdctrl -> fifo [ 11 ];
fdctrl -> precomp_trk = fdctrl -> fifo [ 12 ];
fdctrl -> pwrd = fdctrl -> fifo [ 13 ];
fdctrl_reset_fifo ( fdctrl );
}
static void fdctrl_handle_save ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv = get_cur_drv ( fdctrl );
fdctrl -> fifo [ 0 ] = 0 ;
fdctrl -> fifo [ 1 ] = 0 ;
/* Drives position */
fdctrl -> fifo [ 2 ] = drv0 ( fdctrl ) -> track ;
fdctrl -> fifo [ 3 ] = drv1 ( fdctrl ) -> track ;
1507
1508
1509
1510
# if MAX_FD == 4
fdctrl -> fifo [ 4 ] = drv2 ( fdctrl ) -> track ;
fdctrl -> fifo [ 5 ] = drv3 ( fdctrl ) -> track ;
# else
1511
1512
fdctrl -> fifo [ 4 ] = 0 ;
fdctrl -> fifo [ 5 ] = 0 ;
1513
# endif
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
/* timers */
fdctrl -> fifo [ 6 ] = fdctrl -> timer0 ;
fdctrl -> fifo [ 7 ] = fdctrl -> timer1 ;
fdctrl -> fifo [ 8 ] = cur_drv -> last_sect ;
fdctrl -> fifo [ 9 ] = ( fdctrl -> lock << 7 ) |
( cur_drv -> perpendicular << 2 );
fdctrl -> fifo [ 10 ] = fdctrl -> config ;
fdctrl -> fifo [ 11 ] = fdctrl -> precomp_trk ;
fdctrl -> fifo [ 12 ] = fdctrl -> pwrd ;
fdctrl -> fifo [ 13 ] = 0 ;
fdctrl -> fifo [ 14 ] = 0 ;
fdctrl_set_fifo ( fdctrl , 15 , 1 );
}
static void fdctrl_handle_readid ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv = get_cur_drv ( fdctrl );
/* XXX: should set main status register to busy */
cur_drv -> head = ( fdctrl -> fifo [ 1 ] >> 2 ) & 1 ;
qemu_mod_timer ( fdctrl -> result_timer ,
qemu_get_clock ( vm_clock ) + ( ticks_per_sec / 50 ));
}
static void fdctrl_handle_format_track ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv ;
1542
SET_CUR_DRV ( fdctrl , fdctrl -> fifo [ 1 ] & FD_DOR_SELMASK );
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
cur_drv = get_cur_drv ( fdctrl );
fdctrl -> data_state |= FD_STATE_FORMAT ;
if ( fdctrl -> fifo [ 0 ] & 0x80 )
fdctrl -> data_state |= FD_STATE_MULTI ;
else
fdctrl -> data_state &= ~ FD_STATE_MULTI ;
fdctrl -> data_state &= ~ FD_STATE_SEEK ;
cur_drv -> bps =
fdctrl -> fifo [ 2 ] > 7 ? 16384 : 128 << fdctrl -> fifo [ 2 ];
# if 0
cur_drv -> last_sect =
cur_drv -> flags & FDISK_DBL_SIDES ? fdctrl -> fifo [ 3 ] :
fdctrl -> fifo [ 3 ] / 2 ;
# else
cur_drv -> last_sect = fdctrl -> fifo [ 3 ];
# endif
/* TODO : implement format using DMA expected by the Bochs BIOS
* and Linux fdformat ( read 3 bytes per sector via DMA and fill
* the sector with the specified fill byte
*/
fdctrl -> data_state &= ~ FD_STATE_FORMAT ;
fdctrl_stop_transfer ( fdctrl , 0x00 , 0x00 , 0x00 );
}
static void fdctrl_handle_specify ( fdctrl_t * fdctrl , int direction )
{
fdctrl -> timer0 = ( fdctrl -> fifo [ 1 ] >> 4 ) & 0xF ;
fdctrl -> timer1 = fdctrl -> fifo [ 2 ] >> 1 ;
1571
1572
1573
1574
if ( fdctrl -> fifo [ 2 ] & 1 )
fdctrl -> dor &= ~ FD_DOR_DMAEN ;
else
fdctrl -> dor |= FD_DOR_DMAEN ;
1575
1576
1577
1578
1579
1580
1581
1582
/* No result back */
fdctrl_reset_fifo ( fdctrl );
}
static void fdctrl_handle_sense_drive_status ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv ;
1583
SET_CUR_DRV ( fdctrl , fdctrl -> fifo [ 1 ] & FD_DOR_SELMASK );
1584
1585
1586
1587
1588
1589
cur_drv = get_cur_drv ( fdctrl );
cur_drv -> head = ( fdctrl -> fifo [ 1 ] >> 2 ) & 1 ;
/* 1 Byte status back */
fdctrl -> fifo [ 0 ] = ( cur_drv -> ro << 6 ) |
( cur_drv -> track == 0 ? 0x10 : 0x00 ) |
( cur_drv -> head << 2 ) |
1590
GET_CUR_DRV ( fdctrl ) |
1591
1592
1593
1594
1595
1596
1597
1598
0x28 ;
fdctrl_set_fifo ( fdctrl , 1 , 0 );
}
static void fdctrl_handle_recalibrate ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv ;
1599
SET_CUR_DRV ( fdctrl , fdctrl -> fifo [ 1 ] & FD_DOR_SELMASK );
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
cur_drv = get_cur_drv ( fdctrl );
fd_recalibrate ( cur_drv );
fdctrl_reset_fifo ( fdctrl );
/* Raise Interrupt */
fdctrl_raise_irq ( fdctrl , FD_SR0_SEEK );
}
static void fdctrl_handle_sense_interrupt_status ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv = get_cur_drv ( fdctrl );
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
if ( fdctrl -> reset_sensei > 0 ) {
fdctrl -> fifo [ 0 ] =
FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl -> reset_sensei ;
fdctrl -> reset_sensei -- ;
} else {
/* XXX : status0 handling is broken for read / write
commands , so we do this hack . It should be suppressed
ASAP */
fdctrl -> fifo [ 0 ] =
FD_SR0_SEEK | ( cur_drv -> head << 2 ) | GET_CUR_DRV ( fdctrl );
}
1623
1624
1625
fdctrl -> fifo [ 1 ] = cur_drv -> track ;
fdctrl_set_fifo ( fdctrl , 2 , 0 );
fdctrl_reset_irq ( fdctrl );
1626
fdctrl -> status0 = FD_SR0_RDYCHG ;
1627
1628
1629
1630
1631
1632
}
static void fdctrl_handle_seek ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv ;
1633
SET_CUR_DRV ( fdctrl , fdctrl -> fifo [ 1 ] & FD_DOR_SELMASK );
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
cur_drv = get_cur_drv ( fdctrl );
fdctrl_reset_fifo ( fdctrl );
if ( fdctrl -> fifo [ 2 ] > cur_drv -> max_track ) {
fdctrl_raise_irq ( fdctrl , FD_SR0_ABNTERM | FD_SR0_SEEK );
} else {
cur_drv -> track = fdctrl -> fifo [ 2 ];
/* Raise Interrupt */
fdctrl_raise_irq ( fdctrl , FD_SR0_SEEK );
}
}
static void fdctrl_handle_perpendicular_mode ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv = get_cur_drv ( fdctrl );
if ( fdctrl -> fifo [ 1 ] & 0x80 )
cur_drv -> perpendicular = fdctrl -> fifo [ 1 ] & 0x7 ;
/* No result back */
1652
fdctrl_reset_fifo ( fdctrl );
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
}
static void fdctrl_handle_configure ( fdctrl_t * fdctrl , int direction )
{
fdctrl -> config = fdctrl -> fifo [ 2 ];
fdctrl -> precomp_trk = fdctrl -> fifo [ 3 ];
/* No result back */
fdctrl_reset_fifo ( fdctrl );
}
static void fdctrl_handle_powerdown_mode ( fdctrl_t * fdctrl , int direction )
{
fdctrl -> pwrd = fdctrl -> fifo [ 1 ];
fdctrl -> fifo [ 0 ] = fdctrl -> fifo [ 1 ];
fdctrl_set_fifo ( fdctrl , 1 , 1 );
}
static void fdctrl_handle_option ( fdctrl_t * fdctrl , int direction )
{
/* No result back */
fdctrl_reset_fifo ( fdctrl );
}
static void fdctrl_handle_drive_specification_command ( fdctrl_t * fdctrl , int direction )
{
fdrive_t * cur_drv = get_cur_drv ( fdctrl );
if ( fdctrl -> fifo [ fdctrl -> data_pos - 1 ] & 0x80 ) {
/* Command parameters done */
if ( fdctrl -> fifo [ fdctrl -> data_pos - 1 ] & 0x40 ) {
fdctrl -> fifo [ 0 ] = fdctrl -> fifo [ 1 ];
fdctrl -> fifo [ 2 ] = 0 ;
fdctrl -> fifo [ 3 ] = 0 ;
fdctrl_set_fifo ( fdctrl , 4 , 1 );
} else {
fdctrl_reset_fifo ( fdctrl );
}
} else if ( fdctrl -> data_len > 7 ) {
/* ERROR */
fdctrl -> fifo [ 0 ] = 0x80 |
1693
( cur_drv -> head << 2 ) | GET_CUR_DRV ( fdctrl );
1694
1695
1696
1697
1698
1699
fdctrl_set_fifo ( fdctrl , 1 , 1 );
}
}
static void fdctrl_handle_relative_seek_out ( fdctrl_t * fdctrl , int direction )
{
1700
fdrive_t * cur_drv ;
1701
1702
SET_CUR_DRV ( fdctrl , fdctrl -> fifo [ 1 ] & FD_DOR_SELMASK );
1703
1704
1705
1706
1707
1708
1709
cur_drv = get_cur_drv ( fdctrl );
if ( fdctrl -> fifo [ 2 ] + cur_drv -> track >= cur_drv -> max_track ) {
cur_drv -> track = cur_drv -> max_track - 1 ;
} else {
cur_drv -> track += fdctrl -> fifo [ 2 ];
}
fdctrl_reset_fifo ( fdctrl );
1710
/* Raise Interrupt */
1711
1712
1713
1714
1715
fdctrl_raise_irq ( fdctrl , FD_SR0_SEEK );
}
static void fdctrl_handle_relative_seek_in ( fdctrl_t * fdctrl , int direction )
{
1716
fdrive_t * cur_drv ;
1717
1718
SET_CUR_DRV ( fdctrl , fdctrl -> fifo [ 1 ] & FD_DOR_SELMASK );
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
cur_drv = get_cur_drv ( fdctrl );
if ( fdctrl -> fifo [ 2 ] > cur_drv -> track ) {
cur_drv -> track = 0 ;
} else {
cur_drv -> track -= fdctrl -> fifo [ 2 ];
}
fdctrl_reset_fifo ( fdctrl );
/* Raise Interrupt */
fdctrl_raise_irq ( fdctrl , FD_SR0_SEEK );
}
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
static const struct {
uint8_t value ;
uint8_t mask ;
const char * name ;
int parameters ;
void ( * handler )( fdctrl_t * fdctrl , int direction );
int direction ;
} handlers [] = {
{ FD_CMD_READ , 0x1f , "READ" , 8 , fdctrl_start_transfer , FD_DIR_READ },
{ FD_CMD_WRITE , 0x3f , "WRITE" , 8 , fdctrl_start_transfer , FD_DIR_WRITE },
{ FD_CMD_SEEK , 0xff , "SEEK" , 2 , fdctrl_handle_seek },
{ FD_CMD_SENSE_INTERRUPT_STATUS , 0xff , "SENSE INTERRUPT STATUS" , 0 , fdctrl_handle_sense_interrupt_status },
{ FD_CMD_RECALIBRATE , 0xff , "RECALIBRATE" , 1 , fdctrl_handle_recalibrate },
{ FD_CMD_FORMAT_TRACK , 0xbf , "FORMAT TRACK" , 5 , fdctrl_handle_format_track },
{ FD_CMD_READ_TRACK , 0xbf , "READ TRACK" , 8 , fdctrl_start_transfer , FD_DIR_READ },
{ FD_CMD_RESTORE , 0xff , "RESTORE" , 17 , fdctrl_handle_restore }, /* part of READ DELETED DATA */
{ FD_CMD_SAVE , 0xff , "SAVE" , 0 , fdctrl_handle_save }, /* part of READ DELETED DATA */
{ FD_CMD_READ_DELETED , 0x1f , "READ DELETED DATA" , 8 , fdctrl_start_transfer_del , FD_DIR_READ },
{ FD_CMD_SCAN_EQUAL , 0x1f , "SCAN EQUAL" , 8 , fdctrl_start_transfer , FD_DIR_SCANE },
{ FD_CMD_VERIFY , 0x1f , "VERIFY" , 8 , fdctrl_unimplemented },
{ FD_CMD_SCAN_LOW_OR_EQUAL , 0x1f , "SCAN LOW OR EQUAL" , 8 , fdctrl_start_transfer , FD_DIR_SCANL },
{ FD_CMD_SCAN_HIGH_OR_EQUAL , 0x1f , "SCAN HIGH OR EQUAL" , 8 , fdctrl_start_transfer , FD_DIR_SCANH },
{ FD_CMD_WRITE_DELETED , 0x3f , "WRITE DELETED DATA" , 8 , fdctrl_start_transfer_del , FD_DIR_WRITE },
{ FD_CMD_READ_ID , 0xbf , "READ ID" , 1 , fdctrl_handle_readid },
{ FD_CMD_SPECIFY , 0xff , "SPECIFY" , 2 , fdctrl_handle_specify },
{ FD_CMD_SENSE_DRIVE_STATUS , 0xff , "SENSE DRIVE STATUS" , 1 , fdctrl_handle_sense_drive_status },
{ FD_CMD_PERPENDICULAR_MODE , 0xff , "PERPENDICULAR MODE" , 1 , fdctrl_handle_perpendicular_mode },
{ FD_CMD_CONFIGURE , 0xff , "CONFIGURE" , 3 , fdctrl_handle_configure },
{ FD_CMD_POWERDOWN_MODE , 0xff , "POWERDOWN MODE" , 2 , fdctrl_handle_powerdown_mode },
{ FD_CMD_OPTION , 0xff , "OPTION" , 1 , fdctrl_handle_option },
{ FD_CMD_DRIVE_SPECIFICATION_COMMAND , 0xff , "DRIVE SPECIFICATION COMMAND" , 5 , fdctrl_handle_drive_specification_command },
{ FD_CMD_RELATIVE_SEEK_OUT , 0xff , "RELATIVE SEEK OUT" , 2 , fdctrl_handle_relative_seek_out },
{ FD_CMD_FORMAT_AND_WRITE , 0xff , "FORMAT AND WRITE" , 10 , fdctrl_unimplemented },
{ FD_CMD_RELATIVE_SEEK_IN , 0xff , "RELATIVE SEEK IN" , 2 , fdctrl_handle_relative_seek_in },
{ FD_CMD_LOCK , 0x7f , "LOCK" , 0 , fdctrl_handle_lock },
{ FD_CMD_DUMPREG , 0xff , "DUMPREG" , 0 , fdctrl_handle_dumpreg },
{ FD_CMD_VERSION , 0xff , "VERSION" , 0 , fdctrl_handle_version },
{ FD_CMD_PART_ID , 0xff , "PART ID" , 0 , fdctrl_handle_partid },
{ FD_CMD_WRITE , 0x1f , "WRITE (BeOS)" , 8 , fdctrl_start_transfer , FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
{ 0 , 0 , "unknown" , 0 , fdctrl_unimplemented }, /* default handler */
};
/* Associate command to an index in the 'handlers' array */
static uint8_t command_to_handler [ 256 ];
1774
1775
1776
static void fdctrl_write_data ( fdctrl_t * fdctrl , uint32_t value )
{
fdrive_t * cur_drv ;
1777
int pos ;
1778
1779
/* Reset mode */
1780
if ( ! ( fdctrl -> dor & FD_DOR_nRESET )) {
1781
FLOPPY_DPRINTF ( "Floppy controller in RESET state ! \n " );
1782
1783
return ;
}
1784
1785
if ( ! ( fdctrl -> msr & FD_MSR_RQM ) || ( fdctrl -> msr & FD_MSR_DIO )) {
FLOPPY_ERROR ( "controller not ready for writing \n " );
1786
1787
return ;
}
1788
fdctrl -> dsr &= ~ FD_DSR_PWRDOWN ;
1789
/* Is it write command time ? */
1790
if ( fdctrl -> msr & FD_MSR_NONDMA ) {
1791
/* FIFO data write */
1792
1793
1794
1795
pos = fdctrl -> data_pos ++ ;
pos %= FD_SECTOR_LEN ;
fdctrl -> fifo [ pos ] = value ;
if ( pos == FD_SECTOR_LEN - 1 ||
1796
fdctrl -> data_pos == fdctrl -> data_len ) {
1797
1798
1799
1800
1801
cur_drv = get_cur_drv ( fdctrl );
if ( bdrv_write ( cur_drv -> bs , fd_sector ( cur_drv ), fdctrl -> fifo , 1 ) < 0 ) {
FLOPPY_ERROR ( "writing sector %d \n " , fd_sector ( cur_drv ));
return ;
}
1802
1803
1804
1805
1806
if ( ! fdctrl_seek_to_next_sect ( fdctrl , cur_drv )) {
FLOPPY_DPRINTF ( "error seeking to next sector %d \n " ,
fd_sector ( cur_drv ));
return ;
}
1807
}
1808
/* Switch from transfer mode to status mode
1809
1810
* then from status mode to command mode
*/
1811
if ( fdctrl -> data_pos == fdctrl -> data_len )
1812
fdctrl_stop_transfer ( fdctrl , FD_SR0_SEEK , 0x00 , 0x00 );
1813
1814
return ;
}
1815
if ( fdctrl -> data_pos == 0 ) {
1816
/* Command */
1817
1818
1819
pos = command_to_handler [ value & 0xff ];
FLOPPY_DPRINTF ( "%s command \n " , handlers [ pos ]. name );
fdctrl -> data_len = handlers [ pos ]. parameters + 1 ;
1820
}
1821
1822
FLOPPY_DPRINTF ( "%s: %02x \n " , __func__ , value );
1823
1824
fdctrl -> fifo [ fdctrl -> data_pos ++ ] = value ;
if ( fdctrl -> data_pos == fdctrl -> data_len ) {
1825
1826
1827
/* We now have all parameters
* and will be able to treat the command
*/
1828
1829
if ( fdctrl -> data_state & FD_STATE_FORMAT ) {
fdctrl_format_sector ( fdctrl );
1830
1831
return ;
}
1832
1833
1834
1835
pos = command_to_handler [ fdctrl -> fifo [ 0 ] & 0xff ];
FLOPPY_DPRINTF ( "treat %s command \n " , handlers [ pos ]. name );
( * handlers [ pos ]. handler )( fdctrl , handlers [ pos ]. direction );
1836
1837
}
}
1838
1839
1840
1841
static void fdctrl_result_timer ( void * opaque )
{
fdctrl_t * fdctrl = opaque ;
ths
authored
18 years ago
1842
fdrive_t * cur_drv = get_cur_drv ( fdctrl );
1843
ths
authored
18 years ago
1844
1845
1846
1847
1848
1849
1850
/* Pretend we are spinning .
* This is needed for Coherent , which uses READ ID to check for
* sector interleaving .
*/
if ( cur_drv -> last_sect != 0 ) {
cur_drv -> sect = ( cur_drv -> sect % cur_drv -> last_sect ) + 1 ;
}
1851
1852
fdctrl_stop_transfer ( fdctrl , 0x00 , 0x00 , 0x00 );
}
1853
1854
/* Init functions */
1855
static void fdctrl_connect_drives ( fdctrl_t * fdctrl , BlockDriverState ** fds )
1856
{
1857
unsigned int i ;
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
for ( i = 0 ; i < MAX_FD ; i ++ ) {
fd_init ( & fdctrl -> drives [ i ], fds [ i ]);
fd_revalidate ( & fdctrl -> drives [ i ]);
}
}
fdctrl_t * fdctrl_init ( qemu_irq irq , int dma_chann , int mem_mapped ,
target_phys_addr_t io_base ,
BlockDriverState ** fds )
{
1869
1870
DeviceState * dev ;
SysBusDevice * s ;
1871
1872
fdctrl_t * fdctrl ;
1873
1874
1875
1876
1877
dev = qdev_create ( NULL , "fdc" );
qdev_init ( dev );
s = sysbus_from_qdev ( dev );
sysbus_connect_irq ( s , 0 , irq );
fdctrl = FROM_SYSBUS ( fdctrl_t , s );
1878
if ( mem_mapped ) {
1879
sysbus_mmio_map ( s , 0 , io_base );
1880
} else {
1881
1882
1883
1884
1885
1886
1887
1888
register_ioport_read (( uint32_t ) io_base + 0x01 , 5 , 1 ,
& fdctrl_read_port , fdctrl );
register_ioport_read (( uint32_t ) io_base + 0x07 , 1 , 1 ,
& fdctrl_read_port , fdctrl );
register_ioport_write (( uint32_t ) io_base + 0x01 , 5 , 1 ,
& fdctrl_write_port , fdctrl );
register_ioport_write (( uint32_t ) io_base + 0x07 , 1 , 1 ,
& fdctrl_write_port , fdctrl );
1889
}
1890
1891
fdctrl -> dma_chann = dma_chann ;
DMA_register_channel ( dma_chann , & fdctrl_transfer_handler , fdctrl );
1892
1893
fdctrl_connect_drives ( fdctrl , fds );
1894
1895
1896
1897
1898
1899
1900
return fdctrl ;
}
fdctrl_t * sun4m_fdctrl_init ( qemu_irq irq , target_phys_addr_t io_base ,
BlockDriverState ** fds , qemu_irq * fdc_tc )
{
1901
1902
DeviceState * dev ;
SysBusDevice * s ;
1903
1904
fdctrl_t * fdctrl ;
1905
dev = qdev_create ( NULL , "SUNW,fdtwo" );
1906
1907
1908
1909
1910
1911
1912
qdev_init ( dev );
s = sysbus_from_qdev ( dev );
sysbus_connect_irq ( s , 0 , irq );
sysbus_mmio_map ( s , 0 , io_base );
* fdc_tc = qdev_get_gpio_in ( dev , 0 );
fdctrl = FROM_SYSBUS ( fdctrl_t , s );
1913
1914
1915
1916
fdctrl -> dma_chann = - 1 ;
fdctrl_connect_drives ( fdctrl , fds );
1917
1918
1919
return fdctrl ;
}
1920
1921
1922
static void fdctrl_init_common ( SysBusDevice * dev , fdctrl_t * fdctrl ,
int is_sun4m , int io )
1923
{
1924
1925
int i , j ;
static int command_tables_inited = 0 ;
1926
1927
sysbus_init_irq ( dev , & fdctrl -> irq );
1928
1929
qdev_init_gpio_in ( & dev -> qdev , fdctrl_handle_tc , 1 );
sysbus_init_mmio ( dev , 0x08 , io );
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
/* Fill 'command_to_handler' lookup table */
if ( ! command_tables_inited ) {
command_tables_inited = 1 ;
for ( i = ARRAY_SIZE ( handlers ) - 1 ; i >= 0 ; i -- ) {
for ( j = 0 ; j < sizeof ( command_to_handler ); j ++ ) {
if (( j & handlers [ i ]. mask ) == handlers [ i ]. value ) {
command_to_handler [ j ] = i ;
}
}
}
}
FLOPPY_DPRINTF ( "init controller \n " );
fdctrl -> fifo = qemu_memalign ( 512 , FD_SECTOR_LEN );
fdctrl -> result_timer = qemu_new_timer ( vm_clock ,
fdctrl_result_timer , fdctrl );
fdctrl -> version = 0x90 ; /* Intel 82078 controller */
fdctrl -> config = FD_CONFIG_EIS | FD_CONFIG_EFIFO ; /* Implicit seek, polling & FIFO enabled */
fdctrl -> sun4m = is_sun4m ;
fdctrl_external_reset ( fdctrl );
register_savevm ( "fdc" , - 1 , 2 , fdc_save , fdc_load , fdctrl );
qemu_register_reset ( fdctrl_external_reset , fdctrl );
1955
1956
}
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
static void fdc_init1 ( SysBusDevice * dev )
{
fdctrl_t * fdctrl = FROM_SYSBUS ( fdctrl_t , dev );
int io ;
io = cpu_register_io_memory ( fdctrl_mem_read , fdctrl_mem_write , fdctrl );
fdctrl_init_common ( dev , fdctrl , 0 , io );
}
static void sun4m_fdc_init1 ( SysBusDevice * dev )
{
fdctrl_t * fdctrl = FROM_SYSBUS ( fdctrl_t , dev );
int io ;
io = cpu_register_io_memory ( fdctrl_mem_read_strict ,
fdctrl_mem_write_strict , fdctrl );
fdctrl_init_common ( dev , fdctrl , 1 , io );
}
1975
1976
1977
1978
1979
static SysBusDeviceInfo fdc_info = {
. init = fdc_init1 ,
. qdev . name = "fdc" ,
. qdev . size = sizeof ( fdctrl_t ),
1980
1981
1982
1983
1984
1985
};
static SysBusDeviceInfo sun4m_fdc_info = {
. init = sun4m_fdc_init1 ,
. qdev . name = "SUNW,fdtwo" ,
. qdev . size = sizeof ( fdctrl_t ),
1986
1987
1988
1989
1990
};
static void fdc_register_devices ( void )
{
sysbus_register_withprop ( & fdc_info );
1991
sysbus_register_withprop ( & sun4m_fdc_info );
1992
1993
1994
}
device_init ( fdc_register_devices )