diff options
author | Tilman Schmidt <tilman@imap.cc> | 2006-04-11 01:55:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-11 09:18:50 -0400 |
commit | 69049cc87dccb1e6fb54aa25c63033efac805dbd (patch) | |
tree | 9db1953a831091335b98f8749865f4c8b410ff9b /drivers/isdn/gigaset/usb-gigaset.c | |
parent | 27d1ac2ef7d0b9250ca9fd2ef506e12866ce8fdf (diff) |
[PATCH] isdn4linux: Siemens Gigaset drivers: make some variables non-atomic
With Hansjoerg Lipp <hjlipp@web.de>
Replace some atomic_t variables in the Gigaset drivers by non-atomic ones,
using spinlocks instead to assure atomicity, as proposed in discussions on the
linux-kernel mailing list.
Signed-off-by: Hansjoerg Lipp <hjlipp@web.de>
Signed-off-by: Tilman Schmidt <tilman@imap.cc>
Cc: Karsten Keil <kkeil@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/isdn/gigaset/usb-gigaset.c')
-rw-r--r-- | drivers/isdn/gigaset/usb-gigaset.c | 86 |
1 files changed, 52 insertions, 34 deletions
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index fe8435b8fa97..bfb73fd5077e 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c | |||
@@ -371,13 +371,14 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs) | |||
371 | int r; | 371 | int r; |
372 | unsigned numbytes; | 372 | unsigned numbytes; |
373 | unsigned char *src; | 373 | unsigned char *src; |
374 | 374 | unsigned long flags; | |
375 | if (!atomic_read(&cs->connected)) { | ||
376 | err("%s: disconnected", __func__); | ||
377 | return; | ||
378 | } | ||
379 | 375 | ||
380 | if (!urb->status) { | 376 | if (!urb->status) { |
377 | if (!cs->connected) { | ||
378 | err("%s: disconnected", __func__); /* should never happen */ | ||
379 | return; | ||
380 | } | ||
381 | |||
381 | numbytes = urb->actual_length; | 382 | numbytes = urb->actual_length; |
382 | 383 | ||
383 | if (numbytes) { | 384 | if (numbytes) { |
@@ -399,12 +400,19 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs) | |||
399 | /* The urb might have been killed. */ | 400 | /* The urb might have been killed. */ |
400 | gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d", | 401 | gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d", |
401 | __func__, urb->status); | 402 | __func__, urb->status); |
402 | if (urb->status != -ENOENT) /* not killed */ | 403 | if (urb->status != -ENOENT) { /* not killed */ |
404 | if (!cs->connected) { | ||
405 | err("%s: disconnected", __func__); /* should never happen */ | ||
406 | return; | ||
407 | } | ||
403 | resubmit = 1; | 408 | resubmit = 1; |
409 | } | ||
404 | } | 410 | } |
405 | 411 | ||
406 | if (resubmit) { | 412 | if (resubmit) { |
407 | r = usb_submit_urb(urb, SLAB_ATOMIC); | 413 | spin_lock_irqsave(&cs->lock, flags); |
414 | r = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; | ||
415 | spin_unlock_irqrestore(&cs->lock, flags); | ||
408 | if (r) | 416 | if (r) |
409 | dev_err(cs->dev, "error %d when resubmitting urb.\n", | 417 | dev_err(cs->dev, "error %d when resubmitting urb.\n", |
410 | -r); | 418 | -r); |
@@ -416,21 +424,22 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs) | |||
416 | static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs) | 424 | static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs) |
417 | { | 425 | { |
418 | struct cardstate *cs = urb->context; | 426 | struct cardstate *cs = urb->context; |
427 | unsigned long flags; | ||
419 | 428 | ||
420 | #ifdef CONFIG_GIGASET_DEBUG | ||
421 | if (!atomic_read(&cs->connected)) { | ||
422 | err("%s: not connected", __func__); | ||
423 | return; | ||
424 | } | ||
425 | #endif | ||
426 | if (urb->status) | 429 | if (urb->status) |
427 | dev_err(cs->dev, "bulk transfer failed (status %d)\n", | 430 | dev_err(cs->dev, "bulk transfer failed (status %d)\n", |
428 | -urb->status); | 431 | -urb->status); |
429 | /* That's all we can do. Communication problems | 432 | /* That's all we can do. Communication problems |
430 | are handled by timeouts or network protocols. */ | 433 | are handled by timeouts or network protocols. */ |
431 | 434 | ||
432 | atomic_set(&cs->hw.usb->busy, 0); | 435 | spin_lock_irqsave(&cs->lock, flags); |
433 | tasklet_schedule(&cs->write_tasklet); | 436 | if (!cs->connected) { |
437 | err("%s: not connected", __func__); | ||
438 | } else { | ||
439 | atomic_set(&cs->hw.usb->busy, 0); | ||
440 | tasklet_schedule(&cs->write_tasklet); | ||
441 | } | ||
442 | spin_unlock_irqrestore(&cs->lock, flags); | ||
434 | } | 443 | } |
435 | 444 | ||
436 | static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) | 445 | static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) |
@@ -465,6 +474,8 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) | |||
465 | } | 474 | } |
466 | if (cb) { | 475 | if (cb) { |
467 | count = min(cb->len, ucs->bulk_out_size); | 476 | count = min(cb->len, ucs->bulk_out_size); |
477 | gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count); | ||
478 | |||
468 | usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, | 479 | usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, |
469 | usb_sndbulkpipe(ucs->udev, | 480 | usb_sndbulkpipe(ucs->udev, |
470 | ucs->bulk_out_endpointAddr & 0x0f), | 481 | ucs->bulk_out_endpointAddr & 0x0f), |
@@ -474,14 +485,15 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) | |||
474 | cb->offset += count; | 485 | cb->offset += count; |
475 | cb->len -= count; | 486 | cb->len -= count; |
476 | atomic_set(&ucs->busy, 1); | 487 | atomic_set(&ucs->busy, 1); |
477 | gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count); | ||
478 | 488 | ||
479 | status = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); | 489 | spin_lock_irqsave(&cs->lock, flags); |
490 | status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC) : -ENODEV; | ||
491 | spin_unlock_irqrestore(&cs->lock, flags); | ||
492 | |||
480 | if (status) { | 493 | if (status) { |
481 | atomic_set(&ucs->busy, 0); | 494 | atomic_set(&ucs->busy, 0); |
482 | dev_err(cs->dev, | 495 | err("could not submit urb (error %d)\n", |
483 | "could not submit urb (error %d)\n", | 496 | -status); |
484 | -status); | ||
485 | cb->len = 0; /* skip urb => remove cb+wakeup | 497 | cb->len = 0; /* skip urb => remove cb+wakeup |
486 | in next loop cycle */ | 498 | in next loop cycle */ |
487 | } | 499 | } |
@@ -502,11 +514,6 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | |||
502 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, | 514 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, |
503 | "CMD Transmit", len, buf); | 515 | "CMD Transmit", len, buf); |
504 | 516 | ||
505 | if (!atomic_read(&cs->connected)) { | ||
506 | err("%s: not connected", __func__); | ||
507 | return -ENODEV; | ||
508 | } | ||
509 | |||
510 | if (len <= 0) | 517 | if (len <= 0) |
511 | return 0; | 518 | return 0; |
512 | 519 | ||
@@ -533,7 +540,10 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, | |||
533 | cs->lastcmdbuf = cb; | 540 | cs->lastcmdbuf = cb; |
534 | spin_unlock_irqrestore(&cs->cmdlock, flags); | 541 | spin_unlock_irqrestore(&cs->cmdlock, flags); |
535 | 542 | ||
536 | tasklet_schedule(&cs->write_tasklet); | 543 | spin_lock_irqsave(&cs->lock, flags); |
544 | if (cs->connected) | ||
545 | tasklet_schedule(&cs->write_tasklet); | ||
546 | spin_unlock_irqrestore(&cs->lock, flags); | ||
537 | return len; | 547 | return len; |
538 | } | 548 | } |
539 | 549 | ||
@@ -629,6 +639,7 @@ static int write_modem(struct cardstate *cs) | |||
629 | int count; | 639 | int count; |
630 | struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ | 640 | struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ |
631 | struct usb_cardstate *ucs = cs->hw.usb; | 641 | struct usb_cardstate *ucs = cs->hw.usb; |
642 | unsigned long flags; | ||
632 | 643 | ||
633 | gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len); | 644 | gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len); |
634 | 645 | ||
@@ -644,20 +655,27 @@ static int write_modem(struct cardstate *cs) | |||
644 | count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); | 655 | count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); |
645 | memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count); | 656 | memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count); |
646 | skb_pull(bcs->tx_skb, count); | 657 | skb_pull(bcs->tx_skb, count); |
647 | |||
648 | usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, | ||
649 | usb_sndbulkpipe(ucs->udev, | ||
650 | ucs->bulk_out_endpointAddr & 0x0f), | ||
651 | ucs->bulk_out_buffer, count, | ||
652 | gigaset_write_bulk_callback, cs); | ||
653 | atomic_set(&ucs->busy, 1); | 658 | atomic_set(&ucs->busy, 1); |
654 | gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); | 659 | gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); |
655 | 660 | ||
656 | ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); | 661 | spin_lock_irqsave(&cs->lock, flags); |
662 | if (cs->connected) { | ||
663 | usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, | ||
664 | usb_sndbulkpipe(ucs->udev, | ||
665 | ucs->bulk_out_endpointAddr & 0x0f), | ||
666 | ucs->bulk_out_buffer, count, | ||
667 | gigaset_write_bulk_callback, cs); | ||
668 | ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); | ||
669 | } else { | ||
670 | ret = -ENODEV; | ||
671 | } | ||
672 | spin_unlock_irqrestore(&cs->lock, flags); | ||
673 | |||
657 | if (ret) { | 674 | if (ret) { |
658 | dev_err(cs->dev, "could not submit urb (error %d)\n", -ret); | 675 | err("could not submit urb (error %d)\n", -ret); |
659 | atomic_set(&ucs->busy, 0); | 676 | atomic_set(&ucs->busy, 0); |
660 | } | 677 | } |
678 | |||
661 | if (!bcs->tx_skb->len) { | 679 | if (!bcs->tx_skb->len) { |
662 | /* skb sent completely */ | 680 | /* skb sent completely */ |
663 | gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0? | 681 | gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0? |