Bringing flexcat 2.15 into the main branch (again)
[AROS.git] / arch / m68k-amiga / devs / cd / cd.c
blob987718ff098bfbe22b3e1f0a8a1b8783b30f5412
1 /*
2 * Copyright (C) 2013, The AROS Development Team
3 * All right reserved.
4 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
6 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
7 */
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"
21 struct cdUnit {
22 struct MinNode cu_Node;
23 LONG cu_Unit;
24 ULONG cu_Usage;
25 APTR cu_Private;
26 const struct cdUnitOps *cu_UnitOps;
27 struct Task *cu_Task;
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;
37 struct IOStdReq *io;
39 D(bug("%s.%d Task, Port %p\n", cu->cu_UnitOps->uo_Name, cu->cu_Unit, cu->cu_MsgPort));
40 do {
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);
51 } else {
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",
71 40L);
73 if (ExpansionBase)
75 IPTR pp[24];
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;
82 else
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);
96 if (devnode)
98 AddBootNode(pp[DE_BOOTPRI + 4], ADNF_STARTPROC, devnode, NULL);
100 return TRUE;
103 CloseLibrary((struct Library *)ExpansionBase);
106 return FALSE;
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)
122 struct cdUnit *cu;
124 cu = AllocVec(sizeof(*cu), MEMF_CLEAR | MEMF_ANY);
125 if (cu) {
126 cu->cu_Private = priv;
127 cu->cu_UnitOps = ops;
128 cu->cu_Task = NewCreateTask(TASKTAG_PC, cdTask,
129 TASKTAG_NAME, ops->uo_Name,
130 TASKTAG_ARG1, cb,
131 TASKTAG_ARG2, cu,
132 TASKTAG_TASKMSGPORT, &cu->cu_MsgPort,
133 TAG_END);
134 if (cu->cu_Task) {
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);
140 return cu->cu_Unit;
142 FreeVec(cu);
145 return -1;
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)
167 struct cdUnit *cu;
168 struct IORequest io;
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;
178 io.io_Unit = NULL;
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);
183 WaitPort(mp);
184 GetMsg(mp);
186 if (cu->cu_UnitOps->uo_Expunge)
187 cu->cu_UnitOps->uo_Expunge(cu->cu_Private);
188 FreeVec(cu);
191 DeleteMsgPort(mp);
193 return 1;
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)
203 AROS_LIBFUNC_INIT
205 struct IOStdReq *iostd = (struct IOStdReq *)io;
206 struct cdUnit *cu = (struct cdUnit *)(io->io_Unit);
208 D(bug("%s.%d: %p\n"
209 "io_Command: %d\n"
210 "io_Length: %d\n"
211 "io_Data: %p\n"
212 "io_Offset: %d\n",
213 __func__, cu->cu_Unit, iostd,
214 iostd->io_Command,
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);
222 return;
224 AROS_LIBFUNC_EXIT
227 AROS_LH1(LONG, AbortIO,
228 AROS_LHA(struct IORequest *, io, A1),
229 LIBBASETYPEPTR, LIBBASE, 6, cd)
231 AROS_LIBFUNC_INIT
233 D(bug("%s.%d: %p\n", __func__, ((struct cdUnit *)(io->io_Unit))->cu_Unit, io));
234 Forbid();
235 io->io_Flags |= IOF_ABORT;
236 Permit();
238 return TRUE;
240 AROS_LIBFUNC_EXIT
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) {
250 cu->cu_Usage++;
251 ioreq->io_Unit = (struct Unit *)cu;
252 ReleaseSemaphore(&cdBase->cb_UnitsLock);
253 return TRUE;
256 ReleaseSemaphore(&cdBase->cb_UnitsLock);
258 return FALSE;
261 static int GM_UNIQUENAME(Close)(LIBBASETYPEPTR cdBase, struct IORequest *ioreq)
263 struct cdUnit *cu = (APTR)ioreq->io_Unit;
265 ObtainSemaphore(&cdBase->cb_UnitsLock);
266 cu->cu_Usage--;
267 ReleaseSemaphore(&cdBase->cb_UnitsLock);
269 return TRUE;
272 ADD2OPENDEV(GM_UNIQUENAME(Open),0)
273 ADD2CLOSEDEV(GM_UNIQUENAME(Close),0)