USB 3g nic Driver Process
Introduction
First, we will introduce the overall driver mode in Linux:
The Linux kernel version based on this article is 2.6.36 (and the Huawei em770w driver is customized by friendlyarm.
Therefore, this driver can be downloaded from a friendly official website. Its macro is defined as config_mach_mini6410)
Bus, device, and driver: The three are associated with each other. The device list and driver list are available on the bus. When a device is connected
Traverse all the drivers on the bus and find the drivers that support them. Then, the driver pointer under the device structure points to the driver.
Similarly, the driver adds the device to its own device pointer list.
3G Nic is a USB device, so we will introduce the USB driver.
Bus
USB Bus struct bus_type usb_bus_type ={}; // Let's look at the struct of the bus.
In the [INCLUDE/Linux/device. H] File
Struct bus_type {
Const char * Name;
......
Struct bus_type_private * P;
};
In the [Drivers/base. H] File
Struct bus_type_private {
Struct kset subsys;
Struct kset * drivers_kset;
Struct kset * devices_kset;
Struct klist klist_devices;
Struct klist klist_drivers;
Struct blocking_notifier_head bus_notifier;
Unsigned int drivers_autoprobe: 1;
Struct bus_type * bus;
};
Klist_devices and klist_drivers are the lists of devices and drivers on the bus. When a new device is connected or
Driver. These two lists are traversed.
Device
The following uses usb_device as an example.
[INCLUDE/Linux/USB. H] File
Struct usb_device {
......
Struct usb_bus * bus; // The bus pointing to the device
......
Struce device dev; // attributes of General devices in Linux
};
In the [INCLUDE/Linux/device. H] File
Struct device {
......
Struct device_driver * driver;/* Which driver has allocated this device */
......
};
Here there is the bus and driver pointer that the device points. A device uses a driver. The supported devices are listed in the following drivers.
Table. The driver supports a series of devices.
Driver
Taking opton_driver as an example [Drivers/USB/serial/option. C]
Static struct usb_driver option_driver = {
. Name = "option ",
. Probe = usb_serial_probe,
. Disconnect = usb_serial_disconnect,
# Ifdef config_pm
. Suspend = usb_serial_suspend,
. Resume = usb_serial_resume,
. Supports_autosuspend = 1,
# Endif
. Id_table = option_ids,
. No_dynamic_id = 1,
};
[INCLUDE/Linux/USB. H] File
Struct usb_driver {
Const char * Name;
......
Struct usbdrv_wrap drvwrap;
......
};
Struct usbdrv_wrap {
Struct device_driver driver;
Int for_devices;
};
In the [INCLUDE/Linux/device. H] File
Struct device_driver {
......
Struct bus_type * bus; // the bus to which the driver belongs
......
Struct driver_private * P;
......
};
In the [Drivers/base. H] File
Struct driver_private {
Struct kobject kobj;
Struct klist klist_devices; // list of devices using this driver
Struct klist_node knode_bus;
Struct module_kobject * mkobj;
Struct device_driver * driver;
};
Option-driven bus assignment
When option is initialized in [Drivers/USB/serial/option. C], the driver bus is assigned a value during the registration process.
Static int _ init option_init (void)
{
Retval = usb_register (& option_driver );
}
[INCLUDE/Linux/USB. H]
Static inline int usb_register (struct usb_driver * driver)
{
Return usb_register_driver (driver, this_module, kbuild_modname );
}
[Drivers/USB/CORE/driver. C] File
Int usb_register_driver (struct usb_driver * new_driver, struct module * owner,
Const char * mod_name)
{
New_driver-> drvwrap. Driver. Bus = & usb_bus_type;
New_driver-> drvwrap. Driver. Probe = usb_probe_interface;
}
Legend
Take Huawei em770w as an Example
Take the Huawei em770w WCDMA 3G Nic as an example.
In the Kernel File Linux/Drivers/USB/serial/option. C.
Static const struct usb_device_id option_ids [] = {
{Usb_device_and_interface_info (incluwei_vendor_id, incluwei_product_e600, 0xff, 0xff, 0xff )},
}
This row is defined. The. idproduct read from the device em770w is the same as the value defined by incluwei_product_e600.
When a USB device is inserted, hub_event time is triggered to call the function.
I. Add a USB device
Hub_events (); --> hub_port_connect_change ();
--> Udev = usb_alloc_dev (hdev, hdev-> bus, port1); // assign & usb_bus_type to the device
Usb_new_device (udev );
--> Device_add (& udev-> Dev); (Drivers/base/CORE. c)
--> Bus_add_device (Dev); // Add the device to the bus device list
// Klist_add_tail (& Dev-> P-> knode_bus, & bus-> P-> klist_devices );
Bus_probe_device (Dev );
--> Device_attach (Dev); [Drivers/base/DD. C]
--> Bus_for_each_drv (Dev-> bus, null, Dev, _ device_attach); // traverse the driver and find
Driver
-- >__ Device_attach (DRV, Dev); // The driver USB to be found supports this device.
--> Driver_probe_device (DRV, Dev );
--> Really_probe (Dev, DRV); [Drivers/base/DD. C]
--> DRV-> probe (Dev); // actually call usb_probe_device (Dev); [Drivers/USB/CORE/driver. C]
--> Udriver-> probe (udev); // actually called generic_probe (udev); [Drivers/USB/CORE/generic. C]
--> Usb_set_configuration (udev, c); [Drivers/USB/CORE/message. C]
--> Nintf = CP-> DESC. bnuminterfaces; // obtain the number of interfaces of the device.
Interface
For (I = 0; I <nintf; ++ I ){
Ret = device_add (& INTF-> Dev );
}
2. Add an Interface
Next, enter the process of adding devices to each interface, which is listed separately here.
Device_add (& INTF-> Dev );
--> Bus_probe_device (Dev); --> device_attach (Dev); [Drivers/base/DD. C]
--> Bus_for_each_drv (Dev-> bus, null, Dev, _ device_attach); // traverse the driver and find
Driver
-- >__ Device_attach (DRV, Dev); // when traversing to the option driver, find the driver in the option_ids [] struct.
Hold this device
--> Driver_probe_device (DRV, Dev );
--> Really_probe (Dev, DRV); [Drivers/base/DD. C]
--> DRV-> probe (Dev); // The actually called function is usb_probe_interface (Dev );
--> Driver-> probe (inif, ID); // The actually called function is usb_serial_probe (interface, ID );
[Drivers/USB/serial/usb-serial.c]
// Pl2303 convertor is detected and the attach function of pl2303 is executed.
/*****************
* The following sections do a lot of things.
* Create a usb_serial data structure, add an interface device, find the driver of the interface (such as pl2303), and set
Interface endpoint
******************/
--> Type = search_serial_device (Interface); // find the matched pl2303 driver. For details, refer to the next section.
Test the pl2303 driver]
Serial = create_serial (Dev, interface, type); // create a serial and assign the type driver to the newly created serial-
> Type, that is, the driver points to pl2303.
Port = serial-> port [I];
Dev_set_name (& Port-> Dev, "ttyusb % d", Port-> number );
Device_add (& Port-> Dev); // call to add the device ttyusb0
--> Bus_probe_device (Dev );
-->... As shown above...
--> Really_probe (Dev, DRV); [Drivers/base/DD. C]
--> Dev-> bus-> probe (Dev); // ***** what is actually called here is usb_serial_device_probe (Dev );
--> Tty_register_device (usb_serial_tty_driver, minor, Dev); // device_add (Dev) will be called again here );
Function
USB detection pl2303 driver
USB serial devices are also divided into many types. Such as pl2303 and vivopay
Usb_serial_probe (interface, ID); [Drivers/USB/serial/usb-serial.c]
--> Type = search_serial_device (Interface); // Based on the provided interface,
// Obtain static struct usb_serial_driver pl2303_device ={} [Drivers/USB/serial/pl2303.c]
--> List_for_each_entry (DRV, & usb_serial_driver_list, driver_list ){
Id = get_iface_id (DRV, iface );
If (ID)
Return DRV;
}
Pl2303 driver registration process
Static int _ init pl2303_init (void)
{
Retval = usb_serial_register (& pl2303_device );
}
[Drivers/USB/serial/usb-serial.c] in the register function, add the pl2303 driver to the USB serial driver list
Int usb_serial_register (struct usb_serial_driver * driver)
{
List_add (& driver-> driver_list, & usb_serial_driver_list );
}
3. Add an endpoint
// At this point, the entire call is returned gradually!
At last, it is called when the function returns: usb_set_configuration (udev, c); [Drivers/USB/CORE/message. C]
--> Create_intf_ep_devs (INTF); // adds an endpoint device.
--> For (I = 0; I <alt-> DESC. bnumendpoints; ++ I)
(Void) usb_create_ep_devs (& INTF-> Dev, & alt-> endpoint [I], udev );
--> Retval = device_register (& ep_dev-> Dev );
How can I read and write 3G NICs?
After the pl2303 driver is loaded, the generated devices ttyusb0, ttyusb1, and ttyusb2 can operate these devices.
. Commands such as open, close, read, write, and IOCTL
The following functions are available in pl2303.c: This function is called when the NIC device is enabled.
Static int pl2303_open (struct tty_struct * tty, struct usb_serial_port * port)
{
}
The 3g wcdma Nic can be used on the board, because the Development Board creates three USB devices for the 3G Nic
Ttyusb0, ttyusb1, and ttyusb2 are called three times when the function is enabled.
The general process is
Static int serial_open (struct tty_struct * tty, struct file * filp)
--> Tty_port_open (& Port-> port, tty, filp );
--> Port-> OPS-> activate (port, TTY); // The static int serial_activate (struct tty_port
* Tport, struct tty_struct * tty)
--> Port-> serial-> type-> open (TTY, Port); // call static int pl2303_open (struct
Tty_struct * tty, struct usb_serial_port * port)
In this way, you can enable devices to read, write, and control devices.
Device Identification
After the device is inserted, take the Huawei et127 3G Nic as an example. After the device is inserted, the following logs are generated:
SCSI 0: 0: 0: 0: CD-ROM Huawei mobile cmcc cd 1.25 PQ: 0 ANSI: 0
After the aircard 901 of Datang is inserted, there will also be the following log:
CSI 1: 0: 0: 0: CD-ROM aircard setupdisk 1.00 PQ: 0 ANSI: 2
In this case, the friendly Development Board identifies this device as a CD, that is, a storage device. In this case, you can use
Usb_modeswitch converts the mode of the USB device. Then drive the 3G Nic. I found an article online. Enable drive
I have asked Hu Feifei about how to activate most 3G NICs. Previously, this method was used to drive aircard 901 of Datang.
Http://linuxidc.com: 81/Linux/2011-03/33430. htm
I tried to follow these steps yesterday. But there are two problems
1: The arm card distribution board uses busybox, and some applications (such as dhcpcd) are compiled in the Android system. My compiled
Usb_modeswitch cannot run
2: After a USB 3G device is inserted, the arm Development Board identifies it as a sr0 or SR1 device. I don't know how to exit this device. Maybe
After the usb_modeswitch conversion is complete, the AT command can be used for communication. You still need to perform the test to know.
Function of usb_modeswitch
Usb_modeswitch is a mode conversion tool for controlling "flip flop" (multiple devices) USB devices. It has the following functions:
1. USB flash mode: Driver extraction and Installation
2. Switch Mode: Switch the storage device mode to the required (for example, 3g) device mode.
3. device mode: use the new features of the device.
For details, see the README document of usb_modeswitch.
Terms
USB endpoint)
The endpoint is established by the vendor inside the USB device and therefore permanently exists. Endpoint and host
Controller) is connected Based on pipelines.
One endpoint can only transmit data in one direction (in/out.
The endpoints are grouped by interfaces. Each interface corresponds to a device function.
USB Interface
Endpoints are grouped by interfaces. For example, Huawei's WCDMA is a group of three EP instances and belongs to one
Interface. Each interface corresponds to a separate device function. Such as Huawei et127 TD-CDMA 3G network card
An interface device is named ttyusb_utps_mms. The corresponding function should be SMS sending/receiving.
USB device No.
// WCDMA Huawei em770w can be viewed in Ubuntu 10.04
CrW-RW ---- 1 root dialout 188, 1 ttyusb_utps_diag
CrW-RW ---- 1 root dialout 188, 0 ttyusb_utps_modem
CrW-RW ---- 1 root dialout 188, 2 ttyusb_utps_pcui
// TD-SCDMA Huawei et127 under Ubuntu 10.04 View
CrW-RW ---- 1 root dialout 166, 1 ttyusb_utps_mms
CrW-RW ---- 1 root dialout 166, 0 ttyusb_utps_modem
CrW-RW ---- 1 root dialout 166, 2 ttyusb_utps_pcui
Idvendor = 12d1, idproduct = 1da1
Parameters of Datang TD-SCDMA Equipment
Idvendor = 1ab7, idproduct = 0301
Meaning of the master device number
ACM modem: master device No. 166
USB printer: master device No. 180 (sub-device No. 0 ~ 15)
USB serial port: master device No. 188