dabusb.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 959 行 · 第 1/2 页

C
959
字号
/*****************************************************************************//* *      dabusb.c  --  dab usb driver. * *      Copyright (C) 1999  Deti Fliegl (deti@fliegl.de) * *      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. * * * *  $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $ * *//*****************************************************************************/#include <linux/module.h>#include <linux/socket.h>#include <linux/list.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/init.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include <linux/delay.h>#include <linux/usb.h>#include "compat.h"#include <linux/mutex.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)#include <linux/firmware.h>#include <linux/ihex.h>#endif#include "dabusb.h"#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)#include "dabfirmware.h"#endif/* * Version Information */#define DRIVER_VERSION "v1.54"#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de"#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999"/* --------------------------------------------------------------------- */#ifdef CONFIG_USB_DYNAMIC_MINORS#define NRDABUSB 256#else#define NRDABUSB 4#endif/*-------------------------------------------------------------------*/static dabusb_t dabusb[NRDABUSB];static int buffers = 256;static struct usb_driver dabusb_driver;/*-------------------------------------------------------------------*/static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src){	unsigned long flags;	struct list_head *tmp;	int ret = 0;	spin_lock_irqsave (&s->lock, flags);	if (list_empty (src)) {		// no elements in source buffer		ret = -1;		goto err;	}	tmp = src->next;	list_move_tail (tmp, dst);  err:	spin_unlock_irqrestore (&s->lock, flags);	return ret;}/*-------------------------------------------------------------------*/#ifdef DEBUGstatic void dump_urb (struct urb *urb){	dbg("urb                   :%p", urb);	dbg("dev                   :%p", urb->dev);	dbg("pipe                  :%08X", urb->pipe);	dbg("status                :%d", urb->status);	dbg("transfer_flags        :%08X", urb->transfer_flags);	dbg("transfer_buffer       :%p", urb->transfer_buffer);	dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);	dbg("actual_length         :%d", urb->actual_length);	dbg("setup_packet          :%p", urb->setup_packet);	dbg("start_frame           :%d", urb->start_frame);	dbg("number_of_packets     :%d", urb->number_of_packets);	dbg("interval              :%d", urb->interval);	dbg("error_count           :%d", urb->error_count);	dbg("context               :%p", urb->context);	dbg("complete              :%p", urb->complete);}#endif/*-------------------------------------------------------------------*/static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q){	unsigned long flags;	pbuff_t b;	dbg("dabusb_cancel_queue");	spin_lock_irqsave (&s->lock, flags);	list_for_each_entry(b, q, buff_list) {#ifdef DEBUG		dump_urb(b->purb);#endif		usb_unlink_urb (b->purb);	}	spin_unlock_irqrestore (&s->lock, flags);	return 0;}/*-------------------------------------------------------------------*/static int dabusb_free_queue (struct list_head *q){	struct list_head *tmp;	struct list_head *p;	pbuff_t b;	dbg("dabusb_free_queue");	for (p = q->next; p != q;) {		b = list_entry (p, buff_t, buff_list);#ifdef DEBUG		dump_urb(b->purb);#endif		kfree(b->purb->transfer_buffer);		usb_free_urb(b->purb);		tmp = p->next;		list_del (p);		kfree (b);		p = tmp;	}	return 0;}/*-------------------------------------------------------------------*/static int dabusb_free_buffers (pdabusb_t s){	unsigned long flags;	dbg("dabusb_free_buffers");	spin_lock_irqsave(&s->lock, flags);	dabusb_free_queue (&s->free_buff_list);	dabusb_free_queue (&s->rec_buff_list);	spin_unlock_irqrestore(&s->lock, flags);	s->got_mem = 0;	return 0;}/*-------------------------------------------------------------------*/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs)#elsestatic void dabusb_iso_complete (struct urb *purb)#endif{	pbuff_t b = purb->context;	pdabusb_t s = b->s;	int i;	int len;	int dst = 0;	void *buf = purb->transfer_buffer;	dbg("dabusb_iso_complete");	// process if URB was not killed	if (purb->status != -ENOENT) {		unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);		int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));		for (i = 0; i < purb->number_of_packets; i++)			if (!purb->iso_frame_desc[i].status) {				len = purb->iso_frame_desc[i].actual_length;				if (len <= pipesize) {					memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len);					dst += len;				}				else					err("dabusb_iso_complete: invalid len %d", len);			}			else				dev_warn(&purb->dev->dev, "dabusb_iso_complete: corrupted packet status: %d\n", purb->iso_frame_desc[i].status);		if (dst != purb->actual_length)			err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);	}	if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {		s->overruns++;		err("overrun (%d)", s->overruns);	}	wake_up (&s->wait);}/*-------------------------------------------------------------------*/static int dabusb_alloc_buffers (pdabusb_t s){	int transfer_len = 0;	pbuff_t b;	unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);	int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));	int packets = _ISOPIPESIZE / pipesize;	int transfer_buffer_length = packets * pipesize;	int i;	dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",		 pipesize, packets, transfer_buffer_length);	while (transfer_len < (s->total_buffer_size << 10)) {		b = kzalloc(sizeof (buff_t), GFP_KERNEL);		if (!b) {			err("kzalloc(sizeof(buff_t))==NULL");			goto err;		}		b->s = s;		b->purb = usb_alloc_urb(packets, GFP_KERNEL);		if (!b->purb) {			err("usb_alloc_urb == NULL");			kfree (b);			goto err;		}		b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL);		if (!b->purb->transfer_buffer) {			kfree (b->purb);			kfree (b);			err("kmalloc(%d)==NULL", transfer_buffer_length);			goto err;		}		b->purb->transfer_buffer_length = transfer_buffer_length;		b->purb->number_of_packets = packets;		b->purb->complete = dabusb_iso_complete;		b->purb->context = b;		b->purb->dev = s->usbdev;		b->purb->pipe = pipe;		b->purb->transfer_flags = URB_ISO_ASAP;		for (i = 0; i < packets; i++) {			b->purb->iso_frame_desc[i].offset = i * pipesize;			b->purb->iso_frame_desc[i].length = pipesize;		}		transfer_len += transfer_buffer_length;		list_add_tail (&b->buff_list, &s->free_buff_list);	}	s->got_mem = transfer_len;	return 0;	err:	dabusb_free_buffers (s);	return -ENOMEM;}/*-------------------------------------------------------------------*/static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb){	int ret;	unsigned int pipe;	int actual_length;	dbg("dabusb_bulk");	if (!pb->pipe)		pipe = usb_rcvbulkpipe (s->usbdev, 2);	else		pipe = usb_sndbulkpipe (s->usbdev, 2);	ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100);	if(ret<0) {		err("dabusb: usb_bulk_msg failed(%d)",ret);		if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {			err("set_interface failed");			return -EINVAL;		}	}	if( ret == -EPIPE ) {		dev_warn(&s->usbdev->dev, "CLEAR_FEATURE request to remove STALL condition.\n");		if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))			err("request failed");	}	pb->size = actual_length;	return ret;}/* --------------------------------------------------------------------- */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len)#elsestatic int dabusb_writemem (pdabusb_t s, int pos, const unsigned char *data,			    int len)#endif{	int ret;	unsigned char *transfer_buffer =  kmalloc (len, GFP_KERNEL);	if (!transfer_buffer) {		err("dabusb_writemem: kmalloc(%d) failed.", len);		return -ENOMEM;	}	memcpy (transfer_buffer, data, len);	ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300);	kfree (transfer_buffer);	return ret;}/* --------------------------------------------------------------------- */static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit){	dbg("dabusb_8051_reset: %d",reset_bit);	return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1);}/* --------------------------------------------------------------------- */static int dabusb_loadmem (pdabusb_t s, const char *fname){	int ret;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)	PINTEL_HEX_RECORD ptr = firmware;#else	const struct ihex_binrec *rec;	const struct firmware *fw;#endif	dbg("Enter dabusb_loadmem (internal)");#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)	ret = request_ihex_firmware(&fw, "dabusb/firmware.fw", &s->usbdev->dev);	if (ret) {		err("Failed to load \"dabusb/firmware.fw\": %d\n", ret);		goto out;	}#endif	ret = dabusb_8051_reset (s, 1);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)	while (ptr->Type == 0) {#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)		dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length);#else	for (rec = (const struct ihex_binrec *)fw->data; rec;	     rec = ihex_next_binrec(rec)) {		dbg("dabusb_writemem: %04X %p %d)", be32_to_cpu(rec->addr),		    rec->data, be16_to_cpu(rec->len));#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)		ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length);#else		ret = dabusb_writemem(s, be32_to_cpu(rec->addr), rec->data,				       be16_to_cpu(rec->len));#endif		if (ret < 0) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)			err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length);#else			err("dabusb_writemem failed (%d %04X %p %d)", ret,			    be32_to_cpu(rec->addr), rec->data,			    be16_to_cpu(rec->len));#endif			break;		}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)		ptr++;#endif	}	ret = dabusb_8051_reset (s, 0);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)#else	release_firmware(fw); out:#endif	dbg("dabusb_loadmem: exit");	return ret;}/* --------------------------------------------------------------------- */static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b){	b->size = 4;	b->data[0] = 0x2a;	b->data[1] = 0;	b->data[2] = 0;	b->data[3] = 0;	dbg("dabusb_fpga_clear");	return dabusb_bulk (s, b);}/* --------------------------------------------------------------------- */static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b){	b->size = 4;	b->data[0] = 0x2c;	b->data[1] = 0;	b->data[2] = 0;	b->data[3] = 0;	dbg("dabusb_fpga_init");	return dabusb_bulk (s, b);}/* --------------------------------------------------------------------- */static int dabusb_fpga_download (pdabusb_t s, const char *fname){	pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)	const struct firmware *fw;#endif	unsigned int blen, n;	int ret;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)	unsigned char *buf = bitstream;#endif	dbg("Enter dabusb_fpga_download (internal)");	if (!b) {		err("kmalloc(sizeof(bulk_transfer_t))==NULL");		return -ENOMEM;	}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)	ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev);	if (ret) {		err("Failed to load \"dabusb/bitstream.bin\": %d\n", ret);		kfree(b);		return ret;	}#endif	b->pipe = 1;	ret = dabusb_fpga_clear (s, b);	mdelay (10);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)	blen = buf[73] + (buf[72] << 8);#else	blen = fw->data[73] + (fw->data[72] << 8);#endif	dbg("Bitstream len: %i", blen);	b->data[0] = 0x2b;	b->data[1] = 0;	b->data[2] = 0;	b->data[3] = 60;	for (n = 0; n <= blen + 60; n += 60) {		// some cclks for startup		b->size = 64;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)		memcpy (b->data + 4, buf + 74 + n, 60);#else

⌨️ 快捷键说明

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