Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / arch / i386-pc / drivers / trackdisk / trackdisk_device.c
blob28806dcfc43111e964799095bfc3694b4ecf48b4
1 /*
2 Copyright © 1995-2008, 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 static void TD_DevTask();
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 = NULL;
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 if (!tdb->td_nomount)
66 ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",40);
67 if (unit)
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);
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)unit->td_DMABuffer + DP_SECTORS*512) & 0xffff0000) -
89 ((ULONG)unit->td_DMABuffer&0xffff0000) ) != 0)
91 APTR buffer;
93 buffer = AllocMem(DP_SECTORS*512, MEMF_CLEAR | MEMF_CHIP);
94 if (!buffer)
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;
105 if (ExpansionBase)
107 D(bug("TD: Adding bootnode\n"));
108 pp = (IPTR *)AllocMem(sizeof(struct DosEnvec)+sizeof(IPTR)*4,MEMF_PUBLIC|MEMF_CLEAR);
110 if (pp)
112 dosdevname[2] += num;
113 pp[0] = (IPTR)dosdevname;
114 pp[1] = (IPTR)MOD_NAME_STRING;
115 pp[2] = num;
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] = 0x444F5300;
130 pp[DE_BOOTBLOCKS + 4] = 2;
131 devnode = MakeDosNode(pp);
133 if (devnode)
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),
143 len);
144 AROS_BSTR_setstrlen(devnode->dn_Handler, len);
145 AddBootNode(pp[DE_BOOTPRI + 4], 0, devnode, 0);
151 if (ExpansionBase)
153 CloseLibrary((struct Library *)ExpansionBase);
155 return (unit);
158 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR TDBase)
160 struct Library *OOPBase;
161 struct BootLoaderBase *BootLoaderBase;
162 ULONG i;
163 UBYTE drives;
165 D(bug("TD: Init\n"));
167 /* First thing, are we disabled from the bootloader? */
168 if ((BootLoaderBase = OpenResource("bootloader.resource")))
170 struct List *list;
171 struct Node *node;
173 list = (struct List *)GetBootInfo(BL_Args);
174 if (list)
176 ForeachNode(list,node)
178 if (0 == strncmp(node->ln_Name,"floppy=",5))
180 if (strstr(&node->ln_Name[7], "disabled"))
182 D(bug("[Floppy] Disabled with bootloader argument\n"));
183 return FALSE;
185 TDBase->td_nomount = strstr(&node->ln_Name[7], "nomount");
191 /* First we check if there are any floppy drives configured in BIOS */
192 /* We do this by reading CMOS byte 0x10 */
193 /* It should really reside in battclock.resource */
194 outb(0x10,0x70);
195 drives = inb(0x71);
197 if (drives == 0)
199 /* No drives here. abort */
200 D(bug("TD: No drives defined in BIOS\n"));
201 return FALSE;
204 for (i=0; i<TD_NUMUNITS; i++)
205 TDBase->td_Units[i] = NULL;
207 /* Set up the IRQ system */
208 OOPBase = OpenLibrary(AROSOOP_NAME, 0);
210 if (OOPBase)
212 OOP_Object *o;
214 o = OOP_NewObject(NULL, CLID_Hidd_IRQ, NULL);
216 if (o)
218 HIDDT_IRQ_Handler *irq;
220 irq = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_CLEAR|MEMF_PUBLIC);
222 if(!irq)
224 /* PANIC! No memory for trackdisk IntServer ! */
225 Alert(AT_DeadEnd|AO_TrackDiskDev|AN_IntrMem);
227 irq->h_Node.ln_Pri=127; /* Set the highest pri */
228 irq->h_Node.ln_Name = (STRPTR)MOD_NAME_STRING;
229 irq->h_Code = td_floppyint;
230 irq->h_Data = (APTR)TDBase;
232 HIDD_IRQ_AddHandler(o, irq, vHidd_IRQ_Floppy);
234 irq = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_CLEAR|MEMF_PUBLIC);
236 if(!irq)
238 /* PANIC! No memory for trackdisk IntServer ! */
239 Alert(AT_DeadEnd|AO_TrackDiskDev|AN_IntrMem);
241 irq->h_Node.ln_Pri=10; /* Set the highest pri */
242 irq->h_Node.ln_Name = (STRPTR)MOD_NAME_STRING;
243 irq->h_Code = td_floppytimer;
244 irq->h_Data = (APTR)TDBase;
246 HIDD_IRQ_AddHandler(o, irq, vHidd_IRQ_Timer);
248 OOP_DisposeObject(o);
250 CloseLibrary(OOPBase);
253 /* Swap drivebits around */
254 drives = ( (drives&0xf0)>>4 | (drives&0x0f)<<4 );
256 for (i=0;i<TD_NUMUNITS;i++)
258 /* We only want 3.5" 1.44Mb drives */
259 if (((drives >> (4*i))&0x0f) == 4)
261 kprintf("[Floppy] Unit %d is a 1.44Mb drive\n",i);
262 TD_InitUnit(i,TDBase);
266 /* Create the message processor task */
267 TD_InitTask(TDBase);
269 return TRUE;
272 static int GM_UNIQUENAME(Open)
274 LIBBASETYPEPTR TDBase,
275 struct IOExtTD *iotd,
276 ULONG unitnum,
277 ULONG flags
280 D(bug("TD: Open\n"));
281 iotd->iotd_Req.io_Error = IOERR_OPENFAIL;
283 /* Is the requested unitNumber valid? */
284 if (unitnum < TD_NUMUNITS)
286 struct TDU *unit;
288 iotd->iotd_Req.io_Device = (struct Device *)TDBase;
290 /* Get TDU structure */
291 unit = TDBase->td_Units[unitnum];
292 if (unit && (unit->tdu_Present)) {
293 iotd->iotd_Req.io_Unit = (struct Unit *)unit;
294 ((struct Unit *)unit)->unit_OpenCnt++;
295 iotd->iotd_Req.io_Error = 0;
299 return iotd->iotd_Req.io_Error == 0;
303 static int GM_UNIQUENAME(Close)
305 LIBBASETYPEPTR TDBase,
306 struct IOExtTD *iotd
309 iotd->iotd_Req.io_Unit->unit_OpenCnt --;
311 return TRUE;
314 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
315 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
316 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
317 ADD2LIBS("irq.hidd", 0, static struct Library *, __irqhidd)
319 AROS_LH1(void, beginio,
320 AROS_LHA(struct IOExtTD *, iotd, A1),
321 struct TrackDiskBase *, TDBase, 5, TrackDisk)
323 AROS_LIBFUNC_INIT
324 struct TDU *tdu;
326 if (iotd->iotd_Req.io_Flags & IOF_QUICK)
328 switch(iotd->iotd_Req.io_Command)
330 case TD_CHANGESTATE:
331 tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
332 if ((!(tdu->pub.tdu_PubFlags & TDPF_NOCLICK)) || (tdu->tdu_DiskIn == TDU_DISK))
333 break;
334 case CMD_READ:
335 case CMD_UPDATE:
336 case CMD_WRITE:
337 case TD_FORMAT:
338 case TD_MOTOR:
339 case TD_SEEK:
340 case ETD_READ:
341 case ETD_UPDATE:
342 case ETD_WRITE:
343 case ETD_FORMAT:
344 case ETD_MOTOR:
345 case ETD_SEEK:
346 PutMsg(&TDBase->td_TaskData->td_Port, &iotd->iotd_Req.io_Message);
347 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
348 return;
350 TD_PerformIO(iotd,TDBase);
351 return;
353 else
355 /* Forward to devicetask */
356 PutMsg(&TDBase->td_TaskData->td_Port, &iotd->iotd_Req.io_Message);
357 /* Not done quick */
358 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
359 return;
361 AROS_LIBFUNC_EXIT
364 AROS_LH1(LONG, abortio,
365 AROS_LHA(struct IOExtTD *, iotd, A1),
366 struct TrackDiskBase *, TDBase, 6, TrackDisk)
368 AROS_LIBFUNC_INIT
369 D(bug("TD: AbortIO\n"));
370 return IOERR_NOCMD;
371 AROS_LIBFUNC_EXIT
374 void TestInsert(struct TrackDiskBase *tdb, struct TDU *tdu)
376 UBYTE dir;
377 struct IOExtTD *iotd;
379 td_rseek(tdu->tdu_UnitNum,tdu->tdu_stepdir,1,tdb);
380 tdu->tdu_stepdir = !tdu->tdu_stepdir;
381 dir = (inb(FDC_DIR)>>7);
382 if (dir == 0)
384 D(bug("[Floppy] Insertion detected\n"));
385 td_recalibrate(tdu->tdu_UnitNum,1,0,tdb);
386 tdu->tdu_DiskIn = TDU_DISK;
387 tdu->pub.tdu_Counter++;
388 tdu->tdu_ProtStatus = td_getprotstatus(tdu->tdu_UnitNum,tdb);
389 Forbid();
390 ForeachNode(&tdu->tdu_Listeners,iotd)
392 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
394 Permit();
398 BOOL TD_PerformIO( struct IOExtTD *iotd, struct TrackDiskBase *tdb)
400 struct TDU *tdu;
401 struct DriveGeometry *geo;
402 UBYTE temp;
403 BOOL reply;
405 reply = TRUE;
406 tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
407 switch(iotd->iotd_Req.io_Command)
409 case ETD_CLEAR:
410 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
411 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
412 break;
414 case CMD_CLEAR:
415 tdu->tdu_flags = 0;
416 tdu->tdu_lastcyl = -1;
417 tdu->tdu_lasthd = -1;
418 iotd->iotd_Req.io_Error = 0;
419 break;
420 case ETD_READ:
421 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
422 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
423 break;
425 case CMD_READ:
426 tdu->tdu_Busy = TRUE;
427 iotd->iotd_Req.io_Error = td_read(iotd, tdb);
428 tdu->tdu_Busy = FALSE;
429 break;
430 case ETD_UPDATE:
431 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
432 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
433 break;
435 case CMD_UPDATE:
436 tdu->tdu_Busy = TRUE;
437 iotd->iotd_Req.io_Error = td_update(tdu, tdb);
438 tdu->tdu_Busy = FALSE;
439 break;
440 case ETD_WRITE:
441 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
442 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
443 break;
445 case CMD_WRITE:
446 tdu->tdu_Busy = TRUE;
447 iotd->iotd_Req.io_Error = td_write(iotd, tdb);
448 tdu->tdu_Busy = FALSE;
449 break;
450 case TD_ADDCHANGEINT:
451 Forbid();
452 AddTail(&tdu->tdu_Listeners,(struct Node *)iotd);
453 Permit();
454 reply = FALSE;
455 break;
456 case TD_CHANGENUM:
457 iotd->iotd_Req.io_Actual = tdu->pub.tdu_Counter;
458 iotd->iotd_Req.io_Error=0;
459 break;
460 case TD_CHANGESTATE:
461 if ((tdu->pub.tdu_PubFlags & TDPF_NOCLICK) && (tdu->tdu_DiskIn == TDU_NODISK)) {
462 TestInsert(tdb, tdu);
463 if (!tdu->tdu_MotorOn)
464 td_motoroff(tdu->tdu_UnitNum, tdb);
466 if (tdu->tdu_DiskIn == TDU_DISK)
468 /* test if disk is still in there */
469 temp = td_getDiskChange();
470 iotd->iotd_Req.io_Actual = temp;
471 tdu->tdu_DiskIn = temp ^ 1;
473 else
475 /* No disk in drive */
476 iotd->iotd_Req.io_Actual = 1;
478 iotd->iotd_Req.io_Error=0;
479 break;
480 case ETD_FORMAT:
481 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
482 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
483 break;
485 case TD_FORMAT:
486 tdu->tdu_Busy = TRUE;
487 iotd->iotd_Req.io_Error = td_format(iotd,tdb);
488 tdu->tdu_Busy = FALSE;
489 break;
490 case ETD_MOTOR:
491 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
492 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
493 break;
495 case TD_MOTOR:
496 iotd->iotd_Req.io_Error=0;
497 switch (iotd->iotd_Req.io_Length)
499 case 0:
500 tdu->tdu_MotorOn = 0;
501 td_motoroff(tdu->tdu_UnitNum,tdb);
502 break;
503 case 1:
504 tdu->tdu_MotorOn = 1;
505 td_motoron(tdu->tdu_UnitNum,tdb,TRUE);
506 break;
507 default:
508 iotd->iotd_Req.io_Error = TDERR_NotSpecified;
509 break;
511 break;
512 case TD_PROTSTATUS:
513 iotd->iotd_Req.io_Actual = tdu->tdu_ProtStatus;
514 iotd->iotd_Req.io_Error=0;
515 break;
516 case TD_REMCHANGEINT:
517 Forbid();
518 Remove((struct Node *)iotd);
519 Permit();
520 break;
521 case TD_GETGEOMETRY:
522 geo = (struct DriveGeometry *)iotd->iotd_Req.io_Data;
523 geo->dg_SectorSize = 512;
524 geo->dg_TotalSectors = DP_STOTAL;
525 geo->dg_Cylinders = DP_TRACKS;
526 geo->dg_CylSectors = DP_SECTORS*2;
527 geo->dg_Heads = 2;
528 geo->dg_TrackSectors = DP_SECTORS;
529 geo->dg_BufMemType = MEMF_PUBLIC;
530 geo->dg_DeviceType = DG_DIRECT_ACCESS;
531 geo->dg_Flags = DGF_REMOVABLE;
532 iotd->iotd_Req.io_Error=0;
533 break;
534 case TD_GETDRIVETYPE:
535 iotd->iotd_Req.io_Actual = DRIVE3_5;
536 iotd->iotd_Req.io_Error=0;
537 break;
538 case TD_GETNUMTRACKS:
539 iotd->iotd_Req.io_Actual = DP_TRACKS*2;
540 iotd->iotd_Req.io_Error=0;
541 break;
542 case ETD_SEEK:
543 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
544 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
545 break;
547 case TD_SEEK:
548 temp = (iotd->iotd_Req.io_Offset >> 10) / DP_SECTORS;
549 tdu->tdu_MotorOn = 1;
550 iotd->iotd_Req.io_Error = td_recalibrate(tdu->tdu_UnitNum, 0, temp, tdb);
551 break;
552 default:
553 /* Not supported */
554 D(bug("TD: Unknown command received\n"));
555 iotd->iotd_Req.io_Error = IOERR_NOCMD;
556 break;
557 } /* switch(iotd->iotd_Req.io_Command) */
558 return (reply);
561 ULONG TD_InitTask(struct TrackDiskBase *tdb)
563 struct TaskData *t;
564 struct MemList *ml;
565 struct Task *me;
567 /* Allocate Task Data structure */
568 t = AllocMem(sizeof(struct TaskData), MEMF_PUBLIC|MEMF_CLEAR);
569 /* Allocate Stack space */
570 if ((t) && ((t->td_Stack = AllocMem(STACK_SIZE, MEMF_PUBLIC|MEMF_CLEAR)) == NULL))
572 FreeMem(t, sizeof(struct TaskData));
573 t = NULL;
575 /* Allocate MemEntry for this task */
576 ml = (struct MemList *)AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
578 /* Find the current task */
579 me = FindTask(NULL);
581 if (t && ml)
583 D(bug("TD: Creating devicetask..."));
584 /* Save stack info into task structure */
585 t->td_Task.tc_SPLower = t->td_Stack;
586 t->td_Task.tc_SPUpper = (BYTE *)t->td_Stack + STACK_SIZE;
587 t->td_Task.tc_SPReg = (BYTE *)t->td_Task.tc_SPUpper - SP_OFFSET - sizeof(APTR);
589 /* Init MsgPort */
590 NEWLIST(&t->td_Port.mp_MsgList);
591 t->td_Port.mp_Node.ln_Type = NT_MSGPORT;
592 t->td_Port.mp_Flags = PA_SIGNAL;
593 t->td_Port.mp_SigBit = SIGBREAKB_CTRL_F;
594 t->td_Port.mp_SigTask = &t->td_Task;
595 t->td_Port.mp_Node.ln_Name = "trackdisk.device";
597 /* Init MemList */
598 ml->ml_NumEntries = 1;
599 ml->ml_ME[0].me_Addr = t;
600 ml->ml_ME[0].me_Length = sizeof(struct TaskData);
601 NEWLIST(&t->td_Task.tc_MemEntry);
602 AddHead(&t->td_Task.tc_MemEntry, &ml->ml_Node);
604 /* Init Task structure */
605 t->td_Task.tc_Node.ln_Name = "trackdisk.task";
606 t->td_Task.tc_Node.ln_Type = NT_TASK;
607 t->td_Task.tc_Node.ln_Pri = 5;
608 t->td_Task.tc_UserData = me;
610 tdb->td_TaskData = t;
612 struct TagItem task_Tags[] = {
613 { TASKTAG_ARG1, tdb },
614 { TAG_DONE, 0 },
616 /* Add task to system task list */
617 NewAddTask(&t->td_Task, &TD_DevTask, NULL, task_Tags );
619 /* Wait until started */
620 Wait(SIGBREAKF_CTRL_F);
622 D(bug(" OK\n"));
624 return 1;
626 else
628 if (t)
630 if (t->td_Stack) FreeMem(t->td_Stack, STACK_SIZE);
631 FreeMem(t, sizeof(struct TaskData));
633 if (ml) FreeMem(ml, sizeof(struct MemList));
636 return 0;
639 static void TD_DevTask(struct TrackDiskBase *tdb)
641 struct TaskData *td;
642 struct IOExtTD *iotd;
643 struct TDU *tdu;
644 ULONG tasig,tisig,sigs,i;
645 UBYTE dir;
647 D(bug("[TDTask] TD_DevTask(tdb=%p)\n", tdb));
649 td = tdb->td_TaskData;
651 D(bug("[TDTask] TD_DevTask: struct TaskData @ %p\n", td));
653 tdb->td_IntBit = AllocSignal(-1);
654 tdb->td_TmoBit = AllocSignal(-1);
655 tdb->td_TimerMP = CreateMsgPort();
656 tdb->td_TimerIO = (struct timerequest *) CreateIORequest(tdb->td_TimerMP, sizeof(struct timerequest));
657 OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tdb->td_TimerIO, 0);
659 /* Initialize FDC */
660 td_dinit(tdb);
662 /* Initial check for floppies */
663 for (i=0;i<TD_NUMUNITS;i++)
665 if(tdb->td_Units[i])
667 td_rseek(i, 0, 1, tdb);
668 tdb->td_Units[i]->tdu_Present = !td_recalibrate(tdb->td_Units[i]->tdu_UnitNum,1,0,tdb);
669 tdb->td_Units[i]->pub.tdu_CurrTrk = 0;
670 tdb->td_Units[i]->tdu_DiskIn = (td_getDiskChange() ^ 1);
671 tdb->td_Units[i]->tdu_ProtStatus = td_getprotstatus(i,tdb);
672 tdb->td_Units[i]->tdu_Busy = FALSE;
673 tdb->td_Units[i]->tdu_stepdir = 0;
674 if (((tdb->td_Units[i]->pub.tdu_PubFlags & TDPF_NOCLICK) && (tdb->td_Units[i]->tdu_DiskIn == TDU_NODISK))
675 || (!tdb->td_Units[i]->tdu_Present))
676 td_motoroff(i, tdb);
677 D(bug("Drive %d presence: %ld\n", i, tdb->td_Units[i]->tdu_Present));
681 tasig = 1L << td->td_Port.mp_SigBit;
682 tisig = 1L << tdb->td_TimerMP->mp_SigBit;
684 /* Reply to startup message */
685 Signal(td->td_Task.tc_UserData,SIGBREAKF_CTRL_F);
687 tdb->td_TimerIO->tr_node.io_Command = TR_ADDREQUEST;
688 tdb->td_TimerIO->tr_time.tv_secs = 2;
689 tdb->td_TimerIO->tr_time.tv_micro = 500000;
690 SendIO((struct IORequest *)tdb->td_TimerIO);
692 /* Endless task loop */
693 for(;;)
695 sigs = 0L;
696 sigs = Wait(tasig | tisig); /* Wait for a message */
697 /* If unit was not active process message */
698 if (sigs & tasig)
700 /* We received a message. Deal with it */
701 while((iotd = (struct IOExtTD *)GetMsg(&td->td_Port)) != NULL)
703 /* Execute command */
704 if (TD_PerformIO( iotd, tdb))
706 /* Finish message */
707 ReplyMsg((struct Message *)iotd);
711 if (sigs & tisig)
713 /* We were woken up by the timer. */
714 WaitIO((struct IORequest *)tdb->td_TimerIO);
715 for(i=0;i<TD_NUMUNITS;i++)
717 /* If there is no floppy in drive, scan for changes */
718 if (tdb->td_Units[i])
720 tdu = tdb->td_Units[i];
721 switch (tdu->tdu_DiskIn)
723 case TDU_NODISK:
725 Unfortunately "NoClick" technology which works on Amiga will not
726 work on PC because i82077 does not send step pulse when told to
727 seek to "-1" track and the drive can't recognize disk insertion.
728 Many thanks to Intel! :-(((
730 Here we use another technique: in NoClick mode we just do nothing
731 if the disk is not in drive. We can perform this test only once
732 inside TD_CHANGESTATE command which is invoked by DISKCHANGE
733 CLI command. This means that we'll have to issue DISKCHANGE command
734 manually after wi insert the disk, but this is probably better
735 than those clicks.
737 if (tdu->pub.tdu_PubFlags & TDPF_NOCLICK) {
738 if (!tdu->tdu_MotorOn)
739 td_motoroff(tdu->tdu_UnitNum, tdb);
740 } else
741 TestInsert(tdb, tdu);
742 break;
743 case TDU_DISK:
745 Fortunately this part is completely silent so we don't have to
746 do any extra mess here
748 if (!tdu->tdu_Busy)
750 if (!tdu->tdu_MotorOn)
751 td_motoron(tdu->tdu_UnitNum,tdb,FALSE);
752 dir = (inb(FDC_DIR)>>7);
753 if (!tdu->tdu_MotorOn)
754 td_motoroff(tdu->tdu_UnitNum,tdb);
755 if (dir == 1)
757 D(bug("[Floppy] Removal detected\n"));
758 /* Go to cylinder 0 */
759 td_recalibrate(tdu->tdu_UnitNum,1,0,tdb);
760 tdu->tdu_DiskIn = TDU_NODISK;
761 tdu->pub.tdu_Counter++;
762 Forbid();
763 ForeachNode(&tdu->tdu_Listeners,iotd)
765 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
767 Permit();
768 tdu->tdu_stepdir = 0;
771 break;
776 /* Reload the timer again */
777 GetMsg(tdb->td_TimerMP);
778 tdb->td_TimerIO->tr_node.io_Command = TR_ADDREQUEST;
779 tdb->td_TimerIO->tr_time.tv_secs = 2;
780 tdb->td_TimerIO->tr_time.tv_micro = 500000;
781 SendIO((struct IORequest *)tdb->td_TimerIO);
786 #define TDBase ((struct TrackDiskBase *)irq->h_Data)
787 void td_floppytimer(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
789 // Does anyone wait for io?
790 if (TDBase->td_inttmo)
792 // Decrease timeout
793 TDBase->td_inttmo--;
794 // timeout?
795 if (!TDBase->td_inttmo)
797 Signal(&TDBase->td_TaskData->td_Task,(1L << TDBase->td_TmoBit));
802 void td_floppyint(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
804 Signal(&TDBase->td_TaskData->td_Task,(1L << TDBase->td_IntBit));