void diag_send_feature_mask_update(struct diag_smd_info *smd_info)
{
	void *buf = driver->buf_feature_mask_update;
	int header_size = sizeof(struct diag_ctrl_feature_mask);
	int wr_size = -ENOMEM, retry_count = 0;
	uint8_t feature_bytes[FEATURE_MASK_LEN_BYTES] = {0, 0};
	int total_len = 0;

	if (!smd_info) {
		pr_err("diag: In %s, null smd info pointer\n",
			__func__);
		return;
	}

	if (!smd_info->ch) {
		pr_err("diag: In %s, smd channel not open for peripheral: %d, type: %d\n",
				__func__, smd_info->peripheral, smd_info->type);
		return;
	}

	mutex_lock(&driver->diag_cntl_mutex);
	/* send feature mask update */
	driver->feature_mask->ctrl_pkt_id = DIAG_CTRL_MSG_FEATURE;
	driver->feature_mask->ctrl_pkt_data_len = 4 + FEATURE_MASK_LEN_BYTES;
	driver->feature_mask->feature_mask_len = FEATURE_MASK_LEN_BYTES;
	memcpy(buf, driver->feature_mask, header_size);
	feature_bytes[0] |= F_DIAG_INT_FEATURE_MASK;
	feature_bytes[0] |= F_DIAG_LOG_ON_DEMAND_RSP_ON_MASTER;
	feature_bytes[0] |= driver->supports_separate_cmdrsp ?
				F_DIAG_REQ_RSP_CHANNEL : 0;
	feature_bytes[0] |= driver->supports_apps_hdlc_encoding ?
				F_DIAG_HDLC_ENCODE_IN_APPS_MASK : 0;
	feature_bytes[1] |= F_DIAG_OVER_STM;
	memcpy(buf+header_size, &feature_bytes, FEATURE_MASK_LEN_BYTES);
	total_len = header_size + FEATURE_MASK_LEN_BYTES;

	while (retry_count < 3) {
		mutex_lock(&smd_info->smd_ch_mutex);
		wr_size = smd_write(smd_info->ch, buf, total_len);
		mutex_unlock(&smd_info->smd_ch_mutex);
		if (wr_size == -ENOMEM) {
			retry_count++;
			/*
			 * The smd channel is full. Delay while
			 * smd processes existing data and smd
			 * has memory become available. The delay
			 * of 10000 was determined empirically as
			 * best value to use.
			 */
			usleep_range(10000, 10100);
		} else
			break;
	}
	if (wr_size != total_len)
		pr_err("diag: In %s, peripheral %d fail feature update, size: %d, tried: %d",
			__func__, smd_info->peripheral, wr_size, total_len);

	mutex_unlock(&driver->diag_cntl_mutex);
}
예제 #2
0
static int qmi_send(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
{
    unsigned char *data;
    unsigned hlen;
    unsigned len;
    int r;

//    qmi_dump_msg(msg, "send");

    if (msg->service == QMI_CTL) {
        hlen = QMUX_HEADER - 1;
    } else {
        hlen = QMUX_HEADER;
    }

    /* QMUX length is total header + total payload - IFC selector */
    len = hlen + msg->size - 1;
    if (len > 0xffff)
        return -1;

    data = msg->tlv - hlen;

    /* prepend encap and qmux header */
    *data++ = 0x01; /* ifc selector */

    /* qmux header */
    *data++ = len;
    *data++ = len >> 8;
    *data++ = 0x00; /* flags: client */
    *data++ = msg->service;
    *data++ = msg->client_id;

    /* qmi header */
    *data++ = 0x00; /* flags: send */
    *data++ = msg->txn_id;
    if (msg->service != QMI_CTL)
        *data++ = msg->txn_id >> 8;

    *data++ = msg->type;
    *data++ = msg->type >> 8;
    *data++ = msg->size;
    *data++ = msg->size >> 8;

    // add channel number here 
    *(uint32_t*)(msg->tlv + msg->size) = ctxt->ch_num; 
    DBG("send %d %d\n", len + 1 + 4, ctxt->ch_num);
    //     print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, msg->tlv - hlen, len + 1 + 4);

    /* len + 1 takes the interface selector into account */
    // and add ch_num_size
    r = smd_write(ctrl_ch, msg->tlv - hlen, len + 1 + 4);

    if (r != len) {
        return -1;
    } else {
        return 0;
    }
}
예제 #3
0
void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
						int updated_ssid_last, int proc)
{
	void *buf = driver->buf_msg_mask_update;
	int first, last, actual_last, size = -ENOMEM, retry_count = 0;
	int header_size = sizeof(struct diag_ctrl_msg_mask);
	uint8_t *ptr = driver->msg_masks;

	mutex_lock(&driver->diag_cntl_mutex);
	while (*(uint32_t *)(ptr + 4)) {
		first = *(uint32_t *)ptr;
		ptr += 4;
		last = *(uint32_t *)ptr;
		ptr += 4;
		actual_last = *(uint32_t *)ptr;
		ptr += 4;
		if ((updated_ssid_first >= first && updated_ssid_last <=
			 actual_last) || (updated_ssid_first == ALL_SSID)) {
			/* send f3 mask update */
			driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
			driver->msg_mask->msg_mask_size = actual_last -
								 first + 1;
			driver->msg_mask->data_len = 11 +
					 4 * (driver->msg_mask->msg_mask_size);
			driver->msg_mask->stream_id = 1; /* 2, if dual stream */
			driver->msg_mask->status = 3; /* status valid mask */
			driver->msg_mask->msg_mode = 0; /* Legcay mode */
			driver->msg_mask->ssid_first = first;
			driver->msg_mask->ssid_last = actual_last;
			memcpy(buf, driver->msg_mask, header_size);
			memcpy(buf+header_size, ptr,
				 4 * (driver->msg_mask->msg_mask_size));
			if (ch) {
				while (retry_count < 3) {
					size = smd_write(ch, buf, header_size +
					 4*(driver->msg_mask->msg_mask_size));
					if (size == -ENOMEM) {
						retry_count++;
						WAIT_FOR_SMD(5, 2000);
					} else
						break;
				}
				if (size != header_size +
					 4*(driver->msg_mask->msg_mask_size))
					pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
						proc, size, (header_size +
					4*(driver->msg_mask->msg_mask_size)));
				else
					pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
						first, actual_last, proc);
			} else
				pr_err("diag: proc %d, ch invalid msg mask update\n",
					proc);
		}
		ptr += MAX_SSID_PER_RANGE*4;
	}
	mutex_unlock(&driver->diag_cntl_mutex);
}
예제 #4
0
static int hci_smd_send_frame(struct sk_buff *skb)
{
	int len;
	int avail;
	int ret = 0;
	wake_lock(&hs.wake_lock_tx);

	switch (bt_cb(skb)->pkt_type) {
	case HCI_COMMAND_PKT:
		avail = smd_write_avail(hs.event_channel);
		if (!avail) {
			BT_ERR("No space available for smd frame");
			ret =  -ENOSPC;
		}
		len = smd_write(hs.event_channel, skb->data, skb->len);
		if (len < skb->len) {
			BT_ERR("Failed to write Command %d", len);
			ret = -ENODEV;
		}
		break;
	case HCI_ACLDATA_PKT:
	case HCI_SCODATA_PKT:
		avail = smd_write_avail(hs.data_channel);
		if (!avail) {
			BT_ERR("No space available for smd frame");
			ret = -ENOSPC;
		}
		len = smd_write(hs.data_channel, skb->data, skb->len);
		if (len < skb->len) {
			BT_ERR("Failed to write Data %d", len);
			ret = -ENODEV;
		}
		break;
	default:
		BT_ERR("Uknown packet type");
		ret = -ENODEV;
		break;
	}

	kfree_skb(skb);
	wake_unlock(&hs.wake_lock_tx);
	return ret;
}
void diag_send_diag_mode_update_by_smd(struct diag_smd_info *smd_info,
							int real_time)
{
	struct diag_ctrl_msg_diagmode diagmode;
	char buf[sizeof(struct diag_ctrl_msg_diagmode)];
	int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
	int wr_size = -ENOMEM, retry_count = 0, timer;

	/* For now only allow the modem to receive the message */
	if (!smd_info || smd_info->type != SMD_CNTL_TYPE)
		return;

	mutex_lock(&driver->diag_cntl_mutex);
	diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
	diagmode.ctrl_pkt_data_len = 36;
	diagmode.version = 1;
	diagmode.sleep_vote = real_time ? 1 : 0;
	/*
	 * 0 - Disables real-time logging (to prevent
	 *     frequent APPS wake-ups, etc.).
	 * 1 - Enable real-time logging
	 */
	diagmode.real_time = real_time;
	diagmode.use_nrt_values = 0;
	diagmode.commit_threshold = 0;
	diagmode.sleep_threshold = 0;
	diagmode.sleep_time = 0;
	diagmode.drain_timer_val = 0;
	diagmode.event_stale_timer_val = 0;

	memcpy(buf, &diagmode, msg_size);

	if (smd_info->ch) {
		while (retry_count < 3) {
			wr_size = smd_write(smd_info->ch, buf, msg_size);
			if (wr_size == -ENOMEM) {
				retry_count++;
				for (timer = 0; timer < 5; timer++)
					udelay(2000);
			} else {
				driver->real_time_mode = real_time;
				break;
			}
		}
		if (wr_size != msg_size)
			pr_err("diag: proc %d fail feature update %d, tried %d",
				smd_info->peripheral,
				wr_size, msg_size);
	} else {
		pr_err("diag: ch invalid, feature update on proc %d\n",
				smd_info->peripheral);
	}

	mutex_unlock(&driver->diag_cntl_mutex);
}
static int radio_hci_smd_send_frame(struct sk_buff *skb)
{
	int len = 0;

	len = smd_write(hs.fm_channel, skb->data, skb->len);
	if (len < skb->len) {
		FMDERR("Failed to write Data %d", len);
		return -ENODEV;
	}
	return 0;
}
예제 #7
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;

	
	avail = smd_write_avail(info->ch);
	if (len > avail)
		len = avail;

	return smd_write(info->ch, buf, len);
}
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;
}
/*
 * Sends a message to the ADSP via SMD.
 *
 * @param hdr Specifies message type and other meta data
 * @param msg_ptr Pointer to the message contents.
 *                Must be freed within this function if no error is returned.
 *
 * @return 0 upon success; < 0 upon error
 */
static int
sns_ocmem_send_msg(struct sns_ocmem_hdr_s *hdr, void const *msg_ptr)
{
	int rv = 0;
	int err = 0;
	void *temp = NULL;
	int size = 0;

	if (hdr == NULL) {
		pr_err("%s: NULL message header\n", __func__);
		rv = -EINVAL;
		goto out;
	}

	size = sizeof(struct sns_ocmem_hdr_s) + hdr->msg_size;
	temp = kzalloc(sizeof(struct sns_ocmem_hdr_s) + hdr->msg_size,
			GFP_KERNEL);

	if (temp == NULL) {
		pr_err("%s: allocation failure\n", __func__);
		rv = -ENOMEM;
		goto out;
	}

	hdr->dst_module = SNS_OCMEM_MODULE_ADSP;
	hdr->src_module = SNS_OCMEM_MODULE_KERNEL;

	memcpy(temp, hdr, sizeof(struct sns_ocmem_hdr_s));
	memcpy((char *)temp + sizeof(struct sns_ocmem_hdr_s),
		msg_ptr, hdr->msg_size);
	pr_debug("%s: send msg type: %i size: %i id: %i dst: %i src: %i\n",
				__func__, hdr->msg_type, hdr->msg_size,
				hdr->msg_id, hdr->dst_module, hdr->src_module);

	if (sns_ctl.smd_ch == NULL) {
		pr_err("%s: null smd_ch\n", __func__);
		rv = -EINVAL;
	}
	err = smd_write(sns_ctl.smd_ch, temp, size);
	if (err < 0) {
		pr_err("%s: smd_write failed %i\n", __func__, err);
		rv = -ECOMM;
	} else {
		pr_debug("%s smd_write successful ret=%d\n",
			__func__, err);
	}

	kfree(temp);

out:
	return rv;
}
예제 #10
0
static int qmi_send(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
{
	unsigned char *data;
	unsigned hlen;
	unsigned len;
	int r;

	qmi_dump_msg(msg, "send");

	if (msg->service == QMI_CTL) {
		hlen = QMUX_HEADER - 1;
	} else {
		hlen = QMUX_HEADER;
	}

	/* QMUX length is total header + total payload - IFC selector */
	len = hlen + msg->size - 1;
	if (len > 0xffff)
		return -1;

	data = msg->tlv - hlen;

	/* prepend encap and qmux header */
	*data++ = 0x01; /* ifc selector */

	/* qmux header */
	*data++ = len;
	*data++ = len >> 8;
	*data++ = 0x00; /* flags: client */
	*data++ = msg->service;
	*data++ = msg->client_id;

	/* qmi header */
	*data++ = 0x00; /* flags: send */
	*data++ = msg->txn_id;
	if (msg->service != QMI_CTL)
		*data++ = msg->txn_id >> 8;

	*data++ = msg->type;
	*data++ = msg->type >> 8;
	*data++ = msg->size;
	*data++ = msg->size >> 8;

	/* len + 1 takes the interface selector into account */
	r = smd_write(ctxt->ch, msg->tlv - hlen, len + 1);

	if (r != len) {
		return -1;
	} else {
		return 0;
	}
}
예제 #11
0
static int qmi_send(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
{
	unsigned char *data;
	unsigned hlen;
	unsigned len;
	int r;

	qmi_dump_msg(msg, "send");

	if (msg->service == QMI_CTL) {
		hlen = QMUX_HEADER - 1;
	} else {
		hlen = QMUX_HEADER;
	}

	
	len = hlen + msg->size - 1;
	if (len > 0xffff)
		return -1;

	data = msg->tlv - hlen;

	
	*data++ = 0x01; 

	
	*data++ = len;
	*data++ = len >> 8;
	*data++ = 0x00; 
	*data++ = msg->service;
	*data++ = msg->client_id;

	
	*data++ = 0x00; 
	*data++ = msg->txn_id;
	if (msg->service != QMI_CTL)
		*data++ = msg->txn_id >> 8;

	*data++ = msg->type;
	*data++ = msg->type >> 8;
	*data++ = msg->size;
	*data++ = msg->size >> 8;

	
	r = smd_write(ctxt->ch, msg->tlv - hlen, len + 1);

	if (r != len) {
		return -1;
	} else {
		return 0;
	}
}
int diag_send_stm_state(struct diag_smd_info *smd_info,
			  uint8_t stm_control_data)
{
	struct diag_ctrl_msg_stm stm_msg;
	int msg_size = sizeof(struct diag_ctrl_msg_stm);
	int retry_count = 0;
	int wr_size = 0;
	int success = 0;

	if (!smd_info || (smd_info->type != SMD_CNTL_TYPE) ||
		(driver->peripheral_supports_stm[smd_info->peripheral] ==
								DISABLE_STM)) {
		return -EINVAL;
	}

	if (smd_info->ch) {
		stm_msg.ctrl_pkt_id = 21;
		stm_msg.ctrl_pkt_data_len = 5;
		stm_msg.version = 1;
		stm_msg.control_data = stm_control_data;
		while (retry_count < 3) {
			mutex_lock(&smd_info->smd_ch_mutex);
			wr_size = smd_write(smd_info->ch, &stm_msg, msg_size);
			mutex_unlock(&smd_info->smd_ch_mutex);
			if (wr_size == -ENOMEM) {
				/*
				 * The smd channel is full. Delay while
				 * smd processes existing data and smd
				 * has memory become available. The delay
				 * of 10000 was determined empirically as
				 * best value to use.
				 */
				retry_count++;
				usleep_range(10000, 10000);
			} else {
				success = 1;
				break;
			}
		}
		if (wr_size != msg_size) {
			pr_err("diag: In %s, proc %d fail STM update %d, tried %d",
				__func__, smd_info->peripheral, wr_size,
				msg_size);
			success = 0;
		}
	} else {
		pr_err("diag: In %s, ch invalid, STM update on proc %d\n",
				__func__, smd_info->peripheral);
	}
	return success;
}
예제 #13
0
void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
{
	void *buf = driver->buf_log_mask_update;
	int header_size = sizeof(struct diag_ctrl_log_mask);
	struct mask_info *ptr = (struct mask_info *)driver->log_masks;
	int i, size, wr_size = -ENOMEM, retry_count = 0;

	mutex_lock(&driver->diag_cntl_mutex);
	for (i = 0; i < MAX_EQUIP_ID; i++) {
		size = (ptr->num_items+7)/8;
		/* reached null entry */
		if ((ptr->equip_id == 0) && (ptr->index == 0))
			break;
		driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
		driver->log_mask->num_items = ptr->num_items;
		driver->log_mask->data_len  = 11 + size;
		driver->log_mask->stream_id = 1; /* 2, if dual stream */
		driver->log_mask->status = 3; /* status for valid mask */
		driver->log_mask->equip_id = ptr->equip_id;
		driver->log_mask->log_mask_size = size;
		/* send only desired update, NOT ALL */
		if (equip_id == ALL_EQUIP_ID || equip_id ==
					 driver->log_mask->equip_id) {
			memcpy(buf, driver->log_mask, header_size);
			memcpy(buf+header_size, driver->log_masks+ptr->index,
									 size);
			if (ch) {
				while (retry_count < 3) {
					wr_size = smd_write(ch, buf,
							 header_size + size);
					if (wr_size == -ENOMEM) {
						retry_count++;
						WAIT_FOR_SMD(5, 2000);
					} else
						break;
				}
				if (wr_size != header_size + size)
					pr_err("diag: log mask update failed %d, tried %d",
						wr_size, header_size + size);
				else
					pr_debug("diag: updated log equip ID %d,len %d\n",
					driver->log_mask->equip_id,
					driver->log_mask->log_mask_size);
			} else
				pr_err("diag: ch not valid for log update\n");
		}
		ptr++;
	}
	mutex_unlock(&driver->diag_cntl_mutex);
}
예제 #14
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;

	/* if we're writing to a packet channel we will
	** never be able to write more data than there
	** is currently space for
	*/
	avail = smd_write_avail(info->ch);
	if (len > avail)
		len = avail;

	return smd_write(info->ch, buf, len);
}
예제 #15
0
void diag_process_hdlc(void *data, unsigned len)
{
	struct diag_hdlc_decode_type hdlc;
	int ret, type = 0;
#ifdef DIAG_DEBUG
	int i;
	printk(KERN_INFO "\n HDLC decode function, len of data  %d\n", len);
#endif
	hdlc.dest_ptr = driver->hdlc_buf;
	hdlc.dest_size = USB_MAX_OUT_BUF;
	hdlc.src_ptr = data;
	hdlc.src_size = len;
	hdlc.src_idx = 0;
	hdlc.dest_idx = 0;
	hdlc.escaping = 0;

	ret = diag_hdlc_decode(&hdlc);

	if (ret)
		type = diag_process_apps_pkt(driver->hdlc_buf,
							  hdlc.dest_idx - 3);
	else if (driver->debug_flag) {
		printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
				" errors or partial packet received, packet"
				" length = %d\n", len);
		print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
					   DUMP_PREFIX_ADDRESS, data, len, 1);
		driver->debug_flag = 0;
	}
#ifdef DIAG_DEBUG
	printk(KERN_INFO "\n hdlc.dest_idx = %d \n", hdlc.dest_idx);
	for (i = 0; i < hdlc.dest_idx; i++)
		printk(KERN_DEBUG "\t%x", *(((unsigned char *)
							driver->hdlc_buf)+i));
#endif
	/* ignore 2 bytes for CRC, one for 7E and send */
	if ((driver->ch) && (ret) && (type) && (hdlc.dest_idx > 3)) {
		APPEND_DEBUG('g');
		smd_write(driver->ch, driver->hdlc_buf, hdlc.dest_idx - 3);
		APPEND_DEBUG('h');
#ifdef DIAG_DEBUG
		printk(KERN_INFO "writing data to SMD, pkt length %d \n", len);
		print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
			       1, DUMP_PREFIX_ADDRESS, data, len, 1);
#endif
	}

}
예제 #16
0
static int diag_smd_write(void *ctxt, unsigned char *buf, int len)
{
	int write_len = 0;
	int retry_count = 0;
	int max_retries = 3;
	struct diag_smd_info *smd_info = NULL;

	if (!ctxt || !buf)
		return -EIO;

	smd_info = (struct diag_smd_info *)ctxt;
	if (!smd_info || !buf || len <= 0) {
		pr_err_ratelimited("diag: In %s, invalid params, smd_info: %p, buf: %p, len: %d\n",
				   __func__, smd_info, buf, len);
		return -EINVAL;
	}

	if (!smd_info->inited || !smd_info->hdl ||
	    !atomic_read(&smd_info->opened))
		return -ENODEV;

	if (len > smd_info->fifo_size)
		return diag_smd_write_ext(smd_info, buf, len);

	do {
		mutex_lock(&smd_info->lock);
		write_len = smd_write(smd_info->hdl, buf, len);
		mutex_unlock(&smd_info->lock);
		if (write_len == len)
			break;
		/*
		 * The channel maybe busy - the FIFO can be full. Retry after
		 * sometime. The value of 10000 was chosen emprically as the
		 * optimal value for the peripherals to read data from the SMD
		 * channel.
		 */
		usleep_range(10000, 10100);
		retry_count++;
	} while (retry_count < max_retries);

	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s wrote to channel, write_len: %d\n",
		 smd_info->name, write_len);

	if (write_len != len)
		return -ENOMEM;

	return 0;
}
예제 #17
0
static int wcnss_smd_tx(void *data, int len)
{
	int ret = 0;

	ret = smd_write_avail(penv->smd_ch);
	if (ret < len) {
		pr_err("wcnss: no space available for smd frame\n");
		return -ENOSPC;
	}
	ret = smd_write(penv->smd_ch, data, len);
	if (ret < len) {
		pr_err("wcnss: failed to write Command %d", len);
		ret = -ENODEV;
	}
	return ret;
}
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] %s: smd_write returned error %d",
			dev->name, __func__, smd_ret);
		p->stats.tx_errors++;
		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
	}
	DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
	    dev->name, p->stats.tx_packets, skb->len, skb->mark);

xmit_out:
	/* data xmited, safe to release skb */
	dev_kfree_skb_irq(skb);
	return 0;
}
예제 #19
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;

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

	if (smd_write_avail(ch) < skb->len) {
		rmnet_stop(dev);
		/* schedule a function to poll at exponential interval */
		init_timer(&p->smd_poll_timer);
		p->smd_poll_timer.expires = jiffies
			+ ((SMD_POLL_MILLISECS*HZ)/1000);
		p->smd_poll_timer.function = rmnet_poll_smd_write;
		if (p->skb)
			pr_err("fatal: p->skb was non-zero when"
				"we tried to scheduled timer");
		p->skb = skb;
		p->smd_poll_timer.data = (unsigned long)dev;
		add_timer(&p->smd_poll_timer);
	} else {
		smd_ret = smd_write(ch, skb->data, skb->len);
		if (smd_ret != skb->len) {
			pr_err("fatal: smd_write returned error %d", smd_ret);
			return 0;
		}

		if (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
		}
		/* data xmited, safe to release skb */
		dev_kfree_skb_irq(skb);
	}


	return 0;
}
예제 #20
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;

	if (is_in_reset(info))
		return -ENETRESET;

	avail = smd_write_avail(info->ch);
	if (!avail) {
		smd_enable_read_intr(info->ch);
		return 0;
	}
	if (len > avail)
		len = avail;

	return smd_write(info->ch, buf, len);
}
static int diag_smd_write(void *ctxt, unsigned char *buf, int len)
{
    int write_len = 0;
    int retry_count = 0;
    int max_retries = 3;
    struct diag_smd_info *smd_info = NULL;

    if (!ctxt || !buf)
        return -EIO;

    smd_info = (struct diag_smd_info *)ctxt;
    if (!smd_info || !buf || len <= 0) {
        pr_err_ratelimited("diag: In %s, invalid params, smd_info: %p, buf: %p, len: %d\n",
                           __func__, smd_info, buf, len);
        return -EINVAL;
    }

    if (!smd_info->inited || !smd_info->hdl ||
            !atomic_read(&smd_info->opened))
        return -ENODEV;

    if (len > smd_info->fifo_size)
        return diag_smd_write_ext(smd_info, buf, len);

    do {
        mutex_lock(&smd_info->lock);
        write_len = smd_write(smd_info->hdl, buf, len);
        mutex_unlock(&smd_info->lock);
        if (write_len == len)
            break;
        usleep_range(10000, 10100);
        retry_count++;
    } while (retry_count < max_retries);

    DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s wrote to channel, write_len: %d\n",
             smd_info->name, write_len);

    if (write_len != len)
        return -ENOMEM;

    return 0;
}
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;
}
예제 #23
0
static void diag_process_hdlc(struct diag_context *ctxt, void *_data, unsigned len)
{
	unsigned char *data = _data;
	unsigned count = ctxt->hdlc_count;
	unsigned escape = ctxt->hdlc_escape;
	unsigned char *hdlc = ctxt->hdlc_buf;

	while (len-- > 0) {
		unsigned char x = *data++;
		if (x == 0x7E) { 
			if (count > 2) {
				/* we're just ignoring the crc here */
				//TRACE("PC>", hdlc, count - 2, 0);
				if (ctxt->ch)	{
					smd_write(ctxt->ch, hdlc, count - 2);
					smd_xfer_count_func(count - 2, data_set_tx);
				}
			}
			count = 0;
			escape = 0;
		} else if (x == 0x7D) {
			escape = 1;
		} else {
			if (escape) {
				x = x ^ 0x20;
				escape = 0;
			}
			hdlc[count++] = x;

			/* discard frame if we overflow */
			if (count == HDLC_MAX)
				count = 0;
		}
	}

	ctxt->hdlc_count = count;
	ctxt->hdlc_escape = escape;
}
예제 #24
0
void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
{
	void *buf = driver->buf_event_mask_update;
	int header_size = sizeof(struct diag_ctrl_event_mask);
	int wr_size = -ENOMEM, retry_count = 0;

	mutex_lock(&driver->diag_cntl_mutex);
	if (num_bytes == 0) {
		pr_debug("diag: event mask not set yet, so no update\n");
		mutex_unlock(&driver->diag_cntl_mutex);
		return;
	}
	/* send event mask update */
	driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
	driver->event_mask->data_len = 7 + num_bytes;
	driver->event_mask->stream_id = 1; /* 2, if dual stream */
	driver->event_mask->status = 3; /* status for valid mask */
	driver->event_mask->event_config = diag_event_config; /* event config */
	driver->event_mask->event_mask_size = num_bytes;
	memcpy(buf, driver->event_mask, header_size);
	memcpy(buf+header_size, driver->event_masks, num_bytes);
	if (ch) {
		while (retry_count < 3) {
			wr_size = smd_write(ch, buf, header_size + num_bytes);
			if (wr_size == -ENOMEM) {
				retry_count++;
				WAIT_FOR_SMD(5, 2000);
			} else
				break;
		}
		if (wr_size != header_size + num_bytes)
			pr_err("diag: error writing event mask %d, tried %d\n",
					 wr_size, header_size + num_bytes);
	} else
		pr_err("diag: ch not valid for event update\n");
	mutex_unlock(&driver->diag_cntl_mutex);
}
예제 #25
0
static void diag_send_ctrl_msg(struct diag_smd_info *smd_info,
		const void *msg,
		int len)
{
	int wr_size = -ENOMEM, retry_count = 0, timer;

	if (smd_info->ch) {
		while (retry_count < 3) {
			wr_size = smd_write(smd_info->ch, msg, len);
			if (wr_size == -ENOMEM) {
				retry_count++;
				for (timer = 0; timer < 5; timer++)
					usleep_range(2000, 3000);
			} else
				break;
		}
		if (wr_size != len)
			pr_err("diag: proc %d failed sending msg %d, tried %d",
				smd_info->peripheral,
				wr_size, len);
	} else {
		pr_err("diag: ch invalid on proc %d\n", smd_info->peripheral);
	}
}
예제 #26
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;
}
예제 #27
0
void diag_process_hdlc(void *data, unsigned len)
{
	struct diag_hdlc_decode_type hdlc;
	int ret, type = 0;
#if HPST_FUN
	unsigned char *buf_9k = NULL;
	int path;
#endif
#ifdef DIAG_DEBUG
	int i;
	DIAGFWD_INFO("\n HDLC decode function, len of data  %d\n", len);
#endif
	hdlc.dest_ptr = driver->hdlc_buf;
	hdlc.dest_size = USB_MAX_OUT_BUF;
	hdlc.src_ptr = data;
	hdlc.src_size = len;
	hdlc.src_idx = 0;
	hdlc.dest_idx = 0;
	hdlc.escaping = 0;

	ret = diag_hdlc_decode(&hdlc);

	if (ret)
		type = diag_process_apps_pkt(driver->hdlc_buf,
							  hdlc.dest_idx - 3);
	else if (driver->debug_flag) {
		DIAGFWD_INFO("Packet dropped due to bad HDLC coding/CRC"
				" errors or partial packet received, packet"
				" length = %d\n", len);
		print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", DUMP_PREFIX_ADDRESS, 16, 1,
					    data, len, 1);
		driver->debug_flag = 0;
	}
#ifdef CONFIG_DIAG_NO_MODEM
	if (type == 1) { /* implies this packet is NOT meant for apps */
		if (driver->chqdsp)
			smd_write(driver->chqdsp, driver->hdlc_buf,
							 hdlc.dest_idx - 3);
		type = 0;
	}
#endif /* NO MODEM present */

#ifdef DIAG_DEBUG
	printk(KERN_INFO "\n hdlc.dest_idx = %d", hdlc.dest_idx);
	for (i = 0; i < hdlc.dest_idx; i++)
		printk(KERN_DEBUG "\t%x", *(((unsigned char *)
							driver->hdlc_buf)+i));
#endif /* DIAG DEBUG */
	/* ignore 2 bytes for CRC, one for 7E and send */
	if ((driver->ch) && (ret) && (type) && (hdlc.dest_idx > 3)) {
	/*	APPEND_DEBUG('g'); */
#if defined(CONFIG_ARCH_MSM8X60_LTE) || defined(CONFIG_ARCH_MSM8X60)
		smd_write(driver->ch, driver->hdlc_buf, hdlc.dest_idx - 3);
#else //defined(CONFIG_MACH_MECHA)
		smd_write(driver->ch, data, len);
#endif
		if (diag7k_debug_mask)
		print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", DUMP_PREFIX_ADDRESS, 16,
			       1, data, len, 1);
	/*	APPEND_DEBUG('h'); */
#ifdef DIAG_DEBUG
		printk(KERN_INFO "writing data to SMD, pkt length %d \n", len);
		print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", DUMP_PREFIX_ADDRESS, 16,
			       1, data, len, 1);
#endif /* DIAG DEBUG */
	}

}
static int rpcrouter_smd_loopback_write(void *data, uint32_t len, uint32_t type)
{
    return smd_write(smd_loopback_xprt.channel, data, len);
}
예제 #29
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;
}
예제 #30
0
void diag_process_hdlc(void *data, unsigned len)
{
	struct diag_hdlc_decode_type hdlc;
	int ret, type = 0;
#ifdef DIAG_DEBUG
	int i;
#endif

	pr_debug("diag: HDLC decode fn, len of data  %d\n", len);
	hdlc.dest_ptr = driver->hdlc_buf;
	hdlc.dest_size = USB_MAX_OUT_BUF;
	hdlc.src_ptr = data;
	hdlc.src_size = len;
	hdlc.src_idx = 0;
	hdlc.dest_idx = 0;
	hdlc.escaping = 0;

	ret = diag_hdlc_decode(&hdlc);

	if (ret)
		type = diag_process_apps_pkt(driver->hdlc_buf,
							  hdlc.dest_idx - 3);
	else if (driver->debug_flag) {
		printk(KERN_ERR "Packet dropped due to bad HDLC coding/CRC"
				" errors or partial packet received, packet"
				" length = %d\n", len);
		print_hex_dump(KERN_DEBUG, "Dropped Packet Data: ", 16, 1,
					   DUMP_PREFIX_ADDRESS, data, len, 1);
		driver->debug_flag = 0;
	}
	/* send error responses from APPS for Central Routing */
	if (type == 1 && chk_config_get_id() == AO8960_TOOLS_ID) {
		diag_send_error_rsp(hdlc.dest_idx);
		type = 0;
	}
	/* implies this packet is NOT meant for apps */
	if (!(driver->ch) && type == 1) {
		if (chk_config_get_id() == AO8960_TOOLS_ID) {
			diag_send_error_rsp(hdlc.dest_idx);
		} else { /* APQ 8060, Let Q6 respond */
			if (driver->chqdsp)
				smd_write(driver->chqdsp, driver->hdlc_buf,
						  hdlc.dest_idx - 3);
		}
		type = 0;
	}

#ifdef DIAG_DEBUG
	pr_debug("diag: hdlc.dest_idx = %d", hdlc.dest_idx);
	for (i = 0; i < hdlc.dest_idx; i++)
		printk(KERN_DEBUG "\t%x", *(((unsigned char *)
							driver->hdlc_buf)+i));
#endif /* DIAG DEBUG */
	/* ignore 2 bytes for CRC, one for 7E and send */
	if ((driver->ch) && (ret) && (type) && (hdlc.dest_idx > 3)) {
		APPEND_DEBUG('g');
#ifdef CONFIG_MODEM_DIAG_MASTER
		smd_write(driver->ch, data, len);
#else
		smd_write(driver->ch, driver->hdlc_buf, hdlc.dest_idx - 3);
#endif
		APPEND_DEBUG('h');
#ifdef DIAG_DEBUG
		printk(KERN_INFO "writing data to SMD, pkt length %d\n", len);
		print_hex_dump(KERN_DEBUG, "Written Packet Data to SMD: ", 16,
			       1, DUMP_PREFIX_ADDRESS, data, len, 1);
#endif /* DIAG DEBUG */
	}
}