配置内核
添加USB设备信息
U9300C 的 USB 设备 VID :0x1c9e PID: 0x9b3c 。打开Linux源码 drivers/usb/serial/option.c 文件。定义模块信息:
/* Longsung 4G */
#define LONGSUNG_VENDOR_ID 0x1c9e
#define LONGSUNG_PRODUCT_U9300C_CN 0x9b3c
找到option_ids数组,然后在里面添加U9300C的PID和VID,如下:
添加ECM支持的程序,修改drivers/usb/serial/option.c 文件里的 option_probe 函数。找到此函数,然后里面输入如下内容:
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
struct usb_interface_descriptor *iface_desc =
&serial->interface->cur_altsetting->desc;
struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
const struct option_blacklist_info *blacklist;
/* Never bind to the CD-Rom emulation interface */
if (iface_desc->bInterfaceClass == 0x08)
return -ENODEV;
/*
* Don't bind reserved interfaces (like network ones) which often have
* the same class/subclass/protocol as the serial interfaces. Look at
* the Windows driver .INF files for reserved interface numbers.
*/
blacklist = (void *)id->driver_info;
if (blacklist && test_bit(iface_desc->bInterfaceNumber,
&blacklist->reserved))
return -ENODEV;
/*
* Don't bind network interface on Samsung GT-B3730, it is handled by
* a separate module.
*/
if (dev_desc->idVendor == cpu_to_le16(SAMSUNG_VENDOR_ID) &&
dev_desc->idProduct == cpu_to_le16(SAMSUNG_PRODUCT_GT_B3730) &&
iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
return -ENODEV;
/* EC20 */
if (dev_desc->idVendor == cpu_to_le16(0x05c6) &&
dev_desc->idProduct == cpu_to_le16(0x9003) &&
iface_desc->bInterfaceNumber >= 4)
return -ENODEV;
if (dev_desc->idVendor == cpu_to_le16(0x05c6) &&
dev_desc->idProduct == cpu_to_le16(0x9215) &&
iface_desc->bInterfaceNumber >= 4)
return -ENODEV;
if (dev_desc->idVendor == cpu_to_le16(0x2c7c) &&
iface_desc->bInterfaceNumber >= 4)
return -ENODEV;
/*********************************************************/
if (serial->dev->descriptor.idVendor == cpu_to_le16(LONGSUNG_VENDOR_ID) &&
serial->dev->descriptor.idProduct == cpu_to_le16(LONGSUNG_PRODUCT_U9300C_CN) &&
serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) {
printk(KERN_INFO"DISCOVER THE 4TH interface for u9300c NDIS \n");
return -ENODEV;
}
/*********************************************************/
/* Store the blacklist info so we can use it during attach. */
usb_set_serial_data(serial, (void *)blacklist);
return 0;
}
修改drivers/usb/serial/usb_wwan.c 文件里的usb_wwan_setup_urb 函数,如下:
static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
int endpoint,
int dir, void *ctx, char *buf, int len,
void (*callback) (struct urb *))
{
struct usb_serial *serial = port->serial;
struct urb *urb;
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
if (!urb)
return NULL;
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev, endpoint) | dir,
buf, len, callback, ctx);
/* EC20 */
if (dir == USB_DIR_OUT) {
struct usb_device_descriptor *desc = &serial->dev->descriptor;
if (desc->idVendor == cpu_to_le16(0x05c6) && desc->iProduct == cpu_to_le16(0x9090))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x05c6) && desc->iProduct == cpu_to_le16(0x9003))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x05c6) && desc->iProduct == cpu_to_le16(0x9215))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x2c7c))
urb->transfer_flags |= URB_ZERO_PACKET;
if (desc->idVendor == cpu_to_le16(0x1c9e))
urb->transfer_flags |= URB_ZERO_PACKET;
}
return urb;
}
配置Linux内核
make menuconfig
首先使能usbnet功能,路径如下:
配置如图所示:
还需要是能USB串口GSM、CDMA驱动,配置路径如下:
配置如图:
接着配置Linux内核,使能USB的CDC、ACM模式,配置路径如下:
配置如图:
编译Linux内核,系统启动后就会输出如下内容:
会虚拟出4个USB设备,分别为ttyUSB0~3。
如果U9300C未出现usb0网口,并且未出现如下打印:
cdc_ether 1-1.2:1.4 usb0: register 'cdc_ether' at usb-ci_hdrc.1-1.2, CDC Ethernet Device, 1a:c3:ad:7e:b6:ff
说明模块处于ndis模式,需要设置成ECM模式,如下指令:
echo "AT+LSHECMEN=1,1" >> /dev/ttyUSB2
等待模块重启。就会出现usb0网口。
到此配置结束,通过ECM上网。
udhcpc 功能
给usb0分配IP。
如上图,代表未申请IP成功。
解决方法如下:
mkdir -p /usr/share/udhcpc/
touch /usr/share/udhcpc/default.script
/usr/share/udhcpc/default.script 内容如下:
#!/bin/sh
# udhcpc script edited by Tim Riker <Tim@Rikers.org>
RESOLV_CONF="/etc/resolv.conf"
[ -n "$1" ] || { echo "Error: should be called from udhcpc"; exit 1; }
NETMASK=""
[ -n "$subnet" ] && NETMASK="netmask $subnet"
BROADCAST="broadcast +"
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
case "$1" in
deconfig)
echo "Setting IP address 0.0.0.0 on $interface"
ifconfig $interface 0.0.0.0
;;
renew|bound)
echo "Setting IP address $ip on $interface"
ifconfig $interface $ip $NETMASK $BROADCAST
if [ -n "$router" ] ; then
echo "Deleting routers"
while route del default gw 0.0.0.0 dev $interface ; do
:
done
metric=0
for i in $router ; do
echo "Adding router $i"
if [ "$subnet" = "255.255.255.255" ]; then
# special case for /32 subnets:
# /32 instructs kernel to always use routing for all outgoing packets
# (they can never be sent to local subnet - there is no local subnet for /32).
# Used in datacenters, avoids the need for private ip-addresses between two hops.
ip route add $i dev $interface
fi
route add default gw $i dev $interface metric $((metric++))
done
fi
echo "Recreating $RESOLV_CONF"
# If the file is a symlink somewhere (like /etc/resolv.conf
# pointing to /run/resolv.conf), make sure things work.
realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF")
tmpfile="$realconf-$$"
> "$tmpfile"
[ -n "$domain" ] && echo "search $domain" >> "$tmpfile"
for i in $dns ; do
echo " Adding DNS server $i"
echo "nameserver $i" >> "$tmpfile"
done
mv "$tmpfile" "$realconf"
;;
esac
exit 0
之后再运行命令:
udhcpc -i usb0
成功如下图: