1 /* 2 * Function Control Protocol (IEC 61883-1) 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/device.h> 9 #include <linux/firewire.h> 10 #include <linux/firewire-constants.h> 11 #include <linux/list.h> 12 #include <linux/module.h> 13 #include <linux/sched.h> 14 #include <linux/spinlock.h> 15 #include <linux/wait.h> 16 #include <linux/delay.h> 17 #include "fcp.h" 18 #include "lib.h" 19 20 #define CTS_AVC 0x00 21 22 #define ERROR_RETRIES 3 23 #define ERROR_DELAY_MS 5 24 #define FCP_TIMEOUT_MS 125 25 26 static DEFINE_SPINLOCK(transactions_lock); 27 static LIST_HEAD(transactions); 28 29 enum fcp_state { 30 STATE_PENDING, 31 STATE_BUS_RESET, 32 STATE_COMPLETE, 33 }; 34 35 struct fcp_transaction { 36 struct list_head list; 37 struct fw_unit *unit; 38 void *response_buffer; 39 unsigned int response_size; 40 unsigned int response_match_bytes; 41 enum fcp_state state; 42 wait_queue_head_t wait; 43 }; 44 45 /** 46 * fcp_avc_transaction - send an AV/C command and wait for its response 47 * @unit: a unit on the target device 48 * @command: a buffer containing the command frame; must be DMA-able 49 * @command_size: the size of @command 50 * @response: a buffer for the response frame 51 * @response_size: the maximum size of @response 52 * @response_match_bytes: a bitmap specifying the bytes used to detect the 53 * correct response frame 54 * 55 * This function sends a FCP command frame to the target and waits for the 56 * corresponding response frame to be returned. 57 * 58 * Because it is possible for multiple FCP transactions to be active at the 59 * same time, the correct response frame is detected by the value of certain 60 * bytes. These bytes must be set in @response before calling this function, 61 * and the corresponding bits must be set in @response_match_bytes. 62 * 63 * @command and @response can point to the same buffer. 64 * 65 * Asynchronous operation (INTERIM, NOTIFY) is not supported at the moment. 66 * 67 * Returns the actual size of the response frame, or a negative error code. 68 */ 69 int fcp_avc_transaction(struct fw_unit *unit, 70 const void *command, unsigned int command_size, 71 void *response, unsigned int response_size, 72 unsigned int response_match_bytes) 73 { 74 struct fcp_transaction t; 75 int tcode, ret, tries = 0; 76 77 t.unit = unit; 78 t.response_buffer = response; 79 t.response_size = response_size; 80 t.response_match_bytes = response_match_bytes; 81 t.state = STATE_PENDING; 82 init_waitqueue_head(&t.wait); 83 84 spin_lock_irq(&transactions_lock); 85 list_add_tail(&t.list, &transactions); 86 spin_unlock_irq(&transactions_lock); 87 88 for (;;) { 89 tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST 90 : TCODE_WRITE_BLOCK_REQUEST; 91 ret = snd_fw_transaction(t.unit, tcode, 92 CSR_REGISTER_BASE + CSR_FCP_COMMAND, 93 (void *)command, command_size); 94 if (ret < 0) 95 break; 96 97 wait_event_timeout(t.wait, t.state != STATE_PENDING, 98 msecs_to_jiffies(FCP_TIMEOUT_MS)); 99 100 if (t.state == STATE_COMPLETE) { 101 ret = t.response_size; 102 break; 103 } else if (t.state == STATE_BUS_RESET) { 104 msleep(ERROR_DELAY_MS); 105 } else if (++tries >= ERROR_RETRIES) { 106 dev_err(&t.unit->device, "FCP command timed out\n"); 107 ret = -EIO; 108 break; 109 } 110 } 111 112 spin_lock_irq(&transactions_lock); 113 list_del(&t.list); 114 spin_unlock_irq(&transactions_lock); 115 116 return ret; 117 } 118 EXPORT_SYMBOL(fcp_avc_transaction); 119 120 /** 121 * fcp_bus_reset - inform the target handler about a bus reset 122 * @unit: the unit that might be used by fcp_avc_transaction() 123 * 124 * This function must be called from the driver's .update handler to inform 125 * the FCP transaction handler that a bus reset has happened. Any pending FCP 126 * transactions are retried. 127 */ 128 void fcp_bus_reset(struct fw_unit *unit) 129 { 130 struct fcp_transaction *t; 131 132 spin_lock_irq(&transactions_lock); 133 list_for_each_entry(t, &transactions, list) { 134 if (t->unit == unit && 135 t->state == STATE_PENDING) { 136 t->state = STATE_BUS_RESET; 137 wake_up(&t->wait); 138 } 139 } 140 spin_unlock_irq(&transactions_lock); 141 } 142 EXPORT_SYMBOL(fcp_bus_reset); 143 144 /* checks whether the response matches the masked bytes in response_buffer */ 145 static bool is_matching_response(struct fcp_transaction *transaction, 146 const void *response, size_t length) 147 { 148 const u8 *p1, *p2; 149 unsigned int mask, i; 150 151 p1 = response; 152 p2 = transaction->response_buffer; 153 mask = transaction->response_match_bytes; 154 155 for (i = 0; ; ++i) { 156 if ((mask & 1) && p1[i] != p2[i]) 157 return false; 158 mask >>= 1; 159 if (!mask) 160 return true; 161 if (--length == 0) 162 return false; 163 } 164 } 165 166 static void fcp_response(struct fw_card *card, struct fw_request *request, 167 int tcode, int destination, int source, 168 int generation, unsigned long long offset, 169 void *data, size_t length, void *callback_data) 170 { 171 struct fcp_transaction *t; 172 unsigned long flags; 173 174 if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC) 175 return; 176 177 spin_lock_irqsave(&transactions_lock, flags); 178 list_for_each_entry(t, &transactions, list) { 179 struct fw_device *device = fw_parent_device(t->unit); 180 if (device->card != card || 181 device->generation != generation) 182 continue; 183 smp_rmb(); /* node_id vs. generation */ 184 if (device->node_id != source) 185 continue; 186 187 if (t->state == STATE_PENDING && 188 is_matching_response(t, data, length)) { 189 t->state = STATE_COMPLETE; 190 t->response_size = min((unsigned int)length, 191 t->response_size); 192 memcpy(t->response_buffer, data, t->response_size); 193 wake_up(&t->wait); 194 } 195 } 196 spin_unlock_irqrestore(&transactions_lock, flags); 197 } 198 199 static struct fw_address_handler response_register_handler = { 200 .length = 0x200, 201 .address_callback = fcp_response, 202 }; 203 204 static int __init fcp_module_init(void) 205 { 206 static const struct fw_address_region response_register_region = { 207 .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE, 208 .end = CSR_REGISTER_BASE + CSR_FCP_END, 209 }; 210 211 fw_core_add_address_handler(&response_register_handler, 212 &response_register_region); 213 214 return 0; 215 } 216 217 static void __exit fcp_module_exit(void) 218 { 219 WARN_ON(!list_empty(&transactions)); 220 fw_core_remove_address_handler(&response_register_handler); 221 } 222 223 module_init(fcp_module_init); 224 module_exit(fcp_module_exit); 225