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$ */
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