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

📄 sisusb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Sanity check */	if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)		return -ENODEV;	pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);	buffer = sisusb->ibuf;	bufsize = sisusb->ibufsize;	retry = 5;#ifdef SISUSB_DONTSYNC	if (!(sisusb_wait_all_out_complete(sisusb)))		return -EIO;#endif	while (count > 0) {		if (!sisusb->sisusb_dev)			return -ENODEV;		thispass = (bufsize < count) ? bufsize : count;		result = sisusb_bulkin_msg(sisusb,					   pipe,					   buffer,					   thispass,					   &transferred_len,					   5 * HZ,					   tflags,					   sisusb->transfer_dma_in);		if (transferred_len)			thispass = transferred_len;		else if (result == -ETIMEDOUT) {			if (!retry--)				return -ETIME;			continue;		} else			return -EIO;		if (thispass) {			(*bytes_read) += thispass;			count         -= thispass;			if (userbuffer) {				if (copy_to_user(userbuffer, buffer, thispass))					return -EFAULT;				userbuffer += thispass;			} else {				memcpy(kernbuffer, buffer, thispass);				kernbuffer += thispass;			}		}	}	return ((*bytes_read) == len) ? 0 : -EIO;}static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,						struct sisusb_packet *packet){	int ret;	ssize_t bytes_transferred = 0;	__le32 tmp;	if (len == 6)		packet->data = 0;#ifdef SISUSB_DONTSYNC	if (!(sisusb_wait_all_out_complete(sisusb)))		return 1;#endif	/* Eventually correct endianness */	SISUSB_CORRECT_ENDIANNESS_PACKET(packet);	/* 1. send the packet */	ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,			(char *)packet, NULL, 0, &bytes_transferred, 0, 0);	if ((ret == 0) && (len == 6)) {		/* 2. if packet len == 6, it means we read, so wait for 32bit		 *    return value and write it to packet->data		 */		ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,				(char *)&tmp, NULL, &bytes_transferred, 0);		packet->data = le32_to_cpu(tmp);	}	return ret;}static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,					struct sisusb_packet *packet,					unsigned int tflags){	int ret;	ssize_t bytes_transferred = 0;	__le32 tmp;	if (len == 6)		packet->data = 0;#ifdef SISUSB_DONTSYNC	if (!(sisusb_wait_all_out_complete(sisusb)))		return 1;#endif	/* Eventually correct endianness */	SISUSB_CORRECT_ENDIANNESS_PACKET(packet);	/* 1. send the packet */	ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,			(char *)packet, NULL, 0, &bytes_transferred, tflags, 0);	if ((ret == 0) && (len == 6)) {		/* 2. if packet len == 6, it means we read, so wait for 32bit		 *    return value and write it to packet->data		 */		ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,				(char *)&tmp, NULL, &bytes_transferred, 0);		packet->data = le32_to_cpu(tmp);	}	return ret;}/* access video memory and mmio (return 0 on success) *//* Low level *//* The following routines assume being used to transfer byte, word, * long etc. * This means that *   - the write routines expect "data" in machine endianness format. *     The data will be converted to leXX in sisusb_xxx_packet. *   - the read routines can expect read data in machine-endianess. */static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,							u32 addr, u8 data){	struct sisusb_packet packet;	int ret;	packet.header  = (1 << (addr & 3)) | (type << 6);	packet.address = addr & ~3;	packet.data    = data << ((addr & 3) << 3);	ret = sisusb_send_packet(sisusb, 10, &packet);	return ret;}static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,							u32 addr, u16 data){	struct sisusb_packet packet;	int ret = 0;	packet.address = addr & ~3;	switch (addr & 3) {		case 0:			packet.header = (type << 6) | 0x0003;			packet.data   = (u32)data;			ret = sisusb_send_packet(sisusb, 10, &packet);			break;		case 1:			packet.header = (type << 6) | 0x0006;			packet.data   = (u32)data << 8;			ret = sisusb_send_packet(sisusb, 10, &packet);			break;		case 2:			packet.header = (type << 6) | 0x000c;			packet.data   = (u32)data << 16;			ret = sisusb_send_packet(sisusb, 10, &packet);			break;		case 3:			packet.header = (type << 6) | 0x0008;			packet.data   = (u32)data << 24;			ret = sisusb_send_packet(sisusb, 10, &packet);			packet.header = (type << 6) | 0x0001;			packet.address = (addr & ~3) + 4;			packet.data   = (u32)data >> 8;			ret |= sisusb_send_packet(sisusb, 10, &packet);	}	return ret;}static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,							u32 addr, u32 data){	struct sisusb_packet packet;	int ret = 0;	packet.address = addr & ~3;	switch (addr & 3) {		case 0:			packet.header  = (type << 6) | 0x0007;			packet.data    = data & 0x00ffffff;			ret = sisusb_send_packet(sisusb, 10, &packet);			break;		case 1:			packet.header  = (type << 6) | 0x000e;			packet.data    = data << 8;			ret = sisusb_send_packet(sisusb, 10, &packet);			break;		case 2:			packet.header  = (type << 6) | 0x000c;			packet.data    = data << 16;			ret = sisusb_send_packet(sisusb, 10, &packet);			packet.header  = (type << 6) | 0x0001;			packet.address = (addr & ~3) + 4;			packet.data    = (data >> 16) & 0x00ff;			ret |= sisusb_send_packet(sisusb, 10, &packet);			break;		case 3:			packet.header  = (type << 6) | 0x0008;			packet.data    = data << 24;			ret = sisusb_send_packet(sisusb, 10, &packet);			packet.header  = (type << 6) | 0x0003;			packet.address = (addr & ~3) + 4;			packet.data    = (data >> 8) & 0xffff;			ret |= sisusb_send_packet(sisusb, 10, &packet);	}	return ret;}static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,							u32 addr, u32 data){	struct sisusb_packet packet;	int ret = 0;	packet.address = addr & ~3;	switch (addr & 3) {		case 0:			packet.header  = (type << 6) | 0x000f;			packet.data    = data;			ret = sisusb_send_packet(sisusb, 10, &packet);			break;		case 1:			packet.header  = (type << 6) | 0x000e;			packet.data    = data << 8;			ret = sisusb_send_packet(sisusb, 10, &packet);			packet.header  = (type << 6) | 0x0001;			packet.address = (addr & ~3) + 4;			packet.data    = data >> 24;			ret |= sisusb_send_packet(sisusb, 10, &packet);			break;		case 2:			packet.header  = (type << 6) | 0x000c;			packet.data    = data << 16;			ret = sisusb_send_packet(sisusb, 10, &packet);			packet.header  = (type << 6) | 0x0003;			packet.address = (addr & ~3) + 4;			packet.data    = data >> 16;			ret |= sisusb_send_packet(sisusb, 10, &packet);			break;		case 3:			packet.header  = (type << 6) | 0x0008;			packet.data    = data << 24;			ret = sisusb_send_packet(sisusb, 10, &packet);			packet.header  = (type << 6) | 0x0007;			packet.address = (addr & ~3) + 4;			packet.data    = data >> 8;			ret |= sisusb_send_packet(sisusb, 10, &packet);	}	return ret;}/* The xxx_bulk routines copy a buffer of variable size. They treat the * buffer as chars, therefore lsb/msb has to be corrected if using the * byte/word/long/etc routines for speed-up * * If data is from userland, set "userbuffer" (and clear "kernbuffer"), * if data is in kernel space, set "kernbuffer" (and clear "userbuffer"); * if neither "kernbuffer" nor "userbuffer" are given, it is assumed * that the data already is in the transfer buffer "sisusb->obuf[index]". */static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,				char *kernbuffer, int length,				const char __user *userbuffer, int index,				ssize_t *bytes_written){	struct sisusb_packet packet;	int  ret = 0;	static int msgcount = 0;	u8   swap8, fromkern = kernbuffer ? 1 : 0;	u16  swap16;	u32  swap32, flag = (length >> 28) & 1;	char buf[4];	/* if neither kernbuffer not userbuffer are given, assume	 * data in obuf	 */	if (!fromkern && !userbuffer)		kernbuffer = sisusb->obuf[index];	(*bytes_written = 0);	length &= 0x00ffffff;	while (length) {	    switch (length) {		case 0:			return ret;		case 1:			if (userbuffer) {				if (get_user(swap8, (u8 __user *)userbuffer))					return -EFAULT;			} else				swap8 = kernbuffer[0];			ret = sisusb_write_memio_byte(sisusb,							SISUSB_TYPE_MEM,							addr, swap8);			if (!ret)				(*bytes_written)++;			return ret;		case 2:			if (userbuffer) {				if (get_user(swap16, (u16 __user *)userbuffer))					return -EFAULT;			} else				swap16 = *((u16 *)kernbuffer);			ret = sisusb_write_memio_word(sisusb,							SISUSB_TYPE_MEM,							addr,							swap16);			if (!ret)				(*bytes_written) += 2;			return ret;		case 3:			if (userbuffer) {				if (copy_from_user(&buf, userbuffer, 3))					return -EFAULT;#ifdef __BIG_ENDIAN				swap32 = (buf[0] << 16) |					 (buf[1] <<  8) |					 buf[2];#else				swap32 = (buf[2] << 16) |					 (buf[1] <<  8) |					 buf[0];#endif			} else#ifdef __BIG_ENDIAN				swap32 = (kernbuffer[0] << 16) |					 (kernbuffer[1] <<  8) |					 kernbuffer[2];#else				swap32 = (kernbuffer[2] << 16) |					 (kernbuffer[1] <<  8) |					 kernbuffer[0];#endif			ret = sisusb_write_memio_24bit(sisusb,							SISUSB_TYPE_MEM,							addr,							swap32);			if (!ret)				(*bytes_written) += 3;			return ret;		case 4:			if (userbuffer) {				if (get_user(swap32, (u32 __user *)userbuffer))					return -EFAULT;			} else				swap32 = *((u32 *)kernbuffer);			ret = sisusb_write_memio_long(sisusb,							SISUSB_TYPE_MEM,							addr,							swap32);			if (!ret)				(*bytes_written) += 4;			return ret;		default:			if ((length & ~3) > 0x10000) {			   packet.header  = 0x001f;			   packet.address = 0x000001d4;			   packet.data    = addr;			   ret = sisusb_send_bridge_packet(sisusb, 10,								&packet, 0);			   packet.header  = 0x001f;			   packet.address = 0x000001d0;			   packet.data    = (length & ~3);			   ret |= sisusb_send_bridge_packet(sisusb, 10,								&packet, 0);			   packet.header  = 0x001f;			   packet.address = 0x000001c0;			   packet.data    = flag | 0x16;			   ret |= sisusb_send_bridge_packet(sisusb, 10,								&packet, 0);			   if (userbuffer) {				ret |= sisusb_send_bulk_msg(sisusb,							SISUSB_EP_GFX_LBULK_OUT,							(length & ~3),							NULL, userbuffer, 0,							bytes_written, 0, 1);				userbuffer += (*bytes_written);			   } else if (fromkern) {				ret |= sisusb_send_bulk_msg(sisusb,							SISUSB_EP_GFX_LBULK_OUT,							(length & ~3),							kernbuffer, NULL, 0,							bytes_written, 0, 1);				kernbuffer += (*bytes_written);			   } else {			ret |= sisusb_send_bulk_msg(sisusb,							SISUSB_EP_GFX_LBULK_OUT,							(length & ~3),							NULL, NULL, index,							bytes_written, 0, 1);				kernbuffer += ((*bytes_written) &						(sisusb->obufsize-1));			   }			} else {			   packet.header  = 0x001f;			   packet.address = 0x00000194;			   packet.data    = addr;			   ret = sisusb_send_bridge_packet(sisusb, 10,			   					&packet, 0);			   packet.header  = 0x001f;			   packet.address = 0x00000190;			   packet.data    = (length & ~3);			   ret |= sisusb_send_bridge_packet(sisusb, 10,			   					&packet, 0);			   if (sisusb->flagb0 != 0x16) {				packet.header  = 0x001f;				packet.address = 0x00000180;				packet.data    = flag | 0x16;				ret |= sisusb_send_bridge_packet(sisusb, 10,								&packet, 0);				sisusb->flagb0 = 0x16;			   }			   if (userbuffer) {				ret |= sisusb_send_bulk_msg(sisusb,							SISUSB_EP_GFX_BULK_OUT,							(length & ~3),							NULL, userbuffer, 0,							bytes_written, 0, 1);				userbuffer += (*bytes_written);			   } else if (fromkern) {				ret |= sisusb_send_bulk_msg(sisusb,							SISUSB_EP_GFX_BULK_OUT,							(length & ~3),							kernbuffer, NULL, 0,							bytes_written, 0, 1);				kernbuffer += (*bytes_written);			   } else {				ret |= sisusb_send_bulk_msg(sisusb,							SISUSB_EP_GFX_BULK_OUT,							(length & ~3),							NULL, NULL, index,							bytes_written, 0, 1);				kernbuffer += ((*bytes_written) &						(sisusb->obufsize-1));			   }			}			if (ret) {				msgcount++;				if (msgcount < 500)					printk(KERN_ERR						"sisusbvga[%d]: Wrote %zd of "						"%d bytes, error %d\n",						sisusb->minor, *bytes_written,						length, ret);				else if (msgcount == 500)					printk(KERN_ERR						"sisusbvga[%d]: Too many errors"						", logging stopped\n",						sisusb->minor);			}			addr += (*bytes_written);			length -= (*bytes_written);	    }	    if (ret)	    	break;	}	return ret ? -EIO : 0;}/* Remember: Read data in packet is in machine-endianess! So for * byte, word, 24bit, long no endian correction is necessary. */static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,							u32 addr, u8 *data){

⌨️ 快捷键说明

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