Exemplo n.º 1
0
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
	struct sock *sk = sock->sk;
	struct sockaddr_l2 la;
	int len, err = 0;

	BT_DBG("sk %p", sk);

	if (!addr || addr->sa_family != AF_BLUETOOTH)
		return -EINVAL;

	memset(&la, 0, sizeof(la));
	len = min_t(unsigned int, sizeof(la), alen);
	memcpy(&la, addr, len);

	if (la.l2_cid && la.l2_psm)
		return -EINVAL;

	lock_sock(sk);

	if (sk->sk_state != BT_OPEN) {
		err = -EBADFD;
		goto done;
	}

	if (la.l2_psm) {
		__u16 psm = __le16_to_cpu(la.l2_psm);

		/* PSM must be odd and lsb of upper byte must be 0 */
		if ((psm & 0x0101) != 0x0001) {
			err = -EINVAL;
			goto done;
		}

		/* Restrict usage of well-known PSMs */
		if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
			err = -EACCES;
			goto done;
		}
	}

	write_lock_bh(&l2cap_sk_list.lock);

	if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
		err = -EADDRINUSE;
	} else {
		/* Save source address */
		bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
		l2cap_pi(sk)->psm   = la.l2_psm;
		l2cap_pi(sk)->sport = la.l2_psm;
		sk->sk_state = BT_BOUND;

		if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
					__le16_to_cpu(la.l2_psm) == 0x0003)
			l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
	}

	if (la.l2_cid)
		l2cap_pi(sk)->scid = la.l2_cid;

	write_unlock_bh(&l2cap_sk_list.lock);

done:
	release_sock(sk);
	return err;
}
Exemplo n.º 2
0
/* Connect Complete */
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
	struct hci_conn *conn = NULL;

	BT_DBG("%s", hdev->name);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
	if (!conn) {
		hci_dev_unlock(hdev);
		return;
	}

	if (!ev->status) {
		conn->handle = __le16_to_cpu(ev->handle);
		conn->state  = BT_CONNECTED;

		if (test_bit(HCI_AUTH, &hdev->flags))
			conn->link_mode |= HCI_LM_AUTH;

		if (test_bit(HCI_ENCRYPT, &hdev->flags))
			conn->link_mode |= HCI_LM_ENCRYPT;

		/* Set link policy */
		if (conn->type == ACL_LINK && hdev->link_policy) {
			struct hci_cp_write_link_policy cp;
			cp.handle = ev->handle;
			cp.policy = __cpu_to_le16(hdev->link_policy);
			hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
		}

		/* Set packet type for incoming connection */
		if (!conn->out) {
			struct hci_cp_change_conn_ptype cp;
			cp.handle = ev->handle;
			cp.pkt_type = (conn->type == ACL_LINK) ? 
				__cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
				__cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);

			hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
		}
	} else
		conn->state = BT_CLOSED;

	if (conn->type == ACL_LINK) {
		struct hci_conn *sco = conn->link;
		if (sco) {
			if (!ev->status)
				hci_add_sco(sco, conn->handle);
			else {
				hci_proto_connect_cfm(sco, ev->status);
				hci_conn_del(sco);
			}
		}
	}

	hci_proto_connect_cfm(conn, ev->status);
	if (ev->status)
		hci_conn_del(conn);

	hci_dev_unlock(hdev);
}
/* Recv data */
static int ibs_recv(struct hci_uart *hu, void *data, int count)
{
	struct ibs_struct *ibs = hu->priv;
	register char *ptr;
	struct hci_event_hdr *eh;
	struct hci_acl_hdr   *ah;
	struct hci_sco_hdr   *sh;
	register int len, type, dlen;

	BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
			hu, count, ibs->rx_state, ibs->rx_count);

	ptr = data;
	while (count) {
		if (ibs->rx_count) {
			len = min_t(unsigned int, ibs->rx_count, count);
			memcpy(skb_put(ibs->rx_skb, len), ptr, len);
			ibs->rx_count -= len; count -= len; ptr += len;

			if (ibs->rx_count)
				continue;

			switch (ibs->rx_state) {
			case HCI_IBS_W4_DATA:
				BT_DBG("Complete data");
				hci_recv_frame(ibs->rx_skb);

				ibs->rx_state = HCI_IBS_W4_PACKET_TYPE;
				ibs->rx_skb = NULL;
				continue;

			case HCI_IBS_W4_EVENT_HDR:
				eh = (struct hci_event_hdr *) ibs->rx_skb->data;

				BT_DBG("Event header: evt 0x%2.2x plen %d",
					eh->evt, eh->plen);

				ibs_check_data_len(ibs, eh->plen);
				continue;

			case HCI_IBS_W4_ACL_HDR:
				ah = (struct hci_acl_hdr *) ibs->rx_skb->data;
				dlen = __le16_to_cpu(ah->dlen);

				BT_DBG("ACL header: dlen %d", dlen);

				ibs_check_data_len(ibs, dlen);
				continue;

			case HCI_IBS_W4_SCO_HDR:
				sh = (struct hci_sco_hdr *) ibs->rx_skb->data;

				BT_DBG("SCO header: dlen %d", sh->dlen);

				ibs_check_data_len(ibs, sh->dlen);
				continue;
			}
		}

		/* HCI_IBS_W4_PACKET_TYPE */
		switch (*ptr) {
		case HCI_EVENT_PKT:
			BT_DBG("Event packet");
			ibs->rx_state = HCI_IBS_W4_EVENT_HDR;
			ibs->rx_count = HCI_EVENT_HDR_SIZE;
			type = HCI_EVENT_PKT;
			break;

		case HCI_ACLDATA_PKT:
			BT_DBG("ACL packet");
			ibs->rx_state = HCI_IBS_W4_ACL_HDR;
			ibs->rx_count = HCI_ACL_HDR_SIZE;
			type = HCI_ACLDATA_PKT;
			break;

		case HCI_SCODATA_PKT:
			BT_DBG("SCO packet");
			ibs->rx_state = HCI_IBS_W4_SCO_HDR;
			ibs->rx_count = HCI_SCO_HDR_SIZE;
			type = HCI_SCODATA_PKT;
			break;

		/* HCI_IBS signals */
		case HCI_IBS_SLEEP_IND:
			BT_DBG("HCI_IBS_SLEEP_IND packet");
			ibs_device_want_to_sleep(hu);
			ptr++; count--;
			continue;

		case HCI_IBS_WAKE_IND:
			BT_DBG("HCI_IBS_WAKE_IND packet");
			ibs_device_want_to_wakeup(hu);
			ptr++; count--;
			continue;

		case HCI_IBS_WAKE_ACK:
			BT_DBG("HCI_IBS_WAKE_ACK packet");
			ibs_device_woke_up(hu);
			ptr++; count--;
			continue;

		default:
			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
			hu->hdev->stat.err_rx++;
			ptr++; count--;
			continue;
		};

		ptr++; count--;

		/* Allocate packet */
		ibs->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
		if (!ibs->rx_skb) {
			BT_ERR("Can't allocate mem for new packet");
			ibs->rx_state = HCI_IBS_W4_PACKET_TYPE;
			ibs->rx_count = 0;
			return 0;
		}

		ibs->rx_skb->dev = (void *) hu->hdev;
		bt_cb(ibs->rx_skb)->pkt_type = type;
	}
Exemplo n.º 4
0
static void handle_control (int fd, struct usb_ctrlrequest *setup)
{
	int		result, tmp;
	__u8		buf [256];
	__u16		value, index, length;

	value = __le16_to_cpu(setup->wValue);
	index = __le16_to_cpu(setup->wIndex);
	length = __le16_to_cpu(setup->wLength);

        if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
                goto special;

	switch (setup->bRequest) {	/* usb 2.0 spec ch9 requests */
	case USB_REQ_GET_DESCRIPTOR:
                if (verbose > 1)
                    fprintf(stderr, "USB_REQ_GET_DESCRIPTOR\n");
		if (setup->bRequestType != USB_DIR_IN)
			goto stall;
		switch (value >> 8) {
		case USB_DT_STRING:
			tmp = value & 0x0ff;
			if (verbose > 1)
				fprintf (stderr,
					"... get string %d lang %04x\n",
					tmp, index);
			if (tmp != 0 && index != strings.language) {
				fprintf (stderr, "wrong language, returning defaults\n");
				tmp = 0;
                        }
                        memset (buf, 0, 256);	/* zero all the bytes */
			result = usb_gadget_get_string (&strings, tmp, buf);
			if (result < 0) {
                            perror("usb_gadget_get_string");
                            goto stall;
                        }
			tmp = result;
			if (length < tmp)
				tmp = length;
			result = write (fd, buf, tmp);
			if (result < 0) {
				if (errno == EIDRM)
					fprintf (stderr, "string timeout\n");
				else
					perror ("write string data");
			} else if (result != tmp) {
				fprintf (stderr, "short string write, %d\n",
					result);
			}
			break;
		default:
			goto stall;
		}
		return;
	case USB_REQ_SET_CONFIGURATION:
		if (verbose > 1)
			fprintf (stderr, "USB_REQ_SET_CONFIGURATION #%d\n", value);
		if (setup->bRequestType != USB_DIR_OUT)
			goto stall;

		/* Kernel is normally waiting for us to finish reconfiguring
		 * the device.
		 *
		 * Some hardware can't, notably older PXA2xx hardware.  (With
		 * racey and restrictive config change automagic.  PXA 255 is
		 * OK, most PXA 250s aren't.  If it has a UDC CFR register,
		 * it can handle deferred response for SET_CONFIG.)  To handle
		 * such hardware, don't write code this way ... instead, keep
		 * the endpoints always active and don't rely on seeing any
		 * config change events, either this or SET_INTERFACE.
		 */
		switch (value) {
		case CONFIG_VALUE:
                        if ( source_fd >= 0 || sink_fd >= 0 || status_fd >= 0)
                            stop_io ();
                        start_io ();
			break;
		case 0:
			stop_io ();
			break;
		default:
			/* kernel bug -- "can't happen" */
			fprintf (stderr, "? illegal config\n");
			goto stall;
		}

		/* ... ack (a write would stall) */
		result = read (fd, &result, 0);
		if (result)
			perror ("ack SET_CONFIGURATION");
		return;
	case USB_REQ_GET_INTERFACE:
		if (verbose > 1)
			fprintf (stderr, "USB_REQ_GET_INTERFACE\n");
		if (setup->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
				|| index != 0
				|| length > 1)
			goto stall;

		/* only one altsetting in this driver */
		buf [0] = 0;
		result = write (fd, buf, length);
		if (result < 0) {
			if (errno == EIDRM)
				fprintf (stderr, "GET_INTERFACE timeout\n");
			else
				perror ("write GET_INTERFACE data");
		} else if (result != length) {
			fprintf (stderr, "short GET_INTERFACE write, %d\n",
				result);
		}
		return;
	case USB_REQ_SET_INTERFACE:
		if (verbose > 1)
			fprintf (stderr, "USB_REQ_SET_INTERFACE\n");
		if (setup->bRequestType != USB_RECIP_INTERFACE
				|| index != 0
				|| value != 0)
			goto stall;

		/* just reset toggle/halt for the interface's endpoints */
		result = 0;
                if (ioctl (source_fd, GADGETFS_CLEAR_HALT) < 0) {
                    result = errno;
                    perror ("reset source fd");
                }
                if (ioctl (sink_fd, GADGETFS_CLEAR_HALT) < 0) {
                    result = errno;
                    perror ("reset sink fd");
                }
                if (status_fd > 0) {
                    if (ioctl (status_fd, GADGETFS_CLEAR_HALT) < 0) {
                        result = errno;
                        perror ("reset status fd");
                    }
                }
		/* FIXME eventually reset the result endpoint too */
		if (result)
			goto stall;

		/* ... and ack (a write would stall) */
		result = read (fd, &result, 0);
		if (result)
			perror ("ack SET_INTERFACE");
                return;
	default:
		goto stall;
	}

special:
        switch (setup->bRequestType) {
            case USB_REQ_CCID: {
                    __u8 *outbuf = NULL;
                    result = ccid_parse_control(setup, &outbuf);
                    if (result < 0 || result > 256)
                        goto stall;
                    if (verbose > 1)
                        fprintf(stderr, "control loop: writing %d bytes... ", result);
                    result = write (fd, outbuf, result);
					/* TODO outbuf should also be freed on error */
					free(outbuf);
                    if (result < 0)
                        goto stall;
                    if (verbose > 1)
                        fprintf(stderr, "done (%d written).\n", result);
                } return;
            default:
		goto stall;
        }

stall:
	if (verbose) {
		fprintf (stderr, "... protocol stall %02x.%02x\n",
			setup->bRequestType, setup->bRequest);
                for (tmp = 0; tmp<5; tmp++) {
                    printf("%d: %s\n", stringtab[tmp].id, stringtab[tmp].s);
                }
        }

	/* non-iso endpoints are stalled by issuing an i/o request
	 * in the "wrong" direction.  ep0 is special only because
	 * the direction isn't fixed.
	 */
	if (setup->bRequestType & USB_DIR_IN)
		result = read (fd, &result, 0);
	else
		result = write (fd, &result, 0);
	if (result != -1)
		fprintf (stderr, "can't stall ep0 for %02x.%02x\n",
			setup->bRequestType, setup->bRequest);
	else if (errno != EL2HLT)
		perror ("ep0 stall");
}
Exemplo n.º 5
0
/* Command Complete OGF HOST_CTL  */
static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{
	__u8 status, param;
	__u16 setting;
	struct hci_rp_read_voice_setting *vs;
	void *sent;

	BT_DBG("%s ocf 0x%x", hdev->name, ocf);

	switch (ocf) {
	case OCF_RESET:
		status = *((__u8 *) skb->data);
		hci_req_complete(hdev, status);
		break;

	case OCF_SET_EVENT_FLT:
		status = *((__u8 *) skb->data);
		if (status) {
			BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
		} else {
			BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name);
		}
		break;

	case OCF_WRITE_AUTH_ENABLE:
		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
		if (!sent)
			break;

		status = *((__u8 *) skb->data);
		param  = *((__u8 *) sent);

		if (!status) {
			if (param == AUTH_ENABLED)
				set_bit(HCI_AUTH, &hdev->flags);
			else
				clear_bit(HCI_AUTH, &hdev->flags);
		}
		hci_req_complete(hdev, status);
		break;

	case OCF_WRITE_ENCRYPT_MODE:
		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
		if (!sent)
			break;

		status = *((__u8 *) skb->data);
		param  = *((__u8 *) sent);

		if (!status) {
			if (param)
				set_bit(HCI_ENCRYPT, &hdev->flags);
			else
				clear_bit(HCI_ENCRYPT, &hdev->flags);
		}
		hci_req_complete(hdev, status);
		break;

	case OCF_WRITE_CA_TIMEOUT:
		status = *((__u8 *) skb->data);
		if (status) {
			BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
		} else {
			BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
		}
		break;

	case OCF_WRITE_PG_TIMEOUT:
		status = *((__u8 *) skb->data);
		if (status) {
			BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
		} else {
			BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
		}
		break;

	case OCF_WRITE_SCAN_ENABLE:
		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
		if (!sent)
			break;

		status = *((__u8 *) skb->data);
		param  = *((__u8 *) sent);

		BT_DBG("param 0x%x", param);

		if (!status) {
			clear_bit(HCI_PSCAN, &hdev->flags);
			clear_bit(HCI_ISCAN, &hdev->flags);
			if (param & SCAN_INQUIRY) 
				set_bit(HCI_ISCAN, &hdev->flags);

			if (param & SCAN_PAGE) 
				set_bit(HCI_PSCAN, &hdev->flags);
		}
		hci_req_complete(hdev, status);
		break;

	case OCF_READ_VOICE_SETTING:
		vs = (struct hci_rp_read_voice_setting *) skb->data;

		if (vs->status) {
			BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vs->status);
			break;
		}

		setting = __le16_to_cpu(vs->voice_setting);

		if (hdev->voice_setting != setting ) {
			hdev->voice_setting = setting;

			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);

			if (hdev->notify) {
				tasklet_disable(&hdev->tx_task);
				hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
				tasklet_enable(&hdev->tx_task);
			}
		}
		break;

	case OCF_WRITE_VOICE_SETTING:
		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
		if (!sent)
			break;

		status = *((__u8 *) skb->data);
		setting = __le16_to_cpu(get_unaligned((__u16 *) sent));

		if (!status && hdev->voice_setting != setting) {
			hdev->voice_setting = setting;

			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);

			if (hdev->notify) {
				tasklet_disable(&hdev->tx_task);
				hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
				tasklet_enable(&hdev->tx_task);
			}
		}
		hci_req_complete(hdev, status);
		break;

	case OCF_HOST_BUFFER_SIZE:
		status = *((__u8 *) skb->data);
		if (status) {
			BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
			hci_req_complete(hdev, status);
		}
		break;

	default:
		BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
		break;
	}
}
Exemplo n.º 6
0
static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_cmd_complete *ev = (void *) skb->data;
	__u16 opcode;

	skb_pull(skb, sizeof(*ev));

	opcode = __le16_to_cpu(ev->opcode);

	switch (opcode) {
	case HCI_OP_INQUIRY_CANCEL:
		hci_cc_inquiry_cancel(hdev, skb);
		break;

	case HCI_OP_EXIT_PERIODIC_INQ:
		hci_cc_exit_periodic_inq(hdev, skb);
		break;

	case HCI_OP_REMOTE_NAME_REQ_CANCEL:
		hci_cc_remote_name_req_cancel(hdev, skb);
		break;

	case HCI_OP_ROLE_DISCOVERY:
		hci_cc_role_discovery(hdev, skb);
		break;

	case HCI_OP_READ_LINK_POLICY:
		hci_cc_read_link_policy(hdev, skb);
		break;

	case HCI_OP_WRITE_LINK_POLICY:
		hci_cc_write_link_policy(hdev, skb);
		break;

	case HCI_OP_READ_DEF_LINK_POLICY:
		hci_cc_read_def_link_policy(hdev, skb);
		break;

	case HCI_OP_WRITE_DEF_LINK_POLICY:
		hci_cc_write_def_link_policy(hdev, skb);
		break;

	case HCI_OP_RESET:
		hci_cc_reset(hdev, skb);
		break;

	case HCI_OP_WRITE_LOCAL_NAME:
		hci_cc_write_local_name(hdev, skb);
		break;

	case HCI_OP_READ_LOCAL_NAME:
		hci_cc_read_local_name(hdev, skb);
		break;

	case HCI_OP_WRITE_AUTH_ENABLE:
		hci_cc_write_auth_enable(hdev, skb);
		break;

	case HCI_OP_WRITE_ENCRYPT_MODE:
		hci_cc_write_encrypt_mode(hdev, skb);
		break;

	case HCI_OP_WRITE_SCAN_ENABLE:
		hci_cc_write_scan_enable(hdev, skb);
		break;

	case HCI_OP_READ_CLASS_OF_DEV:
		hci_cc_read_class_of_dev(hdev, skb);
		break;

	case HCI_OP_WRITE_CLASS_OF_DEV:
		hci_cc_write_class_of_dev(hdev, skb);
		break;

	case HCI_OP_READ_VOICE_SETTING:
		hci_cc_read_voice_setting(hdev, skb);
		break;

	case HCI_OP_WRITE_VOICE_SETTING:
		hci_cc_write_voice_setting(hdev, skb);
		break;

	case HCI_OP_HOST_BUFFER_SIZE:
		hci_cc_host_buffer_size(hdev, skb);
		break;

	case HCI_OP_READ_SSP_MODE:
		hci_cc_read_ssp_mode(hdev, skb);
		break;

	case HCI_OP_WRITE_SSP_MODE:
		hci_cc_write_ssp_mode(hdev, skb);
		break;

	case HCI_OP_READ_LOCAL_VERSION:
		hci_cc_read_local_version(hdev, skb);
		break;

	case HCI_OP_READ_LOCAL_COMMANDS:
		hci_cc_read_local_commands(hdev, skb);
		break;

	case HCI_OP_READ_LOCAL_FEATURES:
		hci_cc_read_local_features(hdev, skb);
		break;

	case HCI_OP_READ_BUFFER_SIZE:
		hci_cc_read_buffer_size(hdev, skb);
		break;

	case HCI_OP_READ_BD_ADDR:
		hci_cc_read_bd_addr(hdev, skb);
		break;

	default:
		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
		break;
	}

	if (ev->ncmd) {
		atomic_set(&hdev->cmd_cnt, 1);
		if (!skb_queue_empty(&hdev->cmd_q))
			tasklet_schedule(&hdev->cmd_task);
	}
}
Exemplo n.º 7
0
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_conn_complete *ev = (void *) skb->data;
	struct hci_conn *conn;

	BT_DBG("%s", hdev->name);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
	if (!conn) {
		if (ev->link_type != SCO_LINK)
			goto unlock;

		conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr);
		if (!conn)
			goto unlock;

		conn->type = SCO_LINK;
	}

	if (!ev->status) {
		conn->handle = __le16_to_cpu(ev->handle);

		if (conn->type == ACL_LINK) {
			conn->state = BT_CONFIG;
			hci_conn_hold(conn);
			conn->disc_timeout = HCI_DISCONN_TIMEOUT;
		} else
			conn->state = BT_CONNECTED;

		hci_conn_hold_device(conn);
		hci_conn_add_sysfs(conn);

		if (test_bit(HCI_AUTH, &hdev->flags))
			conn->link_mode |= HCI_LM_AUTH;

		if (test_bit(HCI_ENCRYPT, &hdev->flags))
			conn->link_mode |= HCI_LM_ENCRYPT;

		/* Get remote features */
		if (conn->type == ACL_LINK) {
			struct hci_cp_read_remote_features cp;
			cp.handle = ev->handle;
			hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
							sizeof(cp), &cp);
		}

		/* Set packet type for incoming connection */
		if (!conn->out && hdev->hci_ver < 3) {
			struct hci_cp_change_conn_ptype cp;
			cp.handle = ev->handle;
			cp.pkt_type = cpu_to_le16(conn->pkt_type);
			hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE,
							sizeof(cp), &cp);
		}
	} else
		conn->state = BT_CLOSED;

	if (conn->type == ACL_LINK)
		hci_sco_setup(conn, ev->status);

	if (ev->status) {
		hci_proto_connect_cfm(conn, ev->status);
		hci_conn_del(conn);
	} else if (ev->link_type != ACL_LINK)
		hci_proto_connect_cfm(conn, ev->status);

unlock:
	hci_dev_unlock(hdev);

	hci_conn_check_pending(hdev);
}
Exemplo n.º 8
0
Arquivo: htc.c Projeto: muonn/ath
int ath10k_htc_connect_service(struct ath10k_htc *htc,
			       struct ath10k_htc_svc_conn_req *conn_req,
			       struct ath10k_htc_svc_conn_resp *conn_resp)
{
	struct ath10k_htc_msg *msg;
	struct ath10k_htc_conn_svc *req_msg;
	struct ath10k_htc_conn_svc_response resp_msg_dummy;
	struct ath10k_htc_conn_svc_response *resp_msg = &resp_msg_dummy;
	enum ath10k_htc_ep_id assigned_eid = ATH10K_HTC_EP_COUNT;
	struct ath10k_htc_ep *ep;
	struct sk_buff *skb;
	unsigned int max_msg_size = 0;
	int length, status;
	bool disable_credit_flow_ctrl = false;
	u16 message_id, service_id, flags = 0;
	u8 tx_alloc = 0;

	/* special case for HTC pseudo control service */
	if (conn_req->service_id == ATH10K_HTC_SVC_ID_RSVD_CTRL) {
		disable_credit_flow_ctrl = true;
		assigned_eid = ATH10K_HTC_EP_0;
		max_msg_size = ATH10K_HTC_MAX_CTRL_MSG_LEN;
		memset(&resp_msg_dummy, 0, sizeof(resp_msg_dummy));
		goto setup;
	}

	tx_alloc = ath10k_htc_get_credit_allocation(htc,
						    conn_req->service_id);
	if (!tx_alloc)
		ath10k_dbg(ATH10K_DBG_BOOT,
			   "boot htc service %s does not allocate target credits\n",
			   htc_service_name(conn_req->service_id));

	skb = ath10k_htc_build_tx_ctrl_skb(htc->ar);
	if (!skb) {
		ath10k_err("Failed to allocate HTC packet\n");
		return -ENOMEM;
	}

	length = sizeof(msg->hdr) + sizeof(msg->connect_service);
	skb_put(skb, length);
	memset(skb->data, 0, length);

	msg = (struct ath10k_htc_msg *)skb->data;
	msg->hdr.message_id =
		__cpu_to_le16(ATH10K_HTC_MSG_CONNECT_SERVICE_ID);

	flags |= SM(tx_alloc, ATH10K_HTC_CONN_FLAGS_RECV_ALLOC);

	/* Only enable credit flow control for WMI ctrl service */
	if (conn_req->service_id != ATH10K_HTC_SVC_ID_WMI_CONTROL) {
		flags |= ATH10K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
		disable_credit_flow_ctrl = true;
	}

	req_msg = &msg->connect_service;
	req_msg->flags = __cpu_to_le16(flags);
	req_msg->service_id = __cpu_to_le16(conn_req->service_id);

	reinit_completion(&htc->ctl_resp);

	status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
	if (status) {
		kfree_skb(skb);
		return status;
	}

	/* wait for response */
	status = wait_for_completion_timeout(&htc->ctl_resp,
					     ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
	if (status <= 0) {
		if (status == 0)
			status = -ETIMEDOUT;
		ath10k_err("Service connect timeout: %d\n", status);
		return status;
	}

	/* we controlled the buffer creation, it's aligned */
	msg = (struct ath10k_htc_msg *)htc->control_resp_buffer;
	resp_msg = &msg->connect_service_response;
	message_id = __le16_to_cpu(msg->hdr.message_id);
	service_id = __le16_to_cpu(resp_msg->service_id);

	if ((message_id != ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID) ||
	    (htc->control_resp_len < sizeof(msg->hdr) +
	     sizeof(msg->connect_service_response))) {
		ath10k_err("Invalid resp message ID 0x%x", message_id);
		return -EPROTO;
	}

	ath10k_dbg(ATH10K_DBG_HTC,
		   "HTC Service %s connect response: status: 0x%x, assigned ep: 0x%x\n",
		   htc_service_name(service_id),
		   resp_msg->status, resp_msg->eid);

	conn_resp->connect_resp_code = resp_msg->status;

	/* check response status */
	if (resp_msg->status != ATH10K_HTC_CONN_SVC_STATUS_SUCCESS) {
		ath10k_err("HTC Service %s connect request failed: 0x%x)\n",
			   htc_service_name(service_id),
			   resp_msg->status);
		return -EPROTO;
	}

	assigned_eid = (enum ath10k_htc_ep_id)resp_msg->eid;
	max_msg_size = __le16_to_cpu(resp_msg->max_msg_size);

setup:

	if (assigned_eid >= ATH10K_HTC_EP_COUNT)
		return -EPROTO;

	if (max_msg_size == 0)
		return -EPROTO;

	ep = &htc->endpoint[assigned_eid];
	ep->eid = assigned_eid;

	if (ep->service_id != ATH10K_HTC_SVC_ID_UNUSED)
		return -EPROTO;

	/* return assigned endpoint to caller */
	conn_resp->eid = assigned_eid;
	conn_resp->max_msg_len = __le16_to_cpu(resp_msg->max_msg_size);

	/* setup the endpoint */
	ep->service_id = conn_req->service_id;
	ep->max_tx_queue_depth = conn_req->max_send_queue_depth;
	ep->max_ep_message_len = __le16_to_cpu(resp_msg->max_msg_size);
	ep->tx_credits = tx_alloc;
	ep->tx_credit_size = htc->target_credit_size;
	ep->tx_credits_per_max_message = ep->max_ep_message_len /
					 htc->target_credit_size;

	if (ep->max_ep_message_len % htc->target_credit_size)
		ep->tx_credits_per_max_message++;

	/* copy all the callbacks */
	ep->ep_ops = conn_req->ep_ops;

	status = ath10k_hif_map_service_to_pipe(htc->ar,
						ep->service_id,
						&ep->ul_pipe_id,
						&ep->dl_pipe_id,
						&ep->ul_is_polled,
						&ep->dl_is_polled);
	if (status)
		return status;

	ath10k_dbg(ATH10K_DBG_BOOT,
		   "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
		   htc_service_name(ep->service_id), ep->ul_pipe_id,
		   ep->dl_pipe_id, ep->eid);

	ath10k_dbg(ATH10K_DBG_BOOT,
		   "boot htc ep %d ul polled %d dl polled %d\n",
		   ep->eid, ep->ul_is_polled, ep->dl_is_polled);

	if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
		ep->tx_credit_flow_enabled = false;
		ath10k_dbg(ATH10K_DBG_BOOT,
			   "boot htc service '%s' eid %d TX flow control disabled\n",
			   htc_service_name(ep->service_id), assigned_eid);
	}

	return status;
}
Exemplo n.º 9
0
static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
{
	unsigned int iobase;
	unsigned char buf[31];
	int i, len;

	if (!info) {
		printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n");
		return;
	}

	iobase = info->link.io.BasePort1;

	if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
		bluecard_enable_activity_led(info);

	len = bluecard_read(iobase, offset, buf, sizeof(buf));

	for (i = 0; i < len; i++) {

		/* Allocate packet */
		if (info->rx_skb == NULL) {
			info->rx_state = RECV_WAIT_PACKET_TYPE;
			info->rx_count = 0;
			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
				printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
				return;
			}
		}

		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {

			info->rx_skb->dev = (void *)&(info->hdev);
			info->rx_skb->pkt_type = buf[i];

			switch (info->rx_skb->pkt_type) {

			case 0x00:
				/* init packet */
				if (offset != 0x00) {
					set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
					set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
					set_bit(XMIT_SENDING_READY, &(info->tx_state));
					bluecard_write_wakeup(info);
				}

				kfree_skb(info->rx_skb);
				info->rx_skb = NULL;
				break;

			case HCI_EVENT_PKT:
				info->rx_state = RECV_WAIT_EVENT_HEADER;
				info->rx_count = HCI_EVENT_HDR_SIZE;
				break;

			case HCI_ACLDATA_PKT:
				info->rx_state = RECV_WAIT_ACL_HEADER;
				info->rx_count = HCI_ACL_HDR_SIZE;
				break;

			case HCI_SCODATA_PKT:
				info->rx_state = RECV_WAIT_SCO_HEADER;
				info->rx_count = HCI_SCO_HDR_SIZE;
				break;

			default:
				/* unknown packet */
				printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
				info->hdev.stat.err_rx++;

				kfree_skb(info->rx_skb);
				info->rx_skb = NULL;
				break;

			}

		} else {

			*skb_put(info->rx_skb, 1) = buf[i];
			info->rx_count--;

			if (info->rx_count == 0) {

				int dlen;
				hci_event_hdr *eh;
				hci_acl_hdr *ah;
				hci_sco_hdr *sh;

				switch (info->rx_state) {

				case RECV_WAIT_EVENT_HEADER:
					eh = (hci_event_hdr *)(info->rx_skb->data);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = eh->plen;
					break;

				case RECV_WAIT_ACL_HEADER:
					ah = (hci_acl_hdr *)(info->rx_skb->data);
					dlen = __le16_to_cpu(ah->dlen);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = dlen;
					break;

				case RECV_WAIT_SCO_HEADER:
					sh = (hci_sco_hdr *)(info->rx_skb->data);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = sh->dlen;
					break;

				case RECV_WAIT_DATA:
					hci_recv_frame(info->rx_skb);
					info->rx_skb = NULL;
					break;

				}

			}

		}


	}

	info->hdev.stat.byte_rx += len;
}
Exemplo n.º 10
0
Arquivo: htc.c Projeto: muonn/ath
static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
					    struct sk_buff *skb,
					    u8 pipe_id)
{
	int status = 0;
	struct ath10k_htc *htc = &ar->htc;
	struct ath10k_htc_hdr *hdr;
	struct ath10k_htc_ep *ep;
	u16 payload_len;
	u32 trailer_len = 0;
	size_t min_len;
	u8 eid;
	bool trailer_present;

	hdr = (struct ath10k_htc_hdr *)skb->data;
	skb_pull(skb, sizeof(*hdr));

	eid = hdr->eid;

	if (eid >= ATH10K_HTC_EP_COUNT) {
		ath10k_warn("HTC Rx: invalid eid %d\n", eid);
		ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "",
				hdr, sizeof(*hdr));
		status = -EINVAL;
		goto out;
	}

	ep = &htc->endpoint[eid];

	/*
	 * If this endpoint that received a message from the target has
	 * a to-target HIF pipe whose send completions are polled rather
	 * than interrupt-driven, this is a good point to ask HIF to check
	 * whether it has any completed sends to handle.
	 */
	if (ep->ul_is_polled)
		ath10k_htc_send_complete_check(ep, 1);

	payload_len = __le16_to_cpu(hdr->len);

	if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) {
		ath10k_warn("HTC rx frame too long, len: %zu\n",
			    payload_len + sizeof(*hdr));
		ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "",
				hdr, sizeof(*hdr));
		status = -EINVAL;
		goto out;
	}

	if (skb->len < payload_len) {
		ath10k_dbg(ATH10K_DBG_HTC,
			   "HTC Rx: insufficient length, got %d, expected %d\n",
			   skb->len, payload_len);
		ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len",
				"", hdr, sizeof(*hdr));
		status = -EINVAL;
		goto out;
	}

	/* get flags to check for trailer */
	trailer_present = hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT;
	if (trailer_present) {
		u8 *trailer;

		trailer_len = hdr->trailer_len;
		min_len = sizeof(struct ath10k_ath10k_htc_record_hdr);

		if ((trailer_len < min_len) ||
		    (trailer_len > payload_len)) {
			ath10k_warn("Invalid trailer length: %d\n",
				    trailer_len);
			status = -EPROTO;
			goto out;
		}

		trailer = (u8 *)hdr;
		trailer += sizeof(*hdr);
		trailer += payload_len;
		trailer -= trailer_len;
		status = ath10k_htc_process_trailer(htc, trailer,
						    trailer_len, hdr->eid);
		if (status)
			goto out;

		skb_trim(skb, skb->len - trailer_len);
	}

	if (((int)payload_len - (int)trailer_len) <= 0)
		/* zero length packet with trailer data, just drop these */
		goto out;

	if (eid == ATH10K_HTC_EP_0) {
		struct ath10k_htc_msg *msg = (struct ath10k_htc_msg *)skb->data;

		switch (__le16_to_cpu(msg->hdr.message_id)) {
		default:
			/* handle HTC control message */
			if (completion_done(&htc->ctl_resp)) {
				/*
				 * this is a fatal error, target should not be
				 * sending unsolicited messages on the ep 0
				 */
				ath10k_warn("HTC rx ctrl still processing\n");
				status = -EINVAL;
				complete(&htc->ctl_resp);
				goto out;
			}

			htc->control_resp_len =
				min_t(int, skb->len,
				      ATH10K_HTC_MAX_CTRL_MSG_LEN);

			memcpy(htc->control_resp_buffer, skb->data,
			       htc->control_resp_len);

			complete(&htc->ctl_resp);
			break;
		case ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE:
			htc->htc_ops.target_send_suspend_complete(ar);
		}
		goto out;
	}

	ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
		   eid, skb);
	ep->ep_ops.ep_rx_complete(ar, skb);

	/* skb is now owned by the rx completion handler */
	skb = NULL;
out:
	kfree_skb(skb);

	return status;
}
Exemplo n.º 11
0
Arquivo: htc.c Projeto: muonn/ath
int ath10k_htc_wait_target(struct ath10k_htc *htc)
{
	int i, status = 0;
	struct ath10k_htc_svc_conn_req conn_req;
	struct ath10k_htc_svc_conn_resp conn_resp;
	struct ath10k_htc_msg *msg;
	u16 message_id;
	u16 credit_count;
	u16 credit_size;

	status = wait_for_completion_timeout(&htc->ctl_resp,
					     ATH10K_HTC_WAIT_TIMEOUT_HZ);
	if (status == 0) {
		/* Workaround: In some cases the PCI HIF doesn't
		 * receive interrupt for the control response message
		 * even if the buffer was completed. It is suspected
		 * iomap writes unmasking PCI CE irqs aren't propagated
		 * properly in KVM PCI-passthrough sometimes.
		 */
		ath10k_warn("failed to receive control response completion, polling..\n");

		for (i = 0; i < CE_COUNT; i++)
			ath10k_hif_send_complete_check(htc->ar, i, 1);

		status = wait_for_completion_timeout(&htc->ctl_resp,
					ATH10K_HTC_WAIT_TIMEOUT_HZ);

		if (status == 0)
			status = -ETIMEDOUT;
	}

	if (status < 0) {
		ath10k_err("ctl_resp never came in (%d)\n", status);
		return status;
	}

	if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) {
		ath10k_err("Invalid HTC ready msg len:%d\n",
			   htc->control_resp_len);
		return -ECOMM;
	}

	msg = (struct ath10k_htc_msg *)htc->control_resp_buffer;
	message_id   = __le16_to_cpu(msg->hdr.message_id);
	credit_count = __le16_to_cpu(msg->ready.credit_count);
	credit_size  = __le16_to_cpu(msg->ready.credit_size);

	if (message_id != ATH10K_HTC_MSG_READY_ID) {
		ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id);
		return -ECOMM;
	}

	htc->total_transmit_credits = credit_count;
	htc->target_credit_size = credit_size;

	ath10k_dbg(ATH10K_DBG_HTC,
		   "Target ready! transmit resources: %d size:%d\n",
		   htc->total_transmit_credits,
		   htc->target_credit_size);

	if ((htc->total_transmit_credits == 0) ||
	    (htc->target_credit_size == 0)) {
		ath10k_err("Invalid credit size received\n");
		return -ECOMM;
	}

	ath10k_htc_setup_target_buffer_assignments(htc);

	/* setup our pseudo HTC control endpoint connection */
	memset(&conn_req, 0, sizeof(conn_req));
	memset(&conn_resp, 0, sizeof(conn_resp));
	conn_req.ep_ops.ep_tx_complete = ath10k_htc_control_tx_complete;
	conn_req.ep_ops.ep_rx_complete = ath10k_htc_control_rx_complete;
	conn_req.max_send_queue_depth = ATH10K_NUM_CONTROL_TX_BUFFERS;
	conn_req.service_id = ATH10K_HTC_SVC_ID_RSVD_CTRL;

	/* connect fake service */
	status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
	if (status) {
		ath10k_err("could not connect to htc service (%d)\n", status);
		return status;
	}

	return 0;
}
Exemplo n.º 12
0
static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
{
	struct bpa10x_data *data = hci_get_drvdata(hdev);

	BT_DBG("%s queue %d buffer %p count %d", hdev->name,
							queue, buf, count);

	if (queue < 0 || queue > 1)
		return -EILSEQ;

	hdev->stat.byte_rx += count;

	while (count) {
		struct sk_buff *skb = data->rx_skb[queue];
		struct { __u8 type; int expect; } *scb;
		int type, len = 0;

		if (!skb) {
			/* Start of the frame */

			type = *((__u8 *) buf);
			count--; buf++;

			switch (type) {
			case HCI_EVENT_PKT:
				if (count >= HCI_EVENT_HDR_SIZE) {
					struct hci_event_hdr *h = buf;
					len = HCI_EVENT_HDR_SIZE + h->plen;
				} else
					return -EILSEQ;
				break;

			case HCI_ACLDATA_PKT:
				if (count >= HCI_ACL_HDR_SIZE) {
					struct hci_acl_hdr *h = buf;
					len = HCI_ACL_HDR_SIZE +
							__le16_to_cpu(h->dlen);
				} else
					return -EILSEQ;
				break;

			case HCI_SCODATA_PKT:
				if (count >= HCI_SCO_HDR_SIZE) {
					struct hci_sco_hdr *h = buf;
					len = HCI_SCO_HDR_SIZE + h->dlen;
				} else
					return -EILSEQ;
				break;

			case HCI_VENDOR_PKT:
				if (count >= HCI_VENDOR_HDR_SIZE) {
					struct hci_vendor_hdr *h = buf;
					len = HCI_VENDOR_HDR_SIZE +
							__le16_to_cpu(h->dlen);
				} else
					return -EILSEQ;
				break;
			}

			skb = bt_skb_alloc(len, GFP_ATOMIC);
			if (!skb) {
				BT_ERR("%s no memory for packet", hdev->name);
				return -ENOMEM;
			}

			skb->dev = (void *) hdev;

			data->rx_skb[queue] = skb;

			scb = (void *) skb->cb;
			scb->type = type;
			scb->expect = len;
		} else {
			/* Continuation */

			scb = (void *) skb->cb;
			len = scb->expect;
		}

		len = min(len, count);

		memcpy(skb_put(skb, len), buf, len);

		scb->expect -= len;

		if (scb->expect == 0) {
			/* Complete frame */

			data->rx_skb[queue] = NULL;

			bt_cb(skb)->pkt_type = scb->type;
			hci_recv_frame(skb);
		}

		count -= len; buf += len;
	}

	return 0;
}
Exemplo n.º 13
0
static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len)
{
	BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len);

	if (hdr & 0x10) {
		BT_ERR("%s error in block", data->hdev->name);
		kfree_skb(data->reassembly);
		data->reassembly = NULL;
		return -EIO;
	}

	if (hdr & 0x04) {
		struct sk_buff *skb;
		unsigned char pkt_type;
		int pkt_len = 0;

		if (data->reassembly) {
			BT_ERR("%s unexpected start block", data->hdev->name);
			kfree_skb(data->reassembly);
			data->reassembly = NULL;
		}

		if (len < 1) {
			BT_ERR("%s no packet type found", data->hdev->name);
			return -EPROTO;
		}

		pkt_type = *buf++; len--;

		switch (pkt_type) {
		case HCI_EVENT_PKT:
			if (len >= HCI_EVENT_HDR_SIZE) {
				struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf;
				pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
			} else {
				BT_ERR("%s event block is too short", data->hdev->name);
				return -EILSEQ;
			}
			break;

		case HCI_ACLDATA_PKT:
			if (len >= HCI_ACL_HDR_SIZE) {
				struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf;
				pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
			} else {
				BT_ERR("%s data block is too short", data->hdev->name);
				return -EILSEQ;
			}
			break;

		case HCI_SCODATA_PKT:
			if (len >= HCI_SCO_HDR_SIZE) {
				struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf;
				pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
			} else {
				BT_ERR("%s audio block is too short", data->hdev->name);
				return -EILSEQ;
			}
			break;
		}

		skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
		if (!skb) {
			BT_ERR("%s no memory for the packet", data->hdev->name);
			return -ENOMEM;
		}

		bt_cb(skb)->pkt_type = pkt_type;

		data->reassembly = skb;
	} else {
		if (!data->reassembly) {
			BT_ERR("%s unexpected continuation block", data->hdev->name);
			return -EIO;
		}
	}

	if (len > 0)
		memcpy(skb_put(data->reassembly, len), buf, len);

	if (hdr & 0x08) {
		hci_recv_frame(data->hdev, data->reassembly);
		data->reassembly = NULL;
	}

	return 0;
}
Exemplo n.º 14
0
static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
{
	struct sock *sk = sock->sk;
	struct sockaddr_l2 la;
	int len, err = 0;

	BT_DBG("sk %p type %d mode %d state %d", sk, sk->sk_type,
		l2cap_pi(sk)->mode, sk->sk_state);

	if (!addr || alen < sizeof(addr->sa_family) ||
	    addr->sa_family != AF_BLUETOOTH)
		return -EINVAL;

	memset(&la, 0, sizeof(la));
	len = min_t(unsigned int, sizeof(la), alen);
	memcpy(&la, addr, len);

	if (la.l2_cid && la.l2_psm)
		return -EINVAL;

	lock_sock(sk);

	if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
		&& !(la.l2_psm || la.l2_cid || l2cap_pi(sk)->fixed_channel)) {
		err = -EINVAL;
		goto done;
	}

	switch (l2cap_pi(sk)->mode) {
	case L2CAP_MODE_BASIC:
		break;
	case L2CAP_MODE_ERTM:
	case L2CAP_MODE_STREAMING:
		if (!disable_ertm)
			break;
		/* fall through */
	default:
		err = -ENOTSUPP;
		goto done;
	}

	switch (sk->sk_state) {
	case BT_CONNECT:
	case BT_CONNECT2:
	case BT_CONFIG:
		/* Already connecting */
		goto wait;

	case BT_CONNECTED:
		/* Already connected */
		err = -EISCONN;
		goto done;

	case BT_OPEN:
	case BT_BOUND:
		/* Can connect */
		break;

	default:
		err = -EBADFD;
		goto done;
	}

	/* PSM must be odd and lsb of upper byte must be 0 */
	if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 &&
		!l2cap_pi(sk)->fixed_channel &&
				sk->sk_type != SOCK_RAW && !la.l2_cid) {
		BT_DBG("Bad PSM 0x%x", (int)__le16_to_cpu(la.l2_psm));
		err = -EINVAL;
		goto done;
	}

	/* Set destination address and psm */
	bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
	l2cap_pi(sk)->psm = la.l2_psm;
	l2cap_pi(sk)->dcid = la.l2_cid;

	err = l2cap_do_connect(sk);
	if (err)
		goto done;

wait:
	err = bt_sock_wait_state(sk, BT_CONNECTED,
			sock_sndtimeo(sk, flags & O_NONBLOCK));
done:
	if (err)
		BT_ERR("failed %d", err);
	release_sock(sk);
	return err;
}
Exemplo n.º 15
0
static void bt3c_receive(bt3c_info_t *info)
{
	unsigned int iobase;
	int size = 0, avail;

	if (!info) {
		BT_ERR("Unknown device");
		return;
	}

	iobase = info->link.io.BasePort1;

	avail = bt3c_read(iobase, 0x7006);
	//printk("bt3c_cs: receiving %d bytes\n", avail);

	bt3c_address(iobase, 0x7480);
	while (size < avail) {
		size++;
		info->hdev->stat.byte_rx++;

		/* Allocate packet */
		if (info->rx_skb == NULL) {
			info->rx_state = RECV_WAIT_PACKET_TYPE;
			info->rx_count = 0;
			if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
				BT_ERR("Can't allocate mem for new packet");
				return;
			}
		}


		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {

			info->rx_skb->dev = (void *) info->hdev;
			info->rx_skb->pkt_type = inb(iobase + DATA_L);
			inb(iobase + DATA_H);
			//printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);

			switch (info->rx_skb->pkt_type) {

			case HCI_EVENT_PKT:
				info->rx_state = RECV_WAIT_EVENT_HEADER;
				info->rx_count = HCI_EVENT_HDR_SIZE;
				break;

			case HCI_ACLDATA_PKT:
				info->rx_state = RECV_WAIT_ACL_HEADER;
				info->rx_count = HCI_ACL_HDR_SIZE;
				break;

			case HCI_SCODATA_PKT:
				info->rx_state = RECV_WAIT_SCO_HEADER;
				info->rx_count = HCI_SCO_HDR_SIZE;
				break;

			default:
				/* Unknown packet */
				BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type);
				info->hdev->stat.err_rx++;
				clear_bit(HCI_RUNNING, &(info->hdev->flags));

				kfree_skb(info->rx_skb);
				info->rx_skb = NULL;
				break;

			}

		} else {

			__u8 x = inb(iobase + DATA_L);

			*skb_put(info->rx_skb, 1) = x;
			inb(iobase + DATA_H);
			info->rx_count--;

			if (info->rx_count == 0) {

				int dlen;
				struct hci_event_hdr *eh;
				struct hci_acl_hdr *ah;
				struct hci_sco_hdr *sh;

				switch (info->rx_state) {

				case RECV_WAIT_EVENT_HEADER:
					eh = (struct hci_event_hdr *)(info->rx_skb->data);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = eh->plen;
					break;

				case RECV_WAIT_ACL_HEADER:
					ah = (struct hci_acl_hdr *)(info->rx_skb->data);
					dlen = __le16_to_cpu(ah->dlen);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = dlen;
					break;

				case RECV_WAIT_SCO_HEADER:
					sh = (struct hci_sco_hdr *)(info->rx_skb->data);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = sh->dlen;
					break;

				case RECV_WAIT_DATA:
					hci_recv_frame(info->rx_skb);
					info->rx_skb = NULL;
					break;

				}

			}

		}

	}

	bt3c_io_write(iobase, 0x7006, 0x0000);
}
Exemplo n.º 16
0
/*
 * Beginning of Taskfile OPCODE Library and feature sets.
 */
void ide_fix_driveid (struct hd_driveid *id)
{
#ifndef __LITTLE_ENDIAN
# ifdef __BIG_ENDIAN
	int i;
	u16 *stringcast;

	id->config         = __le16_to_cpu(id->config);
	id->cyls           = __le16_to_cpu(id->cyls);
	id->reserved2      = __le16_to_cpu(id->reserved2);
	id->heads          = __le16_to_cpu(id->heads);
	id->track_bytes    = __le16_to_cpu(id->track_bytes);
	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
	id->sectors        = __le16_to_cpu(id->sectors);
	id->vendor0        = __le16_to_cpu(id->vendor0);
	id->vendor1        = __le16_to_cpu(id->vendor1);
	id->vendor2        = __le16_to_cpu(id->vendor2);
	stringcast = (u16 *)&id->serial_no[0];
	for (i = 0; i < (20/2); i++)
		stringcast[i] = __le16_to_cpu(stringcast[i]);
	id->buf_type       = __le16_to_cpu(id->buf_type);
	id->buf_size       = __le16_to_cpu(id->buf_size);
	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
	stringcast = (u16 *)&id->fw_rev[0];
	for (i = 0; i < (8/2); i++)
		stringcast[i] = __le16_to_cpu(stringcast[i]);
	stringcast = (u16 *)&id->model[0];
	for (i = 0; i < (40/2); i++)
		stringcast[i] = __le16_to_cpu(stringcast[i]);
	id->dword_io       = __le16_to_cpu(id->dword_io);
	id->reserved50     = __le16_to_cpu(id->reserved50);
	id->field_valid    = __le16_to_cpu(id->field_valid);
	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
	id->cur_heads      = __le16_to_cpu(id->cur_heads);
	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
	id->dma_1word      = __le16_to_cpu(id->dma_1word);
	id->dma_mword      = __le16_to_cpu(id->dma_mword);
	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
	id->eide_pio       = __le16_to_cpu(id->eide_pio);
	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
	for (i = 0; i < 2; ++i)
		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
	for (i = 0; i < 4; ++i)
		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
	id->queue_depth    = __le16_to_cpu(id->queue_depth);
	for (i = 0; i < 4; ++i)
		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
	id->command_set_1  = __le16_to_cpu(id->command_set_1);
	id->command_set_2  = __le16_to_cpu(id->command_set_2);
	id->cfsse          = __le16_to_cpu(id->cfsse);
	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
	id->csf_default    = __le16_to_cpu(id->csf_default);
	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
	id->trseuc         = __le16_to_cpu(id->trseuc);
	id->trsEuc         = __le16_to_cpu(id->trsEuc);
	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
	id->mprc           = __le16_to_cpu(id->mprc);
	id->hw_config      = __le16_to_cpu(id->hw_config);
	id->acoustic       = __le16_to_cpu(id->acoustic);
	id->msrqs          = __le16_to_cpu(id->msrqs);
	id->sxfert         = __le16_to_cpu(id->sxfert);
	id->sal            = __le16_to_cpu(id->sal);
	id->spg            = __le32_to_cpu(id->spg);
	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
	for (i = 0; i < 22; i++)
		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
	id->last_lun       = __le16_to_cpu(id->last_lun);
	id->word127        = __le16_to_cpu(id->word127);
	id->dlf            = __le16_to_cpu(id->dlf);
	id->csfo           = __le16_to_cpu(id->csfo);
	for (i = 0; i < 26; i++)
		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
	id->word156        = __le16_to_cpu(id->word156);
	for (i = 0; i < 3; i++)
		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
	id->cfa_power      = __le16_to_cpu(id->cfa_power);
	for (i = 0; i < 14; i++)
		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
	for (i = 0; i < 31; i++)
		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
	for (i = 0; i < 48; i++)
		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
	id->integrity_word  = __le16_to_cpu(id->integrity_word);
# else
#  error "Please fix <asm/byteorder.h>"
# endif
#endif
}
Exemplo n.º 17
0
/* Recv data */
static int h4_recv(struct hci_uart *hu, void *data, int count)
{
#ifdef CONFIG_RADIO_BCM4343S
    struct h4_struct *h4 = hu->priv;
    register char *ptr;
    struct hci_event_hdr *eh;
    struct hci_acl_hdr   *ah;
    struct hci_sco_hdr   *sh;
    struct fm_event_hdr *fm;
    register int len, type, dlen;
    static enum proto_type protoid = PROTO_SH_MAX;

    BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, h4->rx_state, h4->rx_count);

    ptr = (char *)data;
    while (count) {
        if (h4->rx_count) {
            len = min_t(unsigned int, h4->rx_count, count);
              memcpy(skb_put(h4->rx_skb, len), ptr, len);
            h4->rx_count -= len; count -= len; ptr += len;

            if (h4->rx_count)
                continue;

            switch (h4->rx_state) {
            case H4_W4_DATA:

                BT_DBG("%2x %2x %2x %2x",h4->rx_skb->data[0], h4->rx_skb->data[1], h4->rx_skb->data[2], h4->rx_skb->data[3]);
                BT_DBG("%2x %2x %2x %2x",h4->rx_skb->data[4], h4->rx_skb->data[5], h4->rx_skb->data[6], h4->rx_skb->data[7]);

                BT_DBG("Complete data");

                if ( ( h4->rx_skb->data[3] == 0x15 && h4->rx_skb->data[4] == 0xfc )
                  || ( h4->rx_skb->data[0] == 0xff && h4->rx_skb->data[1] == 0x01 && h4->rx_skb->data[2] == 0x08 )
               )
                {
                   BT_DBG("FM Event change to FM CH8 packet");
                   type = FM_CH8_PKT;
                   h4->rx_skb->cb[0] = FM_CH8_PKT;
                   h4->rx_state = FM_W4_EVENT_HDR;
                   protoid = PROTO_SH_FM;
                }

                hci_uart_route_frame(protoid, hu, h4->rx_skb);

                h4->rx_state = H4_W4_PACKET_TYPE;
                h4->rx_skb = NULL;
                protoid = PROTO_SH_MAX;
                continue;

            case H4_W4_EVENT_HDR:
                eh = hci_event_hdr(h4->rx_skb);

                BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);

                h4_check_data_len(h4, hu, protoid, eh->plen);
                continue;

            case H4_W4_ACL_HDR:
                ah = hci_acl_hdr(h4->rx_skb);

                dlen = __le16_to_cpu(ah->dlen);

                BT_DBG("ACL header: dlen %d", dlen);

                h4_check_data_len(h4, hu, protoid, dlen);
                continue;

            case H4_W4_SCO_HDR:
                sh = hci_sco_hdr(h4->rx_skb);

                BT_DBG("SCO header: dlen %d", sh->dlen);

                h4_check_data_len(h4, hu, protoid, sh->dlen);
                continue;

            case FM_W4_EVENT_HDR:
                fm = (struct fm_event_hdr *)h4->rx_skb->data;
                BT_DBG("FM Header: evt 0x%2.2x plen %d",
                    fm->event, fm->plen);
                h4_check_data_len(h4, hu, PROTO_SH_FM, fm->plen);
                continue;

            }
        }

        /* H4_W4_PACKET_TYPE */
        switch (*ptr) {
        case HCI_EVENT_PKT:
            BT_DBG("Event packet");

            BT_DBG("%2x %2x %2x %2x",ptr[0], ptr[1], ptr[2], ptr[3]);
            BT_DBG("%2x %2x %2x %2x",ptr[4], ptr[5], ptr[6], ptr[7]);
            if ( ptr[4] == 0x15 && ptr[5] == 0xfc )
            {
               BT_DBG("FM Event change to FM CH8 packet");
               type = FM_CH8_PKT;
               h4->rx_state = FM_W4_EVENT_HDR;
               h4->rx_count = FM_EVENT_HDR_SIZE;
               protoid = PROTO_SH_FM;
            }
            else
            {
               BT_DBG("FM Event is not detected");
               h4->rx_state = H4_W4_EVENT_HDR;
               h4->rx_count = HCI_EVENT_HDR_SIZE;
               type = HCI_EVENT_PKT;
               protoid = PROTO_SH_BT;
            }
            break;

        case HCI_ACLDATA_PKT:
            BT_DBG("ACL packet");
            h4->rx_state = H4_W4_ACL_HDR;
            h4->rx_count = HCI_ACL_HDR_SIZE;
            type = HCI_ACLDATA_PKT;
            protoid = PROTO_SH_BT;
            break;

        case HCI_SCODATA_PKT:
            BT_DBG("SCO packet");
            h4->rx_state = H4_W4_SCO_HDR;
            h4->rx_count = HCI_SCO_HDR_SIZE;
            type = HCI_SCODATA_PKT;
            protoid = PROTO_SH_BT;
            break;

        /* Channel 8(FM) packet */
        case FM_CH8_PKT:
            BT_DBG("FM CH8 packet");
            type = FM_CH8_PKT;
            h4->rx_state = FM_W4_EVENT_HDR;
            h4->rx_count = FM_EVENT_HDR_SIZE;
            protoid = PROTO_SH_FM;
            break;

        default:
            BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
            hu->hdev->stat.err_rx++;
            ptr++; count--;
            continue;
        };

        ptr++; count--;

        switch (protoid)
        {
            case PROTO_SH_BT:
            case PROTO_SH_FM:
                /* Allocate new packet to hold received data */
                h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
                if (!h4->rx_skb)
                {
                    BT_ERR("Can't allocate mem for new packet");
                    h4->rx_state = H4_W4_PACKET_TYPE;
                    h4->rx_count = 0;
                    return -ENOMEM;
                }
                h4->rx_skb->dev = (void *) hu->hdev;
                sh_ldisc_cb(h4->rx_skb)->pkt_type = type;
                break;
#if 0
            case PROTO_SH_FM:    /* for FM */
                h4->rx_skb = bt_skb_alloc(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
                if (!h4->rx_skb)
                {
                    BT_ERR("Can't allocate mem for new packet");
                    h4->rx_state = H4_W4_PACKET_TYPE;
                    h4->rx_count = 0;
                    return -ENOMEM;
                }
                /* place holder 0x08 */
                /* skb_reserve(h4->rx_skb, 1); */
                sh_ldisc_cb(h4->rx_skb)->pkt_type = FM_CH8_PKT;
                break;
#endif
            case PROTO_SH_MAX:
            case PROTO_SH_GPS:
                break;
        }

    }
Exemplo n.º 18
0
int procGetUnit(unitPtr uPtr,char *recvBuf,int recvLen,char *result,char bitpos,char *pRecvPtr) {
	char string[256];
	char error[1000];
	char buffer[MAXBUF];
	char *errPtr=error;
/* 	short t; */
	float erg;
	int ergI;
	char formatI[20];
	float floatV=0;
	char *inPtr;
	char *tPtr;
	/* hier die Typen fuer die Umrechnung in <type> Tag */
	int8_t charV;
	uint8_t ucharV;
	int16_t shortV;
	int16_t tmpS;
	uint16_t ushortV;
	uint16_t tmpUS;
	int32_t intV;
	int32_t tmpI;
	uint32_t tmpUI;
	uint32_t uintV;
	

	bzero(errPtr,sizeof(error));

	/* wir behandeln die verschiedenen <type> Eintraege */

	if (strstr(uPtr->type,"cycletime")==uPtr->type) { /* Schaltzeit */ 
		if (getCycleTime(recvBuf,recvLen,result))
				return(1);
		else 
			return(-1);
	}
	else if (strstr(uPtr->type,"systime")==uPtr->type) { /* Systemzeit */ 
		if (getSysTime(recvBuf,recvLen,result))
				return(1);
		else 
			return(-1);
	}
	else if (strstr(uPtr->type,"errstate")==uPtr->type) { /* Errrocode + Systemzeit */ 
		if (getErrState(uPtr->ePtr,recvBuf,recvLen,result))
				return(1);
		else 
			return(-1);
	}
	else if (strstr(uPtr->type,"enum")==uPtr->type) { /*enum*/
		if(bytes2Enum(uPtr->ePtr,recvBuf,&tPtr,recvLen)) {
			strcpy(result,tPtr);
			return(1);
		}
		else {
			sprintf(result,"Kein passendes Enum gefunden"); 
			return(-1);
		}
	}

				
		




	/* hier kommen die ganzen numerischen Typen */


	if (strstr(uPtr->type,"char")==uPtr->type) { /* Umrechnung in Char 1Byte */
		memcpy(&charV,recvBuf,1);	
		floatV=charV; /* impliziete Typumnwandlung nach float fuer unsere Arithmetic */
		sprintf(formatI,"%%02X %%s");
	}
	else if (strstr(uPtr->type,"uchar")==uPtr->type) { /* Umrechnung in Unsigned Char 1Byte */
		memcpy(&ucharV,recvBuf,1);	
		floatV=ucharV; /* impliziete Typumnwandlung nach float fuer unsere Arithmetic */
		sprintf(formatI,"%%02X %%s");
	}
	else if (strstr(uPtr->type,"short")==uPtr->type) { /* Umrechnung in Short 2Byte */
		memcpy(&tmpS,recvBuf,2);	
		/* je nach CPU Typ wird hier die Wandlung vorgenommen */
		shortV=__le16_to_cpu(tmpS);
		floatV=shortV; /* impliziete Typumnwandlung nach float fuer unsere Arithmetic */
		sprintf(formatI,"%%04X %%s");
	}
	else if (strstr(uPtr->type,"ushort")==uPtr->type) { /* Umrechnung in Short 2Byte */
		memcpy(&tmpUS,recvBuf,2);	
		/* je nach CPU Typ wird hier die Wandlung vorgenommen */
		ushortV=__le16_to_cpu(tmpUS);
		floatV=ushortV; /* impliziete Typumnwandlung nach float fuer unsere Arithmetic */
		sprintf(formatI,"%%04X %%s");
	}
	else if (strstr(uPtr->type,"int")==uPtr->type) { /* Umrechnung in Int 4Byte */
		memcpy(&tmpI,recvBuf,4);	
		/* je nach CPU Typ wird hier die Wandlung vorgenommen */
		intV=__le32_to_cpu(tmpI);
		floatV=intV; /* impliziete Typumnwandlung nach float fuer unsere Arithmetic */
		sprintf(formatI,"%%08X %%s");
	}
	else if (strstr(uPtr->type,"uint")==uPtr->type) { /* Umrechnung in Unsigned Int 4Byte */
		memcpy(&tmpUI,recvBuf,4);	
		/* je nach CPU Typ wird hier die Wandlung vorgenommen */
		uintV=__le32_to_cpu(tmpUI);
		floatV=uintV; /* impliziete Typumnwandlung nach float fuer unsere Arithmetic */
		sprintf(formatI,"%%08X %%s");
	}
	else if (uPtr->type) {
		bzero(string,sizeof(string));
		snprintf(string, sizeof(string),"Unbekannter Typ %s in Unit %s",uPtr->type,uPtr->name);
		logIT(LOG_ERR,string);
		return(-1);
	}
		

	/* etwas logging */
	int n;
	char *ptr;
	char res;
	ptr=recvBuf;
	bzero(buffer,sizeof(buffer));
	for(n=0;n<=9;n++) {/* Bytes 0..9 sind von Interesse */ 
		bzero(string,sizeof(string));
		unsigned char byte=*ptr++ & 255;
		snprintf(string, sizeof(string),"B%d:%02X ",n,byte);
		strcat(buffer,string);
		if (n >= MAXBUF-3)
			break;
	}
	if (uPtr->gCalc && *uPtr->gCalc) { /* <calc im XML und get darin definiert */
		snprintf(string, sizeof(string),"Typ: %s (in float: %f)",uPtr->type,floatV);
		logIT(LOG_INFO,string);
		inPtr=uPtr->gCalc;
		snprintf(string, sizeof(string),"(FLOAT) Exp:%s [%s]",inPtr,buffer);
		logIT(LOG_INFO,string);
		erg=execExpression(&inPtr,recvBuf,floatV,errPtr);
		if (*errPtr) {
			snprintf(string, sizeof(string),"Exec %s: %s",uPtr->gCalc,error);
			logIT(LOG_ERR,string);
			strcpy(result,string);
			return(-1);
		}
		sprintf(result,"%f %s",erg,uPtr->entity);
	}
	else if (uPtr->gICalc && *uPtr->gICalc) { /* <icalc im XML und get darin definiert */
		inPtr=uPtr->gICalc;
		snprintf(string, sizeof(string),"(INT) Exp:%s [BP:%d] [%s]",inPtr,bitpos,buffer);
		logIT(LOG_INFO,string);
		ergI=execIExpression(&inPtr,recvBuf,bitpos,pRecvPtr,errPtr);
		if (*errPtr) {
			snprintf(string, sizeof(string),"Exec %s: %s",uPtr->gCalc,error);
			logIT(LOG_ERR,string);
			strcpy(result,string);
			return(-1);
		}
		snprintf(string, sizeof(string),"Erg: (Hex max. 4Byte) %08x",ergI);
		logIT(LOG_INFO,string);
		res=ergI;
		if( uPtr->ePtr && bytes2Enum(uPtr->ePtr,&res,&tPtr,recvLen)) {
			strcpy(result,tPtr);
			return(1);
		}
		else {
			sprintf(result,formatI,ergI,uPtr->entity);
			return(1);
		}


		/* hier noch das durchsuchen der enums ggf durchfuehren */
	}
	return(1);
}
Exemplo n.º 19
0
static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_ev_cmd_status *ev = (void *) skb->data;
	__u16 opcode;

	skb_pull(skb, sizeof(*ev));

	opcode = __le16_to_cpu(ev->opcode);

	switch (opcode) {
	case HCI_OP_INQUIRY:
		hci_cs_inquiry(hdev, ev->status);
		break;

	case HCI_OP_CREATE_CONN:
		hci_cs_create_conn(hdev, ev->status);
		break;

	case HCI_OP_ADD_SCO:
		hci_cs_add_sco(hdev, ev->status);
		break;

	case HCI_OP_AUTH_REQUESTED:
		hci_cs_auth_requested(hdev, ev->status);
		break;

	case HCI_OP_SET_CONN_ENCRYPT:
		hci_cs_set_conn_encrypt(hdev, ev->status);
		break;

	case HCI_OP_REMOTE_NAME_REQ:
		hci_cs_remote_name_req(hdev, ev->status);
		break;

	case HCI_OP_READ_REMOTE_FEATURES:
		hci_cs_read_remote_features(hdev, ev->status);
		break;

	case HCI_OP_READ_REMOTE_EXT_FEATURES:
		hci_cs_read_remote_ext_features(hdev, ev->status);
		break;

	case HCI_OP_SETUP_SYNC_CONN:
		hci_cs_setup_sync_conn(hdev, ev->status);
		break;

	case HCI_OP_SNIFF_MODE:
		hci_cs_sniff_mode(hdev, ev->status);
		break;

	case HCI_OP_EXIT_SNIFF_MODE:
		hci_cs_exit_sniff_mode(hdev, ev->status);
		break;

	default:
		BT_DBG("%s opcode 0x%x", hdev->name, opcode);
		break;
	}

	if (ev->ncmd) {
		atomic_set(&hdev->cmd_cnt, 1);
		if (!skb_queue_empty(&hdev->cmd_q))
			tasklet_schedule(&hdev->cmd_task);
	}
}
Exemplo n.º 20
0
static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype)
{
	unsigned int fpos = 0;
	int status;
	struct ext2fs_node *diro = (struct ext2fs_node *) dir;

#ifdef DEBUG
	if (name != NULL)
		printf ("Iterate dir %s\n", name);
#endif /* of DEBUG */
	if (!diro->inode_read) {
		status = ext2fs_read_inode (diro->data, diro->ino,
					    &diro->inode);
		if (status == 0) {
			return (0);
		}
	}
	/* Search the file.  */
	while (fpos < __le32_to_cpu (diro->inode.size)) {
		struct ext2_dirent dirent;

		status = ext2fs_read_file (diro, fpos,
					   sizeof (struct ext2_dirent),
					   (char *) &dirent);
		if (status < 1) {
			return (0);
		}
		if (dirent.namelen != 0) {
			char filename[dirent.namelen + 1];
			ext2fs_node_t fdiro;
			int type = FILETYPE_UNKNOWN;

			status = ext2fs_read_file (diro,
						   fpos + sizeof (struct ext2_dirent),
						   dirent.namelen, filename);
			if (status < 1) {
				return (0);
			}
			fdiro = malloc (sizeof (struct ext2fs_node));
			if (!fdiro) {
				return (0);
			}

			fdiro->data = diro->data;
			fdiro->ino = __le32_to_cpu (dirent.inode);

			filename[dirent.namelen] = '\0';

			if (dirent.filetype != FILETYPE_UNKNOWN) {
				fdiro->inode_read = 0;

				if (dirent.filetype == FILETYPE_DIRECTORY) {
					type = FILETYPE_DIRECTORY;
				} else if (dirent.filetype ==
					   FILETYPE_SYMLINK) {
					type = FILETYPE_SYMLINK;
				} else if (dirent.filetype == FILETYPE_REG) {
					type = FILETYPE_REG;
				}
			} else {
				/* The filetype can not be read from the dirent, get it from inode */

				status = ext2fs_read_inode (diro->data,
							    __le32_to_cpu(dirent.inode),
							    &fdiro->inode);
				if (status == 0) {
					free (fdiro);
					return (0);
				}
				fdiro->inode_read = 1;

				if ((__le16_to_cpu (fdiro->inode.mode) &
				     FILETYPE_INO_MASK) ==
				    FILETYPE_INO_DIRECTORY) {
					type = FILETYPE_DIRECTORY;
				} else if ((__le16_to_cpu (fdiro->inode.mode)
					    & FILETYPE_INO_MASK) ==
					   FILETYPE_INO_SYMLINK) {
					type = FILETYPE_SYMLINK;
				} else if ((__le16_to_cpu (fdiro->inode.mode)
					    & FILETYPE_INO_MASK) ==
					   FILETYPE_INO_REG) {
					type = FILETYPE_REG;
				}
			}
#ifdef DEBUG
			printf ("iterate >%s<\n", filename);
#endif /* of DEBUG */
			if ((name != NULL) && (fnode != NULL)
			    && (ftype != NULL)) {
				if (strcmp (filename, name) == 0) {
					*ftype = type;
					*fnode = fdiro;
					return (1);
				}
			} else {
				if (fdiro->inode_read == 0) {
					status = ext2fs_read_inode (diro->data,
							    __le32_to_cpu (dirent.inode),
							    &fdiro->inode);
					if (status == 0) {
						free (fdiro);
						return (0);
					}
					fdiro->inode_read = 1;
				}
				switch (type) {
				case FILETYPE_DIRECTORY:
					printf ("<DIR> ");
					break;
				case FILETYPE_SYMLINK:
					printf ("<SYM> ");
					break;
				case FILETYPE_REG:
					printf ("      ");
					break;
				default:
					printf ("< ? > ");
					break;
				}
				printf ("%10d %s\n",
					__le32_to_cpu (fdiro->inode.size),
					filename);
			}
			free (fdiro);
		}
		fpos += __le16_to_cpu (dirent.direntlen);
	}
	return (0);
}
Exemplo n.º 21
0
static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count)
{
	register const char *ptr;
	hci_event_hdr *eh;
	hci_acl_hdr   *ah;
	hci_sco_hdr   *sh;
	register int len, type, dlen;

	DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count);

	n_hci->hdev.stat.byte_rx += count;

	ptr = data;
	while (count) {
		if (n_hci->rx_count) {
			len = MIN(n_hci->rx_count, count);
			memcpy(skb_put(n_hci->rx_skb, len), ptr, len);
			n_hci->rx_count -= len; count -= len; ptr += len;

			if (n_hci->rx_count)
				continue;

			switch (n_hci->rx_state) {
				case WAIT_DATA:
					DBG("Complete data");

					DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);

					hci_recv_frame(n_hci->rx_skb);

					n_hci->rx_state = WAIT_PACKET_TYPE;
					n_hci->rx_skb = NULL;
					continue;

				case WAIT_EVENT_HDR:
					eh = (hci_event_hdr *) n_hci->rx_skb->data;

					DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);

					n_hci_check_data_len(n_hci, eh->plen);
					continue;

				case WAIT_ACL_HDR:
					ah = (hci_acl_hdr *) n_hci->rx_skb->data;
					dlen = __le16_to_cpu(ah->dlen);

					DBG("ACL header: dlen %d", dlen);

					n_hci_check_data_len(n_hci, dlen);
					continue;

				case WAIT_SCO_HDR:
					sh = (hci_sco_hdr *) n_hci->rx_skb->data;

					DBG("SCO header: dlen %d", sh->dlen);

					n_hci_check_data_len(n_hci, sh->dlen);
					continue;
			};
		}

		/* WAIT_PACKET_TYPE */
		switch (*ptr) {
			case HCI_EVENT_PKT:
				DBG("Event packet");
				n_hci->rx_state = WAIT_EVENT_HDR;
				n_hci->rx_count = HCI_EVENT_HDR_SIZE;
				type = HCI_EVENT_PKT;
				break;

			case HCI_ACLDATA_PKT:
				DBG("ACL packet");
				n_hci->rx_state = WAIT_ACL_HDR;
				n_hci->rx_count = HCI_ACL_HDR_SIZE;
				type = HCI_ACLDATA_PKT;
				break;

			case HCI_SCODATA_PKT:
				DBG("SCO packet");
				n_hci->rx_state = WAIT_SCO_HDR;
				n_hci->rx_count = HCI_SCO_HDR_SIZE;
				type = HCI_SCODATA_PKT;
				break;

			default:
				ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
				n_hci->hdev.stat.err_rx++;
				ptr++; count--;
				continue;
		};
		ptr++; count--;

		/* Allocate packet */
		if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
			ERR("Can't allocate mem for new packet");

			n_hci->rx_state = WAIT_PACKET_TYPE;
			n_hci->rx_count = 0;
			return;
		}
		n_hci->rx_skb->dev = (void *) &n_hci->hdev;
		n_hci->rx_skb->pkt_type = type;
	}
}
Exemplo n.º 22
0
/* Recv data */
static int h4_recv(struct hci_uart *hu, void *data, int count)
{
	struct h4_struct *h4 = hu->priv;
	register char *ptr;
	struct hci_event_hdr *eh;
	struct hci_acl_hdr   *ah;
	struct hci_sco_hdr   *sh;
	register int len, type, dlen;

	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
			hu, count, h4->rx_state, h4->rx_count);

	ptr = data;
	while (count) {
		if (h4->rx_count) {
			len = min_t(unsigned int, h4->rx_count, count);
			memcpy(skb_put(h4->rx_skb, len), ptr, len);
			h4->rx_count -= len; count -= len; ptr += len;

			if (h4->rx_count)
				continue;

			switch (h4->rx_state) {
			case H4_W4_DATA:
				BT_DBG("Complete data");

				hci_recv_frame(h4->rx_skb);

				h4->rx_state = H4_W4_PACKET_TYPE;
				h4->rx_skb = NULL;
				continue;

			case H4_W4_EVENT_HDR:
				eh = hci_event_hdr(h4->rx_skb);

				BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);

				h4_check_data_len(h4, eh->plen);
				continue;

			case H4_W4_ACL_HDR:
				ah = hci_acl_hdr(h4->rx_skb);
				dlen = __le16_to_cpu(ah->dlen);

				BT_DBG("ACL header: dlen %d", dlen);

				h4_check_data_len(h4, dlen);
				continue;

			case H4_W4_SCO_HDR:
				sh = hci_sco_hdr(h4->rx_skb);

				BT_DBG("SCO header: dlen %d", sh->dlen);

				h4_check_data_len(h4, sh->dlen);
				continue;
			}
		}

		/* H4_W4_PACKET_TYPE */
		switch (*ptr) {
		case HCI_EVENT_PKT:
			BT_DBG("Event packet");
			h4->rx_state = H4_W4_EVENT_HDR;
			h4->rx_count = HCI_EVENT_HDR_SIZE;
			type = HCI_EVENT_PKT;
			break;

		case HCI_ACLDATA_PKT:
			BT_DBG("ACL packet");
			h4->rx_state = H4_W4_ACL_HDR;
			h4->rx_count = HCI_ACL_HDR_SIZE;
			type = HCI_ACLDATA_PKT;
			break;

		case HCI_SCODATA_PKT:
			BT_DBG("SCO packet");
			h4->rx_state = H4_W4_SCO_HDR;
			h4->rx_count = HCI_SCO_HDR_SIZE;
			type = HCI_SCODATA_PKT;
			break;

		default:
			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
			hu->hdev->stat.err_rx++;
			ptr++; count--;
			continue;
		};

		ptr++; count--;

		/* Allocate packet */
		h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
		if (!h4->rx_skb) {
			BT_ERR("Can't allocate mem for new packet");
			h4->rx_state = H4_W4_PACKET_TYPE;
			h4->rx_count = 0;
			return -ENOMEM;
		}

		h4->rx_skb->dev = (void *) hu->hdev;
		bt_cb(h4->rx_skb)->pkt_type = type;
	}
Exemplo n.º 23
0
/* This is almost the only place where usb needs to know whether we're
 * driving an isochronous stream or a bulk one.
 */
static int iso_autoconfig ()
{
	struct stat	statb;

	/* ISO endpoints "must not be part of a default interface setting".
	 * Never do it like this in "real" code!  This uses the default
	 * setting (alt 0) because it's the only one pxa supports.
	 *
	 * This code doesn't adjust the sample rate based on feedback.
	 */
	device_desc.idProduct = __constant_cpu_to_le16(productid);

	/* NetChip 2280 PCI device or dummy_hcd, high/full speed */
	if (stat (DEVNAME = "net2280", &statb) == 0 ||
			stat (DEVNAME = "dummy_udc", &statb) == 0) {
		unsigned	bInterval, wMaxPacketSize;

		HIGHSPEED = 1;
		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0100);

		/* this code won't use two or four uframe periods */
		if (bufsize > 1024) {
			interval = 0;
			bInterval = 1;
			/* "modprobe net2280 fifo_mode=1" may be needed */
			if (bufsize > (2 * 1024)) {
				wMaxPacketSize = min ((bufsize + 2)/3, 1024);
				bufsize = min (3 * wMaxPacketSize, bufsize);
				wMaxPacketSize |= 2 << 11;
			} else {
				wMaxPacketSize = min ((bufsize + 1)/2, 1024);
				wMaxPacketSize |= 1 << 11;
			}
		} else {
			bInterval = interval + 4;
			wMaxPacketSize = bufsize;
		}

		fs_source_desc.bEndpointAddress
			= hs_source_desc.bEndpointAddress
			= USB_DIR_IN | 7;
		fs_source_desc.bmAttributes
			= hs_source_desc.bmAttributes
			= USB_ENDPOINT_XFER_ISOC;
		fs_source_desc.wMaxPacketSize = min (bufsize, 1023);
		hs_source_desc.wMaxPacketSize = wMaxPacketSize;
		fs_source_desc.bInterval = interval + 1;
		hs_source_desc.bInterval = bInterval;
		EP_IN_NAME = "ep-a";

		fs_sink_desc.bEndpointAddress
			= hs_sink_desc.bEndpointAddress
			= USB_DIR_OUT | 3;
		fs_sink_desc.bmAttributes
			= hs_sink_desc.bmAttributes
			= USB_ENDPOINT_XFER_ISOC;
		fs_sink_desc.wMaxPacketSize = min (bufsize, 1023);
		hs_sink_desc.wMaxPacketSize = wMaxPacketSize;
		fs_sink_desc.bInterval = interval + 1;
		hs_sink_desc.bInterval = bInterval;
		EP_OUT_NAME = "ep-b";

		source_sink_intf.bNumEndpoints = 3;
		fs_status_desc.bEndpointAddress
			= hs_status_desc.bEndpointAddress
			= USB_DIR_IN | 11;
		EP_STATUS_NAME = "ep-f";

	/* Intel PXA 2xx processor, full speed only */
	} else if (stat (DEVNAME = "pxa2xx_udc", &statb) == 0) {
		HIGHSPEED = 0;
		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0101),

		bufsize = min (bufsize, 256);

		fs_source_desc.bEndpointAddress = USB_DIR_IN | 3;
		fs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC;
		fs_source_desc.wMaxPacketSize = bufsize;
		fs_source_desc.bInterval = interval;
		EP_IN_NAME = "ep3in-iso";

		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 4;
		fs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC;
		fs_sink_desc.wMaxPacketSize = bufsize;
		fs_sink_desc.bInterval = interval;
		EP_OUT_NAME = "ep4out-iso";

		/* using bulk for this since the pxa interrupt endpoints
		 * always use the no-toggle scheme (discouraged).
		 */
		source_sink_intf.bNumEndpoints = 3;
		fs_status_desc.bEndpointAddress = USB_DIR_IN | 11;
		EP_STATUS_NAME = "ep11in-bulk";

	/* OMAP 1610 and newer devices, full speed only, fifo mode 3 */
	} else if (stat (DEVNAME = "omap_udc", &statb) == 0) {
		HIGHSPEED = 0;
		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0102),

		fs_source_desc.bEndpointAddress = USB_DIR_IN | 7;
		fs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC;
		fs_source_desc.wMaxPacketSize = min (bufsize, 256);
		fs_source_desc.bInterval = interval;
		EP_IN_NAME = "ep7in-iso";

		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 8;
		fs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC;
		fs_sink_desc.wMaxPacketSize = min (bufsize, 256);
		fs_sink_desc.bInterval = interval;
		EP_OUT_NAME = "ep8out-iso";

		source_sink_intf.bNumEndpoints = 3;
		fs_status_desc.bEndpointAddress = USB_DIR_IN | 9;
		EP_STATUS_NAME = "ep9in-int";

	/* Something based on Mentor USB Highspeed Dual-Role Controller;
	 * assumes a core that doesn't include high bandwidth support.
	 */
	} else if (stat (DEVNAME = "musb_hdrc", &statb) == 0) {
		unsigned	bInterval, wMaxPacketSize;

		HIGHSPEED = 1;
		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0103);

		bInterval = interval + 4;
		wMaxPacketSize = bufsize;

		fs_source_desc.bEndpointAddress
			= hs_source_desc.bEndpointAddress
			= USB_DIR_IN | 1;
		fs_source_desc.bmAttributes
			= hs_source_desc.bmAttributes
			= USB_ENDPOINT_XFER_ISOC;
		fs_source_desc.wMaxPacketSize = min (bufsize, 1023);
		hs_source_desc.wMaxPacketSize = wMaxPacketSize;
		fs_source_desc.bInterval = interval + 1;
		hs_source_desc.bInterval = bInterval;
		EP_IN_NAME = "ep1in";

		fs_sink_desc.bEndpointAddress
			= hs_sink_desc.bEndpointAddress
			= USB_DIR_OUT | 1;
		fs_sink_desc.bmAttributes
			= hs_sink_desc.bmAttributes
			= USB_ENDPOINT_XFER_ISOC;
		fs_sink_desc.wMaxPacketSize = min (bufsize, 1023);
		hs_sink_desc.wMaxPacketSize = wMaxPacketSize;
		fs_sink_desc.bInterval = interval + 1;
		hs_sink_desc.bInterval = bInterval;
		EP_OUT_NAME = "ep1out";

		source_sink_intf.bNumEndpoints = 3;
		fs_status_desc.bEndpointAddress
			= hs_status_desc.bEndpointAddress
			= USB_DIR_IN | 11;
		EP_STATUS_NAME = "ep3";

	/* Atmel AT91 processors, full speed only */
	} else if (stat (DEVNAME = "at91_udc", &statb) == 0) {
		HIGHSPEED = 0;
		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0104),

		fs_source_desc.bEndpointAddress = USB_DIR_IN | 4;
		fs_source_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC;
		fs_source_desc.wMaxPacketSize = min (bufsize, 256);
		fs_source_desc.bInterval = interval;
		EP_IN_NAME = "ep4";

		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2;
		fs_sink_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC;
		fs_sink_desc.wMaxPacketSize = min (bufsize, 256);
		fs_sink_desc.bInterval = interval;
		EP_OUT_NAME = "ep5";

		source_sink_intf.bNumEndpoints = 3;
		fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
		EP_STATUS_NAME = "ep3-int";

	/* Atmel AT32AP700x processors, high/full speed */
	} else if (stat (DEVNAME = "atmel_usba_udc", &statb) == 0){
		HIGHSPEED = 1;

		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0105);

		fs_source_desc.bEndpointAddress
			= hs_source_desc.bEndpointAddress
			= USB_DIR_IN | 5;
		fs_source_desc.bmAttributes
			= hs_source_desc.bmAttributes
			= USB_ENDPOINT_XFER_ISOC;
		fs_source_desc.wMaxPacketSize
			= hs_source_desc.wMaxPacketSize
			= __cpu_to_le16(min (bufsize, 1024));
		fs_source_desc.bInterval
			= hs_source_desc.bInterval
			= interval;
		EP_IN_NAME = "ep5in-iso";

		fs_sink_desc.bEndpointAddress
			= hs_sink_desc.bEndpointAddress
			= USB_DIR_OUT | 6;
		fs_sink_desc.bmAttributes
			= hs_sink_desc.bmAttributes
			= USB_ENDPOINT_XFER_ISOC;
		fs_sink_desc.wMaxPacketSize
			= hs_sink_desc.wMaxPacketSize
			= __cpu_to_le16(min (bufsize, 1024));
		fs_sink_desc.bInterval
			= hs_sink_desc.bInterval
			= interval;
		EP_OUT_NAME = "ep6out-iso";

		source_sink_intf.bNumEndpoints = 3;
		fs_status_desc.bEndpointAddress
			= hs_status_desc.bEndpointAddress
			= USB_DIR_IN | 3;
		EP_STATUS_NAME = "ep3in-int";

	} else {
		DEVNAME = 0;
		return -ENODEV;
	}
	if (verbose) {
		fprintf (stderr, "iso fs wMaxPacket %04x bInterval %02x\n",
			__le16_to_cpu(fs_sink_desc.wMaxPacketSize),
			fs_sink_desc.bInterval);
		if (HIGHSPEED)
			fprintf (stderr,
				"iso hs wMaxPacket %04x bInterval %02x\n",
				__le16_to_cpu(hs_sink_desc.wMaxPacketSize),
				hs_sink_desc.bInterval);
	}
	return 0;
}
Exemplo n.º 24
0
int main(int argc, char **argv)
{
    int busnum, devnum, numports;
    enum {DO_POWER, DO_STATUS, DO_BIND} action;
    char fname1[40], fname2[40];
    int rc;
    int portnum;
    struct usb_device_descriptor dev_descr;
    struct usb_hub_descriptor hub_descr;
    struct usbdevfs_ctrltransfer ctrl;
    struct usbdevfs_ioctl usb_ioctl;
    int bus_endian;

    if (argc < 3)
        usage();
    if (sscanf(argv[1], "%d:%d", &busnum, &devnum) != 2 ||
            busnum <= 0 || busnum > 255 ||
            devnum <= 0 || devnum > 255)
        usage();

    if (strcmp(argv[2], "power") == 0) {
        action = DO_POWER;
        if ((argc - 3) % 2 != 0)
            usage();
    } else if (strcmp(argv[2], "status") == 0) {
        action = DO_STATUS;
        if (argc != 3)
            usage();
    } else if (strcmp(argv[2], "bind") == 0) {
        action = DO_BIND;
        if (argc != 3)
            usage();
    } else {
        usage();
    }

    sprintf(fname1, "/dev/bus/usb/%03d/%03d", busnum, devnum);
    sprintf(fname2, "/proc/bus/usb/%03d/%03d", busnum, devnum);

    bus_endian = 1;
    fd = open(fname1, O_RDWR);
    if (fd < 0) {
        int err1 = errno;

        bus_endian = 0;
        fd = open(fname2, O_RDWR);
        if (fd < 0) {
            fprintf(stderr, "Unable to open device file %s: %s\n",
                    fname1, strerror(err1));
            fprintf(stderr, "Unable to open device file %s: %s\n",
                    fname2, strerror(errno));
            return 1;
        }
    }

    rc = read(fd, &dev_descr, USB_DT_DEVICE_SIZE);
    if (rc != USB_DT_DEVICE_SIZE) {
        perror("Error reading device descriptor");
        return 1;
    }
    if (dev_descr.bDeviceClass != USB_CLASS_HUB) {
        fprintf(stderr, "Device %d:%d is not a hub\n",
                busnum, devnum);
        return 1;
    }
    if (bus_endian) {
        dev_descr.bcdUSB = __le16_to_cpu(dev_descr.bcdUSB);
    }
    usb_level = dev_descr.bcdUSB >> 8;

    ctrl.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE;
    ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
    ctrl.wValue = USB_DT_HUB << 8;
    ctrl.wIndex = 0;
    ctrl.wLength = USB_DT_HUB_SIZE;
    ctrl.timeout = USB_HUB_TIMEOUT;
    ctrl.data = &hub_descr;
    rc = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
    if (rc == -1) {
        perror("Error in ioctl (read hub descriptor)");
        return 1;
    }
    numports = hub_descr.bNbrPorts;

    if (action == DO_STATUS) {
        for (portnum = 1; portnum <= numports; ++portnum)
            port_status(portnum);
        return 0;
    }

    if (action == DO_BIND) {
        usb_ioctl.ifno = 0;
        usb_ioctl.ioctl_code = USBDEVFS_CONNECT;
        usb_ioctl.data = NULL;
        rc = ioctl(fd, USBDEVFS_IOCTL, &usb_ioctl);
        if (rc == -1) {
            perror("Error in ioctl (USBDEVFS_CONNECT)");
            return 1;
        }
        printf("Bind-driver request sent to the kernel\n");
        return 0;
    }

    if (action == DO_POWER) {
        int i;

        usb_ioctl.ifno = 0;
        usb_ioctl.ioctl_code = USBDEVFS_DISCONNECT;
        usb_ioctl.data = NULL;
        rc = ioctl(fd, USBDEVFS_IOCTL, &usb_ioctl);
        if (rc == -1 && errno != ENODATA) {
            perror("Error in ioctl (USBDEVFS_DISCONNECT)");
            return 1;
        }

        for (i = 3; i < argc; i += 2) {
            portnum = atoi(argv[i]);
            if (portnum < 1 || portnum > numports) {
                fprintf(stderr, "Invalid port number: %d\n",
                        portnum);
                continue;
            }

            if (strcmp(argv[i+1], "on") == 0)
                ctrl.bRequest = USB_REQ_SET_FEATURE;
            else if (strcmp(argv[i+1], "off") == 0)
                ctrl.bRequest = USB_REQ_CLEAR_FEATURE;
            else {
                fprintf(stderr, "Invalid port power level: %s\n)",
                        argv[i+1]);
                continue;
            }

            ctrl.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS |
                    USB_RECIP_OTHER;
            ctrl.wValue = USB_PORT_FEAT_POWER;
            ctrl.wIndex = portnum;
            ctrl.wLength = 0;
            ctrl.timeout = USB_HUB_TIMEOUT;
            ctrl.data = NULL;
            rc = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
            if (rc == -1) {
                fprintf(stderr, "Error in ioctl "
                    "(set/clear port %d feature): %s\n",
                    portnum, strerror(errno));
                continue;
            }

            port_status(portnum);
        }
    }
    return 0;
}
Exemplo n.º 25
0
/* Command Complete OGF INFO_PARAM  */
static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{
	struct hci_rp_read_loc_features *lf;
	struct hci_rp_read_buffer_size *bs;
	struct hci_rp_read_bd_addr *ba;

	BT_DBG("%s ocf 0x%x", hdev->name, ocf);

	switch (ocf) {
	case OCF_READ_LOCAL_FEATURES:
		lf = (struct hci_rp_read_loc_features *) skb->data;

		if (lf->status) {
			BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
			break;
		}

		memcpy(hdev->features, lf->features, sizeof(hdev->features));

		/* Adjust default settings according to features 
		 * supported by device. */
		if (hdev->features[0] & LMP_3SLOT)
			hdev->pkt_type |= (HCI_DM3 | HCI_DH3);

		if (hdev->features[0] & LMP_5SLOT)
			hdev->pkt_type |= (HCI_DM5 | HCI_DH5);

		if (hdev->features[1] & LMP_HV2)
			hdev->pkt_type |= (HCI_HV2);

		if (hdev->features[1] & LMP_HV3)
			hdev->pkt_type |= (HCI_HV3);

		BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);

		break;

	case OCF_READ_BUFFER_SIZE:
		bs = (struct hci_rp_read_buffer_size *) skb->data;

		if (bs->status) {
			BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
			hci_req_complete(hdev, bs->status);
			break;
		}

		hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
		hdev->sco_mtu  = bs->sco_mtu ? bs->sco_mtu : 64;
		hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
		hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);

		BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
			hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
		break;

	case OCF_READ_BD_ADDR:
		ba = (struct hci_rp_read_bd_addr *) skb->data;

		if (!ba->status) {
			bacpy(&hdev->bdaddr, &ba->bdaddr);
		} else {
			BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
		}

		hci_req_complete(hdev, ba->status);
		break;

	default:
		BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
		break;
	}
}
Exemplo n.º 26
0
/**
 * st_int_recv - ST's internal receive function.
 *	Decodes received RAW data and forwards to corresponding
 *	client drivers (Bluetooth,FM,GPS..etc).
 *	This can receive various types of packets,
 *	HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets
 *	CH-8 packets from FM, CH-9 packets from GPS cores.
 */
void st_int_recv(void *disc_data,
	const unsigned char *data, long count)
{
	char *ptr;
	struct st_proto_s *proto;
	unsigned short payload_len = 0;
	int len = 0;
	unsigned char type = 0;
	unsigned char *plen;
	struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
	unsigned long flags;

	ptr = (char *)data;
	/* tty_receive sent null ? */
	if (unlikely(ptr == NULL) || (st_gdata == NULL)) {
		pr_err(" received null from TTY ");
		return;
	}

	pr_debug("count %ld rx_state %ld"
		   "rx_count %ld", count, st_gdata->rx_state,
		   st_gdata->rx_count);

	spin_lock_irqsave(&st_gdata->lock, flags);
	/* Decode received bytes here */
	while (count) {
		if (st_gdata->rx_count) {
			len = min_t(unsigned int, st_gdata->rx_count, count);
			memcpy(skb_put(st_gdata->rx_skb, len), ptr, len);
			st_gdata->rx_count -= len;
			count -= len;
			ptr += len;

			if (st_gdata->rx_count)
				continue;

			/* Check ST RX state machine , where are we? */
			switch (st_gdata->rx_state) {
			/* Waiting for complete packet ? */
			case ST_W4_DATA:
				pr_debug("Complete pkt received");
				/* Ask ST CORE to forward
				 * the packet to protocol driver */
				st_send_frame(st_gdata->rx_chnl, st_gdata);

				st_gdata->rx_state = ST_W4_PACKET_TYPE;
				st_gdata->rx_skb = NULL;
				continue;
			/* parse the header to know details */
			case ST_W4_HEADER:
				proto = st_gdata->list[st_gdata->rx_chnl];
				plen =
				&st_gdata->rx_skb->data
				[proto->offset_len_in_hdr];
				pr_debug("plen pointing to %x\n", *plen);
				if (proto->len_size == 1)/* 1 byte len field */
					payload_len = *(unsigned char *)plen;
				else if (proto->len_size == 2)
					payload_len =
					__le16_to_cpu(*(unsigned short *)plen);
				else
					pr_info("%s: invalid length "
					"for id %d\n",
					__func__, proto->chnl_id);
				st_check_data_len(st_gdata, proto->chnl_id,
						payload_len);
				pr_debug("off %d, pay len %d\n",
					proto->offset_len_in_hdr, payload_len);
				continue;
			}	/* end of switch rx_state */
		}

		/* end of if rx_count */
		/* Check first byte of packet and identify module
		 * owner (BT/FM/GPS) */
		switch (*ptr) {
		case LL_SLEEP_IND:
		case LL_SLEEP_ACK:
		case LL_WAKE_UP_IND:
			pr_debug("PM packet");
			/* this takes appropriate action based on
			 * sleep state received --
			 */
			st_ll_sleep_state(st_gdata, *ptr);
			/* if WAKEUP_IND collides copy from waitq to txq
			 * and assume chip awake
			 */
			spin_unlock_irqrestore(&st_gdata->lock, flags);
			if (st_ll_getstate(st_gdata) == ST_LL_AWAKE)
				st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK);
			spin_lock_irqsave(&st_gdata->lock, flags);

			ptr++;
			count--;
			continue;
		case LL_WAKE_UP_ACK:
			pr_debug("PM packet");

			spin_unlock_irqrestore(&st_gdata->lock, flags);
			/* wake up ack received */
			st_wakeup_ack(st_gdata, *ptr);
			spin_lock_irqsave(&st_gdata->lock, flags);

			ptr++;
			count--;
			continue;
			/* Unknow packet? */
		default:
			type = *ptr;

			/* Default case means non-HCILL packets,
			 * possibilities are packets for:
			 * (a) valid protocol -  Supported Protocols within
			 *     the ST_MAX_CHANNELS.
			 * (b) registered protocol - Checked by
			 *     "st_gdata->list[type] == NULL)" are supported
			 *     protocols only.
			 *  Rules out any invalid protocol and
			 *  unregistered protocols with channel ID < 16.
			 */

			if ((type >= ST_MAX_CHANNELS) ||
					(st_gdata->list[type] == NULL)) {
				pr_err("chip/interface misbehavior: "
						"dropping frame starting "
						"with 0x%02x\n", type);
				goto done;
			}

			st_gdata->rx_skb = alloc_skb(
					st_gdata->list[type]->max_frame_size,
					GFP_ATOMIC);
			if (st_gdata->rx_skb == NULL) {
				pr_err("out of memory: dropping\n");
				goto done;
			}

			skb_reserve(st_gdata->rx_skb,
					st_gdata->list[type]->reserve);
			/* next 2 required for BT only */
			st_gdata->rx_skb->cb[0] = type; /*pkt_type*/
			st_gdata->rx_skb->cb[1] = 0; /*incoming*/
			st_gdata->rx_chnl = *ptr;
			st_gdata->rx_state = ST_W4_HEADER;
			st_gdata->rx_count = st_gdata->list[type]->hdr_len;
			pr_debug("rx_count %ld\n", st_gdata->rx_count);
		};
		ptr++;
		count--;
	}
Exemplo n.º 27
0
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data;
	struct hci_ev_cmd_complete *ec;
	struct hci_ev_cmd_status *cs;
	u16 opcode, ocf, ogf;

	skb_pull(skb, HCI_EVENT_HDR_SIZE);

	BT_DBG("%s evt 0x%x", hdev->name, hdr->evt);

	switch (hdr->evt) {
	case HCI_EV_NUM_COMP_PKTS:
		hci_num_comp_pkts_evt(hdev, skb);
		break;

	case HCI_EV_INQUIRY_COMPLETE:
		hci_inquiry_complete_evt(hdev, skb);
		break;

	case HCI_EV_INQUIRY_RESULT:
		hci_inquiry_result_evt(hdev, skb);
		break;

	case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
		hci_inquiry_result_with_rssi_evt(hdev, skb);
		break;

	case HCI_EV_CONN_REQUEST:
		hci_conn_request_evt(hdev, skb);
		break;

	case HCI_EV_CONN_COMPLETE:
		hci_conn_complete_evt(hdev, skb);
		break;

	case HCI_EV_DISCONN_COMPLETE:
		hci_disconn_complete_evt(hdev, skb);
		break;

	case HCI_EV_ROLE_CHANGE:
		hci_role_change_evt(hdev, skb);
		break;

	case HCI_EV_AUTH_COMPLETE:
		hci_auth_complete_evt(hdev, skb);
		break;

	case HCI_EV_ENCRYPT_CHANGE:
		hci_encrypt_change_evt(hdev, skb);
		break;

	case HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE:
		hci_change_conn_link_key_complete_evt(hdev, skb);
		break;

	case HCI_EV_PIN_CODE_REQ:
		hci_pin_code_request_evt(hdev, skb);
		break;

	case HCI_EV_LINK_KEY_REQ:
		hci_link_key_request_evt(hdev, skb);
		break;

	case HCI_EV_LINK_KEY_NOTIFY:
		hci_link_key_notify_evt(hdev, skb);
		break;

	case HCI_EV_CLOCK_OFFSET:
		hci_clock_offset_evt(hdev, skb);
		break;

	case HCI_EV_CMD_STATUS:
		cs = (struct hci_ev_cmd_status *) skb->data;
		skb_pull(skb, sizeof(cs));

		opcode = __le16_to_cpu(cs->opcode);
		ogf = hci_opcode_ogf(opcode);
		ocf = hci_opcode_ocf(opcode);

		switch (ogf) {
		case OGF_INFO_PARAM:
			hci_cs_info_param(hdev, ocf, cs->status);
			break;

		case OGF_HOST_CTL:
			hci_cs_host_ctl(hdev, ocf, cs->status);
			break;

		case OGF_LINK_CTL:
			hci_cs_link_ctl(hdev, ocf, cs->status);
			break;

		case OGF_LINK_POLICY:
			hci_cs_link_policy(hdev, ocf, cs->status);
			break;

		default:
			BT_DBG("%s Command Status OGF %x", hdev->name, ogf);
			break;
		}

		if (cs->ncmd) {
			atomic_set(&hdev->cmd_cnt, 1);
			if (!skb_queue_empty(&hdev->cmd_q))
				hci_sched_cmd(hdev);
		}
		break;

	case HCI_EV_CMD_COMPLETE:
		ec = (struct hci_ev_cmd_complete *) skb->data;
		skb_pull(skb, sizeof(*ec));

		opcode = __le16_to_cpu(ec->opcode);
		ogf = hci_opcode_ogf(opcode);
		ocf = hci_opcode_ocf(opcode);

		switch (ogf) {
		case OGF_INFO_PARAM:
			hci_cc_info_param(hdev, ocf, skb);
			break;

		case OGF_HOST_CTL:
			hci_cc_host_ctl(hdev, ocf, skb);
			break;

		case OGF_LINK_CTL:
			hci_cc_link_ctl(hdev, ocf, skb);
			break;

		case OGF_LINK_POLICY:
			hci_cc_link_policy(hdev, ocf, skb);
			break;

		default:
			BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
			break;
		}

		if (ec->ncmd) {
			atomic_set(&hdev->cmd_cnt, 1);
			if (!skb_queue_empty(&hdev->cmd_q))
				hci_sched_cmd(hdev);
		}
		break;
	}

	kfree_skb(skb);
	hdev->stat.evt_rx++;
}
Exemplo n.º 28
0
static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                            struct scm_cookie *scm)
{
	struct sock *sk = sock->sk;
	struct hci_dev *hdev;
	struct sk_buff *skb;
	int err;

	BT_DBG("sock %p sk %p", sock, sk);

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
		return -EINVAL;

	if (len < 4)
		return -EINVAL;
	
	lock_sock(sk);

	if (!(hdev = hci_pi(sk)->hdev)) {
		err = -EBADFD;
		goto done;
	}

	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
		goto done;

	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
		err = -EFAULT;
		goto drop;
	}

	skb->pkt_type = *((unsigned char *) skb->data);
	skb_pull(skb, 1);
	skb->dev = (void *) hdev;

	if (skb->pkt_type == HCI_COMMAND_PKT) {
		u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
		u16 ogf = cmd_opcode_ogf(opcode);
		u16 ocf = cmd_opcode_ocf(opcode);

		if (((ogf > HCI_SFLT_MAX_OGF) || 
				!hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
		    			!capable(CAP_NET_RAW)) {
			err = -EPERM;
			goto drop;
		}

		if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
			skb_queue_tail(&hdev->raw_q, skb);
			hci_sched_tx(hdev);
		} else {
			skb_queue_tail(&hdev->cmd_q, skb);
			hci_sched_cmd(hdev);
		}
	} else {
		if (!capable(CAP_NET_RAW)) {
			err = -EPERM;
			goto drop;
		}

		skb_queue_tail(&hdev->raw_q, skb);
		hci_sched_tx(hdev);
	}

	err = len;

done:
	release_sock(sk);
	return err;

drop:
	kfree_skb(skb);
	goto done;
}
Exemplo n.º 29
0
static void btuart_receive(btuart_info_t *info)
{
	unsigned int iobase;
	int boguscount = 0;

	if (!info) {
		BT_ERR("Unknown device");
		return;
	}

	iobase = info->p_dev->io.BasePort1;

	do {
		info->hdev->stat.byte_rx++;

		/* Allocate packet */
		if (info->rx_skb == NULL) {
			info->rx_state = RECV_WAIT_PACKET_TYPE;
			info->rx_count = 0;
			if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
				BT_ERR("Can't allocate mem for new packet");
				return;
			}
		}

		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {

			info->rx_skb->dev = (void *) info->hdev;
			bt_cb(info->rx_skb)->pkt_type = inb(iobase + UART_RX);

			switch (bt_cb(info->rx_skb)->pkt_type) {

			case HCI_EVENT_PKT:
				info->rx_state = RECV_WAIT_EVENT_HEADER;
				info->rx_count = HCI_EVENT_HDR_SIZE;
				break;

			case HCI_ACLDATA_PKT:
				info->rx_state = RECV_WAIT_ACL_HEADER;
				info->rx_count = HCI_ACL_HDR_SIZE;
				break;

			case HCI_SCODATA_PKT:
				info->rx_state = RECV_WAIT_SCO_HEADER;
				info->rx_count = HCI_SCO_HDR_SIZE;
				break;

			default:
				/* Unknown packet */
				BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
				info->hdev->stat.err_rx++;
				clear_bit(HCI_RUNNING, &(info->hdev->flags));

				kfree_skb(info->rx_skb);
				info->rx_skb = NULL;
				break;

			}

		} else {

			*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
			info->rx_count--;

			if (info->rx_count == 0) {

				int dlen;
				struct hci_event_hdr *eh;
				struct hci_acl_hdr *ah;
				struct hci_sco_hdr *sh;


				switch (info->rx_state) {

				case RECV_WAIT_EVENT_HEADER:
					eh = hci_event_hdr(info->rx_skb);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = eh->plen;
					break;

				case RECV_WAIT_ACL_HEADER:
					ah = hci_acl_hdr(info->rx_skb);
					dlen = __le16_to_cpu(ah->dlen);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = dlen;
					break;

				case RECV_WAIT_SCO_HEADER:
					sh = hci_sco_hdr(info->rx_skb);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = sh->dlen;
					break;

				case RECV_WAIT_DATA:
					hci_recv_frame(info->rx_skb);
					info->rx_skb = NULL;
					break;

				}

			}

		}

		/* Make sure we don't stay here too long */
		if (boguscount++ > 16)
			break;

	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
}
Exemplo n.º 30
0
static int nfcwilink_download_fw(struct nfcwilink *drv)
{
	unsigned char file_name[BTS_FILE_NAME_MAX_SIZE];
	const struct firmware *fw;
	__u16 action_type, action_len;
	__u8 *ptr;
	int len, rc;

	nfc_dev_dbg(&drv->pdev->dev, "download_fw entry");

	set_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);

	rc = nfcwilink_get_bts_file_name(drv, file_name);
	if (rc)
		goto exit;

	rc = request_firmware(&fw, file_name, &drv->pdev->dev);
	if (rc) {
		nfc_dev_err(&drv->pdev->dev, "request_firmware failed %d", rc);

		/* if the file is not found, don't exit with failure */
		if (rc == -ENOENT)
			rc = 0;

		goto exit;
	}

	len = fw->size;
	ptr = (__u8 *)fw->data;

	if ((len == 0) || (ptr == NULL)) {
		nfc_dev_dbg(&drv->pdev->dev,
				"request_firmware returned size %d", len);
		goto release_fw;
	}

	if (__le32_to_cpu(((struct bts_file_hdr *)ptr)->magic) !=
			BTS_FILE_HDR_MAGIC) {
		nfc_dev_err(&drv->pdev->dev, "wrong bts magic number");
		rc = -EINVAL;
		goto release_fw;
	}

	/* remove the BTS header */
	len -= sizeof(struct bts_file_hdr);
	ptr += sizeof(struct bts_file_hdr);

	while (len > 0) {
		action_type =
			__le16_to_cpu(((struct bts_file_action *)ptr)->type);
		action_len =
			__le16_to_cpu(((struct bts_file_action *)ptr)->len);

		nfc_dev_dbg(&drv->pdev->dev, "bts_file_action type %d, len %d",
				action_type, action_len);

		switch (action_type) {
		case BTS_FILE_ACTION_TYPE_SEND_CMD:
			rc = nfcwilink_send_bts_cmd(drv,
					((struct bts_file_action *)ptr)->data,
					action_len);
			if (rc)
				goto release_fw;
			break;
		}

		/* advance to the next action */
		len -= (sizeof(struct bts_file_action) + action_len);
		ptr += (sizeof(struct bts_file_action) + action_len);
	}

release_fw:
	release_firmware(fw);

exit:
	clear_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
	return rc;
}