added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / devs / afs / os_aros_support.c
blob81bbbd63db8ee5d7e96d5d4dbcbd25db0577aa48
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #ifndef DEBUG
7 #define DEBUG 0
8 #endif
10 #include <exec/types.h>
11 #include <devices/input.h>
12 #include <devices/newstyle.h>
13 #include <devices/trackdisk.h>
14 #include <exec/errors.h>
15 #include <exec/io.h>
16 #include <hardware/custom.h>
17 #include <hardware/intbits.h>
18 #include <intuition/intuition.h>
20 #include "os.h"
21 #include "afsblocks.h"
22 #include "error.h"
23 #include "extstrings.h"
24 #include "volumes.h"
25 #include "baseredef.h"
28 * XXX Notes about SendEvent() and LockDosList()
30 * InstallAROS has been hanging during format. Georg figured out why, see here
31 * for the details:
33 * https://mail.aros.org/mailman/prvate/aros-dev/2007-June/050263.html
35 * The quick-and-dirty fix is to remove calls to SendEvent(). This does mean
36 * that Wanderer doesn't get diskchange updates and so doesn't refresh the
37 * volume list, but it avoids the hang.
39 * The correct way to fix is it to call AttemptLockDosList() when
40 * adding/removing the device node. If the list lock can't be obtained right
41 * now, the handler should schedule a retry. fat.handler has a good example of
42 * how to do this.
44 * --rob 2007-06-18
47 // copy pasted from fat.handler,
48 // pushes an IECLASS event in the input stream.
49 static void SendEvent(struct AFSBase *afsbase, LONG event) {
50 struct IOStdReq *InputRequest;
51 struct MsgPort *InputPort;
52 struct InputEvent *ie;
53 if ((InputPort = (struct MsgPort*)CreateMsgPort())) {
55 if ((InputRequest = (struct IOStdReq*)CreateIORequest(InputPort, sizeof(struct IOStdReq)))) {
57 if (!OpenDevice("input.device", 0, (struct IORequest*)InputRequest, 0)) {
59 if ((ie = AllocVec(sizeof(struct InputEvent), MEMF_PUBLIC|MEMF_CLEAR))) {
60 ie->ie_Class = event;
61 InputRequest->io_Command = IND_WRITEEVENT;
62 InputRequest->io_Data = ie;
63 InputRequest->io_Length = sizeof(struct InputEvent);
65 DoIO((struct IORequest*)InputRequest);
67 FreeVec(ie);
69 CloseDevice((struct IORequest*)InputRequest);
71 DeleteIORequest ((APTR)InputRequest);
73 DeleteMsgPort (InputPort);
77 /************************** DOS ******************************************/
78 /*******************************************
79 Name : initDeviceList
80 Descr.: initializes a devicelist structure
81 Input : devicelist - devicelist structure to initialize
82 rootblock - cacheblock of the rootblock
83 Output: DOSTRUE for success; DOSFALSE otherwise
84 ********************************************/
85 LONG initDeviceList
87 struct AFSBase *afsbase,
88 struct Volume *volume,
89 struct BlockCache *rootblock
92 STRPTR name;
93 BSTR newname;
94 UBYTE i;
96 name=(char *)rootblock->buffer+(BLK_DISKNAME_START(volume)*4);
97 volume->devicelist.dl_Next = 0;
98 volume->devicelist.dl_Type = DLT_VOLUME;
99 volume->devicelist.dl_Ext.dl_AROS.dl_Device = volume->device;
100 volume->devicelist.dl_Lock = 0;
101 volume->devicelist.dl_VolumeDate.ds_Days =
102 AROS_BE2LONG(rootblock->buffer[BLK_ROOT_DAYS(volume)]);
103 volume->devicelist.dl_VolumeDate.ds_Minute =
104 AROS_BE2LONG(rootblock->buffer[BLK_ROOT_MINS(volume)]);
105 volume->devicelist.dl_VolumeDate.ds_Tick =
106 AROS_BE2LONG(rootblock->buffer[BLK_ROOT_TICKS(volume)]);
107 volume->devicelist.dl_LockList = 0;
108 volume->devicelist.dl_DiskType = volume->dostype;
109 if (volume->devicelist.dl_Name != NULL)
111 newname = volume->devicelist.dl_Name;
113 else
115 newname = (BSTR)AllocVec(32,MEMF_CLEAR | MEMF_PUBLIC);
116 if (newname == (BSTR)NULL)
117 return DOSFALSE;
119 for (i=0; i<name[0]; i++)
120 AROS_BSTR_putchar(newname, i, name[i+1]);
121 AROS_BSTR_setstrlen(newname, name[0]);
122 volume->devicelist.dl_Name = newname;
123 return DOSTRUE;
126 /*******************************************
127 Name : addDosVolume
128 Descr.: adds a new volume to dos
129 Input : volume - volume to add
130 Output: DOSTRUE for success; DOSFALSE otherwise
131 ********************************************/
132 LONG addDosVolume(struct AFSBase *afsbase, struct Volume *volume) {
133 struct DosList *doslist;
134 struct DosList *dl=NULL;
135 char string[32];
136 BSTR bname;
137 UBYTE i;
139 bname = volume->devicelist.dl_Name;
140 for (i=0; i<AROS_BSTR_strlen(bname); i++)
141 string[i] = AROS_BSTR_getchar(bname,i);
142 string[AROS_BSTR_strlen(bname)] = 0;
143 /* is the volume already in the list? */
144 doslist = LockDosList(LDF_WRITE | LDF_VOLUMES);
145 if (doslist != NULL)
147 dl = FindDosEntry(doslist,string,LDF_VOLUMES);
148 if (dl != NULL)
150 if (((struct AfsHandle *)dl->dol_Ext.dol_AROS.dol_Unit)->volume == volume)
152 if (dl->dol_misc.dol_volume.dol_LockList != NULL)
154 volume->locklist = dl->dol_misc.dol_volume.dol_LockList;
157 else
159 dl = NULL;
162 UnLockDosList(LDF_WRITE | LDF_VOLUMES);
164 /* if not create a new doslist */
165 if (dl == NULL)
167 doslist = MakeDosEntry(string,DLT_VOLUME);
168 if (doslist == NULL)
169 return DOSFALSE;
170 doslist->dol_Ext.dol_AROS.dol_Unit = (struct Unit *)&volume->ah;
171 doslist->dol_Ext.dol_AROS.dol_Device = volume->device;
172 doslist->dol_misc.dol_volume.dol_VolumeDate.ds_Days =
173 volume->devicelist.dl_VolumeDate.ds_Days;
174 doslist->dol_misc.dol_volume.dol_VolumeDate.ds_Minute =
175 volume->devicelist.dl_VolumeDate.ds_Minute;
176 doslist->dol_misc.dol_volume.dol_VolumeDate.ds_Tick =
177 volume->devicelist.dl_VolumeDate.ds_Tick;
178 AddDosEntry(doslist);
179 /* if we re-use "volume" clear locklist */
180 volume->locklist = NULL;
182 //SendEvent(afsbase, IECLASS_DISKINSERTED);
183 return DOSTRUE;
186 /*******************************************
187 Name : remDosVolume
188 Descr.: removes a volume added by addDosVolume
189 or if there are some locks active
190 set dol_LockList
191 Input : volume - volume to remove
192 Output: -
193 Note : displays a message if volume couldn't
194 be found in the system
195 ********************************************/
196 void remDosVolume(struct AFSBase *afsbase, struct Volume *volume) {
197 struct DosList *doslist;
198 struct DosList *dl;
199 BSTR bname;
200 char string[32];
201 UBYTE i;
203 //SendEvent(afsbase, IECLASS_DISKREMOVED);
204 if (volume->dostype == 0x444F5300)
206 bname = volume->devicelist.dl_Name;
207 if (bname != NULL)
209 for (i=0; i<AROS_BSTR_strlen(bname); i++)
210 string[i] = AROS_BSTR_getchar(bname,i);
211 string[AROS_BSTR_strlen(bname)] = 0;
212 doslist = LockDosList(LDF_WRITE | LDF_VOLUMES);
213 if (doslist != NULL)
215 dl = FindDosEntry(doslist,string,LDF_VOLUMES);
216 if (dl != NULL)
218 if (volume->locklist != NULL)
220 dl->dol_misc.dol_volume.dol_LockList = volume->locklist;
222 else
224 RemDosEntry(dl);
225 FreeDosEntry(dl);
228 else
229 showText(afsbase, "doslist not in chain");
230 UnLockDosList(LDF_WRITE | LDF_VOLUMES);
236 LONG osMediumInit
237 (struct AFSBase *afsbase, struct Volume *volume, struct BlockCache *block)
240 if (!initDeviceList(afsbase, volume, block))
241 return ERROR_NO_FREE_STORE;
242 if (!addDosVolume(afsbase, volume))
244 showError(afsbase, ERR_DOSENTRY);
245 remDosVolume(afsbase, volume);
246 return ERROR_UNKNOWN;
248 return 0;
251 void osMediumFree(struct AFSBase *afsbase, struct Volume *volume, LONG all) {
252 remDosVolume(afsbase, volume);
253 if (all)
254 if (volume->devicelist.dl_Name != NULL)
255 FreeVec(BADDR(volume->devicelist.dl_Name));
258 /************************** I/O ******************************************/
259 struct IOExtTD *openDevice
261 struct AFSBase *afsbase,
262 struct MsgPort *mp,
263 STRPTR device,
264 ULONG unit,
265 ULONG flags
268 struct IOExtTD *ioreq;
270 ioreq = (struct IOExtTD *)CreateIORequest(mp, sizeof(struct IOExtTD));
271 if (ioreq != NULL)
273 if (OpenDevice(device, unit, (struct IORequest *)ioreq, flags) == 0)
275 return ioreq;
277 else
278 showError(afsbase, ERR_DEVICE, device);
279 DeleteIORequest((struct IORequest *)ioreq);
281 return NULL;
284 void closeDevice(struct AFSBase *afsbase, struct IOExtTD *ioreq) {
285 if (ioreq->iotd_Req.io_Device != NULL)
286 CloseDevice((struct IORequest *)&ioreq->iotd_Req);
287 DeleteIORequest((APTR)ioreq);
290 LONG getGeometry
291 (struct AFSBase *afsbase, struct IOHandle *ioh, struct DriveGeometry *dg)
293 ioh->ioreq->iotd_Req.io_Command = TD_GETGEOMETRY;
294 ioh->ioreq->iotd_Req.io_Data = dg;
295 ioh->ioreq->iotd_Req.io_Length = sizeof(struct DriveGeometry);
296 return DoIO((struct IORequest *)&ioh->ioreq->iotd_Req);
299 VOID changeIntCode(struct IOHandle *, APTR, struct ExecBase *);
301 LONG addChangeInt(struct AFSBase *afsbase, struct IOHandle *ioh) {
303 ioh->mc_int.is_Code = (void(*)())&changeIntCode;
304 ioh->mc_int.is_Data = ioh;
305 ioh->iochangeint->iotd_Req.io_Command = TD_ADDCHANGEINT;
306 ioh->iochangeint->iotd_Req.io_Flags = 0;
307 ioh->iochangeint->iotd_Req.io_Length = sizeof(struct Interrupt);
308 ioh->iochangeint->iotd_Req.io_Data = &ioh->mc_int;
309 ioh->iochangeint->iotd_Req.io_Error = 0;
310 SendIO((struct IORequest *)&ioh->iochangeint->iotd_Req);
311 return ioh->iochangeint->iotd_Req.io_Error;
314 void remChangeInt(struct AFSBase *afsbase, struct IOHandle *ioh) {
316 if (
317 (ioh->iochangeint != NULL) &&
318 (ioh->iochangeint->iotd_Req.io_Error == 0)
321 ioh->iochangeint->iotd_Req.io_Command = TD_REMCHANGEINT;
322 DoIO((struct IORequest *)&ioh->iochangeint->iotd_Req);
326 void checkAddChangeInt(struct AFSBase *afsbase, struct IOHandle *ioh) {
327 struct DriveGeometry dg;
329 if (!getGeometry(afsbase, ioh, &dg))
331 if (dg.dg_Flags & DGF_REMOVABLE)
333 ioh->iochangeint = openDevice
334 (afsbase, ioh->mp, ioh->blockdevice, ioh->unit, ioh->flags);
335 if (ioh->iochangeint != NULL)
337 addChangeInt(afsbase, ioh);
343 UBYTE diskPresent(struct AFSBase *afsbase, struct IOHandle *ioh) {
345 ioh->ioreq->iotd_Req.io_Command = TD_CHANGESTATE;
346 DoIO((struct IORequest *)&ioh->ioreq->iotd_Req);
347 return ioh->ioreq->iotd_Req.io_Actual == 0;
350 int timercode(struct Custom *, struct IOHandle *, APTR, struct ExecBase *);
352 struct IOHandle *openBlockDevice(struct AFSBase *afsbase, struct IOHandle *ioh)
355 ioh->mp = CreateMsgPort();
356 if (ioh->mp != NULL)
358 ioh->ioreq = openDevice(afsbase, ioh->mp, ioh->blockdevice, ioh->unit, ioh->flags);
359 if (ioh->ioreq != NULL)
361 ioh->cmdread = CMD_READ;
362 ioh->cmdwrite = CMD_WRITE;
363 ioh->cmdseek = TD_SEEK;
364 ioh->cmdformat = TD_FORMAT;
365 ioh->vbl_int.is_Code = (void(*)())&timercode;
366 ioh->vbl_int.is_Data = ioh;
367 ioh->afsbase = afsbase;
368 if (StrCmp(ioh->blockdevice, "trackdisk.device"))
369 ioh->ioflags |= IOHF_TRACKDISK;
370 if (diskPresent(afsbase, ioh))
371 ioh->ioflags |= IOHF_DISK_IN;
372 checkAddChangeInt(afsbase, ioh);
373 return ioh;
375 DeleteMsgPort(ioh->mp);
377 return NULL;
380 void closeBlockDevice(struct AFSBase *afsbase, struct IOHandle *ioh) {
382 remChangeInt(afsbase, ioh);
383 if (ioh->iochangeint != NULL)
384 closeDevice(afsbase, ioh->iochangeint);
385 if (ioh->ioreq != NULL)
386 closeDevice(afsbase, ioh->ioreq);
387 if (ioh->mp != NULL)
388 DeleteMsgPort(ioh->mp);
391 void motorOff(struct AFSBase *afsbase, struct IOHandle *ioh) {
393 ioh->ioreq->iotd_Req.io_Command = TD_MOTOR;
394 ioh->ioreq->iotd_Req.io_Length = 0;
395 DoIO((struct IORequest *)&ioh->ioreq->iotd_Req);
398 void checkDeviceFlags(struct AFSBase *afsbase) {
399 struct Volume *volume;
400 struct IOHandle *ioh;
402 volume = (struct Volume *)afsbase->device_list.lh_Head;
403 while (volume->ln.ln_Succ != NULL)
405 ioh = &volume->ioh;
406 if (ioh->ioflags & IOHF_MOTOR_OFF)
408 motorOff(afsbase, ioh);
409 ioh->ioflags &= ~IOHF_MOTOR_OFF;
411 else if ((ioh->ioflags & IOHF_MEDIA_CHANGE) && (!volume->inhibitcounter))
413 if (diskPresent(afsbase, ioh))
415 if (!(ioh->ioflags & IOHF_DISK_IN))
417 if (!volume->inhibitcounter)
418 newMedium(afsbase, volume);
419 ioh->ioflags |= IOHF_DISK_IN;
422 else
424 if (!volume->inhibitcounter)
426 flush(afsbase, volume);
427 remDosVolume(afsbase, volume);
429 ioh->ioflags &= ~IOHF_DISK_IN;
431 ioh->ioflags &= ~IOHF_MEDIA_CHANGE;
433 volume = (struct Volume *)volume->ln.ln_Succ;
437 void check64BitSupport(struct AFSBase *afsbase, struct Volume *volume) {
438 struct NSDeviceQueryResult nsdq;
439 UWORD *cmdcheck;
441 if (
443 (volume->startblock+(volume->countblocks))* /* last block */
444 (volume->SizeBlock*4/512) /* 1 portion (block) equals 512 (bytes) */
445 )>8388608)
447 nsdq.SizeAvailable = 0;
448 nsdq.DevQueryFormat = 0;
449 volume->ioh.ioreq->iotd_Req.io_Command = NSCMD_DEVICEQUERY;
450 volume->ioh.ioreq->iotd_Req.io_Data = &nsdq;
451 volume->ioh.ioreq->iotd_Req.io_Length = sizeof(struct NSDeviceQueryResult);
452 if (DoIO((struct IORequest *)volume->ioh.ioreq) == IOERR_NOCMD)
454 D(bug("[afs] initVolume-NSD: device doesn't understand NSD-Query\n"));
456 else
458 if (
459 (volume->ioh.ioreq->iotd_Req.io_Actual > sizeof(struct NSDeviceQueryResult)) ||
460 (volume->ioh.ioreq->iotd_Req.io_Actual == 0) ||
461 (volume->ioh.ioreq->iotd_Req.io_Actual != nsdq.SizeAvailable)
464 D(bug("[afs] initVolume-NSD: WARNING wrong io_Actual using NSD\n"));
466 else
468 D(bug("[afs] initVolume-NSD: using NSD commands\n"));
469 if (nsdq.DeviceType != NSDEVTYPE_TRACKDISK)
470 D(bug("[afs] initVolume-NSD: WARNING no trackdisk type\n"));
471 for (cmdcheck=nsdq.SupportedCommands; *cmdcheck; cmdcheck++)
473 if (*cmdcheck == NSCMD_TD_READ64)
474 volume->ioh.cmdread = NSCMD_TD_READ64;
475 if (*cmdcheck == NSCMD_TD_WRITE64);
476 volume->ioh.cmdwrite = NSCMD_TD_WRITE64;
477 if (*cmdcheck == NSCMD_TD_SEEK64)
478 volume->ioh.cmdseek = NSCMD_TD_SEEK64;
479 if (*cmdcheck == NSCMD_TD_FORMAT64)
480 volume->ioh.cmdformat = NSCMD_TD_FORMAT64;
482 if (
483 (volume->ioh.cmdread != NSCMD_TD_READ64) ||
484 (volume->ioh.cmdwrite != NSCMD_TD_WRITE64)
486 D(bug("[afs] initVolume-NSD: WARNING no READ64/WRITE64\n"));
490 else
492 D(bug("[afs] initVolume-NSD: no need for NSD\n"));
496 /*******************************************
497 Name : flush
498 Descr.: flush buffers and update disk (sync)
499 Input : volume - volume to flush
500 Output: DOSTRUE
501 ********************************************/
502 BOOL flush(struct AFSBase *afsbase, struct Volume *volume) {
504 flushCache(afsbase, volume);
505 volume->ioh.ioreq->iotd_Req.io_Command = CMD_UPDATE;
506 DoIO((struct IORequest *)&volume->ioh.ioreq->iotd_Req);
507 clearCache(afsbase, volume->blockcache);
508 /* turn off motor */
509 return DOSTRUE;
512 static ULONG readwriteDisk
514 struct AFSBase *afsbase,
515 struct Volume *volume,
516 ULONG start,
517 ULONG count,
518 APTR mem,
519 ULONG cmd
522 LONG retval;
523 struct IOHandle *ioh = &volume->ioh;
524 UQUAD offset;
526 if (
527 ((volume->startblock+start) <= volume->lastblock) &&
528 ((volume->startblock+start+count-1) <= volume->lastblock)
531 ioh->ioreq->iotd_Req.io_Command = cmd;
532 ioh->ioreq->iotd_Req.io_Length = count*BLOCK_SIZE(volume);
533 ioh->ioreq->iotd_Req.io_Data = mem;
535 offset = start+volume->startblock;
536 offset *= BLOCK_SIZE(volume);
538 ioh->ioreq->iotd_Req.io_Offset = 0xFFFFFFFF & offset;
539 ioh->ioreq->iotd_Req.io_Actual = offset>>32;
540 retval = DoIO((struct IORequest *)&ioh->ioreq->iotd_Req);
541 if (ioh->ioflags & IOHF_TRACKDISK)
543 ioh->moff_time = 100;
544 if (ioh->moff_time <= 0)
545 AddIntServer(INTB_VERTB, &ioh->vbl_int);
548 else
550 showText(afsbase, "Attempted to read/write block outside range!\n\n"
551 "range: %lu-%lu, start: %lu, count: %lu",
552 volume->startblock, volume->lastblock, start, count);
553 retval = 1;
555 return retval;
558 LONG readDisk(struct AFSBase *afsbase, struct Volume *volume, ULONG start, ULONG count, APTR data) {
559 LONG result = 0;
560 BOOL retry = TRUE;
562 while (retry)
564 D(bug("[afs] readDisk: reading blocks %lu to %lu\n", start, start+count-1));
565 result = readwriteDisk(afsbase, volume, start, count, data, volume->ioh.cmdread);
566 if (result == 0)
567 retry = FALSE;
568 else
569 retry = showRetriableError(afsbase, "Read error %ld on block %lu", result, start) == 1;
572 return result;
575 LONG writeDisk(struct AFSBase *afsbase, struct Volume *volume, ULONG start, ULONG count, APTR data) {
576 LONG result = 0;
577 BOOL retry = TRUE;
579 while (retry)
581 D(bug("[afs] writeDisk: writing blocks %lu to %lu\n", start, start+count-1));
582 result = readwriteDisk(afsbase, volume, start, count, data, volume->ioh.cmdwrite);
583 if (result == 0)
584 retry = FALSE;
585 else
586 retry = showRetriableError(afsbase, "Write error %ld on block %lu", result, start) == 1;
589 return result;
592 #undef SysBase
594 AROS_UFH4(int, timercode,
595 AROS_UFHA(struct Custom *, custom, A0),
596 AROS_UFHA(struct IOHandle *, ioh, A1),
597 AROS_UFHA(APTR, is_Code, A5),
598 AROS_UFHA(struct ExecBase *, SysBase, A6))
600 AROS_USERFUNC_INIT
601 if (--ioh->moff_time == 0)
603 ioh->ioflags |= IOHF_MOTOR_OFF;
604 Signal
606 ioh->afsbase->port.mp_SigTask,
607 1<<ioh->afsbase->port.mp_SigBit
609 RemIntServer(INTB_VERTB, &ioh->vbl_int);
611 return 0;
612 AROS_USERFUNC_EXIT
615 AROS_UFH3(VOID, changeIntCode,
616 AROS_UFHA(struct IOHandle *, ioh, A1),
617 AROS_UFHA(APTR, is_Code, A5),
618 AROS_UFHA(struct ExecBase *, SysBase, A6))
620 AROS_USERFUNC_INIT
622 ioh->ioflags |= IOHF_MEDIA_CHANGE;
623 Signal(ioh->afsbase->port.mp_SigTask, 1<<ioh->afsbase->port.mp_SigBit);
625 AROS_USERFUNC_EXIT