2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
5 Desc: Amiga-style device for trackdisk
9 #include <devices/trackdisk.h>
10 #include <exec/resident.h>
11 #include <exec/errors.h>
12 #include <exec/memory.h>
13 #include <exec/lists.h>
14 #include <exec/alerts.h>
15 #include <exec/tasks.h>
16 #include <libraries/expansion.h>
17 #include <libraries/expansionbase.h>
18 #include <libraries/configvars.h>
19 #include <dos/filehandler.h>
20 #include <dos/dosextens.h>
21 #include <dos/dostags.h>
22 #include <clib/alib_protos.h>
23 #include <aros/symbolsets.h>
24 #include <aros/bootloader.h>
27 #include <proto/oop.h>
28 #include <proto/exec.h>
29 #include <proto/expansion.h>
30 #include <proto/utility.h>
31 #include <proto/bootloader.h>
32 #include <proto/dos.h>
35 #include <SDI/SDI_interrupt.h>
37 #include "trackdisk_device.h"
38 #include "trackdisk_hw.h"
40 #include LC_LIBDEFS_FILE
43 #include <aros/debug.h>
47 int td_getbyte(unsigned char *, struct TrackDiskBase
*);
48 int td_sendbyte(unsigned char, struct TrackDiskBase
*);
49 ULONG
TD_InitTask(struct TrackDiskBase
*);
50 static void TD_DevTask();
51 BOOL
TD_PerformIO( struct IOExtTD
*, struct TrackDiskBase
*);
53 struct TDU
*TD_InitUnit(ULONG num
, struct TrackDiskBase
*tdb
)
56 struct ExpansionBase
*ExpansionBase
= NULL
;
57 struct DeviceNode
*devnode
;
59 TEXT dosdevname
[4] = "DF0", *handler
= "FastFileSystem";
62 /* Try to get memory for structure */
63 unit
= AllocMem(sizeof(struct TDU
), MEMF_PUBLIC
| MEMF_CLEAR
);
66 ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library",40);
69 unit
->tdu_DiskIn
= TDU_NODISK
; /* Assume there is no floppy in there */
70 unit
->pub
.tdu_StepDelay
= 4; /* Standard values here */
71 unit
->pub
.tdu_SettleDelay
= 16;
72 unit
->pub
.tdu_RetryCnt
= 3;
73 unit
->pub
.tdu_CalibrateDelay
= 4;
74 unit
->tdu_UnitNum
=num
;
75 unit
->tdu_lastcyl
= -1;
76 unit
->tdu_lasthd
= -1;
77 NEWLIST(&unit
->tdu_Listeners
);
79 /* Alloc memory for track buffering */
80 unit
->td_DMABuffer
= AllocMem(DP_SECTORS
* 512, MEMF_CLEAR
| MEMF_24BITDMA
);
82 if (!unit
->td_DMABuffer
)
84 Alert(AT_DeadEnd
| AO_TrackDiskDev
| AG_NoMemory
);
87 /* If buffer doesn't fit into DMA page realloc it */
88 /* FIXME: we should ensure that the buffer is suitable the first time,
89 either by using an aligned memory allocation function or by
90 allocating twice as much as needed and manually aligning */
91 if (( (((ULONG
)(IPTR
)unit
->td_DMABuffer
+ DP_SECTORS
*512) & 0xffff0000) -
92 ((ULONG
)(IPTR
)unit
->td_DMABuffer
&0xffff0000) ) != 0)
96 buffer
= AllocMem(DP_SECTORS
* 512, MEMF_CLEAR
| MEMF_24BITDMA
);
99 Alert(AT_DeadEnd
| AO_TrackDiskDev
| AG_NoMemory
);
102 FreeMem(unit
->td_DMABuffer
, DP_SECTORS
*512);
103 unit
->td_DMABuffer
= buffer
;
105 /* Store the unit in TDBase */
106 tdb
->td_Units
[num
] = unit
;
110 D(bug("TD: Adding bootnode\n"));
111 pp
= (IPTR
*)AllocMem(sizeof(struct DosEnvec
)+sizeof(IPTR
)*4,MEMF_PUBLIC
|MEMF_CLEAR
);
115 dosdevname
[2] += num
;
116 pp
[0] = (IPTR
)dosdevname
;
117 pp
[1] = (IPTR
)MOD_NAME_STRING
;
119 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
120 pp
[DE_SIZEBLOCK
+ 4] = 128;
121 pp
[DE_NUMHEADS
+ 4] = 2;
122 pp
[DE_SECSPERBLOCK
+ 4] = 1;
123 pp
[DE_BLKSPERTRACK
+ 4] = 18;
124 pp
[DE_RESERVEDBLKS
+ 4] = 2;
125 pp
[DE_LOWCYL
+ 4] = 0;
126 pp
[DE_HIGHCYL
+ 4] = 79;
127 pp
[DE_NUMBUFFERS
+ 4] = 10;
128 pp
[DE_BUFMEMTYPE
+ 4] = MEMF_PUBLIC
| MEMF_24BITDMA
;
129 pp
[DE_MAXTRANSFER
+ 4] = 0x00200000;
130 pp
[DE_MASK
+ 4] = 0x7FFFFFFE;
131 pp
[DE_BOOTPRI
+ 4] = 5;
132 pp
[DE_DOSTYPE
+ 4] = 0;
133 pp
[DE_BOOTBLOCKS
+ 4] = 2;
134 devnode
= MakeDosNode(pp
);
138 len
= strlen(handler
);
139 devnode
->dn_Handler
= MKBADDR(AllocMem(
140 AROS_BSTR_MEMSIZE4LEN(len
), MEMF_PUBLIC
| MEMF_CLEAR
)
143 if (devnode
->dn_Handler
!= BNULL
)
145 CopyMem(handler
, AROS_BSTR_ADDR(devnode
->dn_Handler
),
147 AROS_BSTR_setstrlen(devnode
->dn_Handler
, len
);
148 AddBootNode(pp
[DE_BOOTPRI
+ 4], 0, devnode
, NULL
);
156 CloseLibrary((struct Library
*)ExpansionBase
);
161 static AROS_INTH1(td_floppytimer
, struct TrackDiskBase
*, TDBase
)
165 // Does anyone wait for io?
166 if (TDBase
->td_inttmo
)
171 if (!TDBase
->td_inttmo
)
173 Signal(&TDBase
->td_TaskData
->td_Task
,(1L << TDBase
->td_TmoBit
));
182 static AROS_INTH1(td_floppyint
, struct TrackDiskBase
*, TDBase
)
186 Signal(&TDBase
->td_TaskData
->td_Task
,(1L << TDBase
->td_IntBit
));
193 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR TDBase
)
195 struct BootLoaderBase
*BootLoaderBase
;
198 struct Interrupt
*irq
;
200 D(bug("TD: Init\n"));
202 /* First thing, are we disabled from the bootloader? */
203 if ((BootLoaderBase
= OpenResource("bootloader.resource")))
208 list
= (struct List
*)GetBootInfo(BL_Args
);
211 ForeachNode(list
,node
)
213 if (0 == strncmp(node
->ln_Name
,"floppy=",5))
215 if (strstr(&node
->ln_Name
[7], "disabled"))
217 D(bug("[Floppy] Disabled with bootloader argument\n"));
220 TDBase
->td_nomount
= (strstr(&node
->ln_Name
[7], "nomount") != NULL
);
226 /* First we check if there are any floppy drives configured in BIOS */
227 /* We do this by reading CMOS byte 0x10 */
228 /* It should really reside in battclock.resource */
234 /* No drives here. abort */
235 D(bug("TD: No drives defined in BIOS\n"));
239 for (i
=0; i
<TD_NUMUNITS
; i
++)
240 TDBase
->td_Units
[i
] = NULL
;
242 irq
= &TDBase
->td_FloppyInt
;
243 irq
->is_Node
.ln_Type
= NT_INTERRUPT
;
244 irq
->is_Node
.ln_Pri
=127; /* Set the highest pri */
245 irq
->is_Node
.ln_Name
= (STRPTR
)MOD_NAME_STRING
;
246 irq
->is_Code
= (VOID_FUNC
)td_floppyint
;
247 irq
->is_Data
= (APTR
)TDBase
;
249 AddIntServer(INTB_KERNEL
+ 6, irq
);
251 irq
= &TDBase
->td_TimerInt
;
252 irq
->is_Node
.ln_Type
= NT_INTERRUPT
;
253 irq
->is_Node
.ln_Pri
=10; /* Set the highest pri */
254 irq
->is_Node
.ln_Name
= (STRPTR
)MOD_NAME_STRING
;
255 irq
->is_Code
= (VOID_FUNC
)td_floppytimer
;
256 irq
->is_Data
= (APTR
)TDBase
;
258 AddIntServer(INTB_KERNEL
+ 0, irq
);
260 /* Swap drivebits around */
261 drives
= ( (drives
&0xf0)>>4 | (drives
&0x0f)<<4 );
263 for (i
=0;i
<TD_NUMUNITS
;i
++)
265 /* We only want 3.5" 1.44MB drives */
266 if (((drives
>> (4*i
))&0x0f) == 4)
268 kprintf("[Floppy] Unit %d is a 1.44MB drive\n",i
);
269 TD_InitUnit(i
,TDBase
);
273 /* Create the message processor task */
279 static int GM_UNIQUENAME(Open
)
281 LIBBASETYPEPTR TDBase
,
282 struct IOExtTD
*iotd
,
287 D(bug("TD: Open\n"));
288 iotd
->iotd_Req
.io_Error
= IOERR_OPENFAIL
;
290 /* Is the requested unitNumber valid? */
291 if (unitnum
< TD_NUMUNITS
)
295 iotd
->iotd_Req
.io_Device
= (struct Device
*)TDBase
;
297 /* Get TDU structure */
298 unit
= TDBase
->td_Units
[unitnum
];
299 if (unit
&& (unit
->tdu_Present
)) {
300 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
301 ((struct Unit
*)unit
)->unit_OpenCnt
++;
302 iotd
->iotd_Req
.io_Error
= 0;
306 return iotd
->iotd_Req
.io_Error
== 0;
310 static int GM_UNIQUENAME(Close
)
312 LIBBASETYPEPTR TDBase
,
316 iotd
->iotd_Req
.io_Unit
->unit_OpenCnt
--;
321 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
322 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
323 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
325 AROS_LH1(void, beginio
,
326 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
327 struct TrackDiskBase
*, TDBase
, 5, TrackDisk
)
332 if (iotd
->iotd_Req
.io_Flags
& IOF_QUICK
)
334 switch(iotd
->iotd_Req
.io_Command
)
337 tdu
= (struct TDU
*)iotd
->iotd_Req
.io_Unit
;
338 if ((!(tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
)) || (tdu
->tdu_DiskIn
== TDU_DISK
))
352 PutMsg(&TDBase
->td_TaskData
->td_Port
, &iotd
->iotd_Req
.io_Message
);
353 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
356 TD_PerformIO(iotd
,TDBase
);
361 /* Forward to devicetask */
362 PutMsg(&TDBase
->td_TaskData
->td_Port
, &iotd
->iotd_Req
.io_Message
);
364 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
370 AROS_LH1(LONG
, abortio
,
371 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
372 struct TrackDiskBase
*, TDBase
, 6, TrackDisk
)
375 D(bug("TD: AbortIO\n"));
380 void TestInsert(struct TrackDiskBase
*tdb
, struct TDU
*tdu
)
383 struct IOExtTD
*iotd
;
385 td_rseek(tdu
->tdu_UnitNum
,tdu
->tdu_stepdir
,1,tdb
);
386 tdu
->tdu_stepdir
= !tdu
->tdu_stepdir
;
387 dir
= (inb(FDC_DIR
)>>7);
390 D(bug("[Floppy] Insertion detected\n"));
391 td_recalibrate(tdu
->tdu_UnitNum
,1,0,tdb
);
392 tdu
->tdu_DiskIn
= TDU_DISK
;
393 tdu
->pub
.tdu_Counter
++;
394 tdu
->tdu_ProtStatus
= td_getprotstatus(tdu
->tdu_UnitNum
,tdb
);
396 ForeachNode(&tdu
->tdu_Listeners
,iotd
)
398 Cause((struct Interrupt
*)((struct IOExtTD
*)iotd
->iotd_Req
.io_Data
));
404 BOOL
TD_PerformIO( struct IOExtTD
*iotd
, struct TrackDiskBase
*tdb
)
407 struct DriveGeometry
*geo
;
412 tdu
= (struct TDU
*)iotd
->iotd_Req
.io_Unit
;
413 switch(iotd
->iotd_Req
.io_Command
)
416 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
417 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
422 tdu
->tdu_lastcyl
= -1;
423 tdu
->tdu_lasthd
= -1;
424 iotd
->iotd_Req
.io_Error
= 0;
427 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
428 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
432 tdu
->tdu_Busy
= TRUE
;
433 iotd
->iotd_Req
.io_Error
= td_read(iotd
, tdb
);
434 tdu
->tdu_Busy
= FALSE
;
437 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
438 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
442 tdu
->tdu_Busy
= TRUE
;
443 iotd
->iotd_Req
.io_Error
= td_update(tdu
, tdb
);
444 tdu
->tdu_Busy
= FALSE
;
447 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
448 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
452 tdu
->tdu_Busy
= TRUE
;
453 iotd
->iotd_Req
.io_Error
= td_write(iotd
, tdb
);
454 tdu
->tdu_Busy
= FALSE
;
456 case TD_ADDCHANGEINT
:
458 AddTail(&tdu
->tdu_Listeners
,(struct Node
*)iotd
);
463 iotd
->iotd_Req
.io_Actual
= tdu
->pub
.tdu_Counter
;
464 iotd
->iotd_Req
.io_Error
=0;
467 if ((tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
) && (tdu
->tdu_DiskIn
== TDU_NODISK
)) {
468 TestInsert(tdb
, tdu
);
469 if (!tdu
->tdu_MotorOn
)
470 td_motoroff(tdu
->tdu_UnitNum
, tdb
);
472 if (tdu
->tdu_DiskIn
== TDU_DISK
)
474 /* test if disk is still in there */
475 temp
= td_getDiskChange();
476 iotd
->iotd_Req
.io_Actual
= temp
;
477 tdu
->tdu_DiskIn
= temp
^ 1;
481 /* No disk in drive */
482 iotd
->iotd_Req
.io_Actual
= 1;
484 iotd
->iotd_Req
.io_Error
=0;
487 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
488 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
492 tdu
->tdu_Busy
= TRUE
;
493 iotd
->iotd_Req
.io_Error
= td_format(iotd
,tdb
);
494 tdu
->tdu_Busy
= FALSE
;
497 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
498 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
502 iotd
->iotd_Req
.io_Error
=0;
503 switch (iotd
->iotd_Req
.io_Length
)
506 tdu
->tdu_MotorOn
= 0;
507 td_motoroff(tdu
->tdu_UnitNum
,tdb
);
510 tdu
->tdu_MotorOn
= 1;
511 td_motoron(tdu
->tdu_UnitNum
,tdb
,TRUE
);
514 iotd
->iotd_Req
.io_Error
= TDERR_NotSpecified
;
519 iotd
->iotd_Req
.io_Actual
= tdu
->tdu_ProtStatus
;
520 iotd
->iotd_Req
.io_Error
=0;
522 case TD_REMCHANGEINT
:
524 Remove((struct Node
*)iotd
);
528 geo
= (struct DriveGeometry
*)iotd
->iotd_Req
.io_Data
;
529 geo
->dg_SectorSize
= 512;
530 geo
->dg_TotalSectors
= DP_STOTAL
;
531 geo
->dg_Cylinders
= DP_TRACKS
;
532 geo
->dg_CylSectors
= DP_SECTORS
*2;
534 geo
->dg_TrackSectors
= DP_SECTORS
;
535 geo
->dg_BufMemType
= MEMF_PUBLIC
;
536 geo
->dg_DeviceType
= DG_DIRECT_ACCESS
;
537 geo
->dg_Flags
= DGF_REMOVABLE
;
538 iotd
->iotd_Req
.io_Error
=0;
540 case TD_GETDRIVETYPE
:
541 iotd
->iotd_Req
.io_Actual
= DRIVE3_5
;
542 iotd
->iotd_Req
.io_Error
=0;
544 case TD_GETNUMTRACKS
:
545 iotd
->iotd_Req
.io_Actual
= DP_TRACKS
*2;
546 iotd
->iotd_Req
.io_Error
=0;
549 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
550 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
554 temp
= (iotd
->iotd_Req
.io_Offset
>> 10) / DP_SECTORS
;
555 tdu
->tdu_MotorOn
= 1;
556 iotd
->iotd_Req
.io_Error
= td_recalibrate(tdu
->tdu_UnitNum
, 0, temp
, tdb
);
560 D(bug("TD: Unknown command received\n"));
561 iotd
->iotd_Req
.io_Error
= IOERR_NOCMD
;
563 } /* switch(iotd->iotd_Req.io_Command) */
567 ULONG
TD_InitTask(struct TrackDiskBase
*tdb
)
573 /* Allocate Task Data structure */
574 t
= AllocMem(sizeof(struct TaskData
), MEMF_PUBLIC
|MEMF_CLEAR
);
575 /* Allocate Stack space */
576 if ((t
) && ((t
->td_Stack
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
|MEMF_CLEAR
)) == NULL
))
578 FreeMem(t
, sizeof(struct TaskData
));
581 /* Allocate MemEntry for this task */
582 ml
= (struct MemList
*)AllocMem(sizeof(struct MemList
), MEMF_PUBLIC
|MEMF_CLEAR
);
584 /* Find the current task */
589 D(bug("TD: Creating devicetask..."));
590 /* Save stack info into task structure */
591 t
->td_Task
.tc_SPLower
= t
->td_Stack
;
592 t
->td_Task
.tc_SPUpper
= (BYTE
*)t
->td_Stack
+ STACK_SIZE
;
593 t
->td_Task
.tc_SPReg
= (BYTE
*)t
->td_Task
.tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
596 NEWLIST(&t
->td_Port
.mp_MsgList
);
597 t
->td_Port
.mp_Node
.ln_Type
= NT_MSGPORT
;
598 t
->td_Port
.mp_Flags
= PA_SIGNAL
;
599 t
->td_Port
.mp_SigBit
= SIGBREAKB_CTRL_F
;
600 t
->td_Port
.mp_SigTask
= &t
->td_Task
;
601 t
->td_Port
.mp_Node
.ln_Name
= "trackdisk.device";
604 ml
->ml_NumEntries
= 1;
605 ml
->ml_ME
[0].me_Addr
= t
;
606 ml
->ml_ME
[0].me_Length
= sizeof(struct TaskData
);
607 NEWLIST(&t
->td_Task
.tc_MemEntry
);
608 AddHead(&t
->td_Task
.tc_MemEntry
, &ml
->ml_Node
);
610 /* Init Task structure */
611 t
->td_Task
.tc_Node
.ln_Name
= "trackdisk.task";
612 t
->td_Task
.tc_Node
.ln_Type
= NT_TASK
;
613 t
->td_Task
.tc_Node
.ln_Pri
= 5;
614 t
->td_Task
.tc_UserData
= me
;
616 tdb
->td_TaskData
= t
;
618 struct TagItem task_Tags
[] = {
619 { TASKTAG_ARG1
, (IPTR
)tdb
},
622 /* Add task to system task list */
623 NewAddTask(&t
->td_Task
, &TD_DevTask
, NULL
, task_Tags
);
625 /* Wait until started */
626 Wait(SIGBREAKF_CTRL_F
);
636 if (t
->td_Stack
) FreeMem(t
->td_Stack
, STACK_SIZE
);
637 FreeMem(t
, sizeof(struct TaskData
));
639 if (ml
) FreeMem(ml
, sizeof(struct MemList
));
645 static void TD_DevTask(struct TrackDiskBase
*tdb
)
648 struct IOExtTD
*iotd
;
650 ULONG tasig
,tisig
,sigs
,i
;
653 D(bug("[TDTask] TD_DevTask(tdb=%p)\n", tdb
));
655 td
= tdb
->td_TaskData
;
657 D(bug("[TDTask] TD_DevTask: struct TaskData @ %p\n", td
));
659 tdb
->td_IntBit
= AllocSignal(-1);
660 tdb
->td_TmoBit
= AllocSignal(-1);
661 tdb
->td_TimerMP
= CreateMsgPort();
662 tdb
->td_TimerIO
= (struct timerequest
*) CreateIORequest(tdb
->td_TimerMP
, sizeof(struct timerequest
));
663 OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tdb
->td_TimerIO
, 0);
668 /* Initial check for floppies */
669 for (i
=0;i
<TD_NUMUNITS
;i
++)
673 td_rseek(i
, 0, 1, tdb
);
674 tdb
->td_Units
[i
]->tdu_Present
= !td_recalibrate(tdb
->td_Units
[i
]->tdu_UnitNum
,1,0,tdb
);
675 tdb
->td_Units
[i
]->pub
.tdu_CurrTrk
= 0;
676 tdb
->td_Units
[i
]->tdu_DiskIn
= (td_getDiskChange() ^ 1);
677 tdb
->td_Units
[i
]->tdu_ProtStatus
= td_getprotstatus(i
,tdb
);
678 tdb
->td_Units
[i
]->tdu_Busy
= FALSE
;
679 tdb
->td_Units
[i
]->tdu_stepdir
= 0;
680 if (((tdb
->td_Units
[i
]->pub
.tdu_PubFlags
& TDPF_NOCLICK
) && (tdb
->td_Units
[i
]->tdu_DiskIn
== TDU_NODISK
))
681 || (!tdb
->td_Units
[i
]->tdu_Present
))
683 D(bug("Drive %d presence: %ld\n", i
, tdb
->td_Units
[i
]->tdu_Present
));
687 tasig
= 1L << td
->td_Port
.mp_SigBit
;
688 tisig
= 1L << tdb
->td_TimerMP
->mp_SigBit
;
690 /* Reply to startup message */
691 Signal(td
->td_Task
.tc_UserData
,SIGBREAKF_CTRL_F
);
693 tdb
->td_TimerIO
->tr_node
.io_Command
= TR_ADDREQUEST
;
694 tdb
->td_TimerIO
->tr_time
.tv_secs
= 2;
695 tdb
->td_TimerIO
->tr_time
.tv_micro
= 500000;
696 SendIO((struct IORequest
*)tdb
->td_TimerIO
);
698 /* Endless task loop */
702 sigs
= Wait(tasig
| tisig
); /* Wait for a message */
703 /* If unit was not active process message */
706 /* We received a message. Deal with it */
707 while((iotd
= (struct IOExtTD
*)GetMsg(&td
->td_Port
)) != NULL
)
709 /* Execute command */
710 if (TD_PerformIO( iotd
, tdb
))
713 ReplyMsg((struct Message
*)iotd
);
719 /* We were woken up by the timer. */
720 WaitIO((struct IORequest
*)tdb
->td_TimerIO
);
721 for(i
=0;i
<TD_NUMUNITS
;i
++)
723 /* If there is no floppy in drive, scan for changes */
724 if (tdb
->td_Units
[i
])
726 tdu
= tdb
->td_Units
[i
];
727 switch (tdu
->tdu_DiskIn
)
731 Unfortunately "NoClick" technology which works on Amiga will not
732 work on PC because i82077 does not send step pulse when told to
733 seek to "-1" track and the drive can't recognize disk insertion.
734 Many thanks to Intel! :-(((
736 Here we use another technique: in NoClick mode we just do nothing
737 if the disk is not in drive. We can perform this test only once
738 inside TD_CHANGESTATE command which is invoked by DISKCHANGE
739 CLI command. This means that we'll have to issue DISKCHANGE command
740 manually after we insert the disk, but this is probably better
743 if (tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
) {
744 if (!tdu
->tdu_MotorOn
)
745 td_motoroff(tdu
->tdu_UnitNum
, tdb
);
747 TestInsert(tdb
, tdu
);
751 Fortunately this part is completely silent so we don't have to
752 do any extra mess here
756 if (!tdu
->tdu_MotorOn
)
757 td_motoron(tdu
->tdu_UnitNum
,tdb
,FALSE
);
758 dir
= (inb(FDC_DIR
)>>7);
759 if (!tdu
->tdu_MotorOn
)
760 td_motoroff(tdu
->tdu_UnitNum
,tdb
);
763 D(bug("[Floppy] Removal detected\n"));
764 /* Go to cylinder 0 */
765 td_recalibrate(tdu
->tdu_UnitNum
,1,0,tdb
);
766 tdu
->tdu_DiskIn
= TDU_NODISK
;
767 tdu
->pub
.tdu_Counter
++;
769 ForeachNode(&tdu
->tdu_Listeners
,iotd
)
771 Cause((struct Interrupt
*)((struct IOExtTD
*)iotd
->iotd_Req
.io_Data
));
774 tdu
->tdu_stepdir
= 0;
782 /* Reload the timer again */
783 GetMsg(tdb
->td_TimerMP
);
784 tdb
->td_TimerIO
->tr_node
.io_Command
= TR_ADDREQUEST
;
785 tdb
->td_TimerIO
->tr_time
.tv_secs
= 2;
786 tdb
->td_TimerIO
->tr_time
.tv_micro
= 500000;
787 SendIO((struct IORequest
*)tdb
->td_TimerIO
);