int gobi_debug;
static struct class *devclass;
-static void free_dev(struct kref *ref)
+static void free_dev(struct kobject *ref)
{
- struct qcusbnet *dev = container_of(ref, struct qcusbnet, refcount);
+ struct qcusbnet *dev = container_of(ref, struct qcusbnet, kobj);
+ mutex_lock(&qcusbnet_lock);
list_del(&dev->node);
+ mutex_unlock(&qcusbnet_lock);
kfree(dev);
}
usb_free_urb(urb);
}
+static struct kobj_type ktype_qcusbnet = {
+ .release = free_dev,
+};
+
void qcusbnet_put(struct qcusbnet *dev)
{
- mutex_lock(&qcusbnet_lock);
- kref_put(&dev->refcount, free_dev);
- mutex_unlock(&qcusbnet_lock);
+ kobject_put(&dev->kobj);
}
struct qcusbnet *qcusbnet_get(struct qcusbnet *key)
mutex_lock(&qcusbnet_lock);
list_for_each_entry(entry, &qcusbnet_list, node) {
if (entry == key) {
- kref_get(&entry->refcount);
+ kobject_get(&entry->kobj);
mutex_unlock(&qcusbnet_lock);
return entry;
}
MKVIDPID(0x1199, 0x9008), /* Sierra Wireless Gobi 2000 */
MKVIDPID(0x1199, 0x9009), /* Sierra Wireless Gobi 2000 */
MKVIDPID(0x1199, 0x900a), /* Sierra Wireless Gobi 2000 */
+ MKVIDPID(0x1199, 0x9012), /* Sierra Wireless Gobi 3000 */
+ MKVIDPID(0x1199, 0x9013), /* Sierra Wireless Gobi 3000 */
MKVIDPID(0x05c6, 0x9225), /* Sony Gobi 2000 */
MKVIDPID(0x05c6, 0x9235), /* Top Global Gobi 2000 */
MKVIDPID(0x05c6, 0x9275), /* iRex Technologies Gobi 2000 */
MKVIDPID(0x05c6, 0x920d), /* Qualcomm Gobi 3000 */
- MKVIDPID(0x1410, 0xa021), /* Novatel Gobi 3000 */
+ MKVIDPID(0x0af0, 0x8120), /* Option Gobi 3000 */
+ MKVIDPID(0x1410, 0xa021), /* Novatel Gobi 3000 (E396) */
+ MKVIDPID(0x1410, 0xa023), /* Novatel Gobi 3000 (E396U) */
MKVIDPID(0x413c, 0x8194), /* Dell Gobi 3000 */
MKVIDPID(0x12D1, 0x14F1), /* Sony Gobi 3000 */
{ }
struct qcusbnet *dev;
struct net_device_ops *netdevops;
int i;
+ int addr_len;
u8 *addr;
+ const char *id;
status = usbnet_probe(iface, vidpids);
if (status < 0) {
memset(&(dev->usbnet->net->stats), 0, sizeof(struct net_device_stats));
- memset(&(dev->meid), '0', 14);
+ memset(dev->meid, '0', sizeof(dev->meid));
+ memset(dev->imei, '0', sizeof(dev->imei));
dev->valid = false;
memset(&dev->qmi, 0, sizeof(dev->qmi));
dev->qmi.devclass = devclass;
- kref_init(&dev->refcount);
+ memset(&dev->kobj, 0, sizeof(dev->kobj));
+ kobject_init(&dev->kobj, &ktype_qcusbnet);
INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->qmi.clients);
dev->workqueue = alloc_ordered_workqueue("gobi", 0);
list_add(&dev->node, &qcusbnet_list);
mutex_unlock(&qcusbnet_lock);
- /* After calling qc_register, MEID is valid */
- addr = &usbnet->net->dev_addr[0];
- for (i = 0; i < 6; i++)
- addr[i] = (nibble(dev->meid[i*2+2]) << 4)+
- nibble(dev->meid[i*2+3]);
+ /* After calling qc_register, either MEID or IMEI is valid */
+ id = memchr_inv(dev->meid, '0', sizeof(dev->meid)) ?
+ dev->meid : dev->imei;
+ addr = usbnet->net->dev_addr;
+ addr_len = usbnet->net->addr_len;
+ if (addr_len > ETH_ALEN)
+ addr_len = ETH_ALEN;
+
+ for (i = 0; i < addr_len; i++)
+ addr[i] = (nibble(id[i*2+2]) << 4) + nibble(id[i*2+3]);
addr[0] &= 0xfe; /* clear multicast bit */
addr[0] |= 0x02; /* set local assignment bit (IEEE802) */
intf->needs_remote_wakeup = 0;
netif_carrier_off(usbnet->net);
- usbnet_disconnect(intf);
qc_deregister(dev);
list_del(&urb->urb_list);
free_urb_with_skb(urb);
}
+ usbnet_disconnect(intf);
qcusbnet_put(dev);
}