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

📄 vlsi_ir.h

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 H
📖 第 1 页 / 共 2 页
字号:
 * * SIR-mode:	BAUD = (115.2kHz / baudrate) - 1 *		PLSWID = (pulsetime * freq / (BAUD+1)) - 1 *			where pulsetime is the requested IrPHY pulse width *			and freq is 8(16)MHz for 40(48)MHz primary input clock *		PREAMB: don't care for SIR * *		The nominal SIR pulse width is 3/16 bit time so we have PLSWID=12 *		fixed for all SIR speeds at 40MHz input clock (PLSWID=24 at 48MHz). *		IrPHY also allows shorter pulses down to the nominal pulse duration *		at 115.2kbaud (minus some tolerance) which is 1.41 usec. *		Using the expression PLSWID = 12/(BAUD+1)-1 (multiplied by two for 48MHz) *		we get the minimum acceptable PLSWID values according to the VLSI *		specification, which provides 1.5 usec pulse width for all speeds (except *		for 2.4kbaud getting 6usec). This is fine with IrPHY v1.3 specs and *		reduces the transceiver power which drains the battery. At 9.6kbaud for *		example this amounts to more than 90% battery power saving! * * MIR-mode:	BAUD = 0 *		PLSWID = 9(10) for 40(48) MHz input clock *			to get nominal MIR pulse width *		PREAMB = 1 * * FIR-mode:	BAUD = 0 *		PLSWID: don't care *		PREAMB = 15 */#define PHYCTL_BAUD_SHIFT	10#define PHYCTL_BAUD_MASK	0xfc00#define PHYCTL_PLSWID_SHIFT	5#define PHYCTL_PLSWID_MASK	0x03e0#define PHYCTL_PREAMB_SHIFT	0#define PHYCTL_PREAMB_MASK	0x001f#define PHYCTL_TO_BAUD(bwp)	(((bwp)&PHYCTL_BAUD_MASK)>>PHYCTL_BAUD_SHIFT)#define PHYCTL_TO_PLSWID(bwp)	(((bwp)&PHYCTL_PLSWID_MASK)>>PHYCTL_PLSWID_SHIFT)#define PHYCTL_TO_PREAMB(bwp)	(((bwp)&PHYCTL_PREAMB_MASK)>>PHYCTL_PREAMB_SHIFT)#define BWP_TO_PHYCTL(b,w,p)	((((b)<<PHYCTL_BAUD_SHIFT)&PHYCTL_BAUD_MASK) \				 | (((w)<<PHYCTL_PLSWID_SHIFT)&PHYCTL_PLSWID_MASK) \				 | (((p)<<PHYCTL_PREAMB_SHIFT)&PHYCTL_PREAMB_MASK))#define BAUD_BITS(br)		((115200/(br))-1)static inline unsignedcalc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect){	unsigned	tmp;	if (widthselect)	/* nominal 3/16 puls width */		return (clockselect) ? 12 : 24;	tmp = ((clockselect) ? 12 : 24) / (BAUD_BITS(baudrate)+1);	/* intermediate result of integer division needed here */	return (tmp>0) ? (tmp-1) : 0;}#define PHYCTL_SIR(br,ws,cs)	BWP_TO_PHYCTL(BAUD_BITS(br),calc_width_bits((br),(ws),(cs)),0)#define PHYCTL_MIR(cs)		BWP_TO_PHYCTL(0,((cs)?9:10),1)#define PHYCTL_FIR		BWP_TO_PHYCTL(0,0,15)/* quite ugly, I know. But implementing these calculations here avoids * having magic numbers in the code and allows some playing with pulsewidths * without risk to violate the standards. * FWIW, here is the table for reference: * * baudrate	BAUD	min-PLSWID	nom-PLSWID	PREAMB *     2400	  47	   0(0)		   12(24)	   0 *     9600	  11	   0(0)		   12(24)	   0 *    19200	   5	   1(2)		   12(24)	   0 *    38400	   2	   3(6)	           12(24)	   0 *    57600	   1	   5(10)	   12(24)	   0 *   115200	   0	  11(22)	   12(24)	   0 *	MIR	   0	    -		    9(10)	   1 *	FIR	   0        -               0		  15 * * note: x(y) means x-value for 40MHz / y-value for 48MHz primary input clock *//* ------------------------------------------ *//* VLSI_PIO_MAXPKT: Maximum Packet Length register (u16, rw) *//* maximum acceptable length for received packets *//* hw imposed limitation - register uses only [11:0] */#define MAX_PACKET_LENGTH	0x0fff/* IrLAP I-field (apparently not defined elsewhere) */#define IRDA_MTU		2048/* complete packet consists of A(1)+C(1)+I(<=IRDA_MTU) */#define IRLAP_SKB_ALLOCSIZE	(1+1+IRDA_MTU)/* the buffers we use to exchange frames with the hardware need to be * larger than IRLAP_SKB_ALLOCSIZE because we may have up to 4 bytes FCS * appended and, in SIR mode, a lot of frame wrapping bytes. The worst * case appears to be a SIR packet with I-size==IRDA_MTU and all bytes * requiring to be escaped to provide transparency. Furthermore, the peer * might ask for quite a number of additional XBOFs: *	up to 115+48 XBOFS		 163 *	regular BOF			   1 *	A-field				   1 *	C-field				   1 *	I-field, IRDA_MTU, all escaped	4096 *	FCS (16 bit at SIR, escaped)	   4 *	EOF				   1 * AFAICS nothing in IrLAP guarantees A/C field not to need escaping * (f.e. 0xc0/0xc1 - i.e. BOF/EOF - are legal values there) so in the * worst case we have 4269 bytes total frame size. * However, the VLSI uses 12 bits only for all buffer length values, * which limits the maximum useable buffer size <= 4095. * Note this is not a limitation in the receive case because we use * the SIR filtering mode where the hw unwraps the frame and only the * bare packet+fcs is stored into the buffer - in contrast to the SIR * tx case where we have to pass frame-wrapped packets to the hw. * If this would ever become an issue in real life, the only workaround * I see would be using the legacy UART emulation in SIR mode. */#define XFER_BUF_SIZE		MAX_PACKET_LENGTH/* ------------------------------------------ *//* VLSI_PIO_RCVBCNT: Receive Byte Count Register (u16, ro) *//* receive packet counter gets incremented on every non-filtered * byte which was put in the receive fifo and reset for each * new packet. Used to decide whether we are just in the middle * of receiving *//* better apply the [11:0] mask when reading, as some docs say the * reserved [15:12] would return 1 when reading - which is wrong AFAICS */#define RCVBCNT_MASK	0x0fff/******************************************************************//* descriptors for rx/tx ring * * accessed by hardware - don't change! * * the descriptor is owned by hardware, when the ACTIVE status bit * is set and nothing (besides reading status to test the bit) * shall be done. The bit gets cleared by hw, when the descriptor * gets closed. Premature reaping of descriptors owned be the chip * can be achieved by disabling IRCFG_MSTR * * Attention: Writing addr overwrites status! * * ### FIXME: depends on endianess (but there ain't no non-i586 ob800 ;-) */struct ring_descr_hw {	volatile u16	rd_count;	/* tx/rx count [11:0] */	u16		reserved;	union {		u32	addr;		/* [23:0] of the buffer's busaddress */		struct {			u8		addr_res[3];			volatile u8	status;		/* descriptor status */		} __attribute__((packed)) rd_s;	} __attribute((packed)) rd_u;} __attribute__ ((packed));#define rd_addr		rd_u.addr#define rd_status	rd_u.rd_s.status/* ring descriptor status bits */#define RD_ACTIVE		0x80	/* descriptor owned by hw (both TX,RX) *//* TX ring descriptor status */#define	RD_TX_DISCRC		0x40	/* do not send CRC (for SIR) */#define	RD_TX_BADCRC		0x20	/* force a bad CRC */#define	RD_TX_PULSE		0x10	/* send indication pulse after this frame (MIR/FIR) */#define	RD_TX_FRCEUND		0x08	/* force underrun */#define	RD_TX_CLRENTX		0x04	/* clear ENTX after this frame */#define	RD_TX_UNDRN		0x01	/* TX fifo underrun (probably PCI problem) *//* RX ring descriptor status */#define RD_RX_PHYERR		0x40	/* physical encoding error */#define RD_RX_CRCERR		0x20	/* CRC error (MIR/FIR) */#define RD_RX_LENGTH		0x10	/* frame exceeds buffer length */#define RD_RX_OVER		0x08	/* RX fifo overrun (probably PCI problem) */#define RD_RX_SIRBAD		0x04	/* EOF missing: BOF follows BOF (SIR, filtered) */#define RD_RX_ERROR		0x7c	/* any error in received frame *//* the memory required to hold the 2 descriptor rings */#define HW_RING_AREA_SIZE	(2 * MAX_RING_DESCR * sizeof(struct ring_descr_hw))/******************************************************************//* sw-ring descriptors consists of a bus-mapped transfer buffer with * associated skb and a pointer to the hw entry descriptor */struct ring_descr {	struct ring_descr_hw	*hw;	struct sk_buff		*skb;	void			*buf;};/* wrappers for operations on hw-exposed ring descriptors * access to the hw-part of the descriptors must use these. */static inline int rd_is_active(struct ring_descr *rd){	return ((rd->hw->rd_status & RD_ACTIVE) != 0);}static inline void rd_activate(struct ring_descr *rd){	rd->hw->rd_status |= RD_ACTIVE;}static inline void rd_set_status(struct ring_descr *rd, u8 s){	rd->hw->rd_status = s;	 /* may pass ownership to the hardware */}static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s){	/* order is important for two reasons:	 *  - overlayed: writing addr overwrites status	 *  - we want to write status last so we have valid address in	 *    case status has RD_ACTIVE set	 */	if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) {		IRDA_ERROR("%s: pci busaddr inconsistency!\n", __FUNCTION__);		dump_stack();		return;	}	a &= DMA_MASK_MSTRPAGE;  /* clear highbyte to make sure we won't write				  * to status - just in case MSTRPAGE_VALUE!=0				  */	rd->hw->rd_addr = cpu_to_le32(a);	wmb();	rd_set_status(rd, s);	 /* may pass ownership to the hardware */}static inline void rd_set_count(struct ring_descr *rd, u16 c){	rd->hw->rd_count = cpu_to_le16(c);}static inline u8 rd_get_status(struct ring_descr *rd){	return rd->hw->rd_status;}static inline dma_addr_t rd_get_addr(struct ring_descr *rd){	dma_addr_t	a;	a = le32_to_cpu(rd->hw->rd_addr);	return (a & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24);}static inline u16 rd_get_count(struct ring_descr *rd){	return le16_to_cpu(rd->hw->rd_count);}/******************************************************************//* sw descriptor rings for rx, tx: * * operations follow producer-consumer paradigm, with the hw * in the middle doing the processing. * ring size must be power of two. * * producer advances r->tail after inserting for processing * consumer advances r->head after removing processed rd * ring is empty if head==tail / full if (tail+1)==head */struct vlsi_ring {	struct pci_dev		*pdev;	int			dir;	unsigned		len;	unsigned		size;	unsigned		mask;	atomic_t		head, tail;	struct ring_descr	*rd;};/* ring processing helpers */static inline struct ring_descr *ring_last(struct vlsi_ring *r){	int t;	t = atomic_read(&r->tail) & r->mask;	return (((t+1) & r->mask) == (atomic_read(&r->head) & r->mask)) ? NULL : &r->rd[t];}static inline struct ring_descr *ring_put(struct vlsi_ring *r){	atomic_inc(&r->tail);	return ring_last(r);}static inline struct ring_descr *ring_first(struct vlsi_ring *r){	int h;	h = atomic_read(&r->head) & r->mask;	return (h == (atomic_read(&r->tail) & r->mask)) ? NULL : &r->rd[h];}static inline struct ring_descr *ring_get(struct vlsi_ring *r){	atomic_inc(&r->head);	return ring_first(r);}/******************************************************************//* our private compound VLSI-PCI-IRDA device information */typedef struct vlsi_irda_dev {	struct pci_dev		*pdev;	struct net_device_stats	stats;	struct irlap_cb		*irlap;	struct qos_info		qos;	unsigned		mode;	int			baud, new_baud;	dma_addr_t		busaddr;	void			*virtaddr;	struct vlsi_ring	*tx_ring, *rx_ring;	struct timeval		last_rx;	spinlock_t		lock;	struct semaphore	sem;	u8			resume_ok;		struct proc_dir_entry	*proc_entry;} vlsi_irda_dev_t;/********************************************************//* the remapped error flags we use for returning from frame * post-processing in vlsi_process_tx/rx() after it was completed * by the hardware. These functions either return the >=0 number * of transfered bytes in case of success or the negative (-) * of the or'ed error flags. */#define VLSI_TX_DROP		0x0001#define VLSI_TX_FIFO		0x0002#define VLSI_RX_DROP		0x0100#define VLSI_RX_OVER		0x0200#define VLSI_RX_LENGTH  	0x0400#define VLSI_RX_FRAME		0x0800#define VLSI_RX_CRC		0x1000/********************************************************/#endif /* IRDA_VLSI_FIR_H */

⌨️ 快捷键说明

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