int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
			struct diag_md_session_t *info)
{
	int i, j;
	int err = 0;
	int ret = *pret;
	int num_data = 0;
	int remote_token;
	unsigned long flags;
	struct diag_md_info *ch = NULL;
	struct diag_buf_tbl_t *entry = NULL;
	uint8_t drain_again = 0;
	uint8_t peripheral = 0;
	struct diag_md_session_t *session_info = NULL;

	for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) {
		ch = &diag_md[i];
		for (j = 0; j < ch->num_tbl_entries && !err; j++) {
			entry = &ch->tbl[j];
			if (entry->len <= 0)
				continue;
			peripheral = GET_BUF_PERIPHERAL(entry->ctx);
			
			if (peripheral > NUM_PERIPHERALS)
				goto drop_data;
			session_info =
			diag_md_session_get_peripheral(peripheral);
			if (session_info && info &&
				(session_info->pid != info->pid))
				continue;
			if ((info && (info->peripheral_mask &
			    MD_PERIPHERAL_MASK(peripheral)) == 0))
				goto drop_data;
			if (i > 0) {
				if ((ret + (3 * sizeof(int)) + entry->len) >=
							buf_size) {
					drain_again = 1;
					break;
				}
			} else {
				if ((ret + (2 * sizeof(int)) + entry->len) >=
						buf_size) {
					drain_again = 1;
					break;
				}
			}
			if (i > 0) {
				remote_token = diag_get_remote(i);
				err = copy_to_user(buf + ret, &remote_token,
						   sizeof(int));
				if (err)
					goto drop_data;
				ret += sizeof(int);
			}

			
			err = copy_to_user(buf + ret, (void *)&(entry->len),
					   sizeof(int));
			if (err)
				goto drop_data;
			ret += sizeof(int);

			
			err = copy_to_user(buf + ret, (void *)entry->buf,
					   entry->len);
			if (err)
				goto drop_data;
			ret += entry->len;

			num_data++;
drop_data:
			spin_lock_irqsave(&ch->lock, flags);
			if (ch->ops && ch->ops->write_done)
				ch->ops->write_done(entry->buf, entry->len,
						    entry->ctx,
						    DIAG_MEMORY_DEVICE_MODE);
			diag_ws_on_copy(DIAG_WS_MUX);
			entry->buf = NULL;
			entry->len = 0;
			entry->ctx = 0;
			spin_unlock_irqrestore(&ch->lock, flags);
		}
	}

	*pret = ret;
	err = copy_to_user(buf + sizeof(int), (void *)&num_data, sizeof(int));
	diag_ws_on_copy_complete(DIAG_WS_MUX);
	if (drain_again)
		chk_logging_wakeup();

	return err;
}
Exemplo n.º 2
0
void diag_smd_send_req(struct diag_smd_info *smd_info)
{
	void *buf = NULL, *temp_buf = NULL;
	int total_recd = 0, r = 0, pkt_len;
	int loop_count = 0;
	int notify = 0;

	if (!smd_info) {
		pr_err("diag: In %s, no smd info. Not able to read.\n",
			__func__);
		return;
	}

	if (!smd_info->in_busy_1)
		buf = smd_info->buf_in_1;
	else if ((smd_info->type == SMD_DATA_TYPE) && !smd_info->in_busy_2)
		buf = smd_info->buf_in_2;

	if (smd_info->ch && buf) {
		temp_buf = buf;
		pkt_len = smd_cur_packet_size(smd_info->ch);

		while (pkt_len && (pkt_len != total_recd)) {
			loop_count++;
			r = smd_read_avail(smd_info->ch);
			pr_debug("diag: In %s, received pkt %d %d\n",
				__func__, r, total_recd);
			if (!r) {
				/* Nothing to read from SMD */
				wait_event(driver->smd_wait_q,
					((smd_info->ch == 0) ||
					smd_read_avail(smd_info->ch)));
				/* If the smd channel is open */
				if (smd_info->ch) {
					pr_debug("diag: In %s, return from wait_event\n",
						__func__);
					continue;
				} else {
					pr_debug("diag: In %s, return from wait_event ch closed\n",
						__func__);
					return;
				}
			}
			total_recd += r;
			if (total_recd > IN_BUF_SIZE) {
				if (total_recd < MAX_IN_BUF_SIZE) {
					pr_err("diag: In %s, SMD sending in packets up to %d bytes\n",
						__func__, total_recd);
					buf = krealloc(buf, total_recd,
						GFP_KERNEL);
				} else {
					pr_err("diag: In %s, SMD sending in packets more than %d bytes\n",
						__func__, MAX_IN_BUF_SIZE);
					return;
				}
			}
			if (pkt_len < r) {
				pr_err("diag: In %s, SMD sending incorrect pkt\n",
					__func__);
				return;
			}
			if (pkt_len > r) {
				pr_err("diag: In %s, SMD sending partial pkt %d %d %d %d %d %d\n",
				__func__, pkt_len, r, total_recd, loop_count,
				smd_info->peripheral, smd_info->type);
			}

			/* keep reading for complete packet */
			smd_read(smd_info->ch, temp_buf, r);
			temp_buf += r;
		}

		if (total_recd > 0) {
			if (!buf) {
				pr_err("diag: Out of diagmem for Modem\n");
			} else if (smd_info->process_smd_read_data) {
				notify = smd_info->process_smd_read_data(
						smd_info, buf, total_recd);
				/* Poll SMD channels to check for data */
				if (notify)
					diag_smd_notify(smd_info,
							SMD_EVENT_DATA);
			}
		}
	} else if (smd_info->ch && !buf &&
		(driver->logging_mode == MEMORY_DEVICE_MODE)) {
			chk_logging_wakeup();
	}
}