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.