static int if_chars_in_buffer(struct tty_struct *tty) { struct cardstate *cs; int retval = 0; cs = (struct cardstate *) tty->driver_data; if (!cs) { pr_err("%s: no cardstate\n", __func__); return 0; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); else if (!cs->open_count) dev_warn(cs->dev, "%s: device not opened\n", __func__); else if (cs->mstate != MS_LOCKED) dev_warn(cs->dev, "can't write to unlocked device\n"); else retval = cs->ops->chars_in_buffer(cs); mutex_unlock(&cs->mutex); return retval; }
static void if_close(struct tty_struct *tty, struct file *filp) { struct cardstate *cs; unsigned long flags; cs = (struct cardstate *) tty->driver_data; if (!cs) { pr_err("%s: no cardstate\n", __func__); return; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ else if (!cs->open_count) dev_warn(cs->dev, "%s: device not opened\n", __func__); else { if (!--cs->open_count) { spin_lock_irqsave(&cs->lock, flags); cs->tty = NULL; spin_unlock_irqrestore(&cs->lock, flags); } } mutex_unlock(&cs->mutex); module_put(cs->driver->owner); }
static int if_write_room(struct tty_struct *tty) { struct cardstate *cs; int retval = -ENODEV; cs = (struct cardstate *) tty->driver_data; if (!cs) { pr_err("%s: no cardstate\n", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; } else if (!cs->open_count) dev_warn(cs->dev, "%s: device not opened\n", __func__); else if (cs->mstate != MS_LOCKED) { dev_warn(cs->dev, "can't write to unlocked device\n"); retval = -EBUSY; } else retval = cs->ops->write_room(cs); mutex_unlock(&cs->mutex); return retval; }
static int if_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { struct cardstate *cs; int retval; unsigned mc; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)", cs->minor_index, __func__, set, clear); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->connected) { gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); retval = -ENODEV; } else { mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR); retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc); cs->control_state = mc; } mutex_unlock(&cs->mutex); return retval; }
static int if_chars_in_buffer(struct tty_struct *tty) { struct cardstate *cs; int retval = -ENODEV; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->open_count) warn("%s: device not opened", __func__); else if (cs->mstate != MS_LOCKED) { warn("can't write to unlocked device"); retval = -EBUSY; } else if (!cs->connected) { gig_dbg(DEBUG_ANY, "can't write to unplugged device"); retval = -EBUSY; //FIXME } else retval = cs->ops->chars_in_buffer(cs); mutex_unlock(&cs->mutex); return retval; }
static int if_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct cardstate *cs = tty->driver_data; int retval; unsigned mc; gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)", cs->minor_index, __func__, set, clear); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; } else { mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR); retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc); cs->control_state = mc; } mutex_unlock(&cs->mutex); return retval; }
static inline void dump_bytes(enum debuglevel level, const char *tag, unsigned char *bytes, int count) { #ifdef CONFIG_GIGASET_DEBUG unsigned char c; static char dbgline[3 * 32 + 1]; int i = 0; if (!(gigaset_debuglevel & level)) return; while (count-- > 0) { if (i > sizeof(dbgline) - 4) { dbgline[i] = '\0'; gig_dbg(level, "%s:%s", tag, dbgline); i = 0; } c = *bytes++; dbgline[i] = (i && !(i % 12)) ? '-' : ' '; i++; dbgline[i++] = hex_asc_hi(c); dbgline[i++] = hex_asc_lo(c); } dbgline[i] = '\0'; gig_dbg(level, "%s:%s", tag, dbgline); #endif }
static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct cardstate *cs; int retval = -ENODEV; cs = (struct cardstate *) tty->driver_data; if (!cs) { pr_err("%s: no cardstate\n", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; } else if (!cs->open_count) dev_warn(cs->dev, "%s: device not opened\n", __func__); else if (cs->mstate != MS_LOCKED) { dev_warn(cs->dev, "can't write to unlocked device\n"); retval = -EBUSY; } else { retval = cs->ops->write_cmd(cs, buf, count, &cs->if_wake_tasklet); } mutex_unlock(&cs->mutex); return retval; }
static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) { struct cmdbuf_t *tcb; unsigned long flags; int count; int status = -ENOENT; // FIXME struct usb_cardstate *ucs = cs->hw.usb; do { if (!cb->len) { tcb = cb; spin_lock_irqsave(&cs->cmdlock, flags); cs->cmdbytes -= cs->curlen; gig_dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left", cs->curlen, cs->cmdbytes); cs->cmdbuf = cb = cb->next; if (cb) { cb->prev = NULL; cs->curlen = cb->len; } else { cs->lastcmdbuf = NULL; cs->curlen = 0; } spin_unlock_irqrestore(&cs->cmdlock, flags); if (tcb->wake_tasklet) tasklet_schedule(tcb->wake_tasklet); kfree(tcb); } if (cb) { count = min(cb->len, ucs->bulk_out_size); gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count); usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, usb_sndbulkpipe(ucs->udev, ucs->bulk_out_endpointAddr & 0x0f), cb->buf + cb->offset, count, gigaset_write_bulk_callback, cs); cb->offset += count; cb->len -= count; ucs->busy = 1; spin_lock_irqsave(&cs->lock, flags); status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV; spin_unlock_irqrestore(&cs->lock, flags); if (status) { ucs->busy = 0; err("could not submit urb (error %d)\n", -status); cb->len = 0; /* skip urb => remove cb+wakeup in next loop cycle */ } } } while (cb && status); /* next command on error */ return status; }
static void start_accept(struct at_state_t *at_state) { struct cardstate *cs = at_state->cs; struct bc_state *bcs = at_state->bcs; int i; for (i = 0; i < AT_NUM; ++i) { kfree(bcs->commands[i]); bcs->commands[i] = NULL; } bcs->commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC); bcs->commands[AT_ISO] = kmalloc(9, GFP_ATOMIC); if (!bcs->commands[AT_PROTO] || !bcs->commands[AT_ISO]) { dev_err(at_state->cs->dev, "out of memory\n"); /* error reset */ at_state->pending_commands |= PC_HUP; gig_dbg(DEBUG_EVENT, "Scheduling PC_HUP"); cs->commands_pending = 1; return; } snprintf(bcs->commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2); snprintf(bcs->commands[AT_ISO], 9, "^SISO=%u\r", bcs->channel + 1); at_state->pending_commands |= PC_ACCEPT; gig_dbg(DEBUG_EVENT, "Scheduling PC_ACCEPT"); cs->commands_pending = 1; }
/* Send data from current skb to the device. */ static int write_modem(struct cardstate *cs) { int ret = 0; int count; struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ struct usb_cardstate *ucs = cs->hw.usb; unsigned long flags; gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len); if (!bcs->tx_skb->len) { dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; return -EINVAL; } /* Copy data to bulk out buffer and // FIXME copying not necessary * transmit data */ count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count); skb_pull(bcs->tx_skb, count); ucs->busy = 1; gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); spin_lock_irqsave(&cs->lock, flags); if (cs->connected) { usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, usb_sndbulkpipe(ucs->udev, ucs->bulk_out_endpointAddr & 0x0f), ucs->bulk_out_buffer, count, gigaset_write_bulk_callback, cs); ret = usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC); } else { ret = -ENODEV; } spin_unlock_irqrestore(&cs->lock, flags); if (ret) { err("could not submit urb (error %d)\n", -ret); ucs->busy = 0; } if (!bcs->tx_skb->len) { /* skb sent completely */ gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0? gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!", (unsigned long) bcs->tx_skb); dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } return ret; }
/** * 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); } }
static void schedule_init(struct cardstate *cs, int state) { if (cs->at_state.pending_commands & PC_INIT) { gig_dbg(DEBUG_EVENT, "not scheduling PC_INIT again"); return; } cs->mstate = state; cs->mode = M_UNKNOWN; gigaset_block_channels(cs); cs->at_state.pending_commands |= PC_INIT; gig_dbg(DEBUG_EVENT, "Scheduling PC_INIT"); cs->commands_pending = 1; }
static void if_unthrottle(struct tty_struct *tty) { struct cardstate *cs = tty->driver_data; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ else gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); mutex_unlock(&cs->mutex); }
/* * 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 void if_close(struct tty_struct *tty, struct file *filp) { struct cardstate *cs; unsigned long flags; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->open_count) warn("%s: device not opened", __func__); else { if (!--cs->open_count) { spin_lock_irqsave(&cs->lock, flags); cs->tty = NULL; spin_unlock_irqrestore(&cs->lock, flags); } } mutex_unlock(&cs->mutex); module_put(cs->driver->owner); }
static int if_open(struct tty_struct *tty, struct file *filp) { struct cardstate *cs; unsigned long flags; gig_dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index, __func__); tty->driver_data = NULL; cs = gigaset_get_cs_by_tty(tty); if (!cs || !try_module_get(cs->driver->owner)) return -ENODEV; if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? tty->driver_data = cs; ++cs->open_count; if (cs->open_count == 1) { spin_lock_irqsave(&cs->lock, flags); cs->tty = tty; spin_unlock_irqrestore(&cs->lock, flags); tty->low_latency = 1; //FIXME test } mutex_unlock(&cs->mutex); return 0; }
/* This callback routine is called when data was transmitted to the device. */ static void gigaset_write_bulk_callback(struct urb *urb) { struct cardstate *cs = urb->context; int status = urb->status; unsigned long flags; switch (status) { case 0: /* normal completion */ break; case -ENOENT: /* killed */ gig_dbg(DEBUG_ANY, "%s: killed", __func__); cs->hw.usb->busy = 0; return; default: dev_err(cs->dev, "bulk transfer failed (status %d)\n", -status); /* That's all we can do. Communication problems are handled by timeouts or network protocols. */ } spin_lock_irqsave(&cs->lock, flags); if (!cs->connected) { pr_err("%s: disconnected\n", __func__); } else { cs->hw.usb->busy = 0; tasklet_schedule(&cs->write_tasklet); } spin_unlock_irqrestore(&cs->lock, flags); }
/* * Set M105 configuration value * using undocumented device commands reverse engineered from USB traces * of the Siemens Windows driver */ static int set_value(struct cardstate *cs, u8 req, u16 val) { struct usb_device *udev = cs->hw.usb->udev; int r, r2; gig_dbg(DEBUG_USBREQ, "request %02x (%04x)", (unsigned)req, (unsigned)val); r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x12, 0x41, 0xf /*?*/, 0, NULL, 0, 2000 /*?*/); /* no idea what this does */ if (r < 0) { dev_err(&udev->dev, "error %d on request 0x12\n", -r); return r; } r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), req, 0x41, val, 0, NULL, 0, 2000 /*?*/); if (r < 0) dev_err(&udev->dev, "error %d on request 0x%02x\n", -r, (unsigned)req); r2 = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, 0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/); if (r2 < 0) dev_err(&udev->dev, "error %d on request 0x19\n", -r2); return r < 0 ? r : (r2 < 0 ? r2 : 0); }
/* disconnect * process closing of connection associated with given AT state structure */ static void disconnect(struct at_state_t **at_state_p) { unsigned long flags; struct bc_state *bcs = (*at_state_p)->bcs; struct cardstate *cs = (*at_state_p)->cs; spin_lock_irqsave(&cs->lock, flags); ++(*at_state_p)->seq_index; /* revert to selected idle mode */ if (!cs->cidmode) { cs->at_state.pending_commands |= PC_UMMODE; gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE"); cs->commands_pending = 1; } spin_unlock_irqrestore(&cs->lock, flags); if (bcs) { /* B channel assigned: invoke hardware specific handler */ cs->ops->close_bchannel(bcs); /* notify LL */ if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) { bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL); gigaset_isdn_hupD(bcs); } } else { /* no B channel assigned: just deallocate */ spin_lock_irqsave(&cs->lock, flags); list_del(&(*at_state_p)->list); kfree(*at_state_p); *at_state_p = NULL; spin_unlock_irqrestore(&cs->lock, flags); } }
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; } }
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_open(struct tty_struct *tty, struct file *filp) { struct cardstate *cs; gig_dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index, __func__); cs = gigaset_get_cs_by_tty(tty); if (!cs || !try_module_get(cs->driver->owner)) return -ENODEV; if (mutex_lock_interruptible(&cs->mutex)) { module_put(cs->driver->owner); return -ERESTARTSYS; } tty->driver_data = cs; ++cs->port.count; if (cs->port.count == 1) { tty_port_tty_set(&cs->port, tty); tty->low_latency = 1; } mutex_unlock(&cs->mutex); return 0; }
/* * Get integer from char-pointer */ static int isdn_gethex(char *p) { int v = 0; int c; gig_dbg(DEBUG_TRANSCMD, "string: %s", p); if (!*p) return -1; do { if (v > (INT_MAX - 15) / 16) return -1; c = *p; if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'a' && c <= 'f') c -= 'a' - 10; else if (c >= 'A' && c <= 'F') c -= 'A' - 10; else return -1; v = v * 16 + c; } while (*++p); return v; }
static void gigaset_write_bulk_callback(struct urb *urb) { struct cardstate *cs = urb->context; int status = urb->status; unsigned long flags; switch (status) { case 0: break; case -ENOENT: gig_dbg(DEBUG_ANY, "%s: killed", __func__); cs->hw.usb->busy = 0; return; default: dev_err(cs->dev, "bulk transfer failed (status %d)\n", -status); } spin_lock_irqsave(&cs->lock, flags); if (!cs->connected) { pr_err("%s: disconnected\n", __func__); } else { cs->hw.usb->busy = 0; tasklet_schedule(&cs->write_tasklet); } spin_unlock_irqrestore(&cs->lock, flags); }
/* queue event with CID */ static void add_cid_event(struct cardstate *cs, int cid, int type, void *ptr, int parameter) { unsigned long flags; unsigned next, tail; struct event_t *event; gig_dbg(DEBUG_EVENT, "queueing event %d for cid %d", type, cid); spin_lock_irqsave(&cs->ev_lock, flags); tail = cs->ev_tail; next = (tail + 1) % MAX_EVENTS; if (unlikely(next == cs->ev_head)) { dev_err(cs->dev, "event queue full\n"); kfree(ptr); } else { event = cs->events + tail; event->type = type; event->cid = cid; event->ptr = ptr; event->arg = NULL; event->parameter = parameter; event->at_state = NULL; cs->ev_tail = next; } spin_unlock_irqrestore(&cs->ev_lock, flags); }
/* disconnect_bc * process closing of connection associated with given AT state structure * and B channel */ static void disconnect_bc(struct at_state_t *at_state, struct cardstate *cs, struct bc_state *bcs) { unsigned long flags; spin_lock_irqsave(&cs->lock, flags); ++at_state->seq_index; /* revert to selected idle mode */ if (!cs->cidmode) { cs->at_state.pending_commands |= PC_UMMODE; gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE"); cs->commands_pending = 1; } spin_unlock_irqrestore(&cs->lock, flags); /* invoke hardware specific handler */ cs->ops->close_bchannel(bcs); /* notify LL */ if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) { bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL); gigaset_isdn_hupD(bcs); } }
/* free sysfs for device */ void gigaset_free_dev_sysfs(struct cardstate *cs) { if (!cs->tty_dev) return; gig_dbg(DEBUG_INIT, "removing sysfs entries"); device_remove_file(cs->tty_dev, &dev_attr_cidmode); }
/* initialize sysfs for device */ void gigaset_init_dev_sysfs(struct cardstate *cs) { if (!cs->tty_dev) return; gig_dbg(DEBUG_INIT, "setting up sysfs"); if (device_create_file(cs->tty_dev, &dev_attr_cidmode)) pr_err("could not create sysfs attribute\n"); }
static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct cardstate *cs = tty->driver_data; struct cmdbuf_t *cb; int retval; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; goto done; } if (cs->mstate != MS_LOCKED) { dev_warn(cs->dev, "can't write to unlocked device\n"); retval = -EBUSY; goto done; } if (count <= 0) { /* nothing to do */ retval = 0; goto done; } cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL); if (!cb) { dev_err(cs->dev, "%s: out of memory\n", __func__); retval = -ENOMEM; goto done; } memcpy(cb->buf, buf, count); cb->len = count; cb->offset = 0; cb->next = NULL; cb->wake_tasklet = &cs->if_wake_tasklet; retval = cs->ops->write_cmd(cs, cb); done: mutex_unlock(&cs->mutex); return retval; }