--- linux-2.6-hso-my/drivers/net/usb/hso.c.orig 2008-04-28 12:34:23.000000000 +0300 +++ linux-2.6-hso-my/drivers/net/usb/hso.c 2008-04-28 18:02:23.000000000 +0300 @@ -151,6 +151,7 @@ struct hso_shared_int { struct hso_net { struct hso_device *parent; struct net_device *net; + struct rfkill *rfkill; struct usb_endpoint_descriptor *in_endp; struct usb_endpoint_descriptor *out_endp; @@ -227,7 +228,6 @@ struct hso_device { struct usb_device *usb; struct usb_interface *interface; - struct rfkill *rfkill; struct device *dev; struct kref ref; @@ -2097,6 +2097,58 @@ static int add_net_device(struct hso_dev return 0; } +static int hso_radio_toggle(void *data, enum rfkill_state state) +{ + struct hso_device *hso_dev = data; + int enabled = (state == RFKILL_STATE_ON); + int rv; + + mutex_lock(&hso_dev->mutex); + if (hso_dev->usb_gone) + rv = 0; + else + rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0), + enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + mutex_unlock(&hso_dev->mutex); + return rv; +} + +/* Creates and sets up everything for rfkill */ +static void hso_create_rfkill(struct hso_device *hso_dev, + struct usb_interface *interface) +{ + struct hso_net *hso_net = dev2net(hso_dev); + struct device *dev = hso_dev->dev; + char *rfkn; + + hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev, + RFKILL_TYPE_WLAN); + if (!hso_net->rfkill) { + dev_err(dev, "%s - Out of memory", __func__); + return; + } + rfkn = kzalloc(20, GFP_KERNEL); + if (!rfkn) { + rfkill_free(hso_net->rfkill); + dev_err(dev, "%s - Out of memory", __func__); + return; + } + snprintf(rfkn, 20, "hso-%d", + interface->altsetting->desc.bInterfaceNumber); + hso_net->rfkill->name = rfkn; + hso_net->rfkill->state = RFKILL_STATE_ON; + hso_net->rfkill->data = hso_dev; + hso_net->rfkill->toggle_radio = hso_radio_toggle; + if (rfkill_register(hso_net->rfkill) < 0) { + kfree(rfkn); + hso_net->rfkill->name = NULL; + rfkill_free(hso_net->rfkill); + dev_err(dev, "%s - Failed to register rfkill", __func__); + return; + } +} + /* Creates our network device */ static struct hso_device *hso_create_net_device(struct usb_interface *interface) { @@ -2183,6 +2235,8 @@ static struct hso_device *hso_create_net hso_log_port(hso_dev); + hso_create_rfkill(hso_dev, interface); + return hso_dev; exit: hso_free_net_device(hso_dev); @@ -2467,30 +2521,12 @@ static int hso_get_config_data(struct us return result; } -static int hso_radio_toggle(void *data, enum rfkill_state state) -{ - struct hso_device *hso_dev = data; - int enabled = (state == RFKILL_STATE_ON); - int rv; - - mutex_lock(&hso_dev->mutex); - if (hso_dev->usb_gone) - rv = 0; - else - rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0), - enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - mutex_unlock(&hso_dev->mutex); - return rv; -} - /* called once for each interface upon device insertion */ static int hso_probe(struct usb_interface *interface, const struct usb_device_id *id) { int mux, i, if_num, port_spec; unsigned char port_mask; - char *rfkn; struct hso_device *hso_dev = NULL; struct hso_shared_int *shared_int; struct hso_device *tmp_dev = NULL; @@ -2563,27 +2599,6 @@ static int hso_probe(struct usb_interfac goto exit; } - hso_dev->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev, - RFKILL_TYPE_WLAN); - if (!hso_dev->rfkill) - goto exit; - rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) { - rfkill_free(hso_dev->rfkill); - goto exit; - } - snprintf(rfkn, 20, "hso-%d", if_num); - hso_dev->rfkill->name = rfkn; - hso_dev->rfkill->state = RFKILL_STATE_ON; - hso_dev->rfkill->data = hso_dev; - hso_dev->rfkill->toggle_radio = hso_radio_toggle; - if (rfkill_register(hso_dev->rfkill) < 0) { - kfree(rfkn); - hso_dev->rfkill->name = NULL; - rfkill_free(hso_dev->rfkill); - goto exit; - } - usb_driver_claim_interface(&hso_driver, interface, hso_dev); /* save our data pointer in this device */ @@ -2591,7 +2606,6 @@ static int hso_probe(struct usb_interfac /* done */ return 0; - exit: hso_free_interface(interface); return -ENODEV; @@ -2600,16 +2614,8 @@ exit: /* device removed, cleaning up */ static void hso_disconnect(struct usb_interface *interface) { - struct hso_device *hso_dev = usb_get_intfdata(interface); - hso_free_interface(interface); - if (hso_dev) { - cancel_work_sync(&hso_dev->async_put_intf); - cancel_work_sync(&hso_dev->async_get_intf); - rfkill_unregister(hso_dev->rfkill); - } - /* remove reference of our private data */ usb_set_intfdata(interface, NULL); @@ -2758,10 +2764,15 @@ static void hso_free_interface(struct us for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { if (network_table[i] && (network_table[i]->interface == interface)) { + struct rfkill *rfk = dev2net(network_table[i])->rfkill; /* hso_stop_net_device doesn't stop the net queue since * traffic needs to start it again when suspended */ netif_stop_queue(dev2net(network_table[i])->net); hso_stop_net_device(network_table[i]); + cancel_work_sync(&network_table[i]->async_put_intf); + cancel_work_sync(&network_table[i]->async_get_intf); + if(rfk) + rfkill_unregister(rfk); hso_free_net_device(network_table[i]); } }