Пример #1
0
static ssize_t open_timeout_store(struct device *dev,
				struct device_attribute *attr,
				const char *buf, size_t n)
{
	unsigned int num_dev;
	unsigned long wait;
	if (dev == NULL) {
		SMD_TTY_INFO("%s: Invalid Device passed", __func__);
		return -EINVAL;
	}
	for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
		if (dev == smd_tty[num_dev].device_ptr)
			break;
	}
	if (num_dev >= MAX_SMD_TTYS) {
		SMD_TTY_ERR("[%s]: Device Not found", __func__);
		return -EINVAL;
	}
	if (!kstrtoul(buf, 10, &wait)) {
		smd_tty[num_dev].open_wait = wait;
		return n;
	} else {
		SMD_TTY_INFO("[%s]: Unable to convert %s to an int",
			__func__, buf);
		return -EINVAL;
	}
}
Пример #2
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
	*/
	if (is_in_reset(info))
		return -ENETRESET;

	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;
	SMD_TTY_INFO("[WRITE]: PID %u -> port %s %x bytes",
			current->pid, info->smd->port_name, len);

	return smd_write(info->ch, buf, len);
}
Пример #3
0
static ssize_t open_timeout_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
	unsigned int num_dev;
	unsigned int open_wait;

	if (dev == NULL) {
		SMD_TTY_INFO("%s: Invalid Device passed", __func__);
		return -EINVAL;
	}
	for (num_dev = 0; num_dev < MAX_SMD_TTYS; num_dev++) {
		if (dev == smd_tty[num_dev].device_ptr)
			break;
	}
	if (num_dev >= MAX_SMD_TTYS) {
		SMD_TTY_ERR("[%s]: Device Not Found", __func__);
		return -EINVAL;
	}

	mutex_lock(&smd_tty[num_dev].open_lock_lha1);
	open_wait = smd_tty[num_dev].open_wait;
	mutex_unlock(&smd_tty[num_dev].open_lock_lha1);

	return snprintf(buf, PAGE_SIZE, "%d\n", open_wait);
}
static void smd_tty_port_shutdown(struct tty_port *tport)
{
	struct smd_tty_info *info;
	struct tty_struct *tty = tty_port_tty_get(tport);
	unsigned long flags;
#ifdef CONFIG_LGE_USES_SMD_DS_TTY
	int res = 0;
	int n = tty->index;
#endif

	info = tty->driver_data;
	if (info == 0) {
		tty_kref_put(tty);
		return;
	}

	mutex_lock(&smd_tty_lock);
	spin_lock_irqsave(&info->reset_lock, flags);
	info->is_open = 0;
	spin_unlock_irqrestore(&info->reset_lock, flags);

	tasklet_kill(&info->tty_tsklt);
	wake_lock_destroy(&info->wake_lock);
	wake_lock_destroy(&info->ra_wake_lock);

	SMD_TTY_INFO("%s with PID %u closed port %s",
			current->comm, current->pid,
			info->smd->port_name);
	tty->driver_data = NULL;
	del_timer(&info->buf_req_timer);

	smd_close(info->ch);
#ifdef CONFIG_LGE_USES_SMD_DS_TTY
	/*           
                                                       
                                                   
                                                
                                                      
                                                      
                                                  
                                                      
                                                
                                    
  */
	pr_info("%s: waiting to close smd %s completely\n",
			__func__, smd_tty[n].smd->port_name);
	/* wait for reopen ready status in seconds */
	res = wait_event_interruptible_timeout(
			info->ch_opened_wait_queue,
			!info->is_open, (lge_ds_modem_wait * HZ));
	if (res == 0) {
		/* just in case, remain result value */
		res = -ETIMEDOUT;
		pr_err("%s: timeout to wait for %s smd_close.\
				next smd_open may fail....%d\n",
				__func__, smd_tty[n].smd->port_name, res);
	}
Пример #5
0
static int smd_tty_tiocmset(struct tty_struct *tty,
				unsigned int set, unsigned int clear)
{
	struct smd_tty_info *info = tty->driver_data;

	if (info->in_reset)
		return -ENETRESET;

	SMD_TTY_INFO("PID %u --> %s Set: %x Clear: %x",
			current->pid, __func__, set, clear);
	return smd_tiocmset(info->ch, set, clear);
}
Пример #6
0
/*
 * Returns the current TIOCM status bits including:
 *      SMD Signals (DTR/DSR, CTS/RTS, CD, RI)
 *      TIOCM_OUT1 - reset state (1=in reset)
 *      TIOCM_OUT2 - reset state updated (1=updated)
 */
static int smd_tty_tiocmget(struct tty_struct *tty)
{
	struct smd_tty_info *info = tty->driver_data;
	unsigned long flags;
	int tiocm;

	tiocm = smd_tiocmget(info->ch);

	spin_lock_irqsave(&info->reset_lock, flags);
	tiocm |= (info->in_reset ? TIOCM_OUT1 : 0);
	if (info->in_reset_updated) {
		tiocm |= TIOCM_OUT2;
		info->in_reset_updated = 0;
	}
	SMD_TTY_INFO("PID %u --> %s TIOCM is %x ",
			current->pid, __func__, tiocm);
	spin_unlock_irqrestore(&info->reset_lock, flags);

	return tiocm;
}
Пример #7
0
static void smd_tty_port_shutdown(struct tty_port *tport)
{
	struct smd_tty_info *info;
	struct tty_struct *tty = tty_port_tty_get(tport);
	unsigned long flags;
#ifdef CONFIG_MSM_SMD_TTY_DS_LEGACY
	int res = 0;
	int n = tty->index;
#endif

	info = tty->driver_data;
	if (info == 0) {
		tty_kref_put(tty);
		return;
	}

	mutex_lock(&smd_tty_lock);

	spin_lock_irqsave(&info->reset_lock, flags);
	info->is_open = 0;
	spin_unlock_irqrestore(&info->reset_lock, flags);

	tasklet_kill(&info->tty_tsklt);
	wake_lock_destroy(&info->wake_lock);
	wake_lock_destroy(&info->ra_wake_lock);

	SMD_TTY_INFO("%s with PID %u closed port %s",
			current->comm, current->pid,
			info->smd->port_name);
	tty->driver_data = NULL;
	del_timer(&info->buf_req_timer);

	smd_close(info->ch);
#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).
	 */
	pr_info("%s: waiting to close smd %s completely\n",
			__func__, smd_tty[n].smd->port_name);
	/* wait for reopen ready status in seconds */
	res = wait_event_interruptible_timeout(
		info->ch_opened_wait_queue,
		!info->is_open, (smd_tty_ds_modem_wait * HZ));
	if (res <= 0) {
		/* just in case, remain result value */
		pr_err("%s: timeout to wait for %s smd_close. "
				"next smd_open may fail\n",
				__func__, smd_tty[n].smd->port_name);
	}
#endif
	info->ch = NULL;
	subsystem_put(info->pil);

	mutex_unlock(&smd_tty_lock);
	tty_kref_put(tty);
}
Пример #8
0
static int smd_tty_port_activate(struct tty_port *tport,
				 struct tty_struct *tty)
{
	int res = 0;
	unsigned int n = tty->index;
	struct smd_tty_info *info;
	const char *peripheral = NULL;


	if (n >= MAX_SMD_TTYS || !smd_tty[n].smd)
		return -ENODEV;

	info = smd_tty + n;

	mutex_lock(&smd_tty_lock);
	tty->driver_data = info;

	peripheral = smd_edge_to_subsystem(smd_tty[n].smd->edge);
	if (peripheral) {
		info->pil = subsystem_get(peripheral);
		if (IS_ERR(info->pil)) {
			SMD_TTY_INFO(
				"%s failed on smd_tty device :%s subsystem_get failed for %s",
				__func__, smd_tty[n].smd->port_name,
				peripheral);

			/*
			 * Sleep, inorder to reduce the frequency of
			 * retry by user-space modules and to avoid
			 * possible watchdog bite.
			 */
			msleep((smd_tty[n].open_wait * 1000));
			res = PTR_ERR(info->pil);
			goto out;
		}

		/* Wait for the modem SMSM to be inited for the SMD
		 * Loopback channel to be allocated at the modem. Since
		 * the wait need to be done atmost once, using msleep
		 * doesn't degrade the performance.
		 */
		if (n == LOOPBACK_IDX) {
			if (!is_modem_smsm_inited())
				msleep(5000);
			smsm_change_state(SMSM_APPS_STATE,
					  0, SMSM_SMD_LOOPBACK);
			msleep(100);
		}

		/*
		 * Wait for a channel to be allocated so we know
		 * the modem is ready enough.
		 */
		if (smd_tty[n].open_wait) {
			res = wait_for_completion_interruptible_timeout(
					&info->ch_allocated,
					msecs_to_jiffies(smd_tty[n].open_wait *
									1000));

			if (res == 0) {
				SMD_TTY_INFO(
					"Timed out waiting for SMD channel %s",
					smd_tty[n].smd->port_name);
				res = -ETIMEDOUT;
				goto release_pil;
			} else if (res < 0) {
				SMD_TTY_INFO(
					"Error waiting for SMD channel %s : %d\n",
					smd_tty[n].smd->port_name, res);
				goto release_pil;
			}
#ifdef CONFIG_MSM_SMD_TTY_DS_LEGACY
			/*
			 * on boot, process tried to open smd0 sleeps until
			 * modem is ready or timeout.
			 */
			if (n == DS_IDX) {
				/* wait for open ready status in seconds */
				pr_info("%s: checking DS modem status\n", __func__);
				res = wait_event_interruptible_timeout(
						info->ch_opened_wait_queue,
						info->is_dsmodem_ready,
						(smd_tty_ds_modem_wait * HZ));
				if (!res) {
					res = -ETIMEDOUT;
					pr_err("%s: timeout to wait for %s modem: %d\n",
							__func__,
							smd_tty[n].smd->port_name,
							res);
					goto release_pil;
				} else if (res < 0) {
					pr_err("%s: Error waiting for %s modem: %d\n",
							__func__,
							smd_tty[n].smd->port_name,
							res);
					goto release_pil;
				}
				pr_info("%s: DS modem is OK, open smd0..\n",
						__func__);
			}
#endif
		}
	}

	tasklet_init(&info->tty_tsklt, smd_tty_read, (unsigned long)info);
	wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND,
			smd_tty[n].smd->port_name);
	scnprintf(info->ra_wake_lock_name, MAX_RA_WAKE_LOCK_NAME_LEN,
		  "SMD_TTY_%s_RA", smd_tty[n].smd->port_name);
	wake_lock_init(&info->ra_wake_lock, WAKE_LOCK_SUSPEND,
			info->ra_wake_lock_name);

	res = smd_named_open_on_edge(smd_tty[n].smd->port_name,
				     smd_tty[n].smd->edge, &info->ch, info,
				     smd_tty_notify);
	if (res < 0) {
		SMD_TTY_INFO("%s: %s open failed %d\n",
			      __func__, smd_tty[n].smd->port_name, res);
		goto release_wl_tl;
	}

	res = wait_event_interruptible_timeout(info->ch_opened_wait_queue,
					       info->is_open, (2 * HZ));
	if (res == 0)
		res = -ETIMEDOUT;
	if (res < 0) {
		SMD_TTY_INFO("%s: wait for %s smd_open failed %d\n",
			      __func__, smd_tty[n].smd->port_name, res);
		goto close_ch;
	}
	SMD_TTY_INFO("%s with PID %u opened port %s",
		      current->comm, current->pid, smd_tty[n].smd->port_name);
	smd_disable_read_intr(info->ch);
	mutex_unlock(&smd_tty_lock);
	return 0;

close_ch:
	smd_close(info->ch);
	info->ch = NULL;

release_wl_tl:
	tasklet_kill(&info->tty_tsklt);
	wake_lock_destroy(&info->wake_lock);
	wake_lock_destroy(&info->ra_wake_lock);

release_pil:
	subsystem_put(info->pil);
out:
	mutex_unlock(&smd_tty_lock);

	return res;
}