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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */
  2.  
  3. /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
  4.  
  5. #include <linux/module.h>
  6. #include <linux/sched.h> /* for jiffies */
  7. #include <linux/mm.h>
  8. #include <linux/errno.h>
  9. #include <linux/atmdev.h>
  10. #include <linux/sonet.h>
  11. #include <linux/init.h>
  12. #include <asm/uaccess.h>
  13. #include <asm/atomic.h>
  14. #include "uPD98402.h"
  15. #if 0
  16. #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
  17. #else
  18. #define DPRINTK(format,args...)
  19. #endif
  20. struct uPD98402_priv {
  21. struct k_sonet_stats sonet_stats;/* link diagnostics */
  22. unsigned char framing; /* SONET/SDH framing */
  23. int loop_mode; /* loopback mode */
  24. };
  25. #define PRIV(dev) ((struct uPD98402_priv *) dev->phy_data)
  26. #define PUT(val,reg) dev->ops->phy_put(dev,val,uPD98402_##reg)
  27. #define GET(reg) dev->ops->phy_get(dev,uPD98402_##reg)
  28. static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero)
  29. {
  30. struct sonet_stats tmp;
  31.   int error = 0;
  32. atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs);
  33. sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
  34. if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
  35. if (zero && !error) {
  36. /* unused fields are reported as -1, but we must not "adjust"
  37.    them */
  38. tmp.corr_hcs = tmp.tx_cells = tmp.rx_cells = 0;
  39. sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
  40. }
  41. return error ? -EFAULT : 0;
  42. }
  43. static int set_framing(struct atm_dev *dev,unsigned char framing)
  44. {
  45. static const unsigned char sonet[] = { 1,2,3,0 };
  46. static const unsigned char sdh[] = { 1,0,0,2 };
  47. const char *set;
  48. unsigned long flags;
  49.  
  50. switch (framing) {
  51. case SONET_FRAME_SONET:
  52. set = sonet;
  53. break;
  54. case SONET_FRAME_SDH:
  55. set = sdh;
  56. break;
  57. default:
  58. return -EINVAL;
  59. }
  60. save_flags(flags);
  61. cli();
  62. PUT(set[0],C11T);
  63. PUT(set[1],C12T);
  64. PUT(set[2],C13T);
  65. PUT((GET(MDR) & ~uPD98402_MDR_SS_MASK) | (set[3] <<
  66.     uPD98402_MDR_SS_SHIFT),MDR);
  67. restore_flags(flags);
  68. return 0;
  69. }
  70. static int get_sense(struct atm_dev *dev,u8 *arg)
  71. {
  72. unsigned long flags;
  73. unsigned char s[3];
  74. save_flags(flags);
  75. cli();
  76. s[0] = GET(C11R);
  77. s[1] = GET(C12R);
  78. s[2] = GET(C13R);
  79. restore_flags(flags);
  80. return (put_user(s[0], arg) || put_user(s[1], arg+1) ||
  81.     put_user(s[2], arg+2) || put_user(0xff, arg+3) ||
  82.     put_user(0xff, arg+4) || put_user(0xff, arg+5)) ? -EFAULT : 0;
  83. }
  84. static int set_loopback(struct atm_dev *dev,int mode)
  85. {
  86. unsigned char mode_reg;
  87. mode_reg = GET(MDR) & ~(uPD98402_MDR_TPLP | uPD98402_MDR_ALP |
  88.     uPD98402_MDR_RPLP);
  89. switch (__ATM_LM_XTLOC(mode)) {
  90. case __ATM_LM_NONE:
  91. break;
  92. case __ATM_LM_PHY:
  93. mode_reg |= uPD98402_MDR_TPLP;
  94. break;
  95. case __ATM_LM_ATM:
  96. mode_reg |= uPD98402_MDR_ALP;
  97. break;
  98. default:
  99. return -EINVAL;
  100. }
  101. switch (__ATM_LM_XTRMT(mode)) {
  102. case __ATM_LM_NONE:
  103. break;
  104. case __ATM_LM_PHY:
  105. mode_reg |= uPD98402_MDR_RPLP;
  106. break;
  107. default:
  108. return -EINVAL;
  109. }
  110. PUT(mode_reg,MDR);
  111. PRIV(dev)->loop_mode = mode;
  112. return 0;
  113. }
  114. static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
  115. {
  116. switch (cmd) {
  117. case SONET_GETSTATZ:
  118.                 case SONET_GETSTAT:
  119. return fetch_stats(dev,(struct sonet_stats *) arg,
  120.     cmd == SONET_GETSTATZ);
  121. case SONET_SETFRAMING:
  122. return set_framing(dev,(int) (long) arg);
  123. case SONET_GETFRAMING:
  124. return put_user(PRIV(dev)->framing,(int *) arg) ?
  125.     -EFAULT : 0;
  126. case SONET_GETFRSENSE:
  127. return get_sense(dev,arg);
  128. case ATM_SETLOOP:
  129. return set_loopback(dev,(int) (long) arg);
  130. case ATM_GETLOOP:
  131. return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
  132.     -EFAULT : 0;
  133. case ATM_QUERYLOOP:
  134. return put_user(ATM_LM_LOC_PHY | ATM_LM_LOC_ATM |
  135.     ATM_LM_RMT_PHY,(int *) arg) ? -EFAULT : 0;
  136. default:
  137. return -ENOIOCTLCMD;
  138. }
  139. }
  140. #define ADD_LIMITED(s,v) 
  141.     { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); 
  142.     if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) 
  143. atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); }
  144. static void stat_event(struct atm_dev *dev)
  145. {
  146. unsigned char events;
  147. events = GET(PCR);
  148. if (events & uPD98402_PFM_PFEB) ADD_LIMITED(path_febe,PFECB);
  149. if (events & uPD98402_PFM_LFEB) ADD_LIMITED(line_febe,LECCT);
  150. if (events & uPD98402_PFM_B3E) ADD_LIMITED(path_bip,B3ECT);
  151. if (events & uPD98402_PFM_B2E) ADD_LIMITED(line_bip,B2ECT);
  152. if (events & uPD98402_PFM_B1E) ADD_LIMITED(section_bip,B1ECT);
  153. }
  154. #undef ADD_LIMITED
  155. static void uPD98402_int(struct atm_dev *dev)
  156. {
  157. static unsigned long silence = 0;
  158. unsigned char reason;
  159. while ((reason = GET(PICR))) {
  160. if (reason & uPD98402_INT_LOS)
  161. printk(KERN_NOTICE "%s(itf %d): signal lostn",
  162.     dev->type,dev->number);
  163. if (reason & uPD98402_INT_PFM) stat_event(dev);
  164. if (reason & uPD98402_INT_PCO) {
  165. (void) GET(PCOCR); /* clear interrupt cause */
  166. atomic_add(GET(HECCT),
  167.     &PRIV(dev)->sonet_stats.uncorr_hcs);
  168. }
  169. if ((reason & uPD98402_INT_RFO) && 
  170.     (time_after(jiffies, silence) || silence == 0)) {
  171. printk(KERN_WARNING "%s(itf %d): uPD98402 receive "
  172.     "FIFO overflown",dev->type,dev->number);
  173. silence = (jiffies+HZ/2)|1;
  174. }
  175. }
  176. }
  177. static int uPD98402_start(struct atm_dev *dev)
  178. {
  179. DPRINTK("phy_startn");
  180. if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
  181. return -ENOMEM;
  182. memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
  183. (void) GET(PCR); /* clear performance events */
  184. PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */
  185. (void) GET(PCOCR); /* clear overflows */
  186. PUT(~uPD98402_PCO_HECC,PCOMR);
  187. (void) GET(PICR); /* clear interrupts */
  188. PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO |
  189.   uPD98402_INT_LOS),PIMR); /* enable them */
  190. (void) fetch_stats(dev,NULL,1); /* clear kernel counters */
  191. atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1);
  192. atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1);
  193. atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1);
  194. return 0;
  195. }
  196. static int uPD98402_stop(struct atm_dev *dev)
  197. {
  198. /* let SAR driver worry about stopping interrupts */
  199. kfree(PRIV(dev));
  200. return 0;
  201. }
  202. static const struct atmphy_ops uPD98402_ops = {
  203. start: uPD98402_start,
  204. ioctl: uPD98402_ioctl,
  205. interrupt: uPD98402_int,
  206. stop: uPD98402_stop,
  207. };
  208. int __init uPD98402_init(struct atm_dev *dev)
  209. {
  210. DPRINTK("phy_initn");
  211. dev->phy = &uPD98402_ops;
  212. return 0;
  213. }
  214. #ifdef MODULE
  215. MODULE_LICENSE("GPL");
  216. EXPORT_SYMBOL(uPD98402_init);
  217.  
  218. int init_module(void)
  219. {
  220. MOD_INC_USE_COUNT;
  221. return 0;
  222. }
  223. void cleanup_module(void)
  224. {
  225. /* Nay */
  226. }
  227.  
  228. #endif