2 * Wireless Host Controller (WHC) WUSB operations.
4 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <linux/kernel.h>
19 #include <linux/uwb/umc.h>
21 #include "../../wusbcore/wusbhc.h"
25 static int whc_update_di(struct whc
*whc
, int idx
)
27 int offset
= idx
/ 32;
28 u32 bit
= 1 << (idx
% 32);
30 le_writel(bit
, whc
->base
+ WUSBDIBUPDATED
+ offset
);
32 return whci_wait_for(&whc
->umc
->dev
,
33 whc
->base
+ WUSBDIBUPDATED
+ offset
, bit
, 0,
38 * WHCI starts MMCs based on there being a valid GTK so these need
39 * only start/stop the asynchronous and periodic schedules and send a
40 * channel stop command.
43 int whc_wusbhc_start(struct wusbhc
*wusbhc
)
45 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
53 void whc_wusbhc_stop(struct wusbhc
*wusbhc
, int delay
)
55 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
56 u32 stop_time
, now_time
;
62 now_time
= le_readl(whc
->base
+ WUSBTIME
) & WUSBTIME_CHANNEL_TIME_MASK
;
63 stop_time
= (now_time
+ ((delay
* 8) << 7)) & 0x00ffffff;
64 ret
= whc_do_gencmd(whc
, WUSBGENCMDSTS_CHAN_STOP
, stop_time
, NULL
, 0);
69 int whc_mmcie_add(struct wusbhc
*wusbhc
, u8 interval
, u8 repeat_cnt
,
70 u8 handle
, struct wuie_hdr
*wuie
)
72 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
75 params
= (interval
<< 24)
77 | (wuie
->bLength
<< 8)
80 return whc_do_gencmd(whc
, WUSBGENCMDSTS_MMCIE_ADD
, params
, wuie
, wuie
->bLength
);
83 int whc_mmcie_rm(struct wusbhc
*wusbhc
, u8 handle
)
85 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
90 return whc_do_gencmd(whc
, WUSBGENCMDSTS_MMCIE_RM
, params
, NULL
, 0);
93 int whc_bwa_set(struct wusbhc
*wusbhc
, s8 stream_index
, const struct uwb_mas_bm
*mas_bm
)
95 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
97 if (stream_index
>= 0)
98 whc_write_wusbcmd(whc
, WUSBCMD_WUSBSI_MASK
, WUSBCMD_WUSBSI(stream_index
));
100 return whc_do_gencmd(whc
, WUSBGENCMDSTS_SET_MAS
, 0, (void *)mas_bm
, sizeof(*mas_bm
));
103 int whc_dev_info_set(struct wusbhc
*wusbhc
, struct wusb_dev
*wusb_dev
)
105 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
106 int idx
= wusb_dev
->port_idx
;
107 struct di_buf_entry
*di
= &whc
->di_buf
[idx
];
110 mutex_lock(&whc
->mutex
);
112 uwb_mas_bm_copy_le(di
->availability_info
, &wusb_dev
->availability
);
113 di
->addr_sec_info
&= ~(WHC_DI_DISABLE
| WHC_DI_DEV_ADDR_MASK
);
114 di
->addr_sec_info
|= WHC_DI_DEV_ADDR(wusb_dev
->addr
);
116 ret
= whc_update_di(whc
, idx
);
118 mutex_unlock(&whc
->mutex
);
124 * Set the number of Device Notification Time Slots (DNTS) and enable
125 * device notifications.
127 int whc_set_num_dnts(struct wusbhc
*wusbhc
, u8 interval
, u8 slots
)
129 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
132 dntsctrl
= WUSBDNTSCTRL_ACTIVE
133 | WUSBDNTSCTRL_INTERVAL(interval
)
134 | WUSBDNTSCTRL_SLOTS(slots
);
136 le_writel(dntsctrl
, whc
->base
+ WUSBDNTSCTRL
);
141 static int whc_set_key(struct whc
*whc
, u8 key_index
, uint32_t tkid
,
142 const void *key
, size_t key_size
, bool is_gtk
)
149 memcpy(seckey
, key
, key_size
);
150 setkeycmd
= WUSBSETSECKEYCMD_SET
| WUSBSETSECKEYCMD_IDX(key_index
);
152 setkeycmd
|= WUSBSETSECKEYCMD_GTK
;
154 le_writel(tkid
, whc
->base
+ WUSBTKID
);
155 for (i
= 0; i
< 4; i
++)
156 le_writel(seckey
[i
], whc
->base
+ WUSBSECKEY
+ 4*i
);
157 le_writel(setkeycmd
, whc
->base
+ WUSBSETSECKEYCMD
);
159 ret
= whci_wait_for(&whc
->umc
->dev
, whc
->base
+ WUSBSETSECKEYCMD
,
160 WUSBSETSECKEYCMD_SET
, 0, 100, "set key");
166 * whc_set_ptk - set the PTK to use for a device.
168 * The index into the key table for this PTK is the same as the
169 * device's port index.
171 int whc_set_ptk(struct wusbhc
*wusbhc
, u8 port_idx
, u32 tkid
,
172 const void *ptk
, size_t key_size
)
174 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
175 struct di_buf_entry
*di
= &whc
->di_buf
[port_idx
];
178 mutex_lock(&whc
->mutex
);
181 ret
= whc_set_key(whc
, port_idx
, tkid
, ptk
, key_size
, false);
185 di
->addr_sec_info
&= ~WHC_DI_KEY_IDX_MASK
;
186 di
->addr_sec_info
|= WHC_DI_SECURE
| WHC_DI_KEY_IDX(port_idx
);
188 di
->addr_sec_info
&= ~WHC_DI_SECURE
;
190 ret
= whc_update_di(whc
, port_idx
);
192 mutex_unlock(&whc
->mutex
);
197 * whc_set_gtk - set the GTK for subsequent broadcast packets
199 * The GTK is stored in the last entry in the key table (the previous
200 * N_DEVICES entries are for the per-device PTKs).
202 int whc_set_gtk(struct wusbhc
*wusbhc
, u32 tkid
,
203 const void *gtk
, size_t key_size
)
205 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
208 mutex_lock(&whc
->mutex
);
210 ret
= whc_set_key(whc
, whc
->n_devices
, tkid
, gtk
, key_size
, true);
212 mutex_unlock(&whc
->mutex
);
217 int whc_set_cluster_id(struct whc
*whc
, u8 bcid
)
219 whc_write_wusbcmd(whc
, WUSBCMD_BCID_MASK
, WUSBCMD_BCID(bcid
));