⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hdlc.c

📁 linux驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		skb->mac.raw=skb->data;		dev_to_hdlc(dev)->netif_rx(skb);	}	/* Clear the status flags for this buffer.	*/	bdp->cbd_sc &= ~BD_HDLC_RX_STATS;	/* Mark the buffer empty.	*/	bdp->cbd_sc |= BD_HDLC_RX_EMPTY;	/* Update BD pointer to next entry.	*/	if (bdp->cbd_sc & BD_HDLC_RX_WRAP)		bdp = chp->rx_bd_base;	else		bdp++;   }	chp->cur_rx = (cbd_t *)bdp;	return 0;}static intscc_hdlc_close(struct net_device *dev){	/* Don't know what to do yet.	*/   if (dev_to_hdlc(dev)->stop)      dev_to_hdlc(dev)->stop(dev_to_hdlc(dev));   netif_stop_queue(dev);   MOD_DEC_USE_COUNT;	return 0;}static int scc_encoding_setting(struct net_device *dev){   /* Nothing to do here */   return 0;}#if 0static int scc_clock_setting(struct net_device *dev){   volatile struct scc_hdlc_private *chp = &scc_private_data;   uint bps = chp->settings.clock_rate;   if (bps < 50 || bps > 115200)      return -EINVAL;   m8xx_cpm_setbrg(BRG_HDLC, bps);   chp->settings.clock_rate = m8xx_cpm_getbrg(BRG_HDLC);   if (chp->settings.clock_rate != bps) {      printk(KERN_INFO "%s: clock adjusted from %08d to %08d \n",            dev->name, bps, chp->settings.clock_rate);   }   return 0;}#endifstatic int scc_loopback_setting(struct net_device *dev){   /* Nothing to do here */   return 0;}static int scc_crc_setting(struct net_device *dev){   /* Nothing to do here */   return 0;}static int scc_set_iface(struct net_device *dev){   struct {      int (*action)(struct net_device *);   } *p, do_setting[] = {      { scc_encoding_setting },#if 0      { scc_clock_setting },#endif      { scc_loopback_setting },      { scc_crc_setting },      { NULL }   };   int ret = 0;   for (p = do_setting; p->action; p++) {       if ((ret = p->action(dev)) < 0)       break;   }   return ret;}static int scc_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){   struct scc_hdlc_private *chp = &scc_private_data;   struct if_settings *if_s = &ifr->ifr_settings;   const size_t size = sizeof(chp->settings);   int ret = 0;   printk("hdlc protocol: %x\n",dev_to_hdlc(dev)->proto);   switch(ifr->ifr_settings.type) {      case IF_GET_IFACE : {         if_s->type = IF_IFACE_SYNC_SERIAL;        if (if_s->data_length == 0)           return 0;        if (if_s->data_length < size)           return -ENOMEM;        if (copy_to_user(if_s->data, &chp->settings, size))           return -EFAULT;        if_s->data_length = size;        break;      }      case IF_IFACE_SYNC_SERIAL : {         if (!capable(CAP_NET_ADMIN))            return -EPERM;         if (if_s->data_length != size)            return -ENOMEM;         if (copy_from_user(&chp->settings, if_s->data, size))            return -EFAULT;         ret = scc_set_iface(dev);        break;      }      default : {         ret = hdlc_ioctl(dev, ifr, cmd);      }   }   return ret;}static int scc_hdlc_attach(hdlc_device *hdlc, unsigned short encoding,              unsigned short parity){   volatile struct scc_hdlc_private *chp = &scc_private_data;   if (encoding != ENCODING_NRZ &&       encoding != ENCODING_NRZI &&       encoding != ENCODING_FM_MARK &&       encoding != ENCODING_FM_SPACE &&       encoding != ENCODING_MANCHESTER)      return -EINVAL;   if (parity != PARITY_NONE &&       parity != PARITY_CRC16_PR0_CCITT &&       parity != PARITY_CRC16_PR1_CCITT &&       /* parity != PARITY_CRC32_PR0_CCITT &&  FIXME */       parity != PARITY_CRC32_PR1_CCITT)      return -EINVAL;   chp->encoding = encoding;   chp->parity = parity;   return 0;}/* Remove whatever the scc_hdlc_init() function requested. :-) */static void __exit scc_hdlc_exit(void){   struct scc_hdlc_private *cep = &scc_private_data;   hdlc_device *hdlc = &scc_private_data.hdlc;   volatile scc_hdlc_t *ep = (scc_hdlc_t *) hdlc_to_dev(hdlc)->base_addr;   unsigned long mem_addr;   pte_t *pte;   volatile cbd_t *bdp;   int i,j;   if (scc_hdlc_steps&SCC_HDLC_HDLC_DEV_REG) {      unregister_hdlc_device(hdlc);      cpm_free_handler(CPMVEC_HDLC);   }   if (scc_hdlc_steps&SCC_HDLC_HDLC_PAGE_ALLOC) {      bdp = cep->rx_bd_base;      for (i = 0; i < CPM_HDLC_RX_PAGES; i++) {        /* Get the memory address */         mem_addr = (uint) __va(bdp->cbd_bufaddr);         /* Make it cached */         pte = va_to_pte(mem_addr);         pte_val(*pte) &= ~_PAGE_NO_CACHE;         flush_tlb_page(init_mm.mmap, mem_addr);         /* Deallocate the page */         __free_page((struct page *) mem_addr);         /* Jump to the next page */         for (j = 0; j < CPM_HDLC_RX_FRPPG; j++)           bdp++;      }   }   if (scc_hdlc_steps&SCC_HDLC_TBASE_DPALLOC)      m8xx_cpm_dpfree(ep->shd_genscc.scc_tbase);   if (scc_hdlc_steps&SCC_HDLC_RBASE_DPALLOC)      m8xx_cpm_dpfree(ep->shd_genscc.scc_rbase);}/* Initialize the CPM HDLC on SCC.We don't use CTS and CD lines. * HDLC is on SCC2 */int __init scc_hdlc_init(void){	struct scc_hdlc_private *chp = &scc_private_data;	hdlc_device *hdlc = &scc_private_data.hdlc;	int i, j;	unsigned long	mem_addr;	pte_t		*pte;	bd_t		*bd;	volatile	cbd_t		*bdp;	volatile	cpm8xx_t	*cp;	volatile	scc_t		*sccp;	volatile	scc_hdlc_t	*ep;	volatile	immap_t		*immap;	cp = cpmp;	/* Get pointer to Communication Processor */	immap = (immap_t *)(mfspr(IMMR)&0xFFFF0000);	bd = (bd_t *)__res;	spin_lock_init(&chp->lock);	/* Get pointer to SCC area in parameter RAM.	*/	ep = (scc_hdlc_t *)(&cp->cp_dparam[PROFF_HDLC]);	/* And another to the SCC register area.	*/	sccp = (volatile scc_t *)(&cp->cp_scc[SCC_HDLC]);	chp->sccp = (scc_t *)sccp;		/* Keep the pointer handy */	/* Disable receive and transmit in case EPPC-Bug started it.	*/	sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);	/* Cookbook style from the MPC860 manual.....	 * Not all of this is necessary if EPPC-Bug has initialized	 * the network.	 * So far we are lucky, all board configurations use the same	 * pins, or at least the same I/O Port for these functions.....	 * It can't last though......	 */#if (defined(PA_HDLC_RXD) && defined(PA_HDLC_TXD))	/* Configure port A pins for Txd and Rxd.	*/	immap->im_ioport.iop_papar |=  (PA_HDLC_RXD | PA_HDLC_TXD);	immap->im_ioport.iop_padir &= ~(PA_HDLC_RXD | PA_HDLC_TXD);	immap->im_ioport.iop_paodr &= ~(PA_HDLC_RXD | PA_HDLC_TXD);#elif (defined(PB_HDLC_RXD) && defined(PB_HDLC_TXD))	/* Configure port B pins for Txd and Rxd.	*/	immap->im_cpm.cp_pbpar |=  (PB_HDLC_RXD | PB_HDLC_TXD);	immap->im_cpm.cp_pbdir &= ~(PB_HDLC_RXD | PB_HDLC_TXD);	immap->im_cpm.cp_pbodr &= ~(PB_HDLC_RXD | PB_HDLC_TXD);#else#error Exactly ONE pair of PA_HDLC_[RT]XD, PB_HDLC_[RT]XD must be defined#endif#if defined(PC_HDLC_LBK)	/* Configure port C pins to disable External Loopback	 */	immap->im_ioport.iop_pcpar &= ~PC_HDLC_LBK;	immap->im_ioport.iop_pcdir |=  PC_HDLC_LBK;	immap->im_ioport.iop_pcso  &= ~PC_HDLC_LBK;	immap->im_ioport.iop_pcdat &= ~PC_HDLC_LBK;	/* Disable Loopback */#endif	/* PC_HDLC_LBK */	/* Configure port A for TCLK and RCLK.	*/	immap->im_ioport.iop_papar |=  PA_HDLC_TCLK|PA_HDLC_RCLK;	immap->im_ioport.iop_padir &= ~(PA_HDLC_TCLK|PA_HDLC_RCLK);	/* Configure Serial Interface clock routing.	 * First, clear all SCC bits to zero, then set the ones we want.	 */	cp->cp_sicr &= ~SICR_HDLC_MASK;	cp->cp_sicr |=  SICR_HDLC_CLKRT;	cp->cp_sicr &=  ~0x00004000;	/* Manual says set SDDR, but I can't find anything with that	 * name.  I think it is a misprint, and should be SDCR.  This	 * has already been set by the communication processor initialization.	 */	/* Allocate space for the buffer descriptors in the DP ram.	 * These are relative offsets in the DP ram address space.	 * Initialize base addresses for the buffer descriptors.	 */	i = m8xx_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE);	ep->shd_genscc.scc_rbase = i;	chp->rx_bd_base = (cbd_t *)&cp->cp_dpmem[i];	i = m8xx_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE);	ep->shd_genscc.scc_tbase = i;	chp->tx_bd_base = (cbd_t *)&cp->cp_dpmem[i];	chp->dirty_tx = chp->cur_tx = chp->tx_bd_base;	chp->cur_rx = chp->rx_bd_base;	/* Issue init Rx BD command for SCC.	 * Manual says to perform an Init Rx parameters here.  We have	 * to perform both Rx and Tx because the SCC may have been	 * already running.	 * In addition, we have to do it later because we don't yet have	 * all of the BD control/status set properly.	cp->cp_cpcr = mk_cr_cmd(CPM_CR_HDLC, CPM_CR_INIT_RX) | CPM_CR_FLG;	while (cp->cp_cpcr & CPM_CR_FLG);	 */	/* Initialize function code registers for big-endian.	*/	ep->shd_genscc.scc_rfcr = SCC_EB;	ep->shd_genscc.scc_tfcr = SCC_EB;	/* Set maximum bytes per receive buffer.	 * This appears to be an HDLC frame size, not the buffer	 * fragment size.  It must be a multiple of four.	 */	ep->shd_genscc.scc_mrblr = 1600;	/* Set CRC preset and mask.	*/	ep->shd_cpres = 0x0000ffff;	ep->shd_cmask = 0x0000f0b8;	ep->shd_crcec = 0;	/* CRC Error counter */	ep->shd_abtsc = 0;	/* Abort sequence counter */	ep->shd_nmarc = 0;	/* Nonmatching address received counter */	ep->shd_disfc = 0;	/* discard frame counter */	ep->shd_retrc = 0;	/* Frame retransmission counter */	ep->shd_mflr = 0x0640;	/* Max frame length register */	ep->shd_rfthr = 0x0001;	/* Received frames threshold */	ep->shd_hmask = 0x0000;	/* Mask register */	/* Clear address	*/	ep->shd_haddr1 = 0;	ep->shd_haddr2 = 0;	ep->shd_haddr3 = 0;	ep->shd_haddr4 = 0;	/* Now allocate the host memory pages and initialize the	 * buffer descriptors.	 */	bdp = chp->tx_bd_base;	for (i=0; i<TX_RING_SIZE; i++) {		/* Initialize the BD for every fragment in the page.		*/		bdp->cbd_sc = 0;		bdp->cbd_bufaddr = 0;		bdp++;	}	/* Set the last buffer to wrap.	*/	bdp--;	bdp->cbd_sc |= BD_SC_WRAP;	bdp = chp->rx_bd_base;	for (i=0; i<CPM_HDLC_RX_PAGES; i++) {		/* Allocate a page.		*/		mem_addr = __get_free_page(GFP_KERNEL);		/* Make it uncached.		*/		pte = va_to_pte(mem_addr);		pte_val(*pte) |= _PAGE_NO_CACHE;		flush_tlb_page(init_mm.mmap, mem_addr);		/* Initialize the BD for every fragment in the page.		*/		for (j=0; j<CPM_HDLC_RX_FRPPG; j++) {			bdp->cbd_sc = BD_HDLC_RX_EMPTY | BD_HDLC_RX_INTR;			bdp->cbd_bufaddr = __pa(mem_addr);			mem_addr += CPM_HDLC_RX_FRSIZE;			bdp++;		}	}	/* Set the last buffer to wrap.	*/	bdp--;	bdp->cbd_sc |= BD_SC_WRAP;	/* Let's re-initialize the channel now.  We have to do it later	 * than the manual describes because we have just now finished	 * the BD initialization.	 */	/* init tx and rx command to SCCx */	cp->cp_cpcr = mk_cr_cmd(CPM_CR_HDLC, CPM_CR_INIT_TRX) | CPM_CR_FLG;	while (cp->cp_cpcr & CPM_CR_FLG); /* wait until command finished */	chp->skb_cur = chp->skb_dirty = 0;	sccp->scc_scce = 0xffff;	/* Clear any pending events */	/* Enable interrupts for transmit error, complete frame	 * received, and any transmit buffer we have also set the	 * interrupt flag.	 */	/*	sccp->scc_sccm = (SCCE_HDLC_TXE | SCCE_HDLC_RXF | SCCE_HDLC_TXB);	*/	sccp->scc_sccm = SCCE_HDLC_RXF;	/* Install our interrupt handler.	*/	cpm_install_handler(CPMVEC_HDLC, scc_hdlc_interrupt, NULL);	/* Set GSMR_H to enable all normal operating modes.	 * Set GSMR_L to enable HDLC.	 */	sccp->scc_gsmrh = 0;	sccp->scc_gsmrl = 0;	/* Set processing mode.  Use 16 bit CRC,one opening and one closing 	 * flag,and prevent multiple frames in the FIFO.	 */	sccp->scc_pmsr = (SCC_HDLC_PMSR_NOF | SCC_HDLC_PMSR_HDCRC | SCC_HDLC_PMSR_MFF);	hdlc_to_dev(hdlc)->base_addr = (unsigned long)ep;	hdlc_to_dev(hdlc)->irq = 0;	/*	hdlc_to_dev(hdlc)->priv = &hdlc->state.ppp.syncppp_ptr;	hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;	hdlc->state.ppp.pppdev.dev = hdlc_to_dev(hdlc);	*/	hdlc_to_dev(hdlc)->init = NULL;#if 0	dev->name = "CPM_HDLC";#endif	/* Save some pointers into device structure */	hdlc_to_dev(hdlc)->open = scc_hdlc_open;	hdlc_to_dev(hdlc)->stop = scc_hdlc_close;	hdlc_to_dev(hdlc)->do_ioctl = scc_hdlc_ioctl;	hdlc_to_dev(hdlc)->tx_timeout = scc_hdlc_timeout;	hdlc_to_dev(hdlc)->watchdog_timeo = TX_TIMEOUT;		/* The CPM HDLC specific entries in the device structure */	hdlc->xmit = scc_hdlc_xmit;	hdlc->attach = scc_hdlc_attach;	hdlc->proto = IF_PROTO_HDLC;	hdlc->netif_rx = netif_rx;	/* Now we are ready to register the HDLC device */	if (register_hdlc_device(hdlc) < 0) {	      printk(KERN_ERR "hdlc: unable to register hdlc device\n");	      scc_hdlc_exit();	      return -ENODEV;	 }	 scc_hdlc_steps |= SCC_HDLC_HDLC_DEV_REG;	/* And last, enable the transmit and receive processing.	*/	sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);#if 0	sccp->scc_gsmrl |= 0x00000040; /* local loopback test,add by YZX */#endif	printk("%s: CPM HDLC Version 0.1 on SCC%d, ", hdlc_to_name(hdlc), SCC_HDLC+1);	return 0;}module_init(scc_hdlc_init);module_exit(scc_hdlc_exit);MODULE_DESCRIPTION("HDLC driver for Motorola MPC8xx");EXPORT_NO_SYMBOLS;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -