poseidon: Fix a number of BPTR issues
[AROS.git] / rom / usb / classes / bluetooth / dev.c
blobb364212eeb74789b4303ffb72b71dcea600ea3fa
1 /* dev.c - usbbluetooth.device by Chris Hodges
2 */
4 #include "debug.h"
6 #include "bluetooth.class.h"
8 AROS_UFH3(DEVBASETYPEPTR, 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 if((base->np_UtilityBase = OpenLibrary("utility.library", 0)))
30 KPRINTF(10, ("devInit: Ok\n"));
31 KPRINTF(10, ("devInit: openCnt = %ld\n", base->np_Library.lib_OpenCnt));
32 return(base);
34 else
36 return(NULL);
38 return(base);
40 AROS_USERFUNC_EXIT
43 #undef UtilityBase
44 #define UtilityBase base->np_UtilityBase
46 AROS_LH3(DEVBASETYPEPTR, devOpen,
47 AROS_LHA(struct IOBTHCIReq *, ioreq, A1),
48 AROS_LHA(ULONG, unit, D0),
49 AROS_LHA(ULONG, flags, D1),
50 DEVBASETYPEPTR, base, 1, dev)
52 AROS_LIBFUNC_INIT
54 struct NepClassBT *ncp;
56 KPRINTF(10, ("devOpen ioreq: 0x%08lx unit: %ld flags: 0x%08lx base: 0x%08lx\n",
57 ioreq, unit, flags, base));
59 ++base->np_Library.lib_OpenCnt;
60 base->np_Library.lib_Flags &= ~LIBF_DELEXP;
62 KPRINTF(10, ("devOpen: openCnt = %ld\n", base->np_Library.lib_OpenCnt));
63 /* Damn f*cking programs which leave this field to zero! */
64 if(ioreq->iobt_Req.io_Message.mn_Length && (ioreq->iobt_Req.io_Message.mn_Length < sizeof(struct IOBTHCIReq)))
66 KPRINTF(20, ("devOpen: invalid MN_LENGTH (%ld < %ld)!\n",
67 ioreq->iobt_Req.io_Message.mn_Length, sizeof(struct IOBTHCIReq)));
69 ioreq->iobt_Req.io_Error = IOERR_BADLENGTH;
70 } else {
71 /* Default to open failure. */
72 ioreq->iobt_Req.io_Error = IOERR_OPENFAIL;
74 ioreq->iobt_Req.io_Unit = NULL;
75 ncp = (struct NepClassBT *) base->np_ClsBase->nh_Units.lh_Head;
76 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
78 if(ncp->ncp_UnitNo == unit)
80 if(ncp->ncp_Unit.unit_OpenCnt)
82 ioreq->iobt_Req.io_Error = IOERR_UNITBUSY;
83 } else {
84 ioreq->iobt_Req.io_Unit = (struct Unit *) ncp;
86 break;
88 ncp = (struct NepClassBT *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
91 if(!ioreq->iobt_Req.io_Unit)
93 ioreq->iobt_Req.io_Error = IOERR_OPENFAIL;
94 KPRINTF(20, ("devOpen: could not open unit!\n"));
95 } else {
96 /* Opended ok! */
97 ioreq->iobt_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
98 ioreq->iobt_Req.io_Error = 0;
99 ioreq->iobt_Req.io_Unit->unit_OpenCnt++;
101 /* Allow queuing */
102 ncp->ncp_DenyRequests = FALSE;
104 return base;
108 ioreq->iobt_Req.io_Unit = (APTR) -1;
109 ioreq->iobt_Req.io_Device = (APTR) -1;
110 base->np_Library.lib_OpenCnt--;
112 return(NULL);
114 AROS_LIBFUNC_EXIT
118 AROS_LH1(BPTR, devClose,
119 AROS_LHA(struct IOBTHCIReq *, ioreq, A1),
120 DEVBASETYPEPTR, base, 2, dev)
122 AROS_LIBFUNC_INIT
124 BPTR ret;
125 struct NepClassBT *ncp = (struct NepClassBT *) ioreq->iobt_Req.io_Unit;
127 KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq, base));
129 ret = BNULL;
130 /* Try to flush the last buffer */
131 Forbid();
132 if(ncp->ncp_Unit.unit_MsgPort.mp_SigTask)
134 Signal(ncp->ncp_Unit.unit_MsgPort.mp_SigTask, 1L<<(ncp->ncp_Unit.unit_MsgPort.mp_SigBit));
136 Permit();
138 /* Allow queuing */
139 ncp->ncp_DenyRequests = FALSE;
141 ncp->ncp_Unit.unit_OpenCnt--;
142 ioreq->iobt_Req.io_Unit = (APTR) -1;
143 ioreq->iobt_Req.io_Device = (APTR) -1;
145 if(--base->np_Library.lib_OpenCnt == 0)
147 if(base->np_Library.lib_Flags & LIBF_DELEXP)
149 KPRINTF(5, ("devClose: calling expunge...\n"));
150 ret = AROS_LC1(BPTR, devExpunge,
151 AROS_LCA(DEVBASETYPEPTR, base, D0),
152 DEVBASETYPEPTR, base, 3, dev);
156 KPRINTF(5, ("devClose: lib_OpenCnt = %ld\n", base->np_Library.lib_OpenCnt));
158 return(ret);
160 AROS_LIBFUNC_EXIT
164 AROS_LH1(BPTR, devExpunge,
165 AROS_LHA(DEVBASETYPEPTR, extralh, D0),
166 DEVBASETYPEPTR, base, 3, dev)
168 AROS_LIBFUNC_INIT
170 BPTR ret;
172 KPRINTF(10, ("devExpunge base: 0x%08lx\n", base));
174 ret = BNULL;
176 if(base->np_Library.lib_OpenCnt == 0)
178 KPRINTF(5, ("devExpunge: Unloading...\n"));
180 CloseLibrary(base->np_UtilityBase);
182 ret = base->np_SegList;
184 KPRINTF(5, ("devExpunge: removing device node 0x%08lx\n",
185 &base->np_Library.lib_Node));
186 Remove(&base->np_Library.lib_Node);
188 KPRINTF(5, ("devExpunge: FreeMem()...\n"));
189 FreeMem((char *) base - base->np_Library.lib_NegSize,
190 (ULONG) (base->np_Library.lib_NegSize + base->np_Library.lib_PosSize));
192 KPRINTF(5, ("devExpunge: Unloading done! " DEVNAME " expunged!\n\n"));
194 return(ret);
196 else
198 KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n"));
199 base->np_Library.lib_Flags |= LIBF_DELEXP;
202 return(BNULL);
204 AROS_LIBFUNC_EXIT
207 AROS_LH0(DEVBASETYPEPTR, devReserved,
208 DEVBASETYPEPTR, base, 4, dev)
210 AROS_LIBFUNC_INIT
211 return NULL;
212 AROS_LIBFUNC_EXIT
215 AROS_LH1(void, devBeginIO,
216 AROS_LHA(struct IOBTHCIReq *, ioreq, A1),
217 DEVBASETYPEPTR, base, 5, dev)
219 AROS_LIBFUNC_INIT
221 struct NepClassBT *ncp = (struct NepClassBT *) ioreq->iobt_Req.io_Unit;
222 WORD ret = IOERR_NOCMD;
224 KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->iobt_Req.io_Command));
226 ioreq->iobt_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
227 ioreq->iobt_Req.io_Error = 0;
229 if(ioreq->iobt_Req.io_Command < NSCMD_DEVICEQUERY)
231 switch (ioreq->iobt_Req.io_Command)
233 case BTCMD_ADDMSGPORT:
234 if(ncp->ncp_EventMsgPort)
236 ret = BTIOERR_BADPARAMS;
237 } else {
238 ncp->ncp_EventMsgPort = ioreq->iobt_Data;
239 ret = RC_OK;
241 break;
243 case BTCMD_REMMSGPORT:
244 if(ncp->ncp_EventMsgPort != ioreq->iobt_Data)
246 ret = BTIOERR_BADPARAMS;
247 } else {
248 ncp->ncp_EventMsgPort = NULL;
249 ret = RC_OK;
251 break;
253 case BTCMD_QUERYDEVICE:
254 ret = cmdQueryDevice(ioreq, ncp, base);
255 break;
257 case BTCMD_WRITEHCI:
258 case BTCMD_READEVENT:
259 case BTCMD_READACL:
260 case BTCMD_WRITEACL:
261 case BTCMD_SETUPSCO:
262 case BTCMD_READSCO:
263 case BTCMD_WRITESCO:
264 case CMD_FLUSH:
265 case CMD_RESET:
266 case CMD_CLEAR:
267 if(!ncp->ncp_DenyRequests)
269 ioreq->iobt_Req.io_Flags &= ~IOF_QUICK;
270 ret = RC_DONTREPLY;
271 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
272 } else {
273 ret = IOERR_ABORTED;
275 break;
277 default:
278 ret = IOERR_NOCMD;
279 break;
281 } else {
282 switch(ioreq->iobt_Req.io_Command)
284 case NSCMD_DEVICEQUERY:
285 ret = cmdNSDeviceQuery((struct IOStdReq *) ioreq, ncp, base);
286 break;
288 default:
289 ret = IOERR_NOCMD;
290 break;
294 if(ret != RC_DONTREPLY)
296 KPRINTF(1, ("TermIO\n"));
297 if (ret != RC_OK)
299 /* Set error codes
301 ioreq->iobt_Req.io_Error = ret & 0xff;
303 /* Terminate the iorequest
305 TermIO(ioreq, base);
308 AROS_LIBFUNC_EXIT
311 AROS_LH1(LONG, devAbortIO,
312 AROS_LHA(struct IOBTHCIReq *, ioreq, A1),
313 DEVBASETYPEPTR, base, 6, dev)
315 AROS_LIBFUNC_INIT
317 struct NepClassBT *ncp = (struct NepClassBT *) ioreq->iobt_Req.io_Unit;
319 struct IOBTHCIReq *iocmp;
321 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq));
323 /* Is it pending?
325 Forbid();
326 if(ioreq->iobt_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
328 if(ncp->ncp_ReadPending == ioreq)
330 ncp->ncp_AbortRead = TRUE;
331 Signal(ncp->ncp_Task, 1L<<ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
332 Permit();
333 return(0);
335 if(ncp->ncp_WritePending == ioreq)
337 ncp->ncp_AbortWrite = TRUE;
338 Signal(ncp->ncp_Task, 1L<<ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
339 Permit();
340 return(0);
342 iocmp = (struct IOBTHCIReq *) ncp->ncp_ReadQueue.lh_Head;
343 while(iocmp->iobt_Req.io_Message.mn_Node.ln_Succ)
345 if(iocmp == ioreq)
347 Remove((struct Node *) ioreq);
348 ioreq->iobt_Req.io_Error = IOERR_ABORTED;
349 ReplyMsg(&ioreq->iobt_Req.io_Message);
350 Permit();
351 return(0);
353 iocmp = (struct IOBTHCIReq *) iocmp->iobt_Req.io_Message.mn_Node.ln_Succ;
355 iocmp = (struct IOBTHCIReq *) ncp->ncp_WriteQueue.lh_Head;
356 while(iocmp->iobt_Req.io_Message.mn_Node.ln_Succ)
358 if(iocmp == ioreq)
360 Remove((struct Node *) ioreq);
361 ioreq->iobt_Req.io_Error = IOERR_ABORTED;
362 ReplyMsg(&ioreq->iobt_Req.io_Message);
363 Permit();
364 return(0);
366 iocmp = (struct IOBTHCIReq *) iocmp->iobt_Req.io_Message.mn_Node.ln_Succ;
369 Permit();
370 return(-1);
372 AROS_LIBFUNC_EXIT
375 /* NSD stuff
378 static
379 const UWORD NSDSupported[] =
381 CMD_RESET, CMD_CLEAR,
382 CMD_FLUSH, CMD_READ,
383 CMD_WRITE,
384 NSCMD_DEVICEQUERY, 0
387 WORD cmdNSDeviceQuery(struct IOStdReq *ioreq,
388 struct NepClassBT *ncp,
389 struct NepBTDevBase *base)
391 struct my_NSDeviceQueryResult *query;
393 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
395 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query));
397 /* NULL ptr?
398 Enough data?
399 Valid request?
401 if((!query) ||
402 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
403 (query->DevQueryFormat != 0) ||
404 (query->SizeAvailable != 0))
406 /* Return error. This is special handling, since iorequest is only
407 guaranteed to be sizeof(struct IOBTHCIReq). If we'd let our
408 devBeginIO dispatcher return the error, it would trash some
409 memory past end of the iorequest (ios2_WireError field).
411 ioreq->io_Error = IOERR_NOCMD;
412 TermIO((struct IOBTHCIReq *) ioreq, base);
414 /* 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_UNKNOWN;
422 query->DeviceSubType = 0;
423 query->SupportedCommands = NSDSupported;
425 /* Return success (note that this will NOT poke ios2_WireError).
427 return RC_OK;
430 /* /// "cmdQueryDevice()" */
432 *======================================================================
433 * cmdQueryDevice(ioreq, unit, base)
434 *======================================================================
436 * This is the device UHCMD_QUERYDEVICE routine.
438 * Returns information about the hardware.
442 WORD cmdQueryDevice(struct IOBTHCIReq *ioreq,
443 struct NepClassBT *ncp,
444 struct NepBTDevBase *base)
446 struct TagItem *taglist = (struct TagItem *) ioreq->iobt_Data;
447 struct TagItem *tag;
449 ULONG count = 0;
451 KPRINTF(10, ("BTCMD_QUERYDEVICE ioreq: 0x%08lx, taglist: 0x%08lx\n", ioreq, taglist));
453 if((tag = FindTagItem(BTA_Author, taglist)))
455 *((STRPTR *) tag->ti_Data) = "Chris Hodges";
456 count++;
458 if((tag = FindTagItem(BTA_ProductName, taglist)))
460 *((STRPTR *) tag->ti_Data) = "Bluetooth USB HCI Interface";
461 count++;
463 if((tag = FindTagItem(BTA_Description, taglist)))
465 *((STRPTR *) tag->ti_Data) = "Interfacing device for USB Bluetooth sticks";
466 count++;
468 if((tag = FindTagItem(BTA_Copyright, taglist)))
470 *((STRPTR *) tag->ti_Data) = "©2005-2009 Chris Hodges";
471 count++;
473 if((tag = FindTagItem(BTA_Version, taglist)))
475 *((IPTR *) tag->ti_Data) = VERSION_NUMBER;
476 count++;
478 if((tag = FindTagItem(BTA_Revision, taglist)))
480 *((IPTR *) tag->ti_Data) = REVISION_NUMBER;
481 count++;
483 if((tag = FindTagItem(BTA_DriverVersion, taglist)))
485 *((IPTR *) tag->ti_Data) = 0x100;
486 count++;
488 ioreq->iobt_Actual = count;
489 return RC_OK;
491 /* \\\ */
495 *===========================================================
496 * TermIO(ioreq, base)
497 *===========================================================
499 * Return completed ioreq to sender.
503 void TermIO(struct IOBTHCIReq *ioreq,
504 struct NepBTDevBase *base)
506 ioreq->iobt_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
508 /* If not quick I/O, reply the message
510 if(!(ioreq->iobt_Req.io_Flags & IOF_QUICK))
512 ReplyMsg(&ioreq->iobt_Req.io_Message);