[ Please CC me in replies, since I'm not subscribed to this list ] Hello all, I'm one of the owners of the HP un2400 WWAN card with the Qualcomm's Gobi chipset and today, after many hours of desperate tries, I've managed to upload firmware into this card and switch it into the modem mode. It works fine after that. The shell script that I've used as well as an auxiliary program to convert hex lists into strings are attached. I'm completely ignorant in what USB and serial protocols are concerned (in fact, I've spent the most time figuring out the correct settings for /dev/ttyUSB0), so I hope that someone with a better knowledge can rewrite my crude hack into a useful program that follows all the protocols and behaves nicely w.r.t. suspends etc. Below I'll describe what I did and why. My system is Debian Lenny with 2.6.28 kernel and qcserial.c driver from the current tree. 1) Background. Qualcomm chipset apparently contains two USB devices with different product IDs (can be found in drivers/usb/serial/qcserial.c). After initialization, only the first one is visible (QDL port, in qcserial's slang). It is used to upload firmware into the main modem device. After this is done, the QDL device is disconnected and the modem becomes visible to the system. This sequence is confirmed using a USB sniffer under Windows. Both devices use serial interface. The qcserial recognizes them correctly and logs the corresponding message if loaded with "debug" option. 2) Source of information: a) Log file of the Windows Qualcomm driver. I have found it in C:\Documents and Settings\All Users\Application Data\QUALCOMM\QDLService\QDLService.txt but your location can be different. b) List of the firmware corresponding to the correct wireless carrier found in the same directory (file Options.txt). c) UsbScoop sniffer 3) Protocol used. The firmware upload process consists of a couple of simple handshaking messages and verbatim shoving of the firmware into the corresponding serial interface. The firmware is sent in 1MB-long chunks with zero-length packets in between. One of the firmware file is cut short by 8 bytes for some reason. The correct length can be found in QDLService.txt This file contains all the messages completely, except that most of them are surrounded by 0xfe with the checksum added before sending (compare messages in QDLService.txt with those in my script). This is the only place where the sniffer is needed, since I wasn't able to guess the algorithm for this checksum. Perhaps someone can figure it out. Then all the information needed to upload the firmware will be contained in QDLService.txt completely. 4) Firmware Gobi uses different firmware for different wireless carriers. The current list can be found in C:\QUALCOMM\QDLService\ReadMe.rtf Running "strings" also helps. My carrier is AT&T in the US, so my script works for the corresponding firmware ONLY. I place the firmware into Gobi-Firmware directory (evident from the script). 5) About the script Very crude, basic, and (hopefully) self-explanatory. `send?' --- are the messages that have to be sent. `receive?' --- are those that are supposed to be received in return. They are not used in the script and are only included for information purposes. Everything sent back by the card is logged in Gobi-WWAN-response. So one can use hexdump to compare this output with what is expected. `sleep 0.1' are added to guarantee that that the response is received before the next message is sent. I don't know whether it is needed. `echo -n ""' send empty packets that are present in the sniffer log. I don't know whether this is important either. 0x00915188 in send2 and send3 and 0x0036711c in send4 and send5 are the lengths of the corresponding firmware files I guess that's about it. I will be happy to answer any questions that you might have about this procedure in general and my script in particular. I'm not subscribed to this list, so please CC: me into your replies to this message. I can also e-mail the USB sniffer's log file personally (it's large) if it can be of any help. Best, --- Alex.
#! /bin/sh # # This is a crude hack to load firmware into broadband WWAN modules that # incorporate Gobi chipset from Qualcomm. It appears to work with the HP # un2400 card and AT&T firmware taken from # C:\QUALCOMM\QDLService\Packages\2\AMSS.mbn # C:\QUALCOMM\QDLService\Packages\2\Apps.mbn # # The firmware has to be split into pieces of length 2^20 bytes (that is, 1MB). # Moreover, the last piece of AMSS.mbn has to be shorten by 8 bytes for some # reason. Its correct length is 86408 bytes. # # DISCLAIMER: # This software is NOT authorized to be used by neither Qualcomm nor HP. # It is very likely to damage or destroy your hardware and/or void your # warranty on it. Use it at your own risk. The author of this software # can in no way be held liable for any damage caused by your use of it. # USBdev=/dev/ttyUSB0 # compile with "gcc hex2str.c -o hex2str" hex2str=./hex2str firmware1="Gobi-Firmware/2/amss" firmware2="Gobi-Firmware/2/apps" firmsuffix="mbn" # This firmware is for AT&T _only_ md5sum -c --status <<- EOF 2eeb70c3e71b712374a26b2d36e0dfdf Gobi-Firmware/2/amss-01.mbn 7d9254bc8d70bd83a09fcdde2865ccf8 Gobi-Firmware/2/amss-02.mbn d7a01eece2da5dc5e1c8f4c5ce197025 Gobi-Firmware/2/amss-03.mbn 6fad55473e5a32a459152b8b817c2672 Gobi-Firmware/2/amss-04.mbn 9c55ad1934f61c4da8a28c74624549a9 Gobi-Firmware/2/amss-05.mbn 8604b77efc0442bfeb906b7379b98988 Gobi-Firmware/2/amss-06.mbn 4cdfcf70e8b13ea3dfc8b8833c44a42b Gobi-Firmware/2/amss-07.mbn 4b533b028693faa2010211aedea07019 Gobi-Firmware/2/amss-08.mbn 43241f8968a1e3c3f5a323691b6ac12d Gobi-Firmware/2/amss-09.mbn 5c9a794e424c676f4f75964bc0b80fad Gobi-Firmware/2/amss-10.mbn 999efd6c114f58847f4cf2c1957c949d Gobi-Firmware/2/apps-01.mbn 8ea05d62fa73826c4a50499e57bb4bac Gobi-Firmware/2/apps-02.mbn d96ee221642e328d145fbf6cd6717e93 Gobi-Firmware/2/apps-03.mbn 86bcadbcbafc376ad296e3c88e41750f Gobi-Firmware/2/apps-04.mbn EOF if [ $? = 1 ]; then echo "ERROR: Firmware check sum mismatch, exiting." exit 1 fi # Set the serial interface to be as raw as possible stty -F $USBdev raw -hupcl -cread -clocal -echo -echoe -echok -echoctl -echoke -onlcr -iexten responsefile=Gobi-WWAN-response # Save everything that the modem sends back to us. # This cat should quit by itself if everything works out fine when the QDL # device disconnects. We will try to kill it at the end just in case. cat $USBdev > $responsefile & catID=$! # ------------------------------------------------------------------------ send1="7e 01 51 43 4f 4d 20 68 69 67 68 20 73 70 65 65 64 20 70 72 \ 6f 74 6f 63 6f 6c 20 68 73 74 00 00 00 00 04 04 30 03 0b 7e" # receive1="7e 02 51 43 4f 4d 20 68 69 67 68 20 73 70 65 65 64 20 70 \ # 72 6f 74 6f 63 6f 6c 20 74 67 74 04 00 f0 cb 04 04 00 00 00 \ # 00 00 00 00 00 00 00 00 00 00 30 64 7a 7e" send2="7e 25 05 88 51 91 00 01 00 00 00 04 00 00 c4 e2 7e" # receive2="7e 26 00 00 01 00 00 00 04 52 65 7e" send3="27 00 00 00 00 00 00 88 51 91 00 b4 5c" # receive3="7e 28 00 00 00 00 00 00 00 00 14 39 7e" send4="7e 25 06 1c 71 36 00 01 00 00 00 04 00 00 98 ae 7e" # receive4="7e 26 00 00 01 00 00 00 04 52 65 7e" send5="27 00 00 00 00 00 00 1c 71 36 00 5b 21" # receive5="7e 28 00 00 00 00 00 00 00 00 14 39 7e" send6="7e 29 bb 4c 7e" # ------------------------------------------------------------------------ echo -n "Doing the initial handshake . . ." echo $send1 | $hex2str > $USBdev sleep 0.1 echo $send2 | $hex2str > $USBdev sleep 0.1 echo $send3 | $hex2str > $USBdev echo " done." echo -n "Sending the first firmware file" for i in 01 02 03 04 05 06 07 08 09 10; do cat ${firmware1}-$i.$firmsuffix > $USBdev if [ "$i" != "10" ]; then echo -n "" > $USBdev; fi echo -n " ." done echo " done." echo -n "Doing the intermediate handshake . . ." echo $send4 | $hex2str > $USBdev sleep 0.1 echo $send5 | $hex2str > $USBdev echo " done." echo -n "Sending the second firmware file" for i in 01 02 03 04; do cat ${firmware2}-$i.$firmsuffix > $USBdev if [ "$i" != "04" ]; then echo -n "" > $USBdev; fi echo -n " ." done echo " done." echo -n "Switching to the modem device . . ." echo $send6 | $hex2str > $USBdev echo " done???" sleep 2 catID=`ps --pid $catID -o pid=` if [ ! -z "$catID" ]; then kill $catID; fi
03/21/2009 06:01:41.500 Connect() 03/21/2009 06:01:41.625 Main() 03/21/2009 06:01:41.625 ReportStatus() 03/21/2009 06:01:41.625 Run( "Hewlett-Packard", 1 ) 03/21/2009 06:01:41.625 ReportStatus() 03/21/2009 06:03:54.359 Control() 03/21/2009 06:03:54.359 DeviceChange( ARRIVAL ) - \\?\USB#Vid_03f0&Pid_201d#5&11e1997e&0&2#{86e0d1e0-8089-11d0-9ce4-08003e301f73} 03/21/2009 06:03:54.781 PDA() - Attempting to start download thread, [COM6, vid_03f0&pid_201d#5&11e1997e&0&2] 03/21/2009 06:03:54.781 PDA() - Started download thread 248 (4648), [COM6, vid_03f0&pid_201d#5&11e1997e&0&2] 03/21/2009 06:03:55.000 QDL protocol server request sent 03/21/2009 06:03:55.000 0000 [9 03/21/2009 06:03:54.984] 03/21/2009 06:03:55.000 01 51 43 4F 4D 20 68 69 67 68 20 73 70 65 65 64 03/21/2009 06:03:55.000 20 70 72 6F 74 6F 63 6F 6C 20 68 73 74 00 00 00 03/21/2009 06:03:55.000 00 04 04 30 03/21/2009 06:03:55.015 QDL protocol server response received 03/21/2009 06:03:55.015 0001 [8 03/21/2009 06:03:55.015] 03/21/2009 06:03:55.015 02 51 43 4F 4D 20 68 69 67 68 20 73 70 65 65 64 03/21/2009 06:03:55.015 20 70 72 6F 74 6F 63 6F 6C 20 74 67 74 04 00 F0 03/21/2009 06:03:55.015 CB 04 04 00 00 00 00 00 00 00 00 00 00 00 00 00 03/21/2009 06:03:55.015 30 03/21/2009 06:03:55.015 QDL sending image file: C:\QUALCOMM\QDLService\Packages\2\AMSS.mbn 03/21/2009 06:03:55.031 QDL protocol server request sent 03/21/2009 06:03:55.031 0002 [9 03/21/2009 06:03:55.031] 03/21/2009 06:03:55.031 25 05 88 51 91 00 01 00 00 00 04 00 00 03/21/2009 06:03:55.031 QDL protocol server response received 03/21/2009 06:03:55.031 0003 [8 03/21/2009 06:03:55.031] 03/21/2009 06:03:55.031 26 00 00 01 00 00 00 04 03/21/2009 06:03:55.265 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:55.390 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:55.546 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:55.828 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:56.062 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:56.296 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:56.437 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:56.578 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:56.671 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:56.687 QDL protocol server sent 86408 bytes of image 03/21/2009 06:03:56.687 QDL protocol server request sent 03/21/2009 06:03:56.687 0004 [9 03/21/2009 06:03:56.687] 03/21/2009 06:03:56.687 27 00 00 00 00 00 00 88 51 91 00 B4 5C 03/21/2009 06:03:56.890 QDL protocol server response received 03/21/2009 06:03:56.890 0005 [8 03/21/2009 06:03:56.890] 03/21/2009 06:03:56.890 28 00 00 00 00 00 00 00 00 03/21/2009 06:03:56.890 Sending image file: C:\QUALCOMM\QDLService\Packages\2\Apps.mbn 03/21/2009 06:03:56.890 QDL protocol server request sent 03/21/2009 06:03:56.890 0006 [9 03/21/2009 06:03:56.890] 03/21/2009 06:03:56.890 25 06 1C 71 36 00 01 00 00 00 04 00 00 03/21/2009 06:03:56.937 QDL protocol server response received 03/21/2009 06:03:56.937 0007 [8 03/21/2009 06:03:56.937] 03/21/2009 06:03:56.937 26 00 00 01 00 00 00 04 03/21/2009 06:03:57.187 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:57.312 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:57.437 QDL protocol server sent 1048576 bytes of image 03/21/2009 06:03:57.468 QDL protocol server sent 422172 bytes of image 03/21/2009 06:03:57.468 QDL protocol server request sent 03/21/2009 06:03:57.468 0008 [9 03/21/2009 06:03:57.468] 03/21/2009 06:03:57.468 27 00 00 00 00 00 00 1C 71 36 00 5B 21 03/21/2009 06:03:57.593 QDL protocol server response received 03/21/2009 06:03:57.593 0009 [8 03/21/2009 06:03:57.593] 03/21/2009 06:03:57.593 28 00 00 00 00 00 00 00 00 03/21/2009 06:03:57.593 QDL protocol server request sent 03/21/2009 06:03:57.593 0010 [9 03/21/2009 06:03:57.593] 03/21/2009 06:03:57.593 29 03/21/2009 06:03:58.109 QDL protocol server response timeout 03/21/2009 06:03:58.109 QDL download complete 03/21/2009 06:03:58.796 CT() - Waiting for device removal (1 of 30) 03/21/2009 06:03:59.796 CT() - Waiting for device removal (2 of 30) 03/21/2009 06:04:00.796 CT() - Waiting for device removal (3 of 30) 03/21/2009 06:04:00.984 Control() 03/21/2009 06:04:00.984 DeviceChange( REMOVE ) - \\?\USB#Vid_03f0&Pid_201d#5&11e1997e&0&2#{86e0d1e0-8089-11d0-9ce4-08003e301f73} 03/21/2009 06:04:00.984 CT() - Closed download thread 248, [COM6, vid_03f0&pid_201d#5&11e1997e&0&2, 0] 03/21/2009 06:04:03.921 Control() 03/21/2009 06:04:03.921 DeviceChange( ARRIVAL ) - \\?\USB#Vid_03f0&Pid_1f1d&MI_00#6&368ee46f&0&0000#{86e0d1e0-8089-11d0-9ce4-08003e301f73} 03/21/2009 06:04:04.953 Control() 03/21/2009 06:04:04.953 DeviceChange( ARRIVAL ) - \\?\USB#Vid_03f0&Pid_1f1d&MI_01#6&368ee46f&0&0001#{86e0d1e0-8089-11d0-9ce4-08003e301f73} 03/21/2009 06:06:59.046 Control() 03/21/2009 06:07:24.875 Control()
#include <stdio.h> #include <ctype.h> #include <stdio.h> int main (void) { int inchar, outchar = 0, hexfound = 0; while ((inchar = getchar()) != EOF) { if (isspace(inchar)) { if (hexfound) printf("%c", outchar); hexfound = 0; outchar = 0; continue; } if (isxdigit(inchar)) { if (inchar >= 'a' && inchar <= 'f') inchar += 10 - 'a'; else if (inchar >= 'A' && inchar <= 'F') inchar += 10 - 'A'; else if (inchar >= '0' && inchar <= '9') inchar -= '0'; else perror("Something is wrong with hex digits"); outchar = (outchar << 4) + inchar; hexfound = 1; continue; } putchar (inchar); } return 0; }