static int nci_open_device(struct nci_dev *ndev) { int rc = 0; mutex_lock(&ndev->req_lock); if (test_bit(NCI_UP, &ndev->flags)) { rc = -EALREADY; goto done; } if (ndev->ops->open(ndev)) { rc = -EIO; goto done; } atomic_set(&ndev->cmd_cnt, 1); set_bit(NCI_INIT, &ndev->flags); rc = __nci_request(ndev, nci_reset_req, 0, msecs_to_jiffies(NCI_RESET_TIMEOUT)); if (ndev->ops->setup) ndev->ops->setup(ndev); if (!rc) { rc = __nci_request(ndev, nci_init_req, 0, msecs_to_jiffies(NCI_INIT_TIMEOUT)); } if (!rc) { rc = __nci_request(ndev, nci_init_complete_req, 0, msecs_to_jiffies(NCI_INIT_TIMEOUT)); } clear_bit(NCI_INIT, &ndev->flags); if (!rc) { set_bit(NCI_UP, &ndev->flags); nci_clear_target_list(ndev); atomic_set(&ndev->state, NCI_IDLE); } else { /* Init failed, cleanup */ skb_queue_purge(&ndev->cmd_q); skb_queue_purge(&ndev->rx_q); skb_queue_purge(&ndev->tx_q); ndev->ops->close(ndev); ndev->flags = 0; } done: mutex_unlock(&ndev->req_lock); return rc; }
int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val) { struct nci_set_config_param param; if (!val || !len) return 0; param.id = id; param.len = len; param.val = val; return __nci_request(ndev, nci_set_config_req, (unsigned long)¶m, msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); }
static inline int nci_request(struct nci_dev *ndev, void (*req)(struct nci_dev *ndev, unsigned long opt), unsigned long opt, __u32 timeout) { int rc; if (!test_bit(NCI_UP, &ndev->flags)) return -ENETDOWN; /* Serialize all requests */ mutex_lock(&ndev->req_lock); rc = __nci_request(ndev, req, opt, timeout); mutex_unlock(&ndev->req_lock); return rc; }
static int nci_close_device(struct nci_dev *ndev) { nci_req_cancel(ndev, ENODEV); mutex_lock(&ndev->req_lock); if (!test_and_clear_bit(NCI_UP, &ndev->flags)) { del_timer_sync(&ndev->cmd_timer); del_timer_sync(&ndev->data_timer); mutex_unlock(&ndev->req_lock); return 0; } /* Drop RX and TX queues */ skb_queue_purge(&ndev->rx_q); skb_queue_purge(&ndev->tx_q); /* Flush RX and TX wq */ flush_workqueue(ndev->rx_wq); flush_workqueue(ndev->tx_wq); /* Reset device */ skb_queue_purge(&ndev->cmd_q); atomic_set(&ndev->cmd_cnt, 1); set_bit(NCI_INIT, &ndev->flags); __nci_request(ndev, nci_reset_req, 0, msecs_to_jiffies(NCI_RESET_TIMEOUT)); clear_bit(NCI_INIT, &ndev->flags); del_timer_sync(&ndev->cmd_timer); /* Flush cmd wq */ flush_workqueue(ndev->cmd_wq); /* After this point our queues are empty * and no works are scheduled. */ ndev->ops->close(ndev); /* Clear flags */ ndev->flags = 0; mutex_unlock(&ndev->req_lock); return 0; }
static int nci_close_device(struct nci_dev *ndev) { nci_req_cancel(ndev, ENODEV); mutex_lock(&ndev->req_lock); if (!test_and_clear_bit(NCI_UP, &ndev->flags)) { del_timer_sync(&ndev->cmd_timer); del_timer_sync(&ndev->data_timer); mutex_unlock(&ndev->req_lock); return 0; } skb_queue_purge(&ndev->rx_q); skb_queue_purge(&ndev->tx_q); flush_workqueue(ndev->rx_wq); flush_workqueue(ndev->tx_wq); skb_queue_purge(&ndev->cmd_q); atomic_set(&ndev->cmd_cnt, 1); set_bit(NCI_INIT, &ndev->flags); __nci_request(ndev, nci_reset_req, 0, msecs_to_jiffies(NCI_RESET_TIMEOUT)); clear_bit(NCI_INIT, &ndev->flags); flush_workqueue(ndev->cmd_wq); ndev->ops->close(ndev); ndev->flags = 0; mutex_unlock(&ndev->req_lock); return 0; }