1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 cc -fno-rtti -fno-exceptions -fcheck-new -fvtable-thunks -I.. -I../../BUILD/obj/EXPORT_HDRS/libkern -I../../BUILD/obj/EXPORT_HDRS/osfmk USBTest.cpp ../../BUILD/obj/RELEASE_PPC/IOKit/User/libIOKit.A.dylib -o USBTest
25*/
26
27#include <ctype.h>
28#include <stdlib.h>
29#include <stdio.h>
30
31#include <IOKit/IOLib.h>
32#include <IOKit/IOKitLib.h>
33#include <IOKit/IOContainers.h>
34#include <IOKit/IOSerialize.h>
35#include <IOKit/usb/IOUSBLib.h>
36
37mach_port_t	master_device_port;
38
39void printUSBInterface(IOUSBInterface *intf)
40{
41    int i;
42    int nEP = intf->descriptor->numEndpoints;
43    printf("%d endpoints\n", nEP);
44
45    for(i=0; i<nEP; i++) {
46        IOUSBEndpoint *ep = intf->endpoints[i];
47        printf("ep #%d, dir %d, type %d, maxPack %d\n",
48            ep->number, ep->direction, ep->transferType,
49            ep->maxPacketSize);
50    }
51}
52
53void processDevice(IOUSBIteratorRef enumer)
54{
55    kern_return_t		kr2;
56    IOUSBDeviceDescriptor	desc;
57    IOUSBInterfaceDescriptor	intf;
58
59    kr2 = IOUSBGetDeviceDescriptor(enumer, &desc, sizeof(desc));
60    if (kr2) {
61        printf("IOUSBGetDeviceDescriptor failed, kr=%d\n", kr2);
62            return;
63    }
64    printf("Device Descriptor\n------------\n");
65    printf("length = %d\n", desc.length);
66    printf("descType = %d\n", desc.descType);
67    printf("usbRel = %d\n", desc.usbRel);
68    printf("deviceClass = %d\n", desc.deviceClass);
69    printf("deviceSubClass = %d\n", desc.deviceSubClass);
70    printf("protocol = %d\n", desc.protocol);
71    printf("maxPacketSize = %d\n", desc.maxPacketSize);
72    printf("vendor = %d\n", desc.vendor);
73    printf("product = %d\n", desc.product);
74    printf("devRel = %d\n", desc.devRel);
75    printf("manuIdx = %d\n", desc.manuIdx);
76    printf("prodIdx = %d\n", desc.prodIdx);
77    printf("serialIdx = %d\n", desc.serialIdx);
78    printf("numConf = %d\n", desc.numConf);
79
80
81
82    kr2 = IOUSBGetInterfaceDescriptor(enumer, &intf, sizeof(intf));
83    if (kr2) {
84        UInt8 conf = 123;
85        IOUSBDeviceRef dev;
86        printf("IOUSBGetInterfaceDescriptor failed, kr=%x\n", kr2);
87
88        kr2 = IOUSBNewDeviceRef( enumer, &dev);
89
90        if(kIOReturnSuccess != kr2) {
91            printf("IOUSBNewDeviceRef: err = %x\n", kr2);
92        }
93        else {
94            kr2 = IOUSBGetConfiguration(dev, &conf);
95            if(kIOReturnSuccess == kr2)
96                printf("IOUSBGetConfiguration: conf = %d\n", conf);
97            else
98                printf("IOUSBGetConfiguration: err = %x\n", kr2);
99            if(0 == conf || kIOReturnSuccess != kr2) {
100                conf = 1;
101                kr2 = IOUSBSetConfiguration(dev, conf);
102                if(kIOReturnSuccess == kr2)
103                    printf("IOUSBSetConfiguration: conf = %d\n", conf);
104                else
105                    printf("IOUSBSetConfiguration: err = %x\n", kr2);
106                kr2 = IOUSBGetConfiguration(dev, &conf);
107                if(kIOReturnSuccess == kr2)
108                    printf("IOUSBGetConfiguration: conf = %d\n", conf);
109                else
110                    printf("IOUSBGetConfiguration: err = %x\n", kr2);
111            }
112            // Get full configuration
113            char hack[1024];
114            IOUSBConfigurationDescriptorPtr conf;
115            kr2 = IOUSBGetConfigDescriptor(dev, 0, &conf);
116            if(kIOReturnSuccess == kr2) {
117                printf("IOUSBGetConfigDescriptor(%d) %x %x %x %x %x %x %x\n",
118                 USBToHostWord(conf->totalLength), conf->length,
119 			conf->descriptorType, conf->numInterfaces,
120			conf->configValue,
121                        conf->configStrIndex, conf->attributes, conf->maxPower);
122            }
123            else
124                printf("IOUSBGetConfigDescriptor: err = %x\n", kr2);
125
126            // Try to get first string descriptor
127            UInt16 size = sizeof(hack);
128            kr2 = IOUSBDeviceRequest(dev,
129                USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice),
130                kUSBRqGetDescriptor, (kUSBStringDesc << 8) | 1, 0x409,
131                hack, &size);
132            if(kIOReturnSuccess == kr2) {
133                int i;
134                printf("String 1(%d/%d):", size, hack[0]);
135                for(i=2; i<hack[0]; i+=2)
136                    printf("%c", hack[i]);
137                printf("\n");
138            }
139            else
140                printf("IOUSBDeviceRequest: err = %x\n", kr2);
141
142            IOUSBInterface *ioint;
143            IOUSBFindInterfaceRequest freq;
144
145            freq.theClass = 0;		// requested class,    0 = don't care
146            freq.subClass = 0;		// requested subclass; 0 = don't care
147            freq.protocol = 0;		// requested protocol; 0 = don't care
148            freq.busPowered = 0;	// 1 = not bus powered, 2 = bus powered,
149                                        // 0 = don't care
150            freq.selfPowered = 0;	// 1 = not self powered, 2 = self powered,
151                                        // 0 = don't care
152            freq.remoteWakeup = 0;	// 1 = doesn't support remote wakeup; 2 = does
153                                        // 0 = don't care
154            freq.reserved = 0;
155            freq.maxPower = 0;		// max power in 2ma increments; 0 = don't care
156            freq.alternateIndex = 0;	// alternate #; 0xff = find first only
157            freq.configIndex = 0;	// 0 = start at beginning
158            freq.interfaceIndex = 0;	// 0 = start at beginning
159
160            while(ioint = IOUSBFindNextInterface(dev, &freq)) {
161                printUSBInterface(ioint);
162
163                IOUSBDisposeInterface(ioint);
164            }
165            // test vendor specific read/write for ISVF
166            if(desc.vendor == 0xc706) {
167                printf("Found ImageStudioVF!\n");
168                size = 3;
169                kr2 = IOUSBDeviceRequest(dev,
170                    USBMakeBMRequestType(kUSBIn, kUSBVendor, kUSBDevice),
171                    4, 0, 0,
172                    hack, &size);
173                if(kIOReturnSuccess == kr2) {
174                    int i;
175                    printf("Read %d:", size);
176                    for(i=0; i<size; i++)
177                        printf("%d ", hack[i]);
178                    printf("\n");
179                }
180                else {
181                    printf("IOUSBDeviceRequest: err = %x\n", kr2);
182                    return;
183                }
184                size = 3;
185                hack[0]++;
186                hack[1] += 2;
187                hack[2] += 3;
188                kr2 = IOUSBDeviceRequest(dev,
189                    USBMakeBMRequestType(kUSBOut, kUSBVendor, kUSBDevice),
190                    4, 0, 0,
191                    hack, &size);
192                if(kIOReturnSuccess != kr2) {
193                    printf("IOUSBDeviceRequest: err = %x\n", kr2);
194                    return;
195                }
196                size = 3;
197                kr2 = IOUSBDeviceRequest(dev,
198                    USBMakeBMRequestType(kUSBIn, kUSBVendor, kUSBDevice),
199                    4, 0, 0,
200                    hack, &size);
201                if(kIOReturnSuccess == kr2) {
202                    int i;
203                    printf("Now Read %d:", size);
204                    for(i=0; i<size; i++)
205                        printf("%d ", hack[i]);
206                    printf("\n");
207                }
208                else {
209                    printf("IOUSBDeviceRequest: err = %x\n", kr2);
210                    return;
211                }
212
213            }
214            IOUSBDisposeRef(dev);
215        }
216    }
217    else {
218        printf("Interface Descriptor\n------------\n");
219        printf("length = %d\n", intf.length);
220        printf("descType = %d\n", intf.descriptorType);
221        printf("interfaceNumber = %d\n", intf.interfaceNumber);
222        printf("alternateSetting = %d\n", intf.alternateSetting);
223        printf("numEndpoints = %d\n", intf.numEndpoints);
224        printf("interfaceClass = %d\n", intf.interfaceClass);
225        printf("interfaceSubClass = %d\n", intf.interfaceSubClass);
226        printf("interfaceProtocol = %d\n", intf.interfaceProtocol);
227        printf("interfaceStrIndex = %d\n", intf.interfaceStrIndex);
228
229        // See if we have a HID interface, if so open and read the interupt pipe a few times.
230        if(intf.interfaceClass == kUSBHIDClass) {
231            char hack[1024];
232            UInt16 size;
233            IOUSBDeviceRef dev;
234            IOUSBPipeRef pipe;
235            int i;
236
237            printf("HID Interface\n");
238            kr2 = IOUSBNewDeviceRef( enumer, &dev);
239            if(kIOReturnSuccess != kr2)
240                return;
241            /*
242             * If a boot device, SetProtocol to Boot protocol
243             * SetIdle to read complete after 24mSec
244             * Open interface's first pipe
245             * Read 8 bytes from pipe
246             * Close pipe
247             */
248            size = 0;
249            if(1 == intf.interfaceSubClass) {	// 1 = Boot Interface subclass
250                kr2 = IOUSBDeviceRequest(dev,
251                    USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface),
252                    kHIDRqSetProtocol, kHIDBootProtocolValue,
253		    intf.interfaceNumber,
254                    NULL, &size);
255            }
256            if(kIOReturnSuccess != kr2) {
257                printf("HIDRqSetProtocol: err = %x\n", kr2);
258                return;
259            }
260#if 0
261            size = 0;
262            kr2 = IOUSBDeviceRequest(dev,
263                USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface),
264                kHIDRqSetIdle, (24/4)<<8, intf.interfaceNumber,
265                NULL, &size);
266            if(kIOReturnSuccess != kr2) {
267                printf("HIDRqSetIdle: err = %x\n", kr2);
268                continue;
269            }
270#endif
271            size = 4;
272            kr2 = IOUSBDeviceRequest(dev,
273                USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface),
274                kHIDRqGetReport, kHIDRtInputReport<<8,
275                intf.interfaceNumber,
276                hack, &size);
277            if(kIOReturnSuccess != kr2) {
278                printf("HIDRqGetReport: err = %x\n", kr2);
279                return;
280            }
281            printf("Read %d:%d %d %d %d\n", size,
282                hack[0], hack[1], hack[2], hack[3]);
283
284            IOUSBInterface *ioint;
285            IOUSBFindInterfaceRequest freq;
286            IOUSBEndpoint *ep;
287
288            freq.theClass = intf.interfaceClass;
289            freq.subClass = intf.interfaceSubClass;
290            freq.protocol = intf.interfaceProtocol;
291            freq.busPowered = 0;
292            freq.selfPowered = 0;
293            freq.remoteWakeup = 0;
294            freq.reserved = 0;
295            freq.maxPower = 0;
296            freq.alternateIndex = 0;
297            freq.configIndex = 0;
298            freq.interfaceIndex = 0;
299
300            ioint = IOUSBFindNextInterface(dev, &freq);
301            if(!ioint) {
302                printf("No HID Interfaces found!!\n");
303                return;
304            }
305            printUSBInterface(ioint);
306            ep = 0;
307            for(i=0; i < ioint->descriptor->numEndpoints; i++) {
308                if(ioint->endpoints[i]->direction == kUSBIn &&
309                    ioint->endpoints[i]->transferType == kUSBInterrupt) {
310                    ep = ioint->endpoints[i];
311                    break;
312                }
313            }
314            if(ep) {
315                kr2 = IOUSBOpenPipe(dev, ep, &pipe);
316                if(kIOReturnSuccess != kr2) {
317                    printf("IOUSBOpenPipe: err = %x\n", kr2);
318                    IOUSBDisposeRef(dev);
319                    return;
320                }
321                for(int i=0; i<4; i++) {
322                    UInt32 len = 4;
323                    kr2 = IOUSBReadPipe(pipe, hack, &len);
324                    if(kIOReturnSuccess != kr2) {
325                        printf("IOUSBReadPipe: err = %x\n", kr2);
326                        break;
327                    }
328                    else {
329                        printf("Read %d:%d %d %d %d\n", len,
330                            hack[0], hack[1], hack[2], hack[3]);
331                    }
332                }
333                IOUSBClosePipe(pipe);
334            }
335            IOUSBDisposeInterface(ioint);
336            IOUSBDisposeRef(dev);
337        }
338    }
339}
340int pokeDevices(IOUSBMatch * descMatch)
341{
342    kern_return_t	kr;
343    IOUSBIteratorRef	enumer;
344    mach_port_t		port;
345    unsigned long int  	notifyType;
346    unsigned long int  	ref;
347    struct {
348        mach_msg_header_t	msgHdr;
349        OSNotificationHeader	notifyHeader;
350        mach_msg_trailer_t	trailer;
351    } msg;
352
353    kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
354    if(KERN_SUCCESS != kr) {
355        printf("Failed to create port!:%d\n", kr);
356        return kr;
357    }
358
359    kr = IOUSBCreateIterator(master_device_port, port, descMatch, &enumer);
360    if(kIOReturnSuccess != kr) {
361        printf("IOUSBCreateIterator = %d\n", kr);
362        return kr;
363    }
364
365    // First process any devices already connected
366    while(kIOReturnSuccess == IOUSBIteratorNext(enumer)) {
367        processDevice(enumer);
368    }
369
370    // Now wait for a new device (or devices) to appear and
371    // process them.
372    kr = mach_msg(&msg.msgHdr, MACH_RCV_MSG,
373                0, sizeof(msg), port, 0, MACH_PORT_NULL);
374    kr = OSGetNotificationFromMessage( &msg.msgHdr, 0, &notifyType, &ref,
375                    0, 0 );
376
377    if(ref == (unsigned long int)enumer) {
378        while(kIOReturnSuccess == IOUSBIteratorNext(enumer)) {
379            processDevice(enumer);
380        }
381    }
382    else
383        printf("Unexpected notification type %d, ref %d\n",
384		notifyType, ref);
385    kr = IOUSBDisposeIterator( enumer);
386    return kr;
387}
388
389int
390main(int argc, char **argv)
391{
392    kern_return_t	kr;
393
394    IOUSBMatch match = {
395    kIOUSBAnyClass,
396    kIOUSBAnySubClass,
397    kIOUSBAnyProtocol,
398    kIOUSBAnyVendor,
399    kIOUSBAnyProduct
400    };
401
402    if(argc > 1)
403        match.usbClass = atoi(argv[1]);
404    if(argc > 2)
405        match.usbSubClass = atoi(argv[2]);
406    if(argc > 3)
407        match.usbProtocol = atoi(argv[3]);
408    if(argc > 4)
409        match.usbVendor = atoi(argv[4]);
410    if(argc > 5)
411        match.usbProduct = atoi(argv[5]);
412
413    /*
414     * Get master device port
415     */
416    kr = IOMasterPort(bootstrap_port,
417                              &master_device_port);
418
419    if (kr != KERN_SUCCESS)
420        printf("IOMasterPort failed: %lx\n", kr);
421
422    printf("Looking for devices matching class=%d subclass=%d ",
423        match.usbClass, match.usbSubClass);
424    printf("protocol=%d vendor=%d product=%d\n", match.usbProtocol,
425        match.usbVendor, match.usbProduct);
426    pokeDevices(&match);
427}
428
429