1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * TI FlashMedia driver 4 * 5 * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com> 6 * 7 * Special thanks to Carlos Corbacho for providing various MemoryStick cards 8 * that made this driver possible. 9 */ 10 11 #include <linux/tifm.h> 12 #include <linux/memstick.h> 13 #include <linux/highmem.h> 14 #include <linux/scatterlist.h> 15 #include <linux/log2.h> 16 #include <linux/module.h> 17 #include <asm/io.h> 18 19 #define DRIVER_NAME "tifm_ms" 20 21 static bool no_dma; 22 module_param(no_dma, bool, 0644); 23 24 /* 25 * Some control bits of TIFM appear to conform to Sony's reference design, 26 * so I'm just assuming they all are. 27 */ 28 29 #define TIFM_MS_STAT_DRQ 0x04000 30 #define TIFM_MS_STAT_MSINT 0x02000 31 #define TIFM_MS_STAT_RDY 0x01000 32 #define TIFM_MS_STAT_CRC 0x00200 33 #define TIFM_MS_STAT_TOE 0x00100 34 #define TIFM_MS_STAT_EMP 0x00020 35 #define TIFM_MS_STAT_FUL 0x00010 36 #define TIFM_MS_STAT_CED 0x00008 37 #define TIFM_MS_STAT_ERR 0x00004 38 #define TIFM_MS_STAT_BRQ 0x00002 39 #define TIFM_MS_STAT_CNK 0x00001 40 41 #define TIFM_MS_SYS_DMA 0x10000 42 #define TIFM_MS_SYS_RESET 0x08000 43 #define TIFM_MS_SYS_SRAC 0x04000 44 #define TIFM_MS_SYS_INTEN 0x02000 45 #define TIFM_MS_SYS_NOCRC 0x01000 46 #define TIFM_MS_SYS_INTCLR 0x00800 47 #define TIFM_MS_SYS_MSIEN 0x00400 48 #define TIFM_MS_SYS_FCLR 0x00200 49 #define TIFM_MS_SYS_FDIR 0x00100 50 #define TIFM_MS_SYS_DAM 0x00080 51 #define TIFM_MS_SYS_DRM 0x00040 52 #define TIFM_MS_SYS_DRQSL 0x00020 53 #define TIFM_MS_SYS_REI 0x00010 54 #define TIFM_MS_SYS_REO 0x00008 55 #define TIFM_MS_SYS_BSY_MASK 0x00007 56 57 #define TIFM_MS_SYS_FIFO (TIFM_MS_SYS_INTEN | TIFM_MS_SYS_MSIEN \ 58 | TIFM_MS_SYS_FCLR | TIFM_MS_SYS_BSY_MASK) 59 60 /* Hardware flags */ 61 enum { 62 CMD_READY = 0x01, 63 FIFO_READY = 0x02, 64 CARD_INT = 0x04 65 }; 66 67 struct tifm_ms { 68 struct tifm_dev *dev; 69 struct timer_list timer; 70 struct memstick_request *req; 71 struct tasklet_struct notify; 72 unsigned int mode_mask; 73 unsigned int block_pos; 74 unsigned long timeout_jiffies; 75 unsigned char eject:1, 76 use_dma:1; 77 unsigned char cmd_flags; 78 unsigned char io_pos; 79 unsigned int io_word; 80 }; 81 82 static unsigned int tifm_ms_read_data(struct tifm_ms *host, 83 unsigned char *buf, unsigned int length) 84 { 85 struct tifm_dev *sock = host->dev; 86 unsigned int off = 0; 87 88 while (host->io_pos && length) { 89 buf[off++] = host->io_word & 0xff; 90 host->io_word >>= 8; 91 length--; 92 host->io_pos--; 93 } 94 95 if (!length) 96 return off; 97 98 while (!(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) { 99 if (length < 4) 100 break; 101 *(unsigned int *)(buf + off) = __raw_readl(sock->addr 102 + SOCK_MS_DATA); 103 length -= 4; 104 off += 4; 105 } 106 107 if (length 108 && !(TIFM_MS_STAT_EMP & readl(sock->addr + SOCK_MS_STATUS))) { 109 host->io_word = readl(sock->addr + SOCK_MS_DATA); 110 for (host->io_pos = 4; host->io_pos; --host->io_pos) { 111 buf[off++] = host->io_word & 0xff; 112 host->io_word >>= 8; 113 length--; 114 if (!length) 115 break; 116 } 117 } 118 119 return off; 120 } 121 122 static unsigned int tifm_ms_write_data(struct tifm_ms *host, 123 unsigned char *buf, unsigned int length) 124 { 125 struct tifm_dev *sock = host->dev; 126 unsigned int off = 0; 127 128 if (host->io_pos) { 129 while (host->io_pos < 4 && length) { 130 host->io_word |= buf[off++] << (host->io_pos * 8); 131 host->io_pos++; 132 length--; 133 } 134 } 135 136 if (host->io_pos == 4 137 && !(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) { 138 writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM), 139 sock->addr + SOCK_MS_SYSTEM); 140 writel(host->io_word, sock->addr + SOCK_MS_DATA); 141 host->io_pos = 0; 142 host->io_word = 0; 143 } else if (host->io_pos) { 144 return off; 145 } 146 147 if (!length) 148 return off; 149 150 while (!(TIFM_MS_STAT_FUL & readl(sock->addr + SOCK_MS_STATUS))) { 151 if (length < 4) 152 break; 153 writel(TIFM_MS_SYS_FDIR | readl(sock->addr + SOCK_MS_SYSTEM), 154 sock->addr + SOCK_MS_SYSTEM); 155 __raw_writel(*(unsigned int *)(buf + off), 156 sock->addr + SOCK_MS_DATA); 157 length -= 4; 158 off += 4; 159 } 160 161 switch (length) { 162 case 3: 163 host->io_word |= buf[off + 2] << 16; 164 host->io_pos++; 165 fallthrough; 166 case 2: 167 host->io_word |= buf[off + 1] << 8; 168 host->io_pos++; 169 fallthrough; 170 case 1: 171 host->io_word |= buf[off]; 172 host->io_pos++; 173 } 174 175 off += host->io_pos; 176 177 return off; 178 } 179 180 static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) 181 { 182 struct tifm_dev *sock = host->dev; 183 unsigned int length; 184 unsigned int off; 185 unsigned int t_size, p_cnt; 186 unsigned char *buf; 187 struct page *pg; 188 unsigned long flags = 0; 189 190 if (host->req->long_data) { 191 length = host->req->sg.length - host->block_pos; 192 off = host->req->sg.offset + host->block_pos; 193 } else { 194 length = host->req->data_len - host->block_pos; 195 off = 0; 196 } 197 dev_dbg(&sock->dev, "fifo data transfer, %d, %d\n", length, 198 host->block_pos); 199 200 while (length) { 201 unsigned int p_off; 202 203 if (host->req->long_data) { 204 pg = nth_page(sg_page(&host->req->sg), 205 off >> PAGE_SHIFT); 206 p_off = offset_in_page(off); 207 p_cnt = PAGE_SIZE - p_off; 208 p_cnt = min(p_cnt, length); 209 210 local_irq_save(flags); 211 buf = kmap_atomic(pg) + p_off; 212 } else { 213 buf = host->req->data + host->block_pos; 214 p_cnt = host->req->data_len - host->block_pos; 215 } 216 217 t_size = host->req->data_dir == WRITE 218 ? tifm_ms_write_data(host, buf, p_cnt) 219 : tifm_ms_read_data(host, buf, p_cnt); 220 221 if (host->req->long_data) { 222 kunmap_atomic(buf - p_off); 223 local_irq_restore(flags); 224 } 225 226 if (!t_size) 227 break; 228 host->block_pos += t_size; 229 length -= t_size; 230 off += t_size; 231 } 232 233 dev_dbg(&sock->dev, "fifo data transfer, %d remaining\n", length); 234 if (!length && (host->req->data_dir == WRITE)) { 235 if (host->io_pos) { 236 writel(TIFM_MS_SYS_FDIR 237 | readl(sock->addr + SOCK_MS_SYSTEM), 238 sock->addr + SOCK_MS_SYSTEM); 239 writel(host->io_word, sock->addr + SOCK_MS_DATA); 240 } 241 writel(TIFM_MS_SYS_FDIR 242 | readl(sock->addr + SOCK_MS_SYSTEM), 243 sock->addr + SOCK_MS_SYSTEM); 244 writel(0, sock->addr + SOCK_MS_DATA); 245 } else { 246 readl(sock->addr + SOCK_MS_DATA); 247 } 248 249 return length; 250 } 251 252 static int tifm_ms_issue_cmd(struct tifm_ms *host) 253 { 254 struct tifm_dev *sock = host->dev; 255 unsigned int data_len, cmd, sys_param; 256 257 host->cmd_flags = 0; 258 host->block_pos = 0; 259 host->io_pos = 0; 260 host->io_word = 0; 261 host->cmd_flags = 0; 262 263 host->use_dma = !no_dma; 264 265 if (host->req->long_data) { 266 data_len = host->req->sg.length; 267 if (!is_power_of_2(data_len)) 268 host->use_dma = 0; 269 } else { 270 data_len = host->req->data_len; 271 host->use_dma = 0; 272 } 273 274 writel(TIFM_FIFO_INT_SETALL, 275 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); 276 writel(TIFM_FIFO_ENABLE, 277 sock->addr + SOCK_FIFO_CONTROL); 278 279 if (host->use_dma) { 280 if (1 != tifm_map_sg(sock, &host->req->sg, 1, 281 host->req->data_dir == READ 282 ? DMA_FROM_DEVICE 283 : DMA_TO_DEVICE)) { 284 host->req->error = -ENOMEM; 285 return host->req->error; 286 } 287 data_len = sg_dma_len(&host->req->sg); 288 289 writel(ilog2(data_len) - 2, 290 sock->addr + SOCK_FIFO_PAGE_SIZE); 291 writel(TIFM_FIFO_INTMASK, 292 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); 293 sys_param = TIFM_DMA_EN | (1 << 8); 294 if (host->req->data_dir == WRITE) 295 sys_param |= TIFM_DMA_TX; 296 297 writel(TIFM_FIFO_INTMASK, 298 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); 299 300 writel(sg_dma_address(&host->req->sg), 301 sock->addr + SOCK_DMA_ADDRESS); 302 writel(sys_param, sock->addr + SOCK_DMA_CONTROL); 303 } else { 304 writel(host->mode_mask | TIFM_MS_SYS_FIFO, 305 sock->addr + SOCK_MS_SYSTEM); 306 307 writel(TIFM_FIFO_MORE, 308 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); 309 } 310 311 mod_timer(&host->timer, jiffies + host->timeout_jiffies); 312 writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), 313 sock->addr + SOCK_CONTROL); 314 host->req->error = 0; 315 316 sys_param = readl(sock->addr + SOCK_MS_SYSTEM); 317 sys_param |= TIFM_MS_SYS_INTCLR; 318 319 if (host->use_dma) 320 sys_param |= TIFM_MS_SYS_DMA; 321 else 322 sys_param &= ~TIFM_MS_SYS_DMA; 323 324 writel(sys_param, sock->addr + SOCK_MS_SYSTEM); 325 326 cmd = (host->req->tpc & 0xf) << 12; 327 cmd |= data_len; 328 writel(cmd, sock->addr + SOCK_MS_COMMAND); 329 330 dev_dbg(&sock->dev, "executing TPC %x, %x\n", cmd, sys_param); 331 return 0; 332 } 333 334 static void tifm_ms_complete_cmd(struct tifm_ms *host) 335 { 336 struct tifm_dev *sock = host->dev; 337 struct memstick_host *msh = tifm_get_drvdata(sock); 338 int rc; 339 340 del_timer(&host->timer); 341 342 host->req->int_reg = readl(sock->addr + SOCK_MS_STATUS) & 0xff; 343 host->req->int_reg = (host->req->int_reg & 1) 344 | ((host->req->int_reg << 4) & 0xe0); 345 346 writel(TIFM_FIFO_INT_SETALL, 347 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); 348 writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); 349 350 if (host->use_dma) { 351 tifm_unmap_sg(sock, &host->req->sg, 1, 352 host->req->data_dir == READ 353 ? DMA_FROM_DEVICE 354 : DMA_TO_DEVICE); 355 } 356 357 writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), 358 sock->addr + SOCK_CONTROL); 359 360 dev_dbg(&sock->dev, "TPC complete\n"); 361 do { 362 rc = memstick_next_req(msh, &host->req); 363 } while (!rc && tifm_ms_issue_cmd(host)); 364 } 365 366 static int tifm_ms_check_status(struct tifm_ms *host) 367 { 368 if (!host->req->error) { 369 if (!(host->cmd_flags & CMD_READY)) 370 return 1; 371 if (!(host->cmd_flags & FIFO_READY)) 372 return 1; 373 if (host->req->need_card_int 374 && !(host->cmd_flags & CARD_INT)) 375 return 1; 376 } 377 return 0; 378 } 379 380 /* Called from interrupt handler */ 381 static void tifm_ms_data_event(struct tifm_dev *sock) 382 { 383 struct tifm_ms *host; 384 unsigned int fifo_status = 0, host_status = 0; 385 int rc = 1; 386 387 spin_lock(&sock->lock); 388 host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock)); 389 fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); 390 host_status = readl(sock->addr + SOCK_MS_STATUS); 391 dev_dbg(&sock->dev, 392 "data event: fifo_status %x, host_status %x, flags %x\n", 393 fifo_status, host_status, host->cmd_flags); 394 395 if (host->req) { 396 if (host->use_dma && (fifo_status & 1)) { 397 host->cmd_flags |= FIFO_READY; 398 rc = tifm_ms_check_status(host); 399 } 400 if (!host->use_dma && (fifo_status & TIFM_FIFO_MORE)) { 401 if (!tifm_ms_transfer_data(host)) { 402 host->cmd_flags |= FIFO_READY; 403 rc = tifm_ms_check_status(host); 404 } 405 } 406 } 407 408 writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); 409 if (!rc) 410 tifm_ms_complete_cmd(host); 411 412 spin_unlock(&sock->lock); 413 } 414 415 416 /* Called from interrupt handler */ 417 static void tifm_ms_card_event(struct tifm_dev *sock) 418 { 419 struct tifm_ms *host; 420 unsigned int host_status = 0; 421 int rc = 1; 422 423 spin_lock(&sock->lock); 424 host = memstick_priv((struct memstick_host *)tifm_get_drvdata(sock)); 425 host_status = readl(sock->addr + SOCK_MS_STATUS); 426 dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n", 427 host_status, host->cmd_flags); 428 429 if (host->req) { 430 if (host_status & TIFM_MS_STAT_TOE) 431 host->req->error = -ETIME; 432 else if (host_status & TIFM_MS_STAT_CRC) 433 host->req->error = -EILSEQ; 434 435 if (host_status & TIFM_MS_STAT_RDY) 436 host->cmd_flags |= CMD_READY; 437 438 if (host_status & TIFM_MS_STAT_MSINT) 439 host->cmd_flags |= CARD_INT; 440 441 rc = tifm_ms_check_status(host); 442 443 } 444 445 writel(TIFM_MS_SYS_INTCLR | readl(sock->addr + SOCK_MS_SYSTEM), 446 sock->addr + SOCK_MS_SYSTEM); 447 448 if (!rc) 449 tifm_ms_complete_cmd(host); 450 451 spin_unlock(&sock->lock); 452 return; 453 } 454 455 static void tifm_ms_req_tasklet(unsigned long data) 456 { 457 struct memstick_host *msh = (struct memstick_host *)data; 458 struct tifm_ms *host = memstick_priv(msh); 459 struct tifm_dev *sock = host->dev; 460 unsigned long flags; 461 int rc; 462 463 spin_lock_irqsave(&sock->lock, flags); 464 if (!host->req) { 465 if (host->eject) { 466 do { 467 rc = memstick_next_req(msh, &host->req); 468 if (!rc) 469 host->req->error = -ETIME; 470 } while (!rc); 471 spin_unlock_irqrestore(&sock->lock, flags); 472 return; 473 } 474 475 do { 476 rc = memstick_next_req(msh, &host->req); 477 } while (!rc && tifm_ms_issue_cmd(host)); 478 } 479 spin_unlock_irqrestore(&sock->lock, flags); 480 } 481 482 static void tifm_ms_dummy_submit(struct memstick_host *msh) 483 { 484 return; 485 } 486 487 static void tifm_ms_submit_req(struct memstick_host *msh) 488 { 489 struct tifm_ms *host = memstick_priv(msh); 490 491 tasklet_schedule(&host->notify); 492 } 493 494 static int tifm_ms_set_param(struct memstick_host *msh, 495 enum memstick_param param, 496 int value) 497 { 498 struct tifm_ms *host = memstick_priv(msh); 499 struct tifm_dev *sock = host->dev; 500 501 switch (param) { 502 case MEMSTICK_POWER: 503 /* also affected by media detection mechanism */ 504 if (value == MEMSTICK_POWER_ON) { 505 host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI; 506 writel(TIFM_MS_SYS_RESET, sock->addr + SOCK_MS_SYSTEM); 507 writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, 508 sock->addr + SOCK_MS_SYSTEM); 509 writel(0xffffffff, sock->addr + SOCK_MS_STATUS); 510 } else if (value == MEMSTICK_POWER_OFF) { 511 writel(TIFM_MS_SYS_FCLR | TIFM_MS_SYS_INTCLR, 512 sock->addr + SOCK_MS_SYSTEM); 513 writel(0xffffffff, sock->addr + SOCK_MS_STATUS); 514 } else 515 return -EINVAL; 516 break; 517 case MEMSTICK_INTERFACE: 518 if (value == MEMSTICK_SERIAL) { 519 host->mode_mask = TIFM_MS_SYS_SRAC | TIFM_MS_SYS_REI; 520 writel((~TIFM_CTRL_FAST_CLK) 521 & readl(sock->addr + SOCK_CONTROL), 522 sock->addr + SOCK_CONTROL); 523 } else if (value == MEMSTICK_PAR4) { 524 host->mode_mask = 0; 525 writel(TIFM_CTRL_FAST_CLK 526 | readl(sock->addr + SOCK_CONTROL), 527 sock->addr + SOCK_CONTROL); 528 } else 529 return -EINVAL; 530 break; 531 } 532 533 return 0; 534 } 535 536 static void tifm_ms_abort(struct timer_list *t) 537 { 538 struct tifm_ms *host = from_timer(host, t, timer); 539 540 dev_dbg(&host->dev->dev, "status %x\n", 541 readl(host->dev->addr + SOCK_MS_STATUS)); 542 printk(KERN_ERR 543 "%s : card failed to respond for a long period of time " 544 "(%x, %x)\n", 545 dev_name(&host->dev->dev), host->req ? host->req->tpc : 0, 546 host->cmd_flags); 547 548 tifm_eject(host->dev); 549 } 550 551 static int tifm_ms_probe(struct tifm_dev *sock) 552 { 553 struct memstick_host *msh; 554 struct tifm_ms *host; 555 int rc = -EIO; 556 557 if (!(TIFM_SOCK_STATE_OCCUPIED 558 & readl(sock->addr + SOCK_PRESENT_STATE))) { 559 printk(KERN_WARNING "%s : card gone, unexpectedly\n", 560 dev_name(&sock->dev)); 561 return rc; 562 } 563 564 msh = memstick_alloc_host(sizeof(struct tifm_ms), &sock->dev); 565 if (!msh) 566 return -ENOMEM; 567 568 host = memstick_priv(msh); 569 tifm_set_drvdata(sock, msh); 570 host->dev = sock; 571 host->timeout_jiffies = msecs_to_jiffies(1000); 572 573 timer_setup(&host->timer, tifm_ms_abort, 0); 574 tasklet_init(&host->notify, tifm_ms_req_tasklet, (unsigned long)msh); 575 576 msh->request = tifm_ms_submit_req; 577 msh->set_param = tifm_ms_set_param; 578 sock->card_event = tifm_ms_card_event; 579 sock->data_event = tifm_ms_data_event; 580 if (tifm_has_ms_pif(sock)) 581 msh->caps |= MEMSTICK_CAP_PAR4; 582 583 rc = memstick_add_host(msh); 584 if (!rc) 585 return 0; 586 587 memstick_free_host(msh); 588 return rc; 589 } 590 591 static void tifm_ms_remove(struct tifm_dev *sock) 592 { 593 struct memstick_host *msh = tifm_get_drvdata(sock); 594 struct tifm_ms *host = memstick_priv(msh); 595 int rc = 0; 596 unsigned long flags; 597 598 msh->request = tifm_ms_dummy_submit; 599 tasklet_kill(&host->notify); 600 spin_lock_irqsave(&sock->lock, flags); 601 host->eject = 1; 602 if (host->req) { 603 del_timer(&host->timer); 604 writel(TIFM_FIFO_INT_SETALL, 605 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); 606 writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); 607 if (host->use_dma) 608 tifm_unmap_sg(sock, &host->req->sg, 1, 609 host->req->data_dir == READ 610 ? DMA_TO_DEVICE 611 : DMA_FROM_DEVICE); 612 host->req->error = -ETIME; 613 614 do { 615 rc = memstick_next_req(msh, &host->req); 616 if (!rc) 617 host->req->error = -ETIME; 618 } while (!rc); 619 } 620 spin_unlock_irqrestore(&sock->lock, flags); 621 622 memstick_remove_host(msh); 623 memstick_free_host(msh); 624 } 625 626 #ifdef CONFIG_PM 627 628 static int tifm_ms_suspend(struct tifm_dev *sock, pm_message_t state) 629 { 630 struct memstick_host *msh = tifm_get_drvdata(sock); 631 632 memstick_suspend_host(msh); 633 return 0; 634 } 635 636 static int tifm_ms_resume(struct tifm_dev *sock) 637 { 638 struct memstick_host *msh = tifm_get_drvdata(sock); 639 640 memstick_resume_host(msh); 641 return 0; 642 } 643 644 #else 645 646 #define tifm_ms_suspend NULL 647 #define tifm_ms_resume NULL 648 649 #endif /* CONFIG_PM */ 650 651 static struct tifm_device_id tifm_ms_id_tbl[] = { 652 { TIFM_TYPE_MS }, { 0 } 653 }; 654 655 static struct tifm_driver tifm_ms_driver = { 656 .driver = { 657 .name = DRIVER_NAME, 658 .owner = THIS_MODULE 659 }, 660 .id_table = tifm_ms_id_tbl, 661 .probe = tifm_ms_probe, 662 .remove = tifm_ms_remove, 663 .suspend = tifm_ms_suspend, 664 .resume = tifm_ms_resume 665 }; 666 667 static int __init tifm_ms_init(void) 668 { 669 return tifm_register_driver(&tifm_ms_driver); 670 } 671 672 static void __exit tifm_ms_exit(void) 673 { 674 tifm_unregister_driver(&tifm_ms_driver); 675 } 676 677 MODULE_AUTHOR("Alex Dubov"); 678 MODULE_DESCRIPTION("TI FlashMedia MemoryStick driver"); 679 MODULE_LICENSE("GPL"); 680 MODULE_DEVICE_TABLE(tifm, tifm_ms_id_tbl); 681 682 module_init(tifm_ms_init); 683 module_exit(tifm_ms_exit); 684