- 1
- 2
- 3
- 4
- 5
- 6
- 7
// drivers/usb/serial/cp210x.c
static void cp210x_close(struct usb_serial_port *port)
{
usb_serial_generic_close(port);
cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
}
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+139
// drivers/usb/serial/cp210x.c
static void cp210x_close(struct usb_serial_port *port)
{
usb_serial_generic_close(port);
cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
}
Дело было так.
На прошлой неделе, по просьбе одного знакомого, я сел писать прошивку для attiny2313, которая должна принять по RS-232 строчку и исполнить соответствующую команду. Потратив несколько минут на раскур даташита, а именно главы, посвященной USART, я набросал тупейший код на сях, залил его на чип, и затестил через миником. Все работало нормально, ничто не предвещало беды...
Но когда я попробовал послать команду через echo, меня ждал облом. Она не выполнилась. На 10 раз проверил код - все ок, в миникоме пашет идеально, через echo - куй. Под виндой та же ересь. Чем отличается echo от миникома? Правильно, тем, что оно отправляет символы подряд, без пауз. Контроллер тактировался от внутренного генератора, поэтому я подумал, что оный хреново откалиброван, и что надо бы его настроить... Вечер ушел на написание прошивки для калибровки... Оказалось, что частота действительно уплыла на 2% от расчетной, что некритично. Ну да пофиг, откалибровался до +-0.5%. Запустил echo - куй. Послал все нахрен, и пошел спать...
(Продолжение в комменте ниже)
bormand 26.11.2013 16:05 # +4
На следующий вечер я залил на чип эхо-тест: кидаешь ему байтики, он их отправляет обратно. Тест, внезапно, работал. Идеально. И в миникоме и в echo, и в самопальной сишной проге... Уже договорился с другом, что на следующий день забегу к нему за логическим анализатором, ибо баттхерт становился все сильнее и сильнее... Но спать еще не хотелось, поэтому just for lulz написал для контроллера счетчик полученных байт, которые, для чистоты эксперимента, прошивка выводила на банальный семисегментник. В minicom'е все было нормально, а echo и моя прога, состоящая из open/write/close насчитывали только один байт (хотя write исправно докладывал, что записал столько байт, сколько просили, и даже close не возвращал ошибок)...
В этот момент до меня начало доходить, что в миникоме и при эхо-тестировании я еще и читал из порта, а echo туда только пишет. Я добавил к прошивке подтверждение в виде "OK\n", и его чтение на стороне линухи... и, о чудо!, всё заработало. Убрал read - один байт. Вернул на место - все норм. Поменял read на sleep - все норм. Вот тут-то до меня и начало доходить, что кривые руки не у меня, а у разрабов дров...
Покопавшись в исходниках ядра, я понял в чем было дело... Во время записи драйвер отправлял по usb весь мой пакет на конвертер, и сообщал что все зашибись. А во время закрытия дескриптора он сразу же посылал команду на отключение UART'а на конвертере. Т.к. порт работал медленно (9600), за это время на выход конвертера успевал попасть только тот самый первый байт...
Вот такая вот история произошла из-за шестой строчки в приведенном выше коде ;)
TarasB 26.11.2013 16:12 # +1
guest 26.11.2013 16:18 # −3
http://govnokod.ru/14139#comment202648
guest 26.11.2013 16:18 # −3
bormand 26.11.2013 16:20 # +1
А с подтверждением от чипа ("OK\n") все стабильно работает. Да так и кошерней даже. Обидно только, что эхо не поюзать для отправки команд.
guest 26.11.2013 16:21 # −2
defecate-plusplus 26.11.2013 16:28 # +2
тебе надо закрыть девайс, и тебе пофиг, что у него осталось в буфере отправки и в каком состоянии сейчас передача
иначе ты зашлёшь туда порноролик на 9600 бод/с и будешь ждать до скончания века
defecate-plusplus 26.11.2013 16:36 # +2
как минимум, надо дождаться хоть какого-нибудь вменяемого ACK/NAK - на последовательном порту легко проебутся байты, и эффект будет потрясающий
и не забыть про засылку длины и подписи пакета (lrc, crc, да хоть черта лешего из xor байтов хотя бы)
bormand 26.11.2013 16:47 # 0
Так и сделал ;) Ну если, конечно, считать "OK\n" вменяемым.
> и не забыть про засылку длины и подписи пакета (lrc, crc, да хоть черта лешего из xor байтов хотя бы)
Блин, ну я же не контроллер для опускания стержней в ядерный реактор делал, и даже не прошивку для тормозной системы автомобиля... CRC, длина и Start-of-frame это конечно хорошо, но тогда теряется прелесть ручного управления через терминал :) В цисках вон нет контрольной суммы, и протокол текстовый, но вполне юзабельно.
defecate-plusplus 26.11.2013 17:00 # +1
а вот огребать проблемы от того, что на ком-порту включенный parity check не спасает (и, порой, даже сраный xor) - на старой работе очень часто
особенно было весело, когда в одном из проектов решили немного подзабить на эту особенность и управляющий справочник прилетал по ком-порту, мягко говоря, не заебись
bormand 26.11.2013 17:54 # 0
А как в итоге решили проблему? Побили справочник на более мелкие пакеты, каждый из которых был покрыт своей crc?
defecate-plusplus 26.11.2013 18:49 # +1
как решили - при мне никак, т.к. сбоило лишь в 1% случаев, оставили решение на тот квартал, когда я уже успел уволиться :)
а в сетапах, где заранее учитывались помехи, всё разбито на мелкие пакеты, каждый из которых имеет контрольную сумму, которые затем собираются в нечто большое (например, справочник, или вообще дистрибутив софта для самообновления), для которого вцелом самостоятельно есть контрольная сумма
anonimb84a2f6fd141 26.11.2013 23:06 # −4
defecate-plusplus 27.11.2013 07:38 # 0
krypt 26.11.2013 17:37 # 0
bormand 26.11.2013 17:44 # 0
Dummy00001 26.11.2013 21:29 # 0
Не гони. Она есть. На файл дескриптор ставишь флаг O_SYNC.
Пару дров которые я писал в прошлом именно так это и поддерживали. И если я правильно помню, то я об этом не сам догадался - а где-то подсмотрел.
И к слову. Именно с синком, close() тоже имеет право становится блокирующим что бы дождатся окончания всех pending операций и вернуть в rc их статус.
Ну да твою проблему с echo это не решит, потому что там некому поставить O_SYNC на дескриптор. Надо кастом прогу писать для этой цели.
bormand 26.11.2013 21:51 # 0
Ну так это надо чтобы дрова поддерживали. Вроде бы я даже пробовал этот O_SYNC, но точно не помню... Завтра, если не будет лень, восстановлю макетку, попробую. fsync() тоже пробовал, думал подвесится, пока все не уйдет - фиг там.
> Надо кастом прогу писать для этой цели.
Ну да. А с кастомной прогой проблемы и нет, там подтверждение можно замутить, и труба раньше времени уже не закроется ;)
Dummy00001 26.11.2013 22:36 # +1
> > http://lxr.free-electrons.com/source/drivers/usb/serial/generic.c#L103
Ндя. В старые времена вроде бы как для char device'ов это было нормой O_SYNC поддерживать. Ну да хез какие соглашения для USB устройств.
Ну да в добавок это как бы традиционные серийные устройства с которыми я никогда в глубину не работал. (*) Если я не ошибаюсь они тоже синка не поддерживали, а вместо этого буффер на 1 байт ставили. Это вроде tcsetattr()/друзья. Трэйсни minicom (strace на линухе) глять что он там с устройством делает.
(*) Я как раз для серийных девайсов и делал сетевой интерфейс что бы можно было connect()/bind()/send()/recv() делать. Но там те же грабли были, потому что серийную линию надо на самом деле сбрасывать, потому что приложение ее может слегка подкофигурить, и без сброса, старые настройки будут действительны для ново-подключившихся приложений. Вообщем темный лес.
bormand 26.11.2013 22:48 # 0
P.S. Судя по сырцам она кидает TCSBRK, который делает tty_wait_until_sent, который вызывает "метод" wait_until_set у tty драйвера, который реализован в generic usb serial. Т.е. может даже проканать :)
bormand 26.11.2013 22:58 # 0
Завтра вечерком восстановлю макетку, попробую tcdrain() перед close() сделать.
Dummy00001 26.11.2013 23:25 # 0
В какой-то степени теперь я понимаю почему в кернел это долго отказывались включать: потому что интерфейс дерьмо и его никто не фиксит.
У меня с сетевым интерфейсом было все жутко просто: bind() или connect() со спец PF_BLAHBLAH и настройками в спец sockaddr, а дальше send()/recv() со всеми примочками работли как обычно для DGRAM сокетов, включая SYNC и PEEK.
bormand 27.11.2013 05:33 # 0
Dummy00001 27.11.2013 14:43 # +1
Там было не все так просто. 32 порта на контроллер, 4ре контроллера на борде, и частичная хардварная поддержка MTP2/MTP3 (из SS7) + мои кернеловы приблуды для полноты MTP3 (если сокет в DGRAM режиме, иначе, в STREAM, просто сырая серийная линия).
http://en.wikipedia.org/wiki/E1-carrier#E1_frame_structure
"Или на том конце девайс был не линуксовый [...]?"
Если не ошибаюсь, на другом конце того что я писал, типично находлся либо HLR, либо ISDN клиент. :)
Stertor 26.11.2013 19:03 # −3
В мое время логические элементы составляли сами - на транзисторах. Спаиваешь их по схеме, и готов либо усилитель НЧ либо радиоприемник. Сейчас же берут готовую микросхему, вбивают в нее код - и вуаля. Транзисторы нах никому не нужны.
anonimb84a2f6fd141 26.11.2013 23:08 # −4
Седомудый в треде.
Stertor 27.11.2013 11:08 # −2
anonimb84a2f6fd141 27.11.2013 12:14 # −3
bormand 27.11.2013 12:28 # 0
Мультивибраторы и приемники?
roman-kashitsyn 27.11.2013 12:32 # +2
anonimb84a2f6fd141 27.11.2013 12:38 # −4
anonimb84a2f6fd141 27.11.2013 13:19 # −3
Stertor 27.11.2013 13:35 # 0
Stertor 27.11.2013 13:27 # −1
anonimb84a2f6fd141 27.11.2013 15:22 # 0
Я вообще ничего не собрал, кроме мигалки на мультивибраторе по книжке. Зато от нехуй делать распаивал телевизоры на детали.
anonimb84a2f6fd141 27.11.2013 16:07 # 0
defecate-plusplus 27.11.2013 12:47 # +3
Dummy00001 26.11.2013 21:23 # +1
Гыгы. Пока на эти грябли не наступишь - настоящим системщиком не станешь!
roman-kashitsyn 26.11.2013 16:29 # +2
борманд, это про тебя
bormand 26.11.2013 16:48 # +2
guest 26.11.2013 17:24 # −6
Stertor 26.11.2013 17:45 # −8
Stertor 26.11.2013 19:03 # −7
guest 26.11.2013 20:40 # −1
?
Stertor 26.11.2013 20:42 # −4
bormand 26.11.2013 20:53 # +4
guest 26.11.2013 21:51 # −4
inkanus-gray 28.11.2013 01:08 # +6
Stertor 27.11.2013 11:09 # −1