Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * miscellaneous helper functions
0004  *
0005  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
0006  */
0007 
0008 #include <linux/delay.h>
0009 #include <linux/device.h>
0010 #include <linux/firewire.h>
0011 #include <linux/module.h>
0012 #include <linux/slab.h>
0013 #include "lib.h"
0014 
0015 #define ERROR_RETRY_DELAY_MS    20
0016 
0017 /**
0018  * snd_fw_transaction - send a request and wait for its completion
0019  * @unit: the driver's unit on the target device
0020  * @tcode: the transaction code
0021  * @offset: the address in the target's address space
0022  * @buffer: input/output data
0023  * @length: length of @buffer
0024  * @flags: use %FW_FIXED_GENERATION and add the generation value to attempt the
0025  *         request only in that generation; use %FW_QUIET to suppress error
0026  *         messages
0027  *
0028  * Submits an asynchronous request to the target device, and waits for the
0029  * response.  The node ID and the current generation are derived from @unit.
0030  * On a bus reset or an error, the transaction is retried a few times.
0031  * Returns zero on success, or a negative error code.
0032  */
0033 int snd_fw_transaction(struct fw_unit *unit, int tcode,
0034                u64 offset, void *buffer, size_t length,
0035                unsigned int flags)
0036 {
0037     struct fw_device *device = fw_parent_device(unit);
0038     int generation, rcode, tries = 0;
0039 
0040     generation = flags & FW_GENERATION_MASK;
0041     for (;;) {
0042         if (!(flags & FW_FIXED_GENERATION)) {
0043             generation = device->generation;
0044             smp_rmb(); /* node_id vs. generation */
0045         }
0046         rcode = fw_run_transaction(device->card, tcode,
0047                        device->node_id, generation,
0048                        device->max_speed, offset,
0049                        buffer, length);
0050 
0051         if (rcode == RCODE_COMPLETE)
0052             return 0;
0053 
0054         if (rcode == RCODE_GENERATION && (flags & FW_FIXED_GENERATION))
0055             return -EAGAIN;
0056 
0057         if (rcode_is_permanent_error(rcode) || ++tries >= 3) {
0058             if (!(flags & FW_QUIET))
0059                 dev_err(&unit->device,
0060                     "transaction failed: %s\n",
0061                     fw_rcode_string(rcode));
0062             return -EIO;
0063         }
0064 
0065         msleep(ERROR_RETRY_DELAY_MS);
0066     }
0067 }
0068 EXPORT_SYMBOL(snd_fw_transaction);
0069 
0070 MODULE_DESCRIPTION("FireWire audio helper functions");
0071 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
0072 MODULE_LICENSE("GPL v2");