Fixed compatibility of output.
[AROS.git] / arch / m68k-amiga / devs / trackdisk / trackdisk_device.c
blob214db8908cf0aa20e7290c1e978fbb3d432fe297
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 #define DEBUG 0
10 #include <aros/debug.h>
12 #include <devices/trackdisk.h>
13 #include <exec/resident.h>
14 #include <exec/errors.h>
15 #include <exec/memory.h>
16 #include <exec/lists.h>
17 #include <exec/alerts.h>
18 #include <exec/tasks.h>
19 #include <exec/interrupts.h>
20 #include <clib/alib_protos.h>
21 #include <aros/symbolsets.h>
23 #include <dos/filehandler.h>
24 #include <libraries/expansion.h>
25 #include <libraries/expansionbase.h>
27 #include <proto/exec.h>
28 #include <proto/disk.h>
29 #include <proto/expansion.h>
31 #include <hardware/custom.h>
32 #include <hardware/cia.h>
34 #include <resources/disk.h>
36 #include "trackdisk_device.h"
37 #include "trackdisk_hw.h"
39 #include LC_LIBDEFS_FILE
41 static BOOL ishd(ULONG id)
43 return id == DRT_150RPM;
46 static UBYTE getsectors(struct TDU *tdu)
48 BYTE hdmult = tdu->tdu_hddisk ? 2 : 1;
49 if (tdu->tdu_disktype == DT_UNDETECTED)
50 return 11 * hdmult;
51 return tdu->tdu_sectors;
54 static void getunit(struct TrackDiskBase *tdb)
56 struct DiskBase *DiskBase = tdb->td_DiskBase;
57 while (GetUnit(&tdb->td_dru) == NULL) {
58 WaitPort (&tdb->td_druport);
61 static void giveunit(struct TrackDiskBase *tdb)
63 struct DiskBase *DiskBase = tdb->td_DiskBase;
64 GiveUnit();
67 static AROS_INTH1(disk_block_interrupt, struct TrackDiskBase *, tdb)
69 AROS_INTFUNC_INIT
71 Signal (tdb->td_task, 1L << tdb->td_IntBit);
72 return 0;
74 AROS_INTFUNC_EXIT
77 static void TestInsert(struct TrackDiskBase *tdb, struct TDU *tdu, BOOL dostep)
79 struct IOExtTD *iotd;
81 if (dostep) {
82 if (tdu->pub.tdu_PubFlags & TDPF_NOCLICK) {
83 td_seek(tdu, -1, 0, tdb);
84 } else {
85 // step towards cyl 0 if > 0, if not, step to cyl 1
86 td_seek(tdu, tdu->pub.tdu_CurrTrk >= 2 ? (tdu->pub.tdu_CurrTrk - 2) / 2 : 1, 0, tdb);
89 if (td_getDiskChange (tdu, tdb)) {
90 struct DiskBase *DiskBase = tdb->td_DiskBase;
91 D(bug("[Floppy] Insertion detected\n"));
92 td_recalibrate(tdu, tdb);
93 tdu->tdu_hddisk = ishd(ReadUnitID(tdu->tdu_UnitNum));
94 td_detectformat(tdu, tdb);
95 tdu->tdu_DiskIn = TDU_DISK;
96 tdu->pub.tdu_Counter++;
97 tdu->tdu_ProtStatus = td_getprotstatus(tdu,tdb);
98 Forbid();
99 ForeachNode(&tdu->tdu_Listeners,iotd) {
100 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
102 Permit();
106 static BOOL TD_PerformIO(struct IOExtTD *iotd, struct TrackDiskBase *tdb)
108 struct TDU *tdu = (struct TDU *)iotd->iotd_Req.io_Unit;
109 struct DriveGeometry *geo;
110 UBYTE temp;
111 BOOL reply;
113 D(bug("TD%d PerformIO cmd=%d\n", tdu->tdu_UnitNum, iotd->iotd_Req.io_Command));
115 getunit(tdb);
116 reply = TRUE;
117 switch(iotd->iotd_Req.io_Command)
119 case ETD_CLEAR:
120 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
121 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
122 break;
124 case CMD_CLEAR:
125 td_flush(tdu, tdb);
126 td_clear(tdb);
127 tdu->tdu_flags = 0;
128 iotd->iotd_Req.io_Error = 0;
129 break;
130 case ETD_READ:
131 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
132 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
133 break;
135 case CMD_READ:
136 iotd->iotd_Req.io_Error = td_read(iotd, tdu, tdb);
137 break;
138 case ETD_UPDATE:
139 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
140 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
141 break;
143 case CMD_UPDATE:
144 iotd->iotd_Req.io_Error = td_flush(tdu, tdb);
145 break;
146 case ETD_WRITE:
147 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
148 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
149 break;
151 case CMD_WRITE:
152 iotd->iotd_Req.io_Error = td_write(iotd, tdu, tdb);
153 break;
154 case TD_ADDCHANGEINT:
155 Forbid();
156 AddTail(&tdu->tdu_Listeners,(struct Node *)iotd);
157 Permit();
158 reply = FALSE;
159 break;
160 case TD_CHANGENUM:
161 iotd->iotd_Req.io_Actual = tdu->pub.tdu_Counter;
162 iotd->iotd_Req.io_Error=0;
163 break;
164 case TD_CHANGESTATE:
165 td_select(tdu, tdb);
166 if (tdu->tdu_DiskIn == TDU_NODISK)
167 TestInsert(tdb, tdu, FALSE);
168 if (tdu->tdu_DiskIn == TDU_DISK) {
169 /* test if disk is still in there */
170 temp = td_getDiskChange(tdu, tdb);
171 iotd->iotd_Req.io_Actual = temp ? 0 : 1;
172 tdu->tdu_DiskIn = temp ? TDU_DISK : TDU_NODISK;
173 } else {
174 /* No disk in drive */
175 iotd->iotd_Req.io_Actual = 1;
177 D(bug("TD%d_CHANGESTATE=%d\n", tdu->tdu_UnitNum, iotd->iotd_Req.io_Actual));
178 iotd->iotd_Req.io_Error=0;
179 break;
180 case ETD_FORMAT:
181 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
182 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
183 break;
185 case TD_FORMAT:
186 iotd->iotd_Req.io_Error = td_format(iotd, tdu, tdb);
187 break;
188 case ETD_MOTOR:
189 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
190 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
191 break;
193 case TD_MOTOR:
194 iotd->iotd_Req.io_Error=0;
195 switch (iotd->iotd_Req.io_Length)
197 case 0:
198 td_select(tdu, tdb);
199 td_flush(tdu, tdb);
200 td_motoroff(tdu, tdb);
201 break;
202 case 1:
203 td_select(tdu, tdb);
204 td_motoron(tdu, tdb, TRUE);
205 break;
206 default:
207 iotd->iotd_Req.io_Error = TDERR_NotSpecified;
208 break;
210 break;
211 case TD_PROTSTATUS:
212 iotd->iotd_Req.io_Actual = tdu->tdu_ProtStatus;
213 iotd->iotd_Req.io_Error=0;
214 break;
215 case TD_REMCHANGEINT:
216 Forbid();
217 Remove((struct Node *)iotd);
218 Permit();
219 break;
220 case TD_GETGEOMETRY:
222 BYTE sectors = getsectors(tdu);
223 geo = (struct DriveGeometry *)iotd->iotd_Req.io_Data;
224 geo->dg_SectorSize = 512;
225 geo->dg_Cylinders = 80;
226 geo->dg_CylSectors = sectors * 2;
227 geo->dg_Heads = 2;
228 geo->dg_TrackSectors = sectors;
229 geo->dg_CylSectors = geo->dg_TrackSectors * geo->dg_Heads;
230 geo->dg_TotalSectors = geo->dg_CylSectors * geo->dg_Cylinders;
231 geo->dg_BufMemType = MEMF_PUBLIC;
232 geo->dg_DeviceType = DG_DIRECT_ACCESS;
233 geo->dg_Flags = DGF_REMOVABLE;
234 iotd->iotd_Req.io_Error=0;
236 break;
237 case TD_GETDRIVETYPE:
238 iotd->iotd_Req.io_Actual = tdu->tdu_hddisk ? DRIVE3_5_150RPM : DRIVE3_5;
239 iotd->iotd_Req.io_Error = 0;
240 break;
241 case TD_GETNUMTRACKS:
242 iotd->iotd_Req.io_Actual = 80 * 2;
243 iotd->iotd_Req.io_Error = 0;
244 break;
245 case ETD_SEEK:
246 if (iotd->iotd_Count > tdu->pub.tdu_Counter) {
247 iotd->iotd_Req.io_Error = TDERR_DiskChanged;
248 break;
250 case TD_SEEK:
252 BYTE sectors = getsectors(tdu);
253 td_select(tdu, tdb);
254 temp = (iotd->iotd_Req.io_Offset >> 10) / sectors;
255 iotd->iotd_Req.io_Error = td_seek(tdu, temp >> 1, temp & 1, tdb);
257 break;
258 default:
259 /* Not supported */
260 D(bug("TD: Unknown command received\n"));
261 iotd->iotd_Req.io_Error = IOERR_NOCMD;
262 break;
263 } /* switch(iotd->iotd_Req.io_Command) */
264 td_deselect(tdu, tdb);
265 giveunit(tdb);
266 return reply;
269 AROS_LH1(void, beginio,
270 AROS_LHA(struct IOExtTD *, iotd, A1),
271 struct TrackDiskBase *, TDBase, 5, TrackDisk)
273 AROS_LIBFUNC_INIT
275 iotd->iotd_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
276 if (iotd->iotd_Req.io_Flags & IOF_QUICK) {
277 switch(iotd->iotd_Req.io_Command)
279 case TD_GETNUMTRACKS:
280 case TD_GETDRIVETYPE:
281 case TD_GETGEOMETRY:
282 case TD_REMCHANGEINT:
283 case TD_ADDCHANGEINT:
284 case TD_PROTSTATUS:
285 case TD_CHANGENUM:
286 TD_PerformIO(iotd,TDBase);
287 return;
290 /* Not done quick */
291 iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
292 /* Forward to devicetask */
293 PutMsg(&TDBase->td_Port, &iotd->iotd_Req.io_Message);
295 AROS_LIBFUNC_EXIT
298 AROS_LH1(LONG, abortio,
299 AROS_LHA(struct IOExtTD *, iotd, A1),
300 struct TrackDiskBase *, TDBase, 6, TrackDisk)
302 AROS_LIBFUNC_INIT
304 return IOERR_NOCMD;
306 AROS_LIBFUNC_EXIT
309 static void TD_DevTask(struct Task *parent, struct TrackDiskBase *tdb)
311 struct Task *me;
312 struct IOExtTD *iotd;
313 struct TDU *tdu;
314 ULONG tasig,tisig,sigs,i;
315 struct Interrupt *inter;
316 struct DiskBase *DiskBase = tdb->td_DiskBase;
318 D(bug("[TDTask] TD_DevTask(tdb=%p)\n", tdb));
320 me = FindTask(0);
322 /* Init MsgPort */
323 NEWLIST(&tdb->td_Port.mp_MsgList);
324 tdb->td_Port.mp_Node.ln_Type = NT_MSGPORT;
325 tdb->td_Port.mp_Flags = PA_SIGNAL;
326 tdb->td_Port.mp_SigBit = SIGBREAKB_CTRL_F;
327 tdb->td_Port.mp_SigTask = me;
328 tdb->td_Port.mp_Node.ln_Name = "trackdisk.device";
330 D(bug("[TDTask] TD_DevTask: struct TaskData @ %p\n", td));
332 tdb->td_IntBit = AllocSignal(-1);
333 tdb->td_TimerMP = CreateMsgPort();
334 tdb->td_TimerMP2 = CreateMsgPort();
335 tdb->td_TimerIO = (struct timerequest *) CreateIORequest(tdb->td_TimerMP, sizeof(struct timerequest));
336 tdb->td_TimerIO2 = (struct timerequest *) CreateIORequest(tdb->td_TimerMP2, sizeof(struct timerequest));
337 if (tdb->td_IntBit == -1)
338 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_NoSignal);
339 if (!tdb->td_TimerMP || !tdb->td_TimerMP2 || !tdb->td_TimerIO || !tdb->td_TimerIO2)
340 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_NoMemory);
341 if (OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tdb->td_TimerIO, 0))
342 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_OpenDev);
343 if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *)tdb->td_TimerIO2, 0))
344 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_OpenDev);
347 NEWLIST(&tdb->td_druport.mp_MsgList);
348 tdb->td_dru.dru_Message.mn_ReplyPort = &tdb->td_druport;
349 tdb->td_druport.mp_SigBit = AllocSignal(-1);
350 tdb->td_task = me;
351 tdb->td_druport.mp_SigTask = tdb->td_task;
353 inter = &tdb->td_dru.dru_DiscBlock;
354 inter->is_Node.ln_Pri = 0;
355 inter->is_Node.ln_Type = NT_INTERRUPT;
356 inter->is_Node.ln_Name = "trackdisk.device disk dma done";
357 inter->is_Code = (APTR)disk_block_interrupt;
358 inter->is_Data = tdb;
360 tdb->td_buffer_unit = -1;
361 tdb->td_buffer_track = -1;
363 /* Initial check for floppies */
364 for (i = 0; i < TD_NUMUNITS; i++) {
365 struct TDU *tdu = tdb->td_Units[i];
366 if (tdu) {
367 getunit(tdb);
368 td_select(tdu, tdb);
369 td_motoroff(tdu, tdb);
370 tdu->tdu_broken = td_recalibrate(tdu, tdb) == 0;
371 if (tdu->tdu_broken)
372 bug("DF%d failed to recalibrate!?\n", i);
373 else
374 D(bug("DF%d initialized\n", i));
375 tdu->tdu_DiskIn = td_getDiskChange(tdu, tdb) ? TDU_DISK : TDU_NODISK;
376 tdu->tdu_ProtStatus = td_getprotstatus(tdu,tdb);
377 tdu->tdu_hddisk = ishd(GetUnitID(i));
378 tdu->tdu_sectors = tdu->tdu_hddisk ? 22 : 11;
379 tdu->tdu_disktype = DT_UNDETECTED;
380 td_deselect(tdu, tdb);
381 giveunit(tdb);
385 tasig = 1L << tdb->td_Port.mp_SigBit;
386 tisig = 1L << tdb->td_TimerMP->mp_SigBit;
388 /* Reply to startup message */
389 Signal(parent, SIGBREAKF_CTRL_F);
391 tdb->td_TimerIO->tr_node.io_Command = TR_ADDREQUEST;
392 tdb->td_TimerIO->tr_time.tv_secs = 2;
393 tdb->td_TimerIO->tr_time.tv_micro = 500000;
394 SendIO((struct IORequest *)tdb->td_TimerIO);
396 /* Endless task loop */
397 for(;;)
399 sigs = 0L;
400 sigs = Wait(tasig | tisig); /* Wait for a message */
401 /* If unit was not active process message */
402 if (sigs & tasig) {
403 /* We received a message. Deal with it */
404 while((iotd = (struct IOExtTD *)GetMsg(&tdb->td_Port)) != NULL) {
405 /* Execute command */
406 if (TD_PerformIO(iotd, tdb)) {
407 /* Finish message */
408 ReplyMsg((struct Message *)iotd);
412 if (sigs & tisig)
414 /* We were woken up by the timer. */
415 WaitIO((struct IORequest *)tdb->td_TimerIO);
416 for(i = 0; i < TD_NUMUNITS; i++) {
417 tdu = tdb->td_Units[i];
418 /* If there is no floppy in drive, scan for changes */
419 if (tdu && !tdu->tdu_broken) {
420 getunit(tdb);
421 td_select(tdu, tdb);
422 switch (tdu->tdu_DiskIn)
424 case TDU_NODISK:
425 TestInsert(tdb, tdu, TRUE);
426 break;
427 case TDU_DISK:
428 if (td_getDiskChange(tdu, tdb) == 0) {
429 D(bug("[Floppy] Removal detected\n"));
430 /* Go to cylinder 0 */
431 td_motoroff(tdu, tdb);
432 td_recalibrate(tdu, tdb);
433 tdu->tdu_DiskIn = TDU_NODISK;
434 tdu->tdu_sectors = 11;
435 tdu->tdu_hddisk = 0;
436 tdu->tdu_disktype = DT_UNDETECTED;
437 tdu->pub.tdu_Counter++;
438 if (tdu->tdu_UnitNum == tdb->td_buffer_unit)
439 td_clear(tdb);
440 Forbid();
441 ForeachNode(&tdu->tdu_Listeners,iotd) {
442 Cause((struct Interrupt *)((struct IOExtTD *)iotd->iotd_Req.io_Data));
444 Permit();
445 } else {
446 td_flush(tdu, tdb);
448 break;
450 td_deselect(tdu, tdb);
451 giveunit(tdb);
455 /* Reload the timer again */
456 GetMsg(tdb->td_TimerMP);
457 tdb->td_TimerIO->tr_node.io_Command = TR_ADDREQUEST;
458 tdb->td_TimerIO->tr_time.tv_secs = 2;
459 tdb->td_TimerIO->tr_time.tv_micro = 500000;
460 SendIO((struct IORequest *)tdb->td_TimerIO);
465 ULONG TD_InitTask(struct TrackDiskBase *tdb)
467 struct Task *t;
469 D(bug("TD: Creating devicetask...\n"));
471 t = NewCreateTask(
472 TASKTAG_PC, TD_DevTask,
473 TASKTAG_NAME, "trackdisk.device",
474 TASKTAG_PRI, 5,
475 TASKTAG_ARG1, FindTask(0),
476 TASKTAG_ARG2, tdb,
477 TAG_DONE);
478 if (t) {
479 /* Wait until started */
480 Wait(SIGBREAKF_CTRL_F);
482 D(bug("done\n"));
484 return 1;
487 D(bug("failed\n"));
489 return 0;
493 struct TDU *TD_InitUnit(ULONG num, struct TrackDiskBase *tdb)
495 struct TDU *unit;
496 struct DiskBase *DiskBase = tdb->td_DiskBase;
498 if (AllocUnit(num) == 0)
499 return NULL;
501 /* Try to get memory for structure */
502 unit = AllocMem(sizeof(struct TDU), MEMF_PUBLIC | MEMF_CLEAR);
504 if (unit) {
505 unit->tdu_DiskIn = TDU_NODISK; /* Assume there is no floppy in there */
506 unit->pub.tdu_StepDelay = 3; /* Standard values here */
507 unit->pub.tdu_SettleDelay = 15;
508 unit->pub.tdu_RetryCnt = 3;
509 unit->pub.tdu_CalibrateDelay = 3;
510 unit->tdu_UnitNum = num;
511 NEWLIST(&unit->tdu_Listeners);
513 /* Store the unit in TDBase */
514 tdb->td_Units[num] = unit;
516 return unit;
520 * Create BootNodes for all 4 possible devices
522 static void TD_BootNode(
523 struct ExpansionBase *ExpansionBase,
524 ULONG unit, ULONG id)
526 TEXT dosdevname[4] = "DF0";
527 IPTR pp[4 + DE_BOOTBLOCKS + 1] = {};
528 struct DeviceNode *devnode;
529 BOOL hddisk = ishd(id);
531 dosdevname[2] += unit;
532 D(bug("trackdisk.device: Adding bootnode %s: DDHD=%d\n", dosdevname, hddisk ? 1 : 0));
534 pp[0] = (IPTR)dosdevname;
535 pp[1] = (IPTR)"trackdisk.device";
536 pp[2] = unit;
537 pp[DE_TABLESIZE + 4] = DE_BOOTBLOCKS;
538 pp[DE_SIZEBLOCK + 4] = 128;
539 pp[DE_NUMHEADS + 4] = 2;
540 pp[DE_SECSPERBLOCK + 4] = 1;
541 pp[DE_BLKSPERTRACK + 4] = hddisk ? 22 : 11;
542 pp[DE_RESERVEDBLKS + 4] = 2;
543 pp[DE_LOWCYL + 4] = 0;
544 pp[DE_HIGHCYL + 4] = 79;
545 pp[DE_NUMBUFFERS + 4] = 10;
546 pp[DE_BUFMEMTYPE + 4] = MEMF_PUBLIC;
547 pp[DE_MAXTRANSFER + 4] = 0x00200000;
548 pp[DE_MASK + 4] = 0x7FFFFFFE;
549 pp[DE_BOOTPRI + 4] = 5 - (unit * 10);
550 pp[DE_DOSTYPE + 4] = 0;
551 pp[DE_BOOTBLOCKS + 4] = 2;
552 devnode = MakeDosNode(pp);
554 if (devnode)
555 AddBootNode(pp[DE_BOOTPRI + 4], 0, devnode, NULL);
557 static int GM_UNIQUENAME(init)(LIBBASETYPEPTR TDBase)
559 ULONG i;
560 UBYTE drives;
561 struct DiskBase *DiskBase;
562 struct ExpansionBase *ExpansionBase;
563 ULONG ids[TD_NUMUNITS];
565 D(bug("TD: Init\n"));
567 TDBase->td_supportHD = 0;
568 DiskBase = OpenResource("disk.resource");
569 if (!DiskBase)
570 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_OpenRes);
572 TDBase->td_DiskBase = DiskBase;
573 TDBase->ciaa = (struct CIA*)0xbfe001;
574 TDBase->ciab = (struct CIA*)0xbfd000;
575 TDBase->custom = (struct Custom*)0xdff000;
577 drives = 0;
578 for (i = 0; i < TD_NUMUNITS; i++) {
579 ids[i] = GetUnitID(i);
580 if (ids[i] != DRT_EMPTY)
581 drives++;
584 if (drives == 0) {
585 /* No drives here. abort */
586 D(bug("TD: No drives\n"));
587 return FALSE;
590 ExpansionBase = (struct ExpansionBase *)TaggedOpenLibrary(TAGGEDOPEN_EXPANSION);
591 if (!ExpansionBase)
592 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_OpenLib);
594 /* Alloc memory for track buffering, DD buffer only, reallocated
595 * later if HD disk detected to save RAM on unexpanded machines */
596 TDBase->td_DMABuffer = AllocMem(DISK_BUFFERSIZE, MEMF_CHIP);
597 TDBase->td_DataBuffer = AllocMem(11 * 512, MEMF_ANY);
598 if (!TDBase->td_DMABuffer || !TDBase->td_DataBuffer)
599 Alert(AT_DeadEnd | AO_TrackDiskDev | AG_NoMemory);
601 for (i = 0; i < TD_NUMUNITS; i++) {
602 TDBase->td_Units[i] = NULL;
603 if (ids[i] != DRT_EMPTY)
604 TD_InitUnit(i, TDBase);
605 D(bug("TD%d id=%08x status=%d\n", i, id, TDBase->td_Units[i] ? 1 : 0));
608 /* Create the message processor task */
609 TD_InitTask(TDBase);
611 /* Only add bootnode if recalibration succeeded */
612 for (i = 0; i < TD_NUMUNITS; i++) {
613 if (TDBase->td_Units[i] && !TDBase->td_Units[i]->tdu_broken)
614 TD_BootNode(ExpansionBase, i, ids[i]);
617 CloseLibrary((struct Library *)ExpansionBase);
619 D(bug("TD: done %d\n", drives));
621 return TRUE;
624 static int GM_UNIQUENAME(open)
626 LIBBASETYPEPTR TDBase,
627 struct IOExtTD *iotd,
628 ULONG unitnum,
629 ULONG flags
632 iotd->iotd_Req.io_Error = IOERR_OPENFAIL;
634 /* Is the requested unitNumber valid? */
635 if (unitnum < TD_NUMUNITS) {
636 struct TDU *unit;
638 iotd->iotd_Req.io_Device = (struct Device *)TDBase;
640 /* Get TDU structure */
641 unit = TDBase->td_Units[unitnum];
642 if (unit && !unit->tdu_broken) {
643 iotd->iotd_Req.io_Unit = (struct Unit *)unit;
644 ((struct Unit *)unit)->unit_OpenCnt++;
645 iotd->iotd_Req.io_Error = 0;
648 D(bug("TD%d: Open=%d\n", unitnum, iotd->iotd_Req.io_Error));
650 return iotd->iotd_Req.io_Error == 0;
654 static int GM_UNIQUENAME(close)
656 LIBBASETYPEPTR TDBase,
657 struct IOExtTD *iotd
660 iotd->iotd_Req.io_Unit->unit_OpenCnt --;
662 return TRUE;
665 ADD2INITLIB(GM_UNIQUENAME(init), 0)
666 ADD2OPENDEV(GM_UNIQUENAME(open), 0)
667 ADD2CLOSEDEV(GM_UNIQUENAME(close), 0)