added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / arch / i386-pc / Drivers / trackdisk / trackdisk_device.c
blob8873a602a375c22abbfb0b31448eafc1d07c86bc
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Amigastyle device for trackdisk
6 Lang: English
7 */
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>
24 #include <oop/oop.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>
32 #include <hidd/irq.h>
33 #include <asm/io.h>
35 #include "trackdisk_device.h"
36 #include "trackdisk_hw.h"
38 #include LC_LIBDEFS_FILE
40 #define DEBUG 0
41 #include <aros/debug.h>
43 #undef kprintf
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)
55 struct TDU *unit;
56 struct ExpansionBase *ExpansionBase;
57 struct DeviceNode *devnode;
58 IPTR *pp;
59 TEXT dosdevname[4] = "DF0", *handler = "afs.handler";
60 UWORD len;
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);
66 if (unit)
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)
90 APTR buffer;
92 buffer = AllocMem(DP_SECTORS*512, MEMF_CLEAR | MEMF_CHIP);
93 if (!buffer)
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"));
105 if (ExpansionBase)
107 pp = (IPTR *)AllocMem(sizeof(struct DosEnvec)+sizeof(IPTR)*4,MEMF_PUBLIC|MEMF_CLEAR);
109 if (pp)
111 dosdevname[2] += num;
112 pp[0] = (IPTR)dosdevname;
113 pp[1] = (IPTR)MOD_NAME_STRING;
114 pp[2] = num;
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);
132 if (devnode)
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),
142 len);
143 AROS_BSTR_setstrlen(devnode->dn_Handler, len);
144 AddBootNode(pp[DE_BOOTPRI + 4], 0, devnode, 0);
150 if (ExpansionBase)
152 CloseLibrary((struct Library *)ExpansionBase);
154 return (unit);
157 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR TDBase)
159 struct Library *OOPBase;
160 struct BootLoaderBase *BootLoaderBase;
161 ULONG i;
162 UBYTE drives;
164 D(bug("TD: Init\n"));
166 /* First thing, are we disabled from the bootloader? */
167 if ((BootLoaderBase = OpenResource("bootloader.resource")))
169 struct List *list;
170 struct Node *node;
172 list = (struct List *)GetBootInfo(BL_Args);
173 if (list)
175 ForeachNode(list,node)
177 if (0 == strncmp(node->ln_Name,"nofdc",5))
179 bug("[Floppy] Disabled with bootloader argument\n");
180 return FALSE;
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 */
189 outb(0x10,0x70);
190 drives = inb(0x71);
192 if (drives == 0)
194 /* No drives here. abort */
195 D(bug("TD: No drives defined in BIOS\n"));
196 return FALSE;
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);
205 if (OOPBase)
207 OOP_Object *o;
209 o = OOP_NewObject(NULL, CLID_Hidd_IRQ, NULL);
211 if (o)
213 HIDDT_IRQ_Handler *irq;
215 irq = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_CLEAR|MEMF_PUBLIC);
217 if(!irq)
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);
231 if(!irq)
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 */
262 TD_InitTask(TDBase);
264 return TRUE;
267 static int GM_UNIQUENAME(Open)
269 LIBBASETYPEPTR TDBase,
270 struct IOExtTD *iotd,
271 ULONG unitnum,
272 ULONG flags
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)
281 struct TDU *unit;
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,
301 struct IOExtTD *iotd
304 iotd->iotd_Req.io_Unit->unit_OpenCnt --;
306 return TRUE;
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)
318 AROS_LIBFUNC_INIT
319 struct TDU *tdu;
321 if (iotd->iotd_Req.io_Flags & IOF_QUICK)
323 switch(iotd->iotd_Req.io_Command)
325 case TD_CHANGESTATE:
326 tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
327 if ((!(tdu->pub.tdu_PubFlags & TDPF_NOCLICK)) || (tdu->tdu_DiskIn == TDU_DISK))
328 break;
329 case CMD_READ:
330 case CMD_UPDATE:
331 case CMD_WRITE:
332 case TD_FORMAT:
333 case TD_MOTOR:
334 case ETD_READ:
335 case ETD_UPDATE:
336 case ETD_WRITE:
337 case ETD_FORMAT:
338 case ETD_MOTOR:
339 PutMsg(&TDBase->td_TaskData->td_Port, &iotd->iotd_Req.io_Message);
340 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
341 return;
343 TD_PerformIO(iotd,TDBase);
344 return;
346 else
348 /* Forward to devicetask */
349 PutMsg(&TDBase->td_TaskData->td_Port, &iotd->iotd_Req.io_Message);
350 /* Not done quick */
351 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
352 return;
354 AROS_LIBFUNC_EXIT
357 AROS_LH1(LONG, abortio,
358 AROS_LHA(struct IOExtTD *, iotd, A1),
359 struct TrackDiskBase *, TDBase, 6, TrackDisk)
361 AROS_LIBFUNC_INIT
362 D(bug("TD: AbortIO\n"));
363 return IOERR_NOCMD;
364 AROS_LIBFUNC_EXIT
367 void TestInsert(struct TrackDiskBase *tdb, struct TDU *tdu)
369 UBYTE dir;
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);
375 if (dir == 0)
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);
382 Forbid();
383 ForeachNode(&tdu->tdu_Listeners,iotd)
385 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
387 Permit();
391 BOOL TD_PerformIO( struct IOExtTD *iotd, struct TrackDiskBase *tdb)
393 struct TDU *tdu;
394 struct DriveGeometry *geo;
395 UBYTE temp;
396 BOOL reply;
398 reply = TRUE;
399 tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
400 switch(iotd->iotd_Req.io_Command)
402 case ETD_CLEAR:
403 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
404 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
405 break;
407 case CMD_CLEAR:
408 tdu->tdu_flags = 0;
409 tdu->tdu_lastcyl = -1;
410 tdu->tdu_lasthd = -1;
411 iotd->iotd_Req.io_Error = 0;
412 break;
413 case ETD_READ:
414 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
415 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
416 break;
418 case CMD_READ:
419 tdu->tdu_Busy = TRUE;
420 iotd->iotd_Req.io_Error = td_read(iotd, tdb);
421 tdu->tdu_Busy = FALSE;
422 break;
423 case ETD_UPDATE:
424 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
425 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
426 break;
428 case CMD_UPDATE:
429 tdu->tdu_Busy = TRUE;
430 iotd->iotd_Req.io_Error = td_update(tdu, tdb);
431 tdu->tdu_Busy = FALSE;
432 break;
433 case ETD_WRITE:
434 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
435 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
436 break;
438 case CMD_WRITE:
439 tdu->tdu_Busy = TRUE;
440 iotd->iotd_Req.io_Error = td_write(iotd, tdb);
441 tdu->tdu_Busy = FALSE;
442 break;
443 case TD_ADDCHANGEINT:
444 Forbid();
445 AddTail(&tdu->tdu_Listeners,(struct Node *)iotd);
446 Permit();
447 reply = FALSE;
448 break;
449 case TD_CHANGENUM:
450 iotd->iotd_Req.io_Actual = tdu->pub.tdu_Counter;
451 break;
452 case TD_CHANGESTATE:
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;
465 else
467 /* No disk in drive */
468 iotd->iotd_Req.io_Actual = 1;
470 iotd->iotd_Req.io_Error=0;
471 break;
472 case ETD_FORMAT:
473 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
474 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
475 break;
477 case TD_FORMAT:
478 tdu->tdu_Busy = TRUE;
479 iotd->iotd_Req.io_Error = td_format(iotd,tdb);
480 tdu->tdu_Busy = FALSE;
481 break;
482 case ETD_MOTOR:
483 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
484 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
485 break;
487 case TD_MOTOR:
488 iotd->iotd_Req.io_Error=0;
489 switch (iotd->iotd_Req.io_Length)
491 case 0:
492 tdu->tdu_MotorOn = 0;
493 td_motoroff(tdu->tdu_UnitNum,tdb);
494 break;
495 case 1:
496 tdu->tdu_MotorOn = 1;
497 td_motoron(tdu->tdu_UnitNum,tdb,TRUE);
498 break;
499 default:
500 iotd->iotd_Req.io_Error = TDERR_NotSpecified;
501 break;
503 break;
504 case TD_PROTSTATUS:
505 iotd->iotd_Req.io_Actual = tdu->tdu_ProtStatus;
506 break;
507 case TD_REMCHANGEINT:
508 Forbid();
509 Remove((struct Node *)iotd);
510 Permit();
511 break;
512 case TD_GETGEOMETRY:
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;
518 geo->dg_Heads = 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;
523 break;
524 case TD_GETDRIVETYPE:
525 iotd->iotd_Req.io_Actual = DRIVE3_5;
526 break;
527 case TD_GETNUMTRACKS:
528 iotd->iotd_Req.io_Actual = DP_TRACKS*2;
529 break;
530 default:
531 /* Not supported */
532 D(bug("TD: Unknown command received\n"));
533 iotd->iotd_Req.io_Error = IOERR_NOCMD;
534 break;
535 } /* switch(iotd->iotd_Req.io_Command) */
536 return (reply);
539 ULONG TD_InitTask(struct TrackDiskBase *tdb)
541 struct TaskData *t;
542 struct MemList *ml;
543 struct Task *me;
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 */
551 me = FindTask(NULL);
553 if (t && ml)
555 /* prepare stack */
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;
566 /* Init MsgPort */
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";
574 /* Init MemList */
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);
595 D(bug(" OK\n"));
597 return 1;
600 return 0;
603 /* Device task */
605 void TD_DevTask(struct TrackDiskBase *tdb)
607 struct TaskData *td;
608 struct IOExtTD *iotd;
609 struct TDU *tdu;
610 ULONG tasig,tisig,sigs,i;
611 UBYTE dir;
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);
621 /* Initialize FDC */
622 td_dinit(tdb);
624 /* Initial check for floppies */
625 for (i=0;i<TD_NUMUNITS;i++)
627 if(tdb->td_Units[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))
638 td_motoroff(i, tdb);
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 */
655 for(;;)
657 sigs = 0L;
658 sigs = Wait(tasig | tisig); /* Wait for a message */
659 /* If unit was not active process message */
660 if (sigs & tasig)
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))
668 /* Finish message */
669 ReplyMsg((struct Message *)iotd);
673 if (sigs & tisig)
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)
685 case TDU_NODISK:
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
697 than those clicks.
699 if (tdu->pub.tdu_PubFlags & TDPF_NOCLICK) {
700 if (!tdu->tdu_MotorOn)
701 td_motoroff(tdu->tdu_UnitNum, tdb);
702 } else
703 TestInsert(tdb, tdu);
704 break;
705 case TDU_DISK:
707 Fortunately this part is completely silent so we don't have to
708 do any extra mess here
710 if (!tdu->tdu_Busy)
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);
717 if (dir == 1)
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++;
724 Forbid();
725 ForeachNode(&tdu->tdu_Listeners,iotd)
727 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
729 Permit();
730 tdu->tdu_stepdir = 0;
733 break;
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)
754 // Decrease timeout
755 TDBase->td_inttmo--;
756 // timeout?
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));