Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc9 1268 lines 32 kB view raw
1/* r3964 linediscipline for linux 2 * 3 * ----------------------------------------------------------- 4 * Copyright by 5 * Philips Automation Projects 6 * Kassel (Germany) 7 * http://www.pap-philips.de 8 * ----------------------------------------------------------- 9 * This software may be used and distributed according to the terms of 10 * the GNU General Public License, incorporated herein by reference. 11 * 12 * Author: 13 * L. Haag 14 * 15 * $Log: n_r3964.c,v $ 16 * Revision 1.10 2001/03/18 13:02:24 dwmw2 17 * Fix timer usage, use spinlocks properly. 18 * 19 * Revision 1.9 2001/03/18 12:52:14 dwmw2 20 * Merge changes in 2.4.2 21 * 22 * Revision 1.8 2000/03/23 14:14:54 dwmw2 23 * Fix race in sleeping in r3964_read() 24 * 25 * Revision 1.7 1999/28/08 11:41:50 dwmw2 26 * Port to 2.3 kernel 27 * 28 * Revision 1.6 1998/09/30 00:40:40 dwmw2 29 * Fixed compilation on 2.0.x kernels 30 * Updated to newly registered tty-ldisc number 9 31 * 32 * Revision 1.5 1998/09/04 21:57:36 dwmw2 33 * Signal handling bug fixes, port to 2.1.x. 34 * 35 * Revision 1.4 1998/04/02 20:26:59 lhaag 36 * select, blocking, ... 37 * 38 * Revision 1.3 1998/02/12 18:58:43 root 39 * fixed some memory leaks 40 * calculation of checksum characters 41 * 42 * Revision 1.2 1998/02/07 13:03:34 root 43 * ioctl read_telegram 44 * 45 * Revision 1.1 1998/02/06 19:21:03 root 46 * Initial revision 47 * 48 * 49 */ 50 51#include <linux/module.h> 52#include <linux/kernel.h> 53#include <linux/sched.h> 54#include <linux/types.h> 55#include <linux/fcntl.h> 56#include <linux/interrupt.h> 57#include <linux/ptrace.h> 58#include <linux/ioport.h> 59#include <linux/in.h> 60#include <linux/slab.h> 61#include <linux/tty.h> 62#include <linux/errno.h> 63#include <linux/string.h> /* used in new tty drivers */ 64#include <linux/signal.h> /* used in new tty drivers */ 65#include <linux/ioctl.h> 66#include <linux/n_r3964.h> 67#include <linux/poll.h> 68#include <linux/init.h> 69#include <asm/uaccess.h> 70 71/*#define DEBUG_QUEUE*/ 72 73/* Log successful handshake and protocol operations */ 74/*#define DEBUG_PROTO_S*/ 75 76/* Log handshake and protocol errors: */ 77/*#define DEBUG_PROTO_E*/ 78 79/* Log Linediscipline operations (open, close, read, write...): */ 80/*#define DEBUG_LDISC*/ 81 82/* Log module and memory operations (init, cleanup; kmalloc, kfree): */ 83/*#define DEBUG_MODUL*/ 84 85/* Macro helpers for debug output: */ 86#define TRACE(format, args...) printk("r3964: " format "\n" , ## args) 87 88#ifdef DEBUG_MODUL 89#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args) 90#else 91#define TRACE_M(fmt, arg...) do {} while (0) 92#endif 93#ifdef DEBUG_PROTO_S 94#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args) 95#else 96#define TRACE_PS(fmt, arg...) do {} while (0) 97#endif 98#ifdef DEBUG_PROTO_E 99#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args) 100#else 101#define TRACE_PE(fmt, arg...) do {} while (0) 102#endif 103#ifdef DEBUG_LDISC 104#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args) 105#else 106#define TRACE_L(fmt, arg...) do {} while (0) 107#endif 108#ifdef DEBUG_QUEUE 109#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args) 110#else 111#define TRACE_Q(fmt, arg...) do {} while (0) 112#endif 113static void add_tx_queue(struct r3964_info *, struct r3964_block_header *); 114static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code); 115static void put_char(struct r3964_info *pInfo, unsigned char ch); 116static void trigger_transmit(struct r3964_info *pInfo); 117static void retry_transmit(struct r3964_info *pInfo); 118static void transmit_block(struct r3964_info *pInfo); 119static void receive_char(struct r3964_info *pInfo, const unsigned char c); 120static void receive_error(struct r3964_info *pInfo, const char flag); 121static void on_timeout(unsigned long priv); 122static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg); 123static int read_telegram(struct r3964_info *pInfo, struct pid *pid, 124 unsigned char __user * buf); 125static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, 126 int error_code, struct r3964_block_header *pBlock); 127static struct r3964_message *remove_msg(struct r3964_info *pInfo, 128 struct r3964_client_info *pClient); 129static void remove_client_block(struct r3964_info *pInfo, 130 struct r3964_client_info *pClient); 131 132static int r3964_open(struct tty_struct *tty); 133static void r3964_close(struct tty_struct *tty); 134static ssize_t r3964_read(struct tty_struct *tty, struct file *file, 135 unsigned char __user * buf, size_t nr); 136static ssize_t r3964_write(struct tty_struct *tty, struct file *file, 137 const unsigned char *buf, size_t nr); 138static int r3964_ioctl(struct tty_struct *tty, struct file *file, 139 unsigned int cmd, unsigned long arg); 140static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old); 141static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, 142 struct poll_table_struct *wait); 143static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, 144 char *fp, int count); 145 146static struct tty_ldisc tty_ldisc_N_R3964 = { 147 .owner = THIS_MODULE, 148 .magic = TTY_LDISC_MAGIC, 149 .name = "R3964", 150 .open = r3964_open, 151 .close = r3964_close, 152 .read = r3964_read, 153 .write = r3964_write, 154 .ioctl = r3964_ioctl, 155 .set_termios = r3964_set_termios, 156 .poll = r3964_poll, 157 .receive_buf = r3964_receive_buf, 158}; 159 160static void dump_block(const unsigned char *block, unsigned int length) 161{ 162 unsigned int i, j; 163 char linebuf[16 * 3 + 1]; 164 165 for (i = 0; i < length; i += 16) { 166 for (j = 0; (j < 16) && (j + i < length); j++) { 167 sprintf(linebuf + 3 * j, "%02x ", block[i + j]); 168 } 169 linebuf[3 * j] = '\0'; 170 TRACE_PS("%s", linebuf); 171 } 172} 173 174/************************************************************* 175 * Driver initialisation 176 *************************************************************/ 177 178/************************************************************* 179 * Module support routines 180 *************************************************************/ 181 182static void __exit r3964_exit(void) 183{ 184 int status; 185 186 TRACE_M("cleanup_module()"); 187 188 status = tty_unregister_ldisc(N_R3964); 189 190 if (status != 0) { 191 printk(KERN_ERR "r3964: error unregistering linediscipline: " 192 "%d\n", status); 193 } else { 194 TRACE_L("linediscipline successfully unregistered"); 195 } 196} 197 198static int __init r3964_init(void) 199{ 200 int status; 201 202 printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n"); 203 204 /* 205 * Register the tty line discipline 206 */ 207 208 status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964); 209 if (status == 0) { 210 TRACE_L("line discipline %d registered", N_R3964); 211 TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags, 212 tty_ldisc_N_R3964.num); 213 TRACE_L("open=%p", tty_ldisc_N_R3964.open); 214 TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964); 215 } else { 216 printk(KERN_ERR "r3964: error registering line discipline: " 217 "%d\n", status); 218 } 219 return status; 220} 221 222module_init(r3964_init); 223module_exit(r3964_exit); 224 225/************************************************************* 226 * Protocol implementation routines 227 *************************************************************/ 228 229static void add_tx_queue(struct r3964_info *pInfo, 230 struct r3964_block_header *pHeader) 231{ 232 unsigned long flags; 233 234 spin_lock_irqsave(&pInfo->lock, flags); 235 236 pHeader->next = NULL; 237 238 if (pInfo->tx_last == NULL) { 239 pInfo->tx_first = pInfo->tx_last = pHeader; 240 } else { 241 pInfo->tx_last->next = pHeader; 242 pInfo->tx_last = pHeader; 243 } 244 245 spin_unlock_irqrestore(&pInfo->lock, flags); 246 247 TRACE_Q("add_tx_queue %p, length %d, tx_first = %p", 248 pHeader, pHeader->length, pInfo->tx_first); 249} 250 251static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) 252{ 253 struct r3964_block_header *pHeader; 254 unsigned long flags; 255#ifdef DEBUG_QUEUE 256 struct r3964_block_header *pDump; 257#endif 258 259 pHeader = pInfo->tx_first; 260 261 if (pHeader == NULL) 262 return; 263 264#ifdef DEBUG_QUEUE 265 printk("r3964: remove_from_tx_queue: %p, length %u - ", 266 pHeader, pHeader->length); 267 for (pDump = pHeader; pDump; pDump = pDump->next) 268 printk("%p ", pDump); 269 printk("\n"); 270#endif 271 272 if (pHeader->owner) { 273 if (error_code) { 274 add_msg(pHeader->owner, R3964_MSG_ACK, 0, 275 error_code, NULL); 276 } else { 277 add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length, 278 error_code, NULL); 279 } 280 wake_up_interruptible(&pInfo->read_wait); 281 } 282 283 spin_lock_irqsave(&pInfo->lock, flags); 284 285 pInfo->tx_first = pHeader->next; 286 if (pInfo->tx_first == NULL) { 287 pInfo->tx_last = NULL; 288 } 289 290 spin_unlock_irqrestore(&pInfo->lock, flags); 291 292 kfree(pHeader); 293 TRACE_M("remove_from_tx_queue - kfree %p", pHeader); 294 295 TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p", 296 pInfo->tx_first, pInfo->tx_last); 297} 298 299static void add_rx_queue(struct r3964_info *pInfo, 300 struct r3964_block_header *pHeader) 301{ 302 unsigned long flags; 303 304 spin_lock_irqsave(&pInfo->lock, flags); 305 306 pHeader->next = NULL; 307 308 if (pInfo->rx_last == NULL) { 309 pInfo->rx_first = pInfo->rx_last = pHeader; 310 } else { 311 pInfo->rx_last->next = pHeader; 312 pInfo->rx_last = pHeader; 313 } 314 pInfo->blocks_in_rx_queue++; 315 316 spin_unlock_irqrestore(&pInfo->lock, flags); 317 318 TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d", 319 pHeader, pHeader->length, 320 pInfo->rx_first, pInfo->blocks_in_rx_queue); 321} 322 323static void remove_from_rx_queue(struct r3964_info *pInfo, 324 struct r3964_block_header *pHeader) 325{ 326 unsigned long flags; 327 struct r3964_block_header *pFind; 328 329 if (pHeader == NULL) 330 return; 331 332 TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", 333 pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); 334 TRACE_Q("remove_from_rx_queue: %p, length %u", 335 pHeader, pHeader->length); 336 337 spin_lock_irqsave(&pInfo->lock, flags); 338 339 if (pInfo->rx_first == pHeader) { 340 /* Remove the first block in the linked list: */ 341 pInfo->rx_first = pHeader->next; 342 343 if (pInfo->rx_first == NULL) { 344 pInfo->rx_last = NULL; 345 } 346 pInfo->blocks_in_rx_queue--; 347 } else { 348 /* Find block to remove: */ 349 for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) { 350 if (pFind->next == pHeader) { 351 /* Got it. */ 352 pFind->next = pHeader->next; 353 pInfo->blocks_in_rx_queue--; 354 if (pFind->next == NULL) { 355 /* Oh, removed the last one! */ 356 pInfo->rx_last = pFind; 357 } 358 break; 359 } 360 } 361 } 362 363 spin_unlock_irqrestore(&pInfo->lock, flags); 364 365 kfree(pHeader); 366 TRACE_M("remove_from_rx_queue - kfree %p", pHeader); 367 368 TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", 369 pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); 370} 371 372static void put_char(struct r3964_info *pInfo, unsigned char ch) 373{ 374 struct tty_struct *tty = pInfo->tty; 375 376 if (tty == NULL) 377 return; 378 379 /* FIXME: put_char should not be called from an IRQ */ 380 if (tty->ops->put_char) { 381 tty->ops->put_char(tty, ch); 382 } 383 pInfo->bcc ^= ch; 384} 385 386static void flush(struct r3964_info *pInfo) 387{ 388 struct tty_struct *tty = pInfo->tty; 389 390 if (tty == NULL || tty->ops->flush_chars == NULL) 391 return; 392 tty->ops->flush_chars(tty); 393} 394 395static void trigger_transmit(struct r3964_info *pInfo) 396{ 397 unsigned long flags; 398 399 spin_lock_irqsave(&pInfo->lock, flags); 400 401 if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) { 402 pInfo->state = R3964_TX_REQUEST; 403 pInfo->nRetry = 0; 404 pInfo->flags &= ~R3964_ERROR; 405 mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); 406 407 spin_unlock_irqrestore(&pInfo->lock, flags); 408 409 TRACE_PS("trigger_transmit - sent STX"); 410 411 put_char(pInfo, STX); 412 flush(pInfo); 413 414 pInfo->bcc = 0; 415 } else { 416 spin_unlock_irqrestore(&pInfo->lock, flags); 417 } 418} 419 420static void retry_transmit(struct r3964_info *pInfo) 421{ 422 if (pInfo->nRetry < R3964_MAX_RETRIES) { 423 TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry); 424 pInfo->bcc = 0; 425 put_char(pInfo, STX); 426 flush(pInfo); 427 pInfo->state = R3964_TX_REQUEST; 428 pInfo->nRetry++; 429 mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); 430 } else { 431 TRACE_PE("transmission failed after %d retries", 432 R3964_MAX_RETRIES); 433 434 remove_from_tx_queue(pInfo, R3964_TX_FAIL); 435 436 put_char(pInfo, NAK); 437 flush(pInfo); 438 pInfo->state = R3964_IDLE; 439 440 trigger_transmit(pInfo); 441 } 442} 443 444static void transmit_block(struct r3964_info *pInfo) 445{ 446 struct tty_struct *tty = pInfo->tty; 447 struct r3964_block_header *pBlock = pInfo->tx_first; 448 int room = 0; 449 450 if (tty == NULL || pBlock == NULL) { 451 return; 452 } 453 454 room = tty_write_room(tty); 455 456 TRACE_PS("transmit_block %p, room %d, length %d", 457 pBlock, room, pBlock->length); 458 459 while (pInfo->tx_position < pBlock->length) { 460 if (room < 2) 461 break; 462 463 if (pBlock->data[pInfo->tx_position] == DLE) { 464 /* send additional DLE char: */ 465 put_char(pInfo, DLE); 466 } 467 put_char(pInfo, pBlock->data[pInfo->tx_position++]); 468 469 room--; 470 } 471 472 if ((pInfo->tx_position == pBlock->length) && (room >= 3)) { 473 put_char(pInfo, DLE); 474 put_char(pInfo, ETX); 475 if (pInfo->flags & R3964_BCC) { 476 put_char(pInfo, pInfo->bcc); 477 } 478 pInfo->state = R3964_WAIT_FOR_TX_ACK; 479 mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); 480 } 481 flush(pInfo); 482} 483 484static void on_receive_block(struct r3964_info *pInfo) 485{ 486 unsigned int length; 487 struct r3964_client_info *pClient; 488 struct r3964_block_header *pBlock; 489 490 length = pInfo->rx_position; 491 492 /* compare byte checksum characters: */ 493 if (pInfo->flags & R3964_BCC) { 494 if (pInfo->bcc != pInfo->last_rx) { 495 TRACE_PE("checksum error - got %x but expected %x", 496 pInfo->last_rx, pInfo->bcc); 497 pInfo->flags |= R3964_CHECKSUM; 498 } 499 } 500 501 /* check for errors (parity, overrun,...): */ 502 if (pInfo->flags & R3964_ERROR) { 503 TRACE_PE("on_receive_block - transmission failed error %x", 504 pInfo->flags & R3964_ERROR); 505 506 put_char(pInfo, NAK); 507 flush(pInfo); 508 if (pInfo->nRetry < R3964_MAX_RETRIES) { 509 pInfo->state = R3964_WAIT_FOR_RX_REPEAT; 510 pInfo->nRetry++; 511 mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC); 512 } else { 513 TRACE_PE("on_receive_block - failed after max retries"); 514 pInfo->state = R3964_IDLE; 515 } 516 return; 517 } 518 519 /* received block; submit DLE: */ 520 put_char(pInfo, DLE); 521 flush(pInfo); 522 del_timer_sync(&pInfo->tmr); 523 TRACE_PS(" rx success: got %d chars", length); 524 525 /* prepare struct r3964_block_header: */ 526 pBlock = kmalloc(length + sizeof(struct r3964_block_header), 527 GFP_KERNEL); 528 TRACE_M("on_receive_block - kmalloc %p", pBlock); 529 530 if (pBlock == NULL) 531 return; 532 533 pBlock->length = length; 534 pBlock->data = ((unsigned char *)pBlock) + 535 sizeof(struct r3964_block_header); 536 pBlock->locks = 0; 537 pBlock->next = NULL; 538 pBlock->owner = NULL; 539 540 memcpy(pBlock->data, pInfo->rx_buf, length); 541 542 /* queue block into rx_queue: */ 543 add_rx_queue(pInfo, pBlock); 544 545 /* notify attached client processes: */ 546 for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { 547 if (pClient->sig_flags & R3964_SIG_DATA) { 548 add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, 549 pBlock); 550 } 551 } 552 wake_up_interruptible(&pInfo->read_wait); 553 554 pInfo->state = R3964_IDLE; 555 556 trigger_transmit(pInfo); 557} 558 559static void receive_char(struct r3964_info *pInfo, const unsigned char c) 560{ 561 switch (pInfo->state) { 562 case R3964_TX_REQUEST: 563 if (c == DLE) { 564 TRACE_PS("TX_REQUEST - got DLE"); 565 566 pInfo->state = R3964_TRANSMITTING; 567 pInfo->tx_position = 0; 568 569 transmit_block(pInfo); 570 } else if (c == STX) { 571 if (pInfo->nRetry == 0) { 572 TRACE_PE("TX_REQUEST - init conflict"); 573 if (pInfo->priority == R3964_SLAVE) { 574 goto start_receiving; 575 } 576 } else { 577 TRACE_PE("TX_REQUEST - secondary init " 578 "conflict!? Switching to SLAVE mode " 579 "for next rx."); 580 goto start_receiving; 581 } 582 } else { 583 TRACE_PE("TX_REQUEST - char != DLE: %x", c); 584 retry_transmit(pInfo); 585 } 586 break; 587 case R3964_TRANSMITTING: 588 if (c == NAK) { 589 TRACE_PE("TRANSMITTING - got NAK"); 590 retry_transmit(pInfo); 591 } else { 592 TRACE_PE("TRANSMITTING - got invalid char"); 593 594 pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY; 595 mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); 596 } 597 break; 598 case R3964_WAIT_FOR_TX_ACK: 599 if (c == DLE) { 600 TRACE_PS("WAIT_FOR_TX_ACK - got DLE"); 601 remove_from_tx_queue(pInfo, R3964_OK); 602 603 pInfo->state = R3964_IDLE; 604 trigger_transmit(pInfo); 605 } else { 606 retry_transmit(pInfo); 607 } 608 break; 609 case R3964_WAIT_FOR_RX_REPEAT: 610 /* FALLTROUGH */ 611 case R3964_IDLE: 612 if (c == STX) { 613 /* Prevent rx_queue from overflow: */ 614 if (pInfo->blocks_in_rx_queue >= 615 R3964_MAX_BLOCKS_IN_RX_QUEUE) { 616 TRACE_PE("IDLE - got STX but no space in " 617 "rx_queue!"); 618 pInfo->state = R3964_WAIT_FOR_RX_BUF; 619 mod_timer(&pInfo->tmr, 620 jiffies + R3964_TO_NO_BUF); 621 break; 622 } 623start_receiving: 624 /* Ok, start receiving: */ 625 TRACE_PS("IDLE - got STX"); 626 pInfo->rx_position = 0; 627 pInfo->last_rx = 0; 628 pInfo->flags &= ~R3964_ERROR; 629 pInfo->state = R3964_RECEIVING; 630 mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); 631 pInfo->nRetry = 0; 632 put_char(pInfo, DLE); 633 flush(pInfo); 634 pInfo->bcc = 0; 635 } 636 break; 637 case R3964_RECEIVING: 638 if (pInfo->rx_position < RX_BUF_SIZE) { 639 pInfo->bcc ^= c; 640 641 if (c == DLE) { 642 if (pInfo->last_rx == DLE) { 643 pInfo->last_rx = 0; 644 goto char_to_buf; 645 } 646 pInfo->last_rx = DLE; 647 break; 648 } else if ((c == ETX) && (pInfo->last_rx == DLE)) { 649 if (pInfo->flags & R3964_BCC) { 650 pInfo->state = R3964_WAIT_FOR_BCC; 651 mod_timer(&pInfo->tmr, 652 jiffies + R3964_TO_ZVZ); 653 } else { 654 on_receive_block(pInfo); 655 } 656 } else { 657 pInfo->last_rx = c; 658char_to_buf: 659 pInfo->rx_buf[pInfo->rx_position++] = c; 660 mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); 661 } 662 } 663 /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */ 664 break; 665 case R3964_WAIT_FOR_BCC: 666 pInfo->last_rx = c; 667 on_receive_block(pInfo); 668 break; 669 } 670} 671 672static void receive_error(struct r3964_info *pInfo, const char flag) 673{ 674 switch (flag) { 675 case TTY_NORMAL: 676 break; 677 case TTY_BREAK: 678 TRACE_PE("received break"); 679 pInfo->flags |= R3964_BREAK; 680 break; 681 case TTY_PARITY: 682 TRACE_PE("parity error"); 683 pInfo->flags |= R3964_PARITY; 684 break; 685 case TTY_FRAME: 686 TRACE_PE("frame error"); 687 pInfo->flags |= R3964_FRAME; 688 break; 689 case TTY_OVERRUN: 690 TRACE_PE("frame overrun"); 691 pInfo->flags |= R3964_OVERRUN; 692 break; 693 default: 694 TRACE_PE("receive_error - unknown flag %d", flag); 695 pInfo->flags |= R3964_UNKNOWN; 696 break; 697 } 698} 699 700static void on_timeout(unsigned long priv) 701{ 702 struct r3964_info *pInfo = (void *)priv; 703 704 switch (pInfo->state) { 705 case R3964_TX_REQUEST: 706 TRACE_PE("TX_REQUEST - timeout"); 707 retry_transmit(pInfo); 708 break; 709 case R3964_WAIT_ZVZ_BEFORE_TX_RETRY: 710 put_char(pInfo, NAK); 711 flush(pInfo); 712 retry_transmit(pInfo); 713 break; 714 case R3964_WAIT_FOR_TX_ACK: 715 TRACE_PE("WAIT_FOR_TX_ACK - timeout"); 716 retry_transmit(pInfo); 717 break; 718 case R3964_WAIT_FOR_RX_BUF: 719 TRACE_PE("WAIT_FOR_RX_BUF - timeout"); 720 put_char(pInfo, NAK); 721 flush(pInfo); 722 pInfo->state = R3964_IDLE; 723 break; 724 case R3964_RECEIVING: 725 TRACE_PE("RECEIVING - timeout after %d chars", 726 pInfo->rx_position); 727 put_char(pInfo, NAK); 728 flush(pInfo); 729 pInfo->state = R3964_IDLE; 730 break; 731 case R3964_WAIT_FOR_RX_REPEAT: 732 TRACE_PE("WAIT_FOR_RX_REPEAT - timeout"); 733 pInfo->state = R3964_IDLE; 734 break; 735 case R3964_WAIT_FOR_BCC: 736 TRACE_PE("WAIT_FOR_BCC - timeout"); 737 put_char(pInfo, NAK); 738 flush(pInfo); 739 pInfo->state = R3964_IDLE; 740 break; 741 } 742} 743 744static struct r3964_client_info *findClient(struct r3964_info *pInfo, 745 struct pid *pid) 746{ 747 struct r3964_client_info *pClient; 748 749 for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { 750 if (pClient->pid == pid) { 751 return pClient; 752 } 753 } 754 return NULL; 755} 756 757static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) 758{ 759 struct r3964_client_info *pClient; 760 struct r3964_client_info **ppClient; 761 struct r3964_message *pMsg; 762 763 if ((arg & R3964_SIG_ALL) == 0) { 764 /* Remove client from client list */ 765 for (ppClient = &pInfo->firstClient; *ppClient; 766 ppClient = &(*ppClient)->next) { 767 pClient = *ppClient; 768 769 if (pClient->pid == pid) { 770 TRACE_PS("removing client %d from client list", 771 pid_nr(pid)); 772 *ppClient = pClient->next; 773 while (pClient->msg_count) { 774 pMsg = remove_msg(pInfo, pClient); 775 if (pMsg) { 776 kfree(pMsg); 777 TRACE_M("enable_signals - msg " 778 "kfree %p", pMsg); 779 } 780 } 781 put_pid(pClient->pid); 782 kfree(pClient); 783 TRACE_M("enable_signals - kfree %p", pClient); 784 return 0; 785 } 786 } 787 return -EINVAL; 788 } else { 789 pClient = findClient(pInfo, pid); 790 if (pClient) { 791 /* update signal options */ 792 pClient->sig_flags = arg; 793 } else { 794 /* add client to client list */ 795 pClient = kmalloc(sizeof(struct r3964_client_info), 796 GFP_KERNEL); 797 TRACE_M("enable_signals - kmalloc %p", pClient); 798 if (pClient == NULL) 799 return -ENOMEM; 800 801 TRACE_PS("add client %d to client list", pid_nr(pid)); 802 spin_lock_init(&pClient->lock); 803 pClient->sig_flags = arg; 804 pClient->pid = get_pid(pid); 805 pClient->next = pInfo->firstClient; 806 pClient->first_msg = NULL; 807 pClient->last_msg = NULL; 808 pClient->next_block_to_read = NULL; 809 pClient->msg_count = 0; 810 pInfo->firstClient = pClient; 811 } 812 } 813 814 return 0; 815} 816 817static int read_telegram(struct r3964_info *pInfo, struct pid *pid, 818 unsigned char __user * buf) 819{ 820 struct r3964_client_info *pClient; 821 struct r3964_block_header *block; 822 823 if (!buf) { 824 return -EINVAL; 825 } 826 827 pClient = findClient(pInfo, pid); 828 if (pClient == NULL) { 829 return -EINVAL; 830 } 831 832 block = pClient->next_block_to_read; 833 if (!block) { 834 return 0; 835 } else { 836 if (copy_to_user(buf, block->data, block->length)) 837 return -EFAULT; 838 839 remove_client_block(pInfo, pClient); 840 return block->length; 841 } 842 843 return -EINVAL; 844} 845 846static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, 847 int error_code, struct r3964_block_header *pBlock) 848{ 849 struct r3964_message *pMsg; 850 unsigned long flags; 851 852 if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) { 853queue_the_message: 854 855 pMsg = kmalloc(sizeof(struct r3964_message), 856 error_code ? GFP_ATOMIC : GFP_KERNEL); 857 TRACE_M("add_msg - kmalloc %p", pMsg); 858 if (pMsg == NULL) { 859 return; 860 } 861 862 spin_lock_irqsave(&pClient->lock, flags); 863 864 pMsg->msg_id = msg_id; 865 pMsg->arg = arg; 866 pMsg->error_code = error_code; 867 pMsg->block = pBlock; 868 pMsg->next = NULL; 869 870 if (pClient->last_msg == NULL) { 871 pClient->first_msg = pClient->last_msg = pMsg; 872 } else { 873 pClient->last_msg->next = pMsg; 874 pClient->last_msg = pMsg; 875 } 876 877 pClient->msg_count++; 878 879 if (pBlock != NULL) { 880 pBlock->locks++; 881 } 882 spin_unlock_irqrestore(&pClient->lock, flags); 883 } else { 884 if ((pClient->last_msg->msg_id == R3964_MSG_ACK) 885 && (pClient->last_msg->error_code == R3964_OVERFLOW)) { 886 pClient->last_msg->arg++; 887 TRACE_PE("add_msg - inc prev OVERFLOW-msg"); 888 } else { 889 msg_id = R3964_MSG_ACK; 890 arg = 0; 891 error_code = R3964_OVERFLOW; 892 pBlock = NULL; 893 TRACE_PE("add_msg - queue OVERFLOW-msg"); 894 goto queue_the_message; 895 } 896 } 897 /* Send SIGIO signal to client process: */ 898 if (pClient->sig_flags & R3964_USE_SIGIO) { 899 kill_pid(pClient->pid, SIGIO, 1); 900 } 901} 902 903static struct r3964_message *remove_msg(struct r3964_info *pInfo, 904 struct r3964_client_info *pClient) 905{ 906 struct r3964_message *pMsg = NULL; 907 unsigned long flags; 908 909 if (pClient->first_msg) { 910 spin_lock_irqsave(&pClient->lock, flags); 911 912 pMsg = pClient->first_msg; 913 pClient->first_msg = pMsg->next; 914 if (pClient->first_msg == NULL) { 915 pClient->last_msg = NULL; 916 } 917 918 pClient->msg_count--; 919 if (pMsg->block) { 920 remove_client_block(pInfo, pClient); 921 pClient->next_block_to_read = pMsg->block; 922 } 923 spin_unlock_irqrestore(&pClient->lock, flags); 924 } 925 return pMsg; 926} 927 928static void remove_client_block(struct r3964_info *pInfo, 929 struct r3964_client_info *pClient) 930{ 931 struct r3964_block_header *block; 932 933 TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid)); 934 935 block = pClient->next_block_to_read; 936 if (block) { 937 block->locks--; 938 if (block->locks == 0) { 939 remove_from_rx_queue(pInfo, block); 940 } 941 } 942 pClient->next_block_to_read = NULL; 943} 944 945/************************************************************* 946 * Line discipline routines 947 *************************************************************/ 948 949static int r3964_open(struct tty_struct *tty) 950{ 951 struct r3964_info *pInfo; 952 953 TRACE_L("open"); 954 TRACE_L("tty=%p, PID=%d, disc_data=%p", 955 tty, current->pid, tty->disc_data); 956 957 pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL); 958 TRACE_M("r3964_open - info kmalloc %p", pInfo); 959 960 if (!pInfo) { 961 printk(KERN_ERR "r3964: failed to alloc info structure\n"); 962 return -ENOMEM; 963 } 964 965 pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); 966 TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf); 967 968 if (!pInfo->rx_buf) { 969 printk(KERN_ERR "r3964: failed to alloc receive buffer\n"); 970 kfree(pInfo); 971 TRACE_M("r3964_open - info kfree %p", pInfo); 972 return -ENOMEM; 973 } 974 975 pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL); 976 TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf); 977 978 if (!pInfo->tx_buf) { 979 printk(KERN_ERR "r3964: failed to alloc transmit buffer\n"); 980 kfree(pInfo->rx_buf); 981 TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf); 982 kfree(pInfo); 983 TRACE_M("r3964_open - info kfree %p", pInfo); 984 return -ENOMEM; 985 } 986 987 spin_lock_init(&pInfo->lock); 988 pInfo->tty = tty; 989 init_waitqueue_head(&pInfo->read_wait); 990 pInfo->priority = R3964_MASTER; 991 pInfo->rx_first = pInfo->rx_last = NULL; 992 pInfo->tx_first = pInfo->tx_last = NULL; 993 pInfo->rx_position = 0; 994 pInfo->tx_position = 0; 995 pInfo->last_rx = 0; 996 pInfo->blocks_in_rx_queue = 0; 997 pInfo->firstClient = NULL; 998 pInfo->state = R3964_IDLE; 999 pInfo->flags = R3964_DEBUG; 1000 pInfo->nRetry = 0; 1001 1002 tty->disc_data = pInfo; 1003 tty->receive_room = 65536; 1004 1005 setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo); 1006 1007 return 0; 1008} 1009 1010static void r3964_close(struct tty_struct *tty) 1011{ 1012 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1013 struct r3964_client_info *pClient, *pNext; 1014 struct r3964_message *pMsg; 1015 struct r3964_block_header *pHeader, *pNextHeader; 1016 unsigned long flags; 1017 1018 TRACE_L("close"); 1019 1020 /* 1021 * Make sure that our task queue isn't activated. If it 1022 * is, take it out of the linked list. 1023 */ 1024 del_timer_sync(&pInfo->tmr); 1025 1026 /* Remove client-structs and message queues: */ 1027 pClient = pInfo->firstClient; 1028 while (pClient) { 1029 pNext = pClient->next; 1030 while (pClient->msg_count) { 1031 pMsg = remove_msg(pInfo, pClient); 1032 if (pMsg) { 1033 kfree(pMsg); 1034 TRACE_M("r3964_close - msg kfree %p", pMsg); 1035 } 1036 } 1037 put_pid(pClient->pid); 1038 kfree(pClient); 1039 TRACE_M("r3964_close - client kfree %p", pClient); 1040 pClient = pNext; 1041 } 1042 /* Remove jobs from tx_queue: */ 1043 spin_lock_irqsave(&pInfo->lock, flags); 1044 pHeader = pInfo->tx_first; 1045 pInfo->tx_first = pInfo->tx_last = NULL; 1046 spin_unlock_irqrestore(&pInfo->lock, flags); 1047 1048 while (pHeader) { 1049 pNextHeader = pHeader->next; 1050 kfree(pHeader); 1051 pHeader = pNextHeader; 1052 } 1053 1054 /* Free buffers: */ 1055 wake_up_interruptible(&pInfo->read_wait); 1056 kfree(pInfo->rx_buf); 1057 TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf); 1058 kfree(pInfo->tx_buf); 1059 TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf); 1060 kfree(pInfo); 1061 TRACE_M("r3964_close - info kfree %p", pInfo); 1062} 1063 1064static ssize_t r3964_read(struct tty_struct *tty, struct file *file, 1065 unsigned char __user * buf, size_t nr) 1066{ 1067 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1068 struct r3964_client_info *pClient; 1069 struct r3964_message *pMsg; 1070 struct r3964_client_message theMsg; 1071 int count; 1072 1073 TRACE_L("read()"); 1074 1075 lock_kernel(); 1076 1077 pClient = findClient(pInfo, task_pid(current)); 1078 if (pClient) { 1079 pMsg = remove_msg(pInfo, pClient); 1080 if (pMsg == NULL) { 1081 /* no messages available. */ 1082 if (file->f_flags & O_NONBLOCK) { 1083 unlock_kernel(); 1084 return -EAGAIN; 1085 } 1086 /* block until there is a message: */ 1087 wait_event_interruptible(pInfo->read_wait, 1088 (pMsg = remove_msg(pInfo, pClient))); 1089 } 1090 1091 /* If we still haven't got a message, we must have been signalled */ 1092 1093 if (!pMsg) { 1094 unlock_kernel(); 1095 return -EINTR; 1096 } 1097 1098 /* deliver msg to client process: */ 1099 theMsg.msg_id = pMsg->msg_id; 1100 theMsg.arg = pMsg->arg; 1101 theMsg.error_code = pMsg->error_code; 1102 count = sizeof(struct r3964_client_message); 1103 1104 kfree(pMsg); 1105 TRACE_M("r3964_read - msg kfree %p", pMsg); 1106 1107 if (copy_to_user(buf, &theMsg, count)) { 1108 unlock_kernel(); 1109 return -EFAULT; 1110 } 1111 1112 TRACE_PS("read - return %d", count); 1113 return count; 1114 } 1115 unlock_kernel(); 1116 return -EPERM; 1117} 1118 1119static ssize_t r3964_write(struct tty_struct *tty, struct file *file, 1120 const unsigned char *data, size_t count) 1121{ 1122 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1123 struct r3964_block_header *pHeader; 1124 struct r3964_client_info *pClient; 1125 unsigned char *new_data; 1126 1127 TRACE_L("write request, %d characters", count); 1128/* 1129 * Verify the pointers 1130 */ 1131 1132 if (!pInfo) 1133 return -EIO; 1134 1135/* 1136 * Ensure that the caller does not wish to send too much. 1137 */ 1138 if (count > R3964_MTU) { 1139 if (pInfo->flags & R3964_DEBUG) { 1140 TRACE_L(KERN_WARNING "r3964_write: truncating user " 1141 "packet from %u to mtu %d", count, R3964_MTU); 1142 } 1143 count = R3964_MTU; 1144 } 1145/* 1146 * Allocate a buffer for the data and copy it from the buffer with header prepended 1147 */ 1148 new_data = kmalloc(count + sizeof(struct r3964_block_header), 1149 GFP_KERNEL); 1150 TRACE_M("r3964_write - kmalloc %p", new_data); 1151 if (new_data == NULL) { 1152 if (pInfo->flags & R3964_DEBUG) { 1153 printk(KERN_ERR "r3964_write: no memory\n"); 1154 } 1155 return -ENOSPC; 1156 } 1157 1158 pHeader = (struct r3964_block_header *)new_data; 1159 pHeader->data = new_data + sizeof(struct r3964_block_header); 1160 pHeader->length = count; 1161 pHeader->locks = 0; 1162 pHeader->owner = NULL; 1163 1164 lock_kernel(); 1165 1166 pClient = findClient(pInfo, task_pid(current)); 1167 if (pClient) { 1168 pHeader->owner = pClient; 1169 } 1170 1171 memcpy(pHeader->data, data, count); /* We already verified this */ 1172 1173 if (pInfo->flags & R3964_DEBUG) { 1174 dump_block(pHeader->data, count); 1175 } 1176 1177/* 1178 * Add buffer to transmit-queue: 1179 */ 1180 add_tx_queue(pInfo, pHeader); 1181 trigger_transmit(pInfo); 1182 1183 unlock_kernel(); 1184 1185 return 0; 1186} 1187 1188static int r3964_ioctl(struct tty_struct *tty, struct file *file, 1189 unsigned int cmd, unsigned long arg) 1190{ 1191 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1192 if (pInfo == NULL) 1193 return -EINVAL; 1194 switch (cmd) { 1195 case R3964_ENABLE_SIGNALS: 1196 return enable_signals(pInfo, task_pid(current), arg); 1197 case R3964_SETPRIORITY: 1198 if (arg < R3964_MASTER || arg > R3964_SLAVE) 1199 return -EINVAL; 1200 pInfo->priority = arg & 0xff; 1201 return 0; 1202 case R3964_USE_BCC: 1203 if (arg) 1204 pInfo->flags |= R3964_BCC; 1205 else 1206 pInfo->flags &= ~R3964_BCC; 1207 return 0; 1208 case R3964_READ_TELEGRAM: 1209 return read_telegram(pInfo, task_pid(current), 1210 (unsigned char __user *)arg); 1211 default: 1212 return -ENOIOCTLCMD; 1213 } 1214} 1215 1216static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old) 1217{ 1218 TRACE_L("set_termios"); 1219} 1220 1221/* Called without the kernel lock held - fine */ 1222static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, 1223 struct poll_table_struct *wait) 1224{ 1225 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1226 struct r3964_client_info *pClient; 1227 struct r3964_message *pMsg = NULL; 1228 unsigned long flags; 1229 int result = POLLOUT; 1230 1231 TRACE_L("POLL"); 1232 1233 pClient = findClient(pInfo, task_pid(current)); 1234 if (pClient) { 1235 poll_wait(file, &pInfo->read_wait, wait); 1236 spin_lock_irqsave(&pInfo->lock, flags); 1237 pMsg = pClient->first_msg; 1238 spin_unlock_irqrestore(&pInfo->lock, flags); 1239 if (pMsg) 1240 result |= POLLIN | POLLRDNORM; 1241 } else { 1242 result = -EINVAL; 1243 } 1244 return result; 1245} 1246 1247static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, 1248 char *fp, int count) 1249{ 1250 struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data; 1251 const unsigned char *p; 1252 char *f, flags = 0; 1253 int i; 1254 1255 for (i = count, p = cp, f = fp; i; i--, p++) { 1256 if (f) 1257 flags = *f++; 1258 if (flags == TTY_NORMAL) { 1259 receive_char(pInfo, *p); 1260 } else { 1261 receive_error(pInfo, flags); 1262 } 1263 1264 } 1265} 1266 1267MODULE_LICENSE("GPL"); 1268MODULE_ALIAS_LDISC(N_R3964);