2 * Copyright (C) 2013, The AROS Development Team
4 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
6 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
9 #include <aros/debug.h>
10 #include <proto/exec.h>
11 #include <proto/expansion.h>
13 #include <libraries/expansion.h>
15 #include <dos/filehandler.h>
17 #include <devices/cd.h>
19 #include "cd_intern.h"
22 struct MinNode cu_Node
;
26 const struct cdUnitOps
*cu_UnitOps
;
28 struct MsgPort
*cu_MsgPort
;
31 /* We have a synchonous task for dispatching IO
32 * to each cd.device unit.
34 static VOID
cdTask(IPTR base
, IPTR unit
)
36 struct cdUnit
*cu
= (APTR
)unit
;
39 D(bug("%s.%d Task, Port %p\n", cu
->cu_UnitOps
->uo_Name
, cu
->cu_Unit
, cu
->cu_MsgPort
));
41 WaitPort(cu
->cu_MsgPort
);
42 io
= (struct IOStdReq
*)GetMsg(cu
->cu_MsgPort
);
44 D(bug("%s: Processing %p\n", __func__
, io
));
46 if (io
->io_Flags
& IOF_ABORT
) {
47 io
->io_Error
= CDERR_ABORTED
;
48 } else if (io
->io_Unit
== (struct Unit
*)cu
&&
49 cu
->cu_UnitOps
->uo_DoIO
!= NULL
) {
50 io
->io_Error
= cu
->cu_UnitOps
->uo_DoIO(io
, cu
->cu_Private
);
52 io
->io_Error
= CDERR_NOCMD
;
55 D(bug("%s: Reply %p\n", __func__
, io
));
56 ReplyMsg(&io
->io_Message
);
58 } while (io
->io_Unit
!= NULL
);
60 /* Terminate by fallthough */
63 /* Add a bootnode using expansion.library */
64 static BOOL
cdRegisterVolume(struct cdUnit
*unit
, const struct DosEnvec
*de
)
66 struct ExpansionBase
*ExpansionBase
;
67 struct DeviceNode
*devnode
;
68 TEXT dosdevname
[4] = "CD0";
70 ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library",
77 CopyMem((IPTR
*)de
, &pp
[4], sizeof(IPTR
)*de
->de_TableSize
);
79 /* This should be dealt with using some sort of volume manager or such. */
80 if (unit
->cu_Unit
< 10)
81 dosdevname
[2] += unit
->cu_Unit
% 10;
83 dosdevname
[2] = 'A' - 10 + unit
->cu_Unit
;
85 pp
[0] = (IPTR
)dosdevname
;
86 pp
[1] = (IPTR
)MOD_NAME_STRING
;
87 pp
[2] = unit
->cu_Unit
;
88 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
89 pp
[DE_BOOTPRI
+ 4] = -10;
90 pp
[DE_DOSTYPE
+ 4] = AROS_MAKE_ID('C','D','F','S');
91 pp
[DE_CONTROL
+ 4] = 0;
92 pp
[DE_BOOTBLOCKS
+ 4] = 0;
94 devnode
= MakeDosNode(pp
);
98 AddBootNode(pp
[DE_BOOTPRI
+ 4], ADNF_STARTPROC
, devnode
, NULL
);
103 CloseLibrary((struct Library
*)ExpansionBase
);
109 VOID
cdDelayMS(struct cdBase
*cb
, ULONG ms
)
111 cb
->cb_TimerPort
.mp_SigTask
= FindTask(NULL
);
112 cb
->cb_TimerRequest
.tr_node
.io_Command
= TR_ADDREQUEST
;
113 cb
->cb_TimerRequest
.tr_time
.tv_secs
= ms
/ 1000;
114 cb
->cb_TimerRequest
.tr_time
.tv_micro
= (ms
* 1000) % 1000000;
116 DoIO((struct IORequest
*)&cb
->cb_TimerRequest
);
120 LONG
cdAddUnit(struct cdBase
*cb
, const struct cdUnitOps
*ops
, APTR priv
, const struct DosEnvec
*de
)
124 cu
= AllocVec(sizeof(*cu
), MEMF_CLEAR
| MEMF_ANY
);
126 cu
->cu_Private
= priv
;
127 cu
->cu_UnitOps
= ops
;
128 cu
->cu_Task
= NewCreateTask(TASKTAG_PC
, cdTask
,
129 TASKTAG_NAME
, ops
->uo_Name
,
132 TASKTAG_TASKMSGPORT
, &cu
->cu_MsgPort
,
135 cu
->cu_Unit
= cb
->cb_MaxUnit
++;
136 ObtainSemaphore(&cb
->cb_UnitsLock
);
137 ADDTAIL(&cb
->cb_Units
, &cu
->cu_Node
);
138 ReleaseSemaphore(&cb
->cb_UnitsLock
);
139 cdRegisterVolume(cu
, de
);
148 static int cd_Init(LIBBASETYPE
*cb
)
150 NEWLIST(&cb
->cb_Units
);
151 InitSemaphore(&cb
->cb_UnitsLock
);
153 /* Hand-hacked port for timer responses */
154 cb
->cb_TimerPort
.mp_SigBit
= SIGB_SINGLE
;
155 cb
->cb_TimerPort
.mp_Flags
= PA_SIGNAL
;
156 cb
->cb_TimerPort
.mp_SigTask
= FindTask(NULL
);
157 cb
->cb_TimerPort
.mp_Node
.ln_Type
= NT_MSGPORT
;
159 cb
->cb_TimerRequest
.tr_node
.io_Message
.mn_ReplyPort
= &cb
->cb_TimerPort
;
160 cb
->cb_TimerRequest
.tr_node
.io_Message
.mn_Length
= sizeof(cb
->cb_TimerRequest
);
162 return (0 == OpenDevice(TIMERNAME
, UNIT_MICROHZ
, (struct IORequest
*)&cb
->cb_TimerRequest
, 0));
165 static int cd_Expunge(LIBBASETYPE
*cb
)
169 struct MsgPort
*mp
= CreateMsgPort();
171 CloseDevice((struct IORequest
*)&cb
->cb_TimerPort
);
173 while ((cu
= (APTR
)REMOVE(&cb
->cb_Units
)) != NULL
) {
174 D(bug("%s: Remove Unit %d\n", __func__
, cu
->cu_Unit
));
176 /* Shut down the unit's task */
177 io
.io_Device
= (struct Device
*)cb
;
179 io
.io_Command
= CMD_INVALID
;
180 io
.io_Message
.mn_ReplyPort
= mp
;
181 io
.io_Message
.mn_Length
= sizeof(io
);
182 PutMsg(cu
->cu_MsgPort
, &io
.io_Message
);
186 if (cu
->cu_UnitOps
->uo_Expunge
)
187 cu
->cu_UnitOps
->uo_Expunge(cu
->cu_Private
);
196 ADD2INITLIB(cd_Init
, 0);
197 ADD2EXPUNGELIB(cd_Expunge
, 0);
199 AROS_LH1(void, BeginIO
,
200 AROS_LHA(struct IORequest
*, io
, A1
),
201 LIBBASETYPEPTR
, LIBBASE
, 5, cd
)
205 struct IOStdReq
*iostd
= (struct IOStdReq
*)io
;
206 struct cdUnit
*cu
= (struct cdUnit
*)(io
->io_Unit
);
213 __func__
, cu
->cu_Unit
, iostd
,
215 iostd
->io_Length
, iostd
->io_Data
, iostd
->io_Offset
));
217 io
->io_Error
= CDERR_NOCMD
;
219 io
->io_Flags
&= ~IOF_QUICK
;
220 PutMsg(cu
->cu_MsgPort
, &iostd
->io_Message
);
227 AROS_LH1(LONG
, AbortIO
,
228 AROS_LHA(struct IORequest
*, io
, A1
),
229 LIBBASETYPEPTR
, LIBBASE
, 6, cd
)
233 D(bug("%s.%d: %p\n", __func__
, ((struct cdUnit
*)(io
->io_Unit
))->cu_Unit
, io
));
235 io
->io_Flags
|= IOF_ABORT
;
243 static int GM_UNIQUENAME(Open
)(LIBBASETYPEPTR cdBase
, struct IOStdReq
*ioreq
, ULONG unitnum
, ULONG flags
)
245 struct cdUnit
*cu
= NULL
;
247 ObtainSemaphore(&cdBase
->cb_UnitsLock
);
248 ForeachNode(&cdBase
->cb_Units
, cu
) {
249 if (cu
->cu_Unit
== unitnum
) {
251 ioreq
->io_Unit
= (struct Unit
*)cu
;
252 ReleaseSemaphore(&cdBase
->cb_UnitsLock
);
256 ReleaseSemaphore(&cdBase
->cb_UnitsLock
);
261 static int GM_UNIQUENAME(Close
)(LIBBASETYPEPTR cdBase
, struct IORequest
*ioreq
)
263 struct cdUnit
*cu
= (APTR
)ioreq
->io_Unit
;
265 ObtainSemaphore(&cdBase
->cb_UnitsLock
);
267 ReleaseSemaphore(&cdBase
->cb_UnitsLock
);
272 ADD2OPENDEV(GM_UNIQUENAME(Open
),0)
273 ADD2CLOSEDEV(GM_UNIQUENAME(Close
),0)