Ejemplo n.º 1
0
static void smd_net_notify(void *_dev, unsigned event)
{
	struct rmnet_private *p = netdev_priv((struct net_device *)_dev);

	if (event != SMD_EVENT_DATA)
		return;

	spin_lock(&p->lock);
	if (p->skb && (smd_write_avail(p->ch) >= p->skb->len))
		tasklet_hi_schedule(&p->tsklt);

	spin_unlock(&p->lock);

	if (smd_read_avail(p->ch) &&
	    (smd_read_avail(p->ch) >= smd_cur_packet_size(p->ch))) {
		smd_net_data_tasklet.data = (unsigned long) _dev;
		tasklet_schedule(&smd_net_data_tasklet);
	}
}
static void grmnet_ctrl_smd_notify(void *p, unsigned event)
{
	struct rmnet_ctrl_port	*port = p;
	struct smd_ch_info	*c = &port->ctrl_ch;
	struct rmnet_ctrl_pkt	*cpkt;
	unsigned long		flags;

	pr_debug("%s: EVENT_(%s)\n", __func__, get_smd_event(event));

	switch (event) {
	case SMD_EVENT_DATA:
		if (smd_read_avail(c->ch) && !waitqueue_active(&c->smd_wait_q))
			queue_work(grmnet_ctrl_wq, &c->read_w);
		if (smd_write_avail(c->ch))
			queue_work(grmnet_ctrl_wq, &c->write_w);
		break;
	case SMD_EVENT_OPEN:
		set_bit(CH_OPENED, &c->flags);

		if (port && port->port_usb && port->port_usb->connect)
			port->port_usb->connect(port->port_usb);

		break;
	case SMD_EVENT_CLOSE:
		clear_bit(CH_OPENED, &c->flags);

		if (port && port->port_usb && port->port_usb->disconnect)
			port->port_usb->disconnect(port->port_usb);

		spin_lock_irqsave(&port->port_lock, flags);
		while (!list_empty(&c->tx_q)) {
			cpkt = list_first_entry(&c->tx_q,
					struct rmnet_ctrl_pkt, list);

			list_del(&cpkt->list);
			free_rmnet_ctrl_pkt(cpkt);
		}
		spin_unlock_irqrestore(&port->port_lock, flags);

		break;
	}
	wake_up(&c->smd_wait_q);
}
Ejemplo n.º 3
0
static void _rmnet_resume_flow(unsigned long param)
{
	struct net_device *dev = (struct net_device *)param;
	struct rmnet_private *p = netdev_priv(dev);
	struct sk_buff *skb = NULL;
	unsigned long flags;

	/* xmit and enable the flow only once even if
	   multiple tasklets were scheduled by smd_net_notify */
	spin_lock_irqsave(&p->lock, flags);
	if (p->skb && (smd_write_avail(p->ch) >= p->skb->len)) {
		skb = p->skb;
		p->skb = NULL;
		spin_unlock_irqrestore(&p->lock, flags);
		_rmnet_xmit(skb, dev);
		netif_wake_queue(dev);
	} else
		spin_unlock_irqrestore(&p->lock, flags);
}
Ejemplo n.º 4
0
static void rmnet_check_fifo(struct net_device *dev)
{
#if fcENABLE_FLOW_CTRL
	if (bRmnetFifoFull)
	{
		struct rmnet_private *p = netdev_priv(dev);
		int iAvail = smd_write_avail(p->ch);

		if (iAvail > (smd_total_fifo_size(p->ch) / 2))
		{
			pr_devel(LOG_TAG1 "%s@%d: tx resumed\n", __func__, __LINE__);
			if (netif_carrier_ok(dev))
				netif_wake_queue(dev);
			else
				pr_err(LOG_TAG1 "%s@%d: no netif_carrier_ok\n", __func__, __LINE__);
			bRmnetFifoFull = 0;
		}
	}
#endif
}
static ssize_t smd_lge_write(struct file *fp, const char __user *buf,
			 size_t count, loff_t *pos)
{
	int len = 0, ch_avail = 0, ret = 0;

	SMD_LGE_DBG("%s \n", __func__);

	if (psmd_device->ch == 0) {
		SMD_LGE_INFO("%s : psmd_device->ch is NULL \n", __func__);
		return -EFAULT;
	}

	len = count ;

	if (copy_from_user(psmd_device->tx_buff, buf, count))
		return -EFAULT;

	SMD_LGE_DBG("%s : received len ( %d bytes ) from user \n",
		__func__, count);

	while (len > 0) {
		ch_avail = smd_write_avail(psmd_device->ch);
		SMD_LGE_DBG("%s : ch_avail = %d bytes, len = %d bytes \n",
			__func__, ch_avail, len);

		if (ch_avail < len) {
			ret = smd_write(psmd_device->ch, psmd_device->tx_buff,
				ch_avail);
			len -= ch_avail;
		} else {
			ret = smd_write(psmd_device->ch, psmd_device->tx_buff,
				len);
			len -= len;
		}

	}
	SMD_LGE_DBG("%s : write return value = %d \n", __func__, ret);

	return ret;
}
int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
{
	int w_len;
	unsigned long flags;


	spin_lock_irqsave(&apr_ch->w_lock, flags);
	if (smd_write_avail(apr_ch->ch) < len) {
		spin_unlock_irqrestore(&apr_ch->w_lock, flags);
		return -EAGAIN;
	}

	w_len = smd_write(apr_ch->ch, data, len);
	spin_unlock_irqrestore(&apr_ch->w_lock, flags);
	pr_debug("apr_tal:w_len = %d\n", w_len);

	if (w_len != len) {
		pr_err("apr_tal: Error in write\n");
		return -ENETRESET;
	}
	return w_len;
}
Ejemplo n.º 7
0
static void grmnet_ctrl_smd_notify(void *p, unsigned event)
{
	struct rmnet_ctrl_port	*port = p;
	struct smd_ch_info	*c = &port->ctrl_ch;

	pr_debug("%s: EVENT_(%s)\n", __func__, get_smd_event(event));

	switch (event) {
	case SMD_EVENT_DATA:
		if (smd_read_avail(c->ch))
			queue_work(grmnet_ctrl_wq, &c->read_w);
		if (smd_write_avail(c->ch))
			queue_work(grmnet_ctrl_wq, &c->write_w);
		break;
	case SMD_EVENT_OPEN:
		set_bit(CH_OPENED, &c->flags);
		wake_up(&c->wait);
		break;
	case SMD_EVENT_CLOSE:
		clear_bit(CH_OPENED, &c->flags);
		break;
	}
}
static void smd_net_notify(void *_dev, unsigned event)
{
	struct rmnet_private *p = netdev_priv((struct net_device *)_dev);

	switch (event) {
	case SMD_EVENT_DATA:
		spin_lock(&p->lock);
		if (p->skb && (smd_write_avail(p->ch) >= p->skb->len)) {
			smd_disable_read_intr(p->ch);
			tasklet_hi_schedule(&p->tsklt);
		}

		spin_unlock(&p->lock);

		if (smd_read_avail(p->ch) &&
			(smd_read_avail(p->ch) >= smd_cur_packet_size(p->ch))) {
			smd_net_data_tasklet.data = (unsigned long) _dev;
			tasklet_schedule(&smd_net_data_tasklet);
		}
		break;

	case SMD_EVENT_OPEN:
		DBG0("%s: opening SMD port\n", __func__);
		netif_carrier_on(_dev);
		if (netif_queue_stopped(_dev)) {
			DBG0("%s: re-starting if queue\n", __func__);
			netif_wake_queue(_dev);
		}
		break;

	case SMD_EVENT_CLOSE:
		DBG0("%s: closing SMD port\n", __func__);
		netif_carrier_off(_dev);
		break;
	}
}
Ejemplo n.º 9
0
static int rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
{
	struct rmnet_private *p = netdev_priv(dev);
	smd_channel_t *ch = p->ch;
	unsigned long flags;

	if (netif_queue_stopped(dev)) {
		pr_err("fatal: rmnet_xmit called when netif_queue is stopped");
		return 0;
	}

	spin_lock_irqsave(&p->lock, flags);
	if (smd_write_avail(ch) < skb->len) {
		netif_stop_queue(dev);
		p->skb = skb;
		spin_unlock_irqrestore(&p->lock, flags);
		return 0;
	}
	spin_unlock_irqrestore(&p->lock, flags);

	_rmnet_xmit(skb, dev);

	return 0;
}
Ejemplo n.º 10
0
static void smd_net_notify(void *_dev, unsigned event)
{
	struct rmnet_private *p = netdev_priv((struct net_device *)_dev);
	int space;

	if (event != SMD_EVENT_DATA)
		return;

	spin_lock(&p->lock);
	if (p->skb && ((space=smd_write_avail(p->ch)) >= p->skb->len)) {
		smd_disable_read_intr(p->ch);
		pr_warn("warn: notify write resources on ch %s, available %d, needed %d\n",
				p->chname, space, p->skb->len);
		tasklet_hi_schedule(&p->tsklt);
	}

	spin_unlock(&p->lock);

	if (smd_read_avail(p->ch) &&
	    (smd_read_avail(p->ch) >= smd_cur_packet_size(p->ch))) {
		smd_net_data_tasklet.data = (unsigned long) _dev;
		tasklet_schedule(&smd_net_data_tasklet);
	}
}
Ejemplo n.º 11
0
static int update_modem(enum ssm_ipc_req ipc_req, struct ssm_driver *ssm,
		int length, char *data)
{
	unsigned int packet_len = length + SSM_MSG_FIELD_LEN;
	int rc = 0, count;

	snprintf(ssm->smd_buffer, SSM_MSG_FIELD_LEN + 1, "%10u|", ipc_req);
	memcpy(ssm->smd_buffer + SSM_MSG_FIELD_LEN, data, length);

	if (smd_write_avail(ssm->ch) < packet_len) {
		dev_err(ssm->dev, "Not enough space dropping request\n");
		rc = -ENOSPC;
		goto out;
	}

	count = smd_write(ssm->ch, ssm->smd_buffer, packet_len);
	if (count < packet_len) {
		dev_err(ssm->dev, "smd_write failed for %d\n", ipc_req);
		rc = -EIO;
	}

out:
	return rc;
}
Ejemplo n.º 12
0
static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
{
	struct smd_tty_info *info = tty->driver_data;
	int avail, ret, runfix = 0;
#ifdef CONFIG_MACH_HTCLEO
	static int init = 0;
	// seems to start the modem
	const unsigned char* firstcall ="AT@BRIC=0\r";
	// set functionality to low power mode
	const unsigned char* secondcall="AT+CFUN=0\r";
	// deregister from the network
	const unsigned char* thirdcall ="AT+COPS=2\r";
	unsigned int call_len;
#endif

	/* if we're writing to a packet channel we will
	** never be able to write more data than there
	** is currently space for
	*/
	if (is_in_reset(info))
		return -ENETRESET;

#ifdef CONFIG_MACH_HTCLEO
	if(len>7 && !init && htcleo_is_nand_boot()) {
		pr_info("NAND boot, writing additional init commands to /dev/smd0");

		call_len = strlen(firstcall);
		avail = smd_write_avail(info->ch);
		if (call_len > avail)
			call_len = avail;
		ret = smd_write(info->ch, firstcall, call_len);

		call_len = strlen(secondcall);
		avail = smd_write_avail(info->ch);
		if (call_len > avail)
			call_len = avail;
		ret = smd_write(info->ch, secondcall, call_len);

		call_len = strlen(thirdcall);
		avail = smd_write_avail(info->ch);
		if (call_len > avail)
			call_len = avail;
		ret = smd_write(info->ch, thirdcall, call_len);

		init=1;
	}
#endif

	avail = smd_write_avail(info->ch);
	/* if no space, we'll have to setup a notification later to wake up the
	 * tty framework when space becomes avaliable
	 */
	if (!avail) {
		smd_enable_read_intr(info->ch);
		return 0;
	}
	if (len > avail)
		len = avail;

	return smd_write(info->ch, buf, len);
}
Ejemplo n.º 13
0
wpt_uint32
WCTS_SendMessage
(
   WCTS_HandleType      wctsHandle,
   void*                pMsg,
   wpt_uint32           uLen
)
{
   WCTS_ControlBlockType*    pWCTSCb = (WCTS_ControlBlockType*) wctsHandle;
   WCTS_BufferType*          pBufferQueue;
   int                       len;
   int                       written = 0;
   int                       available;

   

   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic) ||
       (NULL == pMsg) || (0 == uLen) || (0x7fffffff < uLen)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Invalid parameters received.");
      WPAL_ASSERT(0);
      if (NULL != pMsg) {
         wpalMemoryFree(pMsg);
      }
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   
   len = (int)uLen;

   if (WCTS_STATE_OPEN == pWCTSCb->wctsState) {
      available = smd_write_avail(pWCTSCb->wctsChannel);
      if (available >= len) {
         written = smd_write(pWCTSCb->wctsChannel, pMsg, len);
      }
   } else if (WCTS_STATE_DEFERRED == pWCTSCb->wctsState) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
                 "WCTS_SendMessage: FIFO space not available, the packets will be queued");
   } else {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Channel in illegal state [%d].",
                 pWCTSCb->wctsState);
      
      written = -1;
   }

   if (-1 == written) {
      
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Failed to send message over the bus.");
      wpalMemoryFree(pMsg);
      return eWLAN_PAL_STATUS_E_FAILURE;
   } else if (written == len) {
      
      wpalMemoryFree(pMsg);
   } else {
      /* This much data cannot be written at this time,
         queue the rest of the data for later*/
      pBufferQueue = wpalMemoryAllocate(sizeof(WCTS_BufferType));
      if (NULL == pBufferQueue) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_SendMessage: Cannot allocate memory for queuing the buffer");
         wpalMemoryFree(pMsg);
         WPAL_ASSERT(0);
         return eWLAN_PAL_STATUS_E_NOMEM;
      }

      pBufferQueue->bufferSize = len;
      pBufferQueue->pBuffer = pMsg;
      wpal_list_insert_back(&pWCTSCb->wctsPendingQueue, &pBufferQueue->node);

      if (WCTS_STATE_DEFERRED != pWCTSCb->wctsState) {

         pWCTSCb->wctsState = WCTS_STATE_DEFERRED;

         smd_enable_read_intr(pWCTSCb->wctsChannel);
      }

      
      return eWLAN_PAL_STATUS_E_RESOURCES;
   }

   return eWLAN_PAL_STATUS_SUCCESS;

}
Ejemplo n.º 14
0
static void smd_tty_notify(void *priv, unsigned event)
{
	struct smd_tty_info *info = priv;
	struct tty_struct *tty;
	unsigned long flags;

	switch (event) {
	case SMD_EVENT_DATA:
		spin_lock_irqsave(&info->reset_lock, flags);
		if (!info->is_open) {
			spin_unlock_irqrestore(&info->reset_lock, flags);
			break;
		}
		spin_unlock_irqrestore(&info->reset_lock, flags);
		/* There may be clients (tty framework) that are blocked
		 * waiting for space to write data, so if a possible read
		 * interrupt came in wake anyone waiting and disable the
		 * interrupts
		 */
		if (smd_write_avail(info->ch)) {
			smd_disable_read_intr(info->ch);
			tty = tty_port_tty_get(&info->port);
			if (tty)
				wake_up_interruptible(&tty->write_wait);
			tty_kref_put(tty);
		}
		spin_lock_irqsave(&info->ra_lock, flags);
		if (smd_read_avail(info->ch)) {
			wake_lock(&info->ra_wake_lock);
			tasklet_hi_schedule(&info->tty_tsklt);
		}
		spin_unlock_irqrestore(&info->ra_lock, flags);
		break;

	case SMD_EVENT_OPEN:
		spin_lock_irqsave(&info->reset_lock, flags);
		info->in_reset = 0;
		info->in_reset_updated = 1;
		info->is_open = 1;
		wake_up_interruptible(&info->ch_opened_wait_queue);
		spin_unlock_irqrestore(&info->reset_lock, flags);
		break;

	case SMD_EVENT_CLOSE:
		spin_lock_irqsave(&info->reset_lock, flags);
		info->in_reset = 1;
		info->in_reset_updated = 1;
		info->is_open = 0;
		wake_up_interruptible(&info->ch_opened_wait_queue);
		spin_unlock_irqrestore(&info->reset_lock, flags);
		/* schedule task to send TTY_BREAK */
		tasklet_hi_schedule(&info->tty_tsklt);

		tty = tty_port_tty_get(&info->port);
		if (tty->index == LOOPBACK_IDX)
			schedule_delayed_work(&loopback_work,
					msecs_to_jiffies(1000));
		tty_kref_put(tty);
		break;
#ifdef CONFIG_MSM_SMD_TTY_DS_LEGACY
		/*
		 * At current smd_tty framework, if smd_tty_open()
		 * is invoked by process before smd_tty_close() is
		 * completely finished, smd_tty_open() may fail
		 * because smd_tty_close() does not wait to close smd
		 * channel from modem. To fix this situation, new SMD
		 * notify status, SMD_EVENT_REOPEN_READY is used.
		 * Until smd_tty receive this status, smd_tty_close()
		 * will be wait(in fact, process will be wait).
		 */
	case SMD_EVENT_REOPEN_READY:
		/* smd channel is closed completely */
		spin_lock_irqsave(&info->reset_lock, flags);
		info->in_reset = 1;
		info->in_reset_updated = 1;
		info->is_open = 0;
		wake_up_interruptible(&info->ch_opened_wait_queue);
		spin_unlock_irqrestore(&info->reset_lock, flags);
		break;
#endif
	}
}
Ejemplo n.º 15
0
static int smd_tty_write_room(struct tty_struct *tty)
{
	struct smd_tty_info *info = tty->driver_data;
	return smd_write_avail(info->ch);
}
static int rpcrouter_smd_loopback_write_avail(void)
{
    return smd_write_avail(smd_loopback_xprt.channel);
}
static int rpcrouter_smd_remote_write_avail(void)
{
    return smd_write_avail(smd_remote_xprt.channel);
}
Ejemplo n.º 18
0
/* Called in soft-irq context */
static void smd_net_data_handler(unsigned long arg)
{
    struct net_device *dev = (struct net_device *) arg;
    struct rmnet_private *p = netdev_priv(dev);
    struct sk_buff *skb;
    void *ptr = 0;
    int sz;
    u32 opmode = p->operation_mode;
//	unsigned long flags;
//   int max_package_size;
    for (;;) {
        sz = smd_cur_packet_size(p->ch);
        if (sz == 0) break;
        if (smd_read_avail(p->ch) < sz) break;
//ZTE_RIL_WANGCHENG_20110425 start
#ifdef CONFIG_ZTE_PLATFORM

        if (RMNET_IS_MODE_IP(opmode) ? (sz > ((dev->mtu > RMNET_DEFAULT_MTU_LEN)? dev->mtu:RMNET_DEFAULT_MTU_LEN)) :
                (sz > (((dev->mtu > RMNET_DEFAULT_MTU_LEN)? dev->mtu:RMNET_DEFAULT_MTU_LEN) + ETH_HLEN))) {
#else
        if (RMNET_IS_MODE_IP(opmode) ? (sz > dev->mtu) :
                (sz > (dev->mtu + ETH_HLEN))) {

#endif

            pr_err("rmnet_recv() discarding %d len (%d mtu)\n",
                   sz, RMNET_IS_MODE_IP(opmode) ?
                   dev->mtu : (dev->mtu + ETH_HLEN));
            ptr = 0;
        } else {
            skb = dev_alloc_skb(sz + NET_IP_ALIGN);
            if (skb == NULL) {
                pr_err("rmnet_recv() cannot allocate skb\n");
            } else {
                skb->dev = dev;
                skb_reserve(skb, NET_IP_ALIGN);
                ptr = skb_put(skb, sz);
                wake_lock_timeout(&p->wake_lock, HZ / 2);
                if (smd_read(p->ch, ptr, sz) != sz) {
                    pr_err("rmnet_recv() smd lied about avail?!");
                    ptr = 0;
                    dev_kfree_skb_irq(skb);
                } else {
                    /* Handle Rx frame format */
                    //spin_lock_irqsave(&p->lock, flags);
                    //opmode = p->operation_mode;
                    //spin_unlock_irqrestore(&p->lock, flags);

                    if (RMNET_IS_MODE_IP(opmode)) {
                        /* Driver in IP mode */
                        skb->protocol =
                            rmnet_ip_type_trans(skb, dev);
                    } else {
                        /* Driver in Ethernet mode */
                        skb->protocol =
                            eth_type_trans(skb, dev);
                    }
                    if (RMNET_IS_MODE_IP(opmode) ||
                            count_this_packet(ptr, skb->len)) {
#ifdef CONFIG_MSM_RMNET_DEBUG
                        p->wakeups_rcv +=
                            rmnet_cause_wakeup(p);
#endif
                        p->stats.rx_packets++;
                        p->stats.rx_bytes += skb->len;
                    }
                    netif_rx(skb);
                }
                continue;
            }
        }
        if (smd_read(p->ch, ptr, sz) != sz)
            pr_err("rmnet_recv() smd lied about avail?!");
    }
}

//ZTE_RIL_RJG_20101103 end

static DECLARE_TASKLET(smd_net_data_tasklet, smd_net_data_handler, 0);

static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
{
    struct rmnet_private *p = netdev_priv(dev);
    smd_channel_t *ch = p->ch;
    int smd_ret;
    struct QMI_QOS_HDR_S *qmih;
    u32 opmode;
    unsigned long flags;

    /* For QoS mode, prepend QMI header and assign flow ID from skb->mark */
    spin_lock_irqsave(&p->lock, flags);
    opmode = p->operation_mode;
    spin_unlock_irqrestore(&p->lock, flags);

    if (RMNET_IS_MODE_QOS(opmode)) {
        qmih = (struct QMI_QOS_HDR_S *)
               skb_push(skb, sizeof(struct QMI_QOS_HDR_S));
        qmih->version = 1;
        qmih->flags = 0;
        qmih->flow_id = skb->mark;
    }

    dev->trans_start = jiffies;
    smd_ret = smd_write(ch, skb->data, skb->len);
    if (smd_ret != skb->len) {
        pr_err("%s: smd_write returned error %d", __func__, smd_ret);
        goto xmit_out;
    }

    if (RMNET_IS_MODE_IP(opmode) ||
            count_this_packet(skb->data, skb->len)) {
        p->stats.tx_packets++;
        p->stats.tx_bytes += skb->len;
#ifdef CONFIG_MSM_RMNET_DEBUG
        p->wakeups_xmit += rmnet_cause_wakeup(p);
#endif
    }

xmit_out:
    /* data xmited, safe to release skb */
    dev_kfree_skb_irq(skb);
    return 0;
}

static void _rmnet_resume_flow(unsigned long param)
{
    struct net_device *dev = (struct net_device *)param;
    struct rmnet_private *p = netdev_priv(dev);
    struct sk_buff *skb = NULL;
    unsigned long flags;

    /* xmit and enable the flow only once even if
       multiple tasklets were scheduled by smd_net_notify */
    spin_lock_irqsave(&p->lock, flags);
    if (p->skb && (smd_write_avail(p->ch) >= p->skb->len)) {
        skb = p->skb;
        p->skb = NULL;
        spin_unlock_irqrestore(&p->lock, flags);
        _rmnet_xmit(skb, dev);
        netif_wake_queue(dev);
    } else
        spin_unlock_irqrestore(&p->lock, flags);
}

static void msm_rmnet_unload_modem(void *pil)
{
    if (pil)
        pil_put(pil);
}

static void *msm_rmnet_load_modem(struct net_device *dev)
{
    void *pil;
    int rc;
    struct rmnet_private *p = netdev_priv(dev);

    pil = pil_get("modem");
    if (IS_ERR(pil))
        pr_err("%s: modem load failed\n", __func__);
    else if (msm_rmnet_modem_wait) {
        rc = wait_for_completion_interruptible_timeout(
                 &p->complete,
                 msecs_to_jiffies(msm_rmnet_modem_wait * 1000));
        if (!rc)
            rc = -ETIMEDOUT;
        if (rc < 0) {
            pr_err("%s: wait for rmnet port failed %d\n",
                   __func__, rc);
            msm_rmnet_unload_modem(pil);
            pil = ERR_PTR(rc);
        }
    }

    return pil;
}
Ejemplo n.º 19
0
static void smd_tty_notify(void *priv, unsigned event)
{
	struct smd_tty_info *info = priv;
	unsigned long flags;
	unsigned char *ptr;

	switch (event) {
	case SMD_EVENT_DATA:
		spin_lock_irqsave(&info->reset_lock, flags);
		if (!info->is_open) {
			spin_unlock_irqrestore(&info->reset_lock, flags);
			break;
		}
		spin_unlock_irqrestore(&info->reset_lock, flags);
		/* There may be clients (tty framework) that are blocked
		 * waiting for space to write data, so if a possible read
		 * interrupt came in wake anyone waiting and disable the
		 * interrupts
		 */
		if (smd_write_avail(info->ch)) {
			smd_disable_read_intr(info->ch);
			if (info->tty) {
				unsigned int n = info->tty->index;
				wake_up_interruptible(&info->tty->write_wait);

				/* use pm_qos for BT performance */
				if (n == BT_ACL_IDX || n == BT_CMD_IDX)
					schedule_work(&pm_qos_set_work);
			}
		}
		tasklet_hi_schedule(&info->tty_tsklt);
		break;

	case SMD_EVENT_OPEN:
		if (is_in_reset(info)) {
			unsigned int n = info->tty->index;
			if (n == BT_CMD_IDX) {
				pr_err("%s:  BT_CMD_IDX Sending hardware error event to stack\n", __func__);
				tty_prepare_flip_string(info->tty, &ptr, 0x03);
				ptr[0] = 0x10;
				ptr[1] = 0x01;
				ptr[2] = 0x0A;
				tty_flip_buffer_push(info->tty);
			}
		}
		spin_lock_irqsave(&info->reset_lock, flags);
		info->in_reset = 0;
		info->in_reset_updated = 1;
		info->is_open = 1;
		wake_up_interruptible(&info->ch_opened_wait_queue);
		spin_unlock_irqrestore(&info->reset_lock, flags);

		break;

	case SMD_EVENT_CLOSE:
		spin_lock_irqsave(&info->reset_lock, flags);
		info->in_reset = 1;
		info->in_reset_updated = 1;
		info->is_open = 0;
		wake_up_interruptible(&info->ch_opened_wait_queue);
		spin_unlock_irqrestore(&info->reset_lock, flags);
		/* schedule task to send TTY_BREAK */
		tasklet_hi_schedule(&info->tty_tsklt);

		if (info->tty->index == LOOPBACK_IDX)
			schedule_delayed_work(&loopback_work,
					msecs_to_jiffies(1000));
		break;
	}
}
Ejemplo n.º 20
0
/**
 @brief    Callback function for serializing WCTS Write
           processing in the control context

 @param    pWCTSCb  WCTS Control Block

 @see
 @return void
*/
static void
WCTS_PALWriteCallback
(
   WCTS_ControlBlockType*  pWCTSCb
)
{
   wpt_list_node*      pNode;
   WCTS_BufferType*    pBufferQueue;
   void*               pBuffer;
   int                 len;
   int                 available;
   int                 written;

   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   /*--------------------------------------------------------------------
     Sanity check
     --------------------------------------------------------------------*/
   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_PALWriteCallback: Invalid parameter received.");
      return;
   }

   /* if we are not deferred, then there are no pending packets */
   if (WCTS_STATE_DEFERRED != pWCTSCb->wctsState) {
      return;
   }

   /* Keep sending deferred messages as long as there is room in
      the channel.  Note that we initially peek at the head of the
      list to access the parameters for the next message; we don't
      actually remove the next message from the deferred list until
      we know the channel can handle it */
   while (eWLAN_PAL_STATUS_SUCCESS ==
          wpal_list_peek_front(&pWCTSCb->wctsPendingQueue, &pNode)) {
      pBufferQueue = container_of(pNode, WCTS_BufferType, node);
      pBuffer = pBufferQueue->pBuffer;
      len = pBufferQueue->bufferSize;

      available = smd_write_avail(pWCTSCb->wctsChannel);
      if (available < len) {
         /* channel has no room for the next packet so we are done */
         return;
      }

      /* there is room for the next message, so we can now remove
         it from the deferred message queue and send it */
      wpal_list_remove_front(&pWCTSCb->wctsPendingQueue, &pNode);

      /* note that pNode will be the same as when we peeked, so
         there is no need to update pBuffer or len */

      written = smd_write(pWCTSCb->wctsChannel, pBuffer, len);
      if (written != len) {
         /* Something went wrong */
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_PALWriteCallback: channel write failure");

         /* we were unable to send the message that was at the head
            of the deferred list.  there is nothing else we can do
            other than drop it, so we will just fall through to the
            "success" processing.
            hopefully the client can recover from this since there is
            nothing else we can do here */
      }

      /* whether we had success or failure, reclaim all memory */
      wpalMemoryFree(pBuffer);
      wpalMemoryFree(pBufferQueue);

      /* we'll continue to iterate until the channel is full or all
         of the deferred messages have been sent */
   }

   /* if we've exited the loop, then we have drained the deferred queue.
      set the state to indicate we are no longer deferred, and turn off
      the remote read interrupt */
   pWCTSCb->wctsState = WCTS_STATE_OPEN;
   smd_disable_read_intr(pWCTSCb->wctsChannel);

} /*WCTS_PALWriteCallback*/
Ejemplo n.º 21
0
static void smd_tty_notify(void *priv, unsigned event)
{
    struct smd_tty_info *info = priv;
    unsigned long flags;

    switch (event) {
    case SMD_EVENT_DATA:
        spin_lock_irqsave(&info->reset_lock, flags);
        if (!info->is_open) {
            spin_unlock_irqrestore(&info->reset_lock, flags);
            break;
        }
        spin_unlock_irqrestore(&info->reset_lock, flags);
        /* There may be clients (tty framework) that are blocked
         * waiting for space to write data, so if a possible read
         * interrupt came in wake anyone waiting and disable the
         * interrupts
         */
        if (smd_write_avail(info->ch)) {
            smd_disable_read_intr(info->ch);
            if (info->tty)
                wake_up_interruptible(&info->tty->write_wait);
        }
        tasklet_hi_schedule(&info->tty_tsklt);
        break;

    case SMD_EVENT_OPEN:
        spin_lock_irqsave(&info->reset_lock, flags);
        info->in_reset = 0;
        info->in_reset_updated = 1;
        info->is_open = 1;
        wake_up_interruptible(&info->ch_opened_wait_queue);
        spin_unlock_irqrestore(&info->reset_lock, flags);
        break;

    case SMD_EVENT_CLOSE:
        spin_lock_irqsave(&info->reset_lock, flags);
        info->in_reset = 1;
        info->in_reset_updated = 1;
        info->is_open = 0;
        wake_up_interruptible(&info->ch_opened_wait_queue);
        spin_unlock_irqrestore(&info->reset_lock, flags);
        /* schedule task to send TTY_BREAK */
        tasklet_hi_schedule(&info->tty_tsklt);

        if (info->tty->index == LOOPBACK_IDX)
            schedule_delayed_work(&loopback_work,
                                  msecs_to_jiffies(1000));
        break;
#ifdef CONFIG_LGE_USES_SMD_DS_TTY
    /*









    */
    case SMD_EVENT_REOPEN_READY:
        /* smd channel is closed completely */
        spin_lock_irqsave(&info->reset_lock, flags);
        info->in_reset = 1;
        info->in_reset_updated = 1;
        info->is_open = 0;
        wake_up_interruptible(&info->ch_opened_wait_queue);
        spin_unlock_irqrestore(&info->reset_lock, flags);
        break;
#endif
    }
}
Ejemplo n.º 22
0
/**
 @brief    This function is used by the DAL Core to to send a
           message over to the WLAN sub-system.

           Once a buffer has been passed into the Send Message
 API, CT takes full ownership of it and it is responsible for
 freeing the associated resources. (This prevents a memcpy in
 case of a deferred write)

 The messages transported through the CT on both RX and TX are
 flat memory buffers that can be accessed and manipulated
 through standard memory functions.

 @param wctsHandlehandle:  received upon open
        pMsg:  the message to be sent
        uLen: the length of the message

 @see
 @return   0 for success
*/
wpt_uint32
WCTS_SendMessage
(
   WCTS_HandleType      wctsHandle,
   void*                pMsg,
   wpt_uint32           uLen
)
{
   WCTS_ControlBlockType*    pWCTSCb = (WCTS_ControlBlockType*) wctsHandle;
   WCTS_BufferType*          pBufferQueue;
   int                       len;
   int                       written = 0;
   int                       available;

   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   /*--------------------------------------------------------------------
     Sanity check
     --------------------------------------------------------------------*/
   if ((NULL == pWCTSCb) || (WCTS_CB_MAGIC != pWCTSCb->wctsMagic) ||
       (NULL == pMsg) || (0 == uLen) || (0x7fffffff < uLen)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Invalid parameters received.");
      WPAL_ASSERT(0);
      if (NULL != pMsg) {
         wpalMemoryFree(pMsg);
      }
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   /* the SMD API uses int instead of uint, so change types here */
   len = (int)uLen;

   if (WCTS_STATE_OPEN == pWCTSCb->wctsState) {
      available = smd_write_avail(pWCTSCb->wctsChannel);
      if (available >= len) {
         written = smd_write(pWCTSCb->wctsChannel, pMsg, len);
      }
   } else if (WCTS_STATE_DEFERRED == pWCTSCb->wctsState) {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_INFO,
                 "WCTS_SendMessage: FIFO space not available, the packets will be queued");
   } else {
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Channel in illegal state [%d].",
                 pWCTSCb->wctsState);
      /* force following logic to reclaim the buffer */
      written = -1;
   }

   if (-1 == written) {
      /*Something wrong*/
      WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "WCTS_SendMessage: Failed to send message over the bus.");
      wpalMemoryFree(pMsg);
      WPAL_ASSERT(0);
      return eWLAN_PAL_STATUS_E_FAILURE;
   } else if (written == len) {
      /* Message sent! No deferred state, free the buffer*/
      wpalMemoryFree(pMsg);
   } else {
      /* This much data cannot be written at this time,
         queue the rest of the data for later*/
      pBufferQueue = wpalMemoryAllocate(sizeof(WCTS_BufferType));
      if (NULL == pBufferQueue) {
         WPAL_TRACE(eWLAN_MODULE_DAL_CTRL, eWLAN_PAL_TRACE_LEVEL_ERROR,
                    "WCTS_SendMessage: Cannot allocate memory for queuing the buffer");
         wpalMemoryFree(pMsg);
         WPAL_ASSERT(0);
         return eWLAN_PAL_STATUS_E_NOMEM;
      }

      pBufferQueue->bufferSize = len;
      pBufferQueue->pBuffer = pMsg;
      wpal_list_insert_back(&pWCTSCb->wctsPendingQueue, &pBufferQueue->node);

      /* if we are not already in the deferred state, then transition
         to that state.  when we do so, we enable the remote read
         interrupt so that we'll be notified when messages are read
         from the remote end */
      if (WCTS_STATE_DEFERRED != pWCTSCb->wctsState) {

         /* Mark the state as deferred.
            Later: We may need to protect wctsState by locks*/
         pWCTSCb->wctsState = WCTS_STATE_DEFERRED;

         smd_enable_read_intr(pWCTSCb->wctsChannel);
      }

      /*indicate to client that message was placed in deferred queue*/
      return eWLAN_PAL_STATUS_E_RESOURCES;
   }

   return eWLAN_PAL_STATUS_SUCCESS;

}/*WCTS_SendMessage*/