diff options
author | Tilman Schmidt <tilman@imap.cc> | 2010-07-05 10:18:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-07 19:57:51 -0400 |
commit | e3628dd176ba3ed329991ef042c29aae60617630 (patch) | |
tree | 77e47e95ba38276557702a5bfc8e319bc9100b7c /drivers/isdn | |
parent | b3251d8045f87eec5d565603345d262cee134fa6 (diff) |
isdn/gigaset: avoid copying AT commands twice
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>
Diffstat (limited to 'drivers/isdn')
-rw-r--r-- | drivers/isdn/gigaset/bas-gigaset.c | 51 | ||||
-rw-r--r-- | drivers/isdn/gigaset/ev-layer.c | 75 | ||||
-rw-r--r-- | drivers/isdn/gigaset/gigaset.h | 4 | ||||
-rw-r--r-- | drivers/isdn/gigaset/interface.c | 36 | ||||
-rw-r--r-- | drivers/isdn/gigaset/ser-gigaset.c | 27 | ||||
-rw-r--r-- | drivers/isdn/gigaset/usb-gigaset.c | 26 |
6 files changed, 85 insertions, 134 deletions
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 47a5ffec55a3..2dab5313913b 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c | |||
@@ -1913,65 +1913,41 @@ static int start_cbsend(struct cardstate *cs) | |||
1913 | * USB transmission is started if necessary. | 1913 | * USB transmission is started if necessary. |
1914 | * parameters: | 1914 | * parameters: |
1915 | * cs controller state structure | 1915 | * cs controller state structure |
1916 | * buf command string to send | 1916 | * cb command buffer structure |
1917 | * len number of bytes to send (max. IF_WRITEBUF) | ||
1918 | * wake_tasklet tasklet to run when transmission is completed | ||
1919 | * (NULL if none) | ||
1920 | * return value: | 1917 | * return value: |
1921 | * number of bytes queued on success | 1918 | * number of bytes queued on success |
1922 | * error code < 0 on error | 1919 | * error code < 0 on error |
1923 | */ | 1920 | */ |
1924 | static int gigaset_write_cmd(struct cardstate *cs, | 1921 | static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) |
1925 | const unsigned char *buf, int len, | ||
1926 | struct tasklet_struct *wake_tasklet) | ||
1927 | { | 1922 | { |
1928 | struct cmdbuf_t *cb; | ||
1929 | unsigned long flags; | 1923 | unsigned long flags; |
1930 | int rc; | 1924 | int rc; |
1931 | 1925 | ||
1932 | gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? | 1926 | gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? |
1933 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, | 1927 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, |
1934 | "CMD Transmit", len, buf); | 1928 | "CMD Transmit", cb->len, cb->buf); |
1935 | |||
1936 | if (len <= 0) { | ||
1937 | /* nothing to do */ | ||
1938 | rc = 0; | ||
1939 | goto notqueued; | ||
1940 | } | ||
1941 | 1929 | ||
1942 | /* translate "+++" escape sequence sent as a single separate command | 1930 | /* translate "+++" escape sequence sent as a single separate command |
1943 | * into "close AT channel" command for error recovery | 1931 | * into "close AT channel" command for error recovery |
1944 | * The next command will reopen the AT channel automatically. | 1932 | * The next command will reopen the AT channel automatically. |
1945 | */ | 1933 | */ |
1946 | if (len == 3 && !memcmp(buf, "+++", 3)) { | 1934 | if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) { |
1935 | kfree(cb); | ||
1947 | rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); | 1936 | rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); |
1948 | goto notqueued; | 1937 | if (cb->wake_tasklet) |
1949 | } | 1938 | tasklet_schedule(cb->wake_tasklet); |
1950 | 1939 | return rc < 0 ? rc : cb->len; | |
1951 | if (len > IF_WRITEBUF) | ||
1952 | len = IF_WRITEBUF; | ||
1953 | cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC); | ||
1954 | if (!cb) { | ||
1955 | dev_err(cs->dev, "%s: out of memory\n", __func__); | ||
1956 | rc = -ENOMEM; | ||
1957 | goto notqueued; | ||
1958 | } | 1940 | } |
1959 | 1941 | ||
1960 | memcpy(cb->buf, buf, len); | ||
1961 | cb->len = len; | ||
1962 | cb->offset = 0; | ||
1963 | cb->next = NULL; | ||
1964 | cb->wake_tasklet = wake_tasklet; | ||
1965 | |||
1966 | spin_lock_irqsave(&cs->cmdlock, flags); | 1942 | spin_lock_irqsave(&cs->cmdlock, flags); |
1967 | cb->prev = cs->lastcmdbuf; | 1943 | cb->prev = cs->lastcmdbuf; |
1968 | if (cs->lastcmdbuf) | 1944 | if (cs->lastcmdbuf) |
1969 | cs->lastcmdbuf->next = cb; | 1945 | cs->lastcmdbuf->next = cb; |
1970 | else { | 1946 | else { |
1971 | cs->cmdbuf = cb; | 1947 | cs->cmdbuf = cb; |
1972 | cs->curlen = len; | 1948 | cs->curlen = cb->len; |
1973 | } | 1949 | } |
1974 | cs->cmdbytes += len; | 1950 | cs->cmdbytes += cb->len; |
1975 | cs->lastcmdbuf = cb; | 1951 | cs->lastcmdbuf = cb; |
1976 | spin_unlock_irqrestore(&cs->cmdlock, flags); | 1952 | spin_unlock_irqrestore(&cs->cmdlock, flags); |
1977 | 1953 | ||
@@ -1988,12 +1964,7 @@ static int gigaset_write_cmd(struct cardstate *cs, | |||
1988 | } | 1964 | } |
1989 | rc = start_cbsend(cs); | 1965 | rc = start_cbsend(cs); |
1990 | spin_unlock_irqrestore(&cs->lock, flags); | 1966 | spin_unlock_irqrestore(&cs->lock, flags); |
1991 | return rc < 0 ? rc : len; | 1967 | return rc < 0 ? rc : cb->len; |
1992 | |||
1993 | notqueued: /* request handled without queuing */ | ||
1994 | if (wake_tasklet) | ||
1995 | tasklet_schedule(wake_tasklet); | ||
1996 | return rc; | ||
1997 | } | 1968 | } |
1998 | 1969 | ||
1999 | /* gigaset_write_room | 1970 | /* gigaset_write_room |
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index ceaef9a04a42..0d5984a86795 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c | |||
@@ -797,48 +797,27 @@ static void schedule_init(struct cardstate *cs, int state) | |||
797 | static void send_command(struct cardstate *cs, const char *cmd, int cid, | 797 | static void send_command(struct cardstate *cs, const char *cmd, int cid, |
798 | int dle, gfp_t kmallocflags) | 798 | int dle, gfp_t kmallocflags) |
799 | { | 799 | { |
800 | size_t cmdlen, buflen; | 800 | struct cmdbuf_t *cb; |
801 | char *cmdpos, *cmdbuf, *cmdtail; | 801 | size_t buflen; |
802 | 802 | ||
803 | cmdlen = strlen(cmd); | 803 | buflen = strlen(cmd) + 12; /* DLE ( A T 1 2 3 4 5 <cmd> DLE ) \0 */ |
804 | buflen = 11 + cmdlen; | 804 | cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, kmallocflags); |
805 | if (unlikely(buflen <= cmdlen)) { | 805 | if (!cb) { |
806 | dev_err(cs->dev, "integer overflow in buflen\n"); | 806 | dev_err(cs->dev, "%s: out of memory\n", __func__); |
807 | return; | 807 | return; |
808 | } | 808 | } |
809 | 809 | if (cid > 0 && cid <= 65535) | |
810 | cmdbuf = kmalloc(buflen, kmallocflags); | 810 | cb->len = snprintf(cb->buf, buflen, |
811 | if (unlikely(!cmdbuf)) { | 811 | dle ? "\020(AT%d%s\020)" : "AT%d%s", |
812 | dev_err(cs->dev, "out of memory\n"); | 812 | cid, cmd); |
813 | return; | 813 | else |
814 | } | 814 | cb->len = snprintf(cb->buf, buflen, |
815 | 815 | dle ? "\020(AT%s\020)" : "AT%s", | |
816 | cmdpos = cmdbuf + 9; | 816 | cmd); |
817 | cmdtail = cmdpos + cmdlen; | 817 | cb->offset = 0; |
818 | memcpy(cmdpos, cmd, cmdlen); | 818 | cb->next = NULL; |
819 | 819 | cb->wake_tasklet = NULL; | |
820 | if (cid > 0 && cid <= 65535) { | 820 | cs->ops->write_cmd(cs, cb); |
821 | do { | ||
822 | *--cmdpos = '0' + cid % 10; | ||
823 | cid /= 10; | ||
824 | ++cmdlen; | ||
825 | } while (cid); | ||
826 | } | ||
827 | |||
828 | cmdlen += 2; | ||
829 | *--cmdpos = 'T'; | ||
830 | *--cmdpos = 'A'; | ||
831 | |||
832 | if (dle) { | ||
833 | cmdlen += 4; | ||
834 | *--cmdpos = '('; | ||
835 | *--cmdpos = 0x10; | ||
836 | *cmdtail++ = 0x10; | ||
837 | *cmdtail++ = ')'; | ||
838 | } | ||
839 | |||
840 | cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL); | ||
841 | kfree(cmdbuf); | ||
842 | } | 821 | } |
843 | 822 | ||
844 | static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid) | 823 | 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, | |||
1240 | break; | 1219 | break; |
1241 | case ACT_HUPMODEM: | 1220 | case ACT_HUPMODEM: |
1242 | /* send "+++" (hangup in unimodem mode) */ | 1221 | /* send "+++" (hangup in unimodem mode) */ |
1243 | if (cs->connected) | 1222 | if (cs->connected) { |
1244 | cs->ops->write_cmd(cs, "+++", 3, NULL); | 1223 | struct cmdbuf_t *cb; |
1224 | |||
1225 | cb = kmalloc(sizeof(struct cmdbuf_t) + 3, GFP_ATOMIC); | ||
1226 | if (!cb) { | ||
1227 | dev_err(cs->dev, "%s: out of memory\n", | ||
1228 | __func__); | ||
1229 | return; | ||
1230 | } | ||
1231 | memcpy(cb->buf, "+++", 3); | ||
1232 | cb->len = 3; | ||
1233 | cb->offset = 0; | ||
1234 | cb->next = NULL; | ||
1235 | cb->wake_tasklet = NULL; | ||
1236 | cs->ops->write_cmd(cs, cb); | ||
1237 | } | ||
1245 | break; | 1238 | break; |
1246 | case ACT_RING: | 1239 | case ACT_RING: |
1247 | /* get fresh AT state structure for new CID */ | 1240 | /* get fresh AT state structure for new CID */ |
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 8738b0821fc9..904c9473effc 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h | |||
@@ -574,9 +574,7 @@ struct bas_bc_state { | |||
574 | struct gigaset_ops { | 574 | struct gigaset_ops { |
575 | /* Called from ev-layer.c/interface.c for sending AT commands to the | 575 | /* Called from ev-layer.c/interface.c for sending AT commands to the |
576 | device */ | 576 | device */ |
577 | int (*write_cmd)(struct cardstate *cs, | 577 | int (*write_cmd)(struct cardstate *cs, struct cmdbuf_t *cb); |
578 | const unsigned char *buf, int len, | ||
579 | struct tasklet_struct *wake_tasklet); | ||
580 | 578 | ||
581 | /* Called from interface.c for additional device control */ | 579 | /* Called from interface.c for additional device control */ |
582 | int (*write_room)(struct cardstate *cs); | 580 | int (*write_room)(struct cardstate *cs); |
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index c9f28dd40d5c..f45d68620161 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c | |||
@@ -339,7 +339,8 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file, | |||
339 | static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) | 339 | static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) |
340 | { | 340 | { |
341 | struct cardstate *cs; | 341 | struct cardstate *cs; |
342 | int retval = -ENODEV; | 342 | struct cmdbuf_t *cb; |
343 | int retval; | ||
343 | 344 | ||
344 | cs = (struct cardstate *) tty->driver_data; | 345 | cs = (struct cardstate *) tty->driver_data; |
345 | if (!cs) { | 346 | if (!cs) { |
@@ -355,18 +356,39 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) | |||
355 | if (!cs->connected) { | 356 | if (!cs->connected) { |
356 | gig_dbg(DEBUG_IF, "not connected"); | 357 | gig_dbg(DEBUG_IF, "not connected"); |
357 | retval = -ENODEV; | 358 | retval = -ENODEV; |
358 | } else if (!cs->open_count) | 359 | goto done; |
360 | } | ||
361 | if (!cs->open_count) { | ||
359 | dev_warn(cs->dev, "%s: device not opened\n", __func__); | 362 | dev_warn(cs->dev, "%s: device not opened\n", __func__); |
360 | else if (cs->mstate != MS_LOCKED) { | 363 | retval = -ENODEV; |
364 | goto done; | ||
365 | } | ||
366 | if (cs->mstate != MS_LOCKED) { | ||
361 | dev_warn(cs->dev, "can't write to unlocked device\n"); | 367 | dev_warn(cs->dev, "can't write to unlocked device\n"); |
362 | retval = -EBUSY; | 368 | retval = -EBUSY; |
363 | } else { | 369 | goto done; |
364 | retval = cs->ops->write_cmd(cs, buf, count, | 370 | } |
365 | &cs->if_wake_tasklet); | 371 | if (count <= 0) { |
372 | /* nothing to do */ | ||
373 | retval = 0; | ||
374 | goto done; | ||
366 | } | 375 | } |
367 | 376 | ||
368 | mutex_unlock(&cs->mutex); | 377 | cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL); |
378 | if (!cb) { | ||
379 | dev_err(cs->dev, "%s: out of memory\n", __func__); | ||
380 | retval = -ENOMEM; | ||
381 | goto done; | ||
382 | } | ||
369 | 383 | ||
384 | memcpy(cb->buf, buf, count); | ||
385 | cb->len = count; | ||
386 | cb->offset = 0; | ||
387 | cb->next = NULL; | ||
388 | cb->wake_tasklet = &cs->if_wake_tasklet; | ||
389 | retval = cs->ops->write_cmd(cs, cb); | ||
390 | done: | ||
391 | mutex_unlock(&cs->mutex); | ||
370 | return retval; | 392 | return retval; |
371 | } | 393 | } |
372 | 394 | ||
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index e96c0586886c..d151dcbf770d 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c | |||
@@ -241,30 +241,13 @@ static void flush_send_queue(struct cardstate *cs) | |||
241 | * return value: | 241 | * return value: |
242 | * number of bytes queued, or error code < 0 | 242 | * number of bytes queued, or error code < 0 |
243 | */ | 243 | */ |
244 | static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | 244 | static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) |
245 | int len, struct tasklet_struct *wake_tasklet) | ||
246 | { | 245 | { |
247 | struct cmdbuf_t *cb; | ||
248 | unsigned long flags; | 246 | unsigned long flags; |
249 | 247 | ||
250 | gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? | 248 | gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? |
251 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, | 249 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, |
252 | "CMD Transmit", len, buf); | 250 | "CMD Transmit", cb->len, cb->buf); |
253 | |||
254 | if (len <= 0) | ||
255 | return 0; | ||
256 | |||
257 | cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC); | ||
258 | if (!cb) { | ||
259 | dev_err(cs->dev, "%s: out of memory!\n", __func__); | ||
260 | return -ENOMEM; | ||
261 | } | ||
262 | |||
263 | memcpy(cb->buf, buf, len); | ||
264 | cb->len = len; | ||
265 | cb->offset = 0; | ||
266 | cb->next = NULL; | ||
267 | cb->wake_tasklet = wake_tasklet; | ||
268 | 251 | ||
269 | spin_lock_irqsave(&cs->cmdlock, flags); | 252 | spin_lock_irqsave(&cs->cmdlock, flags); |
270 | cb->prev = cs->lastcmdbuf; | 253 | cb->prev = cs->lastcmdbuf; |
@@ -272,9 +255,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | |||
272 | cs->lastcmdbuf->next = cb; | 255 | cs->lastcmdbuf->next = cb; |
273 | else { | 256 | else { |
274 | cs->cmdbuf = cb; | 257 | cs->cmdbuf = cb; |
275 | cs->curlen = len; | 258 | cs->curlen = cb->len; |
276 | } | 259 | } |
277 | cs->cmdbytes += len; | 260 | cs->cmdbytes += cb->len; |
278 | cs->lastcmdbuf = cb; | 261 | cs->lastcmdbuf = cb; |
279 | spin_unlock_irqrestore(&cs->cmdlock, flags); | 262 | spin_unlock_irqrestore(&cs->cmdlock, flags); |
280 | 263 | ||
@@ -282,7 +265,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | |||
282 | if (cs->connected) | 265 | if (cs->connected) |
283 | tasklet_schedule(&cs->write_tasklet); | 266 | tasklet_schedule(&cs->write_tasklet); |
284 | spin_unlock_irqrestore(&cs->lock, flags); | 267 | spin_unlock_irqrestore(&cs->lock, flags); |
285 | return len; | 268 | return cb->len; |
286 | } | 269 | } |
287 | 270 | ||
288 | /* | 271 | /* |
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index f65cf7db216b..4a66338f4e7d 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c | |||
@@ -494,29 +494,13 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) | |||
494 | } | 494 | } |
495 | 495 | ||
496 | /* Send command to device. */ | 496 | /* Send command to device. */ |
497 | static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | 497 | static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) |
498 | int len, struct tasklet_struct *wake_tasklet) | ||
499 | { | 498 | { |
500 | struct cmdbuf_t *cb; | ||
501 | unsigned long flags; | 499 | unsigned long flags; |
502 | 500 | ||
503 | gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? | 501 | gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? |
504 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, | 502 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, |
505 | "CMD Transmit", len, buf); | 503 | "CMD Transmit", cb->len, cb->buf); |
506 | |||
507 | if (len <= 0) | ||
508 | return 0; | ||
509 | cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC); | ||
510 | if (!cb) { | ||
511 | dev_err(cs->dev, "%s: out of memory\n", __func__); | ||
512 | return -ENOMEM; | ||
513 | } | ||
514 | |||
515 | memcpy(cb->buf, buf, len); | ||
516 | cb->len = len; | ||
517 | cb->offset = 0; | ||
518 | cb->next = NULL; | ||
519 | cb->wake_tasklet = wake_tasklet; | ||
520 | 504 | ||
521 | spin_lock_irqsave(&cs->cmdlock, flags); | 505 | spin_lock_irqsave(&cs->cmdlock, flags); |
522 | cb->prev = cs->lastcmdbuf; | 506 | cb->prev = cs->lastcmdbuf; |
@@ -524,9 +508,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | |||
524 | cs->lastcmdbuf->next = cb; | 508 | cs->lastcmdbuf->next = cb; |
525 | else { | 509 | else { |
526 | cs->cmdbuf = cb; | 510 | cs->cmdbuf = cb; |
527 | cs->curlen = len; | 511 | cs->curlen = cb->len; |
528 | } | 512 | } |
529 | cs->cmdbytes += len; | 513 | cs->cmdbytes += cb->len; |
530 | cs->lastcmdbuf = cb; | 514 | cs->lastcmdbuf = cb; |
531 | spin_unlock_irqrestore(&cs->cmdlock, flags); | 515 | spin_unlock_irqrestore(&cs->cmdlock, flags); |
532 | 516 | ||
@@ -534,7 +518,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | |||
534 | if (cs->connected) | 518 | if (cs->connected) |
535 | tasklet_schedule(&cs->write_tasklet); | 519 | tasklet_schedule(&cs->write_tasklet); |
536 | spin_unlock_irqrestore(&cs->lock, flags); | 520 | spin_unlock_irqrestore(&cs->lock, flags); |
537 | return len; | 521 | return cb->len; |
538 | } | 522 | } |
539 | 523 | ||
540 | static int gigaset_write_room(struct cardstate *cs) | 524 | static int gigaset_write_room(struct cardstate *cs) |