diff --git a/driver/headset.c b/driver/headset.c index 44e7572..6def0d8 100644 --- a/driver/headset.c +++ b/driver/headset.c @@ -160,7 +160,7 @@ static const struct snd_pcm_ops gip_headset_pcm_ops = { static bool gip_headset_advance_pointer(struct gip_headset_stream *stream, int len, size_t buf_size) { - snd_pcm_uframes_t period = stream->substream->runtime->period_size; + size_t period = snd_pcm_lib_period_bytes(stream->substream); stream->pointer += len; if (stream->pointer >= buf_size) diff --git a/transport/dongle.c b/transport/dongle.c index fb5494b..ae5825f 100644 --- a/transport/dongle.c +++ b/transport/dongle.c @@ -181,8 +181,11 @@ static int xone_dongle_get_buffer(struct gip_adapter *adap, return -ENOSPC; skb = xone_mt76_alloc_message(XONE_DONGLE_LEN_CMD_PKT, GFP_ATOMIC); - if (!skb) + if (!skb) { + usb_anchor_urb(urb, &client->dongle->urbs_out_idle); + usb_free_urb(urb); return -ENOMEM; + } /* command header + WCID data + TXWI + QoS header + padding */ /* see xone_dongle_prep_packet and xone_mt76_prep_message */ @@ -514,17 +517,24 @@ xone_dongle_create_client(struct xone_dongle *dongle, u8 *addr) return client; } +static int xone_dongle_remove_client(struct xone_dongle *dongle, u8 wcid); + static int xone_dongle_add_client(struct xone_dongle *dongle, u8 *addr) { struct xone_dongle_client *client; - int i, err; + int err; unsigned long flags; - /* reject duplicate: controller already has a WCID slot */ - for (i = 0; i < XONE_DONGLE_MAX_CLIENTS; i++) - if (dongle->clients[i] && - ether_addr_equal(dongle->clients[i]->address, addr)) - return 0; + dev_dbg(dongle->mt.dev, "%s: new mac=%pM\n", __func__, addr); + + for (int i = 0; i < XONE_DONGLE_MAX_CLIENTS; i++) + if (dongle->clients[i] && ether_addr_equal(dongle->clients[i]->address, addr)) { + dev_dbg(dongle->mt.dev, + "%s: Client with this address already exists! Removing old client\n", + __func__); + xone_dongle_remove_client(dongle, dongle->clients[i]->wcid); + break; + } client = xone_dongle_create_client(dongle, addr); if (IS_ERR(client)) @@ -1134,6 +1144,7 @@ static void xone_dongle_fw_load(struct work_struct *work) err = xone_mt76_load_firmware(mt, fw); if (!err) break; + pr_err("%s: Error loading firmware into dongle\n", __func__); ssleep(1); } release_firmware(fw); @@ -1260,6 +1271,8 @@ static void xone_dongle_destroy(struct xone_dongle *dongle) dongle->fw_state = XONE_DONGLE_FW_STATE_STOP_LOADING; } + xone_dongle_toggle_pairing(dongle, false); + usb_kill_anchored_urbs(&dongle->urbs_in_busy); /* cancel fw load before destroying workqueues to avoid use-after-free */ cancel_work_sync(&dongle->load_fw_work); @@ -1318,18 +1331,7 @@ static int xone_dongle_probe(struct usb_interface *intf, spin_lock_init(&dongle->clients_lock); init_waitqueue_head(&dongle->disconnect_wait); - /* - * Do not call usb_reset_device() here. On cold boot the MT76 chip - * disconnects from USB as a normal part of its firmware startup - * sequence (inside xone_mt76_load_ivb). A preceding USB reset leaves - * the XHCI port in a state where it cannot cleanly handle that - * subsequent disconnect/reconnect cycle, causing the chip to - * permanently disappear from the USB bus until a physical replug. - * - * On warm reboot the firmware survives in RAM, so the chip does not - * disconnect at all and the faster xone_mt76_reset_firmware() path - * is taken instead — a reset is equally unnecessary there. - */ + usb_reset_device(dongle->mt.udev); err = xone_dongle_init(dongle); if (err) { xone_dongle_destroy(dongle); @@ -1457,6 +1459,16 @@ static int xone_dongle_pre_reset(struct usb_interface *intf) usb_kill_anchored_urbs(&dongle->urbs_in_busy); usb_kill_anchored_urbs(&dongle->urbs_out_busy); + for (int i = 0; i < XONE_DONGLE_MAX_CLIENTS; i++) { + struct xone_dongle_client *client = dongle->clients[i]; + if (!client) + continue; + gip_destroy_adapter(client->adapter); + kfree(client); + dongle->clients[i] = NULL; + } + atomic_set(&dongle->client_count, 0); + while ((urb = usb_get_from_anchor(&dongle->urbs_out_idle))) usb_free_urb(urb); @@ -1480,68 +1492,21 @@ static int xone_dongle_post_reset(struct usb_interface *intf) return 0; pr_debug("%s: Re-initializing dongle after reset", __func__); + + dongle->pairing = false; + dongle->pairing_scan_idx = 0; + dongle->last_wlan_rx = 0; + return xone_dongle_init(dongle); } static int xone_dongle_reset_resume(struct usb_interface *intf) { - struct xone_dongle *dongle = usb_get_intfdata(intf); - struct xone_dongle_client *client; - struct urb *urb; - int i; - pr_debug("%s", __func__); - /* - * The kernel already reset the USB device before calling - * reset_resume — a second usb_reset_device() is redundant and - * can leave the XHCI port in a bad state (the same class of bug - * as the former usb_reset_device() call in probe). - * - * Instead, clean up all stale state and reinitialize from scratch. - * This also ensures old GIP adapters are destroyed so the - * reconnecting controller gets a fresh input device. - */ - if (dongle->fw_state < XONE_DONGLE_FW_STATE_ERROR) - dongle->fw_state = XONE_DONGLE_FW_STATE_STOP_LOADING; - - usb_kill_anchored_urbs(&dongle->urbs_in_busy); - cancel_work_sync(&dongle->load_fw_work); - /* - * If load_fw_work raced past the STOP_LOADING check and created - * new URBs before cancel_work_sync returned, kill them now. - */ - usb_kill_anchored_urbs(&dongle->urbs_in_busy); - drain_workqueue(dongle->event_wq); - cancel_delayed_work_sync(&dongle->pairing_work); - cancel_delayed_work_sync(&dongle->pairing_scan_work); - - for (i = 0; i < XONE_DONGLE_MAX_CLIENTS; i++) { - client = dongle->clients[i]; - if (!client) - continue; - gip_destroy_adapter(client->adapter); - kfree(client); - dongle->clients[i] = NULL; - } - atomic_set(&dongle->client_count, 0); - - usb_kill_anchored_urbs(&dongle->urbs_out_busy); - - while ((urb = usb_get_from_anchor(&dongle->urbs_out_idle))) - usb_free_urb(urb); - - while ((urb = usb_get_from_anchor(&dongle->urbs_in_idle))) { - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); - usb_free_urb(urb); - } + /* This should be handeled by post_reset already */ - dongle->pairing = false; - dongle->pairing_scan_idx = 0; - dongle->last_wlan_rx = 0; - - return xone_dongle_init(dongle); + return 0; } static const struct usb_device_id xone_dongle_id_table[] = {