Greg Kroah-Hartman | b79c0f4 | 2017-11-07 14:58:47 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
David Kershner | a595a7f | 2017-08-22 13:27:11 -0400 | [diff] [blame] | 2 | /* |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 3 | * Copyright (C) 2010 - 2013 UNISYS CORPORATION |
| 4 | * All rights reserved. |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 5 | */ |
| 6 | |
| 7 | /* |
| 8 | * This header file is to be included by other kernel mode components that |
| 9 | * implement a particular kind of visor_device. Each of these other kernel |
| 10 | * mode components is called a visor device driver. Refer to visortemplate |
| 11 | * for a minimal sample visor device driver. |
| 12 | * |
| 13 | * There should be nothing in this file that is private to the visorbus |
| 14 | * bus implementation itself. |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | #ifndef __VISORBUS_H__ |
| 18 | #define __VISORBUS_H__ |
| 19 | |
| 20 | #include <linux/device.h> |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 21 | |
David Kershner | f09177a | 2017-12-06 11:05:27 -0500 | [diff] [blame] | 22 | #define VISOR_CHANNEL_SIGNATURE ('L' << 24 | 'N' << 16 | 'C' << 8 | 'E') |
Don Zickus | f643921 | 2015-05-05 18:36:02 -0400 | [diff] [blame] | 23 | |
David Kershner | f09177a | 2017-12-06 11:05:27 -0500 | [diff] [blame] | 24 | /* |
| 25 | * enum channel_serverstate |
| 26 | * @CHANNELSRV_UNINITIALIZED: Channel is in an undefined state. |
| 27 | * @CHANNELSRV_READY: Channel has been initialized by server. |
| 28 | */ |
| 29 | enum channel_serverstate { |
| 30 | CHANNELSRV_UNINITIALIZED = 0, |
| 31 | CHANNELSRV_READY = 1 |
| 32 | }; |
| 33 | |
| 34 | /* |
| 35 | * enum channel_clientstate |
| 36 | * @CHANNELCLI_DETACHED: |
| 37 | * @CHANNELCLI_DISABLED: Client can see channel but is NOT allowed to use it |
| 38 | * unless given TBD* explicit request |
| 39 | * (should actually be < DETACHED). |
| 40 | * @CHANNELCLI_ATTACHING: Legacy EFI client request for EFI server to attach. |
| 41 | * @CHANNELCLI_ATTACHED: Idle, but client may want to use channel any time. |
| 42 | * @CHANNELCLI_BUSY: Client either wants to use or is using channel. |
| 43 | * @CHANNELCLI_OWNED: "No worries" state - client can access channel |
| 44 | * anytime. |
| 45 | */ |
| 46 | enum channel_clientstate { |
| 47 | CHANNELCLI_DETACHED = 0, |
| 48 | CHANNELCLI_DISABLED = 1, |
| 49 | CHANNELCLI_ATTACHING = 2, |
| 50 | CHANNELCLI_ATTACHED = 3, |
| 51 | CHANNELCLI_BUSY = 4, |
| 52 | CHANNELCLI_OWNED = 5 |
| 53 | }; |
| 54 | |
| 55 | /* |
| 56 | * Values for VISOR_CHANNEL_PROTOCOL.Features: This define exists so that |
| 57 | * a guest can look at the FeatureFlags in the io channel, and configure the |
| 58 | * driver to use interrupts or not based on this setting. All feature bits for |
| 59 | * all channels should be defined here. The io channel feature bits are defined |
| 60 | * below. |
| 61 | */ |
| 62 | #define VISOR_DRIVER_ENABLES_INTS (0x1ULL << 1) |
| 63 | #define VISOR_CHANNEL_IS_POLLING (0x1ULL << 3) |
| 64 | #define VISOR_IOVM_OK_DRIVER_DISABLING_INTS (0x1ULL << 4) |
| 65 | #define VISOR_DRIVER_DISABLES_INTS (0x1ULL << 5) |
| 66 | #define VISOR_DRIVER_ENHANCED_RCVBUF_CHECKING (0x1ULL << 6) |
| 67 | |
| 68 | /* |
| 69 | * struct channel_header - Common Channel Header |
| 70 | * @signature: Signature. |
| 71 | * @legacy_state: DEPRECATED - being replaced by. |
| 72 | * @header_size: sizeof(struct channel_header). |
| 73 | * @size: Total size of this channel in bytes. |
| 74 | * @features: Flags to modify behavior. |
| 75 | * @chtype: Channel type: data, bus, control, etc.. |
| 76 | * @partition_handle: ID of guest partition. |
| 77 | * @handle: Device number of this channel in client. |
| 78 | * @ch_space_offset: Offset in bytes to channel specific area. |
| 79 | * @version_id: Struct channel_header Version ID. |
| 80 | * @partition_index: Index of guest partition. |
| 81 | * @zone_uuid: Guid of Channel's zone. |
| 82 | * @cli_str_offset: Offset from channel header to null-terminated |
| 83 | * ClientString (0 if ClientString not present). |
| 84 | * @cli_state_boot: CHANNEL_CLIENTSTATE of pre-boot EFI client of this |
| 85 | * channel. |
| 86 | * @cmd_state_cli: CHANNEL_COMMANDSTATE (overloaded in Windows drivers, see |
| 87 | * ServerStateUp, ServerStateDown, etc). |
| 88 | * @cli_state_os: CHANNEL_CLIENTSTATE of Guest OS client of this channel. |
| 89 | * @ch_characteristic: CHANNEL_CHARACTERISTIC_<xxx>. |
| 90 | * @cmd_state_srv: CHANNEL_COMMANDSTATE (overloaded in Windows drivers, see |
| 91 | * ServerStateUp, ServerStateDown, etc). |
| 92 | * @srv_state: CHANNEL_SERVERSTATE. |
| 93 | * @cli_error_boot: Bits to indicate err states for boot clients, so err |
| 94 | * messages can be throttled. |
| 95 | * @cli_error_os: Bits to indicate err states for OS clients, so err |
| 96 | * messages can be throttled. |
| 97 | * @filler: Pad out to 128 byte cacheline. |
| 98 | * @recover_channel: Please add all new single-byte values below here. |
| 99 | */ |
| 100 | struct channel_header { |
| 101 | u64 signature; |
| 102 | u32 legacy_state; |
| 103 | /* SrvState, CliStateBoot, and CliStateOS below */ |
| 104 | u32 header_size; |
| 105 | u64 size; |
| 106 | u64 features; |
| 107 | guid_t chtype; |
| 108 | u64 partition_handle; |
| 109 | u64 handle; |
| 110 | u64 ch_space_offset; |
| 111 | u32 version_id; |
| 112 | u32 partition_index; |
| 113 | guid_t zone_guid; |
| 114 | u32 cli_str_offset; |
| 115 | u32 cli_state_boot; |
| 116 | u32 cmd_state_cli; |
| 117 | u32 cli_state_os; |
| 118 | u32 ch_characteristic; |
| 119 | u32 cmd_state_srv; |
| 120 | u32 srv_state; |
| 121 | u8 cli_error_boot; |
| 122 | u8 cli_error_os; |
| 123 | u8 filler[1]; |
| 124 | u8 recover_channel; |
| 125 | } __packed; |
| 126 | |
| 127 | #define VISOR_CHANNEL_ENABLE_INTS (0x1ULL << 0) |
| 128 | |
| 129 | /* |
| 130 | * struct signal_queue_header - Subheader for the Signal Type variation of the |
| 131 | * Common Channel. |
| 132 | * @version: SIGNAL_QUEUE_HEADER Version ID. |
| 133 | * @chtype: Queue type: storage, network. |
| 134 | * @size: Total size of this queue in bytes. |
| 135 | * @sig_base_offset: Offset to signal queue area. |
| 136 | * @features: Flags to modify behavior. |
| 137 | * @num_sent: Total # of signals placed in this queue. |
| 138 | * @num_overflows: Total # of inserts failed due to full queue. |
| 139 | * @signal_size: Total size of a signal for this queue. |
| 140 | * @max_slots: Max # of slots in queue, 1 slot is always empty. |
| 141 | * @max_signals: Max # of signals in queue (MaxSignalSlots-1). |
| 142 | * @head: Queue head signal #. |
| 143 | * @num_received: Total # of signals removed from this queue. |
| 144 | * @tail: Queue tail signal. |
| 145 | * @reserved1: Reserved field. |
| 146 | * @reserved2: Reserved field. |
| 147 | * @client_queue: |
| 148 | * @num_irq_received: Total # of Interrupts received. This is incremented by the |
| 149 | * ISR in the guest windows driver. |
| 150 | * @num_empty: Number of times that visor_signal_remove is called and |
| 151 | * returned Empty Status. |
| 152 | * @errorflags: Error bits set during SignalReinit to denote trouble with |
| 153 | * client's fields. |
| 154 | * @filler: Pad out to 64 byte cacheline. |
| 155 | */ |
| 156 | struct signal_queue_header { |
| 157 | /* 1st cache line */ |
| 158 | u32 version; |
| 159 | u32 chtype; |
| 160 | u64 size; |
| 161 | u64 sig_base_offset; |
| 162 | u64 features; |
| 163 | u64 num_sent; |
| 164 | u64 num_overflows; |
| 165 | u32 signal_size; |
| 166 | u32 max_slots; |
| 167 | u32 max_signals; |
| 168 | u32 head; |
| 169 | /* 2nd cache line */ |
| 170 | u64 num_received; |
| 171 | u32 tail; |
| 172 | u32 reserved1; |
| 173 | u64 reserved2; |
| 174 | u64 client_queue; |
| 175 | u64 num_irq_received; |
| 176 | u64 num_empty; |
| 177 | u32 errorflags; |
| 178 | u8 filler[12]; |
| 179 | } __packed; |
| 180 | |
| 181 | /* VISORCHANNEL Guids */ |
| 182 | /* {414815ed-c58c-11da-95a9-00e08161165f} */ |
| 183 | #define VISOR_VHBA_CHANNEL_GUID \ |
| 184 | GUID_INIT(0x414815ed, 0xc58c, 0x11da, \ |
| 185 | 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) |
| 186 | #define VISOR_VHBA_CHANNEL_GUID_STR \ |
| 187 | "414815ed-c58c-11da-95a9-00e08161165f" |
Don Zickus | 1fb3016 | 2015-05-13 13:22:18 -0400 | [diff] [blame] | 188 | struct visorchipset_state { |
| 189 | u32 created:1; |
| 190 | u32 attached:1; |
| 191 | u32 configured:1; |
| 192 | u32 running:1; |
Sameer Wadgaonkar | b2d06ca | 2017-09-27 13:14:46 -0400 | [diff] [blame] | 193 | /* Remaining bits in this 32-bit word are reserved. */ |
Don Zickus | 1fb3016 | 2015-05-13 13:22:18 -0400 | [diff] [blame] | 194 | }; |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 195 | |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 196 | /** |
| 197 | * struct visor_device - A device type for things "plugged" into the visorbus |
Sameer Wadgaonkar | b2d06ca | 2017-09-27 13:14:46 -0400 | [diff] [blame] | 198 | * bus |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 199 | * @visorchannel: Points to the channel that the device is |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 200 | * associated with. |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 201 | * @channel_type_guid: Identifies the channel type to the bus driver. |
| 202 | * @device: Device struct meant for use by the bus driver |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 203 | * only. |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 204 | * @list_all: Used by the bus driver to enumerate devices. |
| 205 | * @timer: Timer fired periodically to do interrupt-type |
Tim Sell | 9ebab64 | 2016-06-10 21:48:08 -0400 | [diff] [blame] | 206 | * activity. |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 207 | * @being_removed: Indicates that the device is being removed from |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 208 | * the bus. Private bus driver use only. |
David Kershner | eaec40a | 2017-08-30 13:36:18 -0400 | [diff] [blame] | 209 | * @visordriver_callback_lock: Used by the bus driver to lock when adding and |
| 210 | * removing devices. |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 211 | * @pausing: Indicates that a change towards a paused state. |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 212 | * is in progress. Only modified by the bus driver. |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 213 | * @resuming: Indicates that a change towards a running state |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 214 | * is in progress. Only modified by the bus driver. |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 215 | * @chipset_bus_no: Private field used by the bus driver. |
| 216 | * @chipset_dev_no: Private field used the bus driver. |
| 217 | * @state: Used to indicate the current state of the |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 218 | * device. |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 219 | * @inst: Unique GUID for this instance of the device. |
| 220 | * @name: Name of the device. |
| 221 | * @pending_msg_hdr: For private use by bus driver to respond to |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 222 | * hypervisor requests. |
David Binder | eafc6a9 | 2016-06-10 21:48:20 -0400 | [diff] [blame] | 223 | * @vbus_hdr_info: A pointer to header info. Private use by bus |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 224 | * driver. |
Andy Shevchenko | b32c5cb | 2017-08-22 13:26:54 -0400 | [diff] [blame] | 225 | * @partition_guid: Indicates client partion id. This should be the |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 226 | * same across all visor_devices in the current |
| 227 | * guest. Private use by bus driver only. |
| 228 | */ |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 229 | struct visor_device { |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 230 | struct visorchannel *visorchannel; |
Andy Shevchenko | b32c5cb | 2017-08-22 13:26:54 -0400 | [diff] [blame] | 231 | guid_t channel_type_guid; |
Alexander Curtin | 39b9280 | 2016-04-18 23:22:02 -0400 | [diff] [blame] | 232 | /* These fields are for private use by the bus driver only. */ |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 233 | struct device device; |
| 234 | struct list_head list_all; |
Tim Sell | 9ebab64 | 2016-06-10 21:48:08 -0400 | [diff] [blame] | 235 | struct timer_list timer; |
| 236 | bool timer_active; |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 237 | bool being_removed; |
David Kershner | eaec40a | 2017-08-30 13:36:18 -0400 | [diff] [blame] | 238 | struct mutex visordriver_callback_lock; /* synchronize probe/remove */ |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 239 | bool pausing; |
| 240 | bool resuming; |
Don Zickus | 65bd6e4 | 2015-06-04 09:22:40 -0400 | [diff] [blame] | 241 | u32 chipset_bus_no; |
| 242 | u32 chipset_dev_no; |
Don Zickus | 1fb3016 | 2015-05-13 13:22:18 -0400 | [diff] [blame] | 243 | struct visorchipset_state state; |
Andy Shevchenko | b32c5cb | 2017-08-22 13:26:54 -0400 | [diff] [blame] | 244 | guid_t inst; |
Don Zickus | 1fb3016 | 2015-05-13 13:22:18 -0400 | [diff] [blame] | 245 | u8 *name; |
Don Zickus | 1fb3016 | 2015-05-13 13:22:18 -0400 | [diff] [blame] | 246 | struct controlvm_message_header *pending_msg_hdr; |
| 247 | void *vbus_hdr_info; |
Andy Shevchenko | b32c5cb | 2017-08-22 13:26:54 -0400 | [diff] [blame] | 248 | guid_t partition_guid; |
Tim Sell | 8217bec | 2016-11-03 11:44:16 -0400 | [diff] [blame] | 249 | struct dentry *debugfs_dir; |
David Kershner | 1c21800 | 2017-09-27 13:14:21 -0400 | [diff] [blame] | 250 | struct dentry *debugfs_bus_info; |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 251 | }; |
| 252 | |
| 253 | #define to_visor_device(x) container_of(x, struct visor_device, device) |
| 254 | |
David Kershner | 6db4325 | 2017-09-27 13:14:32 -0400 | [diff] [blame] | 255 | typedef void (*visorbus_state_complete_func) (struct visor_device *dev, |
| 256 | int status); |
| 257 | |
| 258 | /* |
Sameer Wadgaonkar | b2d06ca | 2017-09-27 13:14:46 -0400 | [diff] [blame] | 259 | * This struct describes a specific visor channel, by providing its GUID, name, |
| 260 | * and sizes. |
David Kershner | 6db4325 | 2017-09-27 13:14:32 -0400 | [diff] [blame] | 261 | */ |
| 262 | struct visor_channeltype_descriptor { |
| 263 | const guid_t guid; |
| 264 | const char *name; |
| 265 | u64 min_bytes; |
| 266 | u32 version; |
| 267 | }; |
| 268 | |
| 269 | /** |
| 270 | * struct visor_driver - Information provided by each visor driver when it |
Sameer Wadgaonkar | b2d06ca | 2017-09-27 13:14:46 -0400 | [diff] [blame] | 271 | * registers with the visorbus driver |
David Kershner | 6db4325 | 2017-09-27 13:14:32 -0400 | [diff] [blame] | 272 | * @name: Name of the visor driver. |
| 273 | * @owner: The module owner. |
| 274 | * @channel_types: Types of channels handled by this driver, ending with |
| 275 | * a zero GUID. Our specialized BUS.match() method knows |
| 276 | * about this list, and uses it to determine whether this |
| 277 | * driver will in fact handle a new device that it has |
| 278 | * detected. |
| 279 | * @probe: Called when a new device comes online, by our probe() |
| 280 | * function specified by driver.probe() (triggered |
| 281 | * ultimately by some call to driver_register(), |
| 282 | * bus_add_driver(), or driver_attach()). |
| 283 | * @remove: Called when a new device is removed, by our remove() |
| 284 | * function specified by driver.remove() (triggered |
| 285 | * ultimately by some call to device_release_driver()). |
| 286 | * @channel_interrupt: Called periodically, whenever there is a possiblity |
| 287 | * that "something interesting" may have happened to the |
| 288 | * channel. |
| 289 | * @pause: Called to initiate a change of the device's state. If |
| 290 | * the return valu`e is < 0, there was an error and the |
| 291 | * state transition will NOT occur. If the return value |
| 292 | * is >= 0, then the state transition was INITIATED |
| 293 | * successfully, and complete_func() will be called (or |
| 294 | * was just called) with the final status when either the |
| 295 | * state transition fails or completes successfully. |
| 296 | * @resume: Behaves similar to pause. |
| 297 | * @driver: Private reference to the device driver. For use by bus |
| 298 | * driver only. |
| 299 | */ |
| 300 | struct visor_driver { |
| 301 | const char *name; |
| 302 | struct module *owner; |
| 303 | struct visor_channeltype_descriptor *channel_types; |
| 304 | int (*probe)(struct visor_device *dev); |
| 305 | void (*remove)(struct visor_device *dev); |
| 306 | void (*channel_interrupt)(struct visor_device *dev); |
| 307 | int (*pause)(struct visor_device *dev, |
| 308 | visorbus_state_complete_func complete_func); |
| 309 | int (*resume)(struct visor_device *dev, |
| 310 | visorbus_state_complete_func complete_func); |
| 311 | |
| 312 | /* These fields are for private use by the bus driver only. */ |
| 313 | struct device_driver driver; |
| 314 | }; |
| 315 | |
| 316 | #define to_visor_driver(x) (container_of(x, struct visor_driver, driver)) |
| 317 | |
Sameer Wadgaonkar | e25201d | 2017-08-30 13:36:35 -0400 | [diff] [blame] | 318 | int visor_check_channel(struct channel_header *ch, struct device *dev, |
| 319 | const guid_t *expected_uuid, char *chname, |
| 320 | u64 expected_min_bytes, u32 expected_version, |
| 321 | u64 expected_signature); |
Sameer Wadgaonkar | 403043c | 2017-07-17 16:17:02 -0400 | [diff] [blame] | 322 | |
David Binder | 3cda79c | 2017-03-17 11:27:09 -0400 | [diff] [blame] | 323 | int visorbus_register_visor_driver(struct visor_driver *drv); |
| 324 | void visorbus_unregister_visor_driver(struct visor_driver *drv); |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 325 | int visorbus_read_channel(struct visor_device *dev, |
| 326 | unsigned long offset, void *dest, |
| 327 | unsigned long nbytes); |
| 328 | int visorbus_write_channel(struct visor_device *dev, |
| 329 | unsigned long offset, void *src, |
| 330 | unsigned long nbytes); |
David Kershner | 5dca9b2 | 2017-03-28 09:34:44 -0400 | [diff] [blame] | 331 | int visorbus_enable_channel_interrupts(struct visor_device *dev); |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 332 | void visorbus_disable_channel_interrupts(struct visor_device *dev); |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 333 | |
David Binder | f621a96 | 2016-09-26 11:03:48 -0400 | [diff] [blame] | 334 | int visorchannel_signalremove(struct visorchannel *channel, u32 queue, |
| 335 | void *msg); |
David Binder | 264f7b8 | 2016-09-26 11:03:49 -0400 | [diff] [blame] | 336 | int visorchannel_signalinsert(struct visorchannel *channel, u32 queue, |
| 337 | void *msg); |
Neil Horman | fdc792c | 2015-07-31 18:56:32 -0400 | [diff] [blame] | 338 | bool visorchannel_signalempty(struct visorchannel *channel, u32 queue); |
Andy Shevchenko | b32c5cb | 2017-08-22 13:26:54 -0400 | [diff] [blame] | 339 | const guid_t *visorchannel_get_guid(struct visorchannel *channel); |
Don Zickus | f643921 | 2015-05-05 18:36:02 -0400 | [diff] [blame] | 340 | |
David Binder | 4830aec | 2017-03-17 11:27:26 -0400 | [diff] [blame] | 341 | #define BUS_ROOT_DEVICE UINT_MAX |
Don Zickus | d32517e | 2015-06-04 09:22:41 -0400 | [diff] [blame] | 342 | struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no, |
| 343 | struct visor_device *from); |
Erik Arfvidson | 3703987 | 2015-05-05 18:36:00 -0400 | [diff] [blame] | 344 | #endif |