Commit 6ea53391 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: line6: variax: Rewrite complex timer & work combo with a delayed work



Variax driver had a very complex and staged startup sequence using
multiple timers and a work.  This patch simplifies the procedure to a
single delayed work.

Now the startup stage consists of:
- VARIAX_STARTUP_VERSIONREQ:
  requesting the version and the message handler raises up to the next
  stage upon receiving the reply.  The request is repeated until a
  reply arrives.
- VARIAX_STARTUP_ACTIVATE:
  does activation, and queue for the next stage.
- VARIAX_STARTUP_SETUP:
  registers the card.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent a91c1da7
Loading
Loading
Loading
Loading
+35 −93
Original line number Diff line number Diff line
@@ -26,13 +26,9 @@
	Stages of Variax startup procedure
*/
enum {
	VARIAX_STARTUP_INIT = 1,
	VARIAX_STARTUP_VERSIONREQ,
	VARIAX_STARTUP_WAIT,
	VARIAX_STARTUP_ACTIVATE,
	VARIAX_STARTUP_WORKQUEUE,
	VARIAX_STARTUP_SETUP,
	VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
};

enum {
@@ -47,13 +43,6 @@ struct usb_line6_variax {
	/* Buffer for activation code */
	unsigned char *buffer_activate;

	/* Handler for device initialization */
	struct work_struct startup_work;

	/* Timers for device initialization */
	struct timer_list startup_timer1;
	struct timer_list startup_timer2;

	/* Current progress in startup procedure */
	int startup_progress;
};
@@ -81,11 +70,6 @@ static const char variax_activate[] = {
	0xf7
};

/* forward declarations: */
static void variax_startup2(struct timer_list *t);
static void variax_startup4(struct timer_list *t);
static void variax_startup5(struct timer_list *t);

static void variax_activate_async(struct usb_line6_variax *variax, int a)
{
	variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
@@ -100,74 +84,30 @@ static void variax_activate_async(struct usb_line6_variax *variax, int a)
	context). After the last one has finished, the device is ready to use.
*/

static void variax_startup1(struct usb_line6_variax *variax)
{
	CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);

	/* delay startup procedure: */
	line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
			  variax_startup2);
}

static void variax_startup2(struct timer_list *t)
static void variax_startup(struct usb_line6 *line6)
{
	struct usb_line6_variax *variax = from_timer(variax, t, startup_timer1);
	struct usb_line6 *line6 = &variax->line6;

	/* schedule another startup procedure until startup is complete: */
	if (variax->startup_progress >= VARIAX_STARTUP_LAST)
		return;

	variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
	line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
			  variax_startup2);
	struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;

	switch (variax->startup_progress) {
	case VARIAX_STARTUP_VERSIONREQ:
		/* repeat request until getting the response */
		schedule_delayed_work(&line6->startup_work,
				      msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
		/* request firmware version: */
		line6_version_request_async(line6);
}

static void variax_startup3(struct usb_line6_variax *variax)
{
	CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);

	/* delay startup procedure: */
	line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
			  variax_startup4);
}

static void variax_startup4(struct timer_list *t)
{
	struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2);

	CHECK_STARTUP_PROGRESS(variax->startup_progress,
			       VARIAX_STARTUP_ACTIVATE);

		break;
	case VARIAX_STARTUP_ACTIVATE:
		/* activate device: */
		variax_activate_async(variax, 1);
	line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
			  variax_startup5);
}

static void variax_startup5(struct timer_list *t)
{
	struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2);

	CHECK_STARTUP_PROGRESS(variax->startup_progress,
			       VARIAX_STARTUP_WORKQUEUE);

	/* schedule work for global work queue: */
	schedule_work(&variax->startup_work);
}

static void variax_startup6(struct work_struct *work)
{
	struct usb_line6_variax *variax =
	    container_of(work, struct usb_line6_variax, startup_work);

	CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);

		variax->startup_progress = VARIAX_STARTUP_SETUP;
		schedule_delayed_work(&line6->startup_work,
				      msecs_to_jiffies(VARIAX_STARTUP_DELAY4));
		break;
	case VARIAX_STARTUP_SETUP:
		/* ALSA audio interface: */
		snd_card_register(variax->line6.card);
		break;
	}
}

/*
@@ -186,11 +126,19 @@ static void line6_variax_process_message(struct usb_line6 *line6)
	case LINE6_SYSEX_BEGIN:
		if (memcmp(buf + 1, variax_init_version + 1,
			   sizeof(variax_init_version) - 1) == 0) {
			variax_startup3(variax);
			if (variax->startup_progress >= VARIAX_STARTUP_ACTIVATE)
				break;
			variax->startup_progress = VARIAX_STARTUP_ACTIVATE;
			cancel_delayed_work(&line6->startup_work);
			schedule_delayed_work(&line6->startup_work,
					      msecs_to_jiffies(VARIAX_STARTUP_DELAY3));
		} else if (memcmp(buf + 1, variax_init_done + 1,
				  sizeof(variax_init_done) - 1) == 0) {
			/* notify of complete initialization: */
			variax_startup4(&variax->startup_timer2);
			if (variax->startup_progress >= VARIAX_STARTUP_SETUP)
				break;
			cancel_delayed_work(&line6->startup_work);
			schedule_delayed_work(&line6->startup_work, 0);
		}
		break;
	}
@@ -203,10 +151,6 @@ static void line6_variax_disconnect(struct usb_line6 *line6)
{
	struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;

	del_timer(&variax->startup_timer1);
	del_timer(&variax->startup_timer2);
	cancel_work_sync(&variax->startup_work);

	kfree(variax->buffer_activate);
}

@@ -221,10 +165,7 @@ static int variax_init(struct usb_line6 *line6,

	line6->process_message = line6_variax_process_message;
	line6->disconnect = line6_variax_disconnect;

	timer_setup(&variax->startup_timer1, NULL, 0);
	timer_setup(&variax->startup_timer2, NULL, 0);
	INIT_WORK(&variax->startup_work, variax_startup6);
	line6->startup = variax_startup;

	/* initialize USB buffers: */
	variax->buffer_activate = kmemdup(variax_activate,
@@ -239,7 +180,8 @@ static int variax_init(struct usb_line6 *line6,
		return err;

	/* initiate startup procedure: */
	variax_startup1(variax);
	schedule_delayed_work(&line6->startup_work,
			      msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
	return 0;
}