2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
5 Desc: Amigastyle 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
= "afs.handler";
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_CHIP
| 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 if (( (((ULONG
)(IPTR
)unit
->td_DMABuffer
+ DP_SECTORS
*512) & 0xffff0000) -
89 ((ULONG
)(IPTR
)unit
->td_DMABuffer
&0xffff0000) ) != 0)
93 buffer
= AllocMem(DP_SECTORS
*512, MEMF_CLEAR
| MEMF_CHIP
| MEMF_24BITDMA
);
96 Alert(AT_DeadEnd
| AO_TrackDiskDev
| AG_NoMemory
);
99 FreeMem(unit
->td_DMABuffer
, DP_SECTORS
*512);
100 unit
->td_DMABuffer
= buffer
;
102 /* Store the unit in TDBase */
103 tdb
->td_Units
[num
] = unit
;
107 D(bug("TD: Adding bootnode\n"));
108 pp
= (IPTR
*)AllocMem(sizeof(struct DosEnvec
)+sizeof(IPTR
)*4,MEMF_PUBLIC
|MEMF_CLEAR
);
112 dosdevname
[2] += num
;
113 pp
[0] = (IPTR
)dosdevname
;
114 pp
[1] = (IPTR
)MOD_NAME_STRING
;
116 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
117 pp
[DE_SIZEBLOCK
+ 4] = 128;
118 pp
[DE_NUMHEADS
+ 4] = 2;
119 pp
[DE_SECSPERBLOCK
+ 4] = 1;
120 pp
[DE_BLKSPERTRACK
+ 4] = 18;
121 pp
[DE_RESERVEDBLKS
+ 4] = 2;
122 pp
[DE_LOWCYL
+ 4] = 0;
123 pp
[DE_HIGHCYL
+ 4] = 79;
124 pp
[DE_NUMBUFFERS
+ 4] = 10;
125 pp
[DE_BUFMEMTYPE
+ 4] = MEMF_PUBLIC
| MEMF_CHIP
;
126 pp
[DE_MAXTRANSFER
+ 4] = 0x00200000;
127 pp
[DE_MASK
+ 4] = 0x7FFFFFFE;
128 pp
[DE_BOOTPRI
+ 4] = 5;
129 pp
[DE_DOSTYPE
+ 4] = 0;
130 pp
[DE_BOOTBLOCKS
+ 4] = 2;
131 devnode
= MakeDosNode(pp
);
135 len
= strlen(handler
);
136 devnode
->dn_Handler
= MKBADDR(AllocMem(
137 AROS_BSTR_MEMSIZE4LEN(len
), MEMF_PUBLIC
| MEMF_CLEAR
)
140 if (devnode
->dn_Name
!= NULL
)
142 CopyMem(handler
, AROS_BSTR_ADDR(devnode
->dn_Handler
),
144 AROS_BSTR_setstrlen(devnode
->dn_Handler
, len
);
145 AddBootNode(pp
[DE_BOOTPRI
+ 4], 0, devnode
, NULL
);
153 CloseLibrary((struct Library
*)ExpansionBase
);
158 static AROS_INTH1(td_floppytimer
, struct TrackDiskBase
*, TDBase
)
162 // Does anyone wait for io?
163 if (TDBase
->td_inttmo
)
168 if (!TDBase
->td_inttmo
)
170 Signal(&TDBase
->td_TaskData
->td_Task
,(1L << TDBase
->td_TmoBit
));
179 static AROS_INTH1(td_floppyint
, struct TrackDiskBase
*, TDBase
)
183 Signal(&TDBase
->td_TaskData
->td_Task
,(1L << TDBase
->td_IntBit
));
190 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR TDBase
)
192 struct BootLoaderBase
*BootLoaderBase
;
195 struct Interrupt
*irq
;
197 D(bug("TD: Init\n"));
199 /* First thing, are we disabled from the bootloader? */
200 if ((BootLoaderBase
= OpenResource("bootloader.resource")))
205 list
= (struct List
*)GetBootInfo(BL_Args
);
208 ForeachNode(list
,node
)
210 if (0 == strncmp(node
->ln_Name
,"floppy=",5))
212 if (strstr(&node
->ln_Name
[7], "disabled"))
214 D(bug("[Floppy] Disabled with bootloader argument\n"));
217 TDBase
->td_nomount
= (strstr(&node
->ln_Name
[7], "nomount") != NULL
);
223 /* First we check if there are any floppy drives configured in BIOS */
224 /* We do this by reading CMOS byte 0x10 */
225 /* It should really reside in battclock.resource */
231 /* No drives here. abort */
232 D(bug("TD: No drives defined in BIOS\n"));
236 for (i
=0; i
<TD_NUMUNITS
; i
++)
237 TDBase
->td_Units
[i
] = NULL
;
239 irq
= &TDBase
->td_FloppyInt
;
240 irq
->is_Node
.ln_Type
= NT_INTERRUPT
;
241 irq
->is_Node
.ln_Pri
=127; /* Set the highest pri */
242 irq
->is_Node
.ln_Name
= (STRPTR
)MOD_NAME_STRING
;
243 irq
->is_Code
= (VOID_FUNC
)td_floppyint
;
244 irq
->is_Data
= (APTR
)TDBase
;
246 AddIntServer(INTB_KERNEL
+ 6, irq
);
248 irq
= &TDBase
->td_TimerInt
;
249 irq
->is_Node
.ln_Type
= NT_INTERRUPT
;
250 irq
->is_Node
.ln_Pri
=10; /* Set the highest pri */
251 irq
->is_Node
.ln_Name
= (STRPTR
)MOD_NAME_STRING
;
252 irq
->is_Code
= (VOID_FUNC
)td_floppytimer
;
253 irq
->is_Data
= (APTR
)TDBase
;
255 AddIntServer(INTB_KERNEL
+ 0, irq
);
257 /* Swap drivebits around */
258 drives
= ( (drives
&0xf0)>>4 | (drives
&0x0f)<<4 );
260 for (i
=0;i
<TD_NUMUNITS
;i
++)
262 /* We only want 3.5" 1.44Mb drives */
263 if (((drives
>> (4*i
))&0x0f) == 4)
265 kprintf("[Floppy] Unit %d is a 1.44Mb drive\n",i
);
266 TD_InitUnit(i
,TDBase
);
270 /* Create the message processor task */
276 static int GM_UNIQUENAME(Open
)
278 LIBBASETYPEPTR TDBase
,
279 struct IOExtTD
*iotd
,
284 D(bug("TD: Open\n"));
285 iotd
->iotd_Req
.io_Error
= IOERR_OPENFAIL
;
287 /* Is the requested unitNumber valid? */
288 if (unitnum
< TD_NUMUNITS
)
292 iotd
->iotd_Req
.io_Device
= (struct Device
*)TDBase
;
294 /* Get TDU structure */
295 unit
= TDBase
->td_Units
[unitnum
];
296 if (unit
&& (unit
->tdu_Present
)) {
297 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
298 ((struct Unit
*)unit
)->unit_OpenCnt
++;
299 iotd
->iotd_Req
.io_Error
= 0;
303 return iotd
->iotd_Req
.io_Error
== 0;
307 static int GM_UNIQUENAME(Close
)
309 LIBBASETYPEPTR TDBase
,
313 iotd
->iotd_Req
.io_Unit
->unit_OpenCnt
--;
318 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
319 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
320 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
322 AROS_LH1(void, beginio
,
323 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
324 struct TrackDiskBase
*, TDBase
, 5, TrackDisk
)
329 if (iotd
->iotd_Req
.io_Flags
& IOF_QUICK
)
331 switch(iotd
->iotd_Req
.io_Command
)
334 tdu
= (struct TDU
*)iotd
->iotd_Req
.io_Unit
;
335 if ((!(tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
)) || (tdu
->tdu_DiskIn
== TDU_DISK
))
349 PutMsg(&TDBase
->td_TaskData
->td_Port
, &iotd
->iotd_Req
.io_Message
);
350 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
353 TD_PerformIO(iotd
,TDBase
);
358 /* Forward to devicetask */
359 PutMsg(&TDBase
->td_TaskData
->td_Port
, &iotd
->iotd_Req
.io_Message
);
361 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
367 AROS_LH1(LONG
, abortio
,
368 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
369 struct TrackDiskBase
*, TDBase
, 6, TrackDisk
)
372 D(bug("TD: AbortIO\n"));
377 void TestInsert(struct TrackDiskBase
*tdb
, struct TDU
*tdu
)
380 struct IOExtTD
*iotd
;
382 td_rseek(tdu
->tdu_UnitNum
,tdu
->tdu_stepdir
,1,tdb
);
383 tdu
->tdu_stepdir
= !tdu
->tdu_stepdir
;
384 dir
= (inb(FDC_DIR
)>>7);
387 D(bug("[Floppy] Insertion detected\n"));
388 td_recalibrate(tdu
->tdu_UnitNum
,1,0,tdb
);
389 tdu
->tdu_DiskIn
= TDU_DISK
;
390 tdu
->pub
.tdu_Counter
++;
391 tdu
->tdu_ProtStatus
= td_getprotstatus(tdu
->tdu_UnitNum
,tdb
);
393 ForeachNode(&tdu
->tdu_Listeners
,iotd
)
395 Cause((struct Interrupt
*)((struct IOExtTD
*)iotd
->iotd_Req
.io_Data
));
401 BOOL
TD_PerformIO( struct IOExtTD
*iotd
, struct TrackDiskBase
*tdb
)
404 struct DriveGeometry
*geo
;
409 tdu
= (struct TDU
*)iotd
->iotd_Req
.io_Unit
;
410 switch(iotd
->iotd_Req
.io_Command
)
413 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
414 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
419 tdu
->tdu_lastcyl
= -1;
420 tdu
->tdu_lasthd
= -1;
421 iotd
->iotd_Req
.io_Error
= 0;
424 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
425 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
429 tdu
->tdu_Busy
= TRUE
;
430 iotd
->iotd_Req
.io_Error
= td_read(iotd
, tdb
);
431 tdu
->tdu_Busy
= FALSE
;
434 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
435 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
439 tdu
->tdu_Busy
= TRUE
;
440 iotd
->iotd_Req
.io_Error
= td_update(tdu
, tdb
);
441 tdu
->tdu_Busy
= FALSE
;
444 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
445 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
449 tdu
->tdu_Busy
= TRUE
;
450 iotd
->iotd_Req
.io_Error
= td_write(iotd
, tdb
);
451 tdu
->tdu_Busy
= FALSE
;
453 case TD_ADDCHANGEINT
:
455 AddTail(&tdu
->tdu_Listeners
,(struct Node
*)iotd
);
460 iotd
->iotd_Req
.io_Actual
= tdu
->pub
.tdu_Counter
;
461 iotd
->iotd_Req
.io_Error
=0;
464 if ((tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
) && (tdu
->tdu_DiskIn
== TDU_NODISK
)) {
465 TestInsert(tdb
, tdu
);
466 if (!tdu
->tdu_MotorOn
)
467 td_motoroff(tdu
->tdu_UnitNum
, tdb
);
469 if (tdu
->tdu_DiskIn
== TDU_DISK
)
471 /* test if disk is still in there */
472 temp
= td_getDiskChange();
473 iotd
->iotd_Req
.io_Actual
= temp
;
474 tdu
->tdu_DiskIn
= temp
^ 1;
478 /* No disk in drive */
479 iotd
->iotd_Req
.io_Actual
= 1;
481 iotd
->iotd_Req
.io_Error
=0;
484 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
485 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
489 tdu
->tdu_Busy
= TRUE
;
490 iotd
->iotd_Req
.io_Error
= td_format(iotd
,tdb
);
491 tdu
->tdu_Busy
= FALSE
;
494 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
495 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
499 iotd
->iotd_Req
.io_Error
=0;
500 switch (iotd
->iotd_Req
.io_Length
)
503 tdu
->tdu_MotorOn
= 0;
504 td_motoroff(tdu
->tdu_UnitNum
,tdb
);
507 tdu
->tdu_MotorOn
= 1;
508 td_motoron(tdu
->tdu_UnitNum
,tdb
,TRUE
);
511 iotd
->iotd_Req
.io_Error
= TDERR_NotSpecified
;
516 iotd
->iotd_Req
.io_Actual
= tdu
->tdu_ProtStatus
;
517 iotd
->iotd_Req
.io_Error
=0;
519 case TD_REMCHANGEINT
:
521 Remove((struct Node
*)iotd
);
525 geo
= (struct DriveGeometry
*)iotd
->iotd_Req
.io_Data
;
526 geo
->dg_SectorSize
= 512;
527 geo
->dg_TotalSectors
= DP_STOTAL
;
528 geo
->dg_Cylinders
= DP_TRACKS
;
529 geo
->dg_CylSectors
= DP_SECTORS
*2;
531 geo
->dg_TrackSectors
= DP_SECTORS
;
532 geo
->dg_BufMemType
= MEMF_PUBLIC
;
533 geo
->dg_DeviceType
= DG_DIRECT_ACCESS
;
534 geo
->dg_Flags
= DGF_REMOVABLE
;
535 iotd
->iotd_Req
.io_Error
=0;
537 case TD_GETDRIVETYPE
:
538 iotd
->iotd_Req
.io_Actual
= DRIVE3_5
;
539 iotd
->iotd_Req
.io_Error
=0;
541 case TD_GETNUMTRACKS
:
542 iotd
->iotd_Req
.io_Actual
= DP_TRACKS
*2;
543 iotd
->iotd_Req
.io_Error
=0;
546 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
547 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
551 temp
= (iotd
->iotd_Req
.io_Offset
>> 10) / DP_SECTORS
;
552 tdu
->tdu_MotorOn
= 1;
553 iotd
->iotd_Req
.io_Error
= td_recalibrate(tdu
->tdu_UnitNum
, 0, temp
, tdb
);
557 D(bug("TD: Unknown command received\n"));
558 iotd
->iotd_Req
.io_Error
= IOERR_NOCMD
;
560 } /* switch(iotd->iotd_Req.io_Command) */
564 ULONG
TD_InitTask(struct TrackDiskBase
*tdb
)
570 /* Allocate Task Data structure */
571 t
= AllocMem(sizeof(struct TaskData
), MEMF_PUBLIC
|MEMF_CLEAR
);
572 /* Allocate Stack space */
573 if ((t
) && ((t
->td_Stack
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
|MEMF_CLEAR
)) == NULL
))
575 FreeMem(t
, sizeof(struct TaskData
));
578 /* Allocate MemEntry for this task */
579 ml
= (struct MemList
*)AllocMem(sizeof(struct MemList
), MEMF_PUBLIC
|MEMF_CLEAR
);
581 /* Find the current task */
586 D(bug("TD: Creating devicetask..."));
587 /* Save stack info into task structure */
588 t
->td_Task
.tc_SPLower
= t
->td_Stack
;
589 t
->td_Task
.tc_SPUpper
= (BYTE
*)t
->td_Stack
+ STACK_SIZE
;
590 t
->td_Task
.tc_SPReg
= (BYTE
*)t
->td_Task
.tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
593 NEWLIST(&t
->td_Port
.mp_MsgList
);
594 t
->td_Port
.mp_Node
.ln_Type
= NT_MSGPORT
;
595 t
->td_Port
.mp_Flags
= PA_SIGNAL
;
596 t
->td_Port
.mp_SigBit
= SIGBREAKB_CTRL_F
;
597 t
->td_Port
.mp_SigTask
= &t
->td_Task
;
598 t
->td_Port
.mp_Node
.ln_Name
= "trackdisk.device";
601 ml
->ml_NumEntries
= 1;
602 ml
->ml_ME
[0].me_Addr
= t
;
603 ml
->ml_ME
[0].me_Length
= sizeof(struct TaskData
);
604 NEWLIST(&t
->td_Task
.tc_MemEntry
);
605 AddHead(&t
->td_Task
.tc_MemEntry
, &ml
->ml_Node
);
607 /* Init Task structure */
608 t
->td_Task
.tc_Node
.ln_Name
= "trackdisk.task";
609 t
->td_Task
.tc_Node
.ln_Type
= NT_TASK
;
610 t
->td_Task
.tc_Node
.ln_Pri
= 5;
611 t
->td_Task
.tc_UserData
= me
;
613 tdb
->td_TaskData
= t
;
615 struct TagItem task_Tags
[] = {
616 { TASKTAG_ARG1
, (IPTR
)tdb
},
619 /* Add task to system task list */
620 NewAddTask(&t
->td_Task
, &TD_DevTask
, NULL
, task_Tags
);
622 /* Wait until started */
623 Wait(SIGBREAKF_CTRL_F
);
633 if (t
->td_Stack
) FreeMem(t
->td_Stack
, STACK_SIZE
);
634 FreeMem(t
, sizeof(struct TaskData
));
636 if (ml
) FreeMem(ml
, sizeof(struct MemList
));
642 static void TD_DevTask(struct TrackDiskBase
*tdb
)
645 struct IOExtTD
*iotd
;
647 ULONG tasig
,tisig
,sigs
,i
;
650 D(bug("[TDTask] TD_DevTask(tdb=%p)\n", tdb
));
652 td
= tdb
->td_TaskData
;
654 D(bug("[TDTask] TD_DevTask: struct TaskData @ %p\n", td
));
656 tdb
->td_IntBit
= AllocSignal(-1);
657 tdb
->td_TmoBit
= AllocSignal(-1);
658 tdb
->td_TimerMP
= CreateMsgPort();
659 tdb
->td_TimerIO
= (struct timerequest
*) CreateIORequest(tdb
->td_TimerMP
, sizeof(struct timerequest
));
660 OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tdb
->td_TimerIO
, 0);
665 /* Initial check for floppies */
666 for (i
=0;i
<TD_NUMUNITS
;i
++)
670 td_rseek(i
, 0, 1, tdb
);
671 tdb
->td_Units
[i
]->tdu_Present
= !td_recalibrate(tdb
->td_Units
[i
]->tdu_UnitNum
,1,0,tdb
);
672 tdb
->td_Units
[i
]->pub
.tdu_CurrTrk
= 0;
673 tdb
->td_Units
[i
]->tdu_DiskIn
= (td_getDiskChange() ^ 1);
674 tdb
->td_Units
[i
]->tdu_ProtStatus
= td_getprotstatus(i
,tdb
);
675 tdb
->td_Units
[i
]->tdu_Busy
= FALSE
;
676 tdb
->td_Units
[i
]->tdu_stepdir
= 0;
677 if (((tdb
->td_Units
[i
]->pub
.tdu_PubFlags
& TDPF_NOCLICK
) && (tdb
->td_Units
[i
]->tdu_DiskIn
== TDU_NODISK
))
678 || (!tdb
->td_Units
[i
]->tdu_Present
))
680 D(bug("Drive %d presence: %ld\n", i
, tdb
->td_Units
[i
]->tdu_Present
));
684 tasig
= 1L << td
->td_Port
.mp_SigBit
;
685 tisig
= 1L << tdb
->td_TimerMP
->mp_SigBit
;
687 /* Reply to startup message */
688 Signal(td
->td_Task
.tc_UserData
,SIGBREAKF_CTRL_F
);
690 tdb
->td_TimerIO
->tr_node
.io_Command
= TR_ADDREQUEST
;
691 tdb
->td_TimerIO
->tr_time
.tv_secs
= 2;
692 tdb
->td_TimerIO
->tr_time
.tv_micro
= 500000;
693 SendIO((struct IORequest
*)tdb
->td_TimerIO
);
695 /* Endless task loop */
699 sigs
= Wait(tasig
| tisig
); /* Wait for a message */
700 /* If unit was not active process message */
703 /* We received a message. Deal with it */
704 while((iotd
= (struct IOExtTD
*)GetMsg(&td
->td_Port
)) != NULL
)
706 /* Execute command */
707 if (TD_PerformIO( iotd
, tdb
))
710 ReplyMsg((struct Message
*)iotd
);
716 /* We were woken up by the timer. */
717 WaitIO((struct IORequest
*)tdb
->td_TimerIO
);
718 for(i
=0;i
<TD_NUMUNITS
;i
++)
720 /* If there is no floppy in drive, scan for changes */
721 if (tdb
->td_Units
[i
])
723 tdu
= tdb
->td_Units
[i
];
724 switch (tdu
->tdu_DiskIn
)
728 Unfortunately "NoClick" technology which works on Amiga will not
729 work on PC because i82077 does not send step pulse when told to
730 seek to "-1" track and the drive can't recognize disk insertion.
731 Many thanks to Intel! :-(((
733 Here we use another technique: in NoClick mode we just do nothing
734 if the disk is not in drive. We can perform this test only once
735 inside TD_CHANGESTATE command which is invoked by DISKCHANGE
736 CLI command. This means that we'll have to issue DISKCHANGE command
737 manually after wi insert the disk, but this is probably better
740 if (tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
) {
741 if (!tdu
->tdu_MotorOn
)
742 td_motoroff(tdu
->tdu_UnitNum
, tdb
);
744 TestInsert(tdb
, tdu
);
748 Fortunately this part is completely silent so we don't have to
749 do any extra mess here
753 if (!tdu
->tdu_MotorOn
)
754 td_motoron(tdu
->tdu_UnitNum
,tdb
,FALSE
);
755 dir
= (inb(FDC_DIR
)>>7);
756 if (!tdu
->tdu_MotorOn
)
757 td_motoroff(tdu
->tdu_UnitNum
,tdb
);
760 D(bug("[Floppy] Removal detected\n"));
761 /* Go to cylinder 0 */
762 td_recalibrate(tdu
->tdu_UnitNum
,1,0,tdb
);
763 tdu
->tdu_DiskIn
= TDU_NODISK
;
764 tdu
->pub
.tdu_Counter
++;
766 ForeachNode(&tdu
->tdu_Listeners
,iotd
)
768 Cause((struct Interrupt
*)((struct IOExtTD
*)iotd
->iotd_Req
.io_Data
));
771 tdu
->tdu_stepdir
= 0;
779 /* Reload the timer again */
780 GetMsg(tdb
->td_TimerMP
);
781 tdb
->td_TimerIO
->tr_node
.io_Command
= TR_ADDREQUEST
;
782 tdb
->td_TimerIO
->tr_time
.tv_secs
= 2;
783 tdb
->td_TimerIO
->tr_time
.tv_micro
= 500000;
784 SendIO((struct IORequest
*)tdb
->td_TimerIO
);