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

📄 keyspan.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	keyspan_set_termios(port, NULL);	return (0);}static inline void stop_urb(urb_t *urb){	if (urb && urb->status == -EINPROGRESS) {		urb->transfer_flags &= ~USB_ASYNC_UNLINK;		usb_unlink_urb(urb);	}}static void keyspan_close(struct usb_serial_port *port, struct file *filp){	int			i;	struct usb_serial	*serial;	struct keyspan_serial_private 	*s_priv;	struct keyspan_port_private 	*p_priv;	serial = get_usb_serial (port, __FUNCTION__);	if (!serial)		return;	dbg("keyspan_close called\n");	s_priv = (struct keyspan_serial_private *)(serial->private);	p_priv = (struct keyspan_port_private *)(port->private);		p_priv->rts_state = 0;	p_priv->dtr_state = 0;		if (serial->dev)		keyspan_send_setup(port, 1);	/*while (p_priv->outcont_urb->status == -EINPROGRESS) {		dbg("close - urb in progress\n");	}*/	p_priv->out_flip = 0;	p_priv->in_flip = 0;	down (&port->sem);	if (--port->open_count <= 0) {		if (port->active) {			if (serial->dev) {				/* Stop reading/writing urbs */				stop_urb(p_priv->inack_urb);				stop_urb(p_priv->outcont_urb);				for (i = 0; i < 2; i++) {					stop_urb(p_priv->in_urbs[i]);					stop_urb(p_priv->out_urbs[i]);				}			}		}		port->active = 0;		port->open_count = 0;		port->tty = 0;	}	up (&port->sem);	MOD_DEC_USE_COUNT;}	/* download the firmware to a pre-renumeration device */static int keyspan_fake_startup (struct usb_serial *serial){	int 				response;	const struct ezusb_hex_record 	*record;	char				*fw_name;	dbg("Keyspan startup version %04x product %04x\n",	    serial->dev->descriptor.bcdDevice,	    serial->dev->descriptor.idProduct); 		if ((serial->dev->descriptor.bcdDevice & 0x8000) != 0x8000) {		dbg("Firmware already loaded.  Quitting.\n");		return(1);	}		/* Select firmware image on the basis of idProduct */	switch (serial->dev->descriptor.idProduct) {	case keyspan_usa28_pre_product_id:		record = &keyspan_usa28_firmware[0];		fw_name = "USA28";		break;	case keyspan_usa28x_pre_product_id:		record = &keyspan_usa28x_firmware[0];		fw_name = "USA28X";		break;	case keyspan_usa28xa_pre_product_id:		record = &keyspan_usa28xa_firmware[0];		fw_name = "USA28XA";		break;	case keyspan_usa28xb_pre_product_id:		record = &keyspan_usa28xb_firmware[0];		fw_name = "USA28XB";		break;	case keyspan_usa19_pre_product_id:		record = &keyspan_usa19_firmware[0];		fw_name = "USA19";		break;			     	case keyspan_usa18x_pre_product_id:		record = &keyspan_usa18x_firmware[0];		fw_name = "USA18X";		break;			     	case keyspan_usa19w_pre_product_id:		record = &keyspan_usa19w_firmware[0];		fw_name = "USA19W";		break;			case keyspan_usa49w_pre_product_id:		record = &keyspan_usa49w_firmware[0];		fw_name = "USA49W";		break;	default:		record = NULL;		fw_name = "Unknown";		break;	}	if (record == NULL) {		err("Required keyspan firmware image (%s) unavailable.", fw_name);		return(1);	}	dbg("Uploading Keyspan %s firmware.\n", fw_name);		/* download the firmware image */	response = ezusb_set_reset(serial, 1);	while(record->address != 0xffff) {		response = ezusb_writememory(serial, record->address,					     (unsigned char *)record->data,					     record->data_size, 0xa0);		if (response < 0) {			err("ezusb_writememory failed for Keyspan"			    "firmware (%d %04X %p %d)",			    response, 			    record->address, record->data, record->data_size);			break;		}		record++;	}		/* bring device out of reset. Renumeration will occur in a		   moment and the new device will bind to the real driver */	response = ezusb_set_reset(serial, 0);	/* we don't want this device to have a driver assigned to it. */	return (1);}/* Helper functions used by keyspan_setup_urbs */static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,				int dir, void *ctx, char *buf, int len,				void (*callback)(urb_t *)){	urb_t *urb;	if (endpoint == -1)		return NULL;		/* endpoint not needed */	dbg (__FUNCTION__ " alloc for endpoint %d.\n", endpoint);	urb = usb_alloc_urb(0);		/* No ISO */	if (urb == NULL) {		dbg (__FUNCTION__ " alloc for endpoint %d failed.\n", endpoint);		return NULL;	}		/* Fill URB using supplied data. */	FILL_BULK_URB(urb, serial->dev,		      usb_sndbulkpipe(serial->dev, endpoint) | dir,		      buf, len, callback, ctx);	return urb;}static struct callbacks {	void	(*instat_callback)(urb_t *);	void	(*glocont_callback)(urb_t *);	void	(*indat_callback)(urb_t *);	void	(*outdat_callback)(urb_t *);	void	(*inack_callback)(urb_t *);	void	(*outcont_callback)(urb_t *);} keyspan_callbacks[] = {	{		/* msg_usa26 callbacks */		instat_callback: usa26_instat_callback,		glocont_callback: usa26_glocont_callback,		indat_callback: usa26_indat_callback,		outdat_callback: usa2x_outdat_callback,		inack_callback: usa26_inack_callback,		outcont_callback: usa26_outcont_callback,	}, {		/* msg_usa28 callbacks */		instat_callback: usa28_instat_callback,		glocont_callback: usa28_glocont_callback,		indat_callback: usa28_indat_callback,		outdat_callback: usa2x_outdat_callback,		inack_callback: usa28_inack_callback,		outcont_callback: usa28_outcont_callback,	}, {		/* msg_usa49 callbacks */		instat_callback: usa49_instat_callback,		glocont_callback: usa49_glocont_callback,		indat_callback: usa49_indat_callback,		outdat_callback: usa2x_outdat_callback,		inack_callback: usa49_inack_callback,		outcont_callback: usa49_outcont_callback,	}};	/* Generic setup urbs function that uses	   data in device_details */static void keyspan_setup_urbs(struct usb_serial *serial){	int				i, j;	struct keyspan_serial_private 	*s_priv;	const keyspan_device_details	*d_details;	struct usb_serial_port		*port;	struct keyspan_port_private	*p_priv;	struct callbacks		*cback;	int				endp;	dbg ("%s\n", __FUNCTION__);	s_priv = (struct keyspan_serial_private *)(serial->private);	d_details = s_priv->device_details;		/* Setup values for the various callback routines */	cback = &keyspan_callbacks[d_details->msg_format];		/* Allocate and set up urbs for each one that is in use, 		   starting with instat endpoints */	s_priv->instat_urb = keyspan_setup_urb		(serial, d_details->instat_endpoint, USB_DIR_IN,		 serial, s_priv->instat_buf, INSTAT_BUFLEN,		 cback->instat_callback);	s_priv->glocont_urb = keyspan_setup_urb		(serial, d_details->glocont_endpoint, USB_DIR_OUT,		 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,		 cback->glocont_callback);		/* Setup endpoints for each port specific thing */	for (i = 0; i < d_details->num_ports; i ++) {		port = &serial->port[i];		p_priv = (struct keyspan_port_private *)(port->private);		/* Do indat endpoints first, once for each flip */		endp = d_details->indat_endpoints[i];		for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {			p_priv->in_urbs[j] = keyspan_setup_urb				(serial, endp, USB_DIR_IN, port,				 p_priv->in_buffer[j], 64,				 cback->indat_callback);		}		for (; j < 2; ++j)			p_priv->in_urbs[j] = NULL;		/* outdat endpoints also have flip */		endp = d_details->outdat_endpoints[i];		for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {			p_priv->out_urbs[j] = keyspan_setup_urb				(serial, endp, USB_DIR_OUT, port,				 p_priv->out_buffer[j], 64,				 cback->outdat_callback);		}		for (; j < 2; ++j)			p_priv->out_urbs[j] = NULL;		/* inack endpoint */		p_priv->inack_urb = keyspan_setup_urb			(serial, d_details->inack_endpoints[i], USB_DIR_IN,			 port, p_priv->inack_buffer, 1, cback->inack_callback);		/* outcont endpoint */		p_priv->outcont_urb = keyspan_setup_urb			(serial, d_details->outcont_endpoints[i], USB_DIR_OUT,			 port, p_priv->outcont_buffer, 64,			 cback->outcont_callback);	}	}/* usa19 function doesn't require prescaler */static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk,				   u8 *rate_hi, u8 *rate_low, u8 *prescaler){	u32 	b16,	/* baud rate times 16 (actual rate used internally) */		div,	/* divisor */			cnt;	/* inverse of divisor (programmed into 8051) */				/* prevent divide by zero...  */	if( (b16 = (baud_rate * 16L)) == 0) {		return (KEYSPAN_INVALID_BAUD_RATE);	}		/* Any "standard" rate over 57k6 is marginal on the USA-19		   as we run out of divisor resolution. */	if (baud_rate > 57600) {		return (KEYSPAN_INVALID_BAUD_RATE);	}		/* calculate the divisor and the counter (its inverse) */	if( (div = (baudclk / b16)) == 0) {		return (KEYSPAN_INVALID_BAUD_RATE);	}	else {		cnt = 0 - div;	}	if(div > 0xffff) {		return (KEYSPAN_INVALID_BAUD_RATE);	}		/* return the counter values if non-null */	if (rate_low) {		*rate_low = (u8) (cnt & 0xff);	}	if (rate_hi) {		*rate_hi = (u8) ((cnt >> 8) & 0xff);	}	if (rate_low && rate_hi) {		dbg (__FUNCTION__ " %d %02x %02x.", baud_rate, *rate_hi, *rate_low);	}		return (KEYSPAN_BAUD_RATE_OK);}static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk,				    u8 *rate_hi, u8 *rate_low, u8 *prescaler){	u32 	b16,	/* baud rate times 16 (actual rate used internally) */		clk,	/* clock with 13/8 prescaler */		div,	/* divisor using 13/8 prescaler */			res,	/* resulting baud rate using 13/8 prescaler */		diff,	/* error using 13/8 prescaler */		smallest_diff;	u8	best_prescaler;	int	i;	dbg (__FUNCTION__ " %d.\n", baud_rate);		/* prevent divide by zero */	if( (b16 = baud_rate * 16L) == 0) {		return (KEYSPAN_INVALID_BAUD_RATE);	}		/* Calculate prescaler by trying them all and looking		   for best fit */				/* start with largest possible difference */	smallest_diff = 0xffffffff;		/* 0 is an invalid prescaler, used as a flag */	best_prescaler = 0;	for(i = 8; i <= 0xff; ++i)	{		clk = (baudclk * 8) / (u32) i;				if( (div = clk / b16) == 0) {			continue;		}		res = clk / div;		diff= (res > b16) ? (res-b16) : (b16-res);		if(diff < smallest_diff)		{			best_prescaler = i;			smallest_diff = diff;		}	}	if(best_prescaler == 0) {		return (KEYSPAN_INVALID_BAUD_RATE);	}	clk = (baudclk * 8) / (u32) best_prescaler;	div = clk / b16;		/* return the divisor and prescaler if non-null */	if (rate_low) {		*rate_low = (u8) (div & 0xff);	}	if (rate_hi) {		*rate_hi = (u8) ((div >> 8) & 0xff);	}	if (prescaler) {		*prescaler = best_prescaler;		/*  dbg(__FUNCTION__ " %d %d", *prescaler, div); */	}	return (KEYSPAN_BAUD_RATE_OK);}static int keyspan_usa26_send_setup(struct usb_serial *serial,				    struct usb_serial_port *port,				    int reset_port){	struct keyspan_usa26_portControlMessage	msg;			struct keyspan_serial_private 		*s_priv;	struct keyspan_port_private 		*p_priv;	const  keyspan_device_details		*d_details;	int 					outcont_urb;	urb_t *this_urb;	int err;	dbg ("%s reset=%d\n", __FUNCTION__, reset_port); 	s_priv = (struct keyspan_serial_private *)(serial->private);	p_priv = (struct keyspan_port_private *)(port->private);	d_details = s_priv->device_details;	outcont_urb = d_details->outcont_endpoints[port->number];	this_urb = p_priv->outcont_urb;	dbg(__FUNCTION__ " endpoint %d\n", usb_pipeendpoint(this_urb->pipe));		/* Make sure we have an urb then send the message */	if (this_urb == NULL) {		dbg(__FUNCTION__ " oops no urb.\n");		return -1;	}	p_priv->resend_cont = 1;	if (this_urb->status == -EINPROGRESS) {		/*  dbg (__FUNCTION__ " already writing"); */		return(-1);	}	memset(&msg, 0, sizeof (struct keyspan_usa26_portControlMessage));			/* Only set baud rate if it's changed */		if (p_priv->old_baud != p_priv->baud) {		p_priv->old_baud = p_priv->baud;		msg.setClocking = 0xff;		if (d_details->calculate_baud_rate		    (p_priv->baud, d_details->baudclk, &msg.baudHi,		     &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {			dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.\n",			    p_priv->baud);			msg.baudLo = 0;

⌨️ 快捷键说明

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