Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * IPWireless 3G PCMCIA Network Driver
0004  *
0005  * Original code
0006  *   by Stephen Blackheath <stephen@blacksapphire.com>,
0007  *      Ben Martel <benm@symmetric.co.nz>
0008  *
0009  * Copyrighted as follows:
0010  *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
0011  *
0012  * Various driver changes and rewrites, port to new kernels
0013  *   Copyright (C) 2006-2007 Jiri Kosina
0014  *
0015  * Misc code cleanups and updates
0016  *   Copyright (C) 2007 David Sterba
0017  */
0018 
0019 #include <linux/kernel.h>
0020 #include <linux/module.h>
0021 #include <linux/mutex.h>
0022 #include <linux/ppp_defs.h>
0023 #include <linux/if.h>
0024 #include <linux/ppp-ioctl.h>
0025 #include <linux/sched.h>
0026 #include <linux/serial.h>
0027 #include <linux/slab.h>
0028 #include <linux/tty.h>
0029 #include <linux/tty_driver.h>
0030 #include <linux/tty_flip.h>
0031 #include <linux/uaccess.h>
0032 
0033 #include "tty.h"
0034 #include "network.h"
0035 #include "hardware.h"
0036 #include "main.h"
0037 
0038 #define IPWIRELESS_PCMCIA_START     (0)
0039 #define IPWIRELESS_PCMCIA_MINORS    (24)
0040 #define IPWIRELESS_PCMCIA_MINOR_RANGE   (8)
0041 
0042 #define TTYTYPE_MODEM    (0)
0043 #define TTYTYPE_MONITOR  (1)
0044 #define TTYTYPE_RAS_RAW  (2)
0045 
0046 struct ipw_tty {
0047     struct tty_port port;
0048     int index;
0049     struct ipw_hardware *hardware;
0050     unsigned int channel_idx;
0051     unsigned int secondary_channel_idx;
0052     int tty_type;
0053     struct ipw_network *network;
0054     unsigned int control_lines;
0055     struct mutex ipw_tty_mutex;
0056     int tx_bytes_queued;
0057 };
0058 
0059 static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS];
0060 
0061 static struct tty_driver *ipw_tty_driver;
0062 
0063 static char *tty_type_name(int tty_type)
0064 {
0065     static char *channel_names[] = {
0066         "modem",
0067         "monitor",
0068         "RAS-raw"
0069     };
0070 
0071     return channel_names[tty_type];
0072 }
0073 
0074 static struct ipw_tty *get_tty(int index)
0075 {
0076     /*
0077      * The 'ras_raw' channel is only available when 'loopback' mode
0078      * is enabled.
0079      * Number of minor starts with 16 (_RANGE * _RAS_RAW).
0080      */
0081     if (!ipwireless_loopback && index >=
0082              IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
0083         return NULL;
0084 
0085     return ttys[index];
0086 }
0087 
0088 static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
0089 {
0090     struct ipw_tty *tty = get_tty(linux_tty->index);
0091 
0092     if (!tty)
0093         return -ENODEV;
0094 
0095     mutex_lock(&tty->ipw_tty_mutex);
0096     if (tty->port.count == 0)
0097         tty->tx_bytes_queued = 0;
0098 
0099     tty->port.count++;
0100 
0101     tty->port.tty = linux_tty;
0102     linux_tty->driver_data = tty;
0103 
0104     if (tty->tty_type == TTYTYPE_MODEM)
0105         ipwireless_ppp_open(tty->network);
0106 
0107     mutex_unlock(&tty->ipw_tty_mutex);
0108 
0109     return 0;
0110 }
0111 
0112 static void do_ipw_close(struct ipw_tty *tty)
0113 {
0114     tty->port.count--;
0115 
0116     if (tty->port.count == 0) {
0117         struct tty_struct *linux_tty = tty->port.tty;
0118 
0119         if (linux_tty != NULL) {
0120             tty->port.tty = NULL;
0121             linux_tty->driver_data = NULL;
0122 
0123             if (tty->tty_type == TTYTYPE_MODEM)
0124                 ipwireless_ppp_close(tty->network);
0125         }
0126     }
0127 }
0128 
0129 static void ipw_hangup(struct tty_struct *linux_tty)
0130 {
0131     struct ipw_tty *tty = linux_tty->driver_data;
0132 
0133     if (!tty)
0134         return;
0135 
0136     mutex_lock(&tty->ipw_tty_mutex);
0137     if (tty->port.count == 0) {
0138         mutex_unlock(&tty->ipw_tty_mutex);
0139         return;
0140     }
0141 
0142     do_ipw_close(tty);
0143 
0144     mutex_unlock(&tty->ipw_tty_mutex);
0145 }
0146 
0147 static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
0148 {
0149     ipw_hangup(linux_tty);
0150 }
0151 
0152 /* Take data received from hardware, and send it out the tty */
0153 void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
0154             unsigned int length)
0155 {
0156     int work = 0;
0157 
0158     mutex_lock(&tty->ipw_tty_mutex);
0159 
0160     if (!tty->port.count) {
0161         mutex_unlock(&tty->ipw_tty_mutex);
0162         return;
0163     }
0164     mutex_unlock(&tty->ipw_tty_mutex);
0165 
0166     work = tty_insert_flip_string(&tty->port, data, length);
0167 
0168     if (work != length)
0169         printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
0170                 ": %d chars not inserted to flip buffer!\n",
0171                 length - work);
0172 
0173     if (work)
0174         tty_flip_buffer_push(&tty->port);
0175 }
0176 
0177 static void ipw_write_packet_sent_callback(void *callback_data,
0178                        unsigned int packet_length)
0179 {
0180     struct ipw_tty *tty = callback_data;
0181 
0182     /*
0183      * Packet has been sent, so we subtract the number of bytes from our
0184      * tally of outstanding TX bytes.
0185      */
0186     tty->tx_bytes_queued -= packet_length;
0187 }
0188 
0189 static int ipw_write(struct tty_struct *linux_tty,
0190              const unsigned char *buf, int count)
0191 {
0192     struct ipw_tty *tty = linux_tty->driver_data;
0193     int room, ret;
0194 
0195     if (!tty)
0196         return -ENODEV;
0197 
0198     mutex_lock(&tty->ipw_tty_mutex);
0199     if (!tty->port.count) {
0200         mutex_unlock(&tty->ipw_tty_mutex);
0201         return -EINVAL;
0202     }
0203 
0204     room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
0205     if (room < 0)
0206         room = 0;
0207     /* Don't allow caller to write any more than we have room for */
0208     if (count > room)
0209         count = room;
0210 
0211     if (count == 0) {
0212         mutex_unlock(&tty->ipw_tty_mutex);
0213         return 0;
0214     }
0215 
0216     ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS,
0217                    buf, count,
0218                    ipw_write_packet_sent_callback, tty);
0219     if (ret < 0) {
0220         mutex_unlock(&tty->ipw_tty_mutex);
0221         return 0;
0222     }
0223 
0224     tty->tx_bytes_queued += count;
0225     mutex_unlock(&tty->ipw_tty_mutex);
0226 
0227     return count;
0228 }
0229 
0230 static unsigned int ipw_write_room(struct tty_struct *linux_tty)
0231 {
0232     struct ipw_tty *tty = linux_tty->driver_data;
0233     int room;
0234 
0235     /* FIXME: Exactly how is the tty object locked here .. */
0236     if (!tty)
0237         return 0;
0238 
0239     if (!tty->port.count)
0240         return 0;
0241 
0242     room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
0243     if (room < 0)
0244         room = 0;
0245 
0246     return room;
0247 }
0248 
0249 static int ipwireless_get_serial_info(struct tty_struct *linux_tty,
0250                       struct serial_struct *ss)
0251 {
0252     struct ipw_tty *tty = linux_tty->driver_data;
0253 
0254     if (!tty)
0255         return -ENODEV;
0256 
0257     if (!tty->port.count)
0258         return -EINVAL;
0259 
0260     ss->type = PORT_UNKNOWN;
0261     ss->line = tty->index;
0262     ss->baud_base = 115200;
0263     return 0;
0264 }
0265 
0266 static int ipwireless_set_serial_info(struct tty_struct *linux_tty,
0267                       struct serial_struct *ss)
0268 {
0269     return 0;   /* Keeps the PCMCIA scripts happy. */
0270 }
0271 
0272 static unsigned int ipw_chars_in_buffer(struct tty_struct *linux_tty)
0273 {
0274     struct ipw_tty *tty = linux_tty->driver_data;
0275 
0276     if (!tty)
0277         return 0;
0278 
0279     if (!tty->port.count)
0280         return 0;
0281 
0282     return tty->tx_bytes_queued;
0283 }
0284 
0285 static int get_control_lines(struct ipw_tty *tty)
0286 {
0287     unsigned int my = tty->control_lines;
0288     unsigned int out = 0;
0289 
0290     if (my & IPW_CONTROL_LINE_RTS)
0291         out |= TIOCM_RTS;
0292     if (my & IPW_CONTROL_LINE_DTR)
0293         out |= TIOCM_DTR;
0294     if (my & IPW_CONTROL_LINE_CTS)
0295         out |= TIOCM_CTS;
0296     if (my & IPW_CONTROL_LINE_DSR)
0297         out |= TIOCM_DSR;
0298     if (my & IPW_CONTROL_LINE_DCD)
0299         out |= TIOCM_CD;
0300 
0301     return out;
0302 }
0303 
0304 static int set_control_lines(struct ipw_tty *tty, unsigned int set,
0305                  unsigned int clear)
0306 {
0307     int ret;
0308 
0309     if (set & TIOCM_RTS) {
0310         ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1);
0311         if (ret)
0312             return ret;
0313         if (tty->secondary_channel_idx != -1) {
0314             ret = ipwireless_set_RTS(tty->hardware,
0315                       tty->secondary_channel_idx, 1);
0316             if (ret)
0317                 return ret;
0318         }
0319     }
0320     if (set & TIOCM_DTR) {
0321         ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1);
0322         if (ret)
0323             return ret;
0324         if (tty->secondary_channel_idx != -1) {
0325             ret = ipwireless_set_DTR(tty->hardware,
0326                       tty->secondary_channel_idx, 1);
0327             if (ret)
0328                 return ret;
0329         }
0330     }
0331     if (clear & TIOCM_RTS) {
0332         ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0);
0333         if (tty->secondary_channel_idx != -1) {
0334             ret = ipwireless_set_RTS(tty->hardware,
0335                       tty->secondary_channel_idx, 0);
0336             if (ret)
0337                 return ret;
0338         }
0339     }
0340     if (clear & TIOCM_DTR) {
0341         ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0);
0342         if (tty->secondary_channel_idx != -1) {
0343             ret = ipwireless_set_DTR(tty->hardware,
0344                       tty->secondary_channel_idx, 0);
0345             if (ret)
0346                 return ret;
0347         }
0348     }
0349     return 0;
0350 }
0351 
0352 static int ipw_tiocmget(struct tty_struct *linux_tty)
0353 {
0354     struct ipw_tty *tty = linux_tty->driver_data;
0355     /* FIXME: Exactly how is the tty object locked here .. */
0356 
0357     if (!tty)
0358         return -ENODEV;
0359 
0360     if (!tty->port.count)
0361         return -EINVAL;
0362 
0363     return get_control_lines(tty);
0364 }
0365 
0366 static int
0367 ipw_tiocmset(struct tty_struct *linux_tty,
0368          unsigned int set, unsigned int clear)
0369 {
0370     struct ipw_tty *tty = linux_tty->driver_data;
0371     /* FIXME: Exactly how is the tty object locked here .. */
0372 
0373     if (!tty)
0374         return -ENODEV;
0375 
0376     if (!tty->port.count)
0377         return -EINVAL;
0378 
0379     return set_control_lines(tty, set, clear);
0380 }
0381 
0382 static int ipw_ioctl(struct tty_struct *linux_tty,
0383              unsigned int cmd, unsigned long arg)
0384 {
0385     struct ipw_tty *tty = linux_tty->driver_data;
0386 
0387     if (!tty)
0388         return -ENODEV;
0389 
0390     if (!tty->port.count)
0391         return -EINVAL;
0392 
0393     /* FIXME: Exactly how is the tty object locked here .. */
0394     if (tty->tty_type == TTYTYPE_MODEM) {
0395         switch (cmd) {
0396         case PPPIOCGCHAN:
0397             {
0398                 int chan = ipwireless_ppp_channel_index(
0399                             tty->network);
0400 
0401                 if (chan < 0)
0402                     return -ENODEV;
0403                 if (put_user(chan, (int __user *) arg))
0404                     return -EFAULT;
0405             }
0406             return 0;
0407 
0408         case PPPIOCGUNIT:
0409             {
0410                 int unit = ipwireless_ppp_unit_number(
0411                         tty->network);
0412 
0413                 if (unit < 0)
0414                     return -ENODEV;
0415                 if (put_user(unit, (int __user *) arg))
0416                     return -EFAULT;
0417             }
0418             return 0;
0419 
0420         case FIONREAD:
0421             {
0422                 int val = 0;
0423 
0424                 if (put_user(val, (int __user *) arg))
0425                     return -EFAULT;
0426             }
0427             return 0;
0428         case TCFLSH:
0429             return tty_perform_flush(linux_tty, arg);
0430         }
0431     }
0432     return -ENOIOCTLCMD;
0433 }
0434 
0435 static int add_tty(int j,
0436             struct ipw_hardware *hardware,
0437             struct ipw_network *network, int channel_idx,
0438             int secondary_channel_idx, int tty_type)
0439 {
0440     ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL);
0441     if (!ttys[j])
0442         return -ENOMEM;
0443     ttys[j]->index = j;
0444     ttys[j]->hardware = hardware;
0445     ttys[j]->channel_idx = channel_idx;
0446     ttys[j]->secondary_channel_idx = secondary_channel_idx;
0447     ttys[j]->network = network;
0448     ttys[j]->tty_type = tty_type;
0449     mutex_init(&ttys[j]->ipw_tty_mutex);
0450     tty_port_init(&ttys[j]->port);
0451 
0452     tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
0453     ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
0454 
0455     if (secondary_channel_idx != -1)
0456         ipwireless_associate_network_tty(network,
0457                          secondary_channel_idx,
0458                          ttys[j]);
0459     /* check if we provide raw device (if loopback is enabled) */
0460     if (get_tty(j))
0461         printk(KERN_INFO IPWIRELESS_PCCARD_NAME
0462                ": registering %s device ttyIPWp%d\n",
0463                tty_type_name(tty_type), j);
0464 
0465     return 0;
0466 }
0467 
0468 struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware,
0469                       struct ipw_network *network)
0470 {
0471     int i, j;
0472 
0473     for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) {
0474         int allfree = 1;
0475 
0476         for (j = i; j < IPWIRELESS_PCMCIA_MINORS;
0477                 j += IPWIRELESS_PCMCIA_MINOR_RANGE)
0478             if (ttys[j] != NULL) {
0479                 allfree = 0;
0480                 break;
0481             }
0482 
0483         if (allfree) {
0484             j = i;
0485 
0486             if (add_tty(j, hardware, network,
0487                     IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS,
0488                     TTYTYPE_MODEM))
0489                 return NULL;
0490 
0491             j += IPWIRELESS_PCMCIA_MINOR_RANGE;
0492             if (add_tty(j, hardware, network,
0493                     IPW_CHANNEL_DIALLER, -1,
0494                     TTYTYPE_MONITOR))
0495                 return NULL;
0496 
0497             j += IPWIRELESS_PCMCIA_MINOR_RANGE;
0498             if (add_tty(j, hardware, network,
0499                     IPW_CHANNEL_RAS, -1,
0500                     TTYTYPE_RAS_RAW))
0501                 return NULL;
0502 
0503             return ttys[i];
0504         }
0505     }
0506     return NULL;
0507 }
0508 
0509 /*
0510  * Must be called before ipwireless_network_free().
0511  */
0512 void ipwireless_tty_free(struct ipw_tty *tty)
0513 {
0514     int j;
0515     struct ipw_network *network = ttys[tty->index]->network;
0516 
0517     for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS;
0518             j += IPWIRELESS_PCMCIA_MINOR_RANGE) {
0519         struct ipw_tty *ttyj = ttys[j];
0520 
0521         if (ttyj) {
0522             mutex_lock(&ttyj->ipw_tty_mutex);
0523             if (get_tty(j))
0524                 printk(KERN_INFO IPWIRELESS_PCCARD_NAME
0525                        ": deregistering %s device ttyIPWp%d\n",
0526                        tty_type_name(ttyj->tty_type), j);
0527             if (ttyj->port.tty != NULL) {
0528                 mutex_unlock(&ttyj->ipw_tty_mutex);
0529                 tty_vhangup(ttyj->port.tty);
0530                 /* FIXME: Exactly how is the tty object locked here
0531                    against a parallel ioctl etc */
0532                 /* FIXME2: hangup does not mean all processes
0533                  * are gone */
0534                 mutex_lock(&ttyj->ipw_tty_mutex);
0535             }
0536             while (ttyj->port.count)
0537                 do_ipw_close(ttyj);
0538             ipwireless_disassociate_network_ttys(network,
0539                                  ttyj->channel_idx);
0540             tty_unregister_device(ipw_tty_driver, j);
0541             tty_port_destroy(&ttyj->port);
0542             ttys[j] = NULL;
0543             mutex_unlock(&ttyj->ipw_tty_mutex);
0544             kfree(ttyj);
0545         }
0546     }
0547 }
0548 
0549 static const struct tty_operations tty_ops = {
0550     .open = ipw_open,
0551     .close = ipw_close,
0552     .hangup = ipw_hangup,
0553     .write = ipw_write,
0554     .write_room = ipw_write_room,
0555     .ioctl = ipw_ioctl,
0556     .chars_in_buffer = ipw_chars_in_buffer,
0557     .tiocmget = ipw_tiocmget,
0558     .tiocmset = ipw_tiocmset,
0559     .set_serial = ipwireless_set_serial_info,
0560     .get_serial = ipwireless_get_serial_info,
0561 };
0562 
0563 int ipwireless_tty_init(void)
0564 {
0565     int result;
0566 
0567     ipw_tty_driver = tty_alloc_driver(IPWIRELESS_PCMCIA_MINORS,
0568             TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
0569     if (IS_ERR(ipw_tty_driver))
0570         return PTR_ERR(ipw_tty_driver);
0571 
0572     ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
0573     ipw_tty_driver->name = "ttyIPWp";
0574     ipw_tty_driver->major = 0;
0575     ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START;
0576     ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
0577     ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL;
0578     ipw_tty_driver->init_termios = tty_std_termios;
0579     ipw_tty_driver->init_termios.c_cflag =
0580         B9600 | CS8 | CREAD | HUPCL | CLOCAL;
0581     ipw_tty_driver->init_termios.c_ispeed = 9600;
0582     ipw_tty_driver->init_termios.c_ospeed = 9600;
0583     tty_set_operations(ipw_tty_driver, &tty_ops);
0584     result = tty_register_driver(ipw_tty_driver);
0585     if (result) {
0586         printk(KERN_ERR IPWIRELESS_PCCARD_NAME
0587                ": failed to register tty driver\n");
0588         tty_driver_kref_put(ipw_tty_driver);
0589         return result;
0590     }
0591 
0592     return 0;
0593 }
0594 
0595 void ipwireless_tty_release(void)
0596 {
0597     tty_unregister_driver(ipw_tty_driver);
0598     tty_driver_kref_put(ipw_tty_driver);
0599 }
0600 
0601 int ipwireless_tty_is_modem(struct ipw_tty *tty)
0602 {
0603     return tty->tty_type == TTYTYPE_MODEM;
0604 }
0605 
0606 void
0607 ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
0608                       unsigned int channel_idx,
0609                       unsigned int control_lines,
0610                       unsigned int changed_mask)
0611 {
0612     unsigned int old_control_lines = tty->control_lines;
0613 
0614     tty->control_lines = (tty->control_lines & ~changed_mask)
0615         | (control_lines & changed_mask);
0616 
0617     /*
0618      * If DCD is de-asserted, we close the tty so pppd can tell that we
0619      * have gone offline.
0620      */
0621     if ((old_control_lines & IPW_CONTROL_LINE_DCD)
0622             && !(tty->control_lines & IPW_CONTROL_LINE_DCD)
0623             && tty->port.tty) {
0624         tty_hangup(tty->port.tty);
0625     }
0626 }
0627