avrdude: прошивка в низкоскоростном режиме USB CDC

Мне дали попользоваться в кампусе программатором avr910 с USB интерфейсом. Он мне был просто необходим для сборки своего программатора(USBAsp).

Проблемма

Простая комманда для чтения флеш памяти:

 avrdude -P /dev/ttyACM0 -p m8 -c avr910 -U flash:r:flash.hex:i

Неожиданно выдала:

avrdude: ser_send(): write error: Invalid argument

Cудя по lsusb программатор определился: Bus 004 Device 002: ID 16c0:05e1 VOTI.
Появился соответствующий файл устройства /dev/ttyACM0. Права rw также есть.
Всё казалось бы хорошо..

Причина

Гугл подсказал, что из за действительно правильной реализации(по стандартам) в линуксе ядро и устройство не могут “договориться” между собой, т.к. программатор запрашивает недоступный для низкоскоростных устройств режим CDC. В итоге программатору ставитсья режим INTERRUPT на чём как я понял всё кончается и возникает ошибка выше.

Решение

Один из вариантом которым я воспользовался я нашёл на форуме сайта electronix.ru – пропатчить ядро(usb часть), чтоб игнорировало стандарт. Оригиналы патчей лежат
тут. Разумеется, вам понадобятся исходники ядра.

Продублирую их тут:

-- linux-2.6.25/drivers/usb/core/config.c      2008-04-16 22:49:44.000000000 -0400
+++ linux-2.6.25-usbpatch/drivers/usb/core/config.c     2008-06-12 23:56:54.000000000 -0400
@@ -137,12 +137,16 @@
        if (to_usb_device(ddev)->speed == USB_SPEED_LOW &&
                        usb_endpoint_xfer_bulk(d)) {
                dev_warn(ddev, "config %d interface %d altsetting %d "
-                   "endpoint 0x%X is Bulk; changing to Interrupt\n",
-                   cfgno, inum, asnum, d->bEndpointAddress);
-               endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
-               endpoint->desc.bInterval = 1;
-               if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
-                       endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
+               "endpoint 0x%X is Bulk; this violates USB spec for "
+               "low speed devices.\n",
+               cfgno, inum, asnum, d->bEndpointAddress);
+//             dev_warn(ddev, "config %d interface %d altsetting %d "
+//                 "endpoint 0x%X is Bulk; changing to Interrupt\n",
+//                 cfgno, inum, asnum, d->bEndpointAddress);
+//             endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
+//             endpoint->desc.bInterval = 1;
+//             if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
+//                     endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
        }

и второго файла

--- linux-2.6.25/drivers/usb/host/uhci-q.c      2008-04-16 22:49:44.000000000 -0400
+++ linux-2.6.25-usbpatch/drivers/usb/host/uhci-q.c     2008-06-13 17:41:22.000000000 -0400
@@ -1042,8 +1042,8 @@
        int ret;
 
        /* Can't have low-speed bulk transfers */
-       if (urb->dev->speed == USB_SPEED_LOW)
-               return -EINVAL;
+//     if (urb->dev->speed == USB_SPEED_LOW)
+//             return -EINVAL;
 
        if (qh->state != QH_STATE_ACTIVE)
                qh->skel = SKEL_BULK;

Как видно, эти патчи для ядра 2.6.25!

Соответственно если у вас другое ядро, возможно придётся руками патчить, что я и сделал для своего 2.6.29.2.
Прикрепляю пропатченные файлы:

Пересобираем ядро:

make && make modules && make modules_install && make install

Finish

Незабудьте обеспечить себе права доступа к /dev/ttyACM0. В Debian достаточно юзеру войти в группу dialout.
После перезагрузки программатор заработает с avrdude.