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 | |
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')
-rw-r--r-- | drivers/isdn/gigaset/asyncdata.c | 9 | ||||
-rw-r--r-- | drivers/isdn/gigaset/bas-gigaset.c | 48 | ||||
-rw-r--r-- | drivers/isdn/gigaset/common.c | 64 | ||||
-rw-r--r-- | drivers/isdn/gigaset/ev-layer.c | 87 | ||||
-rw-r--r-- | drivers/isdn/gigaset/gigaset.h | 18 | ||||
-rw-r--r-- | drivers/isdn/gigaset/i4l.c | 19 | ||||
-rw-r--r-- | drivers/isdn/gigaset/interface.c | 19 | ||||
-rw-r--r-- | drivers/isdn/gigaset/isocdata.c | 6 | ||||
-rw-r--r-- | drivers/isdn/gigaset/proc.c | 9 | ||||
-rw-r--r-- | drivers/isdn/gigaset/usb-gigaset.c | 86 |
10 files changed, 211 insertions, 154 deletions
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index ce60f6521b96..ce3cd77094b3 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c | |||
@@ -566,19 +566,22 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) | |||
566 | int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) | 566 | int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) |
567 | { | 567 | { |
568 | unsigned len = skb->len; | 568 | unsigned len = skb->len; |
569 | unsigned long flags; | ||
569 | 570 | ||
570 | if (bcs->proto2 == ISDN_PROTO_L2_HDLC) | 571 | if (bcs->proto2 == ISDN_PROTO_L2_HDLC) |
571 | skb = HDLC_Encode(skb, HW_HDR_LEN, 0); | 572 | skb = HDLC_Encode(skb, HW_HDR_LEN, 0); |
572 | else | 573 | else |
573 | skb = iraw_encode(skb, HW_HDR_LEN, 0); | 574 | skb = iraw_encode(skb, HW_HDR_LEN, 0); |
574 | if (!skb) { | 575 | if (!skb) { |
575 | dev_err(bcs->cs->dev, | 576 | err("unable to allocate memory for encoding!\n"); |
576 | "unable to allocate memory for encoding!\n"); | ||
577 | return -ENOMEM; | 577 | return -ENOMEM; |
578 | } | 578 | } |
579 | 579 | ||
580 | skb_queue_tail(&bcs->squeue, skb); | 580 | skb_queue_tail(&bcs->squeue, skb); |
581 | tasklet_schedule(&bcs->cs->write_tasklet); | 581 | spin_lock_irqsave(&bcs->cs->lock, flags); |
582 | if (bcs->cs->connected) | ||
583 | tasklet_schedule(&bcs->cs->write_tasklet); | ||
584 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
582 | 585 | ||
583 | return len; /* ok so far */ | 586 | return len; /* ok so far */ |
584 | } | 587 | } |
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index fa37db68c962..f86ed6af3aa2 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c | |||
@@ -367,7 +367,7 @@ static void cmd_in_timeout(unsigned long data) | |||
367 | unsigned long flags; | 367 | unsigned long flags; |
368 | 368 | ||
369 | spin_lock_irqsave(&cs->lock, flags); | 369 | spin_lock_irqsave(&cs->lock, flags); |
370 | if (unlikely(!atomic_read(&cs->connected))) { | 370 | if (unlikely(!cs->connected)) { |
371 | gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__); | 371 | gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__); |
372 | spin_unlock_irqrestore(&cs->lock, flags); | 372 | spin_unlock_irqrestore(&cs->lock, flags); |
373 | return; | 373 | return; |
@@ -475,11 +475,6 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) | |||
475 | unsigned l; | 475 | unsigned l; |
476 | int channel; | 476 | int channel; |
477 | 477 | ||
478 | if (unlikely(!atomic_read(&cs->connected))) { | ||
479 | warn("%s: disconnected", __func__); | ||
480 | return; | ||
481 | } | ||
482 | |||
483 | switch (urb->status) { | 478 | switch (urb->status) { |
484 | case 0: /* success */ | 479 | case 0: /* success */ |
485 | break; | 480 | break; |
@@ -603,7 +598,9 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) | |||
603 | check_pending(ucs); | 598 | check_pending(ucs); |
604 | 599 | ||
605 | resubmit: | 600 | resubmit: |
606 | status = usb_submit_urb(urb, SLAB_ATOMIC); | 601 | spin_lock_irqsave(&cs->lock, flags); |
602 | status = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; | ||
603 | spin_unlock_irqrestore(&cs->lock, flags); | ||
607 | if (unlikely(status)) { | 604 | if (unlikely(status)) { |
608 | dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", | 605 | dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", |
609 | get_usb_statmsg(status)); | 606 | get_usb_statmsg(status)); |
@@ -628,7 +625,7 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) | |||
628 | unsigned long flags; | 625 | unsigned long flags; |
629 | 626 | ||
630 | spin_lock_irqsave(&cs->lock, flags); | 627 | spin_lock_irqsave(&cs->lock, flags); |
631 | if (unlikely(!atomic_read(&cs->connected))) { | 628 | if (unlikely(!cs->connected)) { |
632 | warn("%s: disconnected", __func__); | 629 | warn("%s: disconnected", __func__); |
633 | spin_unlock_irqrestore(&cs->lock, flags); | 630 | spin_unlock_irqrestore(&cs->lock, flags); |
634 | return; | 631 | return; |
@@ -949,6 +946,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) | |||
949 | struct bas_bc_state *ubc = ucx->bcs->hw.bas; | 946 | struct bas_bc_state *ubc = ucx->bcs->hw.bas; |
950 | struct usb_iso_packet_descriptor *ifd; | 947 | struct usb_iso_packet_descriptor *ifd; |
951 | int corrbytes, nframe, rc; | 948 | int corrbytes, nframe, rc; |
949 | unsigned long flags; | ||
952 | 950 | ||
953 | /* urb->dev is clobbered by USB subsystem */ | 951 | /* urb->dev is clobbered by USB subsystem */ |
954 | urb->dev = ucx->bcs->cs->hw.bas->udev; | 952 | urb->dev = ucx->bcs->cs->hw.bas->udev; |
@@ -995,7 +993,11 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) | |||
995 | ifd->actual_length = 0; | 993 | ifd->actual_length = 0; |
996 | } | 994 | } |
997 | if ((urb->number_of_packets = nframe) > 0) { | 995 | if ((urb->number_of_packets = nframe) > 0) { |
998 | if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { | 996 | spin_lock_irqsave(&ucx->bcs->cs->lock, flags); |
997 | rc = ucx->bcs->cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; | ||
998 | spin_unlock_irqrestore(&ucx->bcs->cs->lock, flags); | ||
999 | |||
1000 | if (rc) { | ||
999 | dev_err(ucx->bcs->cs->dev, | 1001 | dev_err(ucx->bcs->cs->dev, |
1000 | "could not submit isochronous write URB: %s\n", | 1002 | "could not submit isochronous write URB: %s\n", |
1001 | get_usb_statmsg(rc)); | 1003 | get_usb_statmsg(rc)); |
@@ -1029,11 +1031,6 @@ static void write_iso_tasklet(unsigned long data) | |||
1029 | 1031 | ||
1030 | /* loop while completed URBs arrive in time */ | 1032 | /* loop while completed URBs arrive in time */ |
1031 | for (;;) { | 1033 | for (;;) { |
1032 | if (unlikely(!atomic_read(&cs->connected))) { | ||
1033 | warn("%s: disconnected", __func__); | ||
1034 | return; | ||
1035 | } | ||
1036 | |||
1037 | if (unlikely(!(atomic_read(&ubc->running)))) { | 1034 | if (unlikely(!(atomic_read(&ubc->running)))) { |
1038 | gig_dbg(DEBUG_ISO, "%s: not running", __func__); | 1035 | gig_dbg(DEBUG_ISO, "%s: not running", __func__); |
1039 | return; | 1036 | return; |
@@ -1190,11 +1187,6 @@ static void read_iso_tasklet(unsigned long data) | |||
1190 | 1187 | ||
1191 | /* loop while more completed URBs arrive in the meantime */ | 1188 | /* loop while more completed URBs arrive in the meantime */ |
1192 | for (;;) { | 1189 | for (;;) { |
1193 | if (unlikely(!atomic_read(&cs->connected))) { | ||
1194 | warn("%s: disconnected", __func__); | ||
1195 | return; | ||
1196 | } | ||
1197 | |||
1198 | /* retrieve URB */ | 1190 | /* retrieve URB */ |
1199 | spin_lock_irqsave(&ubc->isoinlock, flags); | 1191 | spin_lock_irqsave(&ubc->isoinlock, flags); |
1200 | if (!(urb = ubc->isoindone)) { | 1192 | if (!(urb = ubc->isoindone)) { |
@@ -1298,7 +1290,10 @@ static void read_iso_tasklet(unsigned long data) | |||
1298 | urb->dev = bcs->cs->hw.bas->udev; | 1290 | urb->dev = bcs->cs->hw.bas->udev; |
1299 | urb->transfer_flags = URB_ISO_ASAP; | 1291 | urb->transfer_flags = URB_ISO_ASAP; |
1300 | urb->number_of_packets = BAS_NUMFRAMES; | 1292 | urb->number_of_packets = BAS_NUMFRAMES; |
1301 | if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { | 1293 | spin_lock_irqsave(&cs->lock, flags); |
1294 | rc = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; | ||
1295 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1296 | if (rc) { | ||
1302 | dev_err(cs->dev, | 1297 | dev_err(cs->dev, |
1303 | "could not resubmit isochronous read URB: %s\n", | 1298 | "could not resubmit isochronous read URB: %s\n", |
1304 | get_usb_statmsg(rc)); | 1299 | get_usb_statmsg(rc)); |
@@ -1639,6 +1634,7 @@ static void atrdy_timeout(unsigned long data) | |||
1639 | static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) | 1634 | static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) |
1640 | { | 1635 | { |
1641 | struct bas_cardstate *ucs = cs->hw.bas; | 1636 | struct bas_cardstate *ucs = cs->hw.bas; |
1637 | unsigned long flags; | ||
1642 | int ret; | 1638 | int ret; |
1643 | 1639 | ||
1644 | gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); | 1640 | gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); |
@@ -1659,7 +1655,11 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) | |||
1659 | (unsigned char*) &ucs->dr_cmd_out, buf, len, | 1655 | (unsigned char*) &ucs->dr_cmd_out, buf, len, |
1660 | write_command_callback, cs); | 1656 | write_command_callback, cs); |
1661 | 1657 | ||
1662 | if ((ret = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC)) != 0) { | 1658 | spin_lock_irqsave(&cs->lock, flags); |
1659 | ret = cs->connected ? usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC) : -ENODEV; | ||
1660 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1661 | |||
1662 | if (ret) { | ||
1663 | dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n", | 1663 | dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n", |
1664 | get_usb_statmsg(ret)); | 1664 | get_usb_statmsg(ret)); |
1665 | return ret; | 1665 | return ret; |
@@ -1758,11 +1758,6 @@ static int gigaset_write_cmd(struct cardstate *cs, | |||
1758 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, | 1758 | DEBUG_TRANSCMD : DEBUG_LOCKCMD, |
1759 | "CMD Transmit", len, buf); | 1759 | "CMD Transmit", len, buf); |
1760 | 1760 | ||
1761 | if (unlikely(!atomic_read(&cs->connected))) { | ||
1762 | err("%s: disconnected", __func__); | ||
1763 | return -ENODEV; | ||
1764 | } | ||
1765 | |||
1766 | if (len <= 0) | 1761 | if (len <= 0) |
1767 | return 0; /* nothing to do */ | 1762 | return 0; /* nothing to do */ |
1768 | 1763 | ||
@@ -2186,6 +2181,7 @@ static int gigaset_probe(struct usb_interface *interface, | |||
2186 | 2181 | ||
2187 | error: | 2182 | error: |
2188 | freeurbs(cs); | 2183 | freeurbs(cs); |
2184 | usb_set_intfdata(interface, NULL); | ||
2189 | gigaset_unassign(cs); | 2185 | gigaset_unassign(cs); |
2190 | return -ENODEV; | 2186 | return -ENODEV; |
2191 | } | 2187 | } |
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index f8e5759c636c..d00acddd6213 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c | |||
@@ -129,11 +129,6 @@ int gigaset_enterconfigmode(struct cardstate *cs) | |||
129 | { | 129 | { |
130 | int i, r; | 130 | int i, r; |
131 | 131 | ||
132 | if (!atomic_read(&cs->connected)) { | ||
133 | err("not connected!"); | ||
134 | return -1; | ||
135 | } | ||
136 | |||
137 | cs->control_state = TIOCM_RTS; //FIXME | 132 | cs->control_state = TIOCM_RTS; //FIXME |
138 | 133 | ||
139 | r = setflags(cs, TIOCM_DTR, 200); | 134 | r = setflags(cs, TIOCM_DTR, 200); |
@@ -176,7 +171,7 @@ static int test_timeout(struct at_state_t *at_state) | |||
176 | } | 171 | } |
177 | 172 | ||
178 | if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL, | 173 | if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL, |
179 | atomic_read(&at_state->timer_index), NULL)) { | 174 | at_state->timer_index, NULL)) { |
180 | //FIXME what should we do? | 175 | //FIXME what should we do? |
181 | } | 176 | } |
182 | 177 | ||
@@ -204,7 +199,7 @@ static void timer_tick(unsigned long data) | |||
204 | if (test_timeout(at_state)) | 199 | if (test_timeout(at_state)) |
205 | timeout = 1; | 200 | timeout = 1; |
206 | 201 | ||
207 | if (atomic_read(&cs->running)) { | 202 | if (cs->running) { |
208 | mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK)); | 203 | mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK)); |
209 | if (timeout) { | 204 | if (timeout) { |
210 | gig_dbg(DEBUG_CMD, "scheduling timeout"); | 205 | gig_dbg(DEBUG_CMD, "scheduling timeout"); |
@@ -298,20 +293,22 @@ static void clear_events(struct cardstate *cs) | |||
298 | { | 293 | { |
299 | struct event_t *ev; | 294 | struct event_t *ev; |
300 | unsigned head, tail; | 295 | unsigned head, tail; |
296 | unsigned long flags; | ||
301 | 297 | ||
302 | /* no locking needed (no reader/writer allowed) */ | 298 | spin_lock_irqsave(&cs->ev_lock, flags); |
303 | 299 | ||
304 | head = atomic_read(&cs->ev_head); | 300 | head = cs->ev_head; |
305 | tail = atomic_read(&cs->ev_tail); | 301 | tail = cs->ev_tail; |
306 | 302 | ||
307 | while (tail != head) { | 303 | while (tail != head) { |
308 | ev = cs->events + head; | 304 | ev = cs->events + head; |
309 | kfree(ev->ptr); | 305 | kfree(ev->ptr); |
310 | |||
311 | head = (head + 1) % MAX_EVENTS; | 306 | head = (head + 1) % MAX_EVENTS; |
312 | } | 307 | } |
313 | 308 | ||
314 | atomic_set(&cs->ev_head, tail); | 309 | cs->ev_head = tail; |
310 | |||
311 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
315 | } | 312 | } |
316 | 313 | ||
317 | struct event_t *gigaset_add_event(struct cardstate *cs, | 314 | struct event_t *gigaset_add_event(struct cardstate *cs, |
@@ -324,9 +321,9 @@ struct event_t *gigaset_add_event(struct cardstate *cs, | |||
324 | 321 | ||
325 | spin_lock_irqsave(&cs->ev_lock, flags); | 322 | spin_lock_irqsave(&cs->ev_lock, flags); |
326 | 323 | ||
327 | tail = atomic_read(&cs->ev_tail); | 324 | tail = cs->ev_tail; |
328 | next = (tail + 1) % MAX_EVENTS; | 325 | next = (tail + 1) % MAX_EVENTS; |
329 | if (unlikely(next == atomic_read(&cs->ev_head))) | 326 | if (unlikely(next == cs->ev_head)) |
330 | err("event queue full"); | 327 | err("event queue full"); |
331 | else { | 328 | else { |
332 | event = cs->events + tail; | 329 | event = cs->events + tail; |
@@ -336,7 +333,7 @@ struct event_t *gigaset_add_event(struct cardstate *cs, | |||
336 | event->ptr = ptr; | 333 | event->ptr = ptr; |
337 | event->arg = arg; | 334 | event->arg = arg; |
338 | event->parameter = parameter; | 335 | event->parameter = parameter; |
339 | atomic_set(&cs->ev_tail, next); | 336 | cs->ev_tail = next; |
340 | } | 337 | } |
341 | 338 | ||
342 | spin_unlock_irqrestore(&cs->ev_lock, flags); | 339 | spin_unlock_irqrestore(&cs->ev_lock, flags); |
@@ -454,7 +451,7 @@ void gigaset_freecs(struct cardstate *cs) | |||
454 | goto f_bcs; | 451 | goto f_bcs; |
455 | 452 | ||
456 | spin_lock_irqsave(&cs->lock, flags); | 453 | spin_lock_irqsave(&cs->lock, flags); |
457 | atomic_set(&cs->running, 0); | 454 | cs->running = 0; |
458 | spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are | 455 | spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are |
459 | not rescheduled below */ | 456 | not rescheduled below */ |
460 | 457 | ||
@@ -513,8 +510,8 @@ void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, | |||
513 | at_state->pending_commands = 0; | 510 | at_state->pending_commands = 0; |
514 | at_state->timer_expires = 0; | 511 | at_state->timer_expires = 0; |
515 | at_state->timer_active = 0; | 512 | at_state->timer_active = 0; |
516 | atomic_set(&at_state->timer_index, 0); | 513 | at_state->timer_index = 0; |
517 | atomic_set(&at_state->seq_index, 0); | 514 | at_state->seq_index = 0; |
518 | at_state->ConState = 0; | 515 | at_state->ConState = 0; |
519 | for (i = 0; i < STR_NUM; ++i) | 516 | for (i = 0; i < STR_NUM; ++i) |
520 | at_state->str_var[i] = NULL; | 517 | at_state->str_var[i] = NULL; |
@@ -665,6 +662,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
665 | int cidmode, const char *modulename) | 662 | int cidmode, const char *modulename) |
666 | { | 663 | { |
667 | struct cardstate *cs = NULL; | 664 | struct cardstate *cs = NULL; |
665 | unsigned long flags; | ||
668 | int i; | 666 | int i; |
669 | 667 | ||
670 | gig_dbg(DEBUG_INIT, "allocating cs"); | 668 | gig_dbg(DEBUG_INIT, "allocating cs"); |
@@ -685,11 +683,11 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
685 | cs->onechannel = onechannel; | 683 | cs->onechannel = onechannel; |
686 | cs->ignoreframes = ignoreframes; | 684 | cs->ignoreframes = ignoreframes; |
687 | INIT_LIST_HEAD(&cs->temp_at_states); | 685 | INIT_LIST_HEAD(&cs->temp_at_states); |
688 | atomic_set(&cs->running, 0); | 686 | cs->running = 0; |
689 | init_timer(&cs->timer); /* clear next & prev */ | 687 | init_timer(&cs->timer); /* clear next & prev */ |
690 | spin_lock_init(&cs->ev_lock); | 688 | spin_lock_init(&cs->ev_lock); |
691 | atomic_set(&cs->ev_tail, 0); | 689 | cs->ev_tail = 0; |
692 | atomic_set(&cs->ev_head, 0); | 690 | cs->ev_head = 0; |
693 | mutex_init(&cs->mutex); | 691 | mutex_init(&cs->mutex); |
694 | mutex_lock(&cs->mutex); | 692 | mutex_lock(&cs->mutex); |
695 | 693 | ||
@@ -701,7 +699,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
701 | cs->open_count = 0; | 699 | cs->open_count = 0; |
702 | cs->dev = NULL; | 700 | cs->dev = NULL; |
703 | cs->tty = NULL; | 701 | cs->tty = NULL; |
704 | atomic_set(&cs->cidmode, cidmode != 0); | 702 | cs->cidmode = cidmode != 0; |
705 | 703 | ||
706 | //if(onechannel) { //FIXME | 704 | //if(onechannel) { //FIXME |
707 | cs->tabnocid = gigaset_tab_nocid_m10x; | 705 | cs->tabnocid = gigaset_tab_nocid_m10x; |
@@ -737,7 +735,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
737 | } else | 735 | } else |
738 | gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command); | 736 | gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command); |
739 | 737 | ||
740 | atomic_set(&cs->connected, 0); | 738 | cs->connected = 0; |
739 | cs->isdn_up = 0; | ||
741 | 740 | ||
742 | gig_dbg(DEBUG_INIT, "setting up cmdbuf"); | 741 | gig_dbg(DEBUG_INIT, "setting up cmdbuf"); |
743 | cs->cmdbuf = cs->lastcmdbuf = NULL; | 742 | cs->cmdbuf = cs->lastcmdbuf = NULL; |
@@ -761,7 +760,9 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
761 | 760 | ||
762 | gigaset_if_init(cs); | 761 | gigaset_if_init(cs); |
763 | 762 | ||
764 | atomic_set(&cs->running, 1); | 763 | spin_lock_irqsave(&cs->lock, flags); |
764 | cs->running = 1; | ||
765 | spin_unlock_irqrestore(&cs->lock, flags); | ||
765 | setup_timer(&cs->timer, timer_tick, (unsigned long) cs); | 766 | setup_timer(&cs->timer, timer_tick, (unsigned long) cs); |
766 | cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK); | 767 | cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK); |
767 | /* FIXME: can jiffies increase too much until the timer is added? | 768 | /* FIXME: can jiffies increase too much until the timer is added? |
@@ -871,10 +872,14 @@ static void cleanup_cs(struct cardstate *cs) | |||
871 | 872 | ||
872 | int gigaset_start(struct cardstate *cs) | 873 | int gigaset_start(struct cardstate *cs) |
873 | { | 874 | { |
875 | unsigned long flags; | ||
876 | |||
874 | if (mutex_lock_interruptible(&cs->mutex)) | 877 | if (mutex_lock_interruptible(&cs->mutex)) |
875 | return 0; | 878 | return 0; |
876 | 879 | ||
877 | atomic_set(&cs->connected, 1); | 880 | spin_lock_irqsave(&cs->lock, flags); |
881 | cs->connected = 1; | ||
882 | spin_unlock_irqrestore(&cs->lock, flags); | ||
878 | 883 | ||
879 | if (atomic_read(&cs->mstate) != MS_LOCKED) { | 884 | if (atomic_read(&cs->mstate) != MS_LOCKED) { |
880 | cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); | 885 | cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); |
@@ -950,11 +955,6 @@ void gigaset_stop(struct cardstate *cs) | |||
950 | { | 955 | { |
951 | mutex_lock(&cs->mutex); | 956 | mutex_lock(&cs->mutex); |
952 | 957 | ||
953 | /* clear device sysfs */ | ||
954 | gigaset_free_dev_sysfs(cs); | ||
955 | |||
956 | atomic_set(&cs->connected, 0); | ||
957 | |||
958 | cs->waiting = 1; | 958 | cs->waiting = 1; |
959 | 959 | ||
960 | if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) { | 960 | if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) { |
@@ -970,8 +970,8 @@ void gigaset_stop(struct cardstate *cs) | |||
970 | //FIXME | 970 | //FIXME |
971 | } | 971 | } |
972 | 972 | ||
973 | /* Tell the LL that the device is not available .. */ | 973 | /* clear device sysfs */ |
974 | gigaset_i4l_cmd(cs, ISDN_STAT_STOP); // FIXME move to event layer? | 974 | gigaset_free_dev_sysfs(cs); |
975 | 975 | ||
976 | cleanup_cs(cs); | 976 | cleanup_cs(cs); |
977 | 977 | ||
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 2e826d051c85..1ba3424a286b 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c | |||
@@ -482,14 +482,6 @@ static int isdn_gethex(char *p) | |||
482 | return v; | 482 | return v; |
483 | } | 483 | } |
484 | 484 | ||
485 | static inline void new_index(atomic_t *index, int max) | ||
486 | { | ||
487 | if (atomic_read(index) == max) //FIXME race? | ||
488 | atomic_set(index, 0); | ||
489 | else | ||
490 | atomic_inc(index); | ||
491 | } | ||
492 | |||
493 | /* retrieve CID from parsed response | 485 | /* retrieve CID from parsed response |
494 | * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535 | 486 | * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535 |
495 | */ | 487 | */ |
@@ -581,8 +573,8 @@ void gigaset_handle_modem_response(struct cardstate *cs) | |||
581 | } | 573 | } |
582 | 574 | ||
583 | spin_lock_irqsave(&cs->ev_lock, flags); | 575 | spin_lock_irqsave(&cs->ev_lock, flags); |
584 | head = atomic_read(&cs->ev_head); | 576 | head = cs->ev_head; |
585 | tail = atomic_read(&cs->ev_tail); | 577 | tail = cs->ev_tail; |
586 | 578 | ||
587 | abort = 1; | 579 | abort = 1; |
588 | curarg = 0; | 580 | curarg = 0; |
@@ -715,7 +707,7 @@ void gigaset_handle_modem_response(struct cardstate *cs) | |||
715 | break; | 707 | break; |
716 | } | 708 | } |
717 | 709 | ||
718 | atomic_set(&cs->ev_tail, tail); | 710 | cs->ev_tail = tail; |
719 | spin_unlock_irqrestore(&cs->ev_lock, flags); | 711 | spin_unlock_irqrestore(&cs->ev_lock, flags); |
720 | 712 | ||
721 | if (curarg != params) | 713 | if (curarg != params) |
@@ -734,14 +726,16 @@ static void disconnect(struct at_state_t **at_state_p) | |||
734 | struct bc_state *bcs = (*at_state_p)->bcs; | 726 | struct bc_state *bcs = (*at_state_p)->bcs; |
735 | struct cardstate *cs = (*at_state_p)->cs; | 727 | struct cardstate *cs = (*at_state_p)->cs; |
736 | 728 | ||
737 | new_index(&(*at_state_p)->seq_index, MAX_SEQ_INDEX); | 729 | spin_lock_irqsave(&cs->lock, flags); |
730 | ++(*at_state_p)->seq_index; | ||
738 | 731 | ||
739 | /* revert to selected idle mode */ | 732 | /* revert to selected idle mode */ |
740 | if (!atomic_read(&cs->cidmode)) { | 733 | if (!cs->cidmode) { |
741 | cs->at_state.pending_commands |= PC_UMMODE; | 734 | cs->at_state.pending_commands |= PC_UMMODE; |
742 | atomic_set(&cs->commands_pending, 1); //FIXME | 735 | atomic_set(&cs->commands_pending, 1); //FIXME |
743 | gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); | 736 | gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); |
744 | } | 737 | } |
738 | spin_unlock_irqrestore(&cs->lock, flags); | ||
745 | 739 | ||
746 | if (bcs) { | 740 | if (bcs) { |
747 | /* B channel assigned: invoke hardware specific handler */ | 741 | /* B channel assigned: invoke hardware specific handler */ |
@@ -933,17 +927,21 @@ static void bchannel_up(struct bc_state *bcs) | |||
933 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); | 927 | gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); |
934 | } | 928 | } |
935 | 929 | ||
936 | static void start_dial(struct at_state_t *at_state, void *data, int seq_index) | 930 | static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_index) |
937 | { | 931 | { |
938 | struct bc_state *bcs = at_state->bcs; | 932 | struct bc_state *bcs = at_state->bcs; |
939 | struct cardstate *cs = at_state->cs; | 933 | struct cardstate *cs = at_state->cs; |
940 | int retval; | 934 | int retval; |
935 | unsigned long flags; | ||
941 | 936 | ||
942 | bcs->chstate |= CHS_NOTIFY_LL; | 937 | bcs->chstate |= CHS_NOTIFY_LL; |
943 | //atomic_set(&bcs->status, BCS_INIT); | ||
944 | 938 | ||
945 | if (atomic_read(&at_state->seq_index) != seq_index) | 939 | spin_lock_irqsave(&cs->lock, flags); |
940 | if (at_state->seq_index != seq_index) { | ||
941 | spin_unlock_irqrestore(&cs->lock, flags); | ||
946 | goto error; | 942 | goto error; |
943 | } | ||
944 | spin_unlock_irqrestore(&cs->lock, flags); | ||
947 | 945 | ||
948 | retval = gigaset_isdn_setup_dial(at_state, data); | 946 | retval = gigaset_isdn_setup_dial(at_state, data); |
949 | if (retval != 0) | 947 | if (retval != 0) |
@@ -988,6 +986,7 @@ static void do_start(struct cardstate *cs) | |||
988 | if (atomic_read(&cs->mstate) != MS_LOCKED) | 986 | if (atomic_read(&cs->mstate) != MS_LOCKED) |
989 | schedule_init(cs, MS_INIT); | 987 | schedule_init(cs, MS_INIT); |
990 | 988 | ||
989 | cs->isdn_up = 1; | ||
991 | gigaset_i4l_cmd(cs, ISDN_STAT_RUN); | 990 | gigaset_i4l_cmd(cs, ISDN_STAT_RUN); |
992 | // FIXME: not in locked mode | 991 | // FIXME: not in locked mode |
993 | // FIXME 2: only after init sequence | 992 | // FIXME 2: only after init sequence |
@@ -1003,6 +1002,12 @@ static void finish_shutdown(struct cardstate *cs) | |||
1003 | atomic_set(&cs->mode, M_UNKNOWN); | 1002 | atomic_set(&cs->mode, M_UNKNOWN); |
1004 | } | 1003 | } |
1005 | 1004 | ||
1005 | /* Tell the LL that the device is not available .. */ | ||
1006 | if (cs->isdn_up) { | ||
1007 | cs->isdn_up = 0; | ||
1008 | gigaset_i4l_cmd(cs, ISDN_STAT_STOP); | ||
1009 | } | ||
1010 | |||
1006 | /* The rest is done by cleanup_cs () in user mode. */ | 1011 | /* The rest is done by cleanup_cs () in user mode. */ |
1007 | 1012 | ||
1008 | cs->cmd_result = -ENODEV; | 1013 | cs->cmd_result = -ENODEV; |
@@ -1025,6 +1030,12 @@ static void do_shutdown(struct cardstate *cs) | |||
1025 | 1030 | ||
1026 | static void do_stop(struct cardstate *cs) | 1031 | static void do_stop(struct cardstate *cs) |
1027 | { | 1032 | { |
1033 | unsigned long flags; | ||
1034 | |||
1035 | spin_lock_irqsave(&cs->lock, flags); | ||
1036 | cs->connected = 0; | ||
1037 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1038 | |||
1028 | do_shutdown(cs); | 1039 | do_shutdown(cs); |
1029 | } | 1040 | } |
1030 | 1041 | ||
@@ -1153,7 +1164,7 @@ static int do_unlock(struct cardstate *cs) | |||
1153 | atomic_set(&cs->mstate, MS_UNINITIALIZED); | 1164 | atomic_set(&cs->mstate, MS_UNINITIALIZED); |
1154 | atomic_set(&cs->mode, M_UNKNOWN); | 1165 | atomic_set(&cs->mode, M_UNKNOWN); |
1155 | gigaset_free_channels(cs); | 1166 | gigaset_free_channels(cs); |
1156 | if (atomic_read(&cs->connected)) | 1167 | if (cs->connected) |
1157 | schedule_init(cs, MS_INIT); | 1168 | schedule_init(cs, MS_INIT); |
1158 | 1169 | ||
1159 | return 0; | 1170 | return 0; |
@@ -1185,11 +1196,14 @@ static void do_action(int action, struct cardstate *cs, | |||
1185 | cs->at_state.pending_commands &= ~PC_INIT; | 1196 | cs->at_state.pending_commands &= ~PC_INIT; |
1186 | cs->cur_at_seq = SEQ_NONE; | 1197 | cs->cur_at_seq = SEQ_NONE; |
1187 | atomic_set(&cs->mode, M_UNIMODEM); | 1198 | atomic_set(&cs->mode, M_UNIMODEM); |
1188 | if (!atomic_read(&cs->cidmode)) { | 1199 | spin_lock_irqsave(&cs->lock, flags); |
1200 | if (!cs->cidmode) { | ||
1201 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1189 | gigaset_free_channels(cs); | 1202 | gigaset_free_channels(cs); |
1190 | atomic_set(&cs->mstate, MS_READY); | 1203 | atomic_set(&cs->mstate, MS_READY); |
1191 | break; | 1204 | break; |
1192 | } | 1205 | } |
1206 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1193 | cs->at_state.pending_commands |= PC_CIDMODE; | 1207 | cs->at_state.pending_commands |= PC_CIDMODE; |
1194 | atomic_set(&cs->commands_pending, 1); | 1208 | atomic_set(&cs->commands_pending, 1); |
1195 | gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); | 1209 | gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); |
@@ -1536,8 +1550,9 @@ static void do_action(int action, struct cardstate *cs, | |||
1536 | 1550 | ||
1537 | /* events from the proc file system */ // FIXME without ACT_xxxx? | 1551 | /* events from the proc file system */ // FIXME without ACT_xxxx? |
1538 | case ACT_PROC_CIDMODE: | 1552 | case ACT_PROC_CIDMODE: |
1539 | if (ev->parameter != atomic_read(&cs->cidmode)) { | 1553 | spin_lock_irqsave(&cs->lock, flags); |
1540 | atomic_set(&cs->cidmode, ev->parameter); | 1554 | if (ev->parameter != cs->cidmode) { |
1555 | cs->cidmode = ev->parameter; | ||
1541 | if (ev->parameter) { | 1556 | if (ev->parameter) { |
1542 | cs->at_state.pending_commands |= PC_CIDMODE; | 1557 | cs->at_state.pending_commands |= PC_CIDMODE; |
1543 | gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); | 1558 | gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); |
@@ -1547,6 +1562,7 @@ static void do_action(int action, struct cardstate *cs, | |||
1547 | } | 1562 | } |
1548 | atomic_set(&cs->commands_pending, 1); | 1563 | atomic_set(&cs->commands_pending, 1); |
1549 | } | 1564 | } |
1565 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1550 | cs->waiting = 0; | 1566 | cs->waiting = 0; |
1551 | wake_up(&cs->waitqueue); | 1567 | wake_up(&cs->waitqueue); |
1552 | break; | 1568 | break; |
@@ -1615,8 +1631,9 @@ static void process_event(struct cardstate *cs, struct event_t *ev) | |||
1615 | /* Setting the pointer to the dial array */ | 1631 | /* Setting the pointer to the dial array */ |
1616 | rep = at_state->replystruct; | 1632 | rep = at_state->replystruct; |
1617 | 1633 | ||
1634 | spin_lock_irqsave(&cs->lock, flags); | ||
1618 | if (ev->type == EV_TIMEOUT) { | 1635 | if (ev->type == EV_TIMEOUT) { |
1619 | if (ev->parameter != atomic_read(&at_state->timer_index) | 1636 | if (ev->parameter != at_state->timer_index |
1620 | || !at_state->timer_active) { | 1637 | || !at_state->timer_active) { |
1621 | ev->type = RSP_NONE; /* old timeout */ | 1638 | ev->type = RSP_NONE; /* old timeout */ |
1622 | gig_dbg(DEBUG_ANY, "old timeout"); | 1639 | gig_dbg(DEBUG_ANY, "old timeout"); |
@@ -1625,6 +1642,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev) | |||
1625 | else | 1642 | else |
1626 | gig_dbg(DEBUG_ANY, "stopped waiting"); | 1643 | gig_dbg(DEBUG_ANY, "stopped waiting"); |
1627 | } | 1644 | } |
1645 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1628 | 1646 | ||
1629 | /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] | 1647 | /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] |
1630 | or at_state->str_var[STR_XXXX], set it */ | 1648 | or at_state->str_var[STR_XXXX], set it */ |
@@ -1686,7 +1704,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev) | |||
1686 | } else { | 1704 | } else { |
1687 | /* Send command to modem if not NULL... */ | 1705 | /* Send command to modem if not NULL... */ |
1688 | if (p_command/*rep->command*/) { | 1706 | if (p_command/*rep->command*/) { |
1689 | if (atomic_read(&cs->connected)) | 1707 | if (cs->connected) |
1690 | send_command(cs, p_command, | 1708 | send_command(cs, p_command, |
1691 | sendcid, cs->dle, | 1709 | sendcid, cs->dle, |
1692 | GFP_ATOMIC); | 1710 | GFP_ATOMIC); |
@@ -1703,8 +1721,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev) | |||
1703 | } else if (rep->timeout > 0) { /* new timeout */ | 1721 | } else if (rep->timeout > 0) { /* new timeout */ |
1704 | at_state->timer_expires = rep->timeout * 10; | 1722 | at_state->timer_expires = rep->timeout * 10; |
1705 | at_state->timer_active = 1; | 1723 | at_state->timer_active = 1; |
1706 | new_index(&at_state->timer_index, | 1724 | ++at_state->timer_index; |
1707 | MAX_TIMER_INDEX); | ||
1708 | } | 1725 | } |
1709 | spin_unlock_irqrestore(&cs->lock, flags); | 1726 | spin_unlock_irqrestore(&cs->lock, flags); |
1710 | } | 1727 | } |
@@ -1724,6 +1741,7 @@ static void process_command_flags(struct cardstate *cs) | |||
1724 | struct bc_state *bcs; | 1741 | struct bc_state *bcs; |
1725 | int i; | 1742 | int i; |
1726 | int sequence; | 1743 | int sequence; |
1744 | unsigned long flags; | ||
1727 | 1745 | ||
1728 | atomic_set(&cs->commands_pending, 0); | 1746 | atomic_set(&cs->commands_pending, 0); |
1729 | 1747 | ||
@@ -1773,8 +1791,9 @@ static void process_command_flags(struct cardstate *cs) | |||
1773 | } | 1791 | } |
1774 | 1792 | ||
1775 | /* only switch back to unimodem mode, if no commands are pending and no channels are up */ | 1793 | /* only switch back to unimodem mode, if no commands are pending and no channels are up */ |
1794 | spin_lock_irqsave(&cs->lock, flags); | ||
1776 | if (cs->at_state.pending_commands == PC_UMMODE | 1795 | if (cs->at_state.pending_commands == PC_UMMODE |
1777 | && !atomic_read(&cs->cidmode) | 1796 | && !cs->cidmode |
1778 | && list_empty(&cs->temp_at_states) | 1797 | && list_empty(&cs->temp_at_states) |
1779 | && atomic_read(&cs->mode) == M_CID) { | 1798 | && atomic_read(&cs->mode) == M_CID) { |
1780 | sequence = SEQ_UMMODE; | 1799 | sequence = SEQ_UMMODE; |
@@ -1788,6 +1807,7 @@ static void process_command_flags(struct cardstate *cs) | |||
1788 | } | 1807 | } |
1789 | } | 1808 | } |
1790 | } | 1809 | } |
1810 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1791 | cs->at_state.pending_commands &= ~PC_UMMODE; | 1811 | cs->at_state.pending_commands &= ~PC_UMMODE; |
1792 | if (sequence != SEQ_NONE) { | 1812 | if (sequence != SEQ_NONE) { |
1793 | schedule_sequence(cs, at_state, sequence); | 1813 | schedule_sequence(cs, at_state, sequence); |
@@ -1900,18 +1920,21 @@ static void process_events(struct cardstate *cs) | |||
1900 | int i; | 1920 | int i; |
1901 | int check_flags = 0; | 1921 | int check_flags = 0; |
1902 | int was_busy; | 1922 | int was_busy; |
1923 | unsigned long flags; | ||
1903 | 1924 | ||
1904 | /* no locking needed (only one reader) */ | 1925 | spin_lock_irqsave(&cs->ev_lock, flags); |
1905 | head = atomic_read(&cs->ev_head); | 1926 | head = cs->ev_head; |
1906 | 1927 | ||
1907 | for (i = 0; i < 2 * MAX_EVENTS; ++i) { | 1928 | for (i = 0; i < 2 * MAX_EVENTS; ++i) { |
1908 | tail = atomic_read(&cs->ev_tail); | 1929 | tail = cs->ev_tail; |
1909 | if (tail == head) { | 1930 | if (tail == head) { |
1910 | if (!check_flags && !atomic_read(&cs->commands_pending)) | 1931 | if (!check_flags && !atomic_read(&cs->commands_pending)) |
1911 | break; | 1932 | break; |
1912 | check_flags = 0; | 1933 | check_flags = 0; |
1934 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
1913 | process_command_flags(cs); | 1935 | process_command_flags(cs); |
1914 | tail = atomic_read(&cs->ev_tail); | 1936 | spin_lock_irqsave(&cs->ev_lock, flags); |
1937 | tail = cs->ev_tail; | ||
1915 | if (tail == head) { | 1938 | if (tail == head) { |
1916 | if (!atomic_read(&cs->commands_pending)) | 1939 | if (!atomic_read(&cs->commands_pending)) |
1917 | break; | 1940 | break; |
@@ -1921,16 +1944,20 @@ static void process_events(struct cardstate *cs) | |||
1921 | 1944 | ||
1922 | ev = cs->events + head; | 1945 | ev = cs->events + head; |
1923 | was_busy = cs->cur_at_seq != SEQ_NONE; | 1946 | was_busy = cs->cur_at_seq != SEQ_NONE; |
1947 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
1924 | process_event(cs, ev); | 1948 | process_event(cs, ev); |
1949 | spin_lock_irqsave(&cs->ev_lock, flags); | ||
1925 | kfree(ev->ptr); | 1950 | kfree(ev->ptr); |
1926 | ev->ptr = NULL; | 1951 | ev->ptr = NULL; |
1927 | if (was_busy && cs->cur_at_seq == SEQ_NONE) | 1952 | if (was_busy && cs->cur_at_seq == SEQ_NONE) |
1928 | check_flags = 1; | 1953 | check_flags = 1; |
1929 | 1954 | ||
1930 | head = (head + 1) % MAX_EVENTS; | 1955 | head = (head + 1) % MAX_EVENTS; |
1931 | atomic_set(&cs->ev_head, head); | 1956 | cs->ev_head = head; |
1932 | } | 1957 | } |
1933 | 1958 | ||
1959 | spin_unlock_irqrestore(&cs->ev_lock, flags); | ||
1960 | |||
1934 | if (i == 2 * MAX_EVENTS) { | 1961 | if (i == 2 * MAX_EVENTS) { |
1935 | dev_err(cs->dev, | 1962 | dev_err(cs->dev, |
1936 | "infinite loop in process_events; aborting.\n"); | 1963 | "infinite loop in process_events; aborting.\n"); |
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 39a883ebc696..350dfcf15e6c 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h | |||
@@ -55,9 +55,6 @@ | |||
55 | #define GIG_RETRYCID | 55 | #define GIG_RETRYCID |
56 | #define GIG_X75 | 56 | #define GIG_X75 |
57 | 57 | ||
58 | #define MAX_TIMER_INDEX 1000 | ||
59 | #define MAX_SEQ_INDEX 1000 | ||
60 | |||
61 | #define GIG_TICK 100 /* in milliseconds */ | 58 | #define GIG_TICK 100 /* in milliseconds */ |
62 | 59 | ||
63 | /* timeout values (unit: 1 sec) */ | 60 | /* timeout values (unit: 1 sec) */ |
@@ -375,7 +372,7 @@ struct at_state_t { | |||
375 | struct list_head list; | 372 | struct list_head list; |
376 | int waiting; | 373 | int waiting; |
377 | int getstring; | 374 | int getstring; |
378 | atomic_t timer_index; | 375 | unsigned timer_index; |
379 | unsigned long timer_expires; | 376 | unsigned long timer_expires; |
380 | int timer_active; | 377 | int timer_active; |
381 | unsigned int ConState; /* State of connection */ | 378 | unsigned int ConState; /* State of connection */ |
@@ -384,7 +381,7 @@ struct at_state_t { | |||
384 | int int_var[VAR_NUM]; /* see VAR_XXXX */ | 381 | int int_var[VAR_NUM]; /* see VAR_XXXX */ |
385 | char *str_var[STR_NUM]; /* see STR_XXXX */ | 382 | char *str_var[STR_NUM]; /* see STR_XXXX */ |
386 | unsigned pending_commands; /* see PC_XXXX */ | 383 | unsigned pending_commands; /* see PC_XXXX */ |
387 | atomic_t seq_index; | 384 | unsigned seq_index; |
388 | 385 | ||
389 | struct cardstate *cs; | 386 | struct cardstate *cs; |
390 | struct bc_state *bcs; | 387 | struct bc_state *bcs; |
@@ -484,10 +481,11 @@ struct cardstate { | |||
484 | unsigned fwver[4]; | 481 | unsigned fwver[4]; |
485 | int gotfwver; | 482 | int gotfwver; |
486 | 483 | ||
487 | atomic_t running; /* !=0 if events are handled */ | 484 | unsigned running; /* !=0 if events are handled */ |
488 | atomic_t connected; /* !=0 if hardware is connected */ | 485 | unsigned connected; /* !=0 if hardware is connected */ |
486 | unsigned isdn_up; /* !=0 after ISDN_STAT_RUN */ | ||
489 | 487 | ||
490 | atomic_t cidmode; | 488 | unsigned cidmode; |
491 | 489 | ||
492 | int myid; /* id for communication with LL */ | 490 | int myid; /* id for communication with LL */ |
493 | isdn_if iif; | 491 | isdn_if iif; |
@@ -528,7 +526,7 @@ struct cardstate { | |||
528 | 526 | ||
529 | /* event queue */ | 527 | /* event queue */ |
530 | struct event_t events[MAX_EVENTS]; | 528 | struct event_t events[MAX_EVENTS]; |
531 | atomic_t ev_tail, ev_head; | 529 | unsigned ev_tail, ev_head; |
532 | spinlock_t ev_lock; | 530 | spinlock_t ev_lock; |
533 | 531 | ||
534 | /* current modem response */ | 532 | /* current modem response */ |
@@ -824,7 +822,7 @@ static inline void gigaset_schedule_event(struct cardstate *cs) | |||
824 | { | 822 | { |
825 | unsigned long flags; | 823 | unsigned long flags; |
826 | spin_lock_irqsave(&cs->lock, flags); | 824 | spin_lock_irqsave(&cs->lock, flags); |
827 | if (atomic_read(&cs->running)) | 825 | if (cs->running) |
828 | tasklet_schedule(&cs->event_tasklet); | 826 | tasklet_schedule(&cs->event_tasklet); |
829 | spin_unlock_irqrestore(&cs->lock, flags); | 827 | spin_unlock_irqrestore(&cs->lock, flags); |
830 | } | 828 | } |
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 7059b84b96a7..0815dbfb8291 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c | |||
@@ -56,11 +56,6 @@ static int writebuf_from_LL(int driverID, int channel, int ack, | |||
56 | "Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)", | 56 | "Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)", |
57 | driverID, channel, ack, len); | 57 | driverID, channel, ack, len); |
58 | 58 | ||
59 | if (!atomic_read(&cs->connected)) { | ||
60 | err("%s: disconnected", __func__); | ||
61 | return -ENODEV; | ||
62 | } | ||
63 | |||
64 | if (!len) { | 59 | if (!len) { |
65 | if (ack) | 60 | if (ack) |
66 | notice("%s: not ACKing empty packet", __func__); | 61 | notice("%s: not ACKing empty packet", __func__); |
@@ -78,7 +73,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack, | |||
78 | len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]); | 73 | len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]); |
79 | 74 | ||
80 | /* pass to device-specific module */ | 75 | /* pass to device-specific module */ |
81 | return cs->ops->send_skb(bcs, skb); | 76 | return cs->ops->send_skb(bcs, skb); //FIXME cs->ops->send_skb() must handle !cs->connected correctly |
82 | } | 77 | } |
83 | 78 | ||
84 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) | 79 | void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) |
@@ -119,11 +114,12 @@ static int command_from_LL(isdn_ctrl *cntrl) | |||
119 | struct bc_state *bcs; | 114 | struct bc_state *bcs; |
120 | int retval = 0; | 115 | int retval = 0; |
121 | struct setup_parm *sp; | 116 | struct setup_parm *sp; |
117 | unsigned param; | ||
118 | unsigned long flags; | ||
122 | 119 | ||
123 | gigaset_debugdrivers(); | 120 | gigaset_debugdrivers(); |
124 | 121 | ||
125 | //FIXME "remove test for &connected" | 122 | if (!cs) { |
126 | if ((!cs || !atomic_read(&cs->connected))) { | ||
127 | warn("LL tried to access unknown device with nr. %d", | 123 | warn("LL tried to access unknown device with nr. %d", |
128 | cntrl->driver); | 124 | cntrl->driver); |
129 | return -ENODEV; | 125 | return -ENODEV; |
@@ -166,8 +162,11 @@ static int command_from_LL(isdn_ctrl *cntrl) | |||
166 | } | 162 | } |
167 | *sp = cntrl->parm.setup; | 163 | *sp = cntrl->parm.setup; |
168 | 164 | ||
169 | if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, | 165 | spin_lock_irqsave(&cs->lock, flags); |
170 | atomic_read(&bcs->at_state.seq_index), | 166 | param = bcs->at_state.seq_index; |
167 | spin_unlock_irqrestore(&cs->lock, flags); | ||
168 | |||
169 | if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, param, | ||
171 | NULL)) { | 170 | NULL)) { |
172 | //FIXME what should we do? | 171 | //FIXME what should we do? |
173 | kfree(sp); | 172 | kfree(sp); |
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index ac408acaaf17..08e4c4eea14d 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c | |||
@@ -33,7 +33,7 @@ static int if_lock(struct cardstate *cs, int *arg) | |||
33 | } | 33 | } |
34 | 34 | ||
35 | if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED | 35 | if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED |
36 | && atomic_read(&cs->connected)) { | 36 | && cs->connected) { |
37 | cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); | 37 | cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); |
38 | cs->ops->baud_rate(cs, B115200); | 38 | cs->ops->baud_rate(cs, B115200); |
39 | cs->ops->set_line_ctrl(cs, CS8); | 39 | cs->ops->set_line_ctrl(cs, CS8); |
@@ -107,6 +107,11 @@ static int if_config(struct cardstate *cs, int *arg) | |||
107 | if (atomic_read(&cs->mstate) != MS_LOCKED) | 107 | if (atomic_read(&cs->mstate) != MS_LOCKED) |
108 | return -EBUSY; | 108 | return -EBUSY; |
109 | 109 | ||
110 | if (!cs->connected) { | ||
111 | err("not connected!"); | ||
112 | return -ENODEV; | ||
113 | } | ||
114 | |||
110 | *arg = 0; | 115 | *arg = 0; |
111 | return gigaset_enterconfigmode(cs); | 116 | return gigaset_enterconfigmode(cs); |
112 | } | 117 | } |
@@ -246,7 +251,7 @@ static int if_ioctl(struct tty_struct *tty, struct file *file, | |||
246 | break; | 251 | break; |
247 | case GIGASET_BRKCHARS: | 252 | case GIGASET_BRKCHARS: |
248 | //FIXME test if MS_LOCKED | 253 | //FIXME test if MS_LOCKED |
249 | if (!atomic_read(&cs->connected)) { | 254 | if (!cs->connected) { |
250 | gig_dbg(DEBUG_ANY, | 255 | gig_dbg(DEBUG_ANY, |
251 | "can't communicate with unplugged device"); | 256 | "can't communicate with unplugged device"); |
252 | retval = -ENODEV; | 257 | retval = -ENODEV; |
@@ -327,7 +332,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file, | |||
327 | if (mutex_lock_interruptible(&cs->mutex)) | 332 | if (mutex_lock_interruptible(&cs->mutex)) |
328 | return -ERESTARTSYS; // FIXME -EINTR? | 333 | return -ERESTARTSYS; // FIXME -EINTR? |
329 | 334 | ||
330 | if (!atomic_read(&cs->connected)) { | 335 | if (!cs->connected) { |
331 | gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); | 336 | gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); |
332 | retval = -ENODEV; | 337 | retval = -ENODEV; |
333 | } else { | 338 | } else { |
@@ -362,7 +367,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) | |||
362 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { | 367 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { |
363 | warn("can't write to unlocked device"); | 368 | warn("can't write to unlocked device"); |
364 | retval = -EBUSY; | 369 | retval = -EBUSY; |
365 | } else if (!atomic_read(&cs->connected)) { | 370 | } else if (!cs->connected) { |
366 | gig_dbg(DEBUG_ANY, "can't write to unplugged device"); | 371 | gig_dbg(DEBUG_ANY, "can't write to unplugged device"); |
367 | retval = -EBUSY; //FIXME | 372 | retval = -EBUSY; //FIXME |
368 | } else { | 373 | } else { |
@@ -396,7 +401,7 @@ static int if_write_room(struct tty_struct *tty) | |||
396 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { | 401 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { |
397 | warn("can't write to unlocked device"); | 402 | warn("can't write to unlocked device"); |
398 | retval = -EBUSY; //FIXME | 403 | retval = -EBUSY; //FIXME |
399 | } else if (!atomic_read(&cs->connected)) { | 404 | } else if (!cs->connected) { |
400 | gig_dbg(DEBUG_ANY, "can't write to unplugged device"); | 405 | gig_dbg(DEBUG_ANY, "can't write to unplugged device"); |
401 | retval = -EBUSY; //FIXME | 406 | retval = -EBUSY; //FIXME |
402 | } else | 407 | } else |
@@ -428,7 +433,7 @@ static int if_chars_in_buffer(struct tty_struct *tty) | |||
428 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { | 433 | else if (atomic_read(&cs->mstate) != MS_LOCKED) { |
429 | warn("can't write to unlocked device"); | 434 | warn("can't write to unlocked device"); |
430 | retval = -EBUSY; | 435 | retval = -EBUSY; |
431 | } else if (!atomic_read(&cs->connected)) { | 436 | } else if (!cs->connected) { |
432 | gig_dbg(DEBUG_ANY, "can't write to unplugged device"); | 437 | gig_dbg(DEBUG_ANY, "can't write to unplugged device"); |
433 | retval = -EBUSY; //FIXME | 438 | retval = -EBUSY; //FIXME |
434 | } else | 439 | } else |
@@ -508,7 +513,7 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old) | |||
508 | goto out; | 513 | goto out; |
509 | } | 514 | } |
510 | 515 | ||
511 | if (!atomic_read(&cs->connected)) { | 516 | if (!cs->connected) { |
512 | gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); | 517 | gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); |
513 | goto out; | 518 | goto out; |
514 | } | 519 | } |
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 2f1628734a38..45f017ed6e8c 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c | |||
@@ -990,13 +990,17 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) | |||
990 | int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) | 990 | int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) |
991 | { | 991 | { |
992 | int len = skb->len; | 992 | int len = skb->len; |
993 | unsigned long flags; | ||
993 | 994 | ||
994 | skb_queue_tail(&bcs->squeue, skb); | 995 | skb_queue_tail(&bcs->squeue, skb); |
995 | gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d", | 996 | gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d", |
996 | __func__, skb_queue_len(&bcs->squeue)); | 997 | __func__, skb_queue_len(&bcs->squeue)); |
997 | 998 | ||
998 | /* tasklet submits URB if necessary */ | 999 | /* tasklet submits URB if necessary */ |
999 | tasklet_schedule(&bcs->hw.bas->sent_tasklet); | 1000 | spin_lock_irqsave(&bcs->cs->lock, flags); |
1001 | if (bcs->cs->connected) | ||
1002 | tasklet_schedule(&bcs->hw.bas->sent_tasklet); | ||
1003 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
1000 | 1004 | ||
1001 | return len; /* ok so far */ | 1005 | return len; /* ok so far */ |
1002 | } | 1006 | } |
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index 80d8ef1874f3..d267a636b53c 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c | |||
@@ -19,8 +19,15 @@ | |||
19 | static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, | 19 | static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, |
20 | char *buf) | 20 | char *buf) |
21 | { | 21 | { |
22 | int ret; | ||
23 | unsigned long flags; | ||
22 | struct cardstate *cs = dev_get_drvdata(dev); | 24 | struct cardstate *cs = dev_get_drvdata(dev); |
23 | return sprintf(buf, "%d\n", atomic_read(&cs->cidmode)); | 25 | |
26 | spin_lock_irqsave(&cs->lock, flags); | ||
27 | ret = sprintf(buf, "%u\n", cs->cidmode); | ||
28 | spin_unlock_irqrestore(&cs->lock, flags); | ||
29 | |||
30 | return ret; | ||
24 | } | 31 | } |
25 | 32 | ||
26 | static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, | 33 | static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, |
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? |