嵌入式linux是2.6.24版的。主机是AT9261(arm926ej-s内核)的开发板。
买是市面上常见的中兴AC2746 usb接口的3G上网卡。在windows下使用极方便,可是在linux下使用就麻烦了。
首先,要确认你的嵌入式linux系统是可以支持热插拔的系统。(我用的是mdev方式支持热插拔)
然后,是驱动的安装。AC2746没有专门linux下的驱动。不过,它的usb口在windows系统中实际是用usb转串口的方式转为串口工作的。那么,在linux下同样也可以用usb转串口的方式来使用。linux内核自带了usb转串口的驱动。在内核的编译选择中,选中
Device Drivers ---> [*] USB support ---> USB Serial Converter support ---> USB Serial Converter support
再选中其下的USB driver for GSM and CDMA modems 的选项即可。要注意的是,编译方式一定要选为模块化编译。
选定这两项后,执行make modules命令,会编译源码中/driver/usb/serial/目录下的usb-serial.c和option.c两个文件及其它一些相关文件。
Device Drivers ---> [*] USB support ---> USB Serial Converter support ---> USB Serial Converter support
再选中其下的USB driver for GSM and CDMA modems 的选项即可。要注意的是,编译方式一定要选为模块化编译。
选定这两项后,执行make modules命令,会编译源码中/driver/usb/serial/目录下的usb-serial.c和option.c两个文件及其它一些相关文件。
在option.c中,可以看到已经定义了很多设备的描述符,但没有定义AC2746的描述符。我们自已定义一下即可。方法是,在源码中,添加
#define ZTE_VENDOR_ID 0x19d2
#define ZTE_PRODUCT_AC2746 0xfff1
在
option_ids[]的数组中添加
#define ZTE_PRODUCT_AC2746 0xfff1
在
option_ids[]的数组中添加
{ USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2746) },
完成后,重新编译即可。 将生成的/driver/usb/serial/usbserial.ko,option.ko拷贝到嵌入式linux根文件系统的/lib/modules/2.6.24目录下。
执行
insmod /lib/modules/2.6.24/usbserial.ko
insmod /lib/modules/2.6.24/option.ko
执行
insmod /lib/modules/2.6.24/usbserial.ko
insmod /lib/modules/2.6.24/option.ko
插入AC2746,通常系统会认为是cdrom和usb stroage设备插入,并会生成/dev/sr0文件(我用的mdev方式生成设备文件,如果你用的是其它方式,可能设备名会不一样)。这时,输入eject /dev/sr0命令,则系统会自动删除/sr0,并重新确认AC2746,这时,就会认出它是一个cdma数据卡,并自动生成/dev/ttyUSB0,/dev/ttyUSB1,
/dev/ttyUSB2,/dev/ttyUSB3,/dev/ttyUSB4,共5个串行口。这一步是最容易出错的,现象是没有生成这几个设备文件。出错的原因主要是设备描述符没有在驱动程序中定义,查看一下你的CDMA卡的设备描述符。方法是,把CDMA数据卡插到桌面版的linux下,执行lsusb命令即可查看到,然后修改option.c中的设备描述符。有了这几个设备,就成功了一大半。
/dev/ttyUSB2,/dev/ttyUSB3,/dev/ttyUSB4,共5个串行口。这一步是最容易出错的,现象是没有生成这几个设备文件。出错的原因主要是设备描述符没有在驱动程序中定义,查看一下你的CDMA卡的设备描述符。方法是,把CDMA数据卡插到桌面版的linux下,执行lsusb命令即可查看到,然后修改option.c中的设备描述符。有了这几个设备,就成功了一大半。
接下来,是安装pppd拨号软件。网上有很多相关资料,我不多说了。安装好后,要写两个脚本。一个是在/etc/ppp/peers/evdo文件。内容如下
# Usage: root>pppd call evdo
# Privied by hugerat
/dev/ttyUSB0
921600
crtscts
modem
debug
nodetach
usepeerdns
noipdefault
defaultroute
user ctnet@mycdma.cn
password vnet.mobi
0.0.0.0:0.0.0.0
connect '/usr/sbin/chat -s -v -f /etc/ppp/evdo-connect-chat'
# Privied by hugerat
/dev/ttyUSB0
921600
crtscts
modem
debug
nodetach
usepeerdns
noipdefault
defaultroute
user ctnet@mycdma.cn
password vnet.mobi
0.0.0.0:0.0.0.0
connect '/usr/sbin/chat -s -v -f /etc/ppp/evdo-connect-chat'
其中,user和password项可能会因为地区不同而不同(这两项是南京地区的)
再建立/etc/ppp/evdo-connect-chat文件,文件内容如下:
#/etc/ppp/evdo-connect-chat
# chat script for China telecom, used AC2746.
# Privided by hugerat
TIMEOUT 15
ABORT "DELAYED"
ABORT "BUSY"
ABORT "ERROR"
ABORT "NO DIALTONE"
ABORT "NO CARRIER"
TIMEOUT 15
"" AT
OK ATE0
OK AT/^PREFMODE=8
OK ATDT#777
CONNECT
再建立/etc/ppp/evdo-connect-chat文件,文件内容如下:
#/etc/ppp/evdo-connect-chat
# chat script for China telecom, used AC2746.
# Privided by hugerat
TIMEOUT 15
ABORT "DELAYED"
ABORT "BUSY"
ABORT "ERROR"
ABORT "NO DIALTONE"
ABORT "NO CARRIER"
TIMEOUT 15
"" AT
OK ATE0
OK AT/^PREFMODE=8
OK ATDT#777
CONNECT
要说明的一项是AT/^PREFMODE=8,这个是设置模块工作模式的。2表示用CDMA 1X模式。4表示EVDO模式,8表示混和模式。模块默认是用2,即CDMA 1X模式。如果你要使用EVDO高速上网就要设为4或8。
但是你会发现网速并没有达到evdo的正常速度。这是因为,usb-serial.c并不是为高速外设设计的,它的缓存开的太小,要把缓存开大。方法如下。
创建一个usbserial.c的补丁文件/root/usbserial.c.patch,内容如下:
--- linuxold/drivers/usb/serial/usb-serial.c 2006-12-31 17:40:28.000000000 -0600
+++ linux/drivers/usb/serial/usb-serial.c 2009-05-02 23:55:08.000000000 -0600
@@ -58,4 +58,5 @@
*/
+static ushort maxRSize, maxWSize, maxISize;
static int debug;
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
@@ -817,4 +818,6 @@
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (buffer_size < maxRSize)
+ buffer_size = maxRSize;
port->bulk_in_size = buffer_size;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
@@ -841,4 +844,6 @@
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (buffer_size < maxWSize)
+ buffer_size = maxWSize;
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
@@ -866,4 +871,6 @@
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (buffer_size < maxISize)
+ buffer_size = maxISize;
port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
@@ -1191,2 +1198,8 @@
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(maxRSize, ushort, 0);
+MODULE_PARM_DESC(maxRSize, "User specified USB input buffer size");
+module_param(maxWSize, ushort, 0);
+MODULE_PARM_DESC(maxWSize, "User specified USB output buffer size");
+module_param(maxISize, ushort, 0);
+MODULE_PARM_DESC(maxISize, "User specified USB interrupt buffer size");
+++ linux/drivers/usb/serial/usb-serial.c 2009-05-02 23:55:08.000000000 -0600
@@ -58,4 +58,5 @@
*/
+static ushort maxRSize, maxWSize, maxISize;
static int debug;
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
@@ -817,4 +818,6 @@
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (buffer_size < maxRSize)
+ buffer_size = maxRSize;
port->bulk_in_size = buffer_size;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
@@ -841,4 +844,6 @@
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (buffer_size < maxWSize)
+ buffer_size = maxWSize;
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
@@ -866,4 +871,6 @@
}
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (buffer_size < maxISize)
+ buffer_size = maxISize;
port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
@@ -1191,2 +1198,8 @@
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(maxRSize, ushort, 0);
+MODULE_PARM_DESC(maxRSize, "User specified USB input buffer size");
+module_param(maxWSize, ushort, 0);
+MODULE_PARM_DESC(maxWSize, "User specified USB output buffer size");
+module_param(maxISize, ushort, 0);
+MODULE_PARM_DESC(maxISize, "User specified USB interrupt buffer size");
这个文件是我在网上找到的,并不是2.6.24版的,不能直接为usb-serial.c打上补丁,不过,没关系,你可以手工添加带“+”号的信息到指定的位置即可。
完成后,重新编译生成usbserial.ko文件。
insmod /lib/modules/2.6.24/usbserial.ko命令改为如下
insmod /lib/modules/2.6.24/usbserial.ko maxRSize=4096 maxWSize=1024
这样,再试试网速吧,一切正常了。
上述方法在AC2746上测试正常,其它的网卡应该也可以,只是要注意修改相应的设备描述符即可。