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; return smd_write(info->ch, buf, len); }
static void smd_tty_read(unsigned long param) { unsigned char *ptr; int avail; struct smd_tty_info *info = (struct smd_tty_info *)param; struct tty_struct *tty = tty_port_tty_get(&info->port); unsigned long flags; if (!tty) return; for (;;) { if (is_in_reset(info)) { /* signal TTY clients using TTY_BREAK */ tty_insert_flip_char(tty, 0x00, TTY_BREAK); tty_flip_buffer_push(tty); break; } if (test_bit(TTY_THROTTLED, &tty->flags)) break; spin_lock_irqsave(&info->ra_lock, flags); avail = smd_read_avail(info->ch); if (avail == 0) { wake_unlock(&info->ra_wake_lock); spin_unlock_irqrestore(&info->ra_lock, flags); break; } spin_unlock_irqrestore(&info->ra_lock, flags); if (avail > MAX_TTY_BUF_SIZE) avail = MAX_TTY_BUF_SIZE; avail = tty_prepare_flip_string(tty, &ptr, avail); if (avail <= 0) { mod_timer(&info->buf_req_timer, jiffies + msecs_to_jiffies(30)); tty_kref_put(tty); return; } if (smd_read(info->ch, ptr, avail) != avail) { /* shouldn't be possible since we're in interrupt ** context here and nobody else could 'steal' our ** characters. */ SMD_TTY_ERR( "%s - Possible smd_tty_buffer mismatch for %s", __func__, info->ch->name); } wake_lock_timeout(&info->wake_lock, HZ / 2); tty_flip_buffer_push(tty); } /* XXX only when writable and necessary */ tty_wakeup(tty); tty_kref_put(tty); }
static void smd_tty_read(unsigned long param) { unsigned char *ptr; int avail; struct smd_tty_info *info = (struct smd_tty_info *)param; struct tty_struct *tty = info->tty; if (!tty) return; for (;;) { unsigned int n = info->tty->index; if (is_in_reset(info)) { if (n == BT_ACL_IDX || n == BT_CMD_IDX) pr_err("%s: BT_IDX read in reset %d \n", __func__, n); if ((n != BT_ACL_IDX) && (n != BT_CMD_IDX)) { /* signal TTY clients using TTY_BREAK */ tty_insert_flip_char(tty, 0x00, TTY_BREAK); tty_flip_buffer_push(tty); break; } } if (test_bit(TTY_THROTTLED, &tty->flags)) break; avail = smd_read_avail(info->ch); if (avail == 0) break; if (avail > MAX_TTY_BUF_SIZE) avail = MAX_TTY_BUF_SIZE; avail = tty_prepare_flip_string(tty, &ptr, avail); if (avail <= 0) { mod_timer(&info->buf_req_timer, jiffies + msecs_to_jiffies(30)); return; } if (smd_read(info->ch, ptr, avail) != avail) { /* shouldn't be possible since we're in interrupt ** context here and nobody else could 'steal' our ** characters. */ printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!"); } #ifdef CONFIG_HAS_WAKELOCK pr_debug("%s: lock wakelock %s\n", __func__, info->wake_lock.name); #endif wake_lock_timeout(&info->wake_lock, HZ / 2); tty_flip_buffer_push(tty); } /* XXX only when writable and necessary */ tty_wakeup(tty); }
static int hsic_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct hsic_tty_info *info = tty->driver_data; unsigned n = tty->index; struct tdata_port *port = info->dport; unsigned port_num; pr_debug("%s:#%d set(%04X), clear(%04X)\n", __func__, n, set, clear); if (is_in_reset(info)) { pr_debug("%s: is in reset\n", __func__); return -ENETRESET; } if (info->tty->index != n) { pr_debug("%s: tty(%d) and info->tty(%d) dismatch, ignore it.\n", __func__, n, info->tty->index); return 0; } port_num = info->client_port_num; /* set */ info->port_handshake_bits |= ((set & TIOCM_DTR) ? ACM_CTRL_DTR : 0) | ((set & TIOCM_RTS) ? ACM_CTRL_RTS : 0); /* clear */ info->port_handshake_bits &= ~(((clear & TIOCM_DTR) ? ACM_CTRL_DTR : 0) | ((clear & TIOCM_RTS) ? ACM_CTRL_RTS : 0)); info->notify_modem(info, port_num, info->port_handshake_bits); if ((info->port_handshake_bits & ACM_CTRL_DTR) && !(info->port_handshake_bits & ACM_CTRL_RTS)) { info->port_handshake_bits |= ACM_CTRL_RTS; info->notify_modem(info, port_num, info->port_handshake_bits); } if (!(info->port_handshake_bits & ACM_CTRL_DTR) && (info->port_handshake_bits & ACM_CTRL_RTS)) { info->port_handshake_bits &= ~ACM_CTRL_RTS; info->notify_modem(info, port_num, info->port_handshake_bits); } if (info->port_handshake_bits & (ACM_CTRL_DTR | ACM_CTRL_RTS)) { pr_debug("%s: ACM_CTRL_DTR and ACM_CTRL_RTS is set. start write_tomdm\n", __func__); spin_lock(&port->rx_lock); queue_work(port->wq, &port->write_tomdm_w); spin_unlock(&port->rx_lock); } return 0; }
static void smd_tty_read(unsigned long param) { unsigned char *ptr; int avail; struct smd_tty_info *info = (struct smd_tty_info *)param; struct tty_struct *tty = info->tty; if (!tty) return; for (;;) { if (is_in_reset(info)) { /* signal TTY clients using TTY_BREAK */ tty_insert_flip_char(tty, 0x00, TTY_BREAK); tty_flip_buffer_push(tty); break; } if (test_bit(TTY_THROTTLED, &tty->flags)) break; avail = smd_read_avail(info->ch); if (avail == 0) break; if (avail > MAX_TTY_BUF_SIZE) avail = MAX_TTY_BUF_SIZE; avail = tty_prepare_flip_string(tty, &ptr, avail); if (avail <= 0) { if (!timer_pending(&info->buf_req_timer)) { init_timer(&info->buf_req_timer); info->buf_req_timer.expires = jiffies + ((30 * HZ)/1000); info->buf_req_timer.function = buf_req_retry; info->buf_req_timer.data = param; add_timer(&info->buf_req_timer); } return; } if (smd_read(info->ch, ptr, avail) != avail) { /* shouldn't be possible since we're in interrupt ** context here and nobody else could 'steal' our ** characters. */ printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!"); } wake_lock_timeout(&info->wake_lock, HZ / 2); tty_flip_buffer_push(tty); } /* XXX only when writable and necessary */ tty_wakeup(tty); }
static void smd_tty_read(unsigned long param) { unsigned char *ptr; int avail; struct smd_tty_info *info = (struct smd_tty_info *)param; struct tty_struct *tty = info->tty; if (!tty) return; for (;;) { if (is_in_reset(info)) { tty_insert_flip_char(tty, 0x00, TTY_BREAK); tty_flip_buffer_push(tty); break; } if (test_bit(TTY_THROTTLED, &tty->flags)) break; avail = smd_read_avail(info->ch); if (avail == 0) break; if (avail > MAX_TTY_BUF_SIZE) avail = MAX_TTY_BUF_SIZE; avail = tty_prepare_flip_string(tty, &ptr, avail); if (avail <= 0) { mod_timer(&info->buf_req_timer, jiffies + msecs_to_jiffies(30)); return; } if (smd_read(info->ch, ptr, avail) != avail) { printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!"); } else { if (get_radio_flag() & 0x0008) { int i = 0; printk("[RIL]"); for (i = 0; i< avail; i++) printk("%c", *(ptr+i)); } } wake_lock_timeout(&info->wake_lock, HZ / 2); tty_flip_buffer_push(tty); } tty_wakeup(tty); }
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 hsic_tty_write(struct tty_struct *tty, const unsigned char *buf, int len) { struct hsic_tty_info *info = tty->driver_data; unsigned n = tty->index; struct tdata_port *port = info->dport; struct sk_buff *skb; pr_debug("%s:#%d\n", __func__, n); /* 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)) { pr_debug("%s: is in reset\n", __func__); return -ENETRESET; } if (info->tty->index != n) { pr_debug("%s: tty(%d) and info->tty(%d) dismatch, ignore it.\n", __func__, n, info->tty->index); return len; } skb = alloc_skb(len, GFP_ATOMIC); if(!skb) { pr_debug("%s: len alloc failed\n", __func__); return -ENOMEM; } skb->data = (unsigned char *)buf; skb->len = len; spin_lock(&port->rx_lock); __skb_queue_tail(&port->rx_skb_q, skb); if (info->port_handshake_bits & ACM_CTRL_DTR) queue_work(port->wq, &port->write_tomdm_w); spin_unlock(&port->rx_lock); return len; }
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; } }
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); }