0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
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
0078
0079
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
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
0184
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
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
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;
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
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
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
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
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
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
0531
0532
0533
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
0619
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