1/* 2 * IPWireless 3G PCMCIA Network Driver 3 * 4 * Original code 5 * by Stephen Blackheath <stephen@blacksapphire.com>, 6 * Ben Martel <benm@symmetric.co.nz> 7 * 8 * Copyrighted as follows: 9 * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) 10 * 11 * Various driver changes and rewrites, port to new kernels 12 * Copyright (C) 2006-2007 Jiri Kosina 13 * 14 * Misc code cleanups and updates 15 * Copyright (C) 2007 David Sterba 16 */ 17 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/mutex.h> 21#include <linux/ppp_defs.h> 22#include <linux/if.h> 23#include <linux/ppp-ioctl.h> 24#include <linux/sched.h> 25#include <linux/serial.h> 26#include <linux/slab.h> 27#include <linux/tty.h> 28#include <linux/tty_driver.h> 29#include <linux/tty_flip.h> 30#include <linux/uaccess.h> 31 32#include "tty.h" 33#include "network.h" 34#include "hardware.h" 35#include "main.h" 36 37#define IPWIRELESS_PCMCIA_START (0) 38#define IPWIRELESS_PCMCIA_MINORS (24) 39#define IPWIRELESS_PCMCIA_MINOR_RANGE (8) 40 41#define TTYTYPE_MODEM (0) 42#define TTYTYPE_MONITOR (1) 43#define TTYTYPE_RAS_RAW (2) 44 45struct ipw_tty { 46 struct tty_port port; 47 int index; 48 struct ipw_hardware *hardware; 49 unsigned int channel_idx; 50 unsigned int secondary_channel_idx; 51 int tty_type; 52 struct ipw_network *network; 53 unsigned int control_lines; 54 struct mutex ipw_tty_mutex; 55 int tx_bytes_queued; 56 int closing; 57}; 58 59static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS]; 60 61static struct tty_driver *ipw_tty_driver; 62 63static char *tty_type_name(int tty_type) 64{ 65 static char *channel_names[] = { 66 "modem", 67 "monitor", 68 "RAS-raw" 69 }; 70 71 return channel_names[tty_type]; 72} 73 74static struct ipw_tty *get_tty(int index) 75{ 76 /* 77 * The 'ras_raw' channel is only available when 'loopback' mode 78 * is enabled. 79 * Number of minor starts with 16 (_RANGE * _RAS_RAW). 80 */ 81 if (!ipwireless_loopback && index >= 82 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW) 83 return NULL; 84 85 return ttys[index]; 86} 87 88static int ipw_open(struct tty_struct *linux_tty, struct file *filp) 89{ 90 struct ipw_tty *tty = get_tty(linux_tty->index); 91 92 if (!tty) 93 return -ENODEV; 94 95 mutex_lock(&tty->ipw_tty_mutex); 96 if (tty->port.count == 0) 97 tty->tx_bytes_queued = 0; 98 99 tty->port.count++; 100 101 tty->port.tty = linux_tty; 102 linux_tty->driver_data = tty; 103 tty->port.low_latency = 1; 104 105 if (tty->tty_type == TTYTYPE_MODEM) 106 ipwireless_ppp_open(tty->network); 107 108 mutex_unlock(&tty->ipw_tty_mutex); 109 110 return 0; 111} 112 113static void do_ipw_close(struct ipw_tty *tty) 114{ 115 tty->port.count--; 116 117 if (tty->port.count == 0) { 118 struct tty_struct *linux_tty = tty->port.tty; 119 120 if (linux_tty != NULL) { 121 tty->port.tty = NULL; 122 linux_tty->driver_data = NULL; 123 124 if (tty->tty_type == TTYTYPE_MODEM) 125 ipwireless_ppp_close(tty->network); 126 } 127 } 128} 129 130static void ipw_hangup(struct tty_struct *linux_tty) 131{ 132 struct ipw_tty *tty = linux_tty->driver_data; 133 134 if (!tty) 135 return; 136 137 mutex_lock(&tty->ipw_tty_mutex); 138 if (tty->port.count == 0) { 139 mutex_unlock(&tty->ipw_tty_mutex); 140 return; 141 } 142 143 do_ipw_close(tty); 144 145 mutex_unlock(&tty->ipw_tty_mutex); 146} 147 148static void ipw_close(struct tty_struct *linux_tty, struct file *filp) 149{ 150 ipw_hangup(linux_tty); 151} 152 153/* Take data received from hardware, and send it out the tty */ 154void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, 155 unsigned int length) 156{ 157 int work = 0; 158 159 mutex_lock(&tty->ipw_tty_mutex); 160 161 if (!tty->port.count) { 162 mutex_unlock(&tty->ipw_tty_mutex); 163 return; 164 } 165 mutex_unlock(&tty->ipw_tty_mutex); 166 167 work = tty_insert_flip_string(&tty->port, data, length); 168 169 if (work != length) 170 printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME 171 ": %d chars not inserted to flip buffer!\n", 172 length - work); 173 174 if (work) 175 tty_flip_buffer_push(&tty->port); 176} 177 178static void ipw_write_packet_sent_callback(void *callback_data, 179 unsigned int packet_length) 180{ 181 struct ipw_tty *tty = callback_data; 182 183 /* 184 * Packet has been sent, so we subtract the number of bytes from our 185 * tally of outstanding TX bytes. 186 */ 187 tty->tx_bytes_queued -= packet_length; 188} 189 190static int ipw_write(struct tty_struct *linux_tty, 191 const unsigned char *buf, int count) 192{ 193 struct ipw_tty *tty = linux_tty->driver_data; 194 int room, ret; 195 196 if (!tty) 197 return -ENODEV; 198 199 mutex_lock(&tty->ipw_tty_mutex); 200 if (!tty->port.count) { 201 mutex_unlock(&tty->ipw_tty_mutex); 202 return -EINVAL; 203 } 204 205 room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; 206 if (room < 0) 207 room = 0; 208 /* Don't allow caller to write any more than we have room for */ 209 if (count > room) 210 count = room; 211 212 if (count == 0) { 213 mutex_unlock(&tty->ipw_tty_mutex); 214 return 0; 215 } 216 217 ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS, 218 buf, count, 219 ipw_write_packet_sent_callback, tty); 220 if (ret == -1) { 221 mutex_unlock(&tty->ipw_tty_mutex); 222 return 0; 223 } 224 225 tty->tx_bytes_queued += count; 226 mutex_unlock(&tty->ipw_tty_mutex); 227 228 return count; 229} 230 231static int ipw_write_room(struct tty_struct *linux_tty) 232{ 233 struct ipw_tty *tty = linux_tty->driver_data; 234 int room; 235 236 /* FIXME: Exactly how is the tty object locked here .. */ 237 if (!tty) 238 return -ENODEV; 239 240 if (!tty->port.count) 241 return -EINVAL; 242 243 room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; 244 if (room < 0) 245 room = 0; 246 247 return room; 248} 249 250static int ipwireless_get_serial_info(struct ipw_tty *tty, 251 struct serial_struct __user *retinfo) 252{ 253 struct serial_struct tmp; 254 255 if (!retinfo) 256 return (-EFAULT); 257 258 memset(&tmp, 0, sizeof(tmp)); 259 tmp.type = PORT_UNKNOWN; 260 tmp.line = tty->index; 261 tmp.port = 0; 262 tmp.irq = 0; 263 tmp.flags = 0; 264 tmp.baud_base = 115200; 265 tmp.close_delay = 0; 266 tmp.closing_wait = 0; 267 tmp.custom_divisor = 0; 268 tmp.hub6 = 0; 269 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) 270 return -EFAULT; 271 272 return 0; 273} 274 275static int ipw_chars_in_buffer(struct tty_struct *linux_tty) 276{ 277 struct ipw_tty *tty = linux_tty->driver_data; 278 279 if (!tty) 280 return 0; 281 282 if (!tty->port.count) 283 return 0; 284 285 return tty->tx_bytes_queued; 286} 287 288static int get_control_lines(struct ipw_tty *tty) 289{ 290 unsigned int my = tty->control_lines; 291 unsigned int out = 0; 292 293 if (my & IPW_CONTROL_LINE_RTS) 294 out |= TIOCM_RTS; 295 if (my & IPW_CONTROL_LINE_DTR) 296 out |= TIOCM_DTR; 297 if (my & IPW_CONTROL_LINE_CTS) 298 out |= TIOCM_CTS; 299 if (my & IPW_CONTROL_LINE_DSR) 300 out |= TIOCM_DSR; 301 if (my & IPW_CONTROL_LINE_DCD) 302 out |= TIOCM_CD; 303 304 return out; 305} 306 307static int set_control_lines(struct ipw_tty *tty, unsigned int set, 308 unsigned int clear) 309{ 310 int ret; 311 312 if (set & TIOCM_RTS) { 313 ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1); 314 if (ret) 315 return ret; 316 if (tty->secondary_channel_idx != -1) { 317 ret = ipwireless_set_RTS(tty->hardware, 318 tty->secondary_channel_idx, 1); 319 if (ret) 320 return ret; 321 } 322 } 323 if (set & TIOCM_DTR) { 324 ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1); 325 if (ret) 326 return ret; 327 if (tty->secondary_channel_idx != -1) { 328 ret = ipwireless_set_DTR(tty->hardware, 329 tty->secondary_channel_idx, 1); 330 if (ret) 331 return ret; 332 } 333 } 334 if (clear & TIOCM_RTS) { 335 ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0); 336 if (tty->secondary_channel_idx != -1) { 337 ret = ipwireless_set_RTS(tty->hardware, 338 tty->secondary_channel_idx, 0); 339 if (ret) 340 return ret; 341 } 342 } 343 if (clear & TIOCM_DTR) { 344 ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0); 345 if (tty->secondary_channel_idx != -1) { 346 ret = ipwireless_set_DTR(tty->hardware, 347 tty->secondary_channel_idx, 0); 348 if (ret) 349 return ret; 350 } 351 } 352 return 0; 353} 354 355static int ipw_tiocmget(struct tty_struct *linux_tty) 356{ 357 struct ipw_tty *tty = linux_tty->driver_data; 358 /* FIXME: Exactly how is the tty object locked here .. */ 359 360 if (!tty) 361 return -ENODEV; 362 363 if (!tty->port.count) 364 return -EINVAL; 365 366 return get_control_lines(tty); 367} 368 369static int 370ipw_tiocmset(struct tty_struct *linux_tty, 371 unsigned int set, unsigned int clear) 372{ 373 struct ipw_tty *tty = linux_tty->driver_data; 374 /* FIXME: Exactly how is the tty object locked here .. */ 375 376 if (!tty) 377 return -ENODEV; 378 379 if (!tty->port.count) 380 return -EINVAL; 381 382 return set_control_lines(tty, set, clear); 383} 384 385static int ipw_ioctl(struct tty_struct *linux_tty, 386 unsigned int cmd, unsigned long arg) 387{ 388 struct ipw_tty *tty = linux_tty->driver_data; 389 390 if (!tty) 391 return -ENODEV; 392 393 if (!tty->port.count) 394 return -EINVAL; 395 396 /* FIXME: Exactly how is the tty object locked here .. */ 397 398 switch (cmd) { 399 case TIOCGSERIAL: 400 return ipwireless_get_serial_info(tty, (void __user *) arg); 401 402 case TIOCSSERIAL: 403 return 0; /* Keeps the PCMCIA scripts happy. */ 404 } 405 406 if (tty->tty_type == TTYTYPE_MODEM) { 407 switch (cmd) { 408 case PPPIOCGCHAN: 409 { 410 int chan = ipwireless_ppp_channel_index( 411 tty->network); 412 413 if (chan < 0) 414 return -ENODEV; 415 if (put_user(chan, (int __user *) arg)) 416 return -EFAULT; 417 } 418 return 0; 419 420 case PPPIOCGUNIT: 421 { 422 int unit = ipwireless_ppp_unit_number( 423 tty->network); 424 425 if (unit < 0) 426 return -ENODEV; 427 if (put_user(unit, (int __user *) arg)) 428 return -EFAULT; 429 } 430 return 0; 431 432 case FIONREAD: 433 { 434 int val = 0; 435 436 if (put_user(val, (int __user *) arg)) 437 return -EFAULT; 438 } 439 return 0; 440 case TCFLSH: 441 return tty_perform_flush(linux_tty, arg); 442 } 443 } 444 return -ENOIOCTLCMD; 445} 446 447static int add_tty(int j, 448 struct ipw_hardware *hardware, 449 struct ipw_network *network, int channel_idx, 450 int secondary_channel_idx, int tty_type) 451{ 452 ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL); 453 if (!ttys[j]) 454 return -ENOMEM; 455 ttys[j]->index = j; 456 ttys[j]->hardware = hardware; 457 ttys[j]->channel_idx = channel_idx; 458 ttys[j]->secondary_channel_idx = secondary_channel_idx; 459 ttys[j]->network = network; 460 ttys[j]->tty_type = tty_type; 461 mutex_init(&ttys[j]->ipw_tty_mutex); 462 tty_port_init(&ttys[j]->port); 463 464 tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL); 465 ipwireless_associate_network_tty(network, channel_idx, ttys[j]); 466 467 if (secondary_channel_idx != -1) 468 ipwireless_associate_network_tty(network, 469 secondary_channel_idx, 470 ttys[j]); 471 /* check if we provide raw device (if loopback is enabled) */ 472 if (get_tty(j)) 473 printk(KERN_INFO IPWIRELESS_PCCARD_NAME 474 ": registering %s device ttyIPWp%d\n", 475 tty_type_name(tty_type), j); 476 477 return 0; 478} 479 480struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware, 481 struct ipw_network *network) 482{ 483 int i, j; 484 485 for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) { 486 int allfree = 1; 487 488 for (j = i; j < IPWIRELESS_PCMCIA_MINORS; 489 j += IPWIRELESS_PCMCIA_MINOR_RANGE) 490 if (ttys[j] != NULL) { 491 allfree = 0; 492 break; 493 } 494 495 if (allfree) { 496 j = i; 497 498 if (add_tty(j, hardware, network, 499 IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS, 500 TTYTYPE_MODEM)) 501 return NULL; 502 503 j += IPWIRELESS_PCMCIA_MINOR_RANGE; 504 if (add_tty(j, hardware, network, 505 IPW_CHANNEL_DIALLER, -1, 506 TTYTYPE_MONITOR)) 507 return NULL; 508 509 j += IPWIRELESS_PCMCIA_MINOR_RANGE; 510 if (add_tty(j, hardware, network, 511 IPW_CHANNEL_RAS, -1, 512 TTYTYPE_RAS_RAW)) 513 return NULL; 514 515 return ttys[i]; 516 } 517 } 518 return NULL; 519} 520 521/* 522 * Must be called before ipwireless_network_free(). 523 */ 524void ipwireless_tty_free(struct ipw_tty *tty) 525{ 526 int j; 527 struct ipw_network *network = ttys[tty->index]->network; 528 529 for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; 530 j += IPWIRELESS_PCMCIA_MINOR_RANGE) { 531 struct ipw_tty *ttyj = ttys[j]; 532 533 if (ttyj) { 534 mutex_lock(&ttyj->ipw_tty_mutex); 535 if (get_tty(j)) 536 printk(KERN_INFO IPWIRELESS_PCCARD_NAME 537 ": deregistering %s device ttyIPWp%d\n", 538 tty_type_name(ttyj->tty_type), j); 539 ttyj->closing = 1; 540 if (ttyj->port.tty != NULL) { 541 mutex_unlock(&ttyj->ipw_tty_mutex); 542 tty_vhangup(ttyj->port.tty); 543 /* FIXME: Exactly how is the tty object locked here 544 against a parallel ioctl etc */ 545 /* FIXME2: hangup does not mean all processes 546 * are gone */ 547 mutex_lock(&ttyj->ipw_tty_mutex); 548 } 549 while (ttyj->port.count) 550 do_ipw_close(ttyj); 551 ipwireless_disassociate_network_ttys(network, 552 ttyj->channel_idx); 553 tty_unregister_device(ipw_tty_driver, j); 554 tty_port_destroy(&ttyj->port); 555 ttys[j] = NULL; 556 mutex_unlock(&ttyj->ipw_tty_mutex); 557 kfree(ttyj); 558 } 559 } 560} 561 562static const struct tty_operations tty_ops = { 563 .open = ipw_open, 564 .close = ipw_close, 565 .hangup = ipw_hangup, 566 .write = ipw_write, 567 .write_room = ipw_write_room, 568 .ioctl = ipw_ioctl, 569 .chars_in_buffer = ipw_chars_in_buffer, 570 .tiocmget = ipw_tiocmget, 571 .tiocmset = ipw_tiocmset, 572}; 573 574int ipwireless_tty_init(void) 575{ 576 int result; 577 578 ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS); 579 if (!ipw_tty_driver) 580 return -ENOMEM; 581 582 ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; 583 ipw_tty_driver->name = "ttyIPWp"; 584 ipw_tty_driver->major = 0; 585 ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START; 586 ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; 587 ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL; 588 ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 589 ipw_tty_driver->init_termios = tty_std_termios; 590 ipw_tty_driver->init_termios.c_cflag = 591 B9600 | CS8 | CREAD | HUPCL | CLOCAL; 592 ipw_tty_driver->init_termios.c_ispeed = 9600; 593 ipw_tty_driver->init_termios.c_ospeed = 9600; 594 tty_set_operations(ipw_tty_driver, &tty_ops); 595 result = tty_register_driver(ipw_tty_driver); 596 if (result) { 597 printk(KERN_ERR IPWIRELESS_PCCARD_NAME 598 ": failed to register tty driver\n"); 599 put_tty_driver(ipw_tty_driver); 600 return result; 601 } 602 603 return 0; 604} 605 606void ipwireless_tty_release(void) 607{ 608 int ret; 609 610 ret = tty_unregister_driver(ipw_tty_driver); 611 put_tty_driver(ipw_tty_driver); 612 if (ret != 0) 613 printk(KERN_ERR IPWIRELESS_PCCARD_NAME 614 ": tty_unregister_driver failed with code %d\n", ret); 615} 616 617int ipwireless_tty_is_modem(struct ipw_tty *tty) 618{ 619 return tty->tty_type == TTYTYPE_MODEM; 620} 621 622void 623ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, 624 unsigned int channel_idx, 625 unsigned int control_lines, 626 unsigned int changed_mask) 627{ 628 unsigned int old_control_lines = tty->control_lines; 629 630 tty->control_lines = (tty->control_lines & ~changed_mask) 631 | (control_lines & changed_mask); 632 633 /* 634 * If DCD is de-asserted, we close the tty so pppd can tell that we 635 * have gone offline. 636 */ 637 if ((old_control_lines & IPW_CONTROL_LINE_DCD) 638 && !(tty->control_lines & IPW_CONTROL_LINE_DCD) 639 && tty->port.tty) { 640 tty_hangup(tty->port.tty); 641 } 642} 643 644