/* Send command to device. */ static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) { unsigned long flags; gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? DEBUG_TRANSCMD : DEBUG_LOCKCMD, "CMD Transmit", cb->len, cb->buf); spin_lock_irqsave(&cs->cmdlock, flags); cb->prev = cs->lastcmdbuf; if (cs->lastcmdbuf) cs->lastcmdbuf->next = cb; else { cs->cmdbuf = cb; cs->curlen = cb->len; } cs->cmdbytes += cb->len; cs->lastcmdbuf = cb; spin_unlock_irqrestore(&cs->cmdlock, flags); spin_lock_irqsave(&cs->lock, flags); if (cs->connected) tasklet_schedule(&cs->write_tasklet); spin_unlock_irqrestore(&cs->lock, flags); return cb->len; }
/* * set the break characters on the internal serial adapter * using undocumented device commands reverse engineered from USB traces * of the Siemens Windows driver */ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) { struct usb_device *udev = cs->hw.usb->udev; gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); memcpy(cs->hw.usb->bchars, buf, 6); return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, 0, 0, &buf, 6, 2000); }
static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) { #ifdef CONFIG_GIGASET_UNDOCREQ struct usb_device *udev = cs->hw.usb->udev; gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); memcpy(cs->hw.usb->bchars, buf, 6); return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, 0, 0, &buf, 6, 2000); #else return -EINVAL; #endif }
/* Send command to device. */ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, int len, struct tasklet_struct *wake_tasklet) { struct cmdbuf_t *cb; unsigned long flags; gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? DEBUG_TRANSCMD : DEBUG_LOCKCMD, "CMD Transmit", len, buf); if (len <= 0) return 0; if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { dev_err(cs->dev, "%s: out of memory\n", __func__); return -ENOMEM; } memcpy(cb->buf, buf, len); cb->len = len; cb->offset = 0; cb->next = NULL; cb->wake_tasklet = wake_tasklet; spin_lock_irqsave(&cs->cmdlock, flags); cb->prev = cs->lastcmdbuf; if (cs->lastcmdbuf) cs->lastcmdbuf->next = cb; else { cs->cmdbuf = cb; cs->curlen = len; } cs->cmdbytes += len; cs->lastcmdbuf = cb; spin_unlock_irqrestore(&cs->cmdlock, flags); spin_lock_irqsave(&cs->lock, flags); if (cs->connected) tasklet_schedule(&cs->write_tasklet); spin_unlock_irqrestore(&cs->lock, flags); return len; }
static int if_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct cardstate *cs; int retval = -ENODEV; int int_arg; unsigned char buf[6]; unsigned version[4]; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->open_count) warn("%s: device not opened", __func__); else { retval = 0; switch (cmd) { case GIGASET_REDIR: retval = get_user(int_arg, (int __user *) arg); if (retval >= 0) retval = if_lock(cs, &int_arg); if (retval >= 0) retval = put_user(int_arg, (int __user *) arg); break; case GIGASET_CONFIG: retval = get_user(int_arg, (int __user *) arg); if (retval >= 0) retval = if_config(cs, &int_arg); if (retval >= 0) retval = put_user(int_arg, (int __user *) arg); break; case GIGASET_BRKCHARS: //FIXME test if MS_LOCKED if (!cs->connected) { gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); retval = -ENODEV; break; } retval = copy_from_user(&buf, (const unsigned char __user *) arg, 6) ? -EFAULT : 0; if (retval >= 0) { gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS", 6, (const unsigned char *) arg); retval = cs->ops->brkchars(cs, buf); } break; case GIGASET_VERSION: retval = copy_from_user(version, (unsigned __user *) arg, sizeof version) ? -EFAULT : 0; if (retval >= 0) retval = if_version(cs, version); if (retval >= 0) retval = copy_to_user((unsigned __user *) arg, version, sizeof version) ? -EFAULT : 0; break; default: gig_dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x", __func__, cmd); retval = -ENOIOCTLCMD; } } mutex_unlock(&cs->mutex); return retval; }
static int if_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct cardstate *cs = tty->driver_data; int retval = -ENODEV; int int_arg; unsigned char buf[6]; unsigned version[4]; gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; } else { retval = 0; switch (cmd) { case GIGASET_REDIR: retval = get_user(int_arg, (int __user *) arg); if (retval >= 0) retval = if_lock(cs, &int_arg); if (retval >= 0) retval = put_user(int_arg, (int __user *) arg); break; case GIGASET_CONFIG: retval = get_user(int_arg, (int __user *) arg); if (retval >= 0) retval = if_config(cs, &int_arg); if (retval >= 0) retval = put_user(int_arg, (int __user *) arg); break; case GIGASET_BRKCHARS: retval = copy_from_user(&buf, (const unsigned char __user *) arg, 6) ? -EFAULT : 0; if (retval >= 0) { gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS", 6, (const unsigned char *) arg); retval = cs->ops->brkchars(cs, buf); } break; case GIGASET_VERSION: retval = copy_from_user(version, (unsigned __user *) arg, sizeof version) ? -EFAULT : 0; if (retval >= 0) retval = if_version(cs, version); if (retval >= 0) retval = copy_to_user((unsigned __user *) arg, version, sizeof version) ? -EFAULT : 0; break; default: gig_dbg(DEBUG_IF, "%s: arg not supported - 0x%04x", __func__, cmd); retval = -ENOIOCTLCMD; } } mutex_unlock(&cs->mutex); return retval; }