libusb-glue.c
来自「Media transfer protocol implementation o」· C语言 代码 · 共 864 行 · 第 1/2 页
C
864 行
if (result > 0) { *readbytes = curread; return (PTP_RC_OK); } else { return PTP_ERROR_IO; }}// Based on same function on library.c in libgphoto2static shortptp_write_func (unsigned char *bytes, unsigned int size, void *data){ PTP_USB *ptp_usb = (PTP_USB *)data; int towrite = 0; int result = 0; int curwrite = 0; /* * gp_port_write returns (in case of success) the number of bytes * written. Too large blocks (>5x MB) could timeout. */ while (curwrite < size) { towrite = size-curwrite; if (towrite > CONTEXT_BLOCK_SIZE) towrite = CONTEXT_BLOCK_SIZE; result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)(bytes+curwrite),towrite,ptpcam_usb_timeout);#ifdef ENABLE_USB_BULK_DEBUG printf("USB OUT==>\n"); data_dump_ascii (stdout,(bytes+curwrite),towrite,16);#endif if (result < 0) return PTP_ERROR_IO; curwrite += result; if (result < towrite) /* short writes happen */ break; } // Increase counters, call callback if (ptp_usb->callback_active) { ptp_usb->current_transfer_complete += curwrite; if (ptp_usb->current_transfer_complete > ptp_usb->current_transfer_total) { // Fishy... but some commands have unpredictable lengths. // send last update and disable callback. ptp_usb->current_transfer_complete = ptp_usb->current_transfer_total; ptp_usb->callback_active = 0; } if (ptp_usb->current_transfer_callback != NULL) { (void) ptp_usb->current_transfer_callback(ptp_usb->current_transfer_complete, ptp_usb->current_transfer_total, ptp_usb->current_transfer_callback_data); } } // If this is the last transfer (callbacks only active if this function called repeatedly with // new data, otherwise this is a single large transaction which ends here). // a request and the bulk send header. if (!ptp_usb->callback_active) { // Then terminate an even packet boundary write with a zero length packet if ((size % ptp_usb->outep_maxpacket) == 0) { result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,ptpcam_usb_timeout); } } else if (ptp_usb->current_transfer_complete == ptp_usb->current_transfer_total) { // This is the amount actually transfered in this large transaction. uint64_t actual_xfer_size = ptp_usb->current_transfer_total - 2*PTP_USB_BULK_HDR_LEN; if ((actual_xfer_size % ptp_usb->outep_maxpacket) == 0) { result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)"x",0,ptpcam_usb_timeout); } // Set as complete and disable callback, just as good. // This also blocks callbacks from the following response command. if (ptp_usb->current_transfer_callback != NULL) { (void) ptp_usb->current_transfer_callback(ptp_usb->current_transfer_total, // Both total = 100% ptp_usb->current_transfer_total, // Both total = 100% ptp_usb->current_transfer_callback_data); } ptp_usb->callback_active = 0; } if (result < 0) return PTP_ERROR_IO; return PTP_RC_OK;}// This is a bit hackish at the moment. I wonder if it even works.static short ptp_check_int (unsigned char *bytes, unsigned int size, void *data, unsigned int *rlen){ PTP_USB *ptp_usb = (PTP_USB *)data; int result; result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)bytes,size,ptpcam_usb_timeout); if (result==0) result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) bytes, size, ptpcam_usb_timeout); if (result >= 0) { *rlen = result; return (PTP_RC_OK); } else { return PTP_ERROR_IO; }}static int init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev){ usb_dev_handle *device_handle; params->write_func=ptp_write_func; params->read_func=ptp_read_func; params->check_int_func=ptp_check_int; params->check_int_fast_func=ptp_check_int; params->error_func=NULL; params->debug_func=NULL; params->sendreq_func=ptp_usb_sendreq; params->senddata_func=ptp_usb_senddata; params->getresp_func=ptp_usb_getresp; params->getdata_func=ptp_usb_getdata; params->data=ptp_usb; params->transaction_id=0; params->byteorder = PTP_DL_LE; if ((device_handle = usb_open(dev))){ if (!device_handle) { perror("usb_open()"); return -1; } ptp_usb->handle = device_handle;#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP /* * If this device is known to be wrongfully claimed by other kernel * drivers (such as mass storage), then try to unload it to make it * accessible from user space. */ if (ptp_usb->device_flags & DEVICE_FLAG_UNLOAD_DRIVER) { if (usb_detach_kernel_driver_np(device_handle, dev->config->interface->altsetting->bInterfaceNumber)) { // Totally ignore this error! // perror("usb_detach_kernel_driver_np()"); } }#endif#ifdef __WIN32__ // Only needed on Windows if (usb_set_configuration(device_handle, dev->config->bConfigurationValue)) { perror("usb_set_configuration()"); return -1; }#endif if (usb_claim_interface(device_handle, dev->config->interface->altsetting->bInterfaceNumber)) { perror("usb_claim_interface()"); return -1; } ptp_usb->interface = dev->config->interface->altsetting->bInterfaceNumber; } return 0;}static void clear_stall(PTP_USB* ptp_usb){ uint16_t status=0; int ret; /* check the inep status */ ret = usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status); if (ret<0) perror ("inep: usb_get_endpoint_status()"); /* and clear the HALT condition if happend */ else if (status) { printf("Resetting input pipe!\n"); ret=usb_clear_stall_feature(ptp_usb,ptp_usb->inep); /*usb_clear_halt(ptp_usb->handle,ptp_usb->inep); */ if (ret<0)perror ("usb_clear_stall_feature()"); } status=0; /* check the outep status */ ret=usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status); if (ret<0) perror ("outep: usb_get_endpoint_status()"); /* and clear the HALT condition if happend */ else if (status) { printf("Resetting output pipe!\n"); ret=usb_clear_stall_feature(ptp_usb,ptp_usb->outep); /*usb_clear_halt(ptp_usb->handle,ptp_usb->outep); */ if (ret<0)perror ("usb_clear_stall_feature()"); } /*usb_clear_halt(ptp_usb->handle,ptp_usb->intep); */}static void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber){ clear_stall(ptp_usb); // Added to clear some stuff on the OUT endpoint // TODO: is this good on the Mac too? usb_resetep(ptp_usb->handle, ptp_usb->outep); usb_release_interface(ptp_usb->handle, interfaceNumber); // Brutally reset device // TODO: is this good on the Mac too? usb_reset(ptp_usb->handle); usb_close(ptp_usb->handle);}/* find_device() returns the pointer to a usb_device structure matching given busn, devicen numbers. If any or both of arguments are 0 then the first matching PTP device structure is returned. */static struct usb_device* find_device (int busn, int devn, short force){ struct usb_bus *bus; struct usb_device *dev; bus=init_usb(); for (; bus; bus = bus->next) for (dev = bus->devices; dev; dev = dev->next) /* somtimes dev->config is null, not sure why... */ if (dev->config != NULL) if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB) { int curbusn, curdevn; curbusn=strtol(bus->dirname,NULL,10); curdevn=strtol(dev->filename,NULL,10); if (devn==0) { if (busn==0) return dev; if (curbusn==busn) return dev; } else { if ((busn==0)&&(curdevn==devn)) return dev; if ((curbusn==busn)&&(curdevn==devn)) return dev; } } return NULL;}/** * This function scans through the device list to see if there are * some devices to connect to. The table at the top of this file is * used to identify potential devices. */uint16_t connect_first_device(PTPParams *params, PTP_USB *ptp_usb, uint8_t *interfaceNumber){ struct usb_bus *bus; struct usb_device *dev; struct usb_endpoint_descriptor *ep; PTPDeviceInfo deviceinfo; uint16_t ret=0; int n; // Reset device flags ptp_usb->device_flags = DEVICE_FLAG_NONE; // First try to locate the device using the extended // device descriptor. dev = probe_usb_bus_for_mtp_devices(); if (dev != NULL) { int i; // See if we can find the name of this beast for (i = 0; i < mtp_device_table_size; i++) { LIBMTP_device_entry_t const *mtp_device = &mtp_device_table[i]; if (dev->descriptor.idVendor == mtp_device->vendor_id && dev->descriptor.idProduct == mtp_device->product_id ) { printf("Autodetected device \"%s\" (VID=%04x,PID=%04x) is known.\n", mtp_device->name, dev->descriptor.idVendor, dev->descriptor.idProduct); ptp_usb->device_flags = mtp_device->device_flags; break; } } if (i == mtp_device_table_size) { printf("Autodetected device with VID=%04x and PID=%04x is UNKNOWN.\n", dev->descriptor.idVendor, dev->descriptor.idProduct); printf("Please report this VID/PID and the device model name etc to the\n"); printf("libmtp development team!\n"); } } // If autodetection fails, scan the bus for well known devices. if (dev == NULL) { bus = init_usb(); for (; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { int i; // Loop over the list of supported devices for (i = 0; i < mtp_device_table_size; i++) { LIBMTP_device_entry_t const *mtp_device = &mtp_device_table[i]; if (dev->descriptor.bDeviceClass != USB_CLASS_HUB && dev->descriptor.idVendor == mtp_device->vendor_id && dev->descriptor.idProduct == mtp_device->product_id ) { printf("Found non-autodetected device \"%s\" on USB bus...\n", mtp_device->name); ptp_usb->device_flags = mtp_device->device_flags; goto next_step; } } } } }next_step: // Still not found any? if (dev == NULL) { return PTP_CD_RC_NO_DEVICES; } // Found a device, then assign endpoints to ptp_usb... ep = dev->config->interface->altsetting->endpoint; n = dev->config->interface->altsetting->bNumEndpoints; find_endpoints(dev, &ptp_usb->inep, &ptp_usb->inep_maxpacket, &ptp_usb->outep, &ptp_usb->outep_maxpacket, &ptp_usb->intep); // printf("Init PTP USB...\n"); if (init_ptp_usb(params, ptp_usb, dev) < 0) { return PTP_CD_RC_ERROR_CONNECTING; } ret = ptp_opensession(params,1); // This works in situations where previous bad applications have not used LIBMTP_Release_Device on exit if (ret == PTP_ERROR_IO) { printf("%s\n","PTP ERROR IO: Trying again after resetting USB"); // printf("%s\n","Closing USB interface..."); close_usb(ptp_usb,dev->config->interface->altsetting->bInterfaceNumber); // printf("%s\n","Init PTP USB..."); if (init_ptp_usb(params, ptp_usb, dev) < 0) { return PTP_CD_RC_ERROR_CONNECTING; } ret = ptp_opensession(params,1); } // printf("Session open (%d)...\n", ret); if (ret == PTP_RC_InvalidTransactionID) { params->transaction_id += 10; ret = ptp_opensession(params,1); } if (ret != PTP_RC_SessionAlreadyOpened && ret != PTP_RC_OK) { printf("Could not open session! (Return code %d)\n Try to reset the device.\n", ret); usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber); } // It is actually permissible to call this before opening the session ret = ptp_getdeviceinfo(params, &deviceinfo); if (ret != PTP_RC_OK) { printf("Could not get device info!\n"); usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber); return PTP_CD_RC_ERROR_CONNECTING; } // we're connected, return OK *interfaceNumber = dev->config->interface->altsetting->bInterfaceNumber; return PTP_CD_RC_CONNECTED;}static void find_endpoints(struct usb_device *dev, int* inep, int* inep_maxpacket, int* outep, int *outep_maxpacket, int* intep){ int i,n; struct usb_endpoint_descriptor *ep; ep = dev->config->interface->altsetting->endpoint; n=dev->config->interface->altsetting->bNumEndpoints; for (i=0;i<n;i++) { if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_BULK) { if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)== USB_ENDPOINT_DIR_MASK) { *inep=ep[i].bEndpointAddress; *inep_maxpacket=ep[i].wMaxPacketSize; } if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0) { *outep=ep[i].bEndpointAddress; *outep_maxpacket=ep[i].wMaxPacketSize; } } else if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){ if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)== USB_ENDPOINT_DIR_MASK) { *intep=ep[i].bEndpointAddress; } } }}int open_device (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev){#ifdef DEBUG printf("dev %i\tbus %i\n",devn,busn);#endif *dev=find_device(busn,devn,force); if (*dev==NULL) { fprintf(stderr,"could not find any device matching given " "bus/dev numbers\n"); exit(-1); } find_endpoints(*dev,&ptp_usb->inep,&ptp_usb->inep_maxpacket,&ptp_usb->outep,&ptp_usb->outep_maxpacket,&ptp_usb->intep); if (init_ptp_usb(params, ptp_usb, *dev) < 0) { return -1; } if (ptp_opensession(params,1)!=PTP_RC_OK) { fprintf(stderr,"ERROR: Could not open session!\n"); close_usb(ptp_usb, (*dev)->config->interface->altsetting->bInterfaceNumber); return -1; } return 0;}void close_device (PTP_USB *ptp_usb, PTPParams *params, uint8_t interfaceNumber){ if (ptp_closesession(params)!=PTP_RC_OK) fprintf(stderr,"ERROR: Could not close session!\n"); close_usb(ptp_usb, interfaceNumber);}static int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep){ return (usb_control_msg(ptp_usb->handle, USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT, ep, NULL, 0, 3000));}static int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status){ return (usb_control_msg(ptp_usb->handle, USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS, USB_FEATURE_HALT, ep, (char *)status, 2, 3000));}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?