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

📄 superh.c

📁 Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/drivers/usbd/superh_bi/udc.c -- USB Device Controller driver.  * * Copyright (c) 2000, 2001, 2002 Lineo * * By:  *      Stuart Lynne <sl@lineo.com>,  *      Tom Rushworth <tbr@lineo.com>,  *      Bruce Balden <balden@lineo.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *//*****************************************************************************/#include <linux/config.h>#include <linux/module.h>#include "../usbd-export.h"#include "../usbd-build.h"#include "../usbd-module.h"MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com");MODULE_DESCRIPTION ("USB Device SuperH Bus Interface");USBD_MODULE_INFO ("superh_bi 0.1-alpha");#include <linux/kernel.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/delay.h>#include <asm/types.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/sh7727.h>#include "../usbd.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-inline.h"#include "usbd-bi.h"#include "superh.h"#include "superh-hardware.h"#define MIN(a,b) ((a) < (b) ? (a) : (b))#define MAX(a,b) ((a) > (b) ? (a) : (b))/* * Define what interrupts are high versus low priority */#define F0_HIGH (EP1_FULL | EP2_TR | EP2_EMPTY )#define F0_LOW  (BRST | SETUP_TS | EP0o_TS | EP0i_TR | EP0i_TS)#define F1_HIGH (0)#define F1_LOW  (EP3_TR | EP3_TS | VBUSF)static struct usb_device_instance *udc_device;	// required for the interrupt handler/* * ep_endpoints - map physical endpoints to logical endpoints */static struct usb_endpoint_instance *ep_endpoints[UDC_MAX_ENDPOINTS];static struct urb *ep0_urb;static unsigned char usb_address;extern unsigned int udc_interrupts;unsigned int udc_f0_interrupts;unsigned int udc_f1_interrupts;unsigned long udc_vbusf_time;/* ********************************************************************************************* *//* * IO */void and_b (unsigned short mask, unsigned long addr){	ctrl_outb (ctrl_inw (addr) & mask, addr);}void or_b (unsigned short mask, unsigned long addr){	ctrl_outb (ctrl_inw (addr) | mask, addr);}void and_w (unsigned short mask, unsigned long addr){	ctrl_outw (ctrl_inw (addr) & mask, addr);}void or_w (unsigned short mask, unsigned long addr){	ctrl_outw (ctrl_inw (addr) | mask, addr);}// IO addresses for each physical ports FIFOunsigned long ep_address_o[4] = { USBEPDR0O, USBEPDR1, 0L, 0L, };unsigned long ep_address_i[4] = { USBEPDR0I, 0L, USBEPDR2, USBEPDR3, };// IO addresses for each physical ports triggerunsigned char ep_trigger_o[4] = { EP0o_PKTE, EP1_PKTE, 0L, 0L, };unsigned char ep_trigger_i[4] = { EP0i_PKTE, 0L, EP2_PKTE, EP3_PKTE, };/** * superh_write_buffer - write a buffer to the superh fifo * @ep: endpoint * @b: pointer to buffer to write * @size: number of bytes to write */static /*__inline__*/ void superh_write_buffer (unsigned char ep, unsigned char *b,						unsigned char size){	if ((ep < UDC_MAX_ENDPOINTS) && ep_address_i[ep]) {		while (size-- > 0) {			ctrl_outb (*b++, ep_address_i[ep]);		}		ctrl_outb (ep_trigger_i[ep], USBTRG);	}}/** * superh_read_buffer - fill a buffer from the superh fifo * @ep: endpoint * @b: pointer to buffer to fill * @size: number of bytes to read */static /*__inline__*/ void superh_read_buffer (unsigned char ep, unsigned char *b,					       unsigned char size){	if ((ep < UDC_MAX_ENDPOINTS) && ep_address_o[ep]) {		while (size-- > 0) {			*b++ = ctrl_inb (ep_address_o[ep]);		}		ctrl_outb (ep_trigger_o[ep], USBTRG);	}}/* ********************************************************************************************* *//* Bulk OUT (recv) */static void /*__inline__*/ superh_out_ep1 (struct usb_endpoint_instance *endpoint){	int size = ctrl_inb (USBEPSZ1);	if (endpoint && endpoint->rcv_urb && size) {		// read data		superh_read_buffer (1, endpoint->rcv_urb->buffer + endpoint->rcv_urb->actual_length,				    size);		usbd_rcv_complete_irq (endpoint, size, 0);	} else {		// reset fifo		or_b (EP1_CLEAR, USBFCLR);		usbd_rcv_complete_irq (endpoint, 0, EINVAL);	}}/* ********************************************************************************************* *//* Bulk IN (tx) *//** * superh_in_epn - process tx interrupt * @ep: * @endpoint: * * Determine status of last data sent, queue new data. */static /* __inline__ */ void superh_in_epn (int ep, int restart){	if (ctrl_inb (USBIFR0) & EP2_EMPTY) {		if ((ep < UDC_MAX_ENDPOINTS) && ep_endpoints[ep]) {			struct usb_endpoint_instance *endpoint = ep_endpoints[ep];			usbd_tx_complete_irq (endpoint, restart);			if (endpoint->tx_urb) {				struct urb *urb = endpoint->tx_urb;				if ((urb->actual_length - endpoint->sent) > 0) {					endpoint->last =					    MIN (urb->actual_length - endpoint->sent,						 endpoint->tx_packetSize);					superh_write_buffer (ep, urb->buffer + endpoint->sent,							     endpoint->last);				} else {					// XXX ZLP					endpoint->last = 0;					superh_write_buffer (ep, urb->buffer + endpoint->sent, 0);				}				// enable transmit done interrupt				switch (ep) {				case 2:					or_b (EP2_TR | EP2_EMPTY, USBIER0);					break;				case 3:					or_b (EP3_TR | EP3_TS, USBIER1);					break;				}			} else {				// disable transmit done interrupt				switch (ep) {				case 2:					if (ctrl_inb (USBIER0) & (EP2_TR | EP2_EMPTY)) {						and_b (~(EP2_TR | EP2_EMPTY), USBIER0);					}					break;				case 3:					and_b (~(EP3_TR | EP3_TS), USBIER1);					break;				}			}		}	}}/* ********************************************************************************************* *//* Control (endpoint zero) *//** * superh_in_ep0 - start transmit * @ep: */static void /*__inline__*/ superh_in_ep0 (struct usb_endpoint_instance *endpoint){	if (endpoint && endpoint->tx_urb) {		struct urb *urb = endpoint->tx_urb;		printk (KERN_DEBUG "superh_in_ep0: length: %d\n", endpoint->tx_urb->actual_length);	// XXX 		if ((urb->actual_length - endpoint->sent) > 0) {			endpoint->last =			    MIN (urb->actual_length - endpoint->sent, endpoint->tx_packetSize);			superh_write_buffer (0, urb->buffer + endpoint->sent, endpoint->last);		} else {			// XXX ZLP			endpoint->last = 0;			superh_write_buffer (0, urb->buffer + endpoint->sent, 0);		}	}}/** * superh_ep0_setup */static void superh_ep0_setup (void){	if (ep_endpoints[0]) {		int i;		struct usb_endpoint_instance *endpoint = ep_endpoints[0];		unsigned char *cp = (unsigned char *) &ep0_urb->device_request;		for (i = 0; i < 8; i++) {			cp[i] = ctrl_inb (USBEPDR0S);		}		// process setup packet		if (usbd_recv_setup (ep0_urb)) {			printk (KERN_DEBUG "superh_ep0: setup failed\n");			return;		}		// check data direction		if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) ==		    USB_REQ_HOST2DEVICE) {			// should we setup to receive data			if (le16_to_cpu (ep0_urb->device_request.wLength)) {				printk (KERN_DEBUG "superh_ep0: setup to read data %d\n",					le16_to_cpu (ep0_urb->device_request.wLength));				endpoint->rcv_urb = ep0_urb;				endpoint->rcv_urb->actual_length = 0;				//superh_out(0, endpoint);				return;			}			printk (KERN_DEBUG "superh_ep0: send ack %d\n", le16_to_cpu (ep0_urb->device_request.wLength));	// XXX 			// should be finished, send ack			ctrl_outb (EP0s_PKTE, USBTRG);			return;		}		// we should be sending data back		// verify that we have non-zero request length		if (!le16_to_cpu (ep0_urb->device_request.wLength)) {			udc_stall_ep (0);			return;		}		// verify that we have non-zero length response		if (!ep0_urb->actual_length) {			udc_stall_ep (0);			return;		}		// send ack prior to sending data		ctrl_outb (EP0s_PKTE, USBTRG);		// start sending		endpoint->tx_urb = ep0_urb;		endpoint->sent = 0;		endpoint->last = 0;		superh_in_ep0 (endpoint);	}}/* ********************************************************************************************* *//* Interrupt Handler(s) *//** * superh_int_hndlr_f0 - high priority interrupt handler * */static void superh_int_hndlr_f0 (int irq, void *dev_id, struct pt_regs *regs){	unsigned char f0_status;	udc_interrupts++;	udc_f0_interrupts++;	f0_status = ctrl_inb (USBIFR0);	if (f0_status & EP1_FULL) {		superh_out_ep1 (ep_endpoints[1]);		f0_status = ctrl_inb (USBIFR0);		if (f0_status & EP1_FULL) {			superh_out_ep1 (ep_endpoints[1]);		}	} else if (f0_status & (EP2_TR | EP2_EMPTY)) {		superh_in_epn (2, 0);	// XXX status?		ctrl_outb (~(f0_status & EP2_TR), USBIFR0);	}}/** * superh_int_hndlr_f1 - low priority interrupt handler * */static void superh_int_hndlr_f1 (int irq, void *dev_id, struct pt_regs *regs){	unsigned char f0_status;	unsigned char f1_status;	udc_interrupts++;	udc_f1_interrupts++;	f0_status = ctrl_inb (USBIFR0);	f1_status = ctrl_inb (USBIFR1);	ctrl_outb (~(f0_status & F0_LOW), USBIFR0);	ctrl_outb (~(f1_status & F1_LOW), USBIFR1);	//printk(KERN_DEBUG"superh_int_hndlr_f1[%x] status %02x %02x\n", udc_interrupts, f0_status, f1_status); // XXX 	if (f1_status & VBUSF) {		/*		 * XXX vbusf can bounce, probably should disarm vbusf interrupt, for now, just check 		 * that we don't handle it more than once.		 */		if (!udc_vbusf_time || ((jiffies - udc_vbusf_time) > 1)) {			if (udc_device) {				if (f1_status & VBUSMN) {					printk (KERN_DEBUG						"superh_int_hndlr_f1[%x]: VBUSF VBUSMN set\n",						udc_interrupts);				} else {					printk (KERN_DEBUG						"superh_int_hndlr_f1[%x]: VBUSF VBUSMN reset\n",						udc_interrupts);				}			}		}		udc_vbusf_time = jiffies;	} else {		udc_vbusf_time = 0;	}	if (f0_status & BRST) {		printk (KERN_DEBUG "superh_int_hndlr_f1[%x]: BRST bus reset\n", udc_interrupts);		// reset fifo's and stall's		or_b (EP3_CLEAR | EP1_CLEAR | EP2_CLEAR | EP0o_CLEAR | EP0i_CLEAR, USBFCLR);		or_b (0, USBEPSTL);		if (udc_device->device_state != DEVICE_RESET) {			printk (KERN_DEBUG "superh_int_hndlr_f1[%x]: DEVICE RESET\n",				udc_interrupts);			usbd_device_event_irq (udc_device, DEVICE_RESET, 0);		}	}	if (f0_status & SETUP_TS) {		printk (KERN_DEBUG "superh_int_hndlr_f1[%x]: SETUP TS\n", udc_interrupts);		or_b (EP0o_CLEAR | EP0i_CLEAR, USBFCLR);		superh_ep0_setup ();		if (udc_device->device_state == STATE_DEFAULT) {			/*			 * superh won't give us set address, configuration or interface, but at least			 * we know that at this point we know that a host is talking to us, close			 * enough.			 */			usbd_device_event (udc_device, DEVICE_ADDRESS_ASSIGNED, 0);			udc_device->configuration = 0;			usbd_device_event (udc_device, DEVICE_CONFIGURED, 0);			udc_device->interface = 1;	// no options			udc_device->alternate = 0;	// no options			usbd_device_event (udc_device, DEVICE_SET_INTERFACE, 0);		}	}	if (f0_status & EP0i_TR) {		usbd_tx_complete_irq (ep_endpoints[0], 0);		superh_in_ep0 (ep_endpoints[0]);	}	if (f0_status & EP0o_TS) {		printk (KERN_DEBUG "superh_int_hndlr_f1[%x]: ep0o TS\n", udc_interrupts);	}	if (f0_status & EP0i_TS) {		printk (KERN_DEBUG "superh_int_hndlr_f1[%x]: ep0iTS\n", udc_interrupts);	}	if (f1_status & EP3_TR) {		printk (KERN_DEBUG "superh_int_hndlr_f1[%x]: EP3 TR\n", udc_interrupts);

⌨️ 快捷键说明

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