@@ -2107,6 +2107,138 @@ EXPORT_SYMBOL_GPL(spi_res_release);
2107
2107
2108
2108
/*-------------------------------------------------------------------------*/
2109
2109
2110
+ /* Core methods for spi_message alterations */
2111
+
2112
+ static void __spi_replace_transfers_release (struct spi_master * master ,
2113
+ struct spi_message * msg ,
2114
+ void * res )
2115
+ {
2116
+ struct spi_replaced_transfers * rxfer = res ;
2117
+ size_t i ;
2118
+
2119
+ /* call extra callback if requested */
2120
+ if (rxfer -> release )
2121
+ rxfer -> release (master , msg , res );
2122
+
2123
+ /* insert replaced transfers back into the message */
2124
+ list_splice (& rxfer -> replaced_transfers , rxfer -> replaced_after );
2125
+
2126
+ /* remove the formerly inserted entries */
2127
+ for (i = 0 ; i < rxfer -> inserted ; i ++ )
2128
+ list_del (& rxfer -> inserted_transfers [i ].transfer_list );
2129
+ }
2130
+
2131
+ /**
2132
+ * spi_replace_transfers - replace transfers with several transfers
2133
+ * and register change with spi_message.resources
2134
+ * @msg: the spi_message we work upon
2135
+ * @xfer_first: the first spi_transfer we want to replace
2136
+ * @remove: number of transfers to remove
2137
+ * @insert: the number of transfers we want to insert instead
2138
+ * @release: extra release code necessary in some circumstances
2139
+ * @extradatasize: extra data to allocate (with alignment guarantees
2140
+ * of struct @spi_transfer)
2141
+ *
2142
+ * Returns: pointer to @spi_replaced_transfers,
2143
+ * PTR_ERR(...) in case of errors.
2144
+ */
2145
+ struct spi_replaced_transfers * spi_replace_transfers (
2146
+ struct spi_message * msg ,
2147
+ struct spi_transfer * xfer_first ,
2148
+ size_t remove ,
2149
+ size_t insert ,
2150
+ spi_replaced_release_t release ,
2151
+ size_t extradatasize ,
2152
+ gfp_t gfp )
2153
+ {
2154
+ struct spi_replaced_transfers * rxfer ;
2155
+ struct spi_transfer * xfer ;
2156
+ size_t i ;
2157
+
2158
+ /* allocate the structure using spi_res */
2159
+ rxfer = spi_res_alloc (msg -> spi , __spi_replace_transfers_release ,
2160
+ insert * sizeof (struct spi_transfer )
2161
+ + sizeof (struct spi_replaced_transfers )
2162
+ + extradatasize ,
2163
+ gfp );
2164
+ if (!rxfer )
2165
+ return ERR_PTR (- ENOMEM );
2166
+
2167
+ /* the release code to invoke before running the generic release */
2168
+ rxfer -> release = release ;
2169
+
2170
+ /* assign extradata */
2171
+ if (extradatasize )
2172
+ rxfer -> extradata =
2173
+ & rxfer -> inserted_transfers [insert ];
2174
+
2175
+ /* init the replaced_transfers list */
2176
+ INIT_LIST_HEAD (& rxfer -> replaced_transfers );
2177
+
2178
+ /* assign the list_entry after which we should reinsert
2179
+ * the @replaced_transfers - it may be spi_message.messages!
2180
+ */
2181
+ rxfer -> replaced_after = xfer_first -> transfer_list .prev ;
2182
+
2183
+ /* remove the requested number of transfers */
2184
+ for (i = 0 ; i < remove ; i ++ ) {
2185
+ /* if the entry after replaced_after it is msg->transfers
2186
+ * then we have been requested to remove more transfers
2187
+ * than are in the list
2188
+ */
2189
+ if (rxfer -> replaced_after -> next == & msg -> transfers ) {
2190
+ dev_err (& msg -> spi -> dev ,
2191
+ "requested to remove more spi_transfers than are available\n" );
2192
+ /* insert replaced transfers back into the message */
2193
+ list_splice (& rxfer -> replaced_transfers ,
2194
+ rxfer -> replaced_after );
2195
+
2196
+ /* free the spi_replace_transfer structure */
2197
+ spi_res_free (rxfer );
2198
+
2199
+ /* and return with an error */
2200
+ return ERR_PTR (- EINVAL );
2201
+ }
2202
+
2203
+ /* remove the entry after replaced_after from list of
2204
+ * transfers and add it to list of replaced_transfers
2205
+ */
2206
+ list_move_tail (rxfer -> replaced_after -> next ,
2207
+ & rxfer -> replaced_transfers );
2208
+ }
2209
+
2210
+ /* create copy of the given xfer with identical settings
2211
+ * based on the first transfer to get removed
2212
+ */
2213
+ for (i = 0 ; i < insert ; i ++ ) {
2214
+ /* we need to run in reverse order */
2215
+ xfer = & rxfer -> inserted_transfers [insert - 1 - i ];
2216
+
2217
+ /* copy all spi_transfer data */
2218
+ memcpy (xfer , xfer_first , sizeof (* xfer ));
2219
+
2220
+ /* add to list */
2221
+ list_add (& xfer -> transfer_list , rxfer -> replaced_after );
2222
+
2223
+ /* clear cs_change and delay_usecs for all but the last */
2224
+ if (i ) {
2225
+ xfer -> cs_change = false;
2226
+ xfer -> delay_usecs = 0 ;
2227
+ }
2228
+ }
2229
+
2230
+ /* set up inserted */
2231
+ rxfer -> inserted = insert ;
2232
+
2233
+ /* and register it with spi_res/spi_message */
2234
+ spi_res_add (msg , rxfer );
2235
+
2236
+ return rxfer ;
2237
+ }
2238
+ EXPORT_SYMBOL_GPL (spi_replace_transfers );
2239
+
2240
+ /*-------------------------------------------------------------------------*/
2241
+
2110
2242
/* Core methods for SPI master protocol drivers. Some of the
2111
2243
* other core methods are currently defined as inline functions.
2112
2244
*/
0 commit comments