/* Code Sample to demonstrate how one can read a string descriptor from a USB device. */ #include <Types.h> #include <Memory.h> #include <Events.h> #include <DriverServices.h> #include <USB.h> #define TIMEOUT 60 //********* PROTOTYPES ******************// void ProbeEndpointCompletionRoutine(USBPB *usbpb); void ExpertNumToString(SInt32 num, char *str); OSStatus GetStringDescriptor(USBDeviceRef ref, UInt16 index, UInt16 len, UInt8 *buf); extern void USBIdleTask(void); void ProbeEndpointCompletionRoutine(USBPB *usbpb) { if (usbpb->usbStatus == kUSBPending) { // DebugStr("\pcompletition called with pending status!"); usbpb->usbStatus = paramErr; } usbpb->usbRefcon = false; } // This is a simple implementation of numtostring, // This version is fully reentrant void ExpertNumToString(SInt32 num, char *str) { char buf[16]; SInt16 cnt=0; if (num < 0) { num = -num; *str++ = '-'; } do { buf[cnt++] = "0123456789"[num % 10]; num = num/10; } while (num); while (cnt-- > 0) { *str++ = buf[cnt]; } *str = '\0'; } //------------------------------- // //GetStringDescriptor // // Descriptor type == 3 //------------------------------- OSStatus GetStringDescriptor(USBDeviceRef ref, UInt16 index, UInt16 len, UInt8 *buf) { UInt32 startTime; OSStatus status; USBPB *pb; char theText[255] = ""; char tempStr[8] = ""; pb = (USBPB *)NewPtrSysClear(sizeof(*pb)); if (!pb) return(memFullErr); // set up to make the kUSBRqGetDescriptor call pb->pbLength = (sizeof(*pb)); pb->usbReference = ref; pb->usbRefcon = true; pb->usbCompletion = ProbeEndpointCompletionRoutine; pb->pbVersion = kUSBCurrentPBVersion; pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice); pb->usbBRequest = kUSBRqGetDescriptor; pb->usbWValue = 0x0300 | index; pb->usbWIndex = 0x409; /* First get the string length in preparation for the real call */ pb->usbReqCount = 2; // 2-byte length for Unicode strings pb->reserved4 = len; pb->usbBuffer = buf; *buf = 0; // in case we don't get anything back! startTime = TickCount(); status = USBDeviceRequest(pb); if (status && (status != kUSBPending)) { // there was an immediate error - bail! DisposePtr((void*)pb); return(status); } while(pb->usbRefcon /*pb->usbStatus == kUSBPending*/) { USBIdleTask(); if (pb->usbRefcon && ((startTime+TIMEOUT) < TickCount())) { pb->usbRefcon = false; // we got tired of waiting for a response pb->usbStatus = -1; } } if (pb->usbStatus > 0 ) pb->usbStatus = noErr; /* Now make the real call */ if (pb->usbStatus == noErr) { pb->pbLength = (sizeof(*pb)); pb->usbReference = ref; pb->usbRefcon = true; pb->usbCompletion = ProbeEndpointCompletionRoutine; pb->pbVersion = kUSBCurrentPBVersion; pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice); pb->usbBRequest = kUSBRqGetDescriptor; pb->usbWValue = 0x0300 | index; pb->usbWIndex = 0x409; pb->usbReqCount = (UInt32)*buf; // actual data length; pb->reserved4 = len; pb->usbBuffer = buf; *buf = 0; // in case we don't get anything back! startTime = TickCount(); status = USBDeviceRequest(pb); if (status && (status != kUSBPending)) { // there was an immediate error - bail! DisposePtr((void*)pb); return(status); } while(pb->usbRefcon /*pb->usbStatus == kUSBPending*/) { USBIdleTask(); if (pb->usbRefcon && ((startTime+TIMEOUT) < TickCount())) { pb->usbRefcon = false; // we got tired of waiting for a response pb->usbStatus = -1; } } if (pb->usbStatus > 0 ) pb->usbStatus = noErr; } status = pb->usbStatus; if (!status) { DisposePtr((void*)pb); } return(status); }