]>
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)}, | |
22 | {} | |
66101de1 PM |
23 | }; |
24 | ||
dd38da46 | 25 | MODULE_DEVICE_TABLE(usb, wb35_table); |
66101de1 PM |
26 | |
27 | static const struct ieee80211_rate wbsoft_rates[] = { | |
28 | { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | |
29 | }; | |
30 | ||
31 | static const struct ieee80211_channel wbsoft_channels[] = { | |
32 | { .center_freq = 2412}, | |
33 | }; | |
34 | ||
35 | int wbsoft_enabled; | |
36 | struct ieee80211_hw *my_dev; | |
37 | PADAPTER my_adapter; | |
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 | ||
52 | static int wbsoft_nop(void) | |
53 | { | |
54 | printk("wbsoft_nop called\n"); | |
55 | return 0; | |
56 | } | |
57 | ||
58 | static void wbsoft_configure_filter(struct ieee80211_hw *dev, | |
59 | unsigned int changed_flags, | |
60 | unsigned int *total_flags, | |
61 | int mc_count, struct dev_mc_list *mclist) | |
62 | { | |
63 | unsigned int bit_nr, new_flags; | |
64 | u32 mc_filter[2]; | |
65 | int i; | |
66 | ||
67 | new_flags = 0; | |
68 | ||
69 | if (*total_flags & FIF_PROMISC_IN_BSS) { | |
70 | new_flags |= FIF_PROMISC_IN_BSS; | |
71 | mc_filter[1] = mc_filter[0] = ~0; | |
72 | } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { | |
73 | new_flags |= FIF_ALLMULTI; | |
74 | mc_filter[1] = mc_filter[0] = ~0; | |
75 | } else { | |
76 | mc_filter[1] = mc_filter[0] = 0; | |
77 | for (i = 0; i < mc_count; i++) { | |
78 | if (!mclist) | |
79 | break; | |
80 | printk("Should call ether_crc here\n"); | |
81 | //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; | |
82 | bit_nr = 0; | |
83 | ||
84 | bit_nr &= 0x3F; | |
85 | mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); | |
86 | mclist = mclist->next; | |
87 | } | |
88 | } | |
89 | ||
90 | dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; | |
91 | ||
92 | *total_flags = new_flags; | |
93 | } | |
94 | ||
95 | static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb, | |
96 | struct ieee80211_tx_control *control) | |
97 | { | |
98 | char *buffer = kmalloc(skb->len, GFP_ATOMIC); | |
99 | printk("Sending frame %d bytes\n", skb->len); | |
100 | memcpy(buffer, skb->data, skb->len); | |
101 | if (1 == MLMESendFrame(my_adapter, buffer, skb->len, FRAME_TYPE_802_11_MANAGEMENT)) | |
102 | printk("frame sent ok (%d bytes)?\n", skb->len); | |
103 | return NETDEV_TX_OK; | |
104 | } | |
105 | ||
106 | ||
107 | static int wbsoft_start(struct ieee80211_hw *dev) | |
108 | { | |
109 | wbsoft_enabled = 1; | |
110 | printk("wbsoft_start called\n"); | |
111 | return 0; | |
112 | } | |
113 | ||
114 | static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) | |
115 | { | |
116 | ChanInfo ch; | |
117 | printk("wbsoft_config called\n"); | |
118 | ||
119 | ch.band = 1; | |
120 | ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */ | |
121 | ||
122 | ||
123 | hal_set_current_channel(&my_adapter->sHwData, ch); | |
124 | hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int); | |
125 | // hal_set_cap_info(&my_adapter->sHwData, ?? ); | |
8b384e0c | 126 | // hal_set_ssid(phw_data_t pHwData, u8 * pssid, u8 ssid_len); ?? |
66101de1 PM |
127 | hal_set_accept_broadcast(&my_adapter->sHwData, 1); |
128 | hal_set_accept_promiscuous(&my_adapter->sHwData, 1); | |
129 | hal_set_accept_multicast(&my_adapter->sHwData, 1); | |
130 | hal_set_accept_beacon(&my_adapter->sHwData, 1); | |
131 | hal_set_radio_mode(&my_adapter->sHwData, 0); | |
132 | //hal_set_antenna_number( phw_data_t pHwData, u8 number ) | |
133 | //hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex) | |
134 | ||
135 | ||
136 | // hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ?? | |
137 | ||
8b384e0c | 138 | //void hal_set_rates(phw_data_t pHwData, u8 * pbss_rates, |
66101de1 PM |
139 | // u8 length, unsigned char basic_rate_set) |
140 | ||
141 | return 0; | |
142 | } | |
143 | ||
144 | static int wbsoft_config_interface(struct ieee80211_hw *dev, | |
145 | struct ieee80211_vif *vif, | |
146 | struct ieee80211_if_conf *conf) | |
147 | { | |
148 | printk("wbsoft_config_interface called\n"); | |
149 | return 0; | |
150 | } | |
151 | ||
152 | static u64 wbsoft_get_tsf(struct ieee80211_hw *dev) | |
153 | { | |
154 | printk("wbsoft_get_tsf called\n"); | |
155 | return 0; | |
156 | } | |
157 | ||
158 | static const struct ieee80211_ops wbsoft_ops = { | |
159 | .tx = wbsoft_tx, | |
160 | .start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */ | |
161 | .stop = wbsoft_nop, | |
162 | .add_interface = wbsoft_add_interface, | |
163 | .remove_interface = wbsoft_remove_interface, | |
164 | .config = wbsoft_config, | |
165 | .config_interface = wbsoft_config_interface, | |
166 | .configure_filter = wbsoft_configure_filter, | |
167 | .get_stats = wbsoft_nop, | |
168 | .get_tx_stats = wbsoft_nop, | |
169 | .get_tsf = wbsoft_get_tsf, | |
170 | // conf_tx: hal_set_cwmin()/hal_set_cwmax; | |
171 | }; | |
172 | ||
173 | struct wbsoft_priv { | |
174 | }; | |
175 | ||
176 | ||
66101de1 PM |
177 | // Usb kernel subsystem will call this function when a new device is plugged into. |
178 | int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table) | |
179 | { | |
180 | PADAPTER Adapter; | |
181 | PWBLINUX pWbLinux; | |
182 | PWBUSB pWbUsb; | |
183 | struct usb_host_interface *interface; | |
184 | struct usb_endpoint_descriptor *endpoint; | |
dd38da46 | 185 | int ret = -1; |
66101de1 PM |
186 | u32 ltmp; |
187 | struct usb_device *udev = interface_to_usbdev(intf); | |
188 | ||
189 | usb_get_dev(udev); | |
190 | ||
191 | printk("[w35und]wb35_probe ->\n"); | |
192 | ||
dc7e04fe PE |
193 | // 20060630.2 Check the device if it already be opened |
194 | ret = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ), | |
195 | 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, | |
196 | 0x0, 0x400, <mp, 4, HZ*100 ); | |
197 | if (ret < 0) | |
198 | goto error; | |
66101de1 | 199 | |
dc7e04fe PE |
200 | ltmp = cpu_to_le32(ltmp); |
201 | if (ltmp) // Is already initialized? | |
202 | goto error; | |
66101de1 | 203 | |
dc7e04fe | 204 | Adapter = kzalloc(sizeof(ADAPTER), GFP_KERNEL); |
66101de1 | 205 | |
dc7e04fe PE |
206 | my_adapter = Adapter; |
207 | pWbLinux = &Adapter->WbLinux; | |
208 | pWbUsb = &Adapter->sHwData.WbUsb; | |
209 | pWbUsb->udev = udev; | |
66101de1 | 210 | |
dc7e04fe PE |
211 | interface = intf->cur_altsetting; |
212 | endpoint = &interface->endpoint[0].desc; | |
66101de1 | 213 | |
dc7e04fe PE |
214 | if (endpoint[2].wMaxPacketSize == 512) { |
215 | printk("[w35und] Working on USB 2.0\n"); | |
216 | pWbUsb->IsUsb20 = 1; | |
217 | } | |
66101de1 | 218 | |
dc7e04fe PE |
219 | if (!WbWLanInitialize(Adapter)) { |
220 | printk("[w35und]WbWLanInitialize fail\n"); | |
221 | goto error; | |
222 | } | |
66101de1 | 223 | |
dc7e04fe PE |
224 | { |
225 | struct wbsoft_priv *priv; | |
226 | struct ieee80211_hw *dev; | |
227 | int res; | |
66101de1 | 228 | |
dc7e04fe | 229 | dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops); |
66101de1 | 230 | |
dc7e04fe PE |
231 | if (!dev) { |
232 | printk("w35und: ieee80211 alloc failed\n" ); | |
233 | BUG(); | |
234 | } | |
66101de1 | 235 | |
dc7e04fe | 236 | my_dev = dev; |
66101de1 | 237 | |
dc7e04fe PE |
238 | SET_IEEE80211_DEV(dev, &udev->dev); |
239 | { | |
240 | phw_data_t pHwData = &Adapter->sHwData; | |
241 | unsigned char dev_addr[MAX_ADDR_LEN]; | |
242 | hal_get_permanent_address(pHwData, dev_addr); | |
243 | SET_IEEE80211_PERM_ADDR(dev, dev_addr); | |
244 | } | |
66101de1 PM |
245 | |
246 | ||
dc7e04fe PE |
247 | dev->extra_tx_headroom = 12; /* FIXME */ |
248 | dev->flags = 0; | |
66101de1 | 249 | |
dc7e04fe PE |
250 | dev->channel_change_time = 1000; |
251 | // dev->max_rssi = 100; | |
66101de1 | 252 | |
dc7e04fe | 253 | dev->queues = 1; |
66101de1 | 254 | |
dc7e04fe | 255 | static struct ieee80211_supported_band band; |
66101de1 | 256 | |
dc7e04fe PE |
257 | band.channels = wbsoft_channels; |
258 | band.n_channels = ARRAY_SIZE(wbsoft_channels); | |
259 | band.bitrates = wbsoft_rates; | |
260 | band.n_bitrates = ARRAY_SIZE(wbsoft_rates); | |
66101de1 | 261 | |
dc7e04fe | 262 | dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band; |
66101de1 | 263 | #if 0 |
dc7e04fe PE |
264 | wbsoft_modes[0].num_channels = 1; |
265 | wbsoft_modes[0].channels = wbsoft_channels; | |
266 | wbsoft_modes[0].mode = MODE_IEEE80211B; | |
267 | wbsoft_modes[0].num_rates = ARRAY_SIZE(wbsoft_rates); | |
268 | wbsoft_modes[0].rates = wbsoft_rates; | |
269 | ||
270 | res = ieee80211_register_hwmode(dev, &wbsoft_modes[0]); | |
271 | BUG_ON(res); | |
66101de1 PM |
272 | #endif |
273 | ||
dc7e04fe PE |
274 | res = ieee80211_register_hw(dev); |
275 | BUG_ON(res); | |
276 | } | |
66101de1 | 277 | |
dc7e04fe | 278 | usb_set_intfdata( intf, Adapter ); |
66101de1 | 279 | |
dc7e04fe PE |
280 | printk("[w35und] _probe OK\n"); |
281 | return 0; | |
282 | error: | |
66101de1 PM |
283 | return -ENOMEM; |
284 | } | |
285 | ||
286 | void packet_came(char *pRxBufferAddress, int PacketSize) | |
287 | { | |
288 | struct sk_buff *skb; | |
289 | struct ieee80211_rx_status rx_status = {0}; | |
290 | ||
291 | if (!wbsoft_enabled) | |
292 | return; | |
293 | ||
294 | skb = dev_alloc_skb(PacketSize); | |
295 | if (!skb) { | |
296 | printk("Not enough memory for packet, FIXME\n"); | |
297 | return; | |
298 | } | |
299 | ||
300 | memcpy(skb_put(skb, PacketSize), | |
301 | pRxBufferAddress, | |
302 | PacketSize); | |
303 | ||
304 | /* | |
305 | rx_status.rate = 10; | |
306 | rx_status.channel = 1; | |
307 | rx_status.freq = 12345; | |
308 | rx_status.phymode = MODE_IEEE80211B; | |
309 | */ | |
310 | ||
311 | ieee80211_rx_irqsafe(my_dev, skb, &rx_status); | |
312 | } | |
313 | ||
314 | unsigned char | |
315 | WbUsb_initial(phw_data_t pHwData) | |
316 | { | |
317 | return 1; | |
318 | } | |
319 | ||
320 | ||
321 | void | |
322 | WbUsb_destroy(phw_data_t pHwData) | |
323 | { | |
324 | } | |
325 | ||
326 | int wb35_open(struct net_device *netdev) | |
327 | { | |
328 | PADAPTER Adapter = (PADAPTER)netdev->priv; | |
329 | phw_data_t pHwData = &Adapter->sHwData; | |
330 | ||
331 | netif_start_queue(netdev); | |
332 | ||
333 | //TODO : put here temporarily | |
334 | hal_set_accept_broadcast(pHwData, 1); // open accept broadcast | |
335 | ||
336 | return 0; | |
337 | } | |
338 | ||
339 | int wb35_close(struct net_device *netdev) | |
340 | { | |
341 | netif_stop_queue(netdev); | |
342 | return 0; | |
343 | } | |
344 | ||
345 | void wb35_disconnect(struct usb_interface *intf) | |
346 | { | |
347 | PWBLINUX pWbLinux; | |
348 | PADAPTER Adapter = usb_get_intfdata(intf); | |
349 | usb_set_intfdata(intf, NULL); | |
350 | ||
351 | pWbLinux = &Adapter->WbLinux; | |
352 | ||
353 | // Card remove | |
354 | WbWlanHalt(Adapter); | |
355 | ||
356 | } | |
357 | ||
dd38da46 PE |
358 | static struct usb_driver wb35_driver = { |
359 | .name = "w35und", | |
360 | .id_table = wb35_table, | |
361 | .probe = wb35_probe, | |
362 | .disconnect = wb35_disconnect, | |
363 | }; | |
364 | ||
365 | static int __init wb35_init(void) | |
366 | { | |
367 | return usb_register(&wb35_driver); | |
368 | } | |
369 | ||
370 | static void __exit wb35_exit(void) | |
371 | { | |
372 | usb_deregister(&wb35_driver); | |
373 | } | |
66101de1 | 374 | |
dd38da46 PE |
375 | module_init(wb35_init); |
376 | module_exit(wb35_exit); |