⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hci_core.c

📁 linux下蓝牙
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	if (!ret) {		set_bit(HCI_UP, &hdev->flags);		hci_notify(hdev, HCI_DEV_UP);	} else {			/* Init failed, cleanup */		tasklet_kill(&hdev->rx_task);		tasklet_kill(&hdev->tx_task);		tasklet_kill(&hdev->cmd_task);		skb_queue_purge(&hdev->cmd_q);		skb_queue_purge(&hdev->rx_q);		if (hdev->flush)			hdev->flush(hdev);		if (hdev->sent_cmd) {			kfree_skb(hdev->sent_cmd);			hdev->sent_cmd = NULL;		}		hdev->close(hdev);		hdev->flags = 0;	}done:	hci_req_unlock(hdev);	hci_dev_put(hdev);	return ret;}static int hci_dev_do_close(struct hci_dev *hdev){	BT_DBG("%s %p", hdev->name, hdev);	hci_req_cancel(hdev, ENODEV);	hci_req_lock(hdev);	if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {		hci_req_unlock(hdev);		return 0;	}	/* Kill RX and TX tasks */	tasklet_kill(&hdev->rx_task);	tasklet_kill(&hdev->tx_task);	hci_dev_lock_bh(hdev);	inquiry_cache_flush(hdev);	hci_conn_hash_flush(hdev);	hci_dev_unlock_bh(hdev);		hci_notify(hdev, HCI_DEV_DOWN);	if (hdev->flush)		hdev->flush(hdev);	/* Reset device */	skb_queue_purge(&hdev->cmd_q);	atomic_set(&hdev->cmd_cnt, 1);	set_bit(HCI_INIT, &hdev->flags);	__hci_request(hdev, hci_reset_req, 0, HZ/4);	clear_bit(HCI_INIT, &hdev->flags);	/* Kill cmd task */	tasklet_kill(&hdev->cmd_task);	/* Drop queues */	skb_queue_purge(&hdev->rx_q);	skb_queue_purge(&hdev->cmd_q);	skb_queue_purge(&hdev->raw_q);	/* Drop last sent command */	if (hdev->sent_cmd) {		kfree_skb(hdev->sent_cmd);		hdev->sent_cmd = NULL;	}	/* After this point our queues are empty	 * and no tasks are scheduled. */	hdev->close(hdev);	/* Clear flags */	hdev->flags = 0;	hci_req_unlock(hdev);	return 0;}int hci_dev_close(__u16 dev){	struct hci_dev *hdev;	int err;		if (!(hdev = hci_dev_get(dev)))		return -ENODEV;	err = hci_dev_do_close(hdev);	hci_dev_put(hdev);	return err;}int hci_dev_reset(__u16 dev){	struct hci_dev *hdev;	int ret = 0;	if (!(hdev = hci_dev_get(dev)))		return -ENODEV;	hci_req_lock(hdev);	tasklet_disable(&hdev->tx_task);	if (!test_bit(HCI_UP, &hdev->flags))		goto done;	/* Drop queues */	skb_queue_purge(&hdev->rx_q);	skb_queue_purge(&hdev->cmd_q);	hci_dev_lock_bh(hdev);	inquiry_cache_flush(hdev);	hci_conn_hash_flush(hdev);	hci_dev_unlock_bh(hdev);	if (hdev->flush)		hdev->flush(hdev);	atomic_set(&hdev->cmd_cnt, 1); 	hdev->acl_cnt = 0; hdev->sco_cnt = 0;	ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);done:	tasklet_enable(&hdev->tx_task);	hci_req_unlock(hdev);	hci_dev_put(hdev);	return ret;}int hci_dev_reset_stat(__u16 dev){	struct hci_dev *hdev;	int ret = 0;	if (!(hdev = hci_dev_get(dev)))		return -ENODEV;	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));	hci_dev_put(hdev);	return ret;}int hci_dev_cmd(unsigned int cmd, unsigned long arg){	struct hci_dev *hdev;	struct hci_dev_req dr;	int err = 0;	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))		return -EFAULT;	if (!(hdev = hci_dev_get(dr.dev_id)))		return -ENODEV;	switch (cmd) {	case HCISETAUTH:		err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);		break;	case HCISETENCRYPT:		if (!lmp_encrypt_capable(hdev)) {			err = -EOPNOTSUPP;			break;		}		if (!test_bit(HCI_AUTH, &hdev->flags)) {			/* Auth must be enabled first */			err = hci_request(hdev, hci_auth_req,					dr.dev_opt, HCI_INIT_TIMEOUT);			if (err)				break;		}					err = hci_request(hdev, hci_encrypt_req,					dr.dev_opt, HCI_INIT_TIMEOUT);		break;		case HCISETSCAN:		err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);		break;		case HCISETPTYPE:		hdev->pkt_type = (__u16) dr.dev_opt;		break;			case HCISETLINKPOL:		hdev->link_policy = (__u16) dr.dev_opt;		break;	case HCISETLINKMODE:		hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);		break;	case HCISETACLMTU:		hdev->acl_mtu  = *((__u16 *)&dr.dev_opt + 1);		hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);		break;	case HCISETSCOMTU:		hdev->sco_mtu  = *((__u16 *)&dr.dev_opt + 1);		hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);		break;	default:		err = -EINVAL;		break;	}		hci_dev_put(hdev);	return err;}int hci_get_dev_list(unsigned long arg){	struct hci_dev_list_req *dl;	struct hci_dev_req *dr;	struct list_head *p;	int n = 0, size;	__u16 dev_num;	if (get_user(dev_num, (__u16 *) arg))		return -EFAULT;	if (!dev_num)		return -EINVAL;		size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);	if (verify_area(VERIFY_WRITE, (void *) arg, size))		return -EFAULT;	if (!(dl = kmalloc(size, GFP_KERNEL)))		return -ENOMEM;	dr = dl->dev_req;	read_lock_bh(&hdev_list_lock);	list_for_each(p, &hdev_list) {		struct hci_dev *hdev;		hdev = list_entry(p, struct hci_dev, list);		(dr + n)->dev_id  = hdev->id;		(dr + n)->dev_opt = hdev->flags;		if (++n >= dev_num)			break;	}	read_unlock_bh(&hdev_list_lock);	dl->dev_num = n;	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);	copy_to_user((void *) arg, dl, size);	kfree(dl);	return 0;}int hci_get_dev_info(unsigned long arg){	struct hci_dev *hdev;	struct hci_dev_info di;	int err = 0;	if (copy_from_user(&di, (void *) arg, sizeof(di)))		return -EFAULT;	if (!(hdev = hci_dev_get(di.dev_id)))		return -ENODEV;	strcpy(di.name, hdev->name);	di.bdaddr   = hdev->bdaddr;	di.type     = hdev->type;	di.flags    = hdev->flags;	di.pkt_type = hdev->pkt_type;	di.acl_mtu  = hdev->acl_mtu;	di.acl_pkts = hdev->acl_pkts;	di.sco_mtu  = hdev->sco_mtu;	di.sco_pkts = hdev->sco_pkts;	di.link_policy = hdev->link_policy;	di.link_mode   = hdev->link_mode;	memcpy(&di.stat, &hdev->stat, sizeof(di.stat));	memcpy(&di.features, &hdev->features, sizeof(di.features));	if (copy_to_user((void *) arg, &di, sizeof(di)))		err = -EFAULT;	hci_dev_put(hdev);	return err;}/* ---- Interface to HCI drivers ---- *//* Register HCI device */int hci_register_dev(struct hci_dev *hdev){	struct list_head *head = &hdev_list, *p;	int id = 0;	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);	if (!hdev->open || !hdev->close || !hdev->destruct)		return -EINVAL;	write_lock_bh(&hdev_list_lock);	/* Find first available device id */	list_for_each(p, &hdev_list) {	       	if (list_entry(p, struct hci_dev, list)->id != id)			break;		head = p; id++;	}		sprintf(hdev->name, "hci%d", id);	hdev->id = id;	list_add(&hdev->list, head);	atomic_set(&hdev->refcnt, 1);	spin_lock_init(&hdev->lock);				hdev->flags = 0;	hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);	hdev->link_mode = (HCI_LM_ACCEPT);	tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);	tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);	tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);	skb_queue_head_init(&hdev->rx_q);	skb_queue_head_init(&hdev->cmd_q);	skb_queue_head_init(&hdev->raw_q);	init_waitqueue_head(&hdev->req_wait_q);	init_MUTEX(&hdev->req_lock);	inquiry_cache_init(hdev);	conn_hash_init(hdev);	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));	atomic_set(&hdev->promisc, 0);	MOD_INC_USE_COUNT;	write_unlock_bh(&hdev_list_lock);	hci_notify(hdev, HCI_DEV_REG);	hci_run_hotplug(hdev->name, "register");	return id;}/* Unregister HCI device */int hci_unregister_dev(struct hci_dev *hdev){	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);	write_lock_bh(&hdev_list_lock);	list_del(&hdev->list);	write_unlock_bh(&hdev_list_lock);	hci_dev_do_close(hdev);	hci_notify(hdev, HCI_DEV_UNREG);	hci_run_hotplug(hdev->name, "unregister");	hci_dev_put(hdev);	MOD_DEC_USE_COUNT;	return 0;}/* Suspend HCI device */int hci_suspend_dev(struct hci_dev *hdev){	hci_notify(hdev, HCI_DEV_SUSPEND);	hci_run_hotplug(hdev->name, "suspend");	return 0;}/* Resume HCI device */int hci_resume_dev(struct hci_dev *hdev){	hci_notify(hdev, HCI_DEV_RESUME);	hci_run_hotplug(hdev->name, "resume");	return 0;}       /* Receive frame from HCI drivers */int hci_recv_frame(struct sk_buff *skb){	struct hci_dev *hdev = (struct hci_dev *) skb->dev;	if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && 				!test_bit(HCI_INIT, &hdev->flags)) ) {		kfree_skb(skb);		return -1;	}	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);	/* Incomming skb */	bluez_cb(skb)->incomming = 1;	/* Time stamp */	do_gettimeofday(&skb->stamp);	/* Queue frame for rx task */	skb_queue_tail(&hdev->rx_q, skb);	hci_sched_rx(hdev);	return 0;}/* ---- Interface to upper protocols ---- *//* Register/Unregister protocols. * hci_task_lock is used to ensure that no tasks are running. */int hci_register_proto(struct hci_proto *hp){	int err = 0;	BT_DBG("%p name %s id %d", hp, hp->name, hp->id);	if (hp->id >= HCI_MAX_PROTO)		return -EINVAL;	write_lock_bh(&hci_task_lock);	if (!hci_proto[hp->id])		hci_proto[hp->id] = hp;	else		err = -EEXIST;	write_unlock_bh(&hci_task_lock);	return err;}int hci_unregister_proto(struct hci_proto *hp){	int err = 0;	BT_DBG("%p name %s id %d", hp, hp->name, hp->id);	if (hp->id >= HCI_MAX_PROTO)		return -EINVAL;	write_lock_bh(&hci_task_lock);	if (hci_proto[hp->id])		hci_proto[hp->id] = NULL;	else		err = -ENOENT;	write_unlock_bh(&hci_task_lock);	return err;}static int hci_send_frame(struct sk_buff *skb){	struct hci_dev *hdev = (struct hci_dev *) skb->dev;	if (!hdev) {		kfree_skb(skb);		return -ENODEV;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -