这个项目已经做了小半年了,客户是一个做智能电话机的。所谓的智能电话就是一台可以插网线、电话线,外观却是座机的手机。
客户的需求特别奇葩,USB网卡和一个内部的交换机直接通过PCB走线相连接。这个设计导致了系统在插入网线并且网卡link up上报后,网卡就一直处于连接状态,无法判断交换机的wan口网线是否拔出。后面经过大家的会议商讨,决定将交换机wan口led接口引出并接到我们的模块上,利用GPIO去判断LED闪烁状态来设置网卡状态。
于是乎,这个问题就首先落到了BSP这边,而后又落到了我这边,因为我这边是处理外设驱动的看😂
简单讲一下思路:DM9601作为USB网卡,driver_info(usbnet.h)中有一个.status的方法,用于轮询网卡状态。
/* for status polling */
void (*status)(struct usbnet *, struct urb *);
// 驱动的具体实现
static void dm9601_status(struct usbnet *dev, struct urb *urb)
{
int link;
u8 *buf;
/* format:
b0: net status
b1: tx status 1
b2: tx status 2
b3: rx status
b4: rx overflow
b5: rx count
b6: tx count
b7: gpr
*/
if (urb->actual_length < 8)
return;
buf = urb->transfer_buffer;
link = !!(buf[0] & 0x40);
if (netif_carrier_ok(dev->net) != link) {
usbnet_link_change(dev, link, 1);
netdev_dbg(dev->net, "Link Status is: %d\n", link);
}
}
通过观察log发现每次插拔网线都会在轮询函数中触发log,再深入分析后发现确实是由该函数来实现网卡link up/down的设置。
于是增加修改如下:
extern struct gpio_desc * eth_switch_gpiod_get(void);
static void dm9601_status(struct usbnet *dev, struct urb *urb)
{
int link;
u8 *buf;
int cnt;
int val;
struct gpio_desc * gpiod = NULL;
/* format:
b0: net status
b1: tx status 1
b2: tx status 2
b3: rx status
b4: rx overflow
b5: rx count
b6: tx count
b7: gpr
*/
if (urb->actual_length < 8)
return;
buf = urb->transfer_buffer;
link = !!(buf[0] & 0x40);
netdev_info(dev->net, "%s link:%d\n", __func__, link);
cnt = 0;
gpiod = eth_switch_gpiod_get();
if (!IS_ERR_OR_NULL(gpiod)) {
while (link && (val = gpiod_get_value(gpiod))) {
netdev_info(dev->net, "gpio%d:%d\n", desc_to_gpio(gpiod), val);
if (cnt++ > 5) {
netdev_info(dev->net, "%s link down\n", __func__);
usbnet_link_change(dev, 0, 1);
return;
}
mdelay(100);
}
}
if (netif_carrier_ok(dev->net) != link) {
usbnet_link_change(dev, link, 1);
netdev_info(dev->net, "Link Status is: %d\n", link);
}
}
解决思路:首先判断当前网卡状态,其次通过GPIO判断LED灯状态,为了防止误判增加重试机制。
如果本文对你有帮助,请不要吝啬你的赞!转载请务必注明来源!
PYPYN.COM 版权所有