static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct cardstate *cs = dev_get_drvdata(dev); long int value; char *end; value = simple_strtol(buf, &end, 0); while (*end) if (!isspace(*end++)) return -EINVAL; if (value < 0 || value > 1) return -EINVAL; if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE, NULL, value, NULL)) { cs->waiting = 0; mutex_unlock(&cs->mutex); return -ENOMEM; } gig_dbg(DEBUG_CMD, "scheduling PROC_CIDMODE"); gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); mutex_unlock(&cs->mutex); return count; }
static int if_version(struct cardstate *cs, unsigned arg[4]) { static const unsigned version[4] = GIG_VERSION; static const unsigned compat[4] = GIG_COMPAT; unsigned cmd = arg[0]; gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd); switch (cmd) { case GIGVER_DRIVER: memcpy(arg, version, sizeof version); return 0; case GIGVER_COMPAT: memcpy(arg, compat, sizeof compat); return 0; case GIGVER_FWBASE: cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER, NULL, 0, arg)) { cs->waiting = 0; return -ENOMEM; } gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); if (cs->cmd_result >= 0) return 0; return cs->cmd_result; default: return -EINVAL; } }
/** * gigaset_read_int_callback * * It is called if the data was received from the device. */ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs) { struct inbuf_t *inbuf = urb->context; struct cardstate *cs = inbuf->cs; int resubmit = 0; int r; unsigned numbytes; unsigned char *src; unsigned long flags; if (!urb->status) { if (!cs->connected) { err("%s: disconnected", __func__); /* should never happen */ return; } numbytes = urb->actual_length; if (numbytes) { src = inbuf->rcvbuf; if (unlikely(*src)) dev_warn(cs->dev, "%s: There was no leading 0, but 0x%02x!\n", __func__, (unsigned) *src); ++src; /* skip leading 0x00 */ --numbytes; if (gigaset_fill_inbuf(inbuf, src, numbytes)) { gig_dbg(DEBUG_INTR, "%s-->BH", __func__); gigaset_schedule_event(inbuf->cs); } } else gig_dbg(DEBUG_INTR, "Received zero block length"); resubmit = 1; } else { /* The urb might have been killed. */ gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d", __func__, urb->status); if (urb->status != -ENOENT) { /* not killed */ if (!cs->connected) { err("%s: disconnected", __func__); /* should never happen */ return; } resubmit = 1; } } if (resubmit) { spin_lock_irqsave(&cs->lock, flags); r = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; spin_unlock_irqrestore(&cs->lock, flags); if (r) dev_err(cs->dev, "error %d when resubmitting urb.\n", -r); } }
/* * Interrupt Input URB completion routine */ static void gigaset_read_int_callback(struct urb *urb) { struct cardstate *cs = urb->context; struct inbuf_t *inbuf = cs->inbuf; int status = urb->status; int r; unsigned numbytes; unsigned char *src; unsigned long flags; if (!status) { numbytes = urb->actual_length; if (numbytes) { src = cs->hw.usb->rcvbuf; if (unlikely(*src)) dev_warn(cs->dev, "%s: There was no leading 0, but 0x%02x!\n", __func__, (unsigned) *src); ++src; /* skip leading 0x00 */ --numbytes; if (gigaset_fill_inbuf(inbuf, src, numbytes)) { gig_dbg(DEBUG_INTR, "%s-->BH", __func__); gigaset_schedule_event(inbuf->cs); } } else gig_dbg(DEBUG_INTR, "Received zero block length"); } else { /* The urb might have been killed. */ gig_dbg(DEBUG_ANY, "%s - nonzero status received: %d", __func__, status); if (status == -ENOENT || status == -ESHUTDOWN) /* killed or endpoint shutdown: don't resubmit */ return; } /* resubmit URB */ spin_lock_irqsave(&cs->lock, flags); if (!cs->connected) { spin_unlock_irqrestore(&cs->lock, flags); pr_err("%s: disconnected\n", __func__); return; } r = usb_submit_urb(urb, GFP_ATOMIC); spin_unlock_irqrestore(&cs->lock, flags); if (r) dev_err(cs->dev, "error %d resubmitting URB\n", -r); }
static int if_lock(struct cardstate *cs, int *arg) { int cmd = *arg; gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd); if (cmd > 1) return -EINVAL; if (cmd < 0) { *arg = cs->mstate == MS_LOCKED; return 0; } if (!cmd && cs->mstate == MS_LOCKED && cs->connected) { cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); cs->ops->baud_rate(cs, B115200); cs->ops->set_line_ctrl(cs, CS8); cs->control_state = TIOCM_DTR|TIOCM_RTS; } cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK, NULL, cmd, NULL)) { cs->waiting = 0; return -ENOMEM; } gig_dbg(DEBUG_CMD, "scheduling IF_LOCK"); gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); if (cs->cmd_result >= 0) { *arg = cs->cmd_result; return 0; } return cs->cmd_result; }