isdn/gigaset: avoid copying AT commands twice
authorTilman Schmidt <tilman@imap.cc>
Mon, 5 Jul 2010 14:18:43 +0000 (14:18 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 7 Jul 2010 23:57:51 +0000 (16:57 -0700)
Change the Gigaset driver's internal write_cmd interface to accept a
cmdbuf structure instead of a string. This avoids copying formatted
AT commands a second time.

Impact: optimization
Signed-off-by: Tilman Schmidt <tilman@imap.cc>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/isdn/gigaset/bas-gigaset.c
drivers/isdn/gigaset/ev-layer.c
drivers/isdn/gigaset/gigaset.h
drivers/isdn/gigaset/interface.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/gigaset/usb-gigaset.c

index 47a5ffec55a393173de8fd01ef8019b2d7115bdd..2dab5313913bb035cd435415e1dad2e2b04003d6 100644 (file)
@@ -1913,65 +1913,41 @@ static int start_cbsend(struct cardstate *cs)
  * 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)
+ *     cb              command buffer structure
  * 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)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
 {
-       struct cmdbuf_t *cb;
        unsigned long flags;
        int rc;
 
        gigaset_dbg_buffer(cs->mstate != MS_LOCKED ?
                             DEBUG_TRANSCMD : DEBUG_LOCKCMD,
-                          "CMD Transmit", len, buf);
-
-       if (len <= 0) {
-               /* nothing to do */
-               rc = 0;
-               goto notqueued;
-       }
+                          "CMD Transmit", cb->len, cb->buf);
 
        /* translate "+++" escape sequence sent as a single separate command
         * into "close AT channel" command for error recovery
         * The next command will reopen the AT channel automatically.
         */
-       if (len == 3 && !memcmp(buf, "+++", 3)) {
+       if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) {
+               kfree(cb);
                rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
-               goto notqueued;
-       }
-
-       if (len > IF_WRITEBUF)
-               len = IF_WRITEBUF;
-       cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
-       if (!cb) {
-               dev_err(cs->dev, "%s: out of memory\n", __func__);
-               rc = -ENOMEM;
-               goto notqueued;
+               if (cb->wake_tasklet)
+                       tasklet_schedule(cb->wake_tasklet);
+               return rc < 0 ? rc : cb->len;
        }
 
-       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->curlen = cb->len;
        }
-       cs->cmdbytes += len;
+       cs->cmdbytes += cb->len;
        cs->lastcmdbuf = cb;
        spin_unlock_irqrestore(&cs->cmdlock, flags);
 
@@ -1988,12 +1964,7 @@ static int gigaset_write_cmd(struct cardstate *cs,
        }
        rc = start_cbsend(cs);
        spin_unlock_irqrestore(&cs->lock, flags);
-       return rc < 0 ? rc : len;
-
-notqueued:                     /* request handled without queuing */
-       if (wake_tasklet)
-               tasklet_schedule(wake_tasklet);
-       return rc;
+       return rc < 0 ? rc : cb->len;
 }
 
 /* gigaset_write_room
index ceaef9a04a42410b876de74558a51301d3a89c3e..0d5984a8679573af2525d9915592831653db0f29 100644 (file)
@@ -797,48 +797,27 @@ static void schedule_init(struct cardstate *cs, int state)
 static void send_command(struct cardstate *cs, const char *cmd, int cid,
                         int dle, gfp_t kmallocflags)
 {
-       size_t cmdlen, buflen;
-       char *cmdpos, *cmdbuf, *cmdtail;
+       struct cmdbuf_t *cb;
+       size_t buflen;
 
-       cmdlen = strlen(cmd);
-       buflen = 11 + cmdlen;
-       if (unlikely(buflen <= cmdlen)) {
-               dev_err(cs->dev, "integer overflow in buflen\n");
+       buflen = strlen(cmd) + 12; /* DLE ( A T 1 2 3 4 5 <cmd> DLE ) \0 */
+       cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, kmallocflags);
+       if (!cb) {
+               dev_err(cs->dev, "%s: out of memory\n", __func__);
                return;
        }
-
-       cmdbuf = kmalloc(buflen, kmallocflags);
-       if (unlikely(!cmdbuf)) {
-               dev_err(cs->dev, "out of memory\n");
-               return;
-       }
-
-       cmdpos = cmdbuf + 9;
-       cmdtail = cmdpos + cmdlen;
-       memcpy(cmdpos, cmd, cmdlen);
-
-       if (cid > 0 && cid <= 65535) {
-               do {
-                       *--cmdpos = '0' + cid % 10;
-                       cid /= 10;
-                       ++cmdlen;
-               } while (cid);
-       }
-
-       cmdlen += 2;
-       *--cmdpos = 'T';
-       *--cmdpos = 'A';
-
-       if (dle) {
-               cmdlen += 4;
-               *--cmdpos = '(';
-               *--cmdpos = 0x10;
-               *cmdtail++ = 0x10;
-               *cmdtail++ = ')';
-       }
-
-       cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL);
-       kfree(cmdbuf);
+       if (cid > 0 && cid <= 65535)
+               cb->len = snprintf(cb->buf, buflen,
+                                 dle ? "\020(AT%d%s\020)" : "AT%d%s",
+                                 cid, cmd);
+       else
+               cb->len = snprintf(cb->buf, buflen,
+                                 dle ? "\020(AT%s\020)" : "AT%s",
+                                 cmd);
+       cb->offset = 0;
+       cb->next = NULL;
+       cb->wake_tasklet = NULL;
+       cs->ops->write_cmd(cs, cb);
 }
 
 static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid)
@@ -1240,8 +1219,22 @@ static void do_action(int action, struct cardstate *cs,
                break;
        case ACT_HUPMODEM:
                /* send "+++" (hangup in unimodem mode) */
-               if (cs->connected)
-                       cs->ops->write_cmd(cs, "+++", 3, NULL);
+               if (cs->connected) {
+                       struct cmdbuf_t *cb;
+
+                       cb = kmalloc(sizeof(struct cmdbuf_t) + 3, GFP_ATOMIC);
+                       if (!cb) {
+                               dev_err(cs->dev, "%s: out of memory\n",
+                                       __func__);
+                               return;
+                       }
+                       memcpy(cb->buf, "+++", 3);
+                       cb->len = 3;
+                       cb->offset = 0;
+                       cb->next = NULL;
+                       cb->wake_tasklet = NULL;
+                       cs->ops->write_cmd(cs, cb);
+               }
                break;
        case ACT_RING:
                /* get fresh AT state structure for new CID */
index 8738b0821fc9c29ea7ddcbec6a888db709766272..904c9473effce769881aeb97668fac1f28683399 100644 (file)
@@ -574,9 +574,7 @@ struct bas_bc_state {
 struct gigaset_ops {
        /* Called from ev-layer.c/interface.c for sending AT commands to the
           device */
-       int (*write_cmd)(struct cardstate *cs,
-                        const unsigned char *buf, int len,
-                        struct tasklet_struct *wake_tasklet);
+       int (*write_cmd)(struct cardstate *cs, struct cmdbuf_t *cb);
 
        /* Called from interface.c for additional device control */
        int (*write_room)(struct cardstate *cs);
index c9f28dd40d5c463d1d12821e47965655da123097..f45d68620161b3f3a04c1f6a2a2cf5c1e7e5218b 100644 (file)
@@ -339,7 +339,8 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file,
 static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        struct cardstate *cs;
-       int retval = -ENODEV;
+       struct cmdbuf_t *cb;
+       int retval;
 
        cs = (struct cardstate *) tty->driver_data;
        if (!cs) {
@@ -355,18 +356,39 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
        if (!cs->connected) {
                gig_dbg(DEBUG_IF, "not connected");
                retval = -ENODEV;
-       } else if (!cs->open_count)
+               goto done;
+       }
+       if (!cs->open_count) {
                dev_warn(cs->dev, "%s: device not opened\n", __func__);
-       else if (cs->mstate != MS_LOCKED) {
+               retval = -ENODEV;
+               goto done;
+       }
+       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);
+               goto done;
+       }
+       if (count <= 0) {
+               /* nothing to do */
+               retval = 0;
+               goto done;
        }
 
-       mutex_unlock(&cs->mutex);
+       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;
 }
 
index e96c0586886c14b5b626427f6199144d84ae4123..d151dcbf770d7dfe668643d65dad9574bc06716e 100644 (file)
@@ -241,30 +241,13 @@ static void flush_send_queue(struct cardstate *cs)
  * return value:
  *     number of bytes queued, or error code < 0
  */
-static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
-                            int len, struct tasklet_struct *wake_tasklet)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
 {
-       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;
-
-       cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
-       if (!cb) {
-               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;
+                          "CMD Transmit", cb->len, cb->buf);
 
        spin_lock_irqsave(&cs->cmdlock, flags);
        cb->prev = cs->lastcmdbuf;
@@ -272,9 +255,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
                cs->lastcmdbuf->next = cb;
        else {
                cs->cmdbuf = cb;
-               cs->curlen = len;
+               cs->curlen = cb->len;
        }
-       cs->cmdbytes += len;
+       cs->cmdbytes += cb->len;
        cs->lastcmdbuf = cb;
        spin_unlock_irqrestore(&cs->cmdlock, flags);
 
@@ -282,7 +265,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
        if (cs->connected)
                tasklet_schedule(&cs->write_tasklet);
        spin_unlock_irqrestore(&cs->lock, flags);
-       return len;
+       return cb->len;
 }
 
 /*
index f65cf7db216b41370ff6c09267e40d5bc389e99f..4a66338f4e7d6ae6dc8e8e62446a7b9ea5ef7a40 100644 (file)
@@ -494,29 +494,13 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
 }
 
 /* Send command to device. */
-static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
-                            int len, struct tasklet_struct *wake_tasklet)
+static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb)
 {
-       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;
-       cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC);
-       if (!cb) {
-               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;
+                          "CMD Transmit", cb->len, cb->buf);
 
        spin_lock_irqsave(&cs->cmdlock, flags);
        cb->prev = cs->lastcmdbuf;
@@ -524,9 +508,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
                cs->lastcmdbuf->next = cb;
        else {
                cs->cmdbuf = cb;
-               cs->curlen = len;
+               cs->curlen = cb->len;
        }
-       cs->cmdbytes += len;
+       cs->cmdbytes += cb->len;
        cs->lastcmdbuf = cb;
        spin_unlock_irqrestore(&cs->cmdlock, flags);
 
@@ -534,7 +518,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
        if (cs->connected)
                tasklet_schedule(&cs->write_tasklet);
        spin_unlock_irqrestore(&cs->lock, flags);
-       return len;
+       return cb->len;
 }
 
 static int gigaset_write_room(struct cardstate *cs)