irqreturn_t mt_bt_eirq_handler(int i, void *arg) { struct hci_dev *hdev = NULL; BT_HWCTL_ALERT("mt_bt_eirq_handler\n"); mt_bt_disable_irq(); #ifdef CONFIG_BT_HCIUART /* BlueZ stack, hci_uart driver */ hdev = hci_dev_get(0); if(hdev == NULL){ /* Avoid the early interrupt before hci0 registered */ BT_HWCTL_ALERT("hdev is NULL\n"); }else{ BT_HWCTL_ALERT("EINT arrives! Notify host awake\n"); BT_HWCTL_ALERT("Send host awake command\n"); hci_send_cmd(hdev, 0xFCC1, 0, NULL); /* Enable irq after receiving host awake command's event */ } #else /* Maybe handle the interrupt in user space? */ eint_gen = 1; wake_up_interruptible(&eint_wait); /* Send host awake command in user space, enable irq then */ #endif return IRQ_HANDLED; }
static int __init bt_hwctl_init(void) { int ret = -1, err = -1; BT_HWCTL_DEBUG("bt_hwctl_init\n"); platform_driver_register(&mt6622_driver); if (!(bh = kzalloc(sizeof(struct bt_hwctl), GFP_KERNEL))) { BT_HWCTL_ALERT("bt_hwctl_init allocate dev struct failed\n"); err = -ENOMEM; goto ERR_EXIT; } ret = alloc_chrdev_region(&bh->dev_t, 0, 1, BTHWCTL_NAME); if (ret) { BT_HWCTL_ALERT("alloc chrdev region failed\n"); goto ERR_EXIT; } BT_HWCTL_DEBUG("alloc %s:%d:%d\n", BTHWCTL_NAME, MAJOR(bh->dev_t), MINOR(bh->dev_t)); cdev_init(&bh->cdev, &bt_hwctl_fops); bh->cdev.owner = THIS_MODULE; bh->cdev.ops = &bt_hwctl_fops; err = cdev_add(&bh->cdev, bh->dev_t, 1); if (err) { BT_HWCTL_ALERT("add chrdev failed\n"); goto ERR_EXIT; } bh->cls = class_create(THIS_MODULE, BTHWCTL_NAME); if (IS_ERR(bh->cls)) { err = PTR_ERR(bh->cls); BT_HWCTL_ALERT("class_create failed, errno:%d\n", err); goto ERR_EXIT; } bh->dev = device_create(bh->cls, NULL, bh->dev_t, NULL, BTHWCTL_NAME); mutex_init(&bh->sem); init_waitqueue_head(&eint_wait); /*INIT_WORK(&mtk_wcn_bt_event_work, mtk_wcn_bt_work_fun); mtk_wcn_bt_workqueue = create_singlethread_workqueue("mtk_wcn_bt"); if (!mtk_wcn_bt_workqueue) { printk("create_singlethread_workqueue failed.\n"); err = -ESRCH; goto ERR_EXIT; }*/ /* request gpio used by BT */ //mt_bt_gpio_init(); BT_HWCTL_DEBUG("bt_hwctl_init ok\n"); return 0; ERR_EXIT: if (err == 0) cdev_del(&bh->cdev); if (ret == 0) unregister_chrdev_region(bh->dev_t, 1); if (bh){ kfree(bh); bh = NULL; } return -1; }
/***************************************************************************** * bt_hwctl_ioctl *****************************************************************************/ static long bt_hwctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; BT_HWCTL_DEBUG("bt_hwctl_ioctl\n"); if(!bh) { BT_HWCTL_ALERT("bt_hwctl struct not initialized\n"); return -EFAULT; } switch(cmd) { case BTHWCTL_IOCTL_SET_POWER: { unsigned long pwr = 0; if (copy_from_user(&pwr, (void*)arg, sizeof(unsigned long))) return -EFAULT; BT_HWCTL_DEBUG("BTHWCTL_IOCTL_SET_POWER: %d\n", (int)pwr); mutex_lock(&bh->sem); if (pwr){ ret = mt_bt_power_on(); } else{ mt_bt_power_off(); } mutex_unlock(&bh->sem); break; } case BTHWCTL_IOCTL_SET_EINT: { unsigned long eint = 0; if (copy_from_user(&eint, (void*)arg, sizeof(unsigned long))) return -EFAULT; BT_HWCTL_DEBUG("BTHWCTL_IOCTL_SET_EINT: %d\n", (int)eint); mutex_lock(&bh->sem); if (eint){ /* Enable irq from user space */ BT_HWCTL_DEBUG("Set BT EINT enable\n"); mt_bt_enable_irq(); } else{ /* Disable irq from user space, maybe time to close driver */ BT_HWCTL_DEBUG("Set BT EINT disable\n"); mt_bt_disable_irq(); eint_mask = 1; wake_up_interruptible(&eint_wait); } mutex_unlock(&bh->sem); break; } default: BT_HWCTL_ALERT("BTHWCTL_IOCTL not support\n"); return -EPERM; } return ret; }