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