bas-gigaset.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,371 行 · 第 1/5 页
C
2,371 行
* return value: * 0 on success * -EBUSY if another request is pending * any URB submission error code */static int req_submit(struct bc_state *bcs, int req, int val, int timeout){ struct bas_cardstate *ucs = bcs->cs->hw.bas; int ret; unsigned long flags; gig_dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val); spin_lock_irqsave(&ucs->lock, flags); if (ucs->pending) { spin_unlock_irqrestore(&ucs->lock, flags); dev_err(bcs->cs->dev, "submission of request 0x%02x failed: " "request 0x%02x still pending\n", req, ucs->pending); return -EBUSY; } ucs->dr_ctrl.bRequestType = OUT_VENDOR_REQ; ucs->dr_ctrl.bRequest = req; ucs->dr_ctrl.wValue = cpu_to_le16(val); ucs->dr_ctrl.wIndex = 0; ucs->dr_ctrl.wLength = 0; usb_fill_control_urb(ucs->urb_ctrl, ucs->udev, usb_sndctrlpipe(ucs->udev, 0), (unsigned char*) &ucs->dr_ctrl, NULL, 0, write_ctrl_callback, ucs); if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) { dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", req, get_usb_statmsg(ret)); spin_unlock_irqrestore(&ucs->lock, flags); return ret; } ucs->pending = req; if (timeout > 0) { gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); ucs->timer_ctrl.expires = jiffies + timeout * HZ / 10; ucs->timer_ctrl.data = (unsigned long) bcs; ucs->timer_ctrl.function = req_timeout; add_timer(&ucs->timer_ctrl); } spin_unlock_irqrestore(&ucs->lock, flags); return 0;}/* gigaset_init_bchannel * called by common.c to connect a B channel * initialize isochronous I/O and tell the Gigaset base to open the channel * argument: * B channel control structure * return value: * 0 on success, error code < 0 on error */static int gigaset_init_bchannel(struct bc_state *bcs){ int req, ret; unsigned long flags; spin_lock_irqsave(&bcs->cs->lock, flags); if (unlikely(!bcs->cs->connected)) { gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); spin_unlock_irqrestore(&bcs->cs->lock, flags); return -ENODEV; } if ((ret = starturbs(bcs)) < 0) { dev_err(bcs->cs->dev, "could not start isochronous I/O for channel B%d: %s\n", bcs->channel + 1, ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret)); if (ret != -ENODEV) error_hangup(bcs); spin_unlock_irqrestore(&bcs->cs->lock, flags); return ret; } req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) { dev_err(bcs->cs->dev, "could not open channel B%d\n", bcs->channel + 1); stopurbs(bcs->hw.bas); if (ret != -ENODEV) error_hangup(bcs); } spin_unlock_irqrestore(&bcs->cs->lock, flags); return ret;}/* gigaset_close_bchannel * called by common.c to disconnect a B channel * tell the Gigaset base to close the channel * stopping isochronous I/O and LL notification will be done when the * acknowledgement for the close arrives * argument: * B channel control structure * return value: * 0 on success, error code < 0 on error */static int gigaset_close_bchannel(struct bc_state *bcs){ int req, ret; unsigned long flags; spin_lock_irqsave(&bcs->cs->lock, flags); if (unlikely(!bcs->cs->connected)) { spin_unlock_irqrestore(&bcs->cs->lock, flags); gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); return -ENODEV; } if (!(atomic_read(&bcs->cs->hw.bas->basstate) & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) { /* channel not running: just signal common.c */ spin_unlock_irqrestore(&bcs->cs->lock, flags); gigaset_bchannel_down(bcs); return 0; } /* channel running: tell device to close it */ req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) dev_err(bcs->cs->dev, "closing channel B%d failed\n", bcs->channel + 1); spin_unlock_irqrestore(&bcs->cs->lock, flags); return ret;}/* Device Operations *//* ================= *//* complete_cb * unqueue first command buffer from queue, waking any sleepers * must be called with cs->cmdlock held * parameter: * cs controller state structure */static void complete_cb(struct cardstate *cs){ struct cmdbuf_t *cb = cs->cmdbuf; /* unqueue completed buffer */ cs->cmdbytes -= cs->curlen; gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "write_command: sent %u bytes, %u left", cs->curlen, cs->cmdbytes); if ((cs->cmdbuf = cb->next) != NULL) { cs->cmdbuf->prev = NULL; cs->curlen = cs->cmdbuf->len; } else { cs->lastcmdbuf = NULL; cs->curlen = 0; } if (cb->wake_tasklet) tasklet_schedule(cb->wake_tasklet); kfree(cb);}/* write_command_callback * USB completion handler for AT command transmission * called by the USB subsystem in interrupt context * parameter: * urb USB request block of completed request * urb->context = controller state structure */static void write_command_callback(struct urb *urb, struct pt_regs *regs){ struct cardstate *cs = urb->context; struct bas_cardstate *ucs = cs->hw.bas; unsigned long flags; update_basstate(ucs, 0, BS_ATWRPEND); /* check status */ switch (urb->status) { case 0: /* normal completion */ break; case -ENOENT: /* cancelled */ case -ECONNRESET: /* cancelled (async) */ case -EINPROGRESS: /* pending */ case -ENODEV: /* device removed */ case -ESHUTDOWN: /* device shut down */ /* ignore silently */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(urb->status)); return; default: /* any failure */ if (++ucs->retry_cmd_out > BAS_RETRY) { dev_warn(cs->dev, "command write: %s, " "giving up after %d retries\n", get_usb_statmsg(urb->status), ucs->retry_cmd_out); break; } if (cs->cmdbuf == NULL) { dev_warn(cs->dev, "command write: %s, " "cannot retry - cmdbuf gone\n", get_usb_statmsg(urb->status)); break; } dev_notice(cs->dev, "command write: %s, retry %d\n", get_usb_statmsg(urb->status), ucs->retry_cmd_out); if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0) /* resubmitted - bypass regular exit block */ return; /* command send failed, assume base still waiting */ update_basstate(ucs, BS_ATREADY, 0); } spin_lock_irqsave(&cs->cmdlock, flags); if (cs->cmdbuf != NULL) complete_cb(cs); spin_unlock_irqrestore(&cs->cmdlock, flags);}/* atrdy_timeout * timeout routine for AT command transmission * argument: * controller state structure */static void atrdy_timeout(unsigned long data){ struct cardstate *cs = (struct cardstate *) data; struct bas_cardstate *ucs = cs->hw.bas; dev_warn(cs->dev, "timeout waiting for HD_READY_SEND_ATDATA\n"); /* fake the missing signal - what else can I do? */ update_basstate(ucs, BS_ATREADY, BS_ATTIMER); start_cbsend(cs);}/* atwrite_submit * submit an HD_WRITE_ATMESSAGE command URB * parameters: * cs controller state structure * buf buffer containing command to send * len length of command to send * return value: * 0 on success * -EBUSY if another request is pending * any URB submission error code */static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len){ struct bas_cardstate *ucs = cs->hw.bas; int rc; gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); if (update_basstate(ucs, BS_ATWRPEND, 0) & BS_ATWRPEND) { dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: URB busy\n"); return -EBUSY; } ucs->dr_cmd_out.bRequestType = OUT_VENDOR_REQ; ucs->dr_cmd_out.bRequest = HD_WRITE_ATMESSAGE; ucs->dr_cmd_out.wValue = 0; ucs->dr_cmd_out.wIndex = 0; ucs->dr_cmd_out.wLength = cpu_to_le16(len); usb_fill_control_urb(ucs->urb_cmd_out, ucs->udev, usb_sndctrlpipe(ucs->udev, 0), (unsigned char*) &ucs->dr_cmd_out, buf, len, write_command_callback, cs); rc = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC); if (unlikely(rc)) { update_basstate(ucs, 0, BS_ATWRPEND); dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n", get_usb_rcmsg(rc)); return rc; } /* submitted successfully, start timeout if necessary */ if (!(update_basstate(ucs, BS_ATTIMER, BS_ATREADY) & BS_ATTIMER)) { gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT); ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10; ucs->timer_atrdy.data = (unsigned long) cs; ucs->timer_atrdy.function = atrdy_timeout; add_timer(&ucs->timer_atrdy); } return 0;}/* start_cbsend * start transmission of AT command queue if necessary * parameter: * cs controller state structure * return value: * 0 on success * error code < 0 on error */static int start_cbsend(struct cardstate *cs){ struct cmdbuf_t *cb; struct bas_cardstate *ucs = cs->hw.bas; unsigned long flags; int rc; int retval = 0; /* check if AT channel is open */ if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) { gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open"); rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT); if (rc < 0) { /* flush command queue */ spin_lock_irqsave(&cs->cmdlock, flags); while (cs->cmdbuf != NULL) complete_cb(cs); spin_unlock_irqrestore(&cs->cmdlock, flags); } return rc; } /* try to send first command in queue */ spin_lock_irqsave(&cs->cmdlock, flags); while ((cb = cs->cmdbuf) != NULL && atomic_read(&ucs->basstate) & BS_ATREADY) { ucs->retry_cmd_out = 0; rc = atwrite_submit(cs, cb->buf, cb->len); if (unlikely(rc)) { retval = rc; complete_cb(cs); } } spin_unlock_irqrestore(&cs->cmdlock, flags); return retval;}/* gigaset_write_cmd * This function is called by the device independent part of the driver * to transmit an AT command string to the Gigaset device. * It encapsulates the device specific method for transmission over the * direct USB connection to the base. * The command string is added to the queue of commands to send, and * USB transmission is started if necessary. * parameters: * cs controller state structure * buf command string to send * len number of bytes to send (max. IF_WRITEBUF) * wake_tasklet tasklet to run when transmission is completed * (NULL if none) * return value: * number of bytes queued on success * error code < 0 on error */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; int status; gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? DEBUG_TRANSCMD : DEBUG_LOCKCMD, "CMD Transmit", len, buf); if (len <= 0) return 0; /* nothing to do */ if (len > IF_WRITEBUF) len = IF_WRITEBUF; 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 (unlikely(!cs->connected)) { spin_unlock_irqrestore(&cs->lock, flags); gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); return -ENODEV; } status = start_cbsend(cs); spin_unlock_irqrestore(&cs->lock, flags); return status < 0 ? status : len;}/* gigaset_write_room * tty_driver.write_room interface routine * return number of characters the driver will accept to be written via * gigaset_write_cmd * parameter: * controller state structure * return value: * number of characters */static int gigaset_write_room(struct cardstate *cs){ return IF_WRITEBUF;}/* gigaset_chars_in_buffer * tty_driver.chars_in_buffer interface routine * return number of characters waiting to be sent * parameter: * controller state structure * return value: * number of characters */static int gigaset_chars_in_buffer(struct cardstate *cs){ unsigned long flags; unsigned bytes; spin_lock_irqsave(&cs->cmdlock, flags); bytes = cs->cmdbytes; spin_unlock_irqrestore(&cs->cmdlock, flags); return bytes;}/* gigaset_brkchars * implementation of ioctl(GIGASET_BRKCHARS) * parameter: * controller state structure * return value: * -EINVAL (unimplemented function) */static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]){ return -EINVAL;}/* Device Initialization/Shutdown *//* ============================== *//* Free hardware dependent part of the B channel structure * parameter: * bcs B channel structure * return value: * !=0 on success */static int gigaset_freebcshw(struct bc_state *bcs){ struct bas_bc_state *ubc = bcs->hw.bas; int i; if (!ubc) return 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?