mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
[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>
This commit is contained in:
parent
27d1ac2ef7
commit
69049cc87d
10 changed files with 211 additions and 154 deletions
|
@ -566,19 +566,22 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
|
||||||
int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
|
int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
unsigned len = skb->len;
|
unsigned len = skb->len;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
|
if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
|
||||||
skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
|
skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
|
||||||
else
|
else
|
||||||
skb = iraw_encode(skb, HW_HDR_LEN, 0);
|
skb = iraw_encode(skb, HW_HDR_LEN, 0);
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
dev_err(bcs->cs->dev,
|
err("unable to allocate memory for encoding!\n");
|
||||||
"unable to allocate memory for encoding!\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
skb_queue_tail(&bcs->squeue, skb);
|
skb_queue_tail(&bcs->squeue, skb);
|
||||||
tasklet_schedule(&bcs->cs->write_tasklet);
|
spin_lock_irqsave(&bcs->cs->lock, flags);
|
||||||
|
if (bcs->cs->connected)
|
||||||
|
tasklet_schedule(&bcs->cs->write_tasklet);
|
||||||
|
spin_unlock_irqrestore(&bcs->cs->lock, flags);
|
||||||
|
|
||||||
return len; /* ok so far */
|
return len; /* ok so far */
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,7 +367,7 @@ static void cmd_in_timeout(unsigned long data)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&cs->lock, flags);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
if (unlikely(!atomic_read(&cs->connected))) {
|
if (unlikely(!cs->connected)) {
|
||||||
gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__);
|
gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__);
|
||||||
spin_unlock_irqrestore(&cs->lock, flags);
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
return;
|
return;
|
||||||
|
@ -475,11 +475,6 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
|
||||||
unsigned l;
|
unsigned l;
|
||||||
int channel;
|
int channel;
|
||||||
|
|
||||||
if (unlikely(!atomic_read(&cs->connected))) {
|
|
||||||
warn("%s: disconnected", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (urb->status) {
|
switch (urb->status) {
|
||||||
case 0: /* success */
|
case 0: /* success */
|
||||||
break;
|
break;
|
||||||
|
@ -603,7 +598,9 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
|
||||||
check_pending(ucs);
|
check_pending(ucs);
|
||||||
|
|
||||||
resubmit:
|
resubmit:
|
||||||
status = usb_submit_urb(urb, SLAB_ATOMIC);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
status = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
if (unlikely(status)) {
|
if (unlikely(status)) {
|
||||||
dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
|
dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
|
||||||
get_usb_statmsg(status));
|
get_usb_statmsg(status));
|
||||||
|
@ -628,7 +625,7 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&cs->lock, flags);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
if (unlikely(!atomic_read(&cs->connected))) {
|
if (unlikely(!cs->connected)) {
|
||||||
warn("%s: disconnected", __func__);
|
warn("%s: disconnected", __func__);
|
||||||
spin_unlock_irqrestore(&cs->lock, flags);
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
return;
|
return;
|
||||||
|
@ -949,6 +946,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
|
||||||
struct bas_bc_state *ubc = ucx->bcs->hw.bas;
|
struct bas_bc_state *ubc = ucx->bcs->hw.bas;
|
||||||
struct usb_iso_packet_descriptor *ifd;
|
struct usb_iso_packet_descriptor *ifd;
|
||||||
int corrbytes, nframe, rc;
|
int corrbytes, nframe, rc;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/* urb->dev is clobbered by USB subsystem */
|
/* urb->dev is clobbered by USB subsystem */
|
||||||
urb->dev = ucx->bcs->cs->hw.bas->udev;
|
urb->dev = ucx->bcs->cs->hw.bas->udev;
|
||||||
|
@ -995,7 +993,11 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
|
||||||
ifd->actual_length = 0;
|
ifd->actual_length = 0;
|
||||||
}
|
}
|
||||||
if ((urb->number_of_packets = nframe) > 0) {
|
if ((urb->number_of_packets = nframe) > 0) {
|
||||||
if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
|
spin_lock_irqsave(&ucx->bcs->cs->lock, flags);
|
||||||
|
rc = ucx->bcs->cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
|
||||||
|
spin_unlock_irqrestore(&ucx->bcs->cs->lock, flags);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
dev_err(ucx->bcs->cs->dev,
|
dev_err(ucx->bcs->cs->dev,
|
||||||
"could not submit isochronous write URB: %s\n",
|
"could not submit isochronous write URB: %s\n",
|
||||||
get_usb_statmsg(rc));
|
get_usb_statmsg(rc));
|
||||||
|
@ -1029,11 +1031,6 @@ static void write_iso_tasklet(unsigned long data)
|
||||||
|
|
||||||
/* loop while completed URBs arrive in time */
|
/* loop while completed URBs arrive in time */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (unlikely(!atomic_read(&cs->connected))) {
|
|
||||||
warn("%s: disconnected", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(!(atomic_read(&ubc->running)))) {
|
if (unlikely(!(atomic_read(&ubc->running)))) {
|
||||||
gig_dbg(DEBUG_ISO, "%s: not running", __func__);
|
gig_dbg(DEBUG_ISO, "%s: not running", __func__);
|
||||||
return;
|
return;
|
||||||
|
@ -1190,11 +1187,6 @@ static void read_iso_tasklet(unsigned long data)
|
||||||
|
|
||||||
/* loop while more completed URBs arrive in the meantime */
|
/* loop while more completed URBs arrive in the meantime */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (unlikely(!atomic_read(&cs->connected))) {
|
|
||||||
warn("%s: disconnected", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* retrieve URB */
|
/* retrieve URB */
|
||||||
spin_lock_irqsave(&ubc->isoinlock, flags);
|
spin_lock_irqsave(&ubc->isoinlock, flags);
|
||||||
if (!(urb = ubc->isoindone)) {
|
if (!(urb = ubc->isoindone)) {
|
||||||
|
@ -1298,7 +1290,10 @@ static void read_iso_tasklet(unsigned long data)
|
||||||
urb->dev = bcs->cs->hw.bas->udev;
|
urb->dev = bcs->cs->hw.bas->udev;
|
||||||
urb->transfer_flags = URB_ISO_ASAP;
|
urb->transfer_flags = URB_ISO_ASAP;
|
||||||
urb->number_of_packets = BAS_NUMFRAMES;
|
urb->number_of_packets = BAS_NUMFRAMES;
|
||||||
if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
rc = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
if (rc) {
|
||||||
dev_err(cs->dev,
|
dev_err(cs->dev,
|
||||||
"could not resubmit isochronous read URB: %s\n",
|
"could not resubmit isochronous read URB: %s\n",
|
||||||
get_usb_statmsg(rc));
|
get_usb_statmsg(rc));
|
||||||
|
@ -1639,6 +1634,7 @@ static void atrdy_timeout(unsigned long data)
|
||||||
static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
|
static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
|
||||||
{
|
{
|
||||||
struct bas_cardstate *ucs = cs->hw.bas;
|
struct bas_cardstate *ucs = cs->hw.bas;
|
||||||
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len);
|
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)
|
||||||
(unsigned char*) &ucs->dr_cmd_out, buf, len,
|
(unsigned char*) &ucs->dr_cmd_out, buf, len,
|
||||||
write_command_callback, cs);
|
write_command_callback, cs);
|
||||||
|
|
||||||
if ((ret = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC)) != 0) {
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
ret = cs->connected ? usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC) : -ENODEV;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n",
|
dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n",
|
||||||
get_usb_statmsg(ret));
|
get_usb_statmsg(ret));
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1758,11 +1758,6 @@ static int gigaset_write_cmd(struct cardstate *cs,
|
||||||
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
|
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
|
||||||
"CMD Transmit", len, buf);
|
"CMD Transmit", len, buf);
|
||||||
|
|
||||||
if (unlikely(!atomic_read(&cs->connected))) {
|
|
||||||
err("%s: disconnected", __func__);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return 0; /* nothing to do */
|
return 0; /* nothing to do */
|
||||||
|
|
||||||
|
@ -2186,6 +2181,7 @@ static int gigaset_probe(struct usb_interface *interface,
|
||||||
|
|
||||||
error:
|
error:
|
||||||
freeurbs(cs);
|
freeurbs(cs);
|
||||||
|
usb_set_intfdata(interface, NULL);
|
||||||
gigaset_unassign(cs);
|
gigaset_unassign(cs);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,11 +129,6 @@ int gigaset_enterconfigmode(struct cardstate *cs)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
||||||
if (!atomic_read(&cs->connected)) {
|
|
||||||
err("not connected!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cs->control_state = TIOCM_RTS; //FIXME
|
cs->control_state = TIOCM_RTS; //FIXME
|
||||||
|
|
||||||
r = setflags(cs, TIOCM_DTR, 200);
|
r = setflags(cs, TIOCM_DTR, 200);
|
||||||
|
@ -176,7 +171,7 @@ static int test_timeout(struct at_state_t *at_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
|
if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
|
||||||
atomic_read(&at_state->timer_index), NULL)) {
|
at_state->timer_index, NULL)) {
|
||||||
//FIXME what should we do?
|
//FIXME what should we do?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +199,7 @@ static void timer_tick(unsigned long data)
|
||||||
if (test_timeout(at_state))
|
if (test_timeout(at_state))
|
||||||
timeout = 1;
|
timeout = 1;
|
||||||
|
|
||||||
if (atomic_read(&cs->running)) {
|
if (cs->running) {
|
||||||
mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK));
|
mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK));
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
gig_dbg(DEBUG_CMD, "scheduling timeout");
|
gig_dbg(DEBUG_CMD, "scheduling timeout");
|
||||||
|
@ -298,20 +293,22 @@ static void clear_events(struct cardstate *cs)
|
||||||
{
|
{
|
||||||
struct event_t *ev;
|
struct event_t *ev;
|
||||||
unsigned head, tail;
|
unsigned head, tail;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/* no locking needed (no reader/writer allowed) */
|
spin_lock_irqsave(&cs->ev_lock, flags);
|
||||||
|
|
||||||
head = atomic_read(&cs->ev_head);
|
head = cs->ev_head;
|
||||||
tail = atomic_read(&cs->ev_tail);
|
tail = cs->ev_tail;
|
||||||
|
|
||||||
while (tail != head) {
|
while (tail != head) {
|
||||||
ev = cs->events + head;
|
ev = cs->events + head;
|
||||||
kfree(ev->ptr);
|
kfree(ev->ptr);
|
||||||
|
|
||||||
head = (head + 1) % MAX_EVENTS;
|
head = (head + 1) % MAX_EVENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_set(&cs->ev_head, tail);
|
cs->ev_head = tail;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&cs->ev_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct event_t *gigaset_add_event(struct cardstate *cs,
|
struct event_t *gigaset_add_event(struct cardstate *cs,
|
||||||
|
@ -324,9 +321,9 @@ struct event_t *gigaset_add_event(struct cardstate *cs,
|
||||||
|
|
||||||
spin_lock_irqsave(&cs->ev_lock, flags);
|
spin_lock_irqsave(&cs->ev_lock, flags);
|
||||||
|
|
||||||
tail = atomic_read(&cs->ev_tail);
|
tail = cs->ev_tail;
|
||||||
next = (tail + 1) % MAX_EVENTS;
|
next = (tail + 1) % MAX_EVENTS;
|
||||||
if (unlikely(next == atomic_read(&cs->ev_head)))
|
if (unlikely(next == cs->ev_head))
|
||||||
err("event queue full");
|
err("event queue full");
|
||||||
else {
|
else {
|
||||||
event = cs->events + tail;
|
event = cs->events + tail;
|
||||||
|
@ -336,7 +333,7 @@ struct event_t *gigaset_add_event(struct cardstate *cs,
|
||||||
event->ptr = ptr;
|
event->ptr = ptr;
|
||||||
event->arg = arg;
|
event->arg = arg;
|
||||||
event->parameter = parameter;
|
event->parameter = parameter;
|
||||||
atomic_set(&cs->ev_tail, next);
|
cs->ev_tail = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&cs->ev_lock, flags);
|
spin_unlock_irqrestore(&cs->ev_lock, flags);
|
||||||
|
@ -454,7 +451,7 @@ void gigaset_freecs(struct cardstate *cs)
|
||||||
goto f_bcs;
|
goto f_bcs;
|
||||||
|
|
||||||
spin_lock_irqsave(&cs->lock, flags);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
atomic_set(&cs->running, 0);
|
cs->running = 0;
|
||||||
spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
|
spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
|
||||||
not rescheduled below */
|
not rescheduled below */
|
||||||
|
|
||||||
|
@ -513,8 +510,8 @@ void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
|
||||||
at_state->pending_commands = 0;
|
at_state->pending_commands = 0;
|
||||||
at_state->timer_expires = 0;
|
at_state->timer_expires = 0;
|
||||||
at_state->timer_active = 0;
|
at_state->timer_active = 0;
|
||||||
atomic_set(&at_state->timer_index, 0);
|
at_state->timer_index = 0;
|
||||||
atomic_set(&at_state->seq_index, 0);
|
at_state->seq_index = 0;
|
||||||
at_state->ConState = 0;
|
at_state->ConState = 0;
|
||||||
for (i = 0; i < STR_NUM; ++i)
|
for (i = 0; i < STR_NUM; ++i)
|
||||||
at_state->str_var[i] = NULL;
|
at_state->str_var[i] = NULL;
|
||||||
|
@ -665,6 +662,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
|
||||||
int cidmode, const char *modulename)
|
int cidmode, const char *modulename)
|
||||||
{
|
{
|
||||||
struct cardstate *cs = NULL;
|
struct cardstate *cs = NULL;
|
||||||
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
gig_dbg(DEBUG_INIT, "allocating cs");
|
gig_dbg(DEBUG_INIT, "allocating cs");
|
||||||
|
@ -685,11 +683,11 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
|
||||||
cs->onechannel = onechannel;
|
cs->onechannel = onechannel;
|
||||||
cs->ignoreframes = ignoreframes;
|
cs->ignoreframes = ignoreframes;
|
||||||
INIT_LIST_HEAD(&cs->temp_at_states);
|
INIT_LIST_HEAD(&cs->temp_at_states);
|
||||||
atomic_set(&cs->running, 0);
|
cs->running = 0;
|
||||||
init_timer(&cs->timer); /* clear next & prev */
|
init_timer(&cs->timer); /* clear next & prev */
|
||||||
spin_lock_init(&cs->ev_lock);
|
spin_lock_init(&cs->ev_lock);
|
||||||
atomic_set(&cs->ev_tail, 0);
|
cs->ev_tail = 0;
|
||||||
atomic_set(&cs->ev_head, 0);
|
cs->ev_head = 0;
|
||||||
mutex_init(&cs->mutex);
|
mutex_init(&cs->mutex);
|
||||||
mutex_lock(&cs->mutex);
|
mutex_lock(&cs->mutex);
|
||||||
|
|
||||||
|
@ -701,7 +699,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
|
||||||
cs->open_count = 0;
|
cs->open_count = 0;
|
||||||
cs->dev = NULL;
|
cs->dev = NULL;
|
||||||
cs->tty = NULL;
|
cs->tty = NULL;
|
||||||
atomic_set(&cs->cidmode, cidmode != 0);
|
cs->cidmode = cidmode != 0;
|
||||||
|
|
||||||
//if(onechannel) { //FIXME
|
//if(onechannel) { //FIXME
|
||||||
cs->tabnocid = gigaset_tab_nocid_m10x;
|
cs->tabnocid = gigaset_tab_nocid_m10x;
|
||||||
|
@ -737,7 +735,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
|
||||||
} else
|
} else
|
||||||
gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command);
|
gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command);
|
||||||
|
|
||||||
atomic_set(&cs->connected, 0);
|
cs->connected = 0;
|
||||||
|
cs->isdn_up = 0;
|
||||||
|
|
||||||
gig_dbg(DEBUG_INIT, "setting up cmdbuf");
|
gig_dbg(DEBUG_INIT, "setting up cmdbuf");
|
||||||
cs->cmdbuf = cs->lastcmdbuf = NULL;
|
cs->cmdbuf = cs->lastcmdbuf = NULL;
|
||||||
|
@ -761,7 +760,9 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
|
||||||
|
|
||||||
gigaset_if_init(cs);
|
gigaset_if_init(cs);
|
||||||
|
|
||||||
atomic_set(&cs->running, 1);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
cs->running = 1;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
setup_timer(&cs->timer, timer_tick, (unsigned long) cs);
|
setup_timer(&cs->timer, timer_tick, (unsigned long) cs);
|
||||||
cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
|
cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
|
||||||
/* FIXME: can jiffies increase too much until the timer is added?
|
/* FIXME: can jiffies increase too much until the timer is added?
|
||||||
|
@ -871,10 +872,14 @@ static void cleanup_cs(struct cardstate *cs)
|
||||||
|
|
||||||
int gigaset_start(struct cardstate *cs)
|
int gigaset_start(struct cardstate *cs)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (mutex_lock_interruptible(&cs->mutex))
|
if (mutex_lock_interruptible(&cs->mutex))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
atomic_set(&cs->connected, 1);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
cs->connected = 1;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
if (atomic_read(&cs->mstate) != MS_LOCKED) {
|
if (atomic_read(&cs->mstate) != MS_LOCKED) {
|
||||||
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
|
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
|
||||||
|
@ -950,11 +955,6 @@ void gigaset_stop(struct cardstate *cs)
|
||||||
{
|
{
|
||||||
mutex_lock(&cs->mutex);
|
mutex_lock(&cs->mutex);
|
||||||
|
|
||||||
/* clear device sysfs */
|
|
||||||
gigaset_free_dev_sysfs(cs);
|
|
||||||
|
|
||||||
atomic_set(&cs->connected, 0);
|
|
||||||
|
|
||||||
cs->waiting = 1;
|
cs->waiting = 1;
|
||||||
|
|
||||||
if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) {
|
if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) {
|
||||||
|
@ -970,8 +970,8 @@ void gigaset_stop(struct cardstate *cs)
|
||||||
//FIXME
|
//FIXME
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell the LL that the device is not available .. */
|
/* clear device sysfs */
|
||||||
gigaset_i4l_cmd(cs, ISDN_STAT_STOP); // FIXME move to event layer?
|
gigaset_free_dev_sysfs(cs);
|
||||||
|
|
||||||
cleanup_cs(cs);
|
cleanup_cs(cs);
|
||||||
|
|
||||||
|
|
|
@ -482,14 +482,6 @@ static int isdn_gethex(char *p)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void new_index(atomic_t *index, int max)
|
|
||||||
{
|
|
||||||
if (atomic_read(index) == max) //FIXME race?
|
|
||||||
atomic_set(index, 0);
|
|
||||||
else
|
|
||||||
atomic_inc(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* retrieve CID from parsed response
|
/* retrieve CID from parsed response
|
||||||
* returns 0 if no CID, -1 if invalid CID, or CID value 1..65535
|
* returns 0 if no CID, -1 if invalid CID, or CID value 1..65535
|
||||||
*/
|
*/
|
||||||
|
@ -581,8 +573,8 @@ void gigaset_handle_modem_response(struct cardstate *cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&cs->ev_lock, flags);
|
spin_lock_irqsave(&cs->ev_lock, flags);
|
||||||
head = atomic_read(&cs->ev_head);
|
head = cs->ev_head;
|
||||||
tail = atomic_read(&cs->ev_tail);
|
tail = cs->ev_tail;
|
||||||
|
|
||||||
abort = 1;
|
abort = 1;
|
||||||
curarg = 0;
|
curarg = 0;
|
||||||
|
@ -715,7 +707,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_set(&cs->ev_tail, tail);
|
cs->ev_tail = tail;
|
||||||
spin_unlock_irqrestore(&cs->ev_lock, flags);
|
spin_unlock_irqrestore(&cs->ev_lock, flags);
|
||||||
|
|
||||||
if (curarg != params)
|
if (curarg != params)
|
||||||
|
@ -734,14 +726,16 @@ static void disconnect(struct at_state_t **at_state_p)
|
||||||
struct bc_state *bcs = (*at_state_p)->bcs;
|
struct bc_state *bcs = (*at_state_p)->bcs;
|
||||||
struct cardstate *cs = (*at_state_p)->cs;
|
struct cardstate *cs = (*at_state_p)->cs;
|
||||||
|
|
||||||
new_index(&(*at_state_p)->seq_index, MAX_SEQ_INDEX);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
++(*at_state_p)->seq_index;
|
||||||
|
|
||||||
/* revert to selected idle mode */
|
/* revert to selected idle mode */
|
||||||
if (!atomic_read(&cs->cidmode)) {
|
if (!cs->cidmode) {
|
||||||
cs->at_state.pending_commands |= PC_UMMODE;
|
cs->at_state.pending_commands |= PC_UMMODE;
|
||||||
atomic_set(&cs->commands_pending, 1); //FIXME
|
atomic_set(&cs->commands_pending, 1); //FIXME
|
||||||
gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
|
gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
if (bcs) {
|
if (bcs) {
|
||||||
/* B channel assigned: invoke hardware specific handler */
|
/* B channel assigned: invoke hardware specific handler */
|
||||||
|
@ -933,17 +927,21 @@ static void bchannel_up(struct bc_state *bcs)
|
||||||
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
|
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_dial(struct at_state_t *at_state, void *data, int seq_index)
|
static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_index)
|
||||||
{
|
{
|
||||||
struct bc_state *bcs = at_state->bcs;
|
struct bc_state *bcs = at_state->bcs;
|
||||||
struct cardstate *cs = at_state->cs;
|
struct cardstate *cs = at_state->cs;
|
||||||
int retval;
|
int retval;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
bcs->chstate |= CHS_NOTIFY_LL;
|
bcs->chstate |= CHS_NOTIFY_LL;
|
||||||
//atomic_set(&bcs->status, BCS_INIT);
|
|
||||||
|
|
||||||
if (atomic_read(&at_state->seq_index) != seq_index)
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
if (at_state->seq_index != seq_index) {
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
retval = gigaset_isdn_setup_dial(at_state, data);
|
retval = gigaset_isdn_setup_dial(at_state, data);
|
||||||
if (retval != 0)
|
if (retval != 0)
|
||||||
|
@ -988,6 +986,7 @@ static void do_start(struct cardstate *cs)
|
||||||
if (atomic_read(&cs->mstate) != MS_LOCKED)
|
if (atomic_read(&cs->mstate) != MS_LOCKED)
|
||||||
schedule_init(cs, MS_INIT);
|
schedule_init(cs, MS_INIT);
|
||||||
|
|
||||||
|
cs->isdn_up = 1;
|
||||||
gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
|
gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
|
||||||
// FIXME: not in locked mode
|
// FIXME: not in locked mode
|
||||||
// FIXME 2: only after init sequence
|
// FIXME 2: only after init sequence
|
||||||
|
@ -1003,6 +1002,12 @@ static void finish_shutdown(struct cardstate *cs)
|
||||||
atomic_set(&cs->mode, M_UNKNOWN);
|
atomic_set(&cs->mode, M_UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tell the LL that the device is not available .. */
|
||||||
|
if (cs->isdn_up) {
|
||||||
|
cs->isdn_up = 0;
|
||||||
|
gigaset_i4l_cmd(cs, ISDN_STAT_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
/* The rest is done by cleanup_cs () in user mode. */
|
/* The rest is done by cleanup_cs () in user mode. */
|
||||||
|
|
||||||
cs->cmd_result = -ENODEV;
|
cs->cmd_result = -ENODEV;
|
||||||
|
@ -1025,6 +1030,12 @@ static void do_shutdown(struct cardstate *cs)
|
||||||
|
|
||||||
static void do_stop(struct cardstate *cs)
|
static void do_stop(struct cardstate *cs)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
cs->connected = 0;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
do_shutdown(cs);
|
do_shutdown(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1153,7 +1164,7 @@ static int do_unlock(struct cardstate *cs)
|
||||||
atomic_set(&cs->mstate, MS_UNINITIALIZED);
|
atomic_set(&cs->mstate, MS_UNINITIALIZED);
|
||||||
atomic_set(&cs->mode, M_UNKNOWN);
|
atomic_set(&cs->mode, M_UNKNOWN);
|
||||||
gigaset_free_channels(cs);
|
gigaset_free_channels(cs);
|
||||||
if (atomic_read(&cs->connected))
|
if (cs->connected)
|
||||||
schedule_init(cs, MS_INIT);
|
schedule_init(cs, MS_INIT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1185,11 +1196,14 @@ static void do_action(int action, struct cardstate *cs,
|
||||||
cs->at_state.pending_commands &= ~PC_INIT;
|
cs->at_state.pending_commands &= ~PC_INIT;
|
||||||
cs->cur_at_seq = SEQ_NONE;
|
cs->cur_at_seq = SEQ_NONE;
|
||||||
atomic_set(&cs->mode, M_UNIMODEM);
|
atomic_set(&cs->mode, M_UNIMODEM);
|
||||||
if (!atomic_read(&cs->cidmode)) {
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
if (!cs->cidmode) {
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
gigaset_free_channels(cs);
|
gigaset_free_channels(cs);
|
||||||
atomic_set(&cs->mstate, MS_READY);
|
atomic_set(&cs->mstate, MS_READY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
cs->at_state.pending_commands |= PC_CIDMODE;
|
cs->at_state.pending_commands |= PC_CIDMODE;
|
||||||
atomic_set(&cs->commands_pending, 1);
|
atomic_set(&cs->commands_pending, 1);
|
||||||
gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
|
gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
|
||||||
|
@ -1536,8 +1550,9 @@ static void do_action(int action, struct cardstate *cs,
|
||||||
|
|
||||||
/* events from the proc file system */ // FIXME without ACT_xxxx?
|
/* events from the proc file system */ // FIXME without ACT_xxxx?
|
||||||
case ACT_PROC_CIDMODE:
|
case ACT_PROC_CIDMODE:
|
||||||
if (ev->parameter != atomic_read(&cs->cidmode)) {
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
atomic_set(&cs->cidmode, ev->parameter);
|
if (ev->parameter != cs->cidmode) {
|
||||||
|
cs->cidmode = ev->parameter;
|
||||||
if (ev->parameter) {
|
if (ev->parameter) {
|
||||||
cs->at_state.pending_commands |= PC_CIDMODE;
|
cs->at_state.pending_commands |= PC_CIDMODE;
|
||||||
gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
|
gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
|
||||||
|
@ -1547,6 +1562,7 @@ static void do_action(int action, struct cardstate *cs,
|
||||||
}
|
}
|
||||||
atomic_set(&cs->commands_pending, 1);
|
atomic_set(&cs->commands_pending, 1);
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
cs->waiting = 0;
|
cs->waiting = 0;
|
||||||
wake_up(&cs->waitqueue);
|
wake_up(&cs->waitqueue);
|
||||||
break;
|
break;
|
||||||
|
@ -1615,8 +1631,9 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
|
||||||
/* Setting the pointer to the dial array */
|
/* Setting the pointer to the dial array */
|
||||||
rep = at_state->replystruct;
|
rep = at_state->replystruct;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
if (ev->type == EV_TIMEOUT) {
|
if (ev->type == EV_TIMEOUT) {
|
||||||
if (ev->parameter != atomic_read(&at_state->timer_index)
|
if (ev->parameter != at_state->timer_index
|
||||||
|| !at_state->timer_active) {
|
|| !at_state->timer_active) {
|
||||||
ev->type = RSP_NONE; /* old timeout */
|
ev->type = RSP_NONE; /* old timeout */
|
||||||
gig_dbg(DEBUG_ANY, "old timeout");
|
gig_dbg(DEBUG_ANY, "old timeout");
|
||||||
|
@ -1625,6 +1642,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
|
||||||
else
|
else
|
||||||
gig_dbg(DEBUG_ANY, "stopped waiting");
|
gig_dbg(DEBUG_ANY, "stopped waiting");
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
/* if the response belongs to a variable in at_state->int_var[VAR_XXXX]
|
/* if the response belongs to a variable in at_state->int_var[VAR_XXXX]
|
||||||
or at_state->str_var[STR_XXXX], set it */
|
or at_state->str_var[STR_XXXX], set it */
|
||||||
|
@ -1686,7 +1704,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
|
||||||
} else {
|
} else {
|
||||||
/* Send command to modem if not NULL... */
|
/* Send command to modem if not NULL... */
|
||||||
if (p_command/*rep->command*/) {
|
if (p_command/*rep->command*/) {
|
||||||
if (atomic_read(&cs->connected))
|
if (cs->connected)
|
||||||
send_command(cs, p_command,
|
send_command(cs, p_command,
|
||||||
sendcid, cs->dle,
|
sendcid, cs->dle,
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
|
@ -1703,8 +1721,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
|
||||||
} else if (rep->timeout > 0) { /* new timeout */
|
} else if (rep->timeout > 0) { /* new timeout */
|
||||||
at_state->timer_expires = rep->timeout * 10;
|
at_state->timer_expires = rep->timeout * 10;
|
||||||
at_state->timer_active = 1;
|
at_state->timer_active = 1;
|
||||||
new_index(&at_state->timer_index,
|
++at_state->timer_index;
|
||||||
MAX_TIMER_INDEX);
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&cs->lock, flags);
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
}
|
}
|
||||||
|
@ -1724,6 +1741,7 @@ static void process_command_flags(struct cardstate *cs)
|
||||||
struct bc_state *bcs;
|
struct bc_state *bcs;
|
||||||
int i;
|
int i;
|
||||||
int sequence;
|
int sequence;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
atomic_set(&cs->commands_pending, 0);
|
atomic_set(&cs->commands_pending, 0);
|
||||||
|
|
||||||
|
@ -1773,8 +1791,9 @@ static void process_command_flags(struct cardstate *cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only switch back to unimodem mode, if no commands are pending and no channels are up */
|
/* only switch back to unimodem mode, if no commands are pending and no channels are up */
|
||||||
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
if (cs->at_state.pending_commands == PC_UMMODE
|
if (cs->at_state.pending_commands == PC_UMMODE
|
||||||
&& !atomic_read(&cs->cidmode)
|
&& !cs->cidmode
|
||||||
&& list_empty(&cs->temp_at_states)
|
&& list_empty(&cs->temp_at_states)
|
||||||
&& atomic_read(&cs->mode) == M_CID) {
|
&& atomic_read(&cs->mode) == M_CID) {
|
||||||
sequence = SEQ_UMMODE;
|
sequence = SEQ_UMMODE;
|
||||||
|
@ -1788,6 +1807,7 @@ static void process_command_flags(struct cardstate *cs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
cs->at_state.pending_commands &= ~PC_UMMODE;
|
cs->at_state.pending_commands &= ~PC_UMMODE;
|
||||||
if (sequence != SEQ_NONE) {
|
if (sequence != SEQ_NONE) {
|
||||||
schedule_sequence(cs, at_state, sequence);
|
schedule_sequence(cs, at_state, sequence);
|
||||||
|
@ -1900,18 +1920,21 @@ static void process_events(struct cardstate *cs)
|
||||||
int i;
|
int i;
|
||||||
int check_flags = 0;
|
int check_flags = 0;
|
||||||
int was_busy;
|
int was_busy;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
/* no locking needed (only one reader) */
|
spin_lock_irqsave(&cs->ev_lock, flags);
|
||||||
head = atomic_read(&cs->ev_head);
|
head = cs->ev_head;
|
||||||
|
|
||||||
for (i = 0; i < 2 * MAX_EVENTS; ++i) {
|
for (i = 0; i < 2 * MAX_EVENTS; ++i) {
|
||||||
tail = atomic_read(&cs->ev_tail);
|
tail = cs->ev_tail;
|
||||||
if (tail == head) {
|
if (tail == head) {
|
||||||
if (!check_flags && !atomic_read(&cs->commands_pending))
|
if (!check_flags && !atomic_read(&cs->commands_pending))
|
||||||
break;
|
break;
|
||||||
check_flags = 0;
|
check_flags = 0;
|
||||||
|
spin_unlock_irqrestore(&cs->ev_lock, flags);
|
||||||
process_command_flags(cs);
|
process_command_flags(cs);
|
||||||
tail = atomic_read(&cs->ev_tail);
|
spin_lock_irqsave(&cs->ev_lock, flags);
|
||||||
|
tail = cs->ev_tail;
|
||||||
if (tail == head) {
|
if (tail == head) {
|
||||||
if (!atomic_read(&cs->commands_pending))
|
if (!atomic_read(&cs->commands_pending))
|
||||||
break;
|
break;
|
||||||
|
@ -1921,16 +1944,20 @@ static void process_events(struct cardstate *cs)
|
||||||
|
|
||||||
ev = cs->events + head;
|
ev = cs->events + head;
|
||||||
was_busy = cs->cur_at_seq != SEQ_NONE;
|
was_busy = cs->cur_at_seq != SEQ_NONE;
|
||||||
|
spin_unlock_irqrestore(&cs->ev_lock, flags);
|
||||||
process_event(cs, ev);
|
process_event(cs, ev);
|
||||||
|
spin_lock_irqsave(&cs->ev_lock, flags);
|
||||||
kfree(ev->ptr);
|
kfree(ev->ptr);
|
||||||
ev->ptr = NULL;
|
ev->ptr = NULL;
|
||||||
if (was_busy && cs->cur_at_seq == SEQ_NONE)
|
if (was_busy && cs->cur_at_seq == SEQ_NONE)
|
||||||
check_flags = 1;
|
check_flags = 1;
|
||||||
|
|
||||||
head = (head + 1) % MAX_EVENTS;
|
head = (head + 1) % MAX_EVENTS;
|
||||||
atomic_set(&cs->ev_head, head);
|
cs->ev_head = head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&cs->ev_lock, flags);
|
||||||
|
|
||||||
if (i == 2 * MAX_EVENTS) {
|
if (i == 2 * MAX_EVENTS) {
|
||||||
dev_err(cs->dev,
|
dev_err(cs->dev,
|
||||||
"infinite loop in process_events; aborting.\n");
|
"infinite loop in process_events; aborting.\n");
|
||||||
|
|
|
@ -55,9 +55,6 @@
|
||||||
#define GIG_RETRYCID
|
#define GIG_RETRYCID
|
||||||
#define GIG_X75
|
#define GIG_X75
|
||||||
|
|
||||||
#define MAX_TIMER_INDEX 1000
|
|
||||||
#define MAX_SEQ_INDEX 1000
|
|
||||||
|
|
||||||
#define GIG_TICK 100 /* in milliseconds */
|
#define GIG_TICK 100 /* in milliseconds */
|
||||||
|
|
||||||
/* timeout values (unit: 1 sec) */
|
/* timeout values (unit: 1 sec) */
|
||||||
|
@ -375,7 +372,7 @@ struct at_state_t {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
int waiting;
|
int waiting;
|
||||||
int getstring;
|
int getstring;
|
||||||
atomic_t timer_index;
|
unsigned timer_index;
|
||||||
unsigned long timer_expires;
|
unsigned long timer_expires;
|
||||||
int timer_active;
|
int timer_active;
|
||||||
unsigned int ConState; /* State of connection */
|
unsigned int ConState; /* State of connection */
|
||||||
|
@ -384,7 +381,7 @@ struct at_state_t {
|
||||||
int int_var[VAR_NUM]; /* see VAR_XXXX */
|
int int_var[VAR_NUM]; /* see VAR_XXXX */
|
||||||
char *str_var[STR_NUM]; /* see STR_XXXX */
|
char *str_var[STR_NUM]; /* see STR_XXXX */
|
||||||
unsigned pending_commands; /* see PC_XXXX */
|
unsigned pending_commands; /* see PC_XXXX */
|
||||||
atomic_t seq_index;
|
unsigned seq_index;
|
||||||
|
|
||||||
struct cardstate *cs;
|
struct cardstate *cs;
|
||||||
struct bc_state *bcs;
|
struct bc_state *bcs;
|
||||||
|
@ -484,10 +481,11 @@ struct cardstate {
|
||||||
unsigned fwver[4];
|
unsigned fwver[4];
|
||||||
int gotfwver;
|
int gotfwver;
|
||||||
|
|
||||||
atomic_t running; /* !=0 if events are handled */
|
unsigned running; /* !=0 if events are handled */
|
||||||
atomic_t connected; /* !=0 if hardware is connected */
|
unsigned connected; /* !=0 if hardware is connected */
|
||||||
|
unsigned isdn_up; /* !=0 after ISDN_STAT_RUN */
|
||||||
|
|
||||||
atomic_t cidmode;
|
unsigned cidmode;
|
||||||
|
|
||||||
int myid; /* id for communication with LL */
|
int myid; /* id for communication with LL */
|
||||||
isdn_if iif;
|
isdn_if iif;
|
||||||
|
@ -528,7 +526,7 @@ struct cardstate {
|
||||||
|
|
||||||
/* event queue */
|
/* event queue */
|
||||||
struct event_t events[MAX_EVENTS];
|
struct event_t events[MAX_EVENTS];
|
||||||
atomic_t ev_tail, ev_head;
|
unsigned ev_tail, ev_head;
|
||||||
spinlock_t ev_lock;
|
spinlock_t ev_lock;
|
||||||
|
|
||||||
/* current modem response */
|
/* current modem response */
|
||||||
|
@ -824,7 +822,7 @@ static inline void gigaset_schedule_event(struct cardstate *cs)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
spin_lock_irqsave(&cs->lock, flags);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
if (atomic_read(&cs->running))
|
if (cs->running)
|
||||||
tasklet_schedule(&cs->event_tasklet);
|
tasklet_schedule(&cs->event_tasklet);
|
||||||
spin_unlock_irqrestore(&cs->lock, flags);
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,11 +56,6 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
|
||||||
"Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)",
|
"Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)",
|
||||||
driverID, channel, ack, len);
|
driverID, channel, ack, len);
|
||||||
|
|
||||||
if (!atomic_read(&cs->connected)) {
|
|
||||||
err("%s: disconnected", __func__);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!len) {
|
if (!len) {
|
||||||
if (ack)
|
if (ack)
|
||||||
notice("%s: not ACKing empty packet", __func__);
|
notice("%s: not ACKing empty packet", __func__);
|
||||||
|
@ -78,7 +73,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
|
||||||
len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]);
|
len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]);
|
||||||
|
|
||||||
/* pass to device-specific module */
|
/* pass to device-specific module */
|
||||||
return cs->ops->send_skb(bcs, skb);
|
return cs->ops->send_skb(bcs, skb); //FIXME cs->ops->send_skb() must handle !cs->connected correctly
|
||||||
}
|
}
|
||||||
|
|
||||||
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
|
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
|
||||||
|
@ -119,11 +114,12 @@ static int command_from_LL(isdn_ctrl *cntrl)
|
||||||
struct bc_state *bcs;
|
struct bc_state *bcs;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
struct setup_parm *sp;
|
struct setup_parm *sp;
|
||||||
|
unsigned param;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
gigaset_debugdrivers();
|
gigaset_debugdrivers();
|
||||||
|
|
||||||
//FIXME "remove test for &connected"
|
if (!cs) {
|
||||||
if ((!cs || !atomic_read(&cs->connected))) {
|
|
||||||
warn("LL tried to access unknown device with nr. %d",
|
warn("LL tried to access unknown device with nr. %d",
|
||||||
cntrl->driver);
|
cntrl->driver);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -166,8 +162,11 @@ static int command_from_LL(isdn_ctrl *cntrl)
|
||||||
}
|
}
|
||||||
*sp = cntrl->parm.setup;
|
*sp = cntrl->parm.setup;
|
||||||
|
|
||||||
if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp,
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
atomic_read(&bcs->at_state.seq_index),
|
param = bcs->at_state.seq_index;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
|
if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, param,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
//FIXME what should we do?
|
//FIXME what should we do?
|
||||||
kfree(sp);
|
kfree(sp);
|
||||||
|
|
|
@ -33,7 +33,7 @@ static int if_lock(struct cardstate *cs, int *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
|
if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
|
||||||
&& atomic_read(&cs->connected)) {
|
&& cs->connected) {
|
||||||
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
|
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
|
||||||
cs->ops->baud_rate(cs, B115200);
|
cs->ops->baud_rate(cs, B115200);
|
||||||
cs->ops->set_line_ctrl(cs, CS8);
|
cs->ops->set_line_ctrl(cs, CS8);
|
||||||
|
@ -107,6 +107,11 @@ static int if_config(struct cardstate *cs, int *arg)
|
||||||
if (atomic_read(&cs->mstate) != MS_LOCKED)
|
if (atomic_read(&cs->mstate) != MS_LOCKED)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (!cs->connected) {
|
||||||
|
err("not connected!");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
*arg = 0;
|
*arg = 0;
|
||||||
return gigaset_enterconfigmode(cs);
|
return gigaset_enterconfigmode(cs);
|
||||||
}
|
}
|
||||||
|
@ -246,7 +251,7 @@ static int if_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
break;
|
break;
|
||||||
case GIGASET_BRKCHARS:
|
case GIGASET_BRKCHARS:
|
||||||
//FIXME test if MS_LOCKED
|
//FIXME test if MS_LOCKED
|
||||||
if (!atomic_read(&cs->connected)) {
|
if (!cs->connected) {
|
||||||
gig_dbg(DEBUG_ANY,
|
gig_dbg(DEBUG_ANY,
|
||||||
"can't communicate with unplugged device");
|
"can't communicate with unplugged device");
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
|
@ -327,7 +332,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file,
|
||||||
if (mutex_lock_interruptible(&cs->mutex))
|
if (mutex_lock_interruptible(&cs->mutex))
|
||||||
return -ERESTARTSYS; // FIXME -EINTR?
|
return -ERESTARTSYS; // FIXME -EINTR?
|
||||||
|
|
||||||
if (!atomic_read(&cs->connected)) {
|
if (!cs->connected) {
|
||||||
gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
|
gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
} else {
|
} else {
|
||||||
|
@ -362,7 +367,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||||
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
|
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
|
||||||
warn("can't write to unlocked device");
|
warn("can't write to unlocked device");
|
||||||
retval = -EBUSY;
|
retval = -EBUSY;
|
||||||
} else if (!atomic_read(&cs->connected)) {
|
} else if (!cs->connected) {
|
||||||
gig_dbg(DEBUG_ANY, "can't write to unplugged device");
|
gig_dbg(DEBUG_ANY, "can't write to unplugged device");
|
||||||
retval = -EBUSY; //FIXME
|
retval = -EBUSY; //FIXME
|
||||||
} else {
|
} else {
|
||||||
|
@ -396,7 +401,7 @@ static int if_write_room(struct tty_struct *tty)
|
||||||
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
|
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
|
||||||
warn("can't write to unlocked device");
|
warn("can't write to unlocked device");
|
||||||
retval = -EBUSY; //FIXME
|
retval = -EBUSY; //FIXME
|
||||||
} else if (!atomic_read(&cs->connected)) {
|
} else if (!cs->connected) {
|
||||||
gig_dbg(DEBUG_ANY, "can't write to unplugged device");
|
gig_dbg(DEBUG_ANY, "can't write to unplugged device");
|
||||||
retval = -EBUSY; //FIXME
|
retval = -EBUSY; //FIXME
|
||||||
} else
|
} else
|
||||||
|
@ -428,7 +433,7 @@ static int if_chars_in_buffer(struct tty_struct *tty)
|
||||||
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
|
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
|
||||||
warn("can't write to unlocked device");
|
warn("can't write to unlocked device");
|
||||||
retval = -EBUSY;
|
retval = -EBUSY;
|
||||||
} else if (!atomic_read(&cs->connected)) {
|
} else if (!cs->connected) {
|
||||||
gig_dbg(DEBUG_ANY, "can't write to unplugged device");
|
gig_dbg(DEBUG_ANY, "can't write to unplugged device");
|
||||||
retval = -EBUSY; //FIXME
|
retval = -EBUSY; //FIXME
|
||||||
} else
|
} else
|
||||||
|
@ -508,7 +513,7 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!atomic_read(&cs->connected)) {
|
if (!cs->connected) {
|
||||||
gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
|
gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -990,13 +990,17 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
|
||||||
int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
|
int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int len = skb->len;
|
int len = skb->len;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
skb_queue_tail(&bcs->squeue, skb);
|
skb_queue_tail(&bcs->squeue, skb);
|
||||||
gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d",
|
gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d",
|
||||||
__func__, skb_queue_len(&bcs->squeue));
|
__func__, skb_queue_len(&bcs->squeue));
|
||||||
|
|
||||||
/* tasklet submits URB if necessary */
|
/* tasklet submits URB if necessary */
|
||||||
tasklet_schedule(&bcs->hw.bas->sent_tasklet);
|
spin_lock_irqsave(&bcs->cs->lock, flags);
|
||||||
|
if (bcs->cs->connected)
|
||||||
|
tasklet_schedule(&bcs->hw.bas->sent_tasklet);
|
||||||
|
spin_unlock_irqrestore(&bcs->cs->lock, flags);
|
||||||
|
|
||||||
return len; /* ok so far */
|
return len; /* ok so far */
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,15 @@
|
||||||
static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr,
|
static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned long flags;
|
||||||
struct cardstate *cs = dev_get_drvdata(dev);
|
struct cardstate *cs = dev_get_drvdata(dev);
|
||||||
return sprintf(buf, "%d\n", atomic_read(&cs->cidmode));
|
|
||||||
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
ret = sprintf(buf, "%u\n", cs->cidmode);
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
|
static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
|
||||||
|
|
|
@ -371,13 +371,14 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
|
||||||
int r;
|
int r;
|
||||||
unsigned numbytes;
|
unsigned numbytes;
|
||||||
unsigned char *src;
|
unsigned char *src;
|
||||||
|
unsigned long flags;
|
||||||
if (!atomic_read(&cs->connected)) {
|
|
||||||
err("%s: disconnected", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!urb->status) {
|
if (!urb->status) {
|
||||||
|
if (!cs->connected) {
|
||||||
|
err("%s: disconnected", __func__); /* should never happen */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
numbytes = urb->actual_length;
|
numbytes = urb->actual_length;
|
||||||
|
|
||||||
if (numbytes) {
|
if (numbytes) {
|
||||||
|
@ -399,12 +400,19 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
|
||||||
/* The urb might have been killed. */
|
/* The urb might have been killed. */
|
||||||
gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
|
gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
|
||||||
__func__, urb->status);
|
__func__, urb->status);
|
||||||
if (urb->status != -ENOENT) /* not killed */
|
if (urb->status != -ENOENT) { /* not killed */
|
||||||
|
if (!cs->connected) {
|
||||||
|
err("%s: disconnected", __func__); /* should never happen */
|
||||||
|
return;
|
||||||
|
}
|
||||||
resubmit = 1;
|
resubmit = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resubmit) {
|
if (resubmit) {
|
||||||
r = usb_submit_urb(urb, SLAB_ATOMIC);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
r = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
if (r)
|
if (r)
|
||||||
dev_err(cs->dev, "error %d when resubmitting urb.\n",
|
dev_err(cs->dev, "error %d when resubmitting urb.\n",
|
||||||
-r);
|
-r);
|
||||||
|
@ -416,21 +424,22 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
|
||||||
static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
|
static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct cardstate *cs = urb->context;
|
struct cardstate *cs = urb->context;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
#ifdef CONFIG_GIGASET_DEBUG
|
|
||||||
if (!atomic_read(&cs->connected)) {
|
|
||||||
err("%s: not connected", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (urb->status)
|
if (urb->status)
|
||||||
dev_err(cs->dev, "bulk transfer failed (status %d)\n",
|
dev_err(cs->dev, "bulk transfer failed (status %d)\n",
|
||||||
-urb->status);
|
-urb->status);
|
||||||
/* That's all we can do. Communication problems
|
/* That's all we can do. Communication problems
|
||||||
are handled by timeouts or network protocols. */
|
are handled by timeouts or network protocols. */
|
||||||
|
|
||||||
atomic_set(&cs->hw.usb->busy, 0);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
tasklet_schedule(&cs->write_tasklet);
|
if (!cs->connected) {
|
||||||
|
err("%s: not connected", __func__);
|
||||||
|
} else {
|
||||||
|
atomic_set(&cs->hw.usb->busy, 0);
|
||||||
|
tasklet_schedule(&cs->write_tasklet);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
|
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)
|
||||||
}
|
}
|
||||||
if (cb) {
|
if (cb) {
|
||||||
count = min(cb->len, ucs->bulk_out_size);
|
count = min(cb->len, ucs->bulk_out_size);
|
||||||
|
gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
|
||||||
|
|
||||||
usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
|
usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
|
||||||
usb_sndbulkpipe(ucs->udev,
|
usb_sndbulkpipe(ucs->udev,
|
||||||
ucs->bulk_out_endpointAddr & 0x0f),
|
ucs->bulk_out_endpointAddr & 0x0f),
|
||||||
|
@ -474,14 +485,15 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
|
||||||
cb->offset += count;
|
cb->offset += count;
|
||||||
cb->len -= count;
|
cb->len -= count;
|
||||||
atomic_set(&ucs->busy, 1);
|
atomic_set(&ucs->busy, 1);
|
||||||
gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
|
|
||||||
|
|
||||||
status = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC) : -ENODEV;
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
atomic_set(&ucs->busy, 0);
|
atomic_set(&ucs->busy, 0);
|
||||||
dev_err(cs->dev,
|
err("could not submit urb (error %d)\n",
|
||||||
"could not submit urb (error %d)\n",
|
-status);
|
||||||
-status);
|
|
||||||
cb->len = 0; /* skip urb => remove cb+wakeup
|
cb->len = 0; /* skip urb => remove cb+wakeup
|
||||||
in next loop cycle */
|
in next loop cycle */
|
||||||
}
|
}
|
||||||
|
@ -502,11 +514,6 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
|
||||||
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
|
DEBUG_TRANSCMD : DEBUG_LOCKCMD,
|
||||||
"CMD Transmit", len, buf);
|
"CMD Transmit", len, buf);
|
||||||
|
|
||||||
if (!atomic_read(&cs->connected)) {
|
|
||||||
err("%s: not connected", __func__);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -533,7 +540,10 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
|
||||||
cs->lastcmdbuf = cb;
|
cs->lastcmdbuf = cb;
|
||||||
spin_unlock_irqrestore(&cs->cmdlock, flags);
|
spin_unlock_irqrestore(&cs->cmdlock, flags);
|
||||||
|
|
||||||
tasklet_schedule(&cs->write_tasklet);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
if (cs->connected)
|
||||||
|
tasklet_schedule(&cs->write_tasklet);
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,6 +639,7 @@ static int write_modem(struct cardstate *cs)
|
||||||
int count;
|
int count;
|
||||||
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
|
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
|
||||||
struct usb_cardstate *ucs = cs->hw.usb;
|
struct usb_cardstate *ucs = cs->hw.usb;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len);
|
gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len);
|
||||||
|
|
||||||
|
@ -644,20 +655,27 @@ static int write_modem(struct cardstate *cs)
|
||||||
count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
|
count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
|
||||||
memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count);
|
memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count);
|
||||||
skb_pull(bcs->tx_skb, count);
|
skb_pull(bcs->tx_skb, count);
|
||||||
|
|
||||||
usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
|
|
||||||
usb_sndbulkpipe(ucs->udev,
|
|
||||||
ucs->bulk_out_endpointAddr & 0x0f),
|
|
||||||
ucs->bulk_out_buffer, count,
|
|
||||||
gigaset_write_bulk_callback, cs);
|
|
||||||
atomic_set(&ucs->busy, 1);
|
atomic_set(&ucs->busy, 1);
|
||||||
gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
|
gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
|
||||||
|
|
||||||
ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
|
spin_lock_irqsave(&cs->lock, flags);
|
||||||
|
if (cs->connected) {
|
||||||
|
usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
|
||||||
|
usb_sndbulkpipe(ucs->udev,
|
||||||
|
ucs->bulk_out_endpointAddr & 0x0f),
|
||||||
|
ucs->bulk_out_buffer, count,
|
||||||
|
gigaset_write_bulk_callback, cs);
|
||||||
|
ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
|
||||||
|
} else {
|
||||||
|
ret = -ENODEV;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&cs->lock, flags);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(cs->dev, "could not submit urb (error %d)\n", -ret);
|
err("could not submit urb (error %d)\n", -ret);
|
||||||
atomic_set(&ucs->busy, 0);
|
atomic_set(&ucs->busy, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bcs->tx_skb->len) {
|
if (!bcs->tx_skb->len) {
|
||||||
/* skb sent completely */
|
/* skb sent completely */
|
||||||
gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0?
|
gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0?
|
||||||
|
|
Loading…
Reference in a new issue