1 /*
2  * avrdude - A Downloader/Uploader for AVR device programmers
3  * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
4  * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
5  * Copyright (C) 2006 Christian Starkjohann
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /* $Id: ser_avrdoper.c 1328 2014-07-16 20:02:01Z rliebscher $ */
22 
23 /*
24  * Serial Interface emulation for USB programmer "AVR-Doper" in HID mode.
25  */
26 
27 #include "ac_cfg.h"
28 
29 #if defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
30 
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 
35 #include "avrdude.h"
36 #include "libavrdude.h"
37 
38 /* ------------------------------------------------------------------------ */
39 
40 /* Numeric constants for 'reportType' parameters */
41 #define USB_HID_REPORT_TYPE_INPUT   1
42 #define USB_HID_REPORT_TYPE_OUTPUT  2
43 #define USB_HID_REPORT_TYPE_FEATURE 3
44 
45 /* These are the error codes which can be returned by functions of this
46  * module.
47  */
48 #define USB_ERROR_NONE      0
49 #define USB_ERROR_ACCESS    1
50 #define USB_ERROR_NOTFOUND  2
51 #define USB_ERROR_BUSY      16
52 #define USB_ERROR_IO        5
53 
54 #define USB_VENDOR_ID   0x16c0
55 #define USB_PRODUCT_ID  0x05df
56 
57 static int  reportDataSizes[4] = {13, 29, 61, 125};
58 
59 static unsigned char    avrdoperRxBuffer[280];  /* buffer for receive data */
60 static int              avrdoperRxLength = 0;   /* amount of valid bytes in rx buffer */
61 static int              avrdoperRxPosition = 0; /* amount of bytes already consumed in rx buffer */
62 
63 /* ------------------------------------------------------------------------ */
64 /* ------------------------------------------------------------------------ */
65 /* ------------------------------------------------------------------------ */
66 
67 #if defined(WIN32NATIVE) && defined(HAVE_LIBHID)
68 
69 #include <windows.h>
70 #include <setupapi.h>
71 
72 #if defined(HAVE_DDK_HIDSDI_H)
73 #  include <ddk/hidsdi.h>
74 #else
75 #  include "my_ddk_hidsdi.h"
76 #endif
77 #include <ddk/hidpi.h>
78 
79 #ifdef USB_DEBUG
80 #define DEBUG_PRINT(arg)    printf arg
81 #else
82 #define DEBUG_PRINT(arg)
83 #endif
84 
85 /* ------------------------------------------------------------------------ */
86 
convertUniToAscii(char * buffer)87 static void convertUniToAscii(char *buffer)
88 {
89     unsigned short  *uni = (void *)buffer;
90     char            *ascii = buffer;
91 
92     while(*uni != 0){
93         if(*uni >= 256){
94             *ascii++ = '?';
95             uni++;
96         }else{
97             *ascii++ = *uni++;
98         }
99     }
100     *ascii++ = 0;
101 }
102 
usbOpenDevice(union filedescriptor * fdp,int vendor,char * vendorName,int product,char * productName,int usesReportIDs)103 static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
104 			 int product, char *productName, int usesReportIDs)
105 {
106     GUID                                hidGuid;        /* GUID for HID driver */
107     HDEVINFO                            deviceInfoList;
108     SP_DEVICE_INTERFACE_DATA            deviceInfo;
109     SP_DEVICE_INTERFACE_DETAIL_DATA     *deviceDetails = NULL;
110     DWORD                               size;
111     int                                 i, openFlag = 0;  /* may be FILE_FLAG_OVERLAPPED */
112     int                                 errorCode = USB_ERROR_NOTFOUND;
113     HANDLE                              handle = INVALID_HANDLE_VALUE;
114     HIDD_ATTRIBUTES                     deviceAttributes;
115 
116     HidD_GetHidGuid(&hidGuid);
117     deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
118 					 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
119     deviceInfo.cbSize = sizeof(deviceInfo);
120     for(i=0;;i++){
121         if(handle != INVALID_HANDLE_VALUE){
122             CloseHandle(handle);
123             handle = INVALID_HANDLE_VALUE;
124         }
125         if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo))
126             break;  /* no more entries */
127         /* first do a dummy call just to determine the actual size required */
128         SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL);
129         if(deviceDetails != NULL)
130             free(deviceDetails);
131         deviceDetails = malloc(size);
132         deviceDetails->cbSize = sizeof(*deviceDetails);
133         /* this call is for real: */
134         SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails,
135 					size, &size, NULL);
136         DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath));
137         /* attempt opening for R/W -- we don't care about devices which can't be accessed */
138         handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE,
139 			    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
140 			    openFlag, NULL);
141         if(handle == INVALID_HANDLE_VALUE){
142             DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError()));
143             /* errorCode = USB_ERROR_ACCESS; opening will always fail for mouse -- ignore */
144             continue;
145         }
146         deviceAttributes.Size = sizeof(deviceAttributes);
147         HidD_GetAttributes(handle, &deviceAttributes);
148         DEBUG_PRINT(("device attributes: vid=%d pid=%d\n",
149 		     deviceAttributes.VendorID, deviceAttributes.ProductID));
150         if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product)
151             continue;   /* ignore this device */
152         errorCode = USB_ERROR_NOTFOUND;
153         if(vendorName != NULL && productName != NULL){
154             char    buffer[512];
155             if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){
156                 DEBUG_PRINT(("error obtaining vendor name\n"));
157                 errorCode = USB_ERROR_IO;
158                 continue;
159             }
160             convertUniToAscii(buffer);
161             DEBUG_PRINT(("vendorName = \"%s\"\n", buffer));
162             if(strcmp(vendorName, buffer) != 0)
163                 continue;
164             if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){
165                 DEBUG_PRINT(("error obtaining product name\n"));
166                 errorCode = USB_ERROR_IO;
167                 continue;
168             }
169             convertUniToAscii(buffer);
170             DEBUG_PRINT(("productName = \"%s\"\n", buffer));
171             if(strcmp(productName, buffer) != 0)
172                 continue;
173         }
174         break;  /* we have found the device we are looking for! */
175     }
176     SetupDiDestroyDeviceInfoList(deviceInfoList);
177     if(deviceDetails != NULL)
178         free(deviceDetails);
179     if(handle != INVALID_HANDLE_VALUE){
180 	fdp->pfd = (void *)handle;
181 	errorCode = 0;
182     }
183     return errorCode;
184 }
185 
186 /* ------------------------------------------------------------------------ */
187 
usbCloseDevice(union filedescriptor * fdp)188 static void    usbCloseDevice(union filedescriptor *fdp)
189 {
190     CloseHandle((HANDLE)fdp->pfd);
191 }
192 
193 /* ------------------------------------------------------------------------ */
194 
usbSetReport(union filedescriptor * fdp,int reportType,char * buffer,int len)195 static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
196 {
197     HANDLE  handle = (HANDLE)fdp->pfd;
198     BOOLEAN rval = 0;
199     DWORD   bytesWritten;
200 
201     switch(reportType){
202     case USB_HID_REPORT_TYPE_INPUT:
203         break;
204     case USB_HID_REPORT_TYPE_OUTPUT:
205         rval = WriteFile(handle, buffer, len, &bytesWritten, NULL);
206         break;
207     case USB_HID_REPORT_TYPE_FEATURE:
208         rval = HidD_SetFeature(handle, buffer, len);
209         break;
210     }
211     return rval == 0 ? USB_ERROR_IO : 0;
212 }
213 
214 /* ------------------------------------------------------------------------ */
215 
usbGetReport(union filedescriptor * fdp,int reportType,int reportNumber,char * buffer,int * len)216 static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
217 			char *buffer, int *len)
218 {
219     HANDLE  handle = (HANDLE)fdp->pfd;
220     BOOLEAN rval = 0;
221     DWORD   bytesRead;
222 
223     switch(reportType){
224     case USB_HID_REPORT_TYPE_INPUT:
225         buffer[0] = reportNumber;
226         rval = ReadFile(handle, buffer, *len, &bytesRead, NULL);
227         if(rval)
228             *len = bytesRead;
229         break;
230     case USB_HID_REPORT_TYPE_OUTPUT:
231         break;
232     case USB_HID_REPORT_TYPE_FEATURE:
233         buffer[0] = reportNumber;
234         rval = HidD_GetFeature(handle, buffer, *len);
235         break;
236     }
237     return rval == 0 ? USB_ERROR_IO : 0;
238 }
239 
240 /* ------------------------------------------------------------------------ */
241 /* ------------------------------------------------------------------------ */
242 /* ------------------------------------------------------------------------ */
243 
244 #else /* !(WIN32NATIVE && HAVE_LIBHID) */
245 
246 /* ------------------------------------------------------------------------ */
247 /* ------------------------------------------------------------------------ */
248 /* ------------------------------------------------------------------------ */
249 
250 #if defined(HAVE_USB_H)
251 #  include <usb.h>
252 #elif defined(HAVE_LUSB0_USB_H)
253 #  include <lusb0_usb.h>
254 #else
255 #  error "libusb needs either <usb.h> or <lusb0_usb.h>"
256 #endif
257 
258 /* ------------------------------------------------------------------------- */
259 
260 #define USBRQ_HID_GET_REPORT    0x01
261 #define USBRQ_HID_SET_REPORT    0x09
262 
263 static int  usesReportIDs;
264 
265 /* ------------------------------------------------------------------------- */
266 
usbGetStringAscii(usb_dev_handle * dev,int index,int langid,char * buf,int buflen)267 static int  usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen)
268 {
269     char    buffer[256];
270     int     rval, i;
271 
272     if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
273 			       (USB_DT_STRING << 8) + index, langid, buffer,
274 			       sizeof(buffer), 1000)) < 0)
275         return rval;
276     if(buffer[1] != USB_DT_STRING)
277         return 0;
278     if((unsigned char)buffer[0] < rval)
279         rval = (unsigned char)buffer[0];
280     rval /= 2;
281     /* lossy conversion to ISO Latin1 */
282     for(i=1;i<rval;i++){
283         if(i > buflen)  /* destination buffer overflow */
284             break;
285         buf[i-1] = buffer[2 * i];
286         if(buffer[2 * i + 1] != 0)  /* outside of ISO Latin1 range */
287             buf[i-1] = '?';
288     }
289     buf[i-1] = 0;
290     return i-1;
291 }
292 
usbOpenDevice(union filedescriptor * fdp,int vendor,char * vendorName,int product,char * productName,int doReportIDs)293 static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
294 			 int product, char *productName, int doReportIDs)
295 {
296     struct usb_bus      *bus;
297     struct usb_device   *dev;
298     usb_dev_handle      *handle = NULL;
299     int                 errorCode = USB_ERROR_NOTFOUND;
300     static int          didUsbInit = 0;
301 
302     if(!didUsbInit){
303         usb_init();
304         didUsbInit = 1;
305     }
306     usb_find_busses();
307     usb_find_devices();
308     for(bus=usb_get_busses(); bus; bus=bus->next){
309         for(dev=bus->devices; dev; dev=dev->next){
310             if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product){
311                 char    string[256];
312                 int     len;
313                 handle = usb_open(dev); /* we need to open the device in order to query strings */
314                 if(!handle){
315                     errorCode = USB_ERROR_ACCESS;
316                     avrdude_message(MSG_INFO, "Warning: cannot open USB device: %s\n",
317 			    usb_strerror());
318                     continue;
319                 }
320                 if(vendorName == NULL && productName == NULL){  /* name does not matter */
321                     break;
322                 }
323                 /* now check whether the names match: */
324                 len = usbGetStringAscii(handle, dev->descriptor.iManufacturer,
325 					0x0409, string, sizeof(string));
326                 if(len < 0){
327                     errorCode = USB_ERROR_IO;
328                     avrdude_message(MSG_INFO, "Warning: cannot query manufacturer for device: %s\n",
329                                     usb_strerror());
330                 }else{
331                     errorCode = USB_ERROR_NOTFOUND;
332                     /* avrdude_message(MSG_INFO, "seen device from vendor ->%s<-\n", string); */
333                     if(strcmp(string, vendorName) == 0){
334                         len = usbGetStringAscii(handle, dev->descriptor.iProduct,
335 						0x0409, string, sizeof(string));
336                         if(len < 0){
337                             errorCode = USB_ERROR_IO;
338                             avrdude_message(MSG_INFO, "Warning: cannot query product for device: %s\n",
339                                             usb_strerror());
340                         }else{
341                             errorCode = USB_ERROR_NOTFOUND;
342                             /* avrdude_message(MSG_INFO, "seen product ->%s<-\n", string); */
343                             if(strcmp(string, productName) == 0)
344                                 break;
345                         }
346                     }
347                 }
348                 usb_close(handle);
349                 handle = NULL;
350             }
351         }
352         if(handle)
353             break;
354     }
355     if(handle != NULL){
356         int rval, retries = 3;
357         if(usb_set_configuration(handle, 1)){
358             avrdude_message(MSG_INFO, "Warning: could not set configuration: %s\n",
359 		    usb_strerror());
360         }
361         /* now try to claim the interface and detach the kernel HID driver on
362          * linux and other operating systems which support the call.
363          */
364         while((rval = usb_claim_interface(handle, 0)) != 0 && retries-- > 0){
365 #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
366             if(usb_detach_kernel_driver_np(handle, 0) < 0){
367                 avrdude_message(MSG_INFO, "Warning: could not detach kernel HID driver: %s\n",
368 			usb_strerror());
369             }
370 #endif
371         }
372         if(rval != 0)
373             avrdude_message(MSG_INFO, "Warning: could not claim interface\n");
374 /* Continue anyway, even if we could not claim the interface. Control transfers
375  * should still work.
376  */
377         errorCode = 0;
378         fdp->pfd = (void *)handle;
379         usesReportIDs = doReportIDs;
380     }
381     return errorCode;
382 }
383 
384 /* ------------------------------------------------------------------------- */
385 
usbCloseDevice(union filedescriptor * fdp)386 static void    usbCloseDevice(union filedescriptor *fdp)
387 {
388     usb_close((usb_dev_handle *)fdp->pfd);
389 }
390 
391 /* ------------------------------------------------------------------------- */
392 
usbSetReport(union filedescriptor * fdp,int reportType,char * buffer,int len)393 static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
394 {
395     int bytesSent;
396 
397     if(!usesReportIDs){
398         buffer++;   /* skip dummy report ID */
399         len--;
400     }
401     bytesSent = usb_control_msg((usb_dev_handle *)fdp->pfd, USB_TYPE_CLASS |
402 				USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT,
403 				reportType << 8 | buffer[0], 0, buffer, len, 5000);
404     if(bytesSent != len){
405         if(bytesSent < 0)
406             avrdude_message(MSG_INFO, "Error sending message: %s\n", usb_strerror());
407         return USB_ERROR_IO;
408     }
409     return 0;
410 }
411 
412 /* ------------------------------------------------------------------------- */
413 
usbGetReport(union filedescriptor * fdp,int reportType,int reportNumber,char * buffer,int * len)414 static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
415 			char *buffer, int *len)
416 {
417     int bytesReceived, maxLen = *len;
418 
419     if(!usesReportIDs){
420         buffer++;   /* make room for dummy report ID */
421         maxLen--;
422     }
423     bytesReceived = usb_control_msg((usb_dev_handle *)fdp->pfd, USB_TYPE_CLASS |
424 				    USB_RECIP_INTERFACE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT,
425 				    reportType << 8 | reportNumber, 0, buffer, maxLen, 5000);
426     if(bytesReceived < 0){
427         avrdude_message(MSG_INFO, "Error sending message: %s\n", usb_strerror());
428         return USB_ERROR_IO;
429     }
430     *len = bytesReceived;
431     if(!usesReportIDs){
432         buffer[-1] = reportNumber;  /* add dummy report ID */
433         len++;
434     }
435     return 0;
436 }
437 
438 #endif  /* WIN32NATIVE */
439 
440 /* ------------------------------------------------------------------------ */
441 /* ------------------------------------------------------------------------ */
442 /* ------------------------------------------------------------------------ */
443 
444 /* ------------------------------------------------------------------------- */
445 
dumpBlock(const char * prefix,const unsigned char * buf,int len)446 static void dumpBlock(const char *prefix, const unsigned char *buf, int len)
447 {
448     int i;
449 
450     if(len <= 8){   /* more compact format for short blocks */
451         avrdude_message(MSG_INFO, "%s: %d bytes: ", prefix, len);
452         for(i = 0; i < len; i++){
453             avrdude_message(MSG_INFO, "%02x ", buf[i]);
454         }
455         avrdude_message(MSG_INFO, " \"");
456         for(i = 0; i < len; i++){
457             if(buf[i] >= 0x20 && buf[i] < 0x7f){
458                 fputc(buf[i], stderr);
459             }else{
460                 fputc('.', stderr);
461             }
462         }
463         avrdude_message(MSG_INFO, "\"\n");
464     }else{
465         avrdude_message(MSG_INFO, "%s: %d bytes:\n", prefix, len);
466         while(len > 0){
467             for(i = 0; i < 16; i++){
468                 if(i < len){
469                     avrdude_message(MSG_INFO, "%02x ", buf[i]);
470                 }else{
471                     avrdude_message(MSG_INFO, "   ");
472                 }
473                 if(i == 7)
474                     fputc(' ', stderr);
475             }
476             avrdude_message(MSG_INFO, "  \"");
477             for(i = 0; i < 16; i++){
478                 if(i < len){
479                     if(buf[i] >= 0x20 && buf[i] < 0x7f){
480                         fputc(buf[i], stderr);
481                     }else{
482                         fputc('.', stderr);
483                     }
484                 }
485             }
486             avrdude_message(MSG_INFO, "\"\n");
487             buf += 16;
488             len -= 16;
489         }
490     }
491 }
492 
usbErrorText(int usbErrno)493 static char *usbErrorText(int usbErrno)
494 {
495     static char buffer[32];
496 
497     switch(usbErrno){
498         case USB_ERROR_NONE:    return "Success.";
499         case USB_ERROR_ACCESS:  return "Access denied.";
500         case USB_ERROR_NOTFOUND:return "Device not found.";
501         case USB_ERROR_BUSY:    return "Device is busy.";
502         case USB_ERROR_IO:      return "I/O Error.";
503         default:
504             sprintf(buffer, "Unknown error %d.", usbErrno);
505             return buffer;
506     }
507 }
508 
509 /* ------------------------------------------------------------------------- */
510 
avrdoper_open(char * port,union pinfo pinfo,union filedescriptor * fdp)511 static int avrdoper_open(char *port, union pinfo pinfo, union filedescriptor *fdp)
512 {
513     int rval;
514     char *vname = "obdev.at";
515     char *devname = "AVR-Doper";
516 
517     rval = usbOpenDevice(fdp, USB_VENDOR_ID, vname, USB_PRODUCT_ID, devname, 1);
518     if(rval != 0){
519         avrdude_message(MSG_INFO, "%s: avrdoper_open(): %s\n", progname, usbErrorText(rval));
520         return -1;
521     }
522     return 0;
523 }
524 
525 /* ------------------------------------------------------------------------- */
526 
avrdoper_close(union filedescriptor * fdp)527 static void avrdoper_close(union filedescriptor *fdp)
528 {
529     usbCloseDevice(fdp);
530 }
531 
532 /* ------------------------------------------------------------------------- */
533 
chooseDataSize(int len)534 static int  chooseDataSize(int len)
535 {
536     int i;
537 
538     for(i = 0; i < sizeof(reportDataSizes)/sizeof(reportDataSizes[0]); i++){
539         if(reportDataSizes[i] >= len)
540             return i;
541     }
542     return i - 1;
543 }
544 
avrdoper_send(union filedescriptor * fdp,const unsigned char * buf,size_t buflen)545 static int avrdoper_send(union filedescriptor *fdp, const unsigned char *buf, size_t buflen)
546 {
547     if(verbose > 3)
548         dumpBlock("Send", buf, buflen);
549     while(buflen > 0){
550         unsigned char buffer[256];
551         int rval, lenIndex = chooseDataSize(buflen);
552         int thisLen = buflen > reportDataSizes[lenIndex] ?
553 	    reportDataSizes[lenIndex] : buflen;
554         buffer[0] = lenIndex + 1;   /* report ID */
555         buffer[1] = thisLen;
556         memcpy(buffer + 2, buf, thisLen);
557         avrdude_message(MSG_TRACE, "Sending %d bytes data chunk\n", thisLen);
558         rval = usbSetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, (char *)buffer,
559 			    reportDataSizes[lenIndex] + 2);
560         if(rval != 0){
561             avrdude_message(MSG_INFO, "%s: avrdoper_send(): %s\n", progname, usbErrorText(rval));
562             return -1;
563         }
564         buflen -= thisLen;
565         buf += thisLen;
566     }
567     return 0;
568 }
569 
570 /* ------------------------------------------------------------------------- */
571 
avrdoperFillBuffer(union filedescriptor * fdp)572 static int avrdoperFillBuffer(union filedescriptor *fdp)
573 {
574     int bytesPending = reportDataSizes[1];  /* guess how much data is buffered in device */
575 
576     avrdoperRxPosition = avrdoperRxLength = 0;
577     while(bytesPending > 0){
578         int len, usbErr, lenIndex = chooseDataSize(bytesPending);
579         unsigned char buffer[128];
580         len = sizeof(avrdoperRxBuffer) - avrdoperRxLength;  /* bytes remaining */
581         if(reportDataSizes[lenIndex] + 2 > len) /* requested data would not fit into buffer */
582             break;
583         len = reportDataSizes[lenIndex] + 2;
584         usbErr = usbGetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, lenIndex + 1,
585 			      (char *)buffer, &len);
586         if(usbErr != 0){
587             avrdude_message(MSG_INFO, "%s: avrdoperFillBuffer(): %s\n", progname, usbErrorText(usbErr));
588             return -1;
589         }
590         avrdude_message(MSG_TRACE, "Received %d bytes data chunk of total %d\n", len - 2, buffer[1]);
591         len -= 2;   /* compensate for report ID and length byte */
592         bytesPending = buffer[1] - len; /* amount still buffered */
593         if(len > buffer[1])             /* cut away padding */
594             len = buffer[1];
595         if(avrdoperRxLength + len > sizeof(avrdoperRxBuffer)){
596             avrdude_message(MSG_INFO, "%s: avrdoperFillBuffer(): internal error: buffer overflow\n",
597                             progname);
598             return -1;
599         }
600         memcpy(avrdoperRxBuffer + avrdoperRxLength, buffer + 2, len);
601         avrdoperRxLength += len;
602     }
603     return 0;
604 }
605 
avrdoper_recv(union filedescriptor * fdp,unsigned char * buf,size_t buflen)606 static int avrdoper_recv(union filedescriptor *fdp, unsigned char *buf, size_t buflen)
607 {
608     unsigned char   *p = buf;
609     int             remaining = buflen;
610 
611     while(remaining > 0){
612         int len, available = avrdoperRxLength - avrdoperRxPosition;
613         if(available <= 0){ /* buffer is empty */
614             if (avrdoperFillBuffer(fdp) < 0)
615                 return -1;
616             continue;
617         }
618         len = remaining < available ? remaining : available;
619         memcpy(p, avrdoperRxBuffer + avrdoperRxPosition, len);
620         p += len;
621         remaining -= len;
622         avrdoperRxPosition += len;
623     }
624     if(verbose > 3)
625         dumpBlock("Receive", buf, buflen);
626     return 0;
627 }
628 
629 /* ------------------------------------------------------------------------- */
630 
avrdoper_drain(union filedescriptor * fdp,int display)631 static int avrdoper_drain(union filedescriptor *fdp, int display)
632 {
633     do{
634         if (avrdoperFillBuffer(fdp) < 0)
635             return -1;
636     }while(avrdoperRxLength > 0);
637     return 0;
638 }
639 
640 /* ------------------------------------------------------------------------- */
641 
avrdoper_set_dtr_rts(union filedescriptor * fdp,int is_on)642 static int avrdoper_set_dtr_rts(union filedescriptor *fdp, int is_on)
643 {
644 	avrdude_message(MSG_INFO, "%s: AVR-Doper doesn't support DTR/RTS setting\n", progname);
645     return -1;
646 }
647 
648 /* ------------------------------------------------------------------------- */
649 
650 struct serial_device avrdoper_serdev =
651 {
652   .open = avrdoper_open,
653   .close = avrdoper_close,
654   .send = avrdoper_send,
655   .recv = avrdoper_recv,
656   .drain = avrdoper_drain,
657   .set_dtr_rts = avrdoper_set_dtr_rts,
658   .flags = SERDEV_FL_NONE,
659 };
660 
661 #endif /* defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID)) */
662