Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / classes / massstorage / dev.c
blobb81b75c3ca2712df6f0338b9284a31535e029087
1 /* dev.c - usbscsi.device by Chris Hodges
2 */
4 #include "debug.h"
6 #include "massstorage.class.h"
8 AROS_UFH3(DEVBASETYPEPTR, GM_UNIQUENAME(devInit),
9 AROS_UFHA(DEVBASETYPEPTR, base, D0),
10 AROS_UFHA(BPTR, seglist, A0),
11 AROS_UFHA(struct ExecBase *, SysBase, A6))
13 AROS_USERFUNC_INIT
15 KPRINTF(10, ("devInit base: 0x%08lx seglist: 0x%08lx SysBase: 0x%08lx\n",
16 base, seglist, SysBase));
18 base->np_Library.lib_Node.ln_Type = NT_DEVICE;
19 base->np_Library.lib_Node.ln_Name = DEVNAME;
20 base->np_Library.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED;
21 base->np_Library.lib_Version = VERSION_NUMBER;
22 base->np_Library.lib_Revision = REVISION_NUMBER;
23 base->np_Library.lib_IdString = VERSION_STRING;
25 /* Store segment */
26 base->np_SegList = seglist;
28 return(base);
30 AROS_USERFUNC_EXIT
33 AROS_LH3(DEVBASETYPEPTR, devOpen,
34 AROS_LHA(struct IORequest *, ioreq, A1),
35 AROS_LHA(ULONG, unitnum, D0),
36 AROS_LHA(ULONG, flags, D1),
37 DEVBASETYPEPTR, base, 1, usbscsidev)
39 AROS_LIBFUNC_INIT
41 struct NepClassMS *ncm;
43 KPRINTF(10, ("devOpen ioreq: 0x%08lx unit: %ld flags: 0x%08lx base: 0x%08lx\n",
44 ioreq, unitnum, flags, base));
46 if(!base->np_UtilityBase)
48 if(!(base->np_UtilityBase = OpenLibrary("utility.library", 0)))
50 ioreq->io_Error = IOERR_OPENFAIL;
51 return(NULL);
55 ++base->np_Library.lib_OpenCnt;
56 base->np_Library.lib_Flags &= ~LIBF_DELEXP;
58 KPRINTF(10, ("devOpen: openCnt = %ld\n", base->np_Library.lib_OpenCnt));
60 /* Damn f*cking programs which leave this field to zero! */
61 if(ioreq->io_Message.mn_Length &&
62 (ioreq->io_Message.mn_Length < sizeof(struct IOStdReq)))
64 KPRINTF(20, ("devOpen: invalid MN_LENGTH (%ld < %ld)!\n",
65 ioreq->io_Message.mn_Length, sizeof(struct IOStdReq)));
67 ioreq->io_Error = IOERR_BADLENGTH;
68 } else {
69 /* Default to open failure. */
70 ioreq->io_Error = IOERR_OPENFAIL;
72 ioreq->io_Unit = NULL;
73 ncm = (struct NepClassMS *) base->np_ClsBase->nh_Units.lh_Head;
74 while(ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ)
76 if(ncm->ncm_UnitNo == unitnum)
78 if(!ncm->ncm_DenyRequests)
80 ioreq->io_Unit = (struct Unit *) ncm;
81 break;
84 ncm = (struct NepClassMS *) ncm->ncm_Unit.unit_MsgPort.mp_Node.ln_Succ;
87 if(!ioreq->io_Unit)
89 ioreq->io_Error = IOERR_OPENFAIL;
90 KPRINTF(20, ("devOpen: could not open unit!\n"));
91 } else {
92 /* Opended ok! */
93 ioreq->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
94 ioreq->io_Error = 0;
95 ioreq->io_Unit->unit_OpenCnt++;
97 return base;
101 ioreq->io_Unit = (APTR) -1;
102 ioreq->io_Device = (APTR) -1;
103 base->np_Library.lib_OpenCnt--;
105 return(NULL);
107 AROS_LIBFUNC_EXIT
111 AROS_LH1(BPTR, devClose,
112 AROS_LHA(struct IORequest *, ioreq, A1),
113 DEVBASETYPEPTR, base, 2, usbscsidev)
115 AROS_LIBFUNC_INIT
117 BPTR ret;
118 struct NepClassMS *unit = (struct NepClassMS *) ioreq->io_Unit;
120 KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq, base));
122 ret = BNULL;
123 unit->ncm_Unit.unit_OpenCnt--;
124 ioreq->io_Unit = (APTR) -1;
125 ioreq->io_Device = (APTR) -1;
127 if(--base->np_Library.lib_OpenCnt == 0)
129 if(base->np_Library.lib_Flags & LIBF_DELEXP)
131 KPRINTF(5, ("devClose: calling expunge...\n"));
132 ret = AROS_LC1(BPTR, devExpunge,
133 AROS_LCA(DEVBASETYPEPTR, base, D0),
134 DEVBASETYPEPTR, base, 3, dev);
138 KPRINTF(5, ("devClose: lib_OpenCnt = %ld\n", base->np_Library.lib_OpenCnt));
140 return(ret);
142 AROS_LIBFUNC_EXIT
146 AROS_LH1(BPTR, devExpunge,
147 AROS_LHA(DEVBASETYPEPTR, extralh, D0),
148 DEVBASETYPEPTR, base, 3,usbscsidev)
150 AROS_LIBFUNC_INIT
152 BPTR ret;
154 KPRINTF(10, ("devExpunge base: 0x%08lx\n", base));
156 ret = BNULL;
158 if(base->np_Library.lib_OpenCnt == 0)
160 KPRINTF(5, ("devExpunge: Unloading...\n"));
162 CloseLibrary(base->np_UtilityBase);
164 ret = base->np_SegList;
166 KPRINTF(5, ("devExpunge: removing device node 0x%08lx\n",
167 &base->np_Library.lib_Node));
168 Remove(&base->np_Library.lib_Node);
170 KPRINTF(5, ("devExpunge: FreeMem()...\n"));
171 FreeMem((char *) base - base->np_Library.lib_NegSize,
172 (ULONG) (base->np_Library.lib_NegSize + base->np_Library.lib_PosSize));
174 KPRINTF(5, ("devExpunge: Unloading done! " DEVNAME " expunged!\n\n"));
176 return(ret);
178 else
180 KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n"));
181 base->np_Library.lib_Flags |= LIBF_DELEXP;
184 return(BNULL);
186 AROS_LIBFUNC_EXIT
189 AROS_LH0(DEVBASETYPEPTR, devReserved,
190 DEVBASETYPEPTR, base, 4, usbscsidev)
192 AROS_LIBFUNC_INIT
193 return NULL;
194 AROS_LIBFUNC_EXIT
197 AROS_LH1(void, devBeginIO,
198 AROS_LHA(struct IOStdReq *, ioreq, A1),
199 DEVBASETYPEPTR, base, 5, usbscsidev)
201 AROS_LIBFUNC_INIT
203 struct NepClassMS *unit = (struct NepClassMS *) ioreq->io_Unit;
204 WORD ret = IOERR_NOCMD;
206 KPRINTF(5, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->io_Command));
208 ioreq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
209 ioreq->io_Error = 0;
211 if(ioreq->io_Command < NSCMD_DEVICEQUERY)
213 switch (ioreq->io_Command)
215 case TD_ADDCHANGEINT:
216 Forbid();
217 AddTail(&unit->ncm_DCInts, (struct Node *) ioreq);
218 Permit();
219 ret = RC_DONTREPLY;
220 break;
222 case TD_REMCHANGEINT:
223 Forbid();
224 Remove((struct Node *) ioreq);
225 Permit();
226 ret = 0;
227 ioreq->io_Flags &= ~IOF_QUICK;
228 break;
230 case TD_CHANGENUM:
231 ioreq->io_Actual = unit->ncm_ChangeCount;
232 ret = 0;
233 break;
235 case TD_CHANGESTATE:
236 ioreq->io_Actual = unit->ncm_UnitReady ? 0 : ~0;
237 ret = 0;
238 break;
240 case TD_PROTSTATUS:
241 ioreq->io_Actual = unit->ncm_WriteProtect ? ~0 : 0;
242 ret = 0;
243 break;
245 case CMD_START:
246 case CMD_STOP:
247 case CMD_RESET:
248 case CMD_FLUSH:
249 case CMD_READ:
250 case CMD_WRITE:
251 case TD_SEEK:
252 case TD_FORMAT:
253 case TD_GETGEOMETRY:
254 case TD_EJECT:
255 case TD_READ64:
256 case TD_WRITE64:
257 case TD_SEEK64:
258 case TD_FORMAT64:
259 case HD_SCSICMD:
260 if(unit->ncm_DenyRequests)
262 ret = TDERR_DiskChanged;
263 } else {
264 ioreq->io_Flags &= ~IOF_QUICK;
265 ret = RC_DONTREPLY;
266 PutMsg(&unit->ncm_Unit.unit_MsgPort, (struct Message *) ioreq);
268 break;
270 /* NOPs */
271 case CMD_CLEAR:
272 case CMD_UPDATE:
273 case TD_MOTOR:
274 ret = 0;
275 break;
277 default:
278 ret = IOERR_NOCMD;
279 break;
281 } else {
282 switch(ioreq->io_Command)
284 case NSCMD_DEVICEQUERY:
285 ret = GM_UNIQUENAME(cmdNSDeviceQuery)((struct IOStdReq *) ioreq, unit, base);
286 break;
288 case NSCMD_TD_READ64:
289 case NSCMD_TD_WRITE64:
290 case NSCMD_TD_FORMAT64:
291 case NSCMD_TD_SEEK64:
292 if(unit->ncm_DenyRequests)
294 ret = IOERR_ABORTED;
295 } else {
296 ioreq->io_Flags &= ~IOF_QUICK;
297 ret = RC_DONTREPLY;
298 PutMsg(&unit->ncm_Unit.unit_MsgPort, (struct Message *) ioreq);
300 break;
302 default:
303 ret = IOERR_NOCMD;
304 break;
308 if(ret != RC_DONTREPLY)
310 KPRINTF(1, ("GM_UNIQUENAME(TermIO)\n"));
311 if (ret != RC_OK)
313 /* Set error codes */
314 ioreq->io_Error = ret & 0xff;
316 /* Terminate the iorequest */
317 GM_UNIQUENAME(TermIO)(ioreq, base);
320 AROS_LIBFUNC_EXIT
323 AROS_LH1(LONG, devAbortIO,
324 AROS_LHA(struct IOStdReq *, ioreq, A1),
325 DEVBASETYPEPTR, base, 6, usbscsidev)
327 AROS_LIBFUNC_INIT
329 struct NepClassMS *unit = (struct NepClassMS *) ioreq->io_Unit;
330 struct IOStdReq *iocmp;
332 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq));
334 /* Is it pending? */
335 if(ioreq->io_Message.mn_Node.ln_Type == NT_MESSAGE)
337 if(unit->ncm_XFerPending == ioreq)
339 unit->ncm_XFerPending = NULL;
340 ioreq->io_Error = IOERR_ABORTED;
341 ReplyMsg(&ioreq->io_Message);
342 return(0);
344 iocmp = (struct IOStdReq *) unit->ncm_XFerQueue.lh_Head;
345 while(iocmp->io_Message.mn_Node.ln_Succ)
347 if(iocmp == ioreq)
349 Remove((struct Node *) ioreq);
350 ioreq->io_Error = IOERR_ABORTED;
351 ReplyMsg(&ioreq->io_Message);
352 return(0);
354 iocmp = (struct IOStdReq *) iocmp->io_Message.mn_Node.ln_Succ;
357 return(-1);
359 AROS_LIBFUNC_EXIT
362 /* NSD stuff */
364 static
365 const UWORD GM_UNIQUENAME(NSDSupported)[] =
367 CMD_CLEAR, CMD_RESET,
368 CMD_FLUSH, CMD_READ,
369 CMD_WRITE, CMD_START,
370 CMD_STOP, CMD_UPDATE,
371 TD_SEEK,
372 TD_MOTOR, TD_EJECT,
373 TD_CHANGENUM, TD_PROTSTATUS,
374 TD_CHANGESTATE,
375 TD_FORMAT,
376 TD_GETGEOMETRY,
377 TD_ADDCHANGEINT, TD_REMCHANGEINT,
378 TD_READ64, TD_WRITE64, TD_SEEK64,
379 TD_FORMAT64,
380 HD_SCSICMD,
381 NSCMD_TD_READ64,
382 NSCMD_TD_WRITE64,
383 NSCMD_TD_FORMAT64,
384 NSCMD_TD_SEEK64,
385 NSCMD_DEVICEQUERY, 0
388 WORD GM_UNIQUENAME(cmdNSDeviceQuery)(struct IOStdReq *ioreq,
389 struct NepClassMS *unit,
390 struct NepMSDevBase *base)
392 struct my_NSDeviceQueryResult *query;
394 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
396 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query));
398 /* NULL ptr?
399 Enough data?
400 Valid request?
402 if((!query) ||
403 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
404 (query->DevQueryFormat != 0) ||
405 (query->SizeAvailable != 0))
407 /* Return error. This is special handling, since iorequest is only
408 guaranteed to be sizeof(struct IOStdReq). If we'd let our
409 devBeginIO dispatcher return the error, it would trash some
410 memory past end of the iorequest (ios2_WireError field).
412 ioreq->io_Error = IOERR_NOCMD;
413 GM_UNIQUENAME(TermIO)((struct IOStdReq *) ioreq, base);
415 /* Don't reply, we already did. */
416 return RC_DONTREPLY;
419 ioreq->io_Actual = query->SizeAvailable
420 = sizeof(struct my_NSDeviceQueryResult);
421 query->DeviceType = NSDEVTYPE_TRACKDISK;
422 query->DeviceSubType = 0;
423 query->SupportedCommands = GM_UNIQUENAME(NSDSupported);
425 /* Return success (note that this will NOT poke ios2_WireError).
427 return RC_OK;
430 void GM_UNIQUENAME(TermIO)(struct IOStdReq *ioreq,
431 struct NepMSDevBase *base)
433 ioreq->io_Message.mn_Node.ln_Type = NT_FREEMSG;
435 /* If not quick I/O, reply the message */
436 if(!(ioreq->io_Flags & IOF_QUICK))
438 ReplyMsg(&ioreq->io_Message);