Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69049cc8 authored by Tilman Schmidt's avatar Tilman Schmidt Committed by Linus Torvalds
Browse files

[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: default avatarHansjoerg Lipp <hjlipp@web.de>
Signed-off-by: default avatarTilman Schmidt <tilman@imap.cc>
Cc: Karsten Keil <kkeil@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 27d1ac2e
Loading
Loading
Loading
Loading
+6 −3
Original line number Original line Diff line number Diff line
@@ -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);
	spin_lock_irqsave(&bcs->cs->lock, flags);
	if (bcs->cs->connected)
		tasklet_schedule(&bcs->cs->write_tasklet);
		tasklet_schedule(&bcs->cs->write_tasklet);
	spin_unlock_irqrestore(&bcs->cs->lock, flags);


	return len;	/* ok so far */
	return len;	/* ok so far */
}
}
+22 −26
Original line number Original line Diff line number Diff line
@@ -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;
}
}
+32 −32
Original line number Original line Diff line number Diff line
@@ -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);


+57 −30
Original line number Original line Diff line number Diff line
@@ -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");
+8 −10
Original line number Original line Diff line number Diff line
@@ -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);
}
}
Loading