2 Copyright © 1995-2007, 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/expansionbase.h>
17 #include <libraries/configvars.h>
18 #include <dos/filehandler.h>
19 #include <dos/dosextens.h>
20 #include <dos/dostags.h>
21 #include <clib/alib_protos.h>
22 #include <aros/symbolsets.h>
23 #include <aros/bootloader.h>
26 #include <proto/oop.h>
27 #include <proto/exec.h>
28 #include <proto/expansion.h>
29 #include <proto/utility.h>
30 #include <proto/bootloader.h>
31 #include <proto/dos.h>
35 #include "trackdisk_device.h"
36 #include "trackdisk_hw.h"
38 #include LC_LIBDEFS_FILE
41 #include <aros/debug.h>
45 void td_floppytimer(HIDDT_IRQ_Handler
*, HIDDT_IRQ_HwInfo
*);
46 void td_floppyint(HIDDT_IRQ_Handler
*, HIDDT_IRQ_HwInfo
*);
47 int td_getbyte(unsigned char *, struct TrackDiskBase
*);
48 int td_sendbyte(unsigned char, struct TrackDiskBase
*);
49 ULONG
TD_InitTask(struct TrackDiskBase
*);
50 void TD_DevTask(struct TrackDiskBase
*);
51 BOOL
TD_PerformIO( struct IOExtTD
*, struct TrackDiskBase
*);
53 struct TDU
*TD_InitUnit(ULONG num
, struct TrackDiskBase
*tdb
)
56 struct ExpansionBase
*ExpansionBase
;
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
);
65 ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library",40);
68 unit
->tdu_DiskIn
= TDU_NODISK
; /* Assume there is no floppy in there */
69 unit
->pub
.tdu_StepDelay
= 4; /* Standard values here */
70 unit
->pub
.tdu_SettleDelay
= 16;
71 unit
->pub
.tdu_RetryCnt
= 3;
72 unit
->pub
.tdu_CalibrateDelay
= 4;
73 unit
->tdu_UnitNum
=num
;
74 unit
->tdu_lastcyl
= -1;
75 unit
->tdu_lasthd
= -1;
76 NEWLIST(&unit
->tdu_Listeners
);
78 /* Alloc memory for track buffering */
79 unit
->td_DMABuffer
=AllocMem(DP_SECTORS
*512,MEMF_CLEAR
|MEMF_CHIP
);
81 if (!unit
->td_DMABuffer
)
83 Alert(AT_DeadEnd
| AO_TrackDiskDev
| AG_NoMemory
);
86 /* If buffer doesn't fit into DMA page realloc it */
87 if (( (((ULONG
)unit
->td_DMABuffer
+ DP_SECTORS
*512) & 0xffff0000) -
88 ((ULONG
)unit
->td_DMABuffer
&0xffff0000) ) != 0)
92 buffer
= AllocMem(DP_SECTORS
*512, MEMF_CLEAR
| MEMF_CHIP
);
95 Alert(AT_DeadEnd
| AO_TrackDiskDev
| AG_NoMemory
);
98 FreeMem(unit
->td_DMABuffer
, DP_SECTORS
*512);
99 unit
->td_DMABuffer
= buffer
;
101 /* Store the unit in TDBase */
102 tdb
->td_Units
[num
] = unit
;
104 D(bug("TD: Adding bootnode\n"));
107 pp
= (IPTR
*)AllocMem(sizeof(struct DosEnvec
)+sizeof(IPTR
)*4,MEMF_PUBLIC
|MEMF_CLEAR
);
111 dosdevname
[2] += num
;
112 pp
[0] = (IPTR
)dosdevname
;
113 pp
[1] = (IPTR
)MOD_NAME_STRING
;
115 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
116 pp
[DE_SIZEBLOCK
+ 4] = 128;
117 pp
[DE_NUMHEADS
+ 4] = 2;
118 pp
[DE_SECSPERBLOCK
+ 4] = 1;
119 pp
[DE_BLKSPERTRACK
+ 4] = 18;
120 pp
[DE_RESERVEDBLKS
+ 4] = 2;
121 pp
[DE_LOWCYL
+ 4] = 0;
122 pp
[DE_HIGHCYL
+ 4] = 79;
123 pp
[DE_NUMBUFFERS
+ 4] = 10;
124 pp
[DE_BUFMEMTYPE
+ 4] = MEMF_PUBLIC
| MEMF_CHIP
;
125 pp
[DE_MAXTRANSFER
+ 4] = 0x00200000;
126 pp
[DE_MASK
+ 4] = 0x7FFFFFFE;
127 pp
[DE_BOOTPRI
+ 4] = 5;
128 pp
[DE_DOSTYPE
+ 4] = 0x444F5300;
129 pp
[DE_BOOTBLOCKS
+ 4] = 2;
130 devnode
= MakeDosNode(pp
);
134 len
= strlen(handler
);
135 devnode
->dn_Handler
= MKBADDR(AllocMem(
136 AROS_BSTR_MEMSIZE4LEN(len
), MEMF_PUBLIC
| MEMF_CLEAR
)
139 if (devnode
->dn_Name
!= NULL
)
141 CopyMem(handler
, AROS_BSTR_ADDR(devnode
->dn_Handler
),
143 AROS_BSTR_setstrlen(devnode
->dn_Handler
, len
);
144 AddBootNode(pp
[DE_BOOTPRI
+ 4], 0, devnode
, 0);
152 CloseLibrary((struct Library
*)ExpansionBase
);
157 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR TDBase
)
159 struct Library
*OOPBase
;
160 struct BootLoaderBase
*BootLoaderBase
;
164 D(bug("TD: Init\n"));
166 /* First thing, are we disabled from the bootloader? */
167 if ((BootLoaderBase
= OpenResource("bootloader.resource")))
172 list
= (struct List
*)GetBootInfo(BL_Args
);
175 ForeachNode(list
,node
)
177 if (0 == strncmp(node
->ln_Name
,"nofdc",5))
179 bug("[Floppy] Disabled with bootloader argument\n");
186 /* First we check if there are any floppy drives configured in BIOS */
187 /* We do this by reading CMOS byte 0x10 */
188 /* It should really reside in battclock.resource */
194 /* No drives here. abort */
195 D(bug("TD: No drives defined in BIOS\n"));
199 for (i
=0; i
<TD_NUMUNITS
; i
++)
200 TDBase
->td_Units
[i
] = NULL
;
202 /* Set up the IRQ system */
203 OOPBase
= OpenLibrary(AROSOOP_NAME
, 0);
209 o
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
213 HIDDT_IRQ_Handler
*irq
;
215 irq
= AllocMem(sizeof(HIDDT_IRQ_Handler
), MEMF_CLEAR
|MEMF_PUBLIC
);
219 /* PANIC! No memory for trackdisk IntServer ! */
220 Alert(AT_DeadEnd
|AO_TrackDiskDev
|AN_IntrMem
);
222 irq
->h_Node
.ln_Pri
=127; /* Set the highest pri */
223 irq
->h_Node
.ln_Name
= (STRPTR
)MOD_NAME_STRING
;
224 irq
->h_Code
= td_floppyint
;
225 irq
->h_Data
= (APTR
)TDBase
;
227 HIDD_IRQ_AddHandler(o
, irq
, vHidd_IRQ_Floppy
);
229 irq
= AllocMem(sizeof(HIDDT_IRQ_Handler
), MEMF_CLEAR
|MEMF_PUBLIC
);
233 /* PANIC! No memory for trackdisk IntServer ! */
234 Alert(AT_DeadEnd
|AO_TrackDiskDev
|AN_IntrMem
);
236 irq
->h_Node
.ln_Pri
=10; /* Set the highest pri */
237 irq
->h_Node
.ln_Name
= (STRPTR
)MOD_NAME_STRING
;
238 irq
->h_Code
= td_floppytimer
;
239 irq
->h_Data
= (APTR
)TDBase
;
241 HIDD_IRQ_AddHandler(o
, irq
, vHidd_IRQ_Timer
);
243 OOP_DisposeObject(o
);
245 CloseLibrary(OOPBase
);
248 /* Swap drivebits around */
249 drives
= ( (drives
&0xf0)>>4 | (drives
&0x0f)<<4 );
251 for (i
=0;i
<TD_NUMUNITS
;i
++)
253 /* We only want 3.5" 1.44Mb drives */
254 if (((drives
>> (4*i
))&0x0f) == 4)
256 kprintf("[Floppy] Unit %d is a 1.44Mb drive\n",i
);
257 TD_InitUnit(i
,TDBase
);
261 /* Create the message processor task */
267 static int GM_UNIQUENAME(Open
)
269 LIBBASETYPEPTR TDBase
,
270 struct IOExtTD
*iotd
,
275 D(bug("TD: Open\n"));
276 iotd
->iotd_Req
.io_Error
= IOERR_OPENFAIL
;
278 /* Is the requested unitNumber valid? */
279 if (unitnum
< TD_NUMUNITS
)
283 iotd
->iotd_Req
.io_Device
= (struct Device
*)TDBase
;
285 /* Get TDU structure */
286 unit
= TDBase
->td_Units
[unitnum
];
287 if (unit
&& (unit
->tdu_Present
)) {
288 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
289 ((struct Unit
*)unit
)->unit_OpenCnt
++;
290 iotd
->iotd_Req
.io_Error
= 0;
294 return iotd
->iotd_Req
.io_Error
== 0;
298 static int GM_UNIQUENAME(Close
)
300 LIBBASETYPEPTR TDBase
,
304 iotd
->iotd_Req
.io_Unit
->unit_OpenCnt
--;
309 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
310 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
311 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
312 ADD2LIBS("irq.hidd", 0, static struct Library
*, __irqhidd
)
314 AROS_LH1(void, beginio
,
315 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
316 struct TrackDiskBase
*, TDBase
, 5, TrackDisk
)
321 if (iotd
->iotd_Req
.io_Flags
& IOF_QUICK
)
323 switch(iotd
->iotd_Req
.io_Command
)
326 tdu
= (struct TDU
*)iotd
->iotd_Req
.io_Unit
;
327 if ((!(tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
)) || (tdu
->tdu_DiskIn
== TDU_DISK
))
339 PutMsg(&TDBase
->td_TaskData
->td_Port
, &iotd
->iotd_Req
.io_Message
);
340 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
343 TD_PerformIO(iotd
,TDBase
);
348 /* Forward to devicetask */
349 PutMsg(&TDBase
->td_TaskData
->td_Port
, &iotd
->iotd_Req
.io_Message
);
351 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
357 AROS_LH1(LONG
, abortio
,
358 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
359 struct TrackDiskBase
*, TDBase
, 6, TrackDisk
)
362 D(bug("TD: AbortIO\n"));
367 void TestInsert(struct TrackDiskBase
*tdb
, struct TDU
*tdu
)
370 struct IOExtTD
*iotd
;
372 td_rseek(tdu
->tdu_UnitNum
,tdu
->tdu_stepdir
,1,tdb
);
373 tdu
->tdu_stepdir
= !tdu
->tdu_stepdir
;
374 dir
= (inb(FDC_DIR
)>>7);
377 D(bug("[Floppy] Insertion detected\n"));
378 td_recalibrate(tdu
->tdu_UnitNum
,1,0,tdb
);
379 tdu
->tdu_DiskIn
= TDU_DISK
;
380 tdu
->pub
.tdu_Counter
++;
381 tdu
->tdu_ProtStatus
= td_getprotstatus(tdu
->tdu_UnitNum
,tdb
);
383 ForeachNode(&tdu
->tdu_Listeners
,iotd
)
385 Cause((struct Interrupt
*)((struct IOExtTD
*)iotd
->iotd_Req
.io_Data
));
391 BOOL
TD_PerformIO( struct IOExtTD
*iotd
, struct TrackDiskBase
*tdb
)
394 struct DriveGeometry
*geo
;
399 tdu
= (struct TDU
*)iotd
->iotd_Req
.io_Unit
;
400 switch(iotd
->iotd_Req
.io_Command
)
403 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
404 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
409 tdu
->tdu_lastcyl
= -1;
410 tdu
->tdu_lasthd
= -1;
411 iotd
->iotd_Req
.io_Error
= 0;
414 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
415 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
419 tdu
->tdu_Busy
= TRUE
;
420 iotd
->iotd_Req
.io_Error
= td_read(iotd
, tdb
);
421 tdu
->tdu_Busy
= FALSE
;
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_update(tdu
, 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_write(iotd
, tdb
);
441 tdu
->tdu_Busy
= FALSE
;
443 case TD_ADDCHANGEINT
:
445 AddTail(&tdu
->tdu_Listeners
,(struct Node
*)iotd
);
450 iotd
->iotd_Req
.io_Actual
= tdu
->pub
.tdu_Counter
;
453 if ((tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
) && (tdu
->tdu_DiskIn
== TDU_NODISK
)) {
454 TestInsert(tdb
, tdu
);
455 if (!tdu
->tdu_MotorOn
)
456 td_motoroff(tdu
->tdu_UnitNum
, tdb
);
458 if (tdu
->tdu_DiskIn
== TDU_DISK
)
460 /* test if disk is still in there */
461 temp
= td_getDiskChange();
462 iotd
->iotd_Req
.io_Actual
= temp
;
463 tdu
->tdu_DiskIn
= temp
^ 1;
467 /* No disk in drive */
468 iotd
->iotd_Req
.io_Actual
= 1;
470 iotd
->iotd_Req
.io_Error
=0;
473 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
474 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
478 tdu
->tdu_Busy
= TRUE
;
479 iotd
->iotd_Req
.io_Error
= td_format(iotd
,tdb
);
480 tdu
->tdu_Busy
= FALSE
;
483 if (iotd
->iotd_Count
> tdu
->pub
.tdu_Counter
) {
484 iotd
->iotd_Req
.io_Error
= TDERR_DiskChanged
;
488 iotd
->iotd_Req
.io_Error
=0;
489 switch (iotd
->iotd_Req
.io_Length
)
492 tdu
->tdu_MotorOn
= 0;
493 td_motoroff(tdu
->tdu_UnitNum
,tdb
);
496 tdu
->tdu_MotorOn
= 1;
497 td_motoron(tdu
->tdu_UnitNum
,tdb
,TRUE
);
500 iotd
->iotd_Req
.io_Error
= TDERR_NotSpecified
;
505 iotd
->iotd_Req
.io_Actual
= tdu
->tdu_ProtStatus
;
507 case TD_REMCHANGEINT
:
509 Remove((struct Node
*)iotd
);
513 geo
= (struct DriveGeometry
*)iotd
->iotd_Req
.io_Data
;
514 geo
->dg_SectorSize
= 512;
515 geo
->dg_TotalSectors
= DP_STOTAL
;
516 geo
->dg_Cylinders
= DP_TRACKS
;
517 geo
->dg_CylSectors
= DP_SECTORS
*2;
519 geo
->dg_TrackSectors
= DP_SECTORS
;
520 geo
->dg_BufMemType
= MEMF_PUBLIC
;
521 geo
->dg_DeviceType
= DG_DIRECT_ACCESS
;
522 geo
->dg_Flags
= DGF_REMOVABLE
;
524 case TD_GETDRIVETYPE
:
525 iotd
->iotd_Req
.io_Actual
= DRIVE3_5
;
527 case TD_GETNUMTRACKS
:
528 iotd
->iotd_Req
.io_Actual
= DP_TRACKS
*2;
532 D(bug("TD: Unknown command received\n"));
533 iotd
->iotd_Req
.io_Error
= IOERR_NOCMD
;
535 } /* switch(iotd->iotd_Req.io_Command) */
539 ULONG
TD_InitTask(struct TrackDiskBase
*tdb
)
545 /* Allocate Task Data structure */
546 t
= AllocMem(sizeof(struct TaskData
), MEMF_PUBLIC
|MEMF_CLEAR
);
547 /* Allocate MemEntry for this task */
548 ml
= (struct MemList
*)AllocMem(sizeof(struct MemList
), MEMF_PUBLIC
|MEMF_CLEAR
);
550 /* Find the current task */
556 BYTE
*sp
= t
->td_Stack
;
558 D(bug("TD: Creating devicetask..."));
559 /* Save stack info into task structure */
560 t
->td_Task
.tc_SPLower
= sp
;
561 t
->td_Task
.tc_SPUpper
= (BYTE
*)sp
+ STACK_SIZE
;
562 t
->td_Task
.tc_SPReg
= (BYTE
*)t
->td_Task
.tc_SPUpper
- SP_OFFSET
- sizeof(APTR
);
563 /* Store TDBase on stack */
564 ((APTR
*)t
->td_Task
.tc_SPUpper
)[-1] = tdb
;
567 NEWLIST(&t
->td_Port
.mp_MsgList
);
568 t
->td_Port
.mp_Node
.ln_Type
= NT_MSGPORT
;
569 t
->td_Port
.mp_Flags
= PA_SIGNAL
;
570 t
->td_Port
.mp_SigBit
= SIGBREAKB_CTRL_F
;
571 t
->td_Port
.mp_SigTask
= &t
->td_Task
;
572 t
->td_Port
.mp_Node
.ln_Name
= "trackdisk.device";
575 ml
->ml_NumEntries
= 1;
576 ml
->ml_ME
[0].me_Addr
= t
;
577 ml
->ml_ME
[0].me_Length
= sizeof(struct TaskData
);
578 NEWLIST(&t
->td_Task
.tc_MemEntry
);
579 AddHead(&t
->td_Task
.tc_MemEntry
, &ml
->ml_Node
);
581 /* Init Task structure */
582 t
->td_Task
.tc_Node
.ln_Name
= "trackdisk.task";
583 t
->td_Task
.tc_Node
.ln_Type
= NT_TASK
;
584 t
->td_Task
.tc_Node
.ln_Pri
= 5;
585 t
->td_Task
.tc_UserData
= me
;
587 tdb
->td_TaskData
= t
;
589 /* Add task to system task list */
590 AddTask(&t
->td_Task
, &TD_DevTask
, NULL
);
592 /* Wait until started */
593 Wait(SIGBREAKF_CTRL_F
);
605 void TD_DevTask(struct TrackDiskBase
*tdb
)
608 struct IOExtTD
*iotd
;
610 ULONG tasig
,tisig
,sigs
,i
;
613 td
= tdb
->td_TaskData
;
615 tdb
->td_IntBit
= AllocSignal(-1);
616 tdb
->td_TmoBit
= AllocSignal(-1);
617 tdb
->td_TimerMP
= CreateMsgPort();
618 tdb
->td_TimerIO
= (struct timerequest
*) CreateIORequest(tdb
->td_TimerMP
, sizeof(struct timerequest
));
619 OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tdb
->td_TimerIO
, 0);
624 /* Initial check for floppies */
625 for (i
=0;i
<TD_NUMUNITS
;i
++)
629 td_rseek(i
, 0, 1, tdb
);
630 tdb
->td_Units
[i
]->tdu_Present
= !td_recalibrate(tdb
->td_Units
[i
]->tdu_UnitNum
,1,0,tdb
);
631 tdb
->td_Units
[i
]->pub
.tdu_CurrTrk
= 0;
632 tdb
->td_Units
[i
]->tdu_DiskIn
= (td_getDiskChange() ^ 1);
633 tdb
->td_Units
[i
]->tdu_ProtStatus
= td_getprotstatus(i
,tdb
);
634 tdb
->td_Units
[i
]->tdu_Busy
= FALSE
;
635 tdb
->td_Units
[i
]->tdu_stepdir
= 0;
636 if (((tdb
->td_Units
[i
]->pub
.tdu_PubFlags
& TDPF_NOCLICK
) && (tdb
->td_Units
[i
]->tdu_DiskIn
== TDU_NODISK
))
637 || (!tdb
->td_Units
[i
]->tdu_Present
))
639 D(bug("Drive %d presence: %ld\n", i
, tdb
->td_Units
[i
]->tdu_Present
));
643 tasig
= 1L << td
->td_Port
.mp_SigBit
;
644 tisig
= 1L << tdb
->td_TimerMP
->mp_SigBit
;
646 /* Reply to startup message */
647 Signal(td
->td_Task
.tc_UserData
,SIGBREAKF_CTRL_F
);
649 tdb
->td_TimerIO
->tr_node
.io_Command
= TR_ADDREQUEST
;
650 tdb
->td_TimerIO
->tr_time
.tv_secs
= 2;
651 tdb
->td_TimerIO
->tr_time
.tv_micro
= 500000;
652 SendIO((struct IORequest
*)tdb
->td_TimerIO
);
654 /* Endless task loop */
658 sigs
= Wait(tasig
| tisig
); /* Wait for a message */
659 /* If unit was not active process message */
662 /* We received a message. Deal with it */
663 while((iotd
= (struct IOExtTD
*)GetMsg(&td
->td_Port
)) != NULL
)
665 /* Execute command */
666 if (TD_PerformIO( iotd
, tdb
))
669 ReplyMsg((struct Message
*)iotd
);
675 /* We were woken up by the timer. */
676 WaitIO((struct IORequest
*)tdb
->td_TimerIO
);
677 for(i
=0;i
<TD_NUMUNITS
;i
++)
679 /* If there is no floppy in drive, scan for changes */
680 if (tdb
->td_Units
[i
])
682 tdu
= tdb
->td_Units
[i
];
683 switch (tdu
->tdu_DiskIn
)
687 Unfortunately "NoClick" technology which works on Amiga will not
688 work on PC because i82077 does not send step pulse when told to
689 seek to "-1" track and the drive can't recognize disk insertion.
690 Many thanks to Intel! :-(((
692 Here we use another technique: in NoClick mode we just do nothing
693 if the disk is not in drive. We can perform this test only once
694 inside TD_CHANGESTATE command which is invoked by DISKCHANGE
695 CLI command. This means that we'll have to issue DISKCHANGE command
696 manually after wi insert the disk, but this is probably better
699 if (tdu
->pub
.tdu_PubFlags
& TDPF_NOCLICK
) {
700 if (!tdu
->tdu_MotorOn
)
701 td_motoroff(tdu
->tdu_UnitNum
, tdb
);
703 TestInsert(tdb
, tdu
);
707 Fortunately this part is completely silent so we don't have to
708 do any extra mess here
712 if (!tdu
->tdu_MotorOn
)
713 td_motoron(tdu
->tdu_UnitNum
,tdb
,FALSE
);
714 dir
= (inb(FDC_DIR
)>>7);
715 if (!tdu
->tdu_MotorOn
)
716 td_motoroff(tdu
->tdu_UnitNum
,tdb
);
719 D(bug("[Floppy] Removal detected\n"));
720 /* Go to cylinder 0 */
721 td_recalibrate(tdu
->tdu_UnitNum
,1,0,tdb
);
722 tdu
->tdu_DiskIn
= TDU_NODISK
;
723 tdu
->pub
.tdu_Counter
++;
725 ForeachNode(&tdu
->tdu_Listeners
,iotd
)
727 Cause((struct Interrupt
*)((struct IOExtTD
*)iotd
->iotd_Req
.io_Data
));
730 tdu
->tdu_stepdir
= 0;
738 /* Reload the timer again */
739 GetMsg(tdb
->td_TimerMP
);
740 tdb
->td_TimerIO
->tr_node
.io_Command
= TR_ADDREQUEST
;
741 tdb
->td_TimerIO
->tr_time
.tv_secs
= 2;
742 tdb
->td_TimerIO
->tr_time
.tv_micro
= 500000;
743 SendIO((struct IORequest
*)tdb
->td_TimerIO
);
748 #define TDBase ((struct TrackDiskBase *)irq->h_Data)
749 void td_floppytimer(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
751 // Does anyone wait for io?
752 if (TDBase
->td_inttmo
)
757 if (!TDBase
->td_inttmo
)
759 Signal(&TDBase
->td_TaskData
->td_Task
,(1L << TDBase
->td_TmoBit
));
764 void td_floppyint(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
766 Signal(&TDBase
->td_TaskData
->td_Task
,(1L << TDBase
->td_IntBit
));