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/init.h>
20 #include <linux/uwb/umc.h>
22 #include "../../wusbcore/wusbhc.h"
26 static int whc_update_di(struct whc
*whc
, int idx
)
28 int offset
= idx
/ 32;
29 u32 bit
= 1 << (idx
% 32);
31 le_writel(bit
, whc
->base
+ WUSBDIBUPDATED
+ offset
);
33 return whci_wait_for(&whc
->umc
->dev
,
34 whc
->base
+ WUSBDIBUPDATED
+ offset
, bit
, 0,
39 * WHCI starts MMCs based on there being a valid GTK so these need
40 * only start/stop the asynchronous and periodic schedules and send a
41 * channel stop command.
44 int whc_wusbhc_start(struct wusbhc
*wusbhc
)
46 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
54 void whc_wusbhc_stop(struct wusbhc
*wusbhc
, int delay
)
56 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
57 u32 stop_time
, now_time
;
63 now_time
= le_readl(whc
->base
+ WUSBTIME
) & WUSBTIME_CHANNEL_TIME_MASK
;
64 stop_time
= (now_time
+ ((delay
* 8) << 7)) & 0x00ffffff;
65 ret
= whc_do_gencmd(whc
, WUSBGENCMDSTS_CHAN_STOP
, stop_time
, NULL
, 0);
70 int whc_mmcie_add(struct wusbhc
*wusbhc
, u8 interval
, u8 repeat_cnt
,
71 u8 handle
, struct wuie_hdr
*wuie
)
73 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
76 params
= (interval
<< 24)
78 | (wuie
->bLength
<< 8)
81 return whc_do_gencmd(whc
, WUSBGENCMDSTS_MMCIE_ADD
, params
, wuie
, wuie
->bLength
);
84 int whc_mmcie_rm(struct wusbhc
*wusbhc
, u8 handle
)
86 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
91 return whc_do_gencmd(whc
, WUSBGENCMDSTS_MMCIE_RM
, params
, NULL
, 0);
94 int whc_bwa_set(struct wusbhc
*wusbhc
, s8 stream_index
, const struct uwb_mas_bm
*mas_bm
)
96 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
98 if (stream_index
>= 0)
99 whc_write_wusbcmd(whc
, WUSBCMD_WUSBSI_MASK
, WUSBCMD_WUSBSI(stream_index
));
101 return whc_do_gencmd(whc
, WUSBGENCMDSTS_SET_MAS
, 0, (void *)mas_bm
, sizeof(*mas_bm
));
104 int whc_dev_info_set(struct wusbhc
*wusbhc
, struct wusb_dev
*wusb_dev
)
106 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
107 int idx
= wusb_dev
->port_idx
;
108 struct di_buf_entry
*di
= &whc
->di_buf
[idx
];
111 mutex_lock(&whc
->mutex
);
113 uwb_mas_bm_copy_le(di
->availability_info
, &wusb_dev
->availability
);
114 di
->addr_sec_info
&= ~(WHC_DI_DISABLE
| WHC_DI_DEV_ADDR_MASK
);
115 di
->addr_sec_info
|= WHC_DI_DEV_ADDR(wusb_dev
->addr
);
117 ret
= whc_update_di(whc
, idx
);
119 mutex_unlock(&whc
->mutex
);
125 * Set the number of Device Notification Time Slots (DNTS) and enable
126 * device notifications.
128 int whc_set_num_dnts(struct wusbhc
*wusbhc
, u8 interval
, u8 slots
)
130 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
133 dntsctrl
= WUSBDNTSCTRL_ACTIVE
134 | WUSBDNTSCTRL_INTERVAL(interval
)
135 | WUSBDNTSCTRL_SLOTS(slots
);
137 le_writel(dntsctrl
, whc
->base
+ WUSBDNTSCTRL
);
142 static int whc_set_key(struct whc
*whc
, u8 key_index
, uint32_t tkid
,
143 const void *key
, size_t key_size
, bool is_gtk
)
150 memcpy(seckey
, key
, key_size
);
151 setkeycmd
= WUSBSETSECKEYCMD_SET
| WUSBSETSECKEYCMD_IDX(key_index
);
153 setkeycmd
|= WUSBSETSECKEYCMD_GTK
;
155 le_writel(tkid
, whc
->base
+ WUSBTKID
);
156 for (i
= 0; i
< 4; i
++)
157 le_writel(seckey
[i
], whc
->base
+ WUSBSECKEY
+ 4*i
);
158 le_writel(setkeycmd
, whc
->base
+ WUSBSETSECKEYCMD
);
160 ret
= whci_wait_for(&whc
->umc
->dev
, whc
->base
+ WUSBSETSECKEYCMD
,
161 WUSBSETSECKEYCMD_SET
, 0, 100, "set key");
167 * whc_set_ptk - set the PTK to use for a device.
169 * The index into the key table for this PTK is the same as the
170 * device's port index.
172 int whc_set_ptk(struct wusbhc
*wusbhc
, u8 port_idx
, u32 tkid
,
173 const void *ptk
, size_t key_size
)
175 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
176 struct di_buf_entry
*di
= &whc
->di_buf
[port_idx
];
179 mutex_lock(&whc
->mutex
);
182 ret
= whc_set_key(whc
, port_idx
, tkid
, ptk
, key_size
, false);
186 di
->addr_sec_info
&= ~WHC_DI_KEY_IDX_MASK
;
187 di
->addr_sec_info
|= WHC_DI_SECURE
| WHC_DI_KEY_IDX(port_idx
);
189 di
->addr_sec_info
&= ~WHC_DI_SECURE
;
191 ret
= whc_update_di(whc
, port_idx
);
193 mutex_unlock(&whc
->mutex
);
198 * whc_set_gtk - set the GTK for subsequent broadcast packets
200 * The GTK is stored in the last entry in the key table (the previous
201 * N_DEVICES entries are for the per-device PTKs).
203 int whc_set_gtk(struct wusbhc
*wusbhc
, u32 tkid
,
204 const void *gtk
, size_t key_size
)
206 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
209 mutex_lock(&whc
->mutex
);
211 ret
= whc_set_key(whc
, whc
->n_devices
, tkid
, gtk
, key_size
, true);
213 mutex_unlock(&whc
->mutex
);
218 int whc_set_cluster_id(struct whc
*whc
, u8 bcid
)
220 whc_write_wusbcmd(whc
, WUSBCMD_BCID_MASK
, WUSBCMD_BCID(bcid
));