main.c revision 2d0ddec5b2b859f06116f631fc0ffe94fbceb556
1/* 2 * Copyright (C) 2008, cozybit Inc. 3 * Copyright (C) 2003-2006, Marvell International Ltd. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or (at 8 * your option) any later version. 9 */ 10#include "libertas_tf.h" 11#include "linux/etherdevice.h" 12 13#define DRIVER_RELEASE_VERSION "004.p0" 14/* thinfirm version: 5.132.X.pX */ 15#define LBTF_FW_VER_MIN 0x05840300 16#define LBTF_FW_VER_MAX 0x0584ffff 17#define QOS_CONTROL_LEN 2 18 19static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION; 20struct workqueue_struct *lbtf_wq; 21 22static const struct ieee80211_channel lbtf_channels[] = { 23 { .center_freq = 2412, .hw_value = 1 }, 24 { .center_freq = 2417, .hw_value = 2 }, 25 { .center_freq = 2422, .hw_value = 3 }, 26 { .center_freq = 2427, .hw_value = 4 }, 27 { .center_freq = 2432, .hw_value = 5 }, 28 { .center_freq = 2437, .hw_value = 6 }, 29 { .center_freq = 2442, .hw_value = 7 }, 30 { .center_freq = 2447, .hw_value = 8 }, 31 { .center_freq = 2452, .hw_value = 9 }, 32 { .center_freq = 2457, .hw_value = 10 }, 33 { .center_freq = 2462, .hw_value = 11 }, 34 { .center_freq = 2467, .hw_value = 12 }, 35 { .center_freq = 2472, .hw_value = 13 }, 36 { .center_freq = 2484, .hw_value = 14 }, 37}; 38 39/* This table contains the hardware specific values for the modulation rates. */ 40static const struct ieee80211_rate lbtf_rates[] = { 41 { .bitrate = 10, 42 .hw_value = 0, }, 43 { .bitrate = 20, 44 .hw_value = 1, 45 .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 46 { .bitrate = 55, 47 .hw_value = 2, 48 .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 49 { .bitrate = 110, 50 .hw_value = 3, 51 .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 52 { .bitrate = 60, 53 .hw_value = 5, 54 .flags = 0 }, 55 { .bitrate = 90, 56 .hw_value = 6, 57 .flags = 0 }, 58 { .bitrate = 120, 59 .hw_value = 7, 60 .flags = 0 }, 61 { .bitrate = 180, 62 .hw_value = 8, 63 .flags = 0 }, 64 { .bitrate = 240, 65 .hw_value = 9, 66 .flags = 0 }, 67 { .bitrate = 360, 68 .hw_value = 10, 69 .flags = 0 }, 70 { .bitrate = 480, 71 .hw_value = 11, 72 .flags = 0 }, 73 { .bitrate = 540, 74 .hw_value = 12, 75 .flags = 0 }, 76}; 77 78static void lbtf_cmd_work(struct work_struct *work) 79{ 80 struct lbtf_private *priv = container_of(work, struct lbtf_private, 81 cmd_work); 82 spin_lock_irq(&priv->driver_lock); 83 /* command response? */ 84 if (priv->cmd_response_rxed) { 85 priv->cmd_response_rxed = 0; 86 spin_unlock_irq(&priv->driver_lock); 87 lbtf_process_rx_command(priv); 88 spin_lock_irq(&priv->driver_lock); 89 } 90 91 if (priv->cmd_timed_out && priv->cur_cmd) { 92 struct cmd_ctrl_node *cmdnode = priv->cur_cmd; 93 94 if (++priv->nr_retries > 10) { 95 lbtf_complete_command(priv, cmdnode, 96 -ETIMEDOUT); 97 priv->nr_retries = 0; 98 } else { 99 priv->cur_cmd = NULL; 100 101 /* Stick it back at the _top_ of the pending 102 * queue for immediate resubmission */ 103 list_add(&cmdnode->list, &priv->cmdpendingq); 104 } 105 } 106 priv->cmd_timed_out = 0; 107 spin_unlock_irq(&priv->driver_lock); 108 109 if (!priv->fw_ready) 110 return; 111 /* Execute the next command */ 112 if (!priv->cur_cmd) 113 lbtf_execute_next_command(priv); 114} 115 116/** 117 * lbtf_setup_firmware: initialize firmware. 118 * 119 * @priv A pointer to struct lbtf_private structure 120 * 121 * Returns: 0 on success. 122 */ 123static int lbtf_setup_firmware(struct lbtf_private *priv) 124{ 125 int ret = -1; 126 127 /* 128 * Read priv address from HW 129 */ 130 memset(priv->current_addr, 0xff, ETH_ALEN); 131 ret = lbtf_update_hw_spec(priv); 132 if (ret) { 133 ret = -1; 134 goto done; 135 } 136 137 lbtf_set_mac_control(priv); 138 lbtf_set_radio_control(priv); 139 140 ret = 0; 141done: 142 return ret; 143} 144 145/** 146 * This function handles the timeout of command sending. 147 * It will re-send the same command again. 148 */ 149static void command_timer_fn(unsigned long data) 150{ 151 struct lbtf_private *priv = (struct lbtf_private *)data; 152 unsigned long flags; 153 154 spin_lock_irqsave(&priv->driver_lock, flags); 155 156 if (!priv->cur_cmd) { 157 printk(KERN_DEBUG "libertastf: command timer expired; " 158 "no pending command\n"); 159 goto out; 160 } 161 162 printk(KERN_DEBUG "libertas: command %x timed out\n", 163 le16_to_cpu(priv->cur_cmd->cmdbuf->command)); 164 165 priv->cmd_timed_out = 1; 166 queue_work(lbtf_wq, &priv->cmd_work); 167out: 168 spin_unlock_irqrestore(&priv->driver_lock, flags); 169} 170 171static int lbtf_init_adapter(struct lbtf_private *priv) 172{ 173 memset(priv->current_addr, 0xff, ETH_ALEN); 174 mutex_init(&priv->lock); 175 176 priv->vif = NULL; 177 setup_timer(&priv->command_timer, command_timer_fn, 178 (unsigned long)priv); 179 180 INIT_LIST_HEAD(&priv->cmdfreeq); 181 INIT_LIST_HEAD(&priv->cmdpendingq); 182 183 spin_lock_init(&priv->driver_lock); 184 185 /* Allocate the command buffers */ 186 if (lbtf_allocate_cmd_buffer(priv)) 187 return -1; 188 189 return 0; 190} 191 192static void lbtf_free_adapter(struct lbtf_private *priv) 193{ 194 lbtf_free_cmd_buffer(priv); 195 del_timer(&priv->command_timer); 196} 197 198static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) 199{ 200 struct lbtf_private *priv = hw->priv; 201 202 priv->skb_to_tx = skb; 203 queue_work(lbtf_wq, &priv->tx_work); 204 /* 205 * queue will be restarted when we receive transmission feedback if 206 * there are no buffered multicast frames to send 207 */ 208 ieee80211_stop_queues(priv->hw); 209 return NETDEV_TX_OK; 210} 211 212static void lbtf_tx_work(struct work_struct *work) 213{ 214 struct lbtf_private *priv = container_of(work, struct lbtf_private, 215 tx_work); 216 unsigned int len; 217 struct ieee80211_tx_info *info; 218 struct txpd *txpd; 219 struct sk_buff *skb = NULL; 220 int err; 221 222 if ((priv->vif->type == NL80211_IFTYPE_AP) && 223 (!skb_queue_empty(&priv->bc_ps_buf))) 224 skb = skb_dequeue(&priv->bc_ps_buf); 225 else if (priv->skb_to_tx) { 226 skb = priv->skb_to_tx; 227 priv->skb_to_tx = NULL; 228 } else 229 return; 230 231 len = skb->len; 232 info = IEEE80211_SKB_CB(skb); 233 txpd = (struct txpd *) skb_push(skb, sizeof(struct txpd)); 234 235 if (priv->surpriseremoved) { 236 dev_kfree_skb_any(skb); 237 return; 238 } 239 240 memset(txpd, 0, sizeof(struct txpd)); 241 /* Activate per-packet rate selection */ 242 txpd->tx_control |= cpu_to_le32(MRVL_PER_PACKET_RATE | 243 ieee80211_get_tx_rate(priv->hw, info)->hw_value); 244 245 /* copy destination address from 802.11 header */ 246 memcpy(txpd->tx_dest_addr_high, skb->data + sizeof(struct txpd) + 4, 247 ETH_ALEN); 248 txpd->tx_packet_length = cpu_to_le16(len); 249 txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); 250 BUG_ON(priv->tx_skb); 251 spin_lock_irq(&priv->driver_lock); 252 priv->tx_skb = skb; 253 err = priv->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len); 254 spin_unlock_irq(&priv->driver_lock); 255 if (err) { 256 dev_kfree_skb_any(skb); 257 priv->tx_skb = NULL; 258 } 259} 260 261static int lbtf_op_start(struct ieee80211_hw *hw) 262{ 263 struct lbtf_private *priv = hw->priv; 264 void *card = priv->card; 265 int ret = -1; 266 267 if (!priv->fw_ready) 268 /* Upload firmware */ 269 if (priv->hw_prog_firmware(card)) 270 goto err_prog_firmware; 271 272 /* poke the firmware */ 273 priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; 274 priv->radioon = RADIO_ON; 275 priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; 276 ret = lbtf_setup_firmware(priv); 277 if (ret) 278 goto err_prog_firmware; 279 280 if ((priv->fwrelease < LBTF_FW_VER_MIN) || 281 (priv->fwrelease > LBTF_FW_VER_MAX)) { 282 ret = -1; 283 goto err_prog_firmware; 284 } 285 286 printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n"); 287 return 0; 288 289err_prog_firmware: 290 priv->hw_reset_device(card); 291 return ret; 292} 293 294static void lbtf_op_stop(struct ieee80211_hw *hw) 295{ 296 struct lbtf_private *priv = hw->priv; 297 unsigned long flags; 298 struct sk_buff *skb; 299 300 struct cmd_ctrl_node *cmdnode; 301 /* Flush pending command nodes */ 302 spin_lock_irqsave(&priv->driver_lock, flags); 303 list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { 304 cmdnode->result = -ENOENT; 305 cmdnode->cmdwaitqwoken = 1; 306 wake_up_interruptible(&cmdnode->cmdwait_q); 307 } 308 309 spin_unlock_irqrestore(&priv->driver_lock, flags); 310 cancel_work_sync(&priv->cmd_work); 311 cancel_work_sync(&priv->tx_work); 312 while ((skb = skb_dequeue(&priv->bc_ps_buf))) 313 dev_kfree_skb_any(skb); 314 priv->radioon = RADIO_OFF; 315 lbtf_set_radio_control(priv); 316 317 return; 318} 319 320static int lbtf_op_add_interface(struct ieee80211_hw *hw, 321 struct ieee80211_if_init_conf *conf) 322{ 323 struct lbtf_private *priv = hw->priv; 324 if (priv->vif != NULL) 325 return -EOPNOTSUPP; 326 327 priv->vif = conf->vif; 328 switch (conf->type) { 329 case NL80211_IFTYPE_MESH_POINT: 330 case NL80211_IFTYPE_AP: 331 lbtf_set_mode(priv, LBTF_AP_MODE); 332 break; 333 case NL80211_IFTYPE_STATION: 334 lbtf_set_mode(priv, LBTF_STA_MODE); 335 break; 336 default: 337 priv->vif = NULL; 338 return -EOPNOTSUPP; 339 } 340 lbtf_set_mac_address(priv, (u8 *) conf->mac_addr); 341 return 0; 342} 343 344static void lbtf_op_remove_interface(struct ieee80211_hw *hw, 345 struct ieee80211_if_init_conf *conf) 346{ 347 struct lbtf_private *priv = hw->priv; 348 349 if (priv->vif->type == NL80211_IFTYPE_AP || 350 priv->vif->type == NL80211_IFTYPE_MESH_POINT) 351 lbtf_beacon_ctrl(priv, 0, 0); 352 lbtf_set_mode(priv, LBTF_PASSIVE_MODE); 353 lbtf_set_bssid(priv, 0, NULL); 354 priv->vif = NULL; 355} 356 357static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) 358{ 359 struct lbtf_private *priv = hw->priv; 360 struct ieee80211_conf *conf = &hw->conf; 361 362 if (conf->channel->center_freq != priv->cur_freq) { 363 priv->cur_freq = conf->channel->center_freq; 364 lbtf_set_channel(priv, conf->channel->hw_value); 365 } 366 return 0; 367} 368 369#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI) 370static void lbtf_op_configure_filter(struct ieee80211_hw *hw, 371 unsigned int changed_flags, 372 unsigned int *new_flags, 373 int mc_count, struct dev_mc_list *mclist) 374{ 375 struct lbtf_private *priv = hw->priv; 376 int old_mac_control = priv->mac_control; 377 int i; 378 changed_flags &= SUPPORTED_FIF_FLAGS; 379 *new_flags &= SUPPORTED_FIF_FLAGS; 380 381 if (!changed_flags) 382 return; 383 384 if (*new_flags & (FIF_PROMISC_IN_BSS)) 385 priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; 386 else 387 priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; 388 if (*new_flags & (FIF_ALLMULTI) || 389 mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { 390 priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; 391 priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; 392 } else if (mc_count) { 393 priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; 394 priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; 395 priv->nr_of_multicastmacaddr = mc_count; 396 for (i = 0; i < mc_count; i++) { 397 if (!mclist) 398 break; 399 memcpy(&priv->multicastlist[i], mclist->da_addr, 400 ETH_ALEN); 401 mclist = mclist->next; 402 } 403 lbtf_cmd_set_mac_multicast_addr(priv); 404 } else { 405 priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE | 406 CMD_ACT_MAC_ALL_MULTICAST_ENABLE); 407 if (priv->nr_of_multicastmacaddr) { 408 priv->nr_of_multicastmacaddr = 0; 409 lbtf_cmd_set_mac_multicast_addr(priv); 410 } 411 } 412 413 414 if (priv->mac_control != old_mac_control) 415 lbtf_set_mac_control(priv); 416} 417 418static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw, 419 struct ieee80211_vif *vif, 420 struct ieee80211_bss_conf *bss_conf, 421 u32 changes) 422{ 423 struct lbtf_private *priv = hw->priv; 424 struct sk_buff *beacon; 425 426 if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_INT)) { 427 switch (priv->vif->type) { 428 case NL80211_IFTYPE_AP: 429 case NL80211_IFTYPE_MESH_POINT: 430 beacon = ieee80211_beacon_get(hw, vif); 431 if (beacon) { 432 lbtf_beacon_set(priv, beacon); 433 kfree_skb(beacon); 434 lbtf_beacon_ctrl(priv, 1, 435 bss_conf->beacon_int); 436 } 437 break; 438 default: 439 break; 440 } 441 } 442 443 if (changes & BSS_CHANGED_BSSID) { 444 bool activate = !is_zero_ether_addr(bss_conf->bssid); 445 lbtf_set_bssid(priv, activate, bss_conf->bssid); 446 } 447 448 if (changes & BSS_CHANGED_ERP_PREAMBLE) { 449 if (bss_conf->use_short_preamble) 450 priv->preamble = CMD_TYPE_SHORT_PREAMBLE; 451 else 452 priv->preamble = CMD_TYPE_LONG_PREAMBLE; 453 lbtf_set_radio_control(priv); 454 } 455} 456 457static const struct ieee80211_ops lbtf_ops = { 458 .tx = lbtf_op_tx, 459 .start = lbtf_op_start, 460 .stop = lbtf_op_stop, 461 .add_interface = lbtf_op_add_interface, 462 .remove_interface = lbtf_op_remove_interface, 463 .config = lbtf_op_config, 464 .configure_filter = lbtf_op_configure_filter, 465 .bss_info_changed = lbtf_op_bss_info_changed, 466}; 467 468int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) 469{ 470 struct ieee80211_rx_status stats; 471 struct rxpd *prxpd; 472 int need_padding; 473 unsigned int flags; 474 struct ieee80211_hdr *hdr; 475 476 prxpd = (struct rxpd *) skb->data; 477 478 stats.flag = 0; 479 if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) 480 stats.flag |= RX_FLAG_FAILED_FCS_CRC; 481 stats.freq = priv->cur_freq; 482 stats.band = IEEE80211_BAND_2GHZ; 483 stats.signal = prxpd->snr; 484 stats.noise = prxpd->nf; 485 stats.qual = prxpd->snr - prxpd->nf; 486 /* Marvell rate index has a hole at value 4 */ 487 if (prxpd->rx_rate > 4) 488 --prxpd->rx_rate; 489 stats.rate_idx = prxpd->rx_rate; 490 skb_pull(skb, sizeof(struct rxpd)); 491 492 hdr = (struct ieee80211_hdr *)skb->data; 493 flags = le32_to_cpu(*(__le32 *)(skb->data + 4)); 494 495 need_padding = ieee80211_is_data_qos(hdr->frame_control); 496 need_padding ^= ieee80211_has_a4(hdr->frame_control); 497 need_padding ^= ieee80211_is_data_qos(hdr->frame_control) && 498 (*ieee80211_get_qos_ctl(hdr) & 499 IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); 500 501 if (need_padding) { 502 memmove(skb->data + 2, skb->data, skb->len); 503 skb_reserve(skb, 2); 504 } 505 506 ieee80211_rx_irqsafe(priv->hw, skb, &stats); 507 return 0; 508} 509EXPORT_SYMBOL_GPL(lbtf_rx); 510 511/** 512 * lbtf_add_card: Add and initialize the card, no fw upload yet. 513 * 514 * @card A pointer to card 515 * 516 * Returns: pointer to struct lbtf_priv. 517 */ 518struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) 519{ 520 struct ieee80211_hw *hw; 521 struct lbtf_private *priv = NULL; 522 523 hw = ieee80211_alloc_hw(sizeof(struct lbtf_private), &lbtf_ops); 524 if (!hw) 525 goto done; 526 527 priv = hw->priv; 528 if (lbtf_init_adapter(priv)) 529 goto err_init_adapter; 530 531 priv->hw = hw; 532 priv->card = card; 533 priv->tx_skb = NULL; 534 535 hw->queues = 1; 536 hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; 537 hw->extra_tx_headroom = sizeof(struct txpd); 538 memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels)); 539 memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates)); 540 priv->band.n_bitrates = ARRAY_SIZE(lbtf_rates); 541 priv->band.bitrates = priv->rates; 542 priv->band.n_channels = ARRAY_SIZE(lbtf_channels); 543 priv->band.channels = priv->channels; 544 hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; 545 skb_queue_head_init(&priv->bc_ps_buf); 546 547 SET_IEEE80211_DEV(hw, dmdev); 548 549 INIT_WORK(&priv->cmd_work, lbtf_cmd_work); 550 INIT_WORK(&priv->tx_work, lbtf_tx_work); 551 if (ieee80211_register_hw(hw)) 552 goto err_init_adapter; 553 554 goto done; 555 556err_init_adapter: 557 lbtf_free_adapter(priv); 558 ieee80211_free_hw(hw); 559 priv = NULL; 560 561done: 562 return priv; 563} 564EXPORT_SYMBOL_GPL(lbtf_add_card); 565 566 567int lbtf_remove_card(struct lbtf_private *priv) 568{ 569 struct ieee80211_hw *hw = priv->hw; 570 571 priv->surpriseremoved = 1; 572 del_timer(&priv->command_timer); 573 lbtf_free_adapter(priv); 574 priv->hw = NULL; 575 ieee80211_unregister_hw(hw); 576 ieee80211_free_hw(hw); 577 578 return 0; 579} 580EXPORT_SYMBOL_GPL(lbtf_remove_card); 581 582void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail) 583{ 584 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb); 585 586 ieee80211_tx_info_clear_status(info); 587 /* 588 * Commented out, otherwise we never go beyond 1Mbit/s using mac80211 589 * default pid rc algorithm. 590 * 591 * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt; 592 */ 593 if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail) 594 info->flags |= IEEE80211_TX_STAT_ACK; 595 skb_pull(priv->tx_skb, sizeof(struct txpd)); 596 ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb); 597 priv->tx_skb = NULL; 598 if (!priv->skb_to_tx && skb_queue_empty(&priv->bc_ps_buf)) 599 ieee80211_wake_queues(priv->hw); 600 else 601 queue_work(lbtf_wq, &priv->tx_work); 602} 603EXPORT_SYMBOL_GPL(lbtf_send_tx_feedback); 604 605void lbtf_bcn_sent(struct lbtf_private *priv) 606{ 607 struct sk_buff *skb = NULL; 608 609 if (priv->vif->type != NL80211_IFTYPE_AP) 610 return; 611 612 if (skb_queue_empty(&priv->bc_ps_buf)) { 613 bool tx_buff_bc = 0; 614 615 while ((skb = ieee80211_get_buffered_bc(priv->hw, priv->vif))) { 616 skb_queue_tail(&priv->bc_ps_buf, skb); 617 tx_buff_bc = 1; 618 } 619 if (tx_buff_bc) { 620 ieee80211_stop_queues(priv->hw); 621 queue_work(lbtf_wq, &priv->tx_work); 622 } 623 } 624 625 skb = ieee80211_beacon_get(priv->hw, priv->vif); 626 627 if (skb) { 628 lbtf_beacon_set(priv, skb); 629 kfree_skb(skb); 630 } 631} 632EXPORT_SYMBOL_GPL(lbtf_bcn_sent); 633 634static int __init lbtf_init_module(void) 635{ 636 lbtf_wq = create_workqueue("libertastf"); 637 if (lbtf_wq == NULL) { 638 printk(KERN_ERR "libertastf: couldn't create workqueue\n"); 639 return -ENOMEM; 640 } 641 return 0; 642} 643 644static void __exit lbtf_exit_module(void) 645{ 646 destroy_workqueue(lbtf_wq); 647} 648 649module_init(lbtf_init_module); 650module_exit(lbtf_exit_module); 651 652MODULE_DESCRIPTION("Libertas WLAN Thinfirm Driver Library"); 653MODULE_AUTHOR("Cozybit Inc."); 654MODULE_LICENSE("GPL"); 655