1 /* dev.c - usbbluetooth.device by Chris Hodges
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
))
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
;
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
));
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
)
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
;
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
;
84 ioreq
->iobt_Req
.io_Unit
= (struct Unit
*) ncp
;
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"));
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
++;
102 ncp
->ncp_DenyRequests
= FALSE
;
108 ioreq
->iobt_Req
.io_Unit
= (APTR
) -1;
109 ioreq
->iobt_Req
.io_Device
= (APTR
) -1;
110 base
->np_Library
.lib_OpenCnt
--;
118 AROS_LH1(BPTR
, devClose
,
119 AROS_LHA(struct IOBTHCIReq
*, ioreq
, A1
),
120 DEVBASETYPEPTR
, base
, 2, dev
)
125 struct NepClassBT
*ncp
= (struct NepClassBT
*) ioreq
->iobt_Req
.io_Unit
;
127 KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq
, base
));
130 /* Try to flush the last buffer */
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
));
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
));
164 AROS_LH1(BPTR
, devExpunge
,
165 AROS_LHA(DEVBASETYPEPTR
, extralh
, D0
),
166 DEVBASETYPEPTR
, base
, 3, dev
)
172 KPRINTF(10, ("devExpunge base: 0x%08lx\n", base
));
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"));
198 KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n"));
199 base
->np_Library
.lib_Flags
|= LIBF_DELEXP
;
207 AROS_LH0(DEVBASETYPEPTR
, devReserved
,
208 DEVBASETYPEPTR
, base
, 4, dev
)
215 AROS_LH1(void, devBeginIO
,
216 AROS_LHA(struct IOBTHCIReq
*, ioreq
, A1
),
217 DEVBASETYPEPTR
, base
, 5, dev
)
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
;
238 ncp
->ncp_EventMsgPort
= ioreq
->iobt_Data
;
243 case BTCMD_REMMSGPORT
:
244 if(ncp
->ncp_EventMsgPort
!= ioreq
->iobt_Data
)
246 ret
= BTIOERR_BADPARAMS
;
248 ncp
->ncp_EventMsgPort
= NULL
;
253 case BTCMD_QUERYDEVICE
:
254 ret
= cmdQueryDevice(ioreq
, ncp
, base
);
258 case BTCMD_READEVENT
:
267 if(!ncp
->ncp_DenyRequests
)
269 ioreq
->iobt_Req
.io_Flags
&= ~IOF_QUICK
;
271 PutMsg(&ncp
->ncp_Unit
.unit_MsgPort
, (struct Message
*) ioreq
);
282 switch(ioreq
->iobt_Req
.io_Command
)
284 case NSCMD_DEVICEQUERY
:
285 ret
= cmdNSDeviceQuery((struct IOStdReq
*) ioreq
, ncp
, base
);
294 if(ret
!= RC_DONTREPLY
)
296 KPRINTF(1, ("TermIO\n"));
301 ioreq
->iobt_Req
.io_Error
= ret
& 0xff;
303 /* Terminate the iorequest
311 AROS_LH1(LONG
, devAbortIO
,
312 AROS_LHA(struct IOBTHCIReq
*, ioreq
, A1
),
313 DEVBASETYPEPTR
, base
, 6, dev
)
317 struct NepClassBT
*ncp
= (struct NepClassBT
*) ioreq
->iobt_Req
.io_Unit
;
319 struct IOBTHCIReq
*iocmp
;
321 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq
));
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
);
335 if(ncp
->ncp_WritePending
== ioreq
)
337 ncp
->ncp_AbortWrite
= TRUE
;
338 Signal(ncp
->ncp_Task
, 1L<<ncp
->ncp_Unit
.unit_MsgPort
.mp_SigBit
);
342 iocmp
= (struct IOBTHCIReq
*) ncp
->ncp_ReadQueue
.lh_Head
;
343 while(iocmp
->iobt_Req
.io_Message
.mn_Node
.ln_Succ
)
347 Remove((struct Node
*) ioreq
);
348 ioreq
->iobt_Req
.io_Error
= IOERR_ABORTED
;
349 ReplyMsg(&ioreq
->iobt_Req
.io_Message
);
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
)
360 Remove((struct Node
*) ioreq
);
361 ioreq
->iobt_Req
.io_Error
= IOERR_ABORTED
;
362 ReplyMsg(&ioreq
->iobt_Req
.io_Message
);
366 iocmp
= (struct IOBTHCIReq
*) iocmp
->iobt_Req
.io_Message
.mn_Node
.ln_Succ
;
379 const UWORD NSDSupported
[] =
381 CMD_RESET
, CMD_CLEAR
,
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
));
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.
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).
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
;
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";
458 if((tag
= FindTagItem(BTA_ProductName
, taglist
)))
460 *((STRPTR
*) tag
->ti_Data
) = "Bluetooth USB HCI Interface";
463 if((tag
= FindTagItem(BTA_Description
, taglist
)))
465 *((STRPTR
*) tag
->ti_Data
) = "Interfacing device for USB Bluetooth sticks";
468 if((tag
= FindTagItem(BTA_Copyright
, taglist
)))
470 *((STRPTR
*) tag
->ti_Data
) = "©2005-2009 Chris Hodges";
473 if((tag
= FindTagItem(BTA_Version
, taglist
)))
475 *((IPTR
*) tag
->ti_Data
) = VERSION_NUMBER
;
478 if((tag
= FindTagItem(BTA_Revision
, taglist
)))
480 *((IPTR
*) tag
->ti_Data
) = REVISION_NUMBER
;
483 if((tag
= FindTagItem(BTA_DriverVersion
, taglist
)))
485 *((IPTR
*) tag
->ti_Data
) = 0x100;
488 ioreq
->iobt_Actual
= count
;
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
);