2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
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>
16 #include <hardware/custom.h>
17 #include <hardware/intbits.h>
18 #include <intuition/intuition.h>
21 #include "afsblocks.h"
23 #include "extstrings.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
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
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
))) {
61 InputRequest
->io_Command
= IND_WRITEEVENT
;
62 InputRequest
->io_Data
= ie
;
63 InputRequest
->io_Length
= sizeof(struct InputEvent
);
65 DoIO((struct IORequest
*)InputRequest
);
69 CloseDevice((struct IORequest
*)InputRequest
);
71 DeleteIORequest ((APTR
)InputRequest
);
73 DeleteMsgPort (InputPort
);
77 /************************** DOS ******************************************/
78 /*******************************************
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 ********************************************/
87 struct AFSBase
*afsbase
,
88 struct Volume
*volume
,
89 struct BlockCache
*rootblock
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
;
115 newname
= (BSTR
)AllocVec(32,MEMF_CLEAR
| MEMF_PUBLIC
);
116 if (newname
== (BSTR
)NULL
)
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
;
126 /*******************************************
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
;
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
);
147 dl
= FindDosEntry(doslist
,string
,LDF_VOLUMES
);
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
;
162 UnLockDosList(LDF_WRITE
| LDF_VOLUMES
);
164 /* if not create a new doslist */
167 doslist
= MakeDosEntry(string
,DLT_VOLUME
);
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);
186 /*******************************************
188 Descr.: removes a volume added by addDosVolume
189 or if there are some locks active
191 Input : volume - volume to remove
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
;
203 //SendEvent(afsbase, IECLASS_DISKREMOVED);
204 if (volume
->dostype
== 0x444F5300)
206 bname
= volume
->devicelist
.dl_Name
;
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
);
215 dl
= FindDosEntry(doslist
,string
,LDF_VOLUMES
);
218 if (volume
->locklist
!= NULL
)
220 dl
->dol_misc
.dol_volume
.dol_LockList
= volume
->locklist
;
229 showText(afsbase
, "doslist not in chain");
230 UnLockDosList(LDF_WRITE
| LDF_VOLUMES
);
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
;
251 void osMediumFree(struct AFSBase
*afsbase
, struct Volume
*volume
, LONG all
) {
252 remDosVolume(afsbase
, volume
);
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
,
268 struct IOExtTD
*ioreq
;
270 ioreq
= (struct IOExtTD
*)CreateIORequest(mp
, sizeof(struct IOExtTD
));
273 if (OpenDevice(device
, unit
, (struct IORequest
*)ioreq
, flags
) == 0)
278 showError(afsbase
, ERR_DEVICE
, device
);
279 DeleteIORequest((struct IORequest
*)ioreq
);
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
);
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
) {
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();
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
);
375 DeleteMsgPort(ioh
->mp
);
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
);
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
)
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
;
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
;
443 (volume
->startblock
+(volume
->countblocks
))* /* last block */
444 (volume
->SizeBlock
*4/512) /* 1 portion (block) equals 512 (bytes) */
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"));
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"));
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
;
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"));
492 D(bug("[afs] initVolume-NSD: no need for NSD\n"));
496 /*******************************************
498 Descr.: flush buffers and update disk (sync)
499 Input : volume - volume to flush
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
);
512 static ULONG readwriteDisk
514 struct AFSBase
*afsbase
,
515 struct Volume
*volume
,
523 struct IOHandle
*ioh
= &volume
->ioh
;
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
);
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
);
558 LONG
readDisk(struct AFSBase
*afsbase
, struct Volume
*volume
, ULONG start
, ULONG count
, APTR data
) {
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
);
569 retry
= showRetriableError(afsbase
, "Read error %ld on block %lu", result
, start
) == 1;
575 LONG
writeDisk(struct AFSBase
*afsbase
, struct Volume
*volume
, ULONG start
, ULONG count
, APTR data
) {
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
);
586 retry
= showRetriableError(afsbase
, "Write error %ld on block %lu", result
, start
) == 1;
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
))
601 if (--ioh
->moff_time
== 0)
603 ioh
->ioflags
|= IOHF_MOTOR_OFF
;
606 ioh
->afsbase
->port
.mp_SigTask
,
607 1<<ioh
->afsbase
->port
.mp_SigBit
609 RemIntServer(INTB_VERTB
, &ioh
->vbl_int
);
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
))
622 ioh
->ioflags
|= IOHF_MEDIA_CHANGE
;
623 Signal(ioh
->afsbase
->port
.mp_SigTask
, 1<<ioh
->afsbase
->port
.mp_SigBit
);