2 Copyright (C) 2006 by Michal Schulz
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the
17 Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <aros/debug.h>
24 #include <aros/libcall.h>
25 #include <aros/asmcall.h>
28 #include <dos/dosextens.h>
31 #include <usb/usb_core.h>
35 #include <proto/oop.h>
36 #include <proto/dos.h>
38 static usb_interface_descriptor_t
*find_idesc(usb_config_descriptor_t
*cd
, int ifaceidx
, int altidx
)
41 char *end
= p
+ AROS_LE2WORD(cd
->wTotalLength
);
42 usb_interface_descriptor_t
*d
;
43 int curidx
, lastidx
, curaidx
= 0;
45 for (curidx
= lastidx
= -1; p
< end
; ) {
46 d
= (usb_interface_descriptor_t
*)p
;
48 if (d
->bLength
== 0) /* bad descriptor */
51 if (p
<= end
&& d
->bDescriptorType
== UDESC_INTERFACE
) {
52 if (d
->bInterfaceNumber
!= lastidx
) {
53 lastidx
= d
->bInterfaceNumber
;
58 if (ifaceidx
== curidx
&& altidx
== curaidx
)
65 static AROS_INTH1(HidInterrupt
, HidData
*, hid
)
71 /* Invalidate the cache. Report has been sent through DMA */
72 CacheClearE(hid
->buffer
, hid
->buflen
, CACRF_InvalidateD
);
74 if (hid
->nreport
!= 1)
76 reportid
= hid
->buffer
[0];
78 /* And let the class handle it */
79 HIDD_USBHID_ParseReport(hid
->o
, reportid
, &hid
->buffer
[1], hid
->buflen
);
82 HIDD_USBHID_ParseReport(hid
->o
, 0, hid
->buffer
, hid
->buflen
);
89 BOOL
METHOD(HID
, Hidd_USBHID
, GetReportDescriptor
)
91 USBDevice_Request req
;
94 OOP_GetAttr(o
, aHidd_USBDevice_InterfaceNumber
, &ifnr
);
96 req
.bmRequestType
= UT_READ_INTERFACE
;
97 req
.bRequest
= UR_GET_DESCRIPTOR
;
98 req
.wValue
= AROS_WORD2LE(UDESC_REPORT
<< 8 | 0);
99 req
.wIndex
= AROS_WORD2LE(ifnr
);
100 req
.wLength
= AROS_WORD2LE(msg
->length
);
102 return HIDD_USBDevice_ControlMessage(o
, NULL
, &req
, msg
->buffer
, msg
->length
);
105 BOOL
METHOD(HID
, Hidd_USBHID
, SetIdle
)
107 USBDevice_Request req
;
110 D(bug("[HID] HID::SetIdle(%d, %d)\n", msg
->duration
, msg
->id
));
112 OOP_GetAttr(o
, aHidd_USBDevice_InterfaceNumber
, &ifnr
);
114 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
115 req
.bRequest
= UR_SET_IDLE
;
116 req
.wValue
= AROS_WORD2LE(msg
->duration
<< 8| msg
->id
);
117 req
.wIndex
= AROS_WORD2LE(ifnr
);
118 req
.wLength
= AROS_WORD2LE(0);
120 return HIDD_USBDevice_ControlMessage(o
, NULL
, &req
, NULL
, 0);
123 BOOL
METHOD(HID
, Hidd_USBHID
, SetReport
)
125 USBDevice_Request req
;
129 uint8_t *b
= msg
->report
;
132 bug("[HID] HID::SetReport(%d, %d, \"", msg
->type
, msg
->id
);
133 for (i
=0; i
< msg
->length
; i
++)
138 OOP_GetAttr(o
, aHidd_USBDevice_InterfaceNumber
, &ifnr
);
140 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
141 req
.bRequest
= UR_SET_REPORT
;
142 req
.wValue
= AROS_WORD2LE(msg
->type
<< 8| msg
->id
);
143 req
.wIndex
= AROS_WORD2LE(ifnr
);
144 req
.wLength
= AROS_WORD2LE(msg
->length
);
146 return HIDD_USBDevice_ControlMessage(o
, NULL
, &req
, msg
->report
, msg
->length
);
149 BOOL
METHOD(HID
, Hidd_USBHID
, SetProtocol
)
151 USBDevice_Request req
;
154 D(bug("[HID] HID::SetProtocol(%s)\n", msg
->protocol
? "Report":"Boot"));
156 OOP_GetAttr(o
, aHidd_USBDevice_InterfaceNumber
, &ifnr
);
158 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
159 req
.bRequest
= UR_SET_PROTOCOL
;
160 req
.wValue
= AROS_WORD2LE(msg
->protocol
);
161 req
.wIndex
= AROS_WORD2LE(ifnr
);
162 req
.wLength
= AROS_WORD2LE(0);
164 return HIDD_USBDevice_ControlMessage(o
, NULL
, &req
, NULL
, 0);
167 void METHOD(HID
, Hidd_USBHID
, ParseReport
)
169 HidData
*hid
= OOP_INST_DATA(cl
, o
);
171 uint8_t *data
= hid
->buffer
;
172 int len
= hid
->buflen
;
174 if (hid
->nreport
!= 1)
180 D(bug("[HID] Unknown report id %d: ", msg
->id
));
182 for (i
=0; i
< len
; i
++)
183 D(bug("%02x ", data
[i
]));
188 usb_hid_descriptor_t
*METHOD(HID
, Hidd_USBHID
, GetHidDescriptor
)
190 HidData
*hid
= OOP_INST_DATA(cl
, o
);
191 usb_hid_descriptor_t
*hdesc
= NULL
, *hd
;
195 OOP_GetAttr(o
, aHidd_USBDevice_Interface
, &iface
);
199 usb_interface_descriptor_t
*idesc
= find_idesc(hid
->cdesc
, iface
, 0);
200 D(bug("[HID] cdesc=%p, idesc=%p\n", hid
->cdesc
, idesc
));
205 p
= (char *)idesc
+ idesc
->bLength
;
206 end
= (char *)hid
->cdesc
+ AROS_LE2WORD(hid
->cdesc
->wTotalLength
);
208 for (; p
< end
; p
+= hd
->bLength
)
210 hd
= (usb_hid_descriptor_t
*)p
;
211 D(bug("[HID] p=%p bLength=%d bDescriptorType=%x\n", p
, hd
->bLength
, hd
->bDescriptorType
));
213 if (p
+ hd
->bLength
<= end
&& hd
->bDescriptorType
== UDESC_HID
)
218 if (hd
->bDescriptorType
== UDESC_INTERFACE
)
222 D(bug("[HID] hdesc=%p\n", hdesc
));
226 OOP_Object
*METHOD(HID
, Root
, New
)
228 D(bug("[HID] HID::New()\n"));
230 BASE(cl
->UserData
)->LibNode
.lib_OpenCnt
++;
232 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
235 HidData
*hid
= OOP_INST_DATA(cl
, o
);
236 usb_config_descriptor_t cdesc
;
239 OOP_GetAttr(o
, aHidd_USBDevice_Interface
, &iface
);
244 D(bug("[HID::New()] HidData=%p Configuring the device...\n", hid
));
246 /* Configure the HID device */
247 HIDD_USBDevice_Configure(o
, 0);
249 D(bug("[HID::New()] Getting device and config descriptors...\n"));
250 HIDD_USBDevice_GetDeviceDescriptor(o
, &hid
->ddesc
);
251 HIDD_USBDevice_GetConfigDescriptor(o
, 0, &cdesc
);
253 HIDD_USBHID_SetIdle(o
, 0, 0);
255 if (AROS_LE2WORD(cdesc
.wTotalLength
))
256 hid
->cdesc
= AllocVecPooled(SD(cl
)->MemPool
, AROS_LE2WORD(cdesc
.wTotalLength
));
262 D(bug("[HID::New()] Getting config descriptor of size %d...\n",AROS_LE2WORD(cdesc
.wTotalLength
)));
264 HIDD_USBDevice_GetDescriptor(o
, UDESC_CONFIG
, 0, AROS_LE2WORD(cdesc
.wTotalLength
), hid
->cdesc
);
265 hid
->hd
= HIDD_USBHID_GetHidDescriptor(o
);
267 D(bug("[HID::New()] Hid descriptor @ %p\n", hid
->hd
));
268 D(bug("[HID::New()] Number of Report descriptors: %d\n", hid
->hd
->bNumDescriptors
));
269 hid
->reportLength
= AROS_LE2WORD(hid
->hd
->descrs
[0].wDescriptorLength
);
270 hid
->report
= AllocVecPooled(SD(cl
)->MemPool
, hid
->reportLength
);
272 D(bug("[HID::New()] Getting report descriptor 1 of size %d\n", hid
->reportLength
));
274 HIDD_USBHID_GetReportDescriptor(o
, hid
->reportLength
, hid
->report
);
276 hid
->nreport
= hid_maxrepid(hid
->report
, hid
->reportLength
) + 1;
279 for (repid
= 0; repid
< hid
->nreport
; repid
++)
281 uint16_t repsize
= hid_report_size(hid
->report
, hid
->reportLength
, hid_input
, repid
);
282 D(bug("[HID::New()] Report %d: size %d\n", repid
, repsize
));
283 if (repsize
> hid
->buflen
)
284 hid
->buflen
= repsize
;
287 /* If there is more than one report ID, make a space for report ID */
288 if (hid
->nreport
!= 1)
291 hid
->buffer
= AllocVecPooled(SD(cl
)->MemPool
, hid
->buflen
);
293 D(bug("[HID::New()] Length of input report is %d\n", hid
->buflen
));
295 usb_endpoint_descriptor_t
*ep
= HIDD_USBDevice_GetEndpoint(o
, iface
, 0);
297 D(bug("[HID::New()] Endpoint descriptor %p addr %02x\n", ep
, ep
->bEndpointAddress
));
301 if ((ep
->bmAttributes
& UE_XFERTYPE
) != UE_INTERRUPT
)
303 bug("[HID::New()] Wrong endpoint type\n");
304 // TODO: unconfigure, error, coercemethod
307 OOP_Object
*drv
= NULL
;
308 OOP_GetAttr(o
, aHidd_USBDevice_Bus
, (IPTR
*)&drv
);
312 hid
->interrupt
.is_Data
= hid
;
313 hid
->interrupt
.is_Code
= (VOID_FUNC
)HidInterrupt
;
314 hid
->intr_pipe
= HIDD_USBDevice_CreatePipe(o
, PIPE_Interrupt
, ep
->bEndpointAddress
, ep
->bInterval
, AROS_LE2WORD(ep
->wMaxPacketSize
), 0);
315 if (hid
->intr_pipe
) {
316 HIDD_USBDrv_AddInterrupt(drv
, hid
->intr_pipe
, hid
->buffer
, hid
->buflen
, &hid
->interrupt
);
317 D(bug("[HID] HID::New() = %p\n", o
));
323 FreeVecPooled(SD(cl
)->MemPool
, hid
->report
);
325 FreeVecPooled(SD(cl
)->MemPool
, hid
->buffer
);
327 FreeVecPooled(SD(cl
)->MemPool
, hid
->cdesc
);
331 D(bug("[HID] HID::New() = NULL\n"));
333 BASE(cl
->UserData
)->LibNode
.lib_OpenCnt
--;
338 void METHOD(HID
, Root
, Dispose
)
340 HidData
*hid
= OOP_INST_DATA(cl
, o
);
341 OOP_Object
*drv
= NULL
;
342 struct Library
*base
= &BASE(cl
->UserData
)->LibNode
;
344 OOP_GetAttr(o
, aHidd_USBDevice_Bus
, (intptr_t *)&drv
);
346 HIDD_USBDrv_RemInterrupt(drv
, hid
->intr_pipe
, &hid
->interrupt
);
347 HIDD_USBDevice_DeletePipe(o
, hid
->intr_pipe
);
350 FreeVecPooled(SD(cl
)->MemPool
, hid
->report
);
352 FreeVecPooled(SD(cl
)->MemPool
, hid
->cdesc
);
354 FreeVecPooled(SD(cl
)->MemPool
, hid
->buffer
);
356 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
362 * The MatchCLID library call gets the device descriptor and full config
363 * descriptor (including the interface and endpoint descriptors). It will
364 * return CLID_Hidd_USBHID if the requested interface conforms to HID.
366 AROS_LH3(void *, MatchCLID
,
367 AROS_LHA(usb_device_descriptor_t
*, dev
, A0
),
368 AROS_LHA(usb_config_descriptor_t
*, cfg
, A1
),
369 AROS_LHA(int, i
, D0
),
370 LIBBASETYPEPTR
, LIBBASE
, 5, HID
)
376 D(bug("[HID] MatchCLID(%p, %p)\n", dev
, cfg
));
378 if (dev
->bDeviceClass
== UDCLASS_IN_INTERFACE
)
380 usb_interface_descriptor_t
*iface
= find_idesc(cfg
, i
, 0);
382 D(bug("[HID] UDCLASS_IN_INTERFACE OK. Checking interface %d\n", i
));
383 D(bug("[HID] iface %d @ %p protocol %d\n", i
, iface
, iface
->bInterfaceProtocol
));
385 if (iface
->bInterfaceClass
== UICLASS_HID
)
387 D(bug("[HID] HID Class found. Handling it.\n"));
389 switch (iface
->bInterfaceProtocol
)
392 D(bug("[HID] Keyboard protocol\n"));
393 clid
= CLID_Hidd_USBKeyboard
;
397 D(bug("[HID] Mouse protocol\n"));
398 clid
= CLID_Hidd_USBMouse
;
402 D(bug("[HID] Protocol unknown, using default class\n"));
403 clid
= CLID_Hidd_USBHID
;