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; } }
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_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 int smd_tty_dummy_probe(struct platform_device *pdev) { int n; int idx; for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) { idx = smd_configs[n].tty_dev_index; if (!smd_configs[n].dev_name) continue; if (pdev->id == smd_configs[n].edge && !strncmp(pdev->name, smd_configs[n].dev_name, SMD_MAX_CH_NAME_LEN)) { complete_all(&smd_tty[idx].ch_allocated); return 0; } } SMD_TTY_ERR("[ERR]%s: unknown device '%s'\n", __func__, pdev->name); return -ENODEV; }
static int __init smd_tty_init(void) { int ret; int n; int idx; struct tty_port *port; smd_tty_log_init(); smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); if (smd_tty_driver == 0) { SMD_TTY_ERR("%s - Driver allocation failed", __func__); return -ENOMEM; } smd_tty_driver->owner = THIS_MODULE; smd_tty_driver->driver_name = "smd_tty_driver"; smd_tty_driver->name = "smd"; smd_tty_driver->major = 0; smd_tty_driver->minor_start = 0; smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; smd_tty_driver->subtype = SERIAL_TYPE_NORMAL; smd_tty_driver->init_termios = tty_std_termios; smd_tty_driver->init_termios.c_iflag = 0; smd_tty_driver->init_termios.c_oflag = 0; smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; smd_tty_driver->init_termios.c_lflag = 0; smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(smd_tty_driver, &smd_tty_ops); ret = tty_register_driver(smd_tty_driver); if (ret) { put_tty_driver(smd_tty_driver); SMD_TTY_ERR("%s: driver registration failed %d", __func__, ret); return ret; } for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) { idx = smd_configs[n].tty_dev_index; if (smd_configs[n].dev_name == NULL) smd_configs[n].dev_name = smd_configs[n].port_name; if (idx == DS_IDX) { /* * DS port uses the kernel API starting with * 8660 Fusion. Only register the userspace * platform device for older targets. */ int legacy_ds = 0; legacy_ds |= cpu_is_msm7x01() || cpu_is_msm7x25(); legacy_ds |= cpu_is_msm7x27() || cpu_is_msm7x30(); legacy_ds |= cpu_is_qsd8x50() || cpu_is_msm8x55(); /* * use legacy mode for 8660 Standalone (subtype 0) */ legacy_ds |= cpu_is_msm8x60() && (socinfo_get_platform_subtype() == 0x0); #ifdef CONFIG_MSM_SMD_TTY_DS_LEGACY legacy_ds |= cpu_is_msm8974(); #endif if (!legacy_ds) continue; } port = &smd_tty[idx].port; tty_port_init(port); port->ops = &smd_tty_port_ops; /* TODO: For kernel >= 3.7 use tty_port_register_device */ smd_tty[idx].device_ptr = tty_register_device(smd_tty_driver, idx, 0); if (device_create_file(smd_tty[idx].device_ptr, &dev_attr_open_timeout)) SMD_TTY_ERR( "%s: Unable to create device attributes for %s", __func__, smd_configs[n].port_name); init_completion(&smd_tty[idx].ch_allocated); /* register platform device */ smd_tty[idx].driver.probe = smd_tty_dummy_probe; #ifdef CONFIG_MSM_SMD_TTY_DS_LEGACY if (idx == DS_IDX) { /* register platform device for DS */ smd_tty[idx].driver.probe = smd_tty_ds_probe; smd_tty[idx].is_dsmodem_ready = 0; } #endif smd_tty[idx].driver.driver.name = smd_configs[n].dev_name; smd_tty[idx].driver.driver.owner = THIS_MODULE; spin_lock_init(&smd_tty[idx].reset_lock); spin_lock_init(&smd_tty[idx].ra_lock); smd_tty[idx].is_open = 0; setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry, (unsigned long)&smd_tty[idx]); init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue); ret = platform_driver_register(&smd_tty[idx].driver); if (ret) { SMD_TTY_ERR( "%s: init failed %d (%d)", __func__, idx, ret); smd_tty[idx].driver.probe = NULL; goto out; } smd_tty[idx].smd = &smd_configs[n]; } INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker); return 0; out: /* unregister platform devices */ for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) { idx = smd_configs[n].tty_dev_index; if (smd_tty[idx].driver.probe) { platform_driver_unregister(&smd_tty[idx].driver); tty_unregister_device(smd_tty_driver, idx); } } tty_unregister_driver(smd_tty_driver); put_tty_driver(smd_tty_driver); return ret; }