Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Wireless USB Host Controller |
| 3 | * Common infrastructure for WHCI and HWA WUSB-HC drivers |
| 4 | * |
| 5 | * |
| 6 | * Copyright (C) 2005-2006 Intel Corporation |
| 7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> |
| 8 | * |
| 9 | * This program is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU General Public License version |
| 11 | * 2 as published by the Free Software Foundation. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software |
| 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 21 | * 02110-1301, USA. |
| 22 | * |
| 23 | * |
| 24 | * This driver implements parts common to all Wireless USB Host |
| 25 | * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used |
| 26 | * by: |
| 27 | * |
| 28 | * - hwahc: HWA, USB-dongle that implements a Wireless USB host |
| 29 | * controller, (Wireless USB 1.0 Host-Wire-Adapter specification). |
| 30 | * |
| 31 | * - whci: WHCI, a PCI card with a wireless host controller |
| 32 | * (Wireless Host Controller Interface 1.0 specification). |
| 33 | * |
| 34 | * Check out the Design-overview.txt file in the source documentation |
| 35 | * for other details on the implementation. |
| 36 | * |
| 37 | * Main blocks: |
| 38 | * |
| 39 | * rh Root Hub emulation (part of the HCD glue) |
| 40 | * |
| 41 | * devconnect Handle all the issues related to device connection, |
| 42 | * authentication, disconnection, timeout, reseting, |
| 43 | * keepalives, etc. |
| 44 | * |
| 45 | * mmc MMC IE broadcasting handling |
| 46 | * |
| 47 | * A host controller driver just initializes its stuff and as part of |
| 48 | * that, creates a 'struct wusbhc' instance that handles all the |
| 49 | * common WUSB mechanisms. Links in the function ops that are specific |
| 50 | * to it and then registers the host controller. Ready to run. |
| 51 | */ |
| 52 | |
| 53 | #ifndef __WUSBHC_H__ |
| 54 | #define __WUSBHC_H__ |
| 55 | |
| 56 | #include <linux/usb.h> |
| 57 | #include <linux/list.h> |
| 58 | #include <linux/mutex.h> |
| 59 | #include <linux/kref.h> |
| 60 | #include <linux/workqueue.h> |
| 61 | /* FIXME: Yes, I know: BAD--it's not my fault the USB HC iface is not |
| 62 | * public */ |
| 63 | #include <linux/../../drivers/usb/core/hcd.h> |
| 64 | #include <linux/uwb.h> |
| 65 | #include <linux/usb/wusb.h> |
| 66 | |
David Vrabel | 4d2bea4 | 2008-10-27 15:42:31 +0000 | [diff] [blame] | 67 | /* |
| 68 | * Time from a WUSB channel stop request to the last transmitted MMC. |
| 69 | * |
| 70 | * This needs to be > 4.096 ms in case no MMCs can be transmitted in |
| 71 | * zone 0. |
| 72 | */ |
| 73 | #define WUSB_CHANNEL_STOP_DELAY_MS 8 |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 74 | |
| 75 | /** |
| 76 | * Wireless USB device |
| 77 | * |
| 78 | * Describe a WUSB device connected to the cluster. This struct |
| 79 | * belongs to the 'struct wusb_port' it is attached to and it is |
| 80 | * responsible for putting and clearing the pointer to it. |
| 81 | * |
| 82 | * Note this "complements" the 'struct usb_device' that the usb_hcd |
| 83 | * keeps for each connected USB device. However, it extends some |
| 84 | * information that is not available (there is no hcpriv ptr in it!) |
| 85 | * *and* most importantly, it's life cycle is different. It is created |
| 86 | * as soon as we get a DN_Connect (connect request notification) from |
| 87 | * the device through the WUSB host controller; the USB stack doesn't |
| 88 | * create the device until we authenticate it. FIXME: this will |
| 89 | * change. |
| 90 | * |
| 91 | * @bos: This is allocated when the BOS descriptors are read from |
| 92 | * the device and freed upon the wusb_dev struct dying. |
| 93 | * @wusb_cap_descr: points into @bos, and has been verified to be size |
| 94 | * safe. |
| 95 | */ |
| 96 | struct wusb_dev { |
| 97 | struct kref refcnt; |
| 98 | struct wusbhc *wusbhc; |
| 99 | struct list_head cack_node; /* Connect-Ack list */ |
| 100 | u8 port_idx; |
| 101 | u8 addr; |
| 102 | u8 beacon_type:4; |
| 103 | struct usb_encryption_descriptor ccm1_etd; |
| 104 | struct wusb_ckhdid cdid; |
| 105 | unsigned long entry_ts; |
| 106 | struct usb_bos_descriptor *bos; |
| 107 | struct usb_wireless_cap_descriptor *wusb_cap_descr; |
| 108 | struct uwb_mas_bm availability; |
| 109 | struct work_struct devconnect_acked_work; |
| 110 | struct urb *set_gtk_urb; |
| 111 | struct usb_ctrlrequest *set_gtk_req; |
| 112 | struct usb_device *usb_dev; |
| 113 | }; |
| 114 | |
| 115 | #define WUSB_DEV_ADDR_UNAUTH 0x80 |
| 116 | |
| 117 | static inline void wusb_dev_init(struct wusb_dev *wusb_dev) |
| 118 | { |
| 119 | kref_init(&wusb_dev->refcnt); |
| 120 | /* no need to init the cack_node */ |
| 121 | } |
| 122 | |
| 123 | extern void wusb_dev_destroy(struct kref *_wusb_dev); |
| 124 | |
| 125 | static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev) |
| 126 | { |
| 127 | kref_get(&wusb_dev->refcnt); |
| 128 | return wusb_dev; |
| 129 | } |
| 130 | |
| 131 | static inline void wusb_dev_put(struct wusb_dev *wusb_dev) |
| 132 | { |
| 133 | kref_put(&wusb_dev->refcnt, wusb_dev_destroy); |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | * Wireless USB Host Controlller root hub "fake" ports |
| 138 | * (state and device information) |
| 139 | * |
| 140 | * Wireless USB is wireless, so there are no ports; but we |
| 141 | * fake'em. Each RC can connect a max of devices at the same time |
| 142 | * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's |
| 143 | * caps), referred to in wusbhc->ports_max. |
| 144 | * |
| 145 | * See rh.c for more information. |
| 146 | * |
| 147 | * The @status and @change use the same bits as in USB2.0[11.24.2.7], |
| 148 | * so we don't have to do much when getting the port's status. |
| 149 | * |
| 150 | * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10], |
| 151 | * include/linux/usb_ch9.h (#define USB_PORT_STAT_*) |
| 152 | */ |
| 153 | struct wusb_port { |
| 154 | u16 status; |
| 155 | u16 change; |
| 156 | struct wusb_dev *wusb_dev; /* connected device's info */ |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 157 | u32 ptk_tkid; |
| 158 | }; |
| 159 | |
| 160 | /** |
| 161 | * WUSB Host Controller specifics |
| 162 | * |
| 163 | * All fields that are common to all Wireless USB controller types |
| 164 | * (HWA and WHCI) are grouped here. Host Controller |
| 165 | * functions/operations that only deal with general Wireless USB HC |
| 166 | * issues use this data type to refer to the host. |
| 167 | * |
| 168 | * @usb_hcd Instantiation of a USB host controller |
| 169 | * (initialized by upper layer [HWA=HC or WHCI]. |
| 170 | * |
| 171 | * @dev Device that implements this; initialized by the |
| 172 | * upper layer (HWA-HC, WHCI...); this device should |
| 173 | * have a refcount. |
| 174 | * |
| 175 | * @trust_timeout After this time without hearing for device |
| 176 | * activity, we consider the device gone and we have to |
| 177 | * re-authenticate. |
| 178 | * |
| 179 | * Can be accessed w/o locking--however, read to a |
| 180 | * local variable then use. |
| 181 | * |
| 182 | * @chid WUSB Cluster Host ID: this is supposed to be a |
| 183 | * unique value that doesn't change across reboots (so |
| 184 | * that your devices do not require re-association). |
| 185 | * |
| 186 | * Read/Write protected by @mutex |
| 187 | * |
| 188 | * @dev_info This array has ports_max elements. It is used to |
| 189 | * give the HC information about the WUSB devices (see |
| 190 | * 'struct wusb_dev_info'). |
| 191 | * |
| 192 | * For HWA we need to allocate it in heap; for WHCI it |
| 193 | * needs to be permanently mapped, so we keep it for |
| 194 | * both and make it easy. Call wusbhc->dev_info_set() |
| 195 | * to update an entry. |
| 196 | * |
| 197 | * @ports_max Number of simultaneous device connections (fake |
| 198 | * ports) this HC will take. Read-only. |
| 199 | * |
| 200 | * @port Array of port status for each fake root port. Guaranteed to |
| 201 | * always be the same lenght during device existence |
| 202 | * [this allows for some unlocked but referenced reading]. |
| 203 | * |
| 204 | * @mmcies_max Max number of Information Elements this HC can send |
| 205 | * in its MMC. Read-only. |
| 206 | * |
David Vrabel | 4d2bea4 | 2008-10-27 15:42:31 +0000 | [diff] [blame] | 207 | * @start Start the WUSB channel. |
| 208 | * |
| 209 | * @stop Stop the WUSB channel after the specified number of |
| 210 | * milliseconds. Channel Stop IEs should be transmitted |
| 211 | * as required by [WUSB] 4.16.2.1. |
| 212 | * |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 213 | * @mmcie_add HC specific operation (WHCI or HWA) for adding an |
| 214 | * MMCIE. |
| 215 | * |
| 216 | * @mmcie_rm HC specific operation (WHCI or HWA) for removing an |
| 217 | * MMCIE. |
| 218 | * |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 219 | * @set_ptk: Set the PTK and enable encryption for a device. Or, if |
| 220 | * the supplied key is NULL, disable encryption for that |
| 221 | * device. |
| 222 | * |
| 223 | * @set_gtk: Set the GTK to be used for all future broadcast packets |
| 224 | * (i.e., MMCs). With some hardware, setting the GTK may start |
| 225 | * MMC transmission. |
| 226 | * |
| 227 | * NOTE: |
| 228 | * |
| 229 | * - If wusb_dev->usb_dev is not NULL, then usb_dev is valid |
| 230 | * (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev |
| 231 | * is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a |
| 232 | * refcount on it). |
| 233 | * |
| 234 | * Most of the times when you need to use it, it will be non-NULL, |
| 235 | * so there is no real need to check for it (wusb_dev will |
| 236 | * dissapear before usb_dev). |
| 237 | * |
| 238 | * - The following fields need to be filled out before calling |
| 239 | * wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}. |
| 240 | * |
| 241 | * - there is no wusbhc_init() method, we do everything in |
| 242 | * wusbhc_create(). |
| 243 | * |
| 244 | * - Creation is done in two phases, wusbhc_create() and |
| 245 | * wusbhc_create_b(); b are the parts that need to be called after |
| 246 | * calling usb_hcd_add(&wusbhc->usb_hcd). |
| 247 | */ |
| 248 | struct wusbhc { |
| 249 | struct usb_hcd usb_hcd; /* HAS TO BE 1st */ |
| 250 | struct device *dev; |
| 251 | struct uwb_rc *uwb_rc; |
| 252 | struct uwb_pal pal; |
| 253 | |
| 254 | unsigned trust_timeout; /* in jiffies */ |
David Vrabel | 6fae35f | 2008-11-17 15:53:42 +0000 | [diff] [blame] | 255 | struct wusb_ckhdid chid; |
| 256 | struct wuie_host_info *wuie_host_info; |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 257 | |
| 258 | struct mutex mutex; /* locks everything else */ |
| 259 | u16 cluster_id; /* Wireless USB Cluster ID */ |
| 260 | struct wusb_port *port; /* Fake port status handling */ |
| 261 | struct wusb_dev_info *dev_info; /* for Set Device Info mgmt */ |
| 262 | u8 ports_max; |
| 263 | unsigned active:1; /* currently xmit'ing MMCs */ |
| 264 | struct wuie_keep_alive keep_alive_ie; /* protected by mutex */ |
| 265 | struct delayed_work keep_alive_timer; |
| 266 | struct list_head cack_list; /* Connect acknowledging */ |
| 267 | size_t cack_count; /* protected by 'mutex' */ |
| 268 | struct wuie_connect_ack cack_ie; |
| 269 | struct uwb_rsv *rsv; /* cluster bandwidth reservation */ |
| 270 | |
| 271 | struct mutex mmcie_mutex; /* MMC WUIE handling */ |
| 272 | struct wuie_hdr **mmcie; /* WUIE array */ |
| 273 | u8 mmcies_max; |
| 274 | /* FIXME: make wusbhc_ops? */ |
| 275 | int (*start)(struct wusbhc *wusbhc); |
David Vrabel | 4d2bea4 | 2008-10-27 15:42:31 +0000 | [diff] [blame] | 276 | void (*stop)(struct wusbhc *wusbhc, int delay); |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 277 | int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, |
| 278 | u8 handle, struct wuie_hdr *wuie); |
| 279 | int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle); |
| 280 | int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev); |
| 281 | int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index, |
| 282 | const struct uwb_mas_bm *); |
| 283 | int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx, |
| 284 | u32 tkid, const void *key, size_t key_size); |
| 285 | int (*set_gtk)(struct wusbhc *wusbhc, |
| 286 | u32 tkid, const void *key, size_t key_size); |
| 287 | int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots); |
| 288 | |
| 289 | struct { |
| 290 | struct usb_key_descriptor descr; |
| 291 | u8 data[16]; /* GTK key data */ |
| 292 | } __attribute__((packed)) gtk; |
| 293 | u8 gtk_index; |
| 294 | u32 gtk_tkid; |
| 295 | struct work_struct gtk_rekey_done_work; |
| 296 | int pending_set_gtks; |
| 297 | |
| 298 | struct usb_encryption_descriptor *ccm1_etd; |
| 299 | }; |
| 300 | |
| 301 | #define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd) |
| 302 | |
| 303 | |
| 304 | extern int wusbhc_create(struct wusbhc *); |
| 305 | extern int wusbhc_b_create(struct wusbhc *); |
| 306 | extern void wusbhc_b_destroy(struct wusbhc *); |
| 307 | extern void wusbhc_destroy(struct wusbhc *); |
| 308 | extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *, |
| 309 | struct wusb_dev *); |
| 310 | extern void wusb_dev_sysfs_rm(struct wusb_dev *); |
| 311 | extern int wusbhc_sec_create(struct wusbhc *); |
| 312 | extern int wusbhc_sec_start(struct wusbhc *); |
| 313 | extern void wusbhc_sec_stop(struct wusbhc *); |
| 314 | extern void wusbhc_sec_destroy(struct wusbhc *); |
| 315 | extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, |
| 316 | int status); |
| 317 | void wusbhc_reset_all(struct wusbhc *wusbhc); |
| 318 | |
| 319 | int wusbhc_pal_register(struct wusbhc *wusbhc); |
| 320 | void wusbhc_pal_unregister(struct wusbhc *wusbhc); |
| 321 | |
| 322 | /* |
| 323 | * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone |
| 324 | * |
| 325 | * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr) |
| 326 | * |
| 327 | * This is a safe assumption as @usb_dev->bus is referenced all the |
| 328 | * time during the @usb_dev life cycle. |
| 329 | */ |
| 330 | static inline struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev) |
| 331 | { |
| 332 | struct usb_hcd *usb_hcd; |
| 333 | usb_hcd = container_of(usb_dev->bus, struct usb_hcd, self); |
| 334 | return usb_get_hcd(usb_hcd); |
| 335 | } |
| 336 | |
| 337 | /* |
| 338 | * Increment the reference count on a wusbhc. |
| 339 | * |
| 340 | * @wusbhc's life cycle is identical to that of the underlying usb_hcd. |
| 341 | */ |
| 342 | static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc) |
| 343 | { |
| 344 | return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL; |
| 345 | } |
| 346 | |
| 347 | /* |
| 348 | * Return the wusbhc associated to a @usb_dev |
| 349 | * |
| 350 | * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr) |
| 351 | * |
| 352 | * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down. |
| 353 | * WARNING: referenced at the usb_hcd level, unlocked |
| 354 | * |
| 355 | * FIXME: move offline |
| 356 | */ |
| 357 | static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev) |
| 358 | { |
| 359 | struct wusbhc *wusbhc = NULL; |
| 360 | struct usb_hcd *usb_hcd; |
| 361 | if (usb_dev->devnum > 1 && !usb_dev->wusb) { |
| 362 | /* but root hubs */ |
| 363 | dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum, |
| 364 | usb_dev->wusb); |
| 365 | BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb); |
| 366 | } |
| 367 | usb_hcd = usb_hcd_get_by_usb_dev(usb_dev); |
| 368 | if (usb_hcd == NULL) |
| 369 | return NULL; |
| 370 | BUG_ON(usb_hcd->wireless == 0); |
| 371 | return wusbhc = usb_hcd_to_wusbhc(usb_hcd); |
| 372 | } |
| 373 | |
| 374 | |
| 375 | static inline void wusbhc_put(struct wusbhc *wusbhc) |
| 376 | { |
| 377 | usb_put_hcd(&wusbhc->usb_hcd); |
| 378 | } |
| 379 | |
David Vrabel | 6fae35f | 2008-11-17 15:53:42 +0000 | [diff] [blame] | 380 | int wusbhc_start(struct wusbhc *wusbhc); |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 381 | void wusbhc_stop(struct wusbhc *wusbhc); |
| 382 | extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *); |
| 383 | |
| 384 | /* Device connect handling */ |
| 385 | extern int wusbhc_devconnect_create(struct wusbhc *); |
| 386 | extern void wusbhc_devconnect_destroy(struct wusbhc *); |
David Vrabel | 6fae35f | 2008-11-17 15:53:42 +0000 | [diff] [blame] | 387 | extern int wusbhc_devconnect_start(struct wusbhc *wusbhc); |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 388 | extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc); |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 389 | extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr, |
| 390 | struct wusb_dn_hdr *dn_hdr, size_t size); |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 391 | extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port); |
| 392 | extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val, |
| 393 | void *priv); |
| 394 | extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, |
| 395 | u8 addr); |
| 396 | |
| 397 | /* Wireless USB fake Root Hub methods */ |
| 398 | extern int wusbhc_rh_create(struct wusbhc *); |
| 399 | extern void wusbhc_rh_destroy(struct wusbhc *); |
| 400 | |
| 401 | extern int wusbhc_rh_status_data(struct usb_hcd *, char *); |
| 402 | extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16); |
| 403 | extern int wusbhc_rh_suspend(struct usb_hcd *); |
| 404 | extern int wusbhc_rh_resume(struct usb_hcd *); |
| 405 | extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned); |
| 406 | |
| 407 | /* MMC handling */ |
| 408 | extern int wusbhc_mmcie_create(struct wusbhc *); |
| 409 | extern void wusbhc_mmcie_destroy(struct wusbhc *); |
| 410 | extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt, |
| 411 | struct wuie_hdr *); |
| 412 | extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *); |
| 413 | |
| 414 | /* Bandwidth reservation */ |
| 415 | int wusbhc_rsv_establish(struct wusbhc *wusbhc); |
| 416 | void wusbhc_rsv_terminate(struct wusbhc *wusbhc); |
| 417 | |
| 418 | /* |
| 419 | * I've always said |
| 420 | * I wanted a wedding in a church... |
| 421 | * |
| 422 | * but lately I've been thinking about |
| 423 | * the Botanical Gardens. |
| 424 | * |
| 425 | * We could do it by the tulips. |
| 426 | * It'll be beautiful |
| 427 | * |
| 428 | * --Security! |
| 429 | */ |
| 430 | extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *, |
| 431 | struct wusb_dev *); |
| 432 | extern void wusb_dev_sec_rm(struct wusb_dev *) ; |
| 433 | extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *, |
| 434 | struct wusb_ckhdid *ck); |
| 435 | void wusbhc_gtk_rekey(struct wusbhc *wusbhc); |
David Vrabel | 4656d5d | 2008-10-27 17:12:33 +0000 | [diff] [blame] | 436 | int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev); |
Inaky Perez-Gonzalez | 90ff96f | 2008-09-17 16:34:23 +0100 | [diff] [blame] | 437 | |
| 438 | |
| 439 | /* WUSB Cluster ID handling */ |
| 440 | extern u8 wusb_cluster_id_get(void); |
| 441 | extern void wusb_cluster_id_put(u8); |
| 442 | |
| 443 | /* |
| 444 | * wusb_port_by_idx - return the port associated to a zero-based port index |
| 445 | * |
| 446 | * NOTE: valid without locking as long as wusbhc is referenced (as the |
| 447 | * number of ports doesn't change). The data pointed to has to |
| 448 | * be verified though :) |
| 449 | */ |
| 450 | static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc, |
| 451 | u8 port_idx) |
| 452 | { |
| 453 | return &wusbhc->port[port_idx]; |
| 454 | } |
| 455 | |
| 456 | /* |
| 457 | * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to |
| 458 | * a port_idx. |
| 459 | * |
| 460 | * USB stack USB ports are 1 based!! |
| 461 | * |
| 462 | * NOTE: only valid for WUSB devices!!! |
| 463 | */ |
| 464 | static inline u8 wusb_port_no_to_idx(u8 port_no) |
| 465 | { |
| 466 | return port_no - 1; |
| 467 | } |
| 468 | |
| 469 | extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *, |
| 470 | struct usb_device *); |
| 471 | |
| 472 | /* |
| 473 | * Return a referenced wusb_dev given a @usb_dev |
| 474 | * |
| 475 | * Returns NULL if the usb_dev is being torn down. |
| 476 | * |
| 477 | * FIXME: move offline |
| 478 | */ |
| 479 | static inline |
| 480 | struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev) |
| 481 | { |
| 482 | struct wusbhc *wusbhc; |
| 483 | struct wusb_dev *wusb_dev; |
| 484 | wusbhc = wusbhc_get_by_usb_dev(usb_dev); |
| 485 | if (wusbhc == NULL) |
| 486 | return NULL; |
| 487 | mutex_lock(&wusbhc->mutex); |
| 488 | wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev); |
| 489 | mutex_unlock(&wusbhc->mutex); |
| 490 | wusbhc_put(wusbhc); |
| 491 | return wusb_dev; |
| 492 | } |
| 493 | |
| 494 | /* Misc */ |
| 495 | |
| 496 | extern struct workqueue_struct *wusbd; |
| 497 | #endif /* #ifndef __WUSBHC_H__ */ |