Commit | Line | Data |
---|---|---|
66101de1 PM |
1 | /* |
2 | * Copyright 2008 Pavel Machek <pavel@suse.cz> | |
3 | * | |
4 | * Distribute under GPLv2. | |
5 | */ | |
6 | #include "sysdef.h" | |
7 | #include <net/mac80211.h> | |
8 | ||
dd38da46 PE |
9 | MODULE_AUTHOR(DRIVER_AUTHOR); |
10 | MODULE_DESCRIPTION(DRIVER_DESC); | |
66101de1 PM |
11 | MODULE_LICENSE("GPL"); |
12 | MODULE_VERSION("0.1"); | |
13 | ||
dd38da46 PE |
14 | static struct usb_device_id wb35_table[] __devinitdata = { |
15 | {USB_DEVICE(0x0416, 0x0035)}, | |
16 | {USB_DEVICE(0x18E8, 0x6201)}, | |
17 | {USB_DEVICE(0x18E8, 0x6206)}, | |
18 | {USB_DEVICE(0x18E8, 0x6217)}, | |
19 | {USB_DEVICE(0x18E8, 0x6230)}, | |
20 | {USB_DEVICE(0x18E8, 0x6233)}, | |
21 | {USB_DEVICE(0x1131, 0x2035)}, | |
68ab0c96 | 22 | { 0, } |
66101de1 PM |
23 | }; |
24 | ||
dd38da46 | 25 | MODULE_DEVICE_TABLE(usb, wb35_table); |
66101de1 | 26 | |
68ab0c96 | 27 | static struct ieee80211_rate wbsoft_rates[] = { |
66101de1 PM |
28 | { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, |
29 | }; | |
30 | ||
68ab0c96 | 31 | static struct ieee80211_channel wbsoft_channels[] = { |
66101de1 PM |
32 | { .center_freq = 2412}, |
33 | }; | |
34 | ||
35 | int wbsoft_enabled; | |
36 | struct ieee80211_hw *my_dev; | |
88ebc4b9 | 37 | struct wb35_adapter * my_adapter; |
66101de1 PM |
38 | |
39 | static int wbsoft_add_interface(struct ieee80211_hw *dev, | |
40 | struct ieee80211_if_init_conf *conf) | |
41 | { | |
42 | printk("wbsoft_add interface called\n"); | |
43 | return 0; | |
44 | } | |
45 | ||
46 | static void wbsoft_remove_interface(struct ieee80211_hw *dev, | |
47 | struct ieee80211_if_init_conf *conf) | |
48 | { | |
49 | printk("wbsoft_remove interface called\n"); | |
50 | } | |
51 | ||
68ab0c96 | 52 | static void wbsoft_stop(struct ieee80211_hw *hw) |
66101de1 | 53 | { |
68ab0c96 GKH |
54 | printk(KERN_INFO "%s called\n", __func__); |
55 | } | |
56 | ||
57 | static int wbsoft_get_stats(struct ieee80211_hw *hw, | |
58 | struct ieee80211_low_level_stats *stats) | |
59 | { | |
60 | printk(KERN_INFO "%s called\n", __func__); | |
61 | return 0; | |
62 | } | |
63 | ||
64 | static int wbsoft_get_tx_stats(struct ieee80211_hw *hw, | |
65 | struct ieee80211_tx_queue_stats *stats) | |
66 | { | |
67 | printk(KERN_INFO "%s called\n", __func__); | |
66101de1 PM |
68 | return 0; |
69 | } | |
70 | ||
71 | static void wbsoft_configure_filter(struct ieee80211_hw *dev, | |
72 | unsigned int changed_flags, | |
73 | unsigned int *total_flags, | |
74 | int mc_count, struct dev_mc_list *mclist) | |
75 | { | |
76 | unsigned int bit_nr, new_flags; | |
77 | u32 mc_filter[2]; | |
78 | int i; | |
79 | ||
80 | new_flags = 0; | |
81 | ||
82 | if (*total_flags & FIF_PROMISC_IN_BSS) { | |
83 | new_flags |= FIF_PROMISC_IN_BSS; | |
84 | mc_filter[1] = mc_filter[0] = ~0; | |
85 | } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { | |
86 | new_flags |= FIF_ALLMULTI; | |
87 | mc_filter[1] = mc_filter[0] = ~0; | |
88 | } else { | |
89 | mc_filter[1] = mc_filter[0] = 0; | |
90 | for (i = 0; i < mc_count; i++) { | |
91 | if (!mclist) | |
92 | break; | |
93 | printk("Should call ether_crc here\n"); | |
94 | //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; | |
95 | bit_nr = 0; | |
96 | ||
97 | bit_nr &= 0x3F; | |
98 | mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); | |
99 | mclist = mclist->next; | |
100 | } | |
101 | } | |
102 | ||
103 | dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; | |
104 | ||
105 | *total_flags = new_flags; | |
106 | } | |
107 | ||
68ab0c96 | 108 | static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb) |
66101de1 PM |
109 | { |
110 | char *buffer = kmalloc(skb->len, GFP_ATOMIC); | |
111 | printk("Sending frame %d bytes\n", skb->len); | |
112 | memcpy(buffer, skb->data, skb->len); | |
113 | if (1 == MLMESendFrame(my_adapter, buffer, skb->len, FRAME_TYPE_802_11_MANAGEMENT)) | |
114 | printk("frame sent ok (%d bytes)?\n", skb->len); | |
115 | return NETDEV_TX_OK; | |
116 | } | |
117 | ||
118 | ||
119 | static int wbsoft_start(struct ieee80211_hw *dev) | |
120 | { | |
121 | wbsoft_enabled = 1; | |
122 | printk("wbsoft_start called\n"); | |
123 | return 0; | |
124 | } | |
125 | ||
126 | static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) | |
127 | { | |
128 | ChanInfo ch; | |
129 | printk("wbsoft_config called\n"); | |
130 | ||
131 | ch.band = 1; | |
132 | ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */ | |
133 | ||
134 | ||
135 | hal_set_current_channel(&my_adapter->sHwData, ch); | |
136 | hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int); | |
137 | // hal_set_cap_info(&my_adapter->sHwData, ?? ); | |
8b384e0c | 138 | // hal_set_ssid(phw_data_t pHwData, u8 * pssid, u8 ssid_len); ?? |
66101de1 PM |
139 | hal_set_accept_broadcast(&my_adapter->sHwData, 1); |
140 | hal_set_accept_promiscuous(&my_adapter->sHwData, 1); | |
141 | hal_set_accept_multicast(&my_adapter->sHwData, 1); | |
142 | hal_set_accept_beacon(&my_adapter->sHwData, 1); | |
143 | hal_set_radio_mode(&my_adapter->sHwData, 0); | |
144 | //hal_set_antenna_number( phw_data_t pHwData, u8 number ) | |
145 | //hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex) | |
146 | ||
147 | ||
148 | // hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ?? | |
149 | ||
8b384e0c | 150 | //void hal_set_rates(phw_data_t pHwData, u8 * pbss_rates, |
66101de1 PM |
151 | // u8 length, unsigned char basic_rate_set) |
152 | ||
153 | return 0; | |
154 | } | |
155 | ||
156 | static int wbsoft_config_interface(struct ieee80211_hw *dev, | |
157 | struct ieee80211_vif *vif, | |
158 | struct ieee80211_if_conf *conf) | |
159 | { | |
160 | printk("wbsoft_config_interface called\n"); | |
161 | return 0; | |
162 | } | |
163 | ||
164 | static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) | |
165 | { | |
166 | printk("wbsoft_get_tsf called\n"); | |
167 | return 0; | |
168 | } | |
169 | ||
170 | static const struct ieee80211_ops wbsoft_ops = { | |
171 | .tx = wbsoft_tx, | |
172 | .start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */ | |
68ab0c96 | 173 | .stop = wbsoft_stop, |
66101de1 PM |
174 | .add_interface = wbsoft_add_interface, |
175 | .remove_interface = wbsoft_remove_interface, | |
176 | .config = wbsoft_config, | |
177 | .config_interface = wbsoft_config_interface, | |
178 | .configure_filter = wbsoft_configure_filter, | |
68ab0c96 GKH |
179 | .get_stats = wbsoft_get_stats, |
180 | .get_tx_stats = wbsoft_get_tx_stats, | |
66101de1 PM |
181 | .get_tsf = wbsoft_get_tsf, |
182 | // conf_tx: hal_set_cwmin()/hal_set_cwmax; | |
183 | }; | |
184 | ||
185 | struct wbsoft_priv { | |
186 | }; | |
187 | ||
302bae85 | 188 | static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table) |
66101de1 | 189 | { |
88ebc4b9 | 190 | struct wb35_adapter *adapter; |
66101de1 PM |
191 | PWBUSB pWbUsb; |
192 | struct usb_host_interface *interface; | |
193 | struct usb_endpoint_descriptor *endpoint; | |
66101de1 PM |
194 | u32 ltmp; |
195 | struct usb_device *udev = interface_to_usbdev(intf); | |
1523ddc4 PE |
196 | struct wbsoft_priv *priv; |
197 | struct ieee80211_hw *dev; | |
198 | static struct ieee80211_supported_band band; | |
199 | int err; | |
66101de1 PM |
200 | |
201 | usb_get_dev(udev); | |
202 | ||
dc7e04fe | 203 | // 20060630.2 Check the device if it already be opened |
1523ddc4 | 204 | err = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), |
dc7e04fe PE |
205 | 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, |
206 | 0x0, 0x400, <mp, 4, HZ*100 ); | |
1523ddc4 | 207 | if (err) |
dc7e04fe | 208 | goto error; |
66101de1 | 209 | |
dc7e04fe | 210 | ltmp = cpu_to_le32(ltmp); |
1523ddc4 PE |
211 | if (ltmp) { // Is already initialized? |
212 | err = -EBUSY; | |
dc7e04fe | 213 | goto error; |
1523ddc4 | 214 | } |
66101de1 | 215 | |
88ebc4b9 | 216 | adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); |
1523ddc4 PE |
217 | if (!adapter) { |
218 | err = -ENOMEM; | |
219 | goto error; | |
220 | } | |
66101de1 | 221 | |
88ebc4b9 | 222 | my_adapter = adapter; |
88ebc4b9 | 223 | pWbUsb = &adapter->sHwData.WbUsb; |
dc7e04fe | 224 | pWbUsb->udev = udev; |
66101de1 | 225 | |
dc7e04fe PE |
226 | interface = intf->cur_altsetting; |
227 | endpoint = &interface->endpoint[0].desc; | |
66101de1 | 228 | |
dc7e04fe PE |
229 | if (endpoint[2].wMaxPacketSize == 512) { |
230 | printk("[w35und] Working on USB 2.0\n"); | |
231 | pWbUsb->IsUsb20 = 1; | |
232 | } | |
66101de1 | 233 | |
88ebc4b9 | 234 | if (!WbWLanInitialize(adapter)) { |
1523ddc4 PE |
235 | err = -EINVAL; |
236 | goto error_free_adapter; | |
dc7e04fe | 237 | } |
66101de1 | 238 | |
1523ddc4 PE |
239 | dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops); |
240 | if (!dev) | |
241 | goto error_free_adapter; | |
66101de1 | 242 | |
1523ddc4 | 243 | my_dev = dev; |
66101de1 | 244 | |
1523ddc4 PE |
245 | SET_IEEE80211_DEV(dev, &udev->dev); |
246 | { | |
247 | phw_data_t pHwData = &adapter->sHwData; | |
248 | unsigned char dev_addr[MAX_ADDR_LEN]; | |
249 | hal_get_permanent_address(pHwData, dev_addr); | |
250 | SET_IEEE80211_PERM_ADDR(dev, dev_addr); | |
251 | } | |
66101de1 | 252 | |
1523ddc4 PE |
253 | dev->extra_tx_headroom = 12; /* FIXME */ |
254 | dev->flags = 0; | |
66101de1 | 255 | |
1523ddc4 PE |
256 | dev->channel_change_time = 1000; |
257 | dev->queues = 1; | |
dc7e04fe | 258 | |
1523ddc4 PE |
259 | band.channels = wbsoft_channels; |
260 | band.n_channels = ARRAY_SIZE(wbsoft_channels); | |
261 | band.bitrates = wbsoft_rates; | |
262 | band.n_bitrates = ARRAY_SIZE(wbsoft_rates); | |
66101de1 | 263 | |
1523ddc4 PE |
264 | dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band; |
265 | err = ieee80211_register_hw(dev); | |
266 | if (err) | |
267 | goto error_free_hw; | |
66101de1 | 268 | |
1523ddc4 | 269 | usb_set_intfdata(intf, adapter); |
66101de1 | 270 | |
dc7e04fe | 271 | return 0; |
1523ddc4 PE |
272 | |
273 | error_free_hw: | |
274 | ieee80211_free_hw(dev); | |
275 | error_free_adapter: | |
276 | kfree(adapter); | |
dc7e04fe | 277 | error: |
1523ddc4 | 278 | return err; |
66101de1 PM |
279 | } |
280 | ||
281 | void packet_came(char *pRxBufferAddress, int PacketSize) | |
282 | { | |
283 | struct sk_buff *skb; | |
284 | struct ieee80211_rx_status rx_status = {0}; | |
285 | ||
286 | if (!wbsoft_enabled) | |
287 | return; | |
288 | ||
289 | skb = dev_alloc_skb(PacketSize); | |
290 | if (!skb) { | |
291 | printk("Not enough memory for packet, FIXME\n"); | |
292 | return; | |
293 | } | |
294 | ||
295 | memcpy(skb_put(skb, PacketSize), | |
296 | pRxBufferAddress, | |
297 | PacketSize); | |
298 | ||
299 | /* | |
300 | rx_status.rate = 10; | |
301 | rx_status.channel = 1; | |
302 | rx_status.freq = 12345; | |
303 | rx_status.phymode = MODE_IEEE80211B; | |
304 | */ | |
305 | ||
306 | ieee80211_rx_irqsafe(my_dev, skb, &rx_status); | |
307 | } | |
308 | ||
302bae85 | 309 | static void wb35_disconnect(struct usb_interface *intf) |
66101de1 | 310 | { |
88ebc4b9 | 311 | struct wb35_adapter * adapter = usb_get_intfdata(intf); |
66101de1 PM |
312 | usb_set_intfdata(intf, NULL); |
313 | ||
66101de1 | 314 | // Card remove |
88ebc4b9 | 315 | WbWlanHalt(adapter); |
66101de1 PM |
316 | |
317 | } | |
318 | ||
dd38da46 PE |
319 | static struct usb_driver wb35_driver = { |
320 | .name = "w35und", | |
321 | .id_table = wb35_table, | |
322 | .probe = wb35_probe, | |
323 | .disconnect = wb35_disconnect, | |
324 | }; | |
325 | ||
326 | static int __init wb35_init(void) | |
327 | { | |
328 | return usb_register(&wb35_driver); | |
329 | } | |
330 | ||
331 | static void __exit wb35_exit(void) | |
332 | { | |
333 | usb_deregister(&wb35_driver); | |
334 | } | |
66101de1 | 335 | |
dd38da46 PE |
336 | module_init(wb35_init); |
337 | module_exit(wb35_exit); |