static void get_txt_property(IOHIDDeviceRef device,char *buffer,u32 maxlen, CFStringRef key) { CFTypeRef ref; size_t len; ref = IOHIDDeviceGetProperty(device, key); if (ref) { if (CFGetTypeID(ref) == CFStringGetTypeID()) { const char *str; CFStringEncoding encodingMethod; encodingMethod = CFStringGetSystemEncoding(); // 1st try for English system str = CFStringGetCStringPtr(ref, encodingMethod); //str = NULL; if ( str == NULL ) { // 2nd try encodingMethod = kCFStringEncodingUTF8; str = CFStringGetCStringPtr(ref, encodingMethod); } if( str == NULL ) { //3rd try CFIndex cflength = CFStringGetLength(ref)*2+2; char *tmp_str = yMalloc( (u32)cflength); if (!CFStringGetCString(ref, tmp_str, cflength, kCFStringEncodingUTF8 )) { yFree( tmp_str ); *buffer=0; return; } if(cflength>maxlen-1){ cflength=maxlen-1; } memcpy(buffer,tmp_str,cflength); buffer[cflength]=0; yFree( tmp_str ); return; } len=strlen(str); if(len>maxlen-1){ len=maxlen-1; } memcpy(buffer,str,len); buffer[len]=0; return; } } *buffer=0; }
int yyyUSBGetInterfaces(yInterfaceSt **ifaces,int *nbifaceDetect,char *errmsg) { int nbifaceAlloc; int deviceIndex; CFIndex deviceCount; IOHIDDeviceRef *dev_refs; // get all device detected by the OSX dev_refs = getDevRef(&yContext->hid, &deviceCount); if(dev_refs == NULL) { return 0; } // allocate buffer for detected interfaces *nbifaceDetect = 0; nbifaceAlloc = 8; *ifaces =yMalloc(nbifaceAlloc * sizeof(yInterfaceSt)); memset(*ifaces, 0 ,nbifaceAlloc * sizeof(yInterfaceSt)); for(deviceIndex=0 ; deviceIndex < deviceCount ;deviceIndex++){ u16 vendorid; u16 deviceid; IOHIDDeviceRef dev = dev_refs[deviceIndex]; yInterfaceSt *iface; vendorid = get_int_property(dev,CFSTR(kIOHIDVendorIDKey)); deviceid = get_int_property(dev,CFSTR(kIOHIDProductIDKey)); //ensure the buffer of detected interface is big enought if(*nbifaceDetect == nbifaceAlloc){ yInterfaceSt *tmp; tmp = (yInterfaceSt*) yMalloc(nbifaceAlloc*2 * sizeof(yInterfaceSt)); memset(tmp,0,nbifaceAlloc*2 * sizeof(yInterfaceSt)); yMemcpy(tmp,*ifaces, nbifaceAlloc * sizeof(yInterfaceSt) ); yFree(*ifaces); *ifaces = tmp; nbifaceAlloc *=2; } iface = *ifaces + *nbifaceDetect; //iface->devref = dev; iface->vendorid = vendorid; iface->deviceid = deviceid; get_txt_property(dev,iface->serial,YOCTO_SERIAL_LEN*2, CFSTR(kIOHIDSerialNumberKey)); HALENUMLOG("work on interface %d (%x:%x:%s)\n",deviceIndex,vendorid,deviceid,iface->serial); (*nbifaceDetect)++; } yFree(dev_refs); return YAPI_SUCCESS; }
int yyySignalOutPkt(yInterfaceSt *iface, char *errmsg) { int res =YAPI_SUCCESS; pktItem *pktitem; yPktQueuePopH2D(iface, &pktitem); while (pktitem!=NULL){ if(iface->devref==NULL){ yFree(pktitem); return YERR(YAPI_IO_ERROR); } res = IOHIDDeviceSetReport(iface->devref, kIOHIDReportTypeOutput, 0, /* Report ID*/ (u8*)&pktitem->pkt, sizeof(USB_Packet)); yFree(pktitem); if (res != kIOReturnSuccess) { dbglog("IOHIDDeviceSetReport failed with 0x%x\n", res); return YERRMSG(YAPI_IO_ERROR,"IOHIDDeviceSetReport failed");; } yPktQueuePopH2D(iface, &pktitem); } return YAPI_SUCCESS; }
int yyySignalOutPkt(yInterfaceSt *iface) { pktItem *pktitem; yPktQueuePopH2D(iface, &pktitem); while (pktitem!=NULL){ int transfered,res; res = libusb_interrupt_transfer(iface->hdl, iface->wrendp, (u8*)&pktitem->pkt, sizeof(USB_Packet), &transfered, 5000/*5 sec*/); yFree(pktitem); if(res<0){ return YAPI_IO_ERROR; } yPktQueuePopH2D(iface, &pktitem); } return YAPI_SUCCESS; }
int yyyUSB_stop(yContextSt *ctx,char *errmsg) { int i; stringCacheSt *c = stringCache; if(ctx->usb_thread_state == USB_THREAD_RUNNING){ ctx->usb_thread_state = USB_THREAD_MUST_STOP; pthread_join(ctx->usb_thread,NULL); } YASSERT(ctx->usb_thread_state == USB_THREAD_STOPED); libusb_exit(ctx->libusb); yReleaseGlobalAccess(ctx); for (i = 0; i < STRING_CACHE_SIZE; i++, c++) { if(c->string) { yFree(c->string); } } yDeleteCriticalSection(&ctx->string_cache_cs); return YAPI_SUCCESS; }
int yyySetup(yInterfaceSt *iface,char *errmsg) { char str[32]; int i; CFIndex deviceCount; IOHIDDeviceRef *dev_refs; if (yContext->osx_flags & YCTX_OSX_MULTIPLES_HID) { if (YISERR(setupHIDManager(yContext, &iface->hid,errmsg))) { return YAPI_IO_ERROR; } // get all device detected by the OSX dev_refs = getDevRef(&iface->hid, &deviceCount); } else { dev_refs = getDevRef(&yContext->hid, &deviceCount); } if(dev_refs == NULL) { return YERRMSG(YAPI_IO_ERROR,"Device disapear before yyySetup"); } for(i=0 ; i < deviceCount ;i++){ u16 vendorid; u16 deviceid; IOHIDDeviceRef dev = dev_refs[i]; vendorid = get_int_property(dev,CFSTR(kIOHIDVendorIDKey)); deviceid = get_int_property(dev,CFSTR(kIOHIDProductIDKey)); if (iface->vendorid == vendorid && iface->deviceid == deviceid){ char serial[YOCTO_SERIAL_LEN * 2]; memset(serial, 0, YOCTO_SERIAL_LEN * 2); get_txt_property(dev,serial,YOCTO_SERIAL_LEN * 2, CFSTR(kIOHIDSerialNumberKey)); if (YSTRCMP(serial, iface->serial) == 0){ HALLOG("right Interface detected (%x:%x:%s)\n",vendorid,deviceid,iface->serial); iface->devref = dev; break; } } } yFree(dev_refs); if (i == deviceCount) { return YERRMSG(YAPI_IO_ERROR,"Unable to match device detected"); } IOReturn ret = IOHIDDeviceOpen(iface->devref, kIOHIDOptionsTypeNone); if (ret != kIOReturnSuccess) { YSPRINTF(str,32,"Unable to open device (0x%x)",ret); return YERRMSG(YAPI_IO_ERROR,str); } yPktQueueInit(&iface->rxQueue); yPktQueueInit(&iface->txQueue); /* Create the Run Loop Mode for this device. printing the reference seems to work. */ sprintf(str, "yocto_%p", iface->devref); iface->run_loop_mode = CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII); /* Attach the device to a Run Loop */ IOHIDDeviceScheduleWithRunLoop(iface->devref, yContext->usb_run_loop, iface->run_loop_mode); IOHIDDeviceRegisterInputReportCallback( iface->devref, // IOHIDDeviceRef for the HID device (u8*) &iface->tmprxpkt, // pointer to the report data USB_PKT_SIZE, // number of bytes in the report (CFIndex) &Handle_IOHIDDeviceIOHIDReportCallback, // the callback routine iface); // context passed to callback // save setuped iface pointer in context in order // to retreive it durring unplugcallback for (i=0; i< SETUPED_IFACE_CACHE_SIZE ; i++) { if(yContext->setupedIfaceCache[i]==NULL){ yContext->setupedIfaceCache[i] = iface; break; } } if (i==SETUPED_IFACE_CACHE_SIZE) { return YERRMSG(YAPI_IO_ERROR,"Too many setuped USB interfaces"); } iface->flags.yyySetupDone = 1; return 0; }
int yUSBGetInterfaces(yInterfaceSt **ifaces,int *nbifaceDetect,char *errmsg) { int nbifaceAlloc; int deviceIndex; CFSetRef deviceCFSetRef; CFIndex deviceCount; IOHIDDeviceRef *dev_refs; // allocate buffer for detected interfaces *nbifaceDetect = 0; nbifaceAlloc = 8; *ifaces =yMalloc(nbifaceAlloc * sizeof(yInterfaceSt)); memset(*ifaces, 0 ,nbifaceAlloc * sizeof(yInterfaceSt)); yEnterCriticalSection(&yContext->hidMCS); deviceCFSetRef = IOHIDManagerCopyDevices( yContext->hidM ); yLeaveCriticalSection(&yContext->hidMCS); if(deviceCFSetRef== NULL){ //no device found return 0; } // how many devices in the set? deviceCount = CFSetGetCount( deviceCFSetRef ); HALLOG("%ld usb interfaces detected\n",deviceCount); dev_refs = yMalloc( sizeof(IOHIDDeviceRef) * (u32)deviceCount ); // now extract the device ref's from the set CFSetGetValues( deviceCFSetRef, (const void **) dev_refs ); for(deviceIndex=0 ; deviceIndex < deviceCount ;deviceIndex++){ u16 vendorid; u16 deviceid; IOHIDDeviceRef dev = dev_refs[deviceIndex]; yInterfaceSt *iface; vendorid = get_int_property(dev,CFSTR(kIOHIDVendorIDKey)); deviceid = get_int_property(dev,CFSTR(kIOHIDProductIDKey)); //ensure the buffer of detected interface is big enought if(*nbifaceDetect == nbifaceAlloc){ yInterfaceSt *tmp; tmp = (yInterfaceSt*) yMalloc(nbifaceAlloc*2 * sizeof(yInterfaceSt)); memset(tmp,0,nbifaceAlloc*2 * sizeof(yInterfaceSt)); yMemcpy(tmp,*ifaces, nbifaceAlloc * sizeof(yInterfaceSt) ); yFree(*ifaces); *ifaces = tmp; nbifaceAlloc *=2; } iface = *ifaces + *nbifaceDetect; iface->devref = dev; iface->vendorid = vendorid; iface->deviceid = deviceid; get_txt_property(dev,iface->serial,YOCTO_SERIAL_LEN*2, CFSTR(kIOHIDSerialNumberKey)); HALLOG("work on interface %d (%x:%x:%s)\n",deviceIndex,vendorid,deviceid,iface->serial); (*nbifaceDetect)++; } CFRelease(deviceCFSetRef); yFree(dev_refs); return YAPI_SUCCESS; }
int yyyUSBGetInterfaces(yInterfaceSt **ifaces,int *nbifaceDetect,char *errmsg) { libusb_device **list; ssize_t nbdev; int returnval=YAPI_SUCCESS; int i,j; int nbifaceAlloc; yInterfaceSt *iface; nbdev=libusb_get_device_list(yContext->libusb,&list); if(nbdev<0) return yLinSetErr("Unable to get device list",nbdev,errmsg); HALLOG("%d devices found\n",nbdev); // allocate buffer for detected interfaces *nbifaceDetect = 0; nbifaceAlloc = nbdev*2; *ifaces = (yInterfaceSt*) yMalloc(nbifaceAlloc * sizeof(yInterfaceSt)); memset(*ifaces,0,nbifaceAlloc * sizeof(yInterfaceSt)); for(i=0; i < nbdev; i++){ int res; struct libusb_device_descriptor desc; struct libusb_config_descriptor *config; libusb_device_handle *hdl; libusb_device *dev=list[i]; if((res=libusb_get_device_descriptor(dev,&desc))!=0){ returnval = yLinSetErr("Unable to get device descriptor",res,errmsg); goto exit; } if(desc.idVendor!=YOCTO_VENDORID ){ continue; } HALLOG("open device %x:%x\n",desc.idVendor,desc.idProduct); if(getDevConfig(dev,&config)<0) continue; for(j=0 ; j < config->bNumInterfaces; j++){ //ensure the buffer of detected interface is big enough if(*nbifaceDetect == nbifaceAlloc){ yInterfaceSt *tmp; u32 newsize = nbifaceAlloc*2 * sizeof(yInterfaceSt); tmp = (yInterfaceSt*) yMalloc(newsize); memset(tmp,0,newsize); yMemcpy(tmp,*ifaces, nbifaceAlloc * sizeof(yInterfaceSt) ); yFree(*ifaces); *ifaces = tmp; nbifaceAlloc *=2; } iface = *ifaces + *nbifaceDetect; iface->vendorid = (u16)desc.idVendor; iface->deviceid = (u16)desc.idProduct; iface->ifaceno = (u16)j; iface->devref = libusb_ref_device(dev); res = libusb_open(dev,&hdl); if(res==LIBUSB_ERROR_ACCESS){ returnval =YERRMSG(YAPI_IO_ERROR,"the user has insufficient permissions to access USB devices"); goto exit; } if(res!=0){ HALLOG("unable to access device %x:%x\n",desc.idVendor,desc.idProduct); continue; } HALLOG("try to get serial for %x:%x:%x (%p)\n",desc.idVendor,desc.idProduct,desc.iSerialNumber,dev); res = getUsbStringASCII(hdl, dev, desc.iSerialNumber, iface->serial, YOCTO_SERIAL_LEN); if(res<0){ HALLOG("unable to get serial for device %x:%x\n",desc.idVendor,desc.idProduct); } libusb_close(hdl); (*nbifaceDetect)++; HALLOG("----Running Dev %x:%x:%d:%s ---\n",iface->vendorid,iface->deviceid,iface->ifaceno,iface->serial); } libusb_free_config_descriptor(config); } exit: libusb_free_device_list(list,1); return returnval; }
// on success data point to a null terminated string of max length-1 characters static int getUsbStringASCII(libusb_device_handle *hdl, libusb_device *dev, u8 desc_index, char *data, u32 length) { u8 buffer[512]; u32 l,len; int res,i; stringCacheSt *c = stringCache; stringCacheSt *f = NULL; u64 now = yapiGetTickCount(); yEnterCriticalSection(&yContext->string_cache_cs); for (i = 0; i < STRING_CACHE_SIZE; i++, c++) { if (c->expiration > now) { if(c->dev == dev && c->desc_index == desc_index) { if (c->len > 0 && c->string) { len = c->len; if (c->len >= length) len = length-1; memcpy(data, c->string, len); data[len] = 0; HALLOG("return string from cache (%p:%d->%s)\n",dev,desc_index,c->string); yLeaveCriticalSection(&yContext->string_cache_cs); return c->len; } else { f = c; break; } } } else { if (c->string) { yFree(c->string); c->string =NULL; } if (f == NULL) { f = c; } } } res=libusb_control_transfer(hdl, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index, 0, buffer, 512, 10000); if(res<0) return res; len=(buffer[0]-2)/2; if (len >= length) { len = length - 1; } for (l = 0; l < len; l++){ data[l] = (char) buffer[2+(l*2)]; } data[len] = 0; if (f != NULL) { f->dev = dev; f->desc_index = desc_index; f->string = yMalloc(len+1); memcpy(f->string, data, len+1); f->len = len; f->expiration = yapiGetTickCount() + STRING_CACHE_EXPIRATION; HALLOG("add string to cache (%p:%d->%s)\n",dev,desc_index,f->string); } yLeaveCriticalSection(&yContext->string_cache_cs); return len; }