linux/drivers/tty/ipwireless/main.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * IPWireless 3G PCMCIA Network Driver
   4 *
   5 * Original code
   6 *   by Stephen Blackheath <stephen@blacksapphire.com>,
   7 *      Ben Martel <benm@symmetric.co.nz>
   8 *
   9 * Copyrighted as follows:
  10 *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
  11 *
  12 * Various driver changes and rewrites, port to new kernels
  13 *   Copyright (C) 2006-2007 Jiri Kosina
  14 *
  15 * Misc code cleanups and updates
  16 *   Copyright (C) 2007 David Sterba
  17 */
  18
  19#include "hardware.h"
  20#include "network.h"
  21#include "main.h"
  22#include "tty.h"
  23
  24#include <linux/delay.h>
  25#include <linux/init.h>
  26#include <linux/io.h>
  27#include <linux/kernel.h>
  28#include <linux/module.h>
  29#include <linux/sched.h>
  30#include <linux/slab.h>
  31
  32#include <pcmcia/cisreg.h>
  33#include <pcmcia/device_id.h>
  34#include <pcmcia/ss.h>
  35#include <pcmcia/ds.h>
  36
  37static const struct pcmcia_device_id ipw_ids[] = {
  38        PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
  39        PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200),
  40        PCMCIA_DEVICE_NULL
  41};
  42MODULE_DEVICE_TABLE(pcmcia, ipw_ids);
  43
  44static void ipwireless_detach(struct pcmcia_device *link);
  45
  46/*
  47 * Module params
  48 */
  49/* Debug mode: more verbose, print sent/recv bytes */
  50int ipwireless_debug;
  51int ipwireless_loopback;
  52int ipwireless_out_queue = 10;
  53
  54module_param_named(debug, ipwireless_debug, int, 0);
  55module_param_named(loopback, ipwireless_loopback, int, 0);
  56module_param_named(out_queue, ipwireless_out_queue, int, 0);
  57MODULE_PARM_DESC(debug, "switch on debug messages [0]");
  58MODULE_PARM_DESC(loopback,
  59                "debug: enable ras_raw channel [0]");
  60MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]");
  61
  62/* Executes in process context. */
  63static void signalled_reboot_work(struct work_struct *work_reboot)
  64{
  65        struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
  66                        work_reboot);
  67        struct pcmcia_device *link = ipw->link;
  68        pcmcia_reset_card(link->socket);
  69}
  70
  71static void signalled_reboot_callback(void *callback_data)
  72{
  73        struct ipw_dev *ipw = (struct ipw_dev *) callback_data;
  74
  75        /* Delegate to process context. */
  76        schedule_work(&ipw->work_reboot);
  77}
  78
  79static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
  80{
  81        struct ipw_dev *ipw = priv_data;
  82        int ret;
  83
  84        p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
  85        p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
  86
  87        /* 0x40 causes it to generate level mode interrupts. */
  88        /* 0x04 enables IREQ pin. */
  89        p_dev->config_index |= 0x44;
  90        p_dev->io_lines = 16;
  91        ret = pcmcia_request_io(p_dev);
  92        if (ret)
  93                return ret;
  94
  95        if (!request_region(p_dev->resource[0]->start,
  96                            resource_size(p_dev->resource[0]),
  97                            IPWIRELESS_PCCARD_NAME)) {
  98                ret = -EBUSY;
  99                goto exit;
 100        }
 101
 102        p_dev->resource[2]->flags |=
 103                WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
 104
 105        ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0);
 106        if (ret != 0)
 107                goto exit1;
 108
 109        ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr);
 110        if (ret != 0)
 111                goto exit1;
 112
 113        ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100;
 114
 115        ipw->common_memory = ioremap(p_dev->resource[2]->start,
 116                                resource_size(p_dev->resource[2]));
 117        if (!ipw->common_memory) {
 118                ret = -ENOMEM;
 119                goto exit1;
 120        }
 121        if (!request_mem_region(p_dev->resource[2]->start,
 122                                resource_size(p_dev->resource[2]),
 123                                IPWIRELESS_PCCARD_NAME)) {
 124                ret = -EBUSY;
 125                goto exit2;
 126        }
 127
 128        p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM |
 129                                        WIN_ENABLE;
 130        p_dev->resource[3]->end = 0; /* this used to be 0x1000 */
 131        ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0);
 132        if (ret != 0)
 133                goto exit3;
 134
 135        ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0);
 136        if (ret != 0)
 137                goto exit3;
 138
 139        ipw->attr_memory = ioremap(p_dev->resource[3]->start,
 140                                resource_size(p_dev->resource[3]));
 141        if (!ipw->attr_memory) {
 142                ret = -ENOMEM;
 143                goto exit3;
 144        }
 145        if (!request_mem_region(p_dev->resource[3]->start,
 146                                resource_size(p_dev->resource[3]),
 147                                IPWIRELESS_PCCARD_NAME)) {
 148                ret = -EBUSY;
 149                goto exit4;
 150        }
 151
 152        return 0;
 153
 154exit4:
 155        iounmap(ipw->attr_memory);
 156exit3:
 157        release_mem_region(p_dev->resource[2]->start,
 158                        resource_size(p_dev->resource[2]));
 159exit2:
 160        iounmap(ipw->common_memory);
 161exit1:
 162        release_region(p_dev->resource[0]->start,
 163                       resource_size(p_dev->resource[0]));
 164exit:
 165        pcmcia_disable_device(p_dev);
 166        return ret;
 167}
 168
 169static int config_ipwireless(struct ipw_dev *ipw)
 170{
 171        struct pcmcia_device *link = ipw->link;
 172        int ret = 0;
 173
 174        ipw->is_v2_card = 0;
 175        link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM |
 176                CONF_ENABLE_IRQ;
 177
 178        ret = pcmcia_loop_config(link, ipwireless_probe, ipw);
 179        if (ret != 0)
 180                return ret;
 181
 182        INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
 183
 184        ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start,
 185                                    ipw->attr_memory, ipw->common_memory,
 186                                    ipw->is_v2_card, signalled_reboot_callback,
 187                                    ipw);
 188
 189        ret = pcmcia_request_irq(link, ipwireless_interrupt);
 190        if (ret != 0)
 191                goto exit;
 192
 193        printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
 194                        ipw->is_v2_card ? "V2/V3" : "V1");
 195        printk(KERN_INFO IPWIRELESS_PCCARD_NAME
 196                ": I/O ports %pR, irq %d\n", link->resource[0],
 197                        (unsigned int) link->irq);
 198        if (ipw->attr_memory && ipw->common_memory)
 199                printk(KERN_INFO IPWIRELESS_PCCARD_NAME
 200                        ": attr memory %pR, common memory %pR\n",
 201                        link->resource[3],
 202                        link->resource[2]);
 203
 204        ipw->network = ipwireless_network_create(ipw->hardware);
 205        if (!ipw->network)
 206                goto exit;
 207
 208        ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network);
 209        if (!ipw->tty)
 210                goto exit;
 211
 212        ipwireless_init_hardware_v2_v3(ipw->hardware);
 213
 214        /*
 215         * Do the RequestConfiguration last, because it enables interrupts.
 216         * Then we don't get any interrupts before we're ready for them.
 217         */
 218        ret = pcmcia_enable_device(link);
 219        if (ret != 0)
 220                goto exit;
 221
 222        return 0;
 223
 224exit:
 225        if (ipw->common_memory) {
 226                release_mem_region(link->resource[2]->start,
 227                                resource_size(link->resource[2]));
 228                iounmap(ipw->common_memory);
 229        }
 230        if (ipw->attr_memory) {
 231                release_mem_region(link->resource[3]->start,
 232                                resource_size(link->resource[3]));
 233                iounmap(ipw->attr_memory);
 234        }
 235        pcmcia_disable_device(link);
 236        return -1;
 237}
 238
 239static void release_ipwireless(struct ipw_dev *ipw)
 240{
 241        release_region(ipw->link->resource[0]->start,
 242                       resource_size(ipw->link->resource[0]));
 243        if (ipw->common_memory) {
 244                release_mem_region(ipw->link->resource[2]->start,
 245                                resource_size(ipw->link->resource[2]));
 246                iounmap(ipw->common_memory);
 247        }
 248        if (ipw->attr_memory) {
 249                release_mem_region(ipw->link->resource[3]->start,
 250                                resource_size(ipw->link->resource[3]));
 251                iounmap(ipw->attr_memory);
 252        }
 253        pcmcia_disable_device(ipw->link);
 254}
 255
 256/*
 257 * ipwireless_attach() creates an "instance" of the driver, allocating
 258 * local data structures for one device (one interface).  The device
 259 * is registered with Card Services.
 260 *
 261 * The pcmcia_device structure is initialized, but we don't actually
 262 * configure the card at this point -- we wait until we receive a
 263 * card insertion event.
 264 */
 265static int ipwireless_attach(struct pcmcia_device *link)
 266{
 267        struct ipw_dev *ipw;
 268        int ret;
 269
 270        ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL);
 271        if (!ipw)
 272                return -ENOMEM;
 273
 274        ipw->link = link;
 275        link->priv = ipw;
 276
 277        ipw->hardware = ipwireless_hardware_create();
 278        if (!ipw->hardware) {
 279                kfree(ipw);
 280                return -ENOMEM;
 281        }
 282        /* RegisterClient will call config_ipwireless */
 283
 284        ret = config_ipwireless(ipw);
 285
 286        if (ret != 0) {
 287                ipwireless_detach(link);
 288                return ret;
 289        }
 290
 291        return 0;
 292}
 293
 294/*
 295 * This deletes a driver "instance".  The device is de-registered with
 296 * Card Services.  If it has been released, all local data structures
 297 * are freed.  Otherwise, the structures will be freed when the device
 298 * is released.
 299 */
 300static void ipwireless_detach(struct pcmcia_device *link)
 301{
 302        struct ipw_dev *ipw = link->priv;
 303
 304        release_ipwireless(ipw);
 305
 306        if (ipw->tty != NULL)
 307                ipwireless_tty_free(ipw->tty);
 308        if (ipw->network != NULL)
 309                ipwireless_network_free(ipw->network);
 310        if (ipw->hardware != NULL)
 311                ipwireless_hardware_free(ipw->hardware);
 312        kfree(ipw);
 313}
 314
 315static struct pcmcia_driver me = {
 316        .owner          = THIS_MODULE,
 317        .probe          = ipwireless_attach,
 318        .remove         = ipwireless_detach,
 319        .name           = IPWIRELESS_PCCARD_NAME,
 320        .id_table       = ipw_ids
 321};
 322
 323/*
 324 * Module insertion : initialisation of the module.
 325 * Register the card with cardmgr...
 326 */
 327static int __init init_ipwireless(void)
 328{
 329        int ret;
 330
 331        ret = ipwireless_tty_init();
 332        if (ret != 0)
 333                return ret;
 334
 335        ret = pcmcia_register_driver(&me);
 336        if (ret != 0)
 337                ipwireless_tty_release();
 338
 339        return ret;
 340}
 341
 342/*
 343 * Module removal
 344 */
 345static void __exit exit_ipwireless(void)
 346{
 347        pcmcia_unregister_driver(&me);
 348        ipwireless_tty_release();
 349}
 350
 351module_init(init_ipwireless);
 352module_exit(exit_ipwireless);
 353
 354MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR);
 355MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION);
 356MODULE_LICENSE("GPL");
 357