Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
   1/*****************************************************************************
   2* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
   3*
   4* Unless you and Broadcom execute a separate written software license
   5* agreement governing use of this software, this software is licensed to you
   6* under the terms of the GNU General Public License version 2, available at
   7* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
   8*
   9* Notwithstanding the above, under no circumstances may you combine this
  10* software in any way with any other Broadcom software provided under a
  11* license other than the GPL, without Broadcom's express prior written
  12* consent.
  13*****************************************************************************/
  14
  15/****************************************************************************/
  16/**
  17*   @file   dma.c
  18*
  19*   @brief  Implements the DMA interface.
  20*/
  21/****************************************************************************/
  22
  23/* ---- Include Files ---------------------------------------------------- */
  24
  25#include <linux/module.h>
  26#include <linux/device.h>
  27#include <linux/dma-mapping.h>
  28#include <linux/interrupt.h>
  29#include <linux/sched.h>
  30#include <linux/irqreturn.h>
  31#include <linux/proc_fs.h>
  32#include <linux/slab.h>
  33
  34#include <mach/timer.h>
  35
  36#include <linux/pfn.h>
  37#include <linux/atomic.h>
  38#include <mach/dma.h>
  39
  40/* ---- Public Variables ------------------------------------------------- */
  41
  42/* ---- Private Constants and Types -------------------------------------- */
  43
  44#define MAKE_HANDLE(controllerIdx, channelIdx)    (((controllerIdx) << 4) | (channelIdx))
  45
  46#define CONTROLLER_FROM_HANDLE(handle)    (((handle) >> 4) & 0x0f)
  47#define CHANNEL_FROM_HANDLE(handle)       ((handle) & 0x0f)
  48
  49
  50/* ---- Private Variables ------------------------------------------------ */
  51
  52static DMA_Global_t gDMA;
  53static struct proc_dir_entry *gDmaDir;
  54
  55#include "dma_device.c"
  56
  57/* ---- Private Function Prototypes -------------------------------------- */
  58
  59/* ---- Functions  ------------------------------------------------------- */
  60
  61/****************************************************************************/
  62/**
  63*   Displays information for /proc/dma/channels
  64*/
  65/****************************************************************************/
  66
  67static int dma_proc_read_channels(char *buf, char **start, off_t offset,
  68				  int count, int *eof, void *data)
  69{
  70	int controllerIdx;
  71	int channelIdx;
  72	int limit = count - 200;
  73	int len = 0;
  74	DMA_Channel_t *channel;
  75
  76	if (down_interruptible(&gDMA.lock) < 0) {
  77		return -ERESTARTSYS;
  78	}
  79
  80	for (controllerIdx = 0; controllerIdx < DMA_NUM_CONTROLLERS;
  81	     controllerIdx++) {
  82		for (channelIdx = 0; channelIdx < DMA_NUM_CHANNELS;
  83		     channelIdx++) {
  84			if (len >= limit) {
  85				break;
  86			}
  87
  88			channel =
  89			    &gDMA.controller[controllerIdx].channel[channelIdx];
  90
  91			len +=
  92			    sprintf(buf + len, "%d:%d ", controllerIdx,
  93				    channelIdx);
  94
  95			if ((channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED) !=
  96			    0) {
  97				len +=
  98				    sprintf(buf + len, "Dedicated for %s ",
  99					    DMA_gDeviceAttribute[channel->
 100								 devType].name);
 101			} else {
 102				len += sprintf(buf + len, "Shared ");
 103			}
 104
 105			if ((channel->flags & DMA_CHANNEL_FLAG_NO_ISR) != 0) {
 106				len += sprintf(buf + len, "No ISR ");
 107			}
 108
 109			if ((channel->flags & DMA_CHANNEL_FLAG_LARGE_FIFO) != 0) {
 110				len += sprintf(buf + len, "Fifo: 128 ");
 111			} else {
 112				len += sprintf(buf + len, "Fifo: 64  ");
 113			}
 114
 115			if ((channel->flags & DMA_CHANNEL_FLAG_IN_USE) != 0) {
 116				len +=
 117				    sprintf(buf + len, "InUse by %s",
 118					    DMA_gDeviceAttribute[channel->
 119								 devType].name);
 120#if (DMA_DEBUG_TRACK_RESERVATION)
 121				len +=
 122				    sprintf(buf + len, " (%s:%d)",
 123					    channel->fileName,
 124					    channel->lineNum);
 125#endif
 126			} else {
 127				len += sprintf(buf + len, "Avail ");
 128			}
 129
 130			if (channel->lastDevType != DMA_DEVICE_NONE) {
 131				len +=
 132				    sprintf(buf + len, "Last use: %s ",
 133					    DMA_gDeviceAttribute[channel->
 134								 lastDevType].
 135					    name);
 136			}
 137
 138			len += sprintf(buf + len, "\n");
 139		}
 140	}
 141	up(&gDMA.lock);
 142	*eof = 1;
 143
 144	return len;
 145}
 146
 147/****************************************************************************/
 148/**
 149*   Displays information for /proc/dma/devices
 150*/
 151/****************************************************************************/
 152
 153static int dma_proc_read_devices(char *buf, char **start, off_t offset,
 154				 int count, int *eof, void *data)
 155{
 156	int limit = count - 200;
 157	int len = 0;
 158	int devIdx;
 159
 160	if (down_interruptible(&gDMA.lock) < 0) {
 161		return -ERESTARTSYS;
 162	}
 163
 164	for (devIdx = 0; devIdx < DMA_NUM_DEVICE_ENTRIES; devIdx++) {
 165		DMA_DeviceAttribute_t *devAttr = &DMA_gDeviceAttribute[devIdx];
 166
 167		if (devAttr->name == NULL) {
 168			continue;
 169		}
 170
 171		if (len >= limit) {
 172			break;
 173		}
 174
 175		len += sprintf(buf + len, "%-12s ", devAttr->name);
 176
 177		if ((devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED) != 0) {
 178			len +=
 179			    sprintf(buf + len, "Dedicated %d:%d ",
 180				    devAttr->dedicatedController,
 181				    devAttr->dedicatedChannel);
 182		} else {
 183			len += sprintf(buf + len, "Shared DMA:");
 184			if ((devAttr->flags & DMA_DEVICE_FLAG_ON_DMA0) != 0) {
 185				len += sprintf(buf + len, "0");
 186			}
 187			if ((devAttr->flags & DMA_DEVICE_FLAG_ON_DMA1) != 0) {
 188				len += sprintf(buf + len, "1");
 189			}
 190			len += sprintf(buf + len, " ");
 191		}
 192		if ((devAttr->flags & DMA_DEVICE_FLAG_NO_ISR) != 0) {
 193			len += sprintf(buf + len, "NoISR ");
 194		}
 195		if ((devAttr->flags & DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO) != 0) {
 196			len += sprintf(buf + len, "Allow-128 ");
 197		}
 198
 199		len +=
 200		    sprintf(buf + len,
 201			    "Xfer #: %Lu Ticks: %Lu Bytes: %Lu DescLen: %u\n",
 202			    devAttr->numTransfers, devAttr->transferTicks,
 203			    devAttr->transferBytes,
 204			    devAttr->ring.bytesAllocated);
 205
 206	}
 207
 208	up(&gDMA.lock);
 209	*eof = 1;
 210
 211	return len;
 212}
 213
 214/****************************************************************************/
 215/**
 216*   Determines if a DMA_Device_t is "valid".
 217*
 218*   @return
 219*       TRUE        - dma device is valid
 220*       FALSE       - dma device isn't valid
 221*/
 222/****************************************************************************/
 223
 224static inline int IsDeviceValid(DMA_Device_t device)
 225{
 226	return (device >= 0) && (device < DMA_NUM_DEVICE_ENTRIES);
 227}
 228
 229/****************************************************************************/
 230/**
 231*   Translates a DMA handle into a pointer to a channel.
 232*
 233*   @return
 234*       non-NULL    - pointer to DMA_Channel_t
 235*       NULL        - DMA Handle was invalid
 236*/
 237/****************************************************************************/
 238
 239static inline DMA_Channel_t *HandleToChannel(DMA_Handle_t handle)
 240{
 241	int controllerIdx;
 242	int channelIdx;
 243
 244	controllerIdx = CONTROLLER_FROM_HANDLE(handle);
 245	channelIdx = CHANNEL_FROM_HANDLE(handle);
 246
 247	if ((controllerIdx > DMA_NUM_CONTROLLERS)
 248	    || (channelIdx > DMA_NUM_CHANNELS)) {
 249		return NULL;
 250	}
 251	return &gDMA.controller[controllerIdx].channel[channelIdx];
 252}
 253
 254/****************************************************************************/
 255/**
 256*   Interrupt handler which is called to process DMA interrupts.
 257*/
 258/****************************************************************************/
 259
 260static irqreturn_t dma_interrupt_handler(int irq, void *dev_id)
 261{
 262	DMA_Channel_t *channel;
 263	DMA_DeviceAttribute_t *devAttr;
 264	int irqStatus;
 265
 266	channel = (DMA_Channel_t *) dev_id;
 267
 268	/* Figure out why we were called, and knock down the interrupt */
 269
 270	irqStatus = dmacHw_getInterruptStatus(channel->dmacHwHandle);
 271	dmacHw_clearInterrupt(channel->dmacHwHandle);
 272
 273	if ((channel->devType < 0)
 274	    || (channel->devType > DMA_NUM_DEVICE_ENTRIES)) {
 275		printk(KERN_ERR "dma_interrupt_handler: Invalid devType: %d\n",
 276		       channel->devType);
 277		return IRQ_NONE;
 278	}
 279	devAttr = &DMA_gDeviceAttribute[channel->devType];
 280
 281	/* Update stats */
 282
 283	if ((irqStatus & dmacHw_INTERRUPT_STATUS_TRANS) != 0) {
 284		devAttr->transferTicks +=
 285		    (timer_get_tick_count() - devAttr->transferStartTime);
 286	}
 287
 288	if ((irqStatus & dmacHw_INTERRUPT_STATUS_ERROR) != 0) {
 289		printk(KERN_ERR
 290		       "dma_interrupt_handler: devType :%d DMA error (%s)\n",
 291		       channel->devType, devAttr->name);
 292	} else {
 293		devAttr->numTransfers++;
 294		devAttr->transferBytes += devAttr->numBytes;
 295	}
 296
 297	/* Call any installed handler */
 298
 299	if (devAttr->devHandler != NULL) {
 300		devAttr->devHandler(channel->devType, irqStatus,
 301				    devAttr->userData);
 302	}
 303
 304	return IRQ_HANDLED;
 305}
 306
 307/****************************************************************************/
 308/**
 309*   Allocates memory to hold a descriptor ring. The descriptor ring then
 310*   needs to be populated by making one or more calls to
 311*   dna_add_descriptors.
 312*
 313*   The returned descriptor ring will be automatically initialized.
 314*
 315*   @return
 316*       0           Descriptor ring was allocated successfully
 317*       -EINVAL     Invalid parameters passed in
 318*       -ENOMEM     Unable to allocate memory for the desired number of descriptors.
 319*/
 320/****************************************************************************/
 321
 322int dma_alloc_descriptor_ring(DMA_DescriptorRing_t *ring,	/* Descriptor ring to populate */
 323			      int numDescriptors	/* Number of descriptors that need to be allocated. */
 324    ) {
 325	size_t bytesToAlloc = dmacHw_descriptorLen(numDescriptors);
 326
 327	if ((ring == NULL) || (numDescriptors <= 0)) {
 328		return -EINVAL;
 329	}
 330
 331	ring->physAddr = 0;
 332	ring->descriptorsAllocated = 0;
 333	ring->bytesAllocated = 0;
 334
 335	ring->virtAddr = dma_alloc_writecombine(NULL,
 336						     bytesToAlloc,
 337						     &ring->physAddr,
 338						     GFP_KERNEL);
 339	if (ring->virtAddr == NULL) {
 340		return -ENOMEM;
 341	}
 342
 343	ring->bytesAllocated = bytesToAlloc;
 344	ring->descriptorsAllocated = numDescriptors;
 345
 346	return dma_init_descriptor_ring(ring, numDescriptors);
 347}
 348
 349EXPORT_SYMBOL(dma_alloc_descriptor_ring);
 350
 351/****************************************************************************/
 352/**
 353*   Releases the memory which was previously allocated for a descriptor ring.
 354*/
 355/****************************************************************************/
 356
 357void dma_free_descriptor_ring(DMA_DescriptorRing_t *ring	/* Descriptor to release */
 358    ) {
 359	if (ring->virtAddr != NULL) {
 360		dma_free_writecombine(NULL,
 361				      ring->bytesAllocated,
 362				      ring->virtAddr, ring->physAddr);
 363	}
 364
 365	ring->bytesAllocated = 0;
 366	ring->descriptorsAllocated = 0;
 367	ring->virtAddr = NULL;
 368	ring->physAddr = 0;
 369}
 370
 371EXPORT_SYMBOL(dma_free_descriptor_ring);
 372
 373/****************************************************************************/
 374/**
 375*   Initializes a descriptor ring, so that descriptors can be added to it.
 376*   Once a descriptor ring has been allocated, it may be reinitialized for
 377*   use with additional/different regions of memory.
 378*
 379*   Note that if 7 descriptors are allocated, it's perfectly acceptable to
 380*   initialize the ring with a smaller number of descriptors. The amount
 381*   of memory allocated for the descriptor ring will not be reduced, and
 382*   the descriptor ring may be reinitialized later
 383*
 384*   @return
 385*       0           Descriptor ring was initialized successfully
 386*       -ENOMEM     The descriptor which was passed in has insufficient space
 387*                   to hold the desired number of descriptors.
 388*/
 389/****************************************************************************/
 390
 391int dma_init_descriptor_ring(DMA_DescriptorRing_t *ring,	/* Descriptor ring to initialize */
 392			     int numDescriptors	/* Number of descriptors to initialize. */
 393    ) {
 394	if (ring->virtAddr == NULL) {
 395		return -EINVAL;
 396	}
 397	if (dmacHw_initDescriptor(ring->virtAddr,
 398				  ring->physAddr,
 399				  ring->bytesAllocated, numDescriptors) < 0) {
 400		printk(KERN_ERR
 401		       "dma_init_descriptor_ring: dmacHw_initDescriptor failed\n");
 402		return -ENOMEM;
 403	}
 404
 405	return 0;
 406}
 407
 408EXPORT_SYMBOL(dma_init_descriptor_ring);
 409
 410/****************************************************************************/
 411/**
 412*   Determines the number of descriptors which would be required for a
 413*   transfer of the indicated memory region.
 414*
 415*   This function also needs to know which DMA device this transfer will
 416*   be destined for, so that the appropriate DMA configuration can be retrieved.
 417*   DMA parameters such as transfer width, and whether this is a memory-to-memory
 418*   or memory-to-peripheral, etc can all affect the actual number of descriptors
 419*   required.
 420*
 421*   @return
 422*       > 0     Returns the number of descriptors required for the indicated transfer
 423*       -ENODEV - Device handed in is invalid.
 424*       -EINVAL Invalid parameters
 425*       -ENOMEM Memory exhausted
 426*/
 427/****************************************************************************/
 428
 429int dma_calculate_descriptor_count(DMA_Device_t device,	/* DMA Device that this will be associated with */
 430				   dma_addr_t srcData,	/* Place to get data to write to device */
 431				   dma_addr_t dstData,	/* Pointer to device data address */
 432				   size_t numBytes	/* Number of bytes to transfer to the device */
 433    ) {
 434	int numDescriptors;
 435	DMA_DeviceAttribute_t *devAttr;
 436
 437	if (!IsDeviceValid(device)) {
 438		return -ENODEV;
 439	}
 440	devAttr = &DMA_gDeviceAttribute[device];
 441
 442	numDescriptors = dmacHw_calculateDescriptorCount(&devAttr->config,
 443							      (void *)srcData,
 444							      (void *)dstData,
 445							      numBytes);
 446	if (numDescriptors < 0) {
 447		printk(KERN_ERR
 448		       "dma_calculate_descriptor_count: dmacHw_calculateDescriptorCount failed\n");
 449		return -EINVAL;
 450	}
 451
 452	return numDescriptors;
 453}
 454
 455EXPORT_SYMBOL(dma_calculate_descriptor_count);
 456
 457/****************************************************************************/
 458/**
 459*   Adds a region of memory to the descriptor ring. Note that it may take
 460*   multiple descriptors for each region of memory. It is the callers
 461*   responsibility to allocate a sufficiently large descriptor ring.
 462*
 463*   @return
 464*       0       Descriptors were added successfully
 465*       -ENODEV Device handed in is invalid.
 466*       -EINVAL Invalid parameters
 467*       -ENOMEM Memory exhausted
 468*/
 469/****************************************************************************/
 470
 471int dma_add_descriptors(DMA_DescriptorRing_t *ring,	/* Descriptor ring to add descriptors to */
 472			DMA_Device_t device,	/* DMA Device that descriptors are for */
 473			dma_addr_t srcData,	/* Place to get data (memory or device) */
 474			dma_addr_t dstData,	/* Place to put data (memory or device) */
 475			size_t numBytes	/* Number of bytes to transfer to the device */
 476    ) {
 477	int rc;
 478	DMA_DeviceAttribute_t *devAttr;
 479
 480	if (!IsDeviceValid(device)) {
 481		return -ENODEV;
 482	}
 483	devAttr = &DMA_gDeviceAttribute[device];
 484
 485	rc = dmacHw_setDataDescriptor(&devAttr->config,
 486				      ring->virtAddr,
 487				      (void *)srcData,
 488				      (void *)dstData, numBytes);
 489	if (rc < 0) {
 490		printk(KERN_ERR
 491		       "dma_add_descriptors: dmacHw_setDataDescriptor failed with code: %d\n",
 492		       rc);
 493		return -ENOMEM;
 494	}
 495
 496	return 0;
 497}
 498
 499EXPORT_SYMBOL(dma_add_descriptors);
 500
 501/****************************************************************************/
 502/**
 503*   Sets the descriptor ring associated with a device.
 504*
 505*   Once set, the descriptor ring will be associated with the device, even
 506*   across channel request/free calls. Passing in a NULL descriptor ring
 507*   will release any descriptor ring currently associated with the device.
 508*
 509*   Note: If you call dma_transfer, or one of the other dma_alloc_ functions
 510*         the descriptor ring may be released and reallocated.
 511*
 512*   Note: This function will release the descriptor memory for any current
 513*         descriptor ring associated with this device.
 514*
 515*   @return
 516*       0       Descriptors were added successfully
 517*       -ENODEV Device handed in is invalid.
 518*/
 519/****************************************************************************/
 520
 521int dma_set_device_descriptor_ring(DMA_Device_t device,	/* Device to update the descriptor ring for. */
 522				   DMA_DescriptorRing_t *ring	/* Descriptor ring to add descriptors to */
 523    ) {
 524	DMA_DeviceAttribute_t *devAttr;
 525
 526	if (!IsDeviceValid(device)) {
 527		return -ENODEV;
 528	}
 529	devAttr = &DMA_gDeviceAttribute[device];
 530
 531	/* Free the previously allocated descriptor ring */
 532
 533	dma_free_descriptor_ring(&devAttr->ring);
 534
 535	if (ring != NULL) {
 536		/* Copy in the new one */
 537
 538		devAttr->ring = *ring;
 539	}
 540
 541	/* Set things up so that if dma_transfer is called then this descriptor */
 542	/* ring will get freed. */
 543
 544	devAttr->prevSrcData = 0;
 545	devAttr->prevDstData = 0;
 546	devAttr->prevNumBytes = 0;
 547
 548	return 0;
 549}
 550
 551EXPORT_SYMBOL(dma_set_device_descriptor_ring);
 552
 553/****************************************************************************/
 554/**
 555*   Retrieves the descriptor ring associated with a device.
 556*
 557*   @return
 558*       0       Descriptors were added successfully
 559*       -ENODEV Device handed in is invalid.
 560*/
 561/****************************************************************************/
 562
 563int dma_get_device_descriptor_ring(DMA_Device_t device,	/* Device to retrieve the descriptor ring for. */
 564				   DMA_DescriptorRing_t *ring	/* Place to store retrieved ring */
 565    ) {
 566	DMA_DeviceAttribute_t *devAttr;
 567
 568	memset(ring, 0, sizeof(*ring));
 569
 570	if (!IsDeviceValid(device)) {
 571		return -ENODEV;
 572	}
 573	devAttr = &DMA_gDeviceAttribute[device];
 574
 575	*ring = devAttr->ring;
 576
 577	return 0;
 578}
 579
 580EXPORT_SYMBOL(dma_get_device_descriptor_ring);
 581
 582/****************************************************************************/
 583/**
 584*   Configures a DMA channel.
 585*
 586*   @return
 587*       >= 0    - Initialization was successful.
 588*
 589*       -EBUSY  - Device is currently being used.
 590*       -ENODEV - Device handed in is invalid.
 591*/
 592/****************************************************************************/
 593
 594static int ConfigChannel(DMA_Handle_t handle)
 595{
 596	DMA_Channel_t *channel;
 597	DMA_DeviceAttribute_t *devAttr;
 598	int controllerIdx;
 599
 600	channel = HandleToChannel(handle);
 601	if (channel == NULL) {
 602		return -ENODEV;
 603	}
 604	devAttr = &DMA_gDeviceAttribute[channel->devType];
 605	controllerIdx = CONTROLLER_FROM_HANDLE(handle);
 606
 607	if ((devAttr->flags & DMA_DEVICE_FLAG_PORT_PER_DMAC) != 0) {
 608		if (devAttr->config.transferType ==
 609		    dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL) {
 610			devAttr->config.dstPeripheralPort =
 611			    devAttr->dmacPort[controllerIdx];
 612		} else if (devAttr->config.transferType ==
 613			   dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM) {
 614			devAttr->config.srcPeripheralPort =
 615			    devAttr->dmacPort[controllerIdx];
 616		}
 617	}
 618
 619	if (dmacHw_configChannel(channel->dmacHwHandle, &devAttr->config) != 0) {
 620		printk(KERN_ERR "ConfigChannel: dmacHw_configChannel failed\n");
 621		return -EIO;
 622	}
 623
 624	return 0;
 625}
 626
 627/****************************************************************************/
 628/**
 629*   Initializes all of the data structures associated with the DMA.
 630*   @return
 631*       >= 0    - Initialization was successful.
 632*
 633*       -EBUSY  - Device is currently being used.
 634*       -ENODEV - Device handed in is invalid.
 635*/
 636/****************************************************************************/
 637
 638int dma_init(void)
 639{
 640	int rc = 0;
 641	int controllerIdx;
 642	int channelIdx;
 643	DMA_Device_t devIdx;
 644	DMA_Channel_t *channel;
 645	DMA_Handle_t dedicatedHandle;
 646
 647	memset(&gDMA, 0, sizeof(gDMA));
 648
 649	sema_init(&gDMA.lock, 0);
 650	init_waitqueue_head(&gDMA.freeChannelQ);
 651
 652	/* Initialize the Hardware */
 653
 654	dmacHw_initDma();
 655
 656	/* Start off by marking all of the DMA channels as shared. */
 657
 658	for (controllerIdx = 0; controllerIdx < DMA_NUM_CONTROLLERS;
 659	     controllerIdx++) {
 660		for (channelIdx = 0; channelIdx < DMA_NUM_CHANNELS;
 661		     channelIdx++) {
 662			channel =
 663			    &gDMA.controller[controllerIdx].channel[channelIdx];
 664
 665			channel->flags = 0;
 666			channel->devType = DMA_DEVICE_NONE;
 667			channel->lastDevType = DMA_DEVICE_NONE;
 668
 669#if (DMA_DEBUG_TRACK_RESERVATION)
 670			channel->fileName = "";
 671			channel->lineNum = 0;
 672#endif
 673
 674			channel->dmacHwHandle =
 675			    dmacHw_getChannelHandle(dmacHw_MAKE_CHANNEL_ID
 676						    (controllerIdx,
 677						     channelIdx));
 678			dmacHw_initChannel(channel->dmacHwHandle);
 679		}
 680	}
 681
 682	/* Record any special attributes that channels may have */
 683
 684	gDMA.controller[0].channel[0].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO;
 685	gDMA.controller[0].channel[1].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO;
 686	gDMA.controller[1].channel[0].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO;
 687	gDMA.controller[1].channel[1].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO;
 688
 689	/* Now walk through and record the dedicated channels. */
 690
 691	for (devIdx = 0; devIdx < DMA_NUM_DEVICE_ENTRIES; devIdx++) {
 692		DMA_DeviceAttribute_t *devAttr = &DMA_gDeviceAttribute[devIdx];
 693
 694		if (((devAttr->flags & DMA_DEVICE_FLAG_NO_ISR) != 0)
 695		    && ((devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED) == 0)) {
 696			printk(KERN_ERR
 697			       "DMA Device: %s Can only request NO_ISR for dedicated devices\n",
 698			       devAttr->name);
 699			rc = -EINVAL;
 700			goto out;
 701		}
 702
 703		if ((devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED) != 0) {
 704			/* This is a dedicated device. Mark the channel as being reserved. */
 705
 706			if (devAttr->dedicatedController >= DMA_NUM_CONTROLLERS) {
 707				printk(KERN_ERR
 708				       "DMA Device: %s DMA Controller %d is out of range\n",
 709				       devAttr->name,
 710				       devAttr->dedicatedController);
 711				rc = -EINVAL;
 712				goto out;
 713			}
 714
 715			if (devAttr->dedicatedChannel >= DMA_NUM_CHANNELS) {
 716				printk(KERN_ERR
 717				       "DMA Device: %s DMA Channel %d is out of range\n",
 718				       devAttr->name,
 719				       devAttr->dedicatedChannel);
 720				rc = -EINVAL;
 721				goto out;
 722			}
 723
 724			dedicatedHandle =
 725			    MAKE_HANDLE(devAttr->dedicatedController,
 726					devAttr->dedicatedChannel);
 727			channel = HandleToChannel(dedicatedHandle);
 728
 729			if ((channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED) !=
 730			    0) {
 731				printk
 732				    ("DMA Device: %s attempting to use same DMA Controller:Channel (%d:%d) as %s\n",
 733				     devAttr->name,
 734				     devAttr->dedicatedController,
 735				     devAttr->dedicatedChannel,
 736				     DMA_gDeviceAttribute[channel->devType].
 737				     name);
 738				rc = -EBUSY;
 739				goto out;
 740			}
 741
 742			channel->flags |= DMA_CHANNEL_FLAG_IS_DEDICATED;
 743			channel->devType = devIdx;
 744
 745			if (devAttr->flags & DMA_DEVICE_FLAG_NO_ISR) {
 746				channel->flags |= DMA_CHANNEL_FLAG_NO_ISR;
 747			}
 748
 749			/* For dedicated channels, we can go ahead and configure the DMA channel now */
 750			/* as well. */
 751
 752			ConfigChannel(dedicatedHandle);
 753		}
 754	}
 755
 756	/* Go through and register the interrupt handlers */
 757
 758	for (controllerIdx = 0; controllerIdx < DMA_NUM_CONTROLLERS;
 759	     controllerIdx++) {
 760		for (channelIdx = 0; channelIdx < DMA_NUM_CHANNELS;
 761		     channelIdx++) {
 762			channel =
 763			    &gDMA.controller[controllerIdx].channel[channelIdx];
 764
 765			if ((channel->flags & DMA_CHANNEL_FLAG_NO_ISR) == 0) {
 766				snprintf(channel->name, sizeof(channel->name),
 767					 "dma %d:%d %s", controllerIdx,
 768					 channelIdx,
 769					 channel->devType ==
 770					 DMA_DEVICE_NONE ? "" :
 771					 DMA_gDeviceAttribute[channel->devType].
 772					 name);
 773
 774				rc =
 775				     request_irq(IRQ_DMA0C0 +
 776						 (controllerIdx *
 777						  DMA_NUM_CHANNELS) +
 778						 channelIdx,
 779						 dma_interrupt_handler,
 780						 IRQF_DISABLED, channel->name,
 781						 channel);
 782				if (rc != 0) {
 783					printk(KERN_ERR
 784					       "request_irq for IRQ_DMA%dC%d failed\n",
 785					       controllerIdx, channelIdx);
 786				}
 787			}
 788		}
 789	}
 790
 791	/* Create /proc/dma/channels and /proc/dma/devices */
 792
 793	gDmaDir = proc_mkdir("dma", NULL);
 794
 795	if (gDmaDir == NULL) {
 796		printk(KERN_ERR "Unable to create /proc/dma\n");
 797	} else {
 798		create_proc_read_entry("channels", 0, gDmaDir,
 799				       dma_proc_read_channels, NULL);
 800		create_proc_read_entry("devices", 0, gDmaDir,
 801				       dma_proc_read_devices, NULL);
 802	}
 803
 804out:
 805
 806	up(&gDMA.lock);
 807
 808	return rc;
 809}
 810
 811/****************************************************************************/
 812/**
 813*   Reserves a channel for use with @a dev. If the device is setup to use
 814*   a shared channel, then this function will block until a free channel
 815*   becomes available.
 816*
 817*   @return
 818*       >= 0    - A valid DMA Handle.
 819*       -EBUSY  - Device is currently being used.
 820*       -ENODEV - Device handed in is invalid.
 821*/
 822/****************************************************************************/
 823
 824#if (DMA_DEBUG_TRACK_RESERVATION)
 825DMA_Handle_t dma_request_channel_dbg
 826    (DMA_Device_t dev, const char *fileName, int lineNum)
 827#else
 828DMA_Handle_t dma_request_channel(DMA_Device_t dev)
 829#endif
 830{
 831	DMA_Handle_t handle;
 832	DMA_DeviceAttribute_t *devAttr;
 833	DMA_Channel_t *channel;
 834	int controllerIdx;
 835	int controllerIdx2;
 836	int channelIdx;
 837
 838	if (down_interruptible(&gDMA.lock) < 0) {
 839		return -ERESTARTSYS;
 840	}
 841
 842	if ((dev < 0) || (dev >= DMA_NUM_DEVICE_ENTRIES)) {
 843		handle = -ENODEV;
 844		goto out;
 845	}
 846	devAttr = &DMA_gDeviceAttribute[dev];
 847
 848#if (DMA_DEBUG_TRACK_RESERVATION)
 849	{
 850		char *s;
 851
 852		s = strrchr(fileName, '/');
 853		if (s != NULL) {
 854			fileName = s + 1;
 855		}
 856	}
 857#endif
 858	if ((devAttr->flags & DMA_DEVICE_FLAG_IN_USE) != 0) {
 859		/* This device has already been requested and not been freed */
 860
 861		printk(KERN_ERR "%s: device %s is already requested\n",
 862		       __func__, devAttr->name);
 863		handle = -EBUSY;
 864		goto out;
 865	}
 866
 867	if ((devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED) != 0) {
 868		/* This device has a dedicated channel. */
 869
 870		channel =
 871		    &gDMA.controller[devAttr->dedicatedController].
 872		    channel[devAttr->dedicatedChannel];
 873		if ((channel->flags & DMA_CHANNEL_FLAG_IN_USE) != 0) {
 874			handle = -EBUSY;
 875			goto out;
 876		}
 877
 878		channel->flags |= DMA_CHANNEL_FLAG_IN_USE;
 879		devAttr->flags |= DMA_DEVICE_FLAG_IN_USE;
 880
 881#if (DMA_DEBUG_TRACK_RESERVATION)
 882		channel->fileName = fileName;
 883		channel->lineNum = lineNum;
 884#endif
 885		handle =
 886		    MAKE_HANDLE(devAttr->dedicatedController,
 887				devAttr->dedicatedChannel);
 888		goto out;
 889	}
 890
 891	/* This device needs to use one of the shared channels. */
 892
 893	handle = DMA_INVALID_HANDLE;
 894	while (handle == DMA_INVALID_HANDLE) {
 895		/* Scan through the shared channels and see if one is available */
 896
 897		for (controllerIdx2 = 0; controllerIdx2 < DMA_NUM_CONTROLLERS;
 898		     controllerIdx2++) {
 899			/* Check to see if we should try on controller 1 first. */
 900
 901			controllerIdx = controllerIdx2;
 902			if ((devAttr->
 903			     flags & DMA_DEVICE_FLAG_ALLOC_DMA1_FIRST) != 0) {
 904				controllerIdx = 1 - controllerIdx;
 905			}
 906
 907			/* See if the device is available on the controller being tested */
 908
 909			if ((devAttr->
 910			     flags & (DMA_DEVICE_FLAG_ON_DMA0 << controllerIdx))
 911			    != 0) {
 912				for (channelIdx = 0;
 913				     channelIdx < DMA_NUM_CHANNELS;
 914				     channelIdx++) {
 915					channel =
 916					    &gDMA.controller[controllerIdx].
 917					    channel[channelIdx];
 918
 919					if (((channel->
 920					      flags &
 921					      DMA_CHANNEL_FLAG_IS_DEDICATED) ==
 922					     0)
 923					    &&
 924					    ((channel->
 925					      flags & DMA_CHANNEL_FLAG_IN_USE)
 926					     == 0)) {
 927						if (((channel->
 928						      flags &
 929						      DMA_CHANNEL_FLAG_LARGE_FIFO)
 930						     != 0)
 931						    &&
 932						    ((devAttr->
 933						      flags &
 934						      DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO)
 935						     == 0)) {
 936							/* This channel is a large fifo - don't tie it up */
 937							/* with devices that we don't want using it. */
 938
 939							continue;
 940						}
 941
 942						channel->flags |=
 943						    DMA_CHANNEL_FLAG_IN_USE;
 944						channel->devType = dev;
 945						devAttr->flags |=
 946						    DMA_DEVICE_FLAG_IN_USE;
 947
 948#if (DMA_DEBUG_TRACK_RESERVATION)
 949						channel->fileName = fileName;
 950						channel->lineNum = lineNum;
 951#endif
 952						handle =
 953						    MAKE_HANDLE(controllerIdx,
 954								channelIdx);
 955
 956						/* Now that we've reserved the channel - we can go ahead and configure it */
 957
 958						if (ConfigChannel(handle) != 0) {
 959							handle = -EIO;
 960							printk(KERN_ERR
 961							       "dma_request_channel: ConfigChannel failed\n");
 962						}
 963						goto out;
 964					}
 965				}
 966			}
 967		}
 968
 969		/* No channels are currently available. Let's wait for one to free up. */
 970
 971		{
 972			DEFINE_WAIT(wait);
 973
 974			prepare_to_wait(&gDMA.freeChannelQ, &wait,
 975					TASK_INTERRUPTIBLE);
 976			up(&gDMA.lock);
 977			schedule();
 978			finish_wait(&gDMA.freeChannelQ, &wait);
 979
 980			if (signal_pending(current)) {
 981				/* We don't currently hold gDMA.lock, so we return directly */
 982
 983				return -ERESTARTSYS;
 984			}
 985		}
 986
 987		if (down_interruptible(&gDMA.lock)) {
 988			return -ERESTARTSYS;
 989		}
 990	}
 991
 992out:
 993	up(&gDMA.lock);
 994
 995	return handle;
 996}
 997
 998/* Create both _dbg and non _dbg functions for modules. */
 999
1000#if (DMA_DEBUG_TRACK_RESERVATION)
1001#undef dma_request_channel
1002DMA_Handle_t dma_request_channel(DMA_Device_t dev)
1003{
1004	return dma_request_channel_dbg(dev, __FILE__, __LINE__);
1005}
1006
1007EXPORT_SYMBOL(dma_request_channel_dbg);
1008#endif
1009EXPORT_SYMBOL(dma_request_channel);
1010
1011/****************************************************************************/
1012/**
1013*   Frees a previously allocated DMA Handle.
1014*/
1015/****************************************************************************/
1016
1017int dma_free_channel(DMA_Handle_t handle	/* DMA handle. */
1018    ) {
1019	int rc = 0;
1020	DMA_Channel_t *channel;
1021	DMA_DeviceAttribute_t *devAttr;
1022
1023	if (down_interruptible(&gDMA.lock) < 0) {
1024		return -ERESTARTSYS;
1025	}
1026
1027	channel = HandleToChannel(handle);
1028	if (channel == NULL) {
1029		rc = -EINVAL;
1030		goto out;
1031	}
1032
1033	devAttr = &DMA_gDeviceAttribute[channel->devType];
1034
1035	if ((channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED) == 0) {
1036		channel->lastDevType = channel->devType;
1037		channel->devType = DMA_DEVICE_NONE;
1038	}
1039	channel->flags &= ~DMA_CHANNEL_FLAG_IN_USE;
1040	devAttr->flags &= ~DMA_DEVICE_FLAG_IN_USE;
1041
1042out:
1043	up(&gDMA.lock);
1044
1045	wake_up_interruptible(&gDMA.freeChannelQ);
1046
1047	return rc;
1048}
1049
1050EXPORT_SYMBOL(dma_free_channel);
1051
1052/****************************************************************************/
1053/**
1054*   Determines if a given device has been configured as using a shared
1055*   channel.
1056*
1057*   @return
1058*       0           Device uses a dedicated channel
1059*       > zero      Device uses a shared channel
1060*       < zero      Error code
1061*/
1062/****************************************************************************/
1063
1064int dma_device_is_channel_shared(DMA_Device_t device	/* Device to check. */
1065    ) {
1066	DMA_DeviceAttribute_t *devAttr;
1067
1068	if (!IsDeviceValid(device)) {
1069		return -ENODEV;
1070	}
1071	devAttr = &DMA_gDeviceAttribute[device];
1072
1073	return ((devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED) == 0);
1074}
1075
1076EXPORT_SYMBOL(dma_device_is_channel_shared);
1077
1078/****************************************************************************/
1079/**
1080*   Allocates buffers for the descriptors. This is normally done automatically
1081*   but needs to be done explicitly when initiating a dma from interrupt
1082*   context.
1083*
1084*   @return
1085*       0       Descriptors were allocated successfully
1086*       -EINVAL Invalid device type for this kind of transfer
1087*               (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
1088*       -ENOMEM Memory exhausted
1089*/
1090/****************************************************************************/
1091
1092int dma_alloc_descriptors(DMA_Handle_t handle,	/* DMA Handle */
1093			  dmacHw_TRANSFER_TYPE_e transferType,	/* Type of transfer being performed */
1094			  dma_addr_t srcData,	/* Place to get data to write to device */
1095			  dma_addr_t dstData,	/* Pointer to device data address */
1096			  size_t numBytes	/* Number of bytes to transfer to the device */
1097    ) {
1098	DMA_Channel_t *channel;
1099	DMA_DeviceAttribute_t *devAttr;
1100	int numDescriptors;
1101	size_t ringBytesRequired;
1102	int rc = 0;
1103
1104	channel = HandleToChannel(handle);
1105	if (channel == NULL) {
1106		return -ENODEV;
1107	}
1108
1109	devAttr = &DMA_gDeviceAttribute[channel->devType];
1110
1111	if (devAttr->config.transferType != transferType) {
1112		return -EINVAL;
1113	}
1114
1115	/* Figure out how many descriptors we need. */
1116
1117	/* printk("srcData: 0x%08x dstData: 0x%08x, numBytes: %d\n", */
1118	/*        srcData, dstData, numBytes); */
1119
1120	numDescriptors = dmacHw_calculateDescriptorCount(&devAttr->config,
1121							      (void *)srcData,
1122							      (void *)dstData,
1123							      numBytes);
1124	if (numDescriptors < 0) {
1125		printk(KERN_ERR "%s: dmacHw_calculateDescriptorCount failed\n",
1126		       __func__);
1127		return -EINVAL;
1128	}
1129
1130	/* Check to see if we can reuse the existing descriptor ring, or if we need to allocate */
1131	/* a new one. */
1132
1133	ringBytesRequired = dmacHw_descriptorLen(numDescriptors);
1134
1135	/* printk("ringBytesRequired: %d\n", ringBytesRequired); */
1136
1137	if (ringBytesRequired > devAttr->ring.bytesAllocated) {
1138		/* Make sure that this code path is never taken from interrupt context. */
1139		/* It's OK for an interrupt to initiate a DMA transfer, but the descriptor */
1140		/* allocation needs to have already been done. */
1141
1142		might_sleep();
1143
1144		/* Free the old descriptor ring and allocate a new one. */
1145
1146		dma_free_descriptor_ring(&devAttr->ring);
1147
1148		/* And allocate a new one. */
1149
1150		rc =
1151		     dma_alloc_descriptor_ring(&devAttr->ring,
1152					       numDescriptors);
1153		if (rc < 0) {
1154			printk(KERN_ERR
1155			       "%s: dma_alloc_descriptor_ring(%d) failed\n",
1156			       __func__, numDescriptors);
1157			return rc;
1158		}
1159		/* Setup the descriptor for this transfer */
1160
1161		if (dmacHw_initDescriptor(devAttr->ring.virtAddr,
1162					  devAttr->ring.physAddr,
1163					  devAttr->ring.bytesAllocated,
1164					  numDescriptors) < 0) {
1165			printk(KERN_ERR "%s: dmacHw_initDescriptor failed\n",
1166			       __func__);
1167			return -EINVAL;
1168		}
1169	} else {
1170		/* We've already got enough ring buffer allocated. All we need to do is reset */
1171		/* any control information, just in case the previous DMA was stopped. */
1172
1173		dmacHw_resetDescriptorControl(devAttr->ring.virtAddr);
1174	}
1175
1176	/* dma_alloc/free both set the prevSrc/DstData to 0. If they happen to be the same */
1177	/* as last time, then we don't need to call setDataDescriptor again. */
1178
1179	if (dmacHw_setDataDescriptor(&devAttr->config,
1180				     devAttr->ring.virtAddr,
1181				     (void *)srcData,
1182				     (void *)dstData, numBytes) < 0) {
1183		printk(KERN_ERR "%s: dmacHw_setDataDescriptor failed\n",
1184		       __func__);
1185		return -EINVAL;
1186	}
1187
1188	/* Remember the critical information for this transfer so that we can eliminate */
1189	/* another call to dma_alloc_descriptors if the caller reuses the same buffers */
1190
1191	devAttr->prevSrcData = srcData;
1192	devAttr->prevDstData = dstData;
1193	devAttr->prevNumBytes = numBytes;
1194
1195	return 0;
1196}
1197
1198EXPORT_SYMBOL(dma_alloc_descriptors);
1199
1200/****************************************************************************/
1201/**
1202*   Allocates and sets up descriptors for a double buffered circular buffer.
1203*
1204*   This is primarily intended to be used for things like the ingress samples
1205*   from a microphone.
1206*
1207*   @return
1208*       > 0     Number of descriptors actually allocated.
1209*       -EINVAL Invalid device type for this kind of transfer
1210*               (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
1211*       -ENOMEM Memory exhausted
1212*/
1213/****************************************************************************/
1214
1215int dma_alloc_double_dst_descriptors(DMA_Handle_t handle,	/* DMA Handle */
1216				     dma_addr_t srcData,	/* Physical address of source data */
1217				     dma_addr_t dstData1,	/* Physical address of first destination buffer */
1218				     dma_addr_t dstData2,	/* Physical address of second destination buffer */
1219				     size_t numBytes	/* Number of bytes in each destination buffer */
1220    ) {
1221	DMA_Channel_t *channel;
1222	DMA_DeviceAttribute_t *devAttr;
1223	int numDst1Descriptors;
1224	int numDst2Descriptors;
1225	int numDescriptors;
1226	size_t ringBytesRequired;
1227	int rc = 0;
1228
1229	channel = HandleToChannel(handle);
1230	if (channel == NULL) {
1231		return -ENODEV;
1232	}
1233
1234	devAttr = &DMA_gDeviceAttribute[channel->devType];
1235
1236	/* Figure out how many descriptors we need. */
1237
1238	/* printk("srcData: 0x%08x dstData: 0x%08x, numBytes: %d\n", */
1239	/*        srcData, dstData, numBytes); */
1240
1241	numDst1Descriptors =
1242	     dmacHw_calculateDescriptorCount(&devAttr->config, (void *)srcData,
1243					     (void *)dstData1, numBytes);
1244	if (numDst1Descriptors < 0) {
1245		return -EINVAL;
1246	}
1247	numDst2Descriptors =
1248	     dmacHw_calculateDescriptorCount(&devAttr->config, (void *)srcData,
1249					     (void *)dstData2, numBytes);
1250	if (numDst2Descriptors < 0) {
1251		return -EINVAL;
1252	}
1253	numDescriptors = numDst1Descriptors + numDst2Descriptors;
1254	/* printk("numDescriptors: %d\n", numDescriptors); */
1255
1256	/* Check to see if we can reuse the existing descriptor ring, or if we need to allocate */
1257	/* a new one. */
1258
1259	ringBytesRequired = dmacHw_descriptorLen(numDescriptors);
1260
1261	/* printk("ringBytesRequired: %d\n", ringBytesRequired); */
1262
1263	if (ringBytesRequired > devAttr->ring.bytesAllocated) {
1264		/* Make sure that this code path is never taken from interrupt context. */
1265		/* It's OK for an interrupt to initiate a DMA transfer, but the descriptor */
1266		/* allocation needs to have already been done. */
1267
1268		might_sleep();
1269
1270		/* Free the old descriptor ring and allocate a new one. */
1271
1272		dma_free_descriptor_ring(&devAttr->ring);
1273
1274		/* And allocate a new one. */
1275
1276		rc =
1277		     dma_alloc_descriptor_ring(&devAttr->ring,
1278					       numDescriptors);
1279		if (rc < 0) {
1280			printk(KERN_ERR
1281			       "%s: dma_alloc_descriptor_ring(%d) failed\n",
1282			       __func__, ringBytesRequired);
1283			return rc;
1284		}
1285	}
1286
1287	/* Setup the descriptor for this transfer. Since this function is used with */
1288	/* CONTINUOUS DMA operations, we need to reinitialize every time, otherwise */
1289	/* setDataDescriptor will keep trying to append onto the end. */
1290
1291	if (dmacHw_initDescriptor(devAttr->ring.virtAddr,
1292				  devAttr->ring.physAddr,
1293				  devAttr->ring.bytesAllocated,
1294				  numDescriptors) < 0) {
1295		printk(KERN_ERR "%s: dmacHw_initDescriptor failed\n", __func__);
1296		return -EINVAL;
1297	}
1298
1299	/* dma_alloc/free both set the prevSrc/DstData to 0. If they happen to be the same */
1300	/* as last time, then we don't need to call setDataDescriptor again. */
1301
1302	if (dmacHw_setDataDescriptor(&devAttr->config,
1303				     devAttr->ring.virtAddr,
1304				     (void *)srcData,
1305				     (void *)dstData1, numBytes) < 0) {
1306		printk(KERN_ERR "%s: dmacHw_setDataDescriptor 1 failed\n",
1307		       __func__);
1308		return -EINVAL;
1309	}
1310	if (dmacHw_setDataDescriptor(&devAttr->config,
1311				     devAttr->ring.virtAddr,
1312				     (void *)srcData,
1313				     (void *)dstData2, numBytes) < 0) {
1314		printk(KERN_ERR "%s: dmacHw_setDataDescriptor 2 failed\n",
1315		       __func__);
1316		return -EINVAL;
1317	}
1318
1319	/* You should use dma_start_transfer rather than dma_transfer_xxx so we don't */
1320	/* try to make the 'prev' variables right. */
1321
1322	devAttr->prevSrcData = 0;
1323	devAttr->prevDstData = 0;
1324	devAttr->prevNumBytes = 0;
1325
1326	return numDescriptors;
1327}
1328
1329EXPORT_SYMBOL(dma_alloc_double_dst_descriptors);
1330
1331/****************************************************************************/
1332/**
1333*   Initiates a transfer when the descriptors have already been setup.
1334*
1335*   This is a special case, and normally, the dma_transfer_xxx functions should
1336*   be used.
1337*
1338*   @return
1339*       0       Transfer was started successfully
1340*       -ENODEV Invalid handle
1341*/
1342/****************************************************************************/
1343
1344int dma_start_transfer(DMA_Handle_t handle)
1345{
1346	DMA_Channel_t *channel;
1347	DMA_DeviceAttribute_t *devAttr;
1348
1349	channel = HandleToChannel(handle);
1350	if (channel == NULL) {
1351		return -ENODEV;
1352	}
1353	devAttr = &DMA_gDeviceAttribute[channel->devType];
1354
1355	dmacHw_initiateTransfer(channel->dmacHwHandle, &devAttr->config,
1356				devAttr->ring.virtAddr);
1357
1358	/* Since we got this far, everything went successfully */
1359
1360	return 0;
1361}
1362
1363EXPORT_SYMBOL(dma_start_transfer);
1364
1365/****************************************************************************/
1366/**
1367*   Stops a previously started DMA transfer.
1368*
1369*   @return
1370*       0       Transfer was stopped successfully
1371*       -ENODEV Invalid handle
1372*/
1373/****************************************************************************/
1374
1375int dma_stop_transfer(DMA_Handle_t handle)
1376{
1377	DMA_Channel_t *channel;
1378
1379	channel = HandleToChannel(handle);
1380	if (channel == NULL) {
1381		return -ENODEV;
1382	}
1383
1384	dmacHw_stopTransfer(channel->dmacHwHandle);
1385
1386	return 0;
1387}
1388
1389EXPORT_SYMBOL(dma_stop_transfer);
1390
1391/****************************************************************************/
1392/**
1393*   Waits for a DMA to complete by polling. This function is only intended
1394*   to be used for testing. Interrupts should be used for most DMA operations.
1395*/
1396/****************************************************************************/
1397
1398int dma_wait_transfer_done(DMA_Handle_t handle)
1399{
1400	DMA_Channel_t *channel;
1401	dmacHw_TRANSFER_STATUS_e status;
1402
1403	channel = HandleToChannel(handle);
1404	if (channel == NULL) {
1405		return -ENODEV;
1406	}
1407
1408	while ((status =
1409		dmacHw_transferCompleted(channel->dmacHwHandle)) ==
1410	       dmacHw_TRANSFER_STATUS_BUSY) {
1411		;
1412	}
1413
1414	if (status == dmacHw_TRANSFER_STATUS_ERROR) {
1415		printk(KERN_ERR "%s: DMA transfer failed\n", __func__);
1416		return -EIO;
1417	}
1418	return 0;
1419}
1420
1421EXPORT_SYMBOL(dma_wait_transfer_done);
1422
1423/****************************************************************************/
1424/**
1425*   Initiates a DMA, allocating the descriptors as required.
1426*
1427*   @return
1428*       0       Transfer was started successfully
1429*       -EINVAL Invalid device type for this kind of transfer
1430*               (i.e. the device is _DEV_TO_MEM and not _MEM_TO_DEV)
1431*/
1432/****************************************************************************/
1433
1434int dma_transfer(DMA_Handle_t handle,	/* DMA Handle */
1435		 dmacHw_TRANSFER_TYPE_e transferType,	/* Type of transfer being performed */
1436		 dma_addr_t srcData,	/* Place to get data to write to device */
1437		 dma_addr_t dstData,	/* Pointer to device data address */
1438		 size_t numBytes	/* Number of bytes to transfer to the device */
1439    ) {
1440	DMA_Channel_t *channel;
1441	DMA_DeviceAttribute_t *devAttr;
1442	int rc = 0;
1443
1444	channel = HandleToChannel(handle);
1445	if (channel == NULL) {
1446		return -ENODEV;
1447	}
1448
1449	devAttr = &DMA_gDeviceAttribute[channel->devType];
1450
1451	if (devAttr->config.transferType != transferType) {
1452		return -EINVAL;
1453	}
1454
1455	/* We keep track of the information about the previous request for this */
1456	/* device, and if the attributes match, then we can use the descriptors we setup */
1457	/* the last time, and not have to reinitialize everything. */
1458
1459	{
1460		rc =
1461		     dma_alloc_descriptors(handle, transferType, srcData,
1462					   dstData, numBytes);
1463		if (rc != 0) {
1464			return rc;
1465		}
1466	}
1467
1468	/* And kick off the transfer */
1469
1470	devAttr->numBytes = numBytes;
1471	devAttr->transferStartTime = timer_get_tick_count();
1472
1473	dmacHw_initiateTransfer(channel->dmacHwHandle, &devAttr->config,
1474				devAttr->ring.virtAddr);
1475
1476	/* Since we got this far, everything went successfully */
1477
1478	return 0;
1479}
1480
1481EXPORT_SYMBOL(dma_transfer);
1482
1483/****************************************************************************/
1484/**
1485*   Set the callback function which will be called when a transfer completes.
1486*   If a NULL callback function is set, then no callback will occur.
1487*
1488*   @note   @a devHandler will be called from IRQ context.
1489*
1490*   @return
1491*       0       - Success
1492*       -ENODEV - Device handed in is invalid.
1493*/
1494/****************************************************************************/
1495
1496int dma_set_device_handler(DMA_Device_t dev,	/* Device to set the callback for. */
1497			   DMA_DeviceHandler_t devHandler,	/* Function to call when the DMA completes */
1498			   void *userData	/* Pointer which will be passed to devHandler. */
1499    ) {
1500	DMA_DeviceAttribute_t *devAttr;
1501	unsigned long flags;
1502
1503	if (!IsDeviceValid(dev)) {
1504		return -ENODEV;
1505	}
1506	devAttr = &DMA_gDeviceAttribute[dev];
1507
1508	local_irq_save(flags);
1509
1510	devAttr->userData = userData;
1511	devAttr->devHandler = devHandler;
1512
1513	local_irq_restore(flags);
1514
1515	return 0;
1516}
1517
1518EXPORT_SYMBOL(dma_set_device_handler);