Merge tag 'v2.6.39-rc7'
[pandora-kernel.git] / sound / firewire / lib.c
1 /*
2  * miscellaneous helper functions
3  *
4  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5  * Licensed under the terms of the GNU General Public License, version 2.
6  */
7
8 #include <linux/delay.h>
9 #include <linux/device.h>
10 #include <linux/firewire.h>
11 #include <linux/module.h>
12 #include "lib.h"
13
14 #define ERROR_RETRY_DELAY_MS    5
15
16 /**
17  * rcode_string - convert a firewire result code to a string
18  * @rcode: the result
19  */
20 const char *rcode_string(unsigned int rcode)
21 {
22         static const char *const names[] = {
23                 [RCODE_COMPLETE]        = "complete",
24                 [RCODE_CONFLICT_ERROR]  = "conflict error",
25                 [RCODE_DATA_ERROR]      = "data error",
26                 [RCODE_TYPE_ERROR]      = "type error",
27                 [RCODE_ADDRESS_ERROR]   = "address error",
28                 [RCODE_SEND_ERROR]      = "send error",
29                 [RCODE_CANCELLED]       = "cancelled",
30                 [RCODE_BUSY]            = "busy",
31                 [RCODE_GENERATION]      = "generation",
32                 [RCODE_NO_ACK]          = "no ack",
33         };
34
35         if (rcode < ARRAY_SIZE(names) && names[rcode])
36                 return names[rcode];
37         else
38                 return "unknown";
39 }
40 EXPORT_SYMBOL(rcode_string);
41
42 /**
43  * snd_fw_transaction - send a request and wait for its completion
44  * @unit: the driver's unit on the target device
45  * @tcode: the transaction code
46  * @offset: the address in the target's address space
47  * @buffer: input/output data
48  * @length: length of @buffer
49  *
50  * Submits an asynchronous request to the target device, and waits for the
51  * response.  The node ID and the current generation are derived from @unit.
52  * On a bus reset or an error, the transaction is retried a few times.
53  * Returns zero on success, or a negative error code.
54  */
55 int snd_fw_transaction(struct fw_unit *unit, int tcode,
56                        u64 offset, void *buffer, size_t length)
57 {
58         struct fw_device *device = fw_parent_device(unit);
59         int generation, rcode, tries = 0;
60
61         for (;;) {
62                 generation = device->generation;
63                 smp_rmb(); /* node_id vs. generation */
64                 rcode = fw_run_transaction(device->card, tcode,
65                                            device->node_id, generation,
66                                            device->max_speed, offset,
67                                            buffer, length);
68
69                 if (rcode == RCODE_COMPLETE)
70                         return 0;
71
72                 if (rcode_is_permanent_error(rcode) || ++tries >= 3) {
73                         dev_err(&unit->device, "transaction failed: %s\n",
74                                 rcode_string(rcode));
75                         return -EIO;
76                 }
77
78                 msleep(ERROR_RETRY_DELAY_MS);
79         }
80 }
81 EXPORT_SYMBOL(snd_fw_transaction);
82
83 MODULE_DESCRIPTION("FireWire audio helper functions");
84 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
85 MODULE_LICENSE("GPL v2");