Ejemplo n.º 1
0
/**
 * st_int_enqueue - internal Q-ing function.
 *	Will either Q the skb to txq or the tx_waitq
 *	depending on the ST LL state.
 *	If the chip is asleep, then Q it onto waitq and
 *	wakeup the chip.
 *	txq and waitq needs protection since the other contexts
 *	may be sending data, waking up chip.
 */
static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
{
	unsigned long flags = 0;

	pr_debug("%s", __func__);
	spin_lock_irqsave(&st_gdata->lock, flags);

	switch (st_ll_getstate(st_gdata)) {
	case ST_LL_AWAKE:
		pr_debug("ST LL is AWAKE, sending normally");
		skb_queue_tail(&st_gdata->txq, skb);
		break;
	case ST_LL_ASLEEP_TO_AWAKE:
		skb_queue_tail(&st_gdata->tx_waitq, skb);
		break;
	case ST_LL_AWAKE_TO_ASLEEP:
		pr_err("ST LL is illegal state(%ld),"
			   "purging received skb.", st_ll_getstate(st_gdata));
		kfree_skb(skb);
		break;
	case ST_LL_ASLEEP:
		skb_queue_tail(&st_gdata->tx_waitq, skb);
		st_ll_wakeup(st_gdata);
		break;
	default:
		pr_err("ST LL is illegal state(%ld),"
			   "purging received skb.", st_ll_getstate(st_gdata));
		kfree_skb(skb);
		break;
	}

	spin_unlock_irqrestore(&st_gdata->lock, flags);
	pr_debug("done %s", __func__);
	return;
}
static bool is_bt_active(void)
{
	struct platform_device  *pdev;
	struct kim_data_s       *kim_gdata;

	pdev = &wl128x_device;
	kim_gdata = dev_get_drvdata(&pdev->dev);
	if (st_ll_getstate(kim_gdata->core_data) != ST_LL_ASLEEP &&
			st_ll_getstate(kim_gdata->core_data) != ST_LL_INVALID)
		return true;
	else
		return false;
}
Ejemplo n.º 3
0
static int plat_kim_suspend(struct platform_device *pdev, pm_message_t state)
{
	struct kim_data_s *kim_gdata;
	struct st_data_s *core_data;
	kim_gdata = dev_get_drvdata(&pdev->dev);
	core_data = kim_gdata->core_data;
	if (st_ll_getstate(core_data) != ST_LL_INVALID) {
		/* Prevent suspend until sleep indication from chip */
		while (st_ll_getstate(core_data) != ST_LL_ASLEEP &&
			(retry_suspend++ < 5)) {
				return -1;
		}
	}
	return 0;
}
Ejemplo n.º 4
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;
			if (st_gdata->list[type] == NULL) {
				pr_err("chip/interface misbehavior dropping"
					" frame starting with 0x%02x", 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--;
	}