📄 sl11.c
字号:
/* * sl11_bi/udc.c * * 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 SL11 Bus Interface");USBD_MODULE_INFO ("sl11_bi 0.1-alpha");#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/atomic.h>#include <asm/io.h>#include <linux/netdevice.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/delay.h>#include "../usbd.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-inline.h"#include "usbd-bi.h"#include "sl11.h"#include "sl11-info.h"#define MIN(a,b) ((a) < (b) ? (a) : (b))#define MAX(a,b) ((a) > (b) ? (a) : (b))/* * ep_address - endpoint buffer addresses * * 0-3 epNa * 4-7 epNb */static unsigned char ep_address[UDC_MAX_ENDPOINTS * 2] = { EP_S_BUF, EP_S_BUF, EP_S_BUF, EP_S_BUF, EP_S_BUF, EP_S_BUF, EP_S_BUF, EP_S_BUF};/* * ep_register - endpoint register addresses * * 0-3 epNa * 4-7 epNb */static unsigned char ep_register[UDC_MAX_ENDPOINTS * 2] = { EP0_Control, EP1_Control, EP2_Control, EP3_Control, EP0_Control + 8, EP1_Control + 8, EP2_Control + 8, EP3_Control + 8};static struct usb_device_instance *udc_device; // required for the interrupt handler/* * ep_sequence - current sequence number for each endpoint */static unsigned char ep_sequence[UDC_MAX_ENDPOINTS] = { 0, 0, 0, 0};/* * ep_next - next ping pong buffer */static unsigned char ep_next[UDC_MAX_ENDPOINTS] = { 0, 0, 0, 0};/* * ep_int_mask - interrupt status register endpoint bit masks */static unsigned char ep_int_mask[UDC_MAX_ENDPOINTS] = { INT_EP0_DONE, INT_EP1_DONE, INT_EP2_DONE, INT_EP3_DONE};/* * ep_endpoints - map physical endpoints to logical endpoints */static struct usb_endpoint_instance *ep_endpoints[UDC_MAX_ENDPOINTS];// static struct urb ep0_urb;static struct urb *ep0_urb;static unsigned char usb_address;static int udc_saw_sof;static int udc_suspended;static int udc_addressed;static struct tq_struct sl11_tq;extern unsigned int udc_interrupts;unsigned int udc_ticks;/* ********************************************************************************************* */#ifdef CONFIG_X86/** * sl11write_byte - write a byte to the sl11 * @a: sl11 address * @b: byte to write */static __inline__ void sl11write_byte (unsigned char a, unsigned char b){ outb (a, UDC_ADDR); outb (b, UDC_ADDR + 1);}static __inline__ void _sl11write_byte (unsigned char a, unsigned char b){ printk (KERN_DEBUG "sl11write_byte: Reg: %02x Val: %02x\n", a, b); outb (a, UDC_ADDR); outb (b, UDC_ADDR + 1);}/** * sl11write_buffer - write a buffer to the sl11 using auto-increment mode * @a: sl11 address * @b: pointer to buffer to write * @size: number of bytes to write */static __inline__ void sl11write_buffer (unsigned char a, unsigned char *b, unsigned char size){ outb (a, UDC_ADDR); while (size--) { outb (*b++, UDC_ADDR + 1); }}/** * sl11read_byte - read a byte from the sl11 and return * @a: sl11 address */static __inline__ unsigned char sl11read_byte (unsigned char a){ outb (a, UDC_ADDR); return inb (UDC_ADDR + 1);}/** * sl11read_buffer - fill a buffer from the sl11 using auto-increment mode * @a: sl11 address * @b: pointer to buffer to fill * @size: number of bytes to read */static __inline__ void sl11read_buffer (unsigned char a, unsigned char *b, unsigned char size){ outb (a, UDC_ADDR); while (size--) { *b++ = inb (UDC_ADDR + 1); }}/** * sl11clear - clear sl11 memory * @a: sl11 address * @size: bytes to clear */static void sl11clear (unsigned char a, unsigned char size){ outb (a, UDC_ADDR); while (size--) { outb (0, UDC_ADDR + 1); }}#else#abort SL11 memory mapped IO not implemented#endif/* ********************************************************************************************* *//** * sl11write_epn - write a byte to a sl11 endpoint register * @a: endpoint * @b: endpoint register * @d: byte to write */static __inline__ void sl11write_epn (unsigned char ep, unsigned char b, unsigned char c){ sl11write_byte (ep_register[ep] + b, c);}static __inline__ void _sl11write_epn (unsigned char ep, unsigned char b, unsigned char c){ printk (KERN_DEBUG "sl11write_epn: Reg: %02x Val: %02x\n", ep_register[ep] + b, c); _sl11write_byte (ep_register[ep] + b, c);}/** * sl11read_epn - read a byte from a sl11 endpoint register * @a: endpoint * @b: endpoint register * @d: byte to write */__inline__ unsigned char sl11read_epn (unsigned char ep, unsigned char b){ return sl11read_byte (ep_register[ep] + b);}/* ********************************************************************************************* *//** * sl11_dump */static void sl11_dump (unsigned char a, unsigned char size){ int i; for (i = 0; i < size; i++) { if ((i % 8) == 0) { printk ("\n[%02x]: ", a + i); } printk ("%02x ", sl11read_byte (a + i)); } printk ("\n");}static void sl11_dump_epn (unsigned char ep, char *m){ printk ("ep[%d]: Ctl:%02x Adr:%02x Xfr:%02x Sts:%02x Cnt:%02x Seq:%d%s", ep, sl11read_epn (ep, EPN_Control), sl11read_epn (ep, EPN_Address), sl11read_epn (ep, EPN_XferLen), sl11read_epn (ep, EPN_Status), sl11read_epn (ep, EPN_Counter), ep_sequence[ep & 0x3], m);}/** * sl11_probe - initialize * * 0. Issue a reset to CtrlReg * * 1. After reset we typically see: * * IntStatus 0x40 or 0x60 * DATASet 0x10 * * 2. We test that IntStatus can be changed to 0x00 by writing 0xff to it. * * 3. If successful clear all chip memory. * **/static int sl11_probe (void){ sl11_dump (0, 64); printk (KERN_DEBUG "sl11_probe: start\n"); // reset sl11write_byte (CtrlReg, CTRL_USB_RESET); udelay (100); // XXX may not be needed sl11write_byte (CtrlReg, 0); sl11_dump (0, 64); printk (KERN_DEBUG "sl11_probe: RESET\n"); /* * XXX * * If device is present DATASet&CDS_RESERVED will be true. * * After reset we will see IntStatus & INT_USB_RESET if cable is plugged in. * */ if (((sl11read_byte (IntStatus) & INT_USB_RESET) != INT_USB_RESET) || ((sl11read_byte (DATASet) & 0x10) != 0x10)) { sl11_dump (0, 64); printk (KERN_DEBUG "sl11_probe: cannot see " UDC_NAME ", failed initial probe\n"); //udc_regs(); //return -EINVAL; } // reset interrupt status sl11write_byte (IntStatus, 0xff); if ((sl11read_byte (IntStatus) != 0x00)) { sl11_dump (0, 64); printk (KERN_DEBUG "sl11_probe: cannot see " UDC_NAME ", failed interrupt status reset\n"); udc_regs (); return -EINVAL; } // success! // clear all memory sl11clear (0, 255); printk (KERN_DEBUG "sl11_probe: found and setup\n"); //sl11_dump(0, 64); //udc_regs(); return 0;}/* ********************************************************************************************* *//** * sl11send_data - send packet via endpoint * @ep: logical endpoint number * @bp: pointer to data * @size: bytes to write */static void __inline__ sl11send_data (unsigned char ep, unsigned char *bp, unsigned char size){ // copy data from buffer to chip if (bp && size) { sl11write_buffer (ep_address[ep], bp, size); } sl11write_epn (ep, EPN_XferLen, size); // arm sl11write_epn (ep, EPN_Control, EPN_CTRL_ARM | EPN_CTRL_ENABLE | EPN_CTRL_DIRECTION_IN | (ep_sequence[ep] ? EPN_CTRL_SEQUENCE : 0) );}/** * s111send_done * @ep */static void __inline__ sl11send_done (unsigned ep){ // disarm sl11write_epn (ep, EPN_Control, EPN_CTRL_ENABLE | EPN_CTRL_DIRECTION_IN); // flip sequence ep_sequence[ep] = (~ep_sequence[ep]) & 0x1;}/* ********************************************************************************************* *//** * s111read_init * @ep: endpoint */static void sl11read_init (unsigned char ep, unsigned char size){ // setup packet size sl11write_epn (ep, EPN_XferLen, size); // arm sl11write_epn (ep, EPN_Control, EPN_CTRL_ARM | EPN_CTRL_ENABLE | EPN_CTRL_DIRECTION_OUT);}/** * sl11read_done * @ep: endpoint */static void sl11read_done (unsigned char ep, unsigned char *bp, unsigned char size){ // disarm sl11write_epn (ep, EPN_Control, EPN_CTRL_ENABLE | EPN_CTRL_DIRECTION_OUT); // copy data from chip to buffer sl11read_buffer (ep_address[ep], bp, size);}/* ********************************************************************************************* *//** * sl11_out - process rcv interrupt * * Queue received data. */static void __inline__ sl11_out (unsigned int ep, struct usb_endpoint_instance *endpoint){ int len; int cnt; int error = 0; int adr; int i; unsigned char status; unsigned char ctl; unsigned int cep; // loop alternating between A-B register sets looking for ACK in packet status // for (i = 0; i < 8; i++) { cep = ep + (ep_next[ep] ? 4 : 0); ep_next[ep] = ~ep_next[ep] & 0x1; status = sl11read_epn (cep, EPN_Status); //printk(KERN_DEBUG"[%d] out[%d]: seq: %d next: %d sts: %02x\n", udc_interrupts, ep, ep_sequence[ep], ep_next[ep], status); if (!(status & EPN_PSTS_ACK)) { continue; //return; } // check packet status bits for errors ctl = sl11read_epn (cep, EPN_Control); len = sl11read_epn (cep, EPN_XferLen); cnt = sl11read_epn (cep, EPN_Counter); adr = sl11read_epn (cep, EPN_Address); //printk(KERN_DEBUG"[%d] out[%d]: sts: %02x len: %d cnt: %d adr: %02x seq: %02x bytes: %0d\n", // udc_interrupts, cep, status, len, cnt, adr, ep_sequence[ep], len - cnt); //sl11_dump_epn(ep, " "); //sl11_dump_epn(ep + 4, "\n"); len -= cnt; if (status & (EPN_PSTS_ERROR | EPN_PSTS_TIMEOUT | EPN_PSTS_SETUP | EPN_PSTS_OVERFLOW)) { printk (KERN_DEBUG "sl11_out[%d]: ERROR\n", cep); error = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -