/* * Line6 Linux USB driver - 0.9.1beta * * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. * */ #include <linux/slab.h> #include "driver.h" #include "dumprequest.h" /* Set "dump in progress" flag. */ void line6_dump_started(struct line6_dump_request *l6dr, int dest) { l6dr->in_progress = dest; } /* Invalidate current channel, i.e., set "dump in progress" flag. Reading from the "dump" special file blocks until dump is completed. */ void line6_invalidate_current(struct line6_dump_request *l6dr) { line6_dump_started(l6dr, LINE6_DUMP_CURRENT); } /* Clear "dump in progress" flag and notify waiting processes. */ void line6_dump_finished(struct line6_dump_request *l6dr) { l6dr->in_progress = LINE6_DUMP_NONE; wake_up(&l6dr->wait); } /* Send an asynchronous channel dump request. */ int line6_dump_request_async(struct line6_dump_request *l6dr, struct usb_line6 *line6, int num, int dest) { int ret; line6_dump_started(l6dr, dest); ret = line6_send_raw_message_async(line6, l6dr->reqbufs[num].buffer, l6dr->reqbufs[num].length); if (ret < 0) line6_dump_finished(l6dr); return ret; } /* Wait for completion (interruptible). */ int line6_dump_wait_interruptible(struct line6_dump_request *l6dr) { return wait_event_interruptible(l6dr->wait, l6dr->in_progress == LINE6_DUMP_NONE); } /* Wait for completion. */ void line6_dump_wait(struct line6_dump_request *l6dr) { wait_event(l6dr->wait, l6dr->in_progress == LINE6_DUMP_NONE); } /* Wait for completion (with timeout). */ int line6_dump_wait_timeout(struct line6_dump_request *l6dr, long timeout) { return wait_event_timeout(l6dr->wait, l6dr->in_progress == LINE6_DUMP_NONE, timeout); } /* Initialize dump request buffer. */ int line6_dumpreq_initbuf(struct line6_dump_request *l6dr, const void *buf, size_t len, int num) { l6dr->reqbufs[num].buffer = kmemdup(buf, len, GFP_KERNEL); if (l6dr->reqbufs[num].buffer == NULL) return -ENOMEM; l6dr->reqbufs[num].length = len; return 0; } /* Initialize dump request data structure (including one buffer). */ int line6_dumpreq_init(struct line6_dump_request *l6dr, const void *buf, size_t len) { int ret; ret = line6_dumpreq_initbuf(l6dr, buf, len, 0); if (ret < 0) return ret; init_waitqueue_head(&l6dr->wait); return 0; } /* Destruct dump request data structure. */ void line6_dumpreq_destructbuf(struct line6_dump_request *l6dr, int num) { if (l6dr == NULL) return; if (l6dr->reqbufs[num].buffer == NULL) return; kfree(l6dr->reqbufs[num].buffer); l6dr->reqbufs[num].buffer = NULL; } /* Destruct dump request data structure. */ void line6_dumpreq_destruct(struct line6_dump_request *l6dr) { if (l6dr->reqbufs[0].buffer == NULL) return; line6_dumpreq_destructbuf(l6dr, 0); }