8253xnet.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:16k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* -*- linux-c -*- */
  2. /* 
  3.  * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version
  8.  * 2 of the License, or (at your option) any later version.
  9.  *
  10.  **/
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/pci.h>
  14. #include <linux/stddef.h>
  15. #include <linux/string.h>
  16. #include <linux/sockios.h>
  17. #include <asm/io.h>
  18. #include <asm/byteorder.h>
  19. #include <asm/pgtable.h>
  20. #include <linux/skbuff.h>
  21. #include <linux/if_arp.h>
  22. #include <linux/fs.h>
  23. #include <linux/sched.h>
  24. #include <asm/uaccess.h>
  25. #include <linux/version.h>
  26. #include <linux/etherdevice.h>
  27. #include "Reg9050.h"
  28. #include "8253xctl.h"
  29. #include "ring.h"
  30. #include "8253x.h"
  31. #include "crc32dcl.h"
  32. /* turns network packet into a pseudoethernet */
  33. /* frame -- does ethernet stuff that 8253x does */
  34. /* not do -- makes minimum  64 bytes add crc, etc*/
  35. int 
  36. sab8253xn_write2(struct sk_buff *skb, struct net_device *dev)
  37. {
  38. size_t cnt;
  39. unsigned int flags;
  40. SAB_PORT *priv = (SAB_PORT*) dev->priv;
  41. struct sk_buff *substitute;
  42. #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
  43. if(dev->tbusy != 0) /* something of an error */
  44. {
  45. ++(priv->Counters.tx_drops);
  46. dev_kfree_skb_any(skb);
  47. return -EBUSY; /* only during release */
  48. }
  49. #endif
  50. if(priv->active2.transmit == NULL)
  51. {
  52. return -ENOMEM;
  53. }
  54. DEBUGPRINT((KERN_ALERT "sab8253x: sending IP packet(bytes):n"));
  55. DEBUGPRINT((KERN_ALERT "sab8253x: start address is %p.n", skb->data));
  56. cnt = skb->tail - skb->data;
  57. cnt = MIN(cnt, sab8253xn_rbufsize);
  58. if(cnt < ETH_ZLEN)
  59. {
  60. if((skb->end - skb->data) >= ETH_ZLEN)
  61. {
  62. skb->tail = (skb->data + ETH_ZLEN);
  63. cnt = ETH_ZLEN;
  64. }
  65. else
  66. {
  67. substitute = dev_alloc_skb(ETH_ZLEN);
  68. if(substitute == NULL)
  69. {
  70. dev_kfree_skb_any(skb);
  71. return 0;
  72. }
  73. substitute->tail = (substitute->data + ETH_ZLEN);
  74. memcpy(substitute->data, skb->data, cnt);
  75. cnt = ETH_ZLEN;
  76. dev_kfree_skb_any(skb);
  77. skb = substitute;
  78. }
  79. }
  80. save_flags(flags); cli();
  81. if((priv->active2.transmit->Count & OWNER) == OWN_SAB)
  82. {
  83. ++(priv->Counters.tx_drops);
  84. #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
  85. dev->tbusy = 1;
  86. #else
  87. netif_stop_queue (dev);
  88. #endif
  89. priv->tx_full = 1;
  90. restore_flags(flags);
  91. return 1;
  92. }
  93. restore_flags(flags);
  94. #ifndef FREEINTERRUPT
  95. if(priv->active2.transmit->HostVaddr != NULL)
  96. {
  97. register RING_DESCRIPTOR *freeme;
  98. freeme = priv->active2.transmit;
  99. do
  100. {
  101. skb_unlink((struct sk_buff*)freeme->HostVaddr);
  102. dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr);
  103. freeme->HostVaddr = NULL;
  104. freeme = (RING_DESCRIPTOR*) freeme->VNext;
  105. }
  106. while(((freeme->Count & OWNER) != OWN_SAB) &&
  107.       (freeme->HostVaddr != NULL));
  108. }
  109. #endif
  110. dev->trans_start = jiffies;
  111. skb_queue_head(priv->sab8253xbuflist, skb);
  112. priv->active2.transmit->HostVaddr = skb;
  113. priv->active2.transmit->sendcrc = 1;
  114. priv->active2.transmit->crcindex = 0;
  115. priv->active2.transmit->crc = fn_calc_memory_crc32(skb->data, cnt);
  116. priv->active2.transmit->Count = (OWN_SAB|cnt); /* must be this order */
  117. priv->active2.transmit = 
  118. (RING_DESCRIPTOR*) priv->active2.transmit->VNext;
  119. priv->Counters.transmitbytes += cnt;
  120. sab8253x_start_txS(priv);
  121. return 0;
  122. }
  123. /* packetizes the received character */
  124. /* stream */
  125. static void sab8253x_receive_charsN(struct sab_port *port,
  126.     union sab8253x_irq_status *stat)
  127. {
  128. unsigned char buf[32];
  129. int free_fifo = 0;
  130. int reset_fifo = 0;
  131. int msg_done = 0;
  132. int msg_bad = 0;
  133. int count = 0;
  134. int total_size = 0;
  135. int rstatus = 0;
  136. struct sk_buff *skb;
  137. /* Read number of BYTES (Character + Status) available. */
  138. if((stat->images[ISR1_IDX] & SAB82532_ISR1_RDO) || (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) )
  139. {
  140. ++msg_bad;
  141. ++free_fifo;
  142. ++reset_fifo;
  143. }
  144. else
  145. {
  146. if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) 
  147. {
  148. count = port->recv_fifo_size;
  149. ++free_fifo;
  150. }
  151. if (stat->images[ISR0_IDX] & SAB82532_ISR0_RME) 
  152. {
  153. count = READB(port,rbcl);
  154. count &= (port->recv_fifo_size - 1);
  155. ++msg_done;
  156. ++free_fifo;
  157. total_size = READB(port, rbch);
  158. if(total_size & SAB82532_RBCH_OV)
  159. {
  160. msg_bad++;
  161. }
  162. rstatus = READB(port, rsta);
  163. if((rstatus & SAB82532_RSTA_VFR) == 0)
  164. {
  165. msg_bad++;
  166. }
  167. if(rstatus & SAB82532_RSTA_RDO)
  168. {
  169. msg_bad++;
  170. }
  171. if((rstatus & SAB82532_RSTA_CRC) == 0)
  172. {
  173. msg_bad++;
  174. }
  175. if(rstatus & SAB82532_RSTA_RAB)
  176. {
  177. msg_bad++;
  178. }
  179. }
  180. }
  181. /* Read the FIFO. */
  182. (*port->readfifo)(port, buf, count);
  183. /* Issue Receive Message Complete command. */
  184. if (free_fifo) 
  185. {
  186. sab8253x_cec_wait(port);
  187. WRITEB(port, cmdr, SAB82532_CMDR_RMC);
  188. }
  189. if(reset_fifo)
  190. {
  191. sab8253x_cec_wait(port);
  192. WRITEB(port, cmdr, SAB82532_CMDR_RHR);
  193. }
  194. if(port->active2.receive == NULL)
  195. {
  196. return;
  197. }
  198. if(msg_bad)
  199. {
  200. ++(port->Counters.rx_drops);
  201. port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; /* clear the buffer */
  202. port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB;
  203. return;
  204. }
  205. memcpy(port->active2.receive->HostVaddr->tail, buf, count);
  206. port->active2.receive->HostVaddr->tail += count;
  207. if(msg_done)
  208. {
  209. port->active2.receive->Count = 
  210. (port->active2.receive->HostVaddr->tail - port->active2.receive->HostVaddr->data);
  211. if((port->active2.receive->Count < (ETH_ZLEN+4+3)) || /* 4 is the CRC32 size 3 bytes from the SAB part */
  212.    (skb = dev_alloc_skb(sab8253xn_rbufsize), skb == NULL))
  213. {
  214. ++(port->Counters.rx_drops);
  215. port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; 
  216. /* clear the buffer */
  217. port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB;
  218. }
  219. else
  220. {
  221. port->active2.receive->Count -= 3;
  222. port->active2.receive->HostVaddr->len = port->active2.receive->Count;
  223. port->active2.receive->HostVaddr->pkt_type = PACKET_HOST;
  224. port->active2.receive->HostVaddr->dev = port->dev;
  225. port->active2.receive->HostVaddr->protocol = 
  226. eth_type_trans(port->active2.receive->HostVaddr, port->dev);
  227. port->active2.receive->HostVaddr->tail -= 3;
  228. ++(port->Counters.receivepacket);
  229. port->Counters.receivebytes += port->active2.receive->Count;
  230. skb_unlink(port->active2.receive->HostVaddr);
  231. netif_rx(port->active2.receive->HostVaddr);
  232. skb_queue_head(port->sab8253xbuflist, skb);
  233. port->active2.receive->HostVaddr = skb;
  234. port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB;
  235. }
  236. }
  237. }
  238. static void sab8253x_check_statusN(struct sab_port *port,
  239.    union sab8253x_irq_status *stat)
  240. {
  241. int modem_change = 0;
  242. mctlsig_t         *sig;
  243. if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) 
  244. {
  245. port->icount.buf_overrun++;
  246. }
  247. /* Checking DCD */
  248. sig = &port->dcd;
  249. if (stat->images[sig->irq] & sig->irqmask) 
  250. {
  251. sig->val = ISON(port,dcd);
  252. port->icount.dcd++;
  253. modem_change++;
  254. }
  255. /* Checking CTS */
  256. sig = &port->cts;
  257. if (stat->images[sig->irq] & sig->irqmask) 
  258. {
  259. sig->val = ISON(port,cts);
  260. port->icount.cts++;
  261. modem_change++;
  262. }
  263. /* Checking DSR */
  264. sig = &port->dsr;
  265. if (stat->images[sig->irq] & sig->irqmask) 
  266. {
  267. sig->val = ISON(port,dsr);
  268. port->icount.dsr++;
  269. modem_change++;
  270. }
  271. if (modem_change)
  272. {
  273. wake_up_interruptible(&port->delta_msr_wait);
  274. }
  275. sig = &port->dcd;
  276. if ((port->flags & FLAG8253X_CHECK_CD) &&
  277.     (stat->images[sig->irq] & sig->irqmask)) 
  278. {
  279. if (sig->val)
  280. {
  281. netif_carrier_on(port->dev);
  282. }
  283. else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) &&
  284.    (port->flags & FLAG8253X_CALLOUT_NOHUP))) 
  285. {
  286. netif_carrier_off(port->dev);
  287. }
  288. }
  289. #if 0 /* need to think about CTS/RTS stuff for a network driver */
  290. sig = &port->cts;
  291. if (port->flags & FLAG8253X_CTS_FLOW) 
  292. { /* not setting this yet */
  293. if (port->tty->hw_stopped) 
  294. {
  295. if (sig->val) 
  296. {
  297. port->tty->hw_stopped = 0;
  298. sab8253x_sched_event(port, RS_EVENT_WRITE_WAKEUP);
  299. port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR);
  300. WRITEB(port, imr1, port->interrupt_mask1);
  301. sab8253x_start_txS(port);
  302. }
  303. else 
  304. {
  305. if (!(sig->val)) 
  306. {
  307. port->tty->hw_stopped = 1;
  308. }
  309. }
  310. }
  311. #endif
  312. }
  313. static void Sab8253xCollectStats(struct net_device *dev)
  314. {
  315. struct net_device_stats *statsp = 
  316. &((SAB_PORT*) dev->priv)->stats;
  317. memset(statsp, 0, sizeof(struct net_device_stats));
  318. statsp->rx_packets +=
  319. ((SAB_PORT*)dev->priv)->Counters.receivepacket;
  320. statsp->tx_packets +=
  321. ((SAB_PORT*)dev->priv)->Counters.transmitpacket;
  322. statsp->tx_dropped += 
  323. ((SAB_PORT*)dev->priv)->Counters.tx_drops;
  324. statsp->rx_dropped += 
  325. ((SAB_PORT*)dev->priv)->Counters.rx_drops;
  326. }
  327. struct net_device_stats *sab8253xn_stats(struct net_device *dev)
  328. {
  329. SAB_PORT *priv = (SAB_PORT*) dev->priv;
  330. Sab8253xCollectStats(dev);
  331. return &priv->stats;
  332. }
  333. /* minimal ioctls -- more to be added later */
  334. int sab8253xn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  335. {
  336. SAB_PORT *priv = (SAB_PORT*) dev->priv;
  337. switch(cmd)
  338. {
  339. case SAB8253XCLEARCOUNTERS:
  340. memset(&priv->Counters, 0, sizeof(struct counters));
  341. break;
  342. default:
  343. break;
  344. }
  345. return 0;
  346. }
  347. #if 0
  348. static int sab8253x_block_til_readyN(SAB_PORT *port)
  349. {
  350. DECLARE_WAITQUEUE(wait, current);
  351. int retval;
  352. int do_clocal = 0;
  353. unsigned long flags;
  354. /*
  355.  * If the device is in the middle of being closed, then block
  356.  * until it's done, and then try again.
  357.  */
  358. if (port->flags & FLAG8253X_CLOSING)
  359. {
  360. if (port->flags & FLAG8253X_CLOSING)
  361. {
  362. interruptible_sleep_on(&port->close_wait);
  363. }
  364. #ifdef SERIAL_DO_RESTART
  365. if (port->flags & FLAG8253X_HUP_NOTIFY)
  366. {
  367. return -EAGAIN;
  368. }
  369. else
  370. {
  371. return -ERESTARTSYS;
  372. }
  373. #else
  374. return -EAGAIN;
  375. #endif
  376. }
  377. /*
  378.  * this is not a callout device
  379.  */
  380. /* suppose callout active */
  381. if (port->flags & FLAG8253X_CALLOUT_ACTIVE) 
  382. {
  383. if (port->normal_termios.c_cflag & CLOCAL)
  384. {
  385. do_clocal = 1;
  386. }
  387. /*
  388.  * Block waiting for the carrier detect and the line to become
  389.  * free (i.e., not in use by the callout).  While we are in
  390.  * this loop, port->count is dropped by one, so that
  391.  * sab8253x_close() knows when to free things.  We restore it upon
  392.  * exit, either normal or abnormal.
  393.  */
  394. retval = 0;
  395. add_wait_queue(&port->open_wait, &wait);
  396. port->blocked_open++;
  397. while (1) 
  398. {
  399. save_flags(flags); cli();
  400. if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE))
  401. {
  402. RAISE(port,dtr);
  403. RAISE(port,rts); /* maybe not correct for sync */
  404. /*
  405.  * ??? Why changing the mode here? 
  406.  *  port->regs->rw.mode |= SAB82532_MODE_FRTS;
  407.  *  port->regs->rw.mode &= ~(SAB82532_MODE_RTS);
  408.  */
  409. }
  410. restore_flags(flags);
  411. current->state = TASK_INTERRUPTIBLE;
  412. if (!(port->flags & FLAG8253X_INITIALIZED)) 
  413. {
  414. #ifdef SERIAL_DO_RESTART
  415. if (port->flags & FLAG8253X_HUP_NOTIFY)
  416. {
  417. retval = -EAGAIN;
  418. }
  419. else
  420. {
  421. retval = -ERESTARTSYS;
  422. }
  423. #else
  424. retval = -EAGAIN;
  425. #endif
  426. break;
  427. }
  428. if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE) &&
  429.     !(port->flags & FLAG8253X_CLOSING) &&
  430.     (do_clocal || ISON(port,dcd))) 
  431. {
  432. break;
  433. }
  434. #ifdef DEBUG_OPEN
  435. printk("block_til_readyN:2 flags = 0x%xn",port->flags);
  436. #endif
  437. if (signal_pending(current)) 
  438. {
  439. retval = -ERESTARTSYS;
  440. break;
  441. }
  442. schedule();
  443. }
  444. current->state = TASK_RUNNING;
  445. remove_wait_queue(&port->open_wait, &wait);
  446. port->blocked_open--;
  447. if (retval)
  448. {
  449. return retval;
  450. }
  451. port->flags |= FLAG8253X_NORMAL_ACTIVE; /* is this a good flag? */
  452. return 0;
  453. }
  454. #endif
  455. int sab8253x_startupN(struct sab_port *port)
  456. {
  457. unsigned long flags;
  458. int retval = 0;
  459. save_flags(flags); cli();
  460. if (port->flags & FLAG8253X_INITIALIZED) 
  461. {
  462. goto errout;
  463. }
  464. if (!port->regs) 
  465. {
  466. retval = -ENODEV;
  467. goto errout;
  468. }
  469. /*
  470.  * Initialize the Hardware
  471.  */
  472. sab8253x_init_lineS(port); /* nothing in this function
  473.  * refers to tty structure */
  474. /* Activate RTS */
  475. RAISE(port,rts);
  476. /* Activate DTR */
  477. RAISE(port,dtr);
  478. /*
  479.  * Initialize the modem signals values
  480.  */
  481. port->dcd.val=ISON(port,dcd);
  482. port->cts.val=ISON(port,cts);
  483. port->dsr.val=ISON(port,dsr);
  484. /*
  485.  * Finally, enable interrupts
  486.  */
  487. port->interrupt_mask0 = SAB82532_IMR0_RFS | SAB82532_IMR0_PCE |
  488. SAB82532_IMR0_PLLA | SAB82532_IMR0_RSC | SAB82532_IMR0_CDSC;
  489. /*((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? SAB82532_IMR0_CDSC : 0); */
  490. WRITEB(port,imr0,port->interrupt_mask0);
  491. port->interrupt_mask1 = SAB82532_IMR1_EOP | SAB82532_IMR1_XMR |
  492. SAB82532_IMR1_TIN | SAB82532_IMR1_XPR;
  493. WRITEB(port, imr1, port->interrupt_mask1);
  494. port->all_sent = 1;
  495. /*
  496.  * and set the speed of the serial port
  497.  */
  498. sab8253x_change_speedN(port);
  499. port->flags |= FLAG8253X_INITIALIZED; /* bad name for indicating to other functionalities status */
  500. port->receive_chars = sab8253x_receive_charsN;
  501. port->transmit_chars = sab8253x_transmit_charsS;
  502. port->check_status = sab8253x_check_statusN;
  503. port->receive_test = (SAB82532_ISR0_RME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF);
  504. port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_RDO | SAB82532_ISR1_XPR |
  505.        SAB82532_ISR1_XDU | SAB82532_ISR1_CSC);
  506. port->check_status_test = (SAB82532_ISR1_CSC);
  507. /*((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? 0 : SAB82532_ISR0_CDSC));*/
  508. restore_flags(flags);
  509. return 0;
  510.  errout:
  511. restore_flags(flags);
  512. return retval;
  513. }
  514. int sab8253xn_open(struct net_device *dev)
  515. {
  516. unsigned int retval;
  517. SAB_PORT *priv = (SAB_PORT*) dev->priv;
  518. if(priv->function != FUNCTION_NR)
  519. {
  520. return -ENODEV; /* only allowed if there are no restrictions on the port */
  521. }
  522. if(priv->flags & FLAG8253X_CLOSING) /* try again after the TTY close finishes */
  523. {
  524. #ifdef SERIAL_DO_RESTART
  525. return ((priv->flags & FLAG8253X_HUP_NOTIFY) ?
  526. -EAGAIN : -ERESTARTSYS); /* The ifconfig UP will just fail */
  527. #else
  528. return -EAGAIN;
  529. #endif
  530. }
  531. /*
  532.  * Maybe start up serial port -- may already be running a TTY
  533.  */
  534. if(priv->flags & FLAG8253X_NORMAL_ACTIVE) /* probably should be a test open at all */
  535. {
  536. return -EBUSY; /* can't reopen in NET */
  537. }
  538. if(Sab8253xSetUpLists(priv))
  539. {
  540. return -ENODEV;
  541. }
  542. if(Sab8253xInitDescriptors2(priv, sab8253xn_listsize, sab8253xn_rbufsize))
  543. {
  544. Sab8253xCleanUpTransceiveN(priv);
  545. return -ENODEV;
  546. }
  547. netif_carrier_off(dev);
  548. priv->open_type = OPEN_SYNC_NET;
  549. priv->tty = 0;
  550. retval = sab8253x_startupN(priv);
  551. if (retval)
  552. {
  553. Sab8253xCleanUpTransceiveN(priv);
  554. return retval;
  555. }
  556. priv->flags |= FLAG8253X_NETWORK; /* flag the call out driver that it has to reinitialize the port */
  557. priv->tx_full = 0;
  558. #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
  559. dev->start = 1;
  560. dev->tbusy = 0;
  561. #else
  562. netif_start_queue(dev);
  563. #endif
  564. priv->flags |= FLAG8253X_NORMAL_ACTIVE; /* is this a good flag? */
  565. MOD_INC_USE_COUNT;
  566. return 0; /* success */
  567. }
  568. /* stop the PPC, free all skbuffers */
  569. int sab8253xn_release(struct net_device *dev) /* stop */
  570. {
  571. SAB_PORT *priv = (SAB_PORT*) dev->priv;
  572. unsigned long flags;
  573. printk(KERN_ALERT "sab8253xn: network interface going down.n");
  574. save_flags(flags); cli();
  575. #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
  576. dev->start = 0;
  577. dev->tbusy = 1;
  578. #else
  579. netif_stop_queue (dev);
  580. #endif
  581. sab8253x_shutdownN(priv);
  582. Sab8253xCleanUpTransceiveN(priv);
  583. netif_carrier_off(dev);
  584. priv->flags &= ~FLAG8253X_NETWORK; 
  585. priv->flags &= ~(FLAG8253X_NORMAL_ACTIVE|/*FLAG8253X_CALLOUT_ACTIVE|*/
  586.  FLAG8253X_CLOSING);
  587. priv->open_type = OPEN_NOT;
  588. MOD_DEC_USE_COUNT;
  589. restore_flags(flags);
  590. return 0;
  591. }
  592. SAB_PORT *current_sab_port = NULL;
  593. int sab8253xn_init(struct net_device *dev)
  594. {
  595. SAB_PORT *priv;
  596. printk(KERN_ALERT "sab8253xn: initializing SAB8253X network driver instance.n");
  597. priv = current_sab_port;
  598. dev->priv = priv;
  599. if(dev->priv == NULL)
  600. {
  601. printk(KERN_ALERT "sab8253xn: could not find active port!n");
  602. return -ENOMEM;
  603. }
  604. priv->dev = dev;
  605. ether_setup(dev);
  606. dev->irq = priv->irq;
  607. dev->hard_start_xmit = sab8253xn_write2;
  608. dev->do_ioctl = sab8253xn_ioctl;
  609. dev->open = sab8253xn_open;
  610. dev->stop = sab8253xn_release;
  611. dev->get_stats = sab8253xn_stats;
  612. dev->base_addr = (unsigned) priv->regs;
  613. /* should I do a request region here */
  614. priv->next_dev = Sab8253xRoot;
  615. Sab8253xRoot = dev;
  616. return 0;
  617. }