2 * Wireless USB - Cable Based Association
5 * Copyright (C) 2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
7 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
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.
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.
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
24 * WUSB devices have to be paired (associated in WUSB lingo) so
25 * that they can connect to the system.
27 * One way of pairing is using CBA-Cable Based Association. First
28 * time you plug the device with a cable, association is done between
29 * host and device and subsequent times, you can connect wirelessly
30 * without having to associate again. That's the idea.
32 * This driver does nothing Earth shattering. It just provides an
33 * interface to chat with the wire-connected device so we can get a
34 * CDID (device ID) that might have been previously associated to a
35 * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet
36 * (connection context), with the CK being the secret, or connection
37 * key. This is the pairing data.
39 * When a device with the CBA capability connects, the probe routine
40 * just creates a bunch of sysfs files that a user space enumeration
41 * manager uses to allow it to connect wirelessly to the system or not.
43 * The process goes like this:
45 * 1. Device plugs, cbaf is loaded, notifications happen.
47 * 2. The connection manager (CM) sees a device with CBAF capability
48 * (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE).
50 * 3. The CM writes the host name, supported band groups, and the CHID
51 * (host ID) into the wusb_host_name, wusb_host_band_groups and
52 * wusb_chid files. These get sent to the device and the CDID (if
53 * any) for this host is requested.
55 * 4. The CM can verify that the device's supported band groups
56 * (wusb_device_band_groups) are compatible with the host.
58 * 5. The CM reads the wusb_cdid file.
60 * 6. The CM looks up its database
62 * 6.1 If it has a matching CHID,CDID entry, the device has been
63 * authorized before (paired) and nothing further needs to be
66 * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in
67 * its database), the device is assumed to be not known. The CM
68 * may associate the host with device by: writing a randomly
69 * generated CDID to wusb_cdid and then a random CK to wusb_ck
70 * (this uploads the new CC to the device).
72 * CMD may choose to prompt the user before associating with a new
75 * 7. Device is unplugged.
77 * When the device tries to connect wirelessly, it will present its
78 * CDID to the WUSB host controller. The CM will query the
79 * database. If the CHID/CDID pair found, it will (with a 4-way
80 * handshake) challenge the device to demonstrate it has the CK secret
81 * key (from our database) without actually exchanging it. Once
82 * satisfied, crypto keys are derived from the CK, the device is
83 * connected and all communication is encrypted.
86 * [WUSB-AM] Association Models Supplement to the Certified Wireless
87 * Universal Serial Bus Specification, version 1.0.
89 #include <linux/module.h>
90 #include <linux/ctype.h>
91 #include <linux/usb.h>
92 #include <linux/interrupt.h>
93 #include <linux/delay.h>
94 #include <linux/random.h>
95 #include <linux/slab.h>
96 #include <linux/mutex.h>
97 #include <linux/uwb.h>
98 #include <linux/usb/wusb.h>
99 #include <linux/usb/association.h>
101 #define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */
103 /* An instance of a Cable-Based-Association-Framework device */
105 struct usb_device
*usb_dev
;
106 struct usb_interface
*usb_iface
;
110 struct wusb_ckhdid chid
;
111 char host_name
[CBA_NAME_LEN
];
112 u16 host_band_groups
;
114 struct wusb_ckhdid cdid
;
115 char device_name
[CBA_NAME_LEN
];
116 u16 device_band_groups
;
118 struct wusb_ckhdid ck
;
122 * Verify that a CBAF USB-interface has what we need
124 * According to [WUSB-AM], CBA devices should provide at least two
126 * - RETRIEVE_HOST_INFO
129 * If the device doesn't provide these interfaces, we do not know how
132 static int cbaf_check(struct cbaf
*cbaf
)
135 struct device
*dev
= &cbaf
->usb_iface
->dev
;
136 struct wusb_cbaf_assoc_info
*assoc_info
;
137 struct wusb_cbaf_assoc_request
*assoc_request
;
140 int ar_rhi
= 0, ar_assoc
= 0;
142 result
= usb_control_msg(
143 cbaf
->usb_dev
, usb_rcvctrlpipe(cbaf
->usb_dev
, 0),
144 CBAF_REQ_GET_ASSOCIATION_INFORMATION
,
145 USB_DIR_IN
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
,
146 0, cbaf
->usb_iface
->cur_altsetting
->desc
.bInterfaceNumber
,
147 cbaf
->buffer
, cbaf
->buffer_size
, USB_CTRL_GET_TIMEOUT
);
149 dev_err(dev
, "Cannot get available association types: %d\n",
154 assoc_info
= cbaf
->buffer
;
155 if (result
< sizeof(*assoc_info
)) {
156 dev_err(dev
, "Not enough data to decode association info "
157 "header (%zu vs %zu bytes required)\n",
158 (size_t)result
, sizeof(*assoc_info
));
162 assoc_size
= le16_to_cpu(assoc_info
->Length
);
163 if (result
< assoc_size
) {
164 dev_err(dev
, "Not enough data to decode association info "
165 "(%zu vs %zu bytes required)\n",
166 (size_t)assoc_size
, sizeof(*assoc_info
));
170 * From now on, we just verify, but won't error out unless we
171 * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE}
174 itr
= cbaf
->buffer
+ sizeof(*assoc_info
);
175 top
= cbaf
->buffer
+ assoc_size
;
176 dev_dbg(dev
, "Found %u association requests (%zu bytes)\n",
177 assoc_info
->NumAssociationRequests
, assoc_size
);
180 u16 ar_type
, ar_subtype
;
186 if (top
- itr
< sizeof(*assoc_request
)) {
187 dev_err(dev
, "Not enough data to decode association "
188 "request (%zu vs %zu bytes needed)\n",
189 top
- itr
, sizeof(*assoc_request
));
193 ar_type
= le16_to_cpu(assoc_request
->AssociationTypeId
);
194 ar_subtype
= le16_to_cpu(assoc_request
->AssociationSubTypeId
);
195 ar_size
= le32_to_cpu(assoc_request
->AssociationTypeInfoSize
);
200 /* Verify we have what is mandated by [WUSB-AM]. */
201 switch (ar_subtype
) {
202 case AR_TYPE_WUSB_RETRIEVE_HOST_INFO
:
203 ar_name
= "RETRIEVE_HOST_INFO";
206 case AR_TYPE_WUSB_ASSOCIATE
:
207 /* send assoc data */
208 ar_name
= "ASSOCIATE";
215 dev_dbg(dev
, "Association request #%02u: 0x%04x/%04x "
217 assoc_request
->AssociationDataIndex
, ar_type
,
218 ar_subtype
, (size_t)ar_size
, ar_name
);
220 itr
+= sizeof(*assoc_request
);
224 dev_err(dev
, "Missing RETRIEVE_HOST_INFO association "
229 dev_err(dev
, "Missing ASSOCIATE association request\n");
236 static const struct wusb_cbaf_host_info cbaf_host_info_defaults
= {
237 .AssociationTypeId_hdr
= WUSB_AR_AssociationTypeId
,
238 .AssociationTypeId
= cpu_to_le16(AR_TYPE_WUSB
),
239 .AssociationSubTypeId_hdr
= WUSB_AR_AssociationSubTypeId
,
240 .AssociationSubTypeId
= cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO
),
241 .CHID_hdr
= WUSB_AR_CHID
,
242 .LangID_hdr
= WUSB_AR_LangID
,
243 .HostFriendlyName_hdr
= WUSB_AR_HostFriendlyName
,
246 /* Send WUSB host information (CHID and name) to a CBAF device */
247 static int cbaf_send_host_info(struct cbaf
*cbaf
)
249 struct wusb_cbaf_host_info
*hi
;
254 memset(hi
, 0, sizeof(*hi
));
255 *hi
= cbaf_host_info_defaults
;
256 hi
->CHID
= cbaf
->chid
;
257 hi
->LangID
= 0; /* FIXME: I guess... */
258 strlcpy(hi
->HostFriendlyName
, cbaf
->host_name
, CBA_NAME_LEN
);
259 name_len
= strlen(cbaf
->host_name
);
260 hi
->HostFriendlyName_hdr
.len
= cpu_to_le16(name_len
);
261 hi_size
= sizeof(*hi
) + name_len
;
263 return usb_control_msg(cbaf
->usb_dev
,
264 usb_sndctrlpipe(cbaf
->usb_dev
, 0),
265 CBAF_REQ_SET_ASSOCIATION_RESPONSE
,
266 USB_DIR_OUT
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
,
268 cbaf
->usb_iface
->cur_altsetting
->desc
.bInterfaceNumber
,
269 hi
, hi_size
, USB_CTRL_SET_TIMEOUT
);
273 * Get device's information (CDID) associated to CHID
275 * The device will return it's information (CDID, name, bandgroups)
276 * associated to the CHID we have set before, or 0 CDID and default
277 * name and bandgroup if no CHID set or unknown.
279 static int cbaf_cdid_get(struct cbaf
*cbaf
)
282 struct device
*dev
= &cbaf
->usb_iface
->dev
;
283 struct wusb_cbaf_device_info
*di
;
287 result
= usb_control_msg(
288 cbaf
->usb_dev
, usb_rcvctrlpipe(cbaf
->usb_dev
, 0),
289 CBAF_REQ_GET_ASSOCIATION_REQUEST
,
290 USB_DIR_IN
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
,
291 0x0200, cbaf
->usb_iface
->cur_altsetting
->desc
.bInterfaceNumber
,
292 di
, cbaf
->buffer_size
, USB_CTRL_GET_TIMEOUT
);
294 dev_err(dev
, "Cannot request device information: %d\n",
299 needed
= result
< sizeof(*di
) ? sizeof(*di
) : le32_to_cpu(di
->Length
);
300 if (result
< needed
) {
301 dev_err(dev
, "Not enough data in DEVICE_INFO reply (%zu vs "
302 "%zu bytes needed)\n", (size_t)result
, needed
);
306 strlcpy(cbaf
->device_name
, di
->DeviceFriendlyName
, CBA_NAME_LEN
);
307 cbaf
->cdid
= di
->CDID
;
308 cbaf
->device_band_groups
= le16_to_cpu(di
->BandGroups
);
313 static ssize_t
cbaf_wusb_chid_show(struct device
*dev
,
314 struct device_attribute
*attr
,
317 struct usb_interface
*iface
= to_usb_interface(dev
);
318 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
319 char pr_chid
[WUSB_CKHDID_STRSIZE
];
321 ckhdid_printf(pr_chid
, sizeof(pr_chid
), &cbaf
->chid
);
322 return scnprintf(buf
, PAGE_SIZE
, "%s\n", pr_chid
);
325 static ssize_t
cbaf_wusb_chid_store(struct device
*dev
,
326 struct device_attribute
*attr
,
327 const char *buf
, size_t size
)
330 struct usb_interface
*iface
= to_usb_interface(dev
);
331 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
334 "%02hhx %02hhx %02hhx %02hhx "
335 "%02hhx %02hhx %02hhx %02hhx "
336 "%02hhx %02hhx %02hhx %02hhx "
337 "%02hhx %02hhx %02hhx %02hhx",
338 &cbaf
->chid
.data
[0] , &cbaf
->chid
.data
[1],
339 &cbaf
->chid
.data
[2] , &cbaf
->chid
.data
[3],
340 &cbaf
->chid
.data
[4] , &cbaf
->chid
.data
[5],
341 &cbaf
->chid
.data
[6] , &cbaf
->chid
.data
[7],
342 &cbaf
->chid
.data
[8] , &cbaf
->chid
.data
[9],
343 &cbaf
->chid
.data
[10], &cbaf
->chid
.data
[11],
344 &cbaf
->chid
.data
[12], &cbaf
->chid
.data
[13],
345 &cbaf
->chid
.data
[14], &cbaf
->chid
.data
[15]);
350 result
= cbaf_send_host_info(cbaf
);
353 result
= cbaf_cdid_get(cbaf
);
358 static DEVICE_ATTR(wusb_chid
, 0600, cbaf_wusb_chid_show
, cbaf_wusb_chid_store
);
360 static ssize_t
cbaf_wusb_host_name_show(struct device
*dev
,
361 struct device_attribute
*attr
,
364 struct usb_interface
*iface
= to_usb_interface(dev
);
365 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
367 return scnprintf(buf
, PAGE_SIZE
, "%s\n", cbaf
->host_name
);
370 static ssize_t
cbaf_wusb_host_name_store(struct device
*dev
,
371 struct device_attribute
*attr
,
372 const char *buf
, size_t size
)
375 struct usb_interface
*iface
= to_usb_interface(dev
);
376 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
378 result
= sscanf(buf
, "%63s", cbaf
->host_name
);
384 static DEVICE_ATTR(wusb_host_name
, 0600, cbaf_wusb_host_name_show
,
385 cbaf_wusb_host_name_store
);
387 static ssize_t
cbaf_wusb_host_band_groups_show(struct device
*dev
,
388 struct device_attribute
*attr
,
391 struct usb_interface
*iface
= to_usb_interface(dev
);
392 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
394 return scnprintf(buf
, PAGE_SIZE
, "0x%04x\n", cbaf
->host_band_groups
);
397 static ssize_t
cbaf_wusb_host_band_groups_store(struct device
*dev
,
398 struct device_attribute
*attr
,
399 const char *buf
, size_t size
)
402 struct usb_interface
*iface
= to_usb_interface(dev
);
403 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
406 result
= sscanf(buf
, "%04hx", &band_groups
);
410 cbaf
->host_band_groups
= band_groups
;
415 static DEVICE_ATTR(wusb_host_band_groups
, 0600,
416 cbaf_wusb_host_band_groups_show
,
417 cbaf_wusb_host_band_groups_store
);
419 static const struct wusb_cbaf_device_info cbaf_device_info_defaults
= {
420 .Length_hdr
= WUSB_AR_Length
,
421 .CDID_hdr
= WUSB_AR_CDID
,
422 .BandGroups_hdr
= WUSB_AR_BandGroups
,
423 .LangID_hdr
= WUSB_AR_LangID
,
424 .DeviceFriendlyName_hdr
= WUSB_AR_DeviceFriendlyName
,
427 static ssize_t
cbaf_wusb_cdid_show(struct device
*dev
,
428 struct device_attribute
*attr
, char *buf
)
430 struct usb_interface
*iface
= to_usb_interface(dev
);
431 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
432 char pr_cdid
[WUSB_CKHDID_STRSIZE
];
434 ckhdid_printf(pr_cdid
, sizeof(pr_cdid
), &cbaf
->cdid
);
435 return scnprintf(buf
, PAGE_SIZE
, "%s\n", pr_cdid
);
438 static ssize_t
cbaf_wusb_cdid_store(struct device
*dev
,
439 struct device_attribute
*attr
,
440 const char *buf
, size_t size
)
443 struct usb_interface
*iface
= to_usb_interface(dev
);
444 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
445 struct wusb_ckhdid cdid
;
448 "%02hhx %02hhx %02hhx %02hhx "
449 "%02hhx %02hhx %02hhx %02hhx "
450 "%02hhx %02hhx %02hhx %02hhx "
451 "%02hhx %02hhx %02hhx %02hhx",
452 &cdid
.data
[0] , &cdid
.data
[1],
453 &cdid
.data
[2] , &cdid
.data
[3],
454 &cdid
.data
[4] , &cdid
.data
[5],
455 &cdid
.data
[6] , &cdid
.data
[7],
456 &cdid
.data
[8] , &cdid
.data
[9],
457 &cdid
.data
[10], &cdid
.data
[11],
458 &cdid
.data
[12], &cdid
.data
[13],
459 &cdid
.data
[14], &cdid
.data
[15]);
467 static DEVICE_ATTR(wusb_cdid
, 0600, cbaf_wusb_cdid_show
, cbaf_wusb_cdid_store
);
469 static ssize_t
cbaf_wusb_device_band_groups_show(struct device
*dev
,
470 struct device_attribute
*attr
,
473 struct usb_interface
*iface
= to_usb_interface(dev
);
474 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
476 return scnprintf(buf
, PAGE_SIZE
, "0x%04x\n", cbaf
->device_band_groups
);
479 static DEVICE_ATTR(wusb_device_band_groups
, 0600,
480 cbaf_wusb_device_band_groups_show
,
483 static ssize_t
cbaf_wusb_device_name_show(struct device
*dev
,
484 struct device_attribute
*attr
,
487 struct usb_interface
*iface
= to_usb_interface(dev
);
488 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
490 return scnprintf(buf
, PAGE_SIZE
, "%s\n", cbaf
->device_name
);
492 static DEVICE_ATTR(wusb_device_name
, 0600, cbaf_wusb_device_name_show
, NULL
);
494 static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults
= {
495 .AssociationTypeId_hdr
= WUSB_AR_AssociationTypeId
,
496 .AssociationTypeId
= cpu_to_le16(AR_TYPE_WUSB
),
497 .AssociationSubTypeId_hdr
= WUSB_AR_AssociationSubTypeId
,
498 .AssociationSubTypeId
= cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE
),
499 .Length_hdr
= WUSB_AR_Length
,
500 .Length
= cpu_to_le32(sizeof(struct wusb_cbaf_cc_data
)),
501 .ConnectionContext_hdr
= WUSB_AR_ConnectionContext
,
502 .BandGroups_hdr
= WUSB_AR_BandGroups
,
505 static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults
= {
506 .AssociationTypeId_hdr
= WUSB_AR_AssociationTypeId
,
507 .AssociationSubTypeId_hdr
= WUSB_AR_AssociationSubTypeId
,
508 .Length_hdr
= WUSB_AR_Length
,
509 .AssociationStatus_hdr
= WUSB_AR_AssociationStatus
,
513 * Send a new CC to the device.
515 static int cbaf_cc_upload(struct cbaf
*cbaf
)
518 struct device
*dev
= &cbaf
->usb_iface
->dev
;
519 struct wusb_cbaf_cc_data
*ccd
;
520 char pr_cdid
[WUSB_CKHDID_STRSIZE
];
523 *ccd
= cbaf_cc_data_defaults
;
524 ccd
->CHID
= cbaf
->chid
;
525 ccd
->CDID
= cbaf
->cdid
;
527 ccd
->BandGroups
= cpu_to_le16(cbaf
->host_band_groups
);
529 dev_dbg(dev
, "Trying to upload CC:\n");
530 ckhdid_printf(pr_cdid
, sizeof(pr_cdid
), &ccd
->CHID
);
531 dev_dbg(dev
, " CHID %s\n", pr_cdid
);
532 ckhdid_printf(pr_cdid
, sizeof(pr_cdid
), &ccd
->CDID
);
533 dev_dbg(dev
, " CDID %s\n", pr_cdid
);
534 dev_dbg(dev
, " Bandgroups 0x%04x\n", cbaf
->host_band_groups
);
536 result
= usb_control_msg(
537 cbaf
->usb_dev
, usb_sndctrlpipe(cbaf
->usb_dev
, 0),
538 CBAF_REQ_SET_ASSOCIATION_RESPONSE
,
539 USB_DIR_OUT
| USB_TYPE_CLASS
| USB_RECIP_INTERFACE
,
540 0x0201, cbaf
->usb_iface
->cur_altsetting
->desc
.bInterfaceNumber
,
541 ccd
, sizeof(*ccd
), USB_CTRL_SET_TIMEOUT
);
546 static ssize_t
cbaf_wusb_ck_store(struct device
*dev
,
547 struct device_attribute
*attr
,
548 const char *buf
, size_t size
)
551 struct usb_interface
*iface
= to_usb_interface(dev
);
552 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
555 "%02hhx %02hhx %02hhx %02hhx "
556 "%02hhx %02hhx %02hhx %02hhx "
557 "%02hhx %02hhx %02hhx %02hhx "
558 "%02hhx %02hhx %02hhx %02hhx",
559 &cbaf
->ck
.data
[0] , &cbaf
->ck
.data
[1],
560 &cbaf
->ck
.data
[2] , &cbaf
->ck
.data
[3],
561 &cbaf
->ck
.data
[4] , &cbaf
->ck
.data
[5],
562 &cbaf
->ck
.data
[6] , &cbaf
->ck
.data
[7],
563 &cbaf
->ck
.data
[8] , &cbaf
->ck
.data
[9],
564 &cbaf
->ck
.data
[10], &cbaf
->ck
.data
[11],
565 &cbaf
->ck
.data
[12], &cbaf
->ck
.data
[13],
566 &cbaf
->ck
.data
[14], &cbaf
->ck
.data
[15]);
570 result
= cbaf_cc_upload(cbaf
);
576 static DEVICE_ATTR(wusb_ck
, 0600, NULL
, cbaf_wusb_ck_store
);
578 static struct attribute
*cbaf_dev_attrs
[] = {
579 &dev_attr_wusb_host_name
.attr
,
580 &dev_attr_wusb_host_band_groups
.attr
,
581 &dev_attr_wusb_chid
.attr
,
582 &dev_attr_wusb_cdid
.attr
,
583 &dev_attr_wusb_device_name
.attr
,
584 &dev_attr_wusb_device_band_groups
.attr
,
585 &dev_attr_wusb_ck
.attr
,
589 static struct attribute_group cbaf_dev_attr_group
= {
590 .name
= NULL
, /* we want them in the same directory */
591 .attrs
= cbaf_dev_attrs
,
594 static int cbaf_probe(struct usb_interface
*iface
,
595 const struct usb_device_id
*id
)
598 struct device
*dev
= &iface
->dev
;
599 int result
= -ENOMEM
;
601 cbaf
= kzalloc(sizeof(*cbaf
), GFP_KERNEL
);
604 cbaf
->buffer
= kmalloc(512, GFP_KERNEL
);
605 if (cbaf
->buffer
== NULL
)
606 goto error_kmalloc_buffer
;
608 cbaf
->buffer_size
= 512;
609 cbaf
->usb_dev
= usb_get_dev(interface_to_usbdev(iface
));
610 cbaf
->usb_iface
= usb_get_intf(iface
);
611 result
= cbaf_check(cbaf
);
613 dev_err(dev
, "This device is not WUSB-CBAF compliant"
614 "and is not supported yet.\n");
618 result
= sysfs_create_group(&dev
->kobj
, &cbaf_dev_attr_group
);
620 dev_err(dev
, "Can't register sysfs attr group: %d\n", result
);
621 goto error_create_group
;
623 usb_set_intfdata(iface
, cbaf
);
629 usb_put_dev(cbaf
->usb_dev
);
631 error_kmalloc_buffer
:
637 static void cbaf_disconnect(struct usb_interface
*iface
)
639 struct cbaf
*cbaf
= usb_get_intfdata(iface
);
640 struct device
*dev
= &iface
->dev
;
641 sysfs_remove_group(&dev
->kobj
, &cbaf_dev_attr_group
);
642 usb_set_intfdata(iface
, NULL
);
644 usb_put_dev(cbaf
->usb_dev
);
646 /* paranoia: clean up crypto keys */
650 static const struct usb_device_id cbaf_id_table
[] = {
651 { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
654 MODULE_DEVICE_TABLE(usb
, cbaf_id_table
);
656 static struct usb_driver cbaf_driver
= {
658 .id_table
= cbaf_id_table
,
660 .disconnect
= cbaf_disconnect
,
663 module_usb_driver(cbaf_driver
);
665 MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
666 MODULE_DESCRIPTION("Wireless USB Cable Based Association");
667 MODULE_LICENSE("GPL");