libpdma.c

00001 /* #pragma ident "@(#)libpdma.c 1.24 05/30/07 EDT" */
00002 
00003 /*
00004  * See /opt/EDTpcd/README.pdma
00005  */
00006 
00007 #include <sys/mman.h>
00008 #include "edtinc.h"
00009 #include "libpdma.h"
00010 
00011 
00012 u_int
00013 regswap(u_int val)
00014 {
00015 #ifdef __sparc
00016     /* byteswap */
00017     val = ((val & 0xFF00FF00) >> 8) | ((val & 0x00FF00FF) << 8);
00018 
00019     /* shortswap */
00020     val = ((val & 0xFFFF0000) >> 16) | ((val & 0x0000FFFF) << 16);
00021 #endif
00022 
00023     return val;
00024 }
00025 
00026 
00027 
00028 int
00029 pdma_init(EdtDev *edt_p, int bufsize, int numbufs, u_char **bufs)
00030 {
00031     u_int mode;
00032     void * mapaddr;
00033     Pdma_t *p;
00034 
00035     if (bufsize > PDMA_MAX_SIZE)
00036     {
00037         fprintf(stderr, "pdma_init:  bufsize (%d) exceeds PDMA_MAX_SIZE (%d)\n",
00038                                                        bufsize, PDMA_MAX_SIZE);
00039         return -1;
00040     }
00041 
00042     if (numbufs != 1)
00043     {
00044         fprintf(stderr, "pdma_init:  number of buffers must be 1.\nContinuing with one buffer.\n");
00045         numbufs = 1;
00046     }
00047 
00048     if ((edt_p->Pdma_p = (Pdma_t *) edt_alloc(sizeof(Pdma_t))) == NULL)
00049     {
00050         return -1;
00051     }
00052 
00053     p = (Pdma_t *) edt_p->Pdma_p;
00054     memset(p, 0, sizeof(Pdma_t));
00055 
00056 
00057     /*
00058      * Map in the PCI registers and set a pointer to the DMA command register
00059      */
00060 
00061     if ((mapaddr = (void *) edt_mapmem(edt_p, 0, 256)) == NULL)
00062         return -1;
00063 
00064     p->dmacmd  = (u_int  *) ((u_char *)mapaddr + (EDT_SG_NXT_CNT    & 0xff));
00065     p->dmaaddr = (u_int  *) ((u_char *)mapaddr + (EDT_SG_NXT_ADDR   & 0xff));
00066     p->dmacfg  = (u_int  *) ((u_char *)mapaddr + (EDT_DMA_CFG       & 0xff));
00067     p->dmacnt  = (u_int  *) ((u_char *)mapaddr + (EDT_DMA_CUR_CNT   & 0xff));
00068     p->off_p   = (u_char *) ((u_char *)mapaddr + (EDT_REMOTE_OFFSET & 0xff));
00069     p->data_p  = (u_char *) ((u_char *)mapaddr + (EDT_REMOTE_DATA   & 0xff));
00070 
00071 
00072     /*
00073      * Enable Programmed DMA mode, form a single ring buffer, and
00074      * map in the buffer's scatter-gather list
00075      */
00076 
00077     mode = 1;
00078     edt_ioctl(edt_p, EDTS_PDMA_MODE, &mode);
00079 
00080     if (edt_configure_ring_buffers(edt_p, bufsize, numbufs, EDT_WRITE, bufs) != 0)
00081     {
00082         edt_free((u_char *)p);
00083         return -1;
00084     }
00085 
00086     p->pdma_size     = bufsize;
00087     p->pdma_databufs = edt_buffer_addresses(edt_p);
00088 
00089 
00090     /*
00091      * Map and copy the driver ring buffer SG list.
00092      */
00093     if ((mapaddr = (volatile caddr_t) mmap((caddr_t)0, PDMA_SIZE,
00094         PROT_READ|PROT_WRITE, MAP_SHARED, edt_p->fd, PDMA_OFFSET)) == NULL)
00095     {
00096         edt_free((u_char *)p);
00097         return -1;
00098     }
00099     p->dma_sglist = (u_int *) mapaddr;
00100 
00101     memcpy((u_char *)p->dma_sglist_copy, (u_char *)p->dma_sglist, PDMA_SIZE);
00102 
00103     /*
00104      * Obtain the physical address for the scatter-gather list.
00105      */
00106     {
00107         edt_buf sg_args;
00108 
00109         sg_args.desc = EDT_SGTODO_FIRST_SG;
00110         sg_args.value = 0;
00111         edt_ioctl(edt_p, EDTG_SGINFO, &sg_args);
00112         p->sg_paddr = (u_int) sg_args.value;
00113     }
00114 
00115     p->sv_dma_cfg = *p->dmacfg;
00116     p->dma_intr_en = 1;
00117 
00118     /*
00119      * At this step the driver does everything except program
00120      * the DMA registers in PDMA mode.  Later the user calls
00121      * pdma_start_dma() to program the registers each time a
00122      * zero-latency DMA is required.
00123      */
00124     edt_start_buffers(edt_p, 0);
00125 
00126     return 0;
00127 }
00128 
00129 
00130 int
00131 pdma_close(EdtDev *edt_p)
00132 {
00133     int mode = 0;
00134     Pdma_t *p = (Pdma_t *) edt_p->Pdma_p;
00135     extern int errno;
00136 
00137     if (p == NULL)
00138     {
00139         errno = EINVAL;
00140         return -1;
00141     }
00142 
00143     if (p && p->dma_sglist)
00144         munmap((caddr_t) p->dma_sglist, PDMA_SIZE);
00145 
00146     edt_disable_ring_buffers(edt_p);
00147     edt_ioctl(edt_p, EDTS_PDMA_MODE, &mode);
00148     edt_free((u_char *)edt_p->Pdma_p);
00149     edt_p->Pdma_p = NULL;
00150 
00151     return 0;
00152 }
00153 
00154 
00155 /*
00156  * Set the size of the next Pdma transfer in bytes.
00157  */
00158 int
00159 pdma_set_size(EdtDev *edt_p, int size)
00160 {
00161     int i;
00162     Pdma_t *p = (Pdma_t *) edt_p->Pdma_p;
00163     extern int errno;
00164 
00165     if (p == NULL)
00166     {
00167         errno = EINVAL;
00168         return -1;
00169     }
00170 
00171     /*
00172      * Return error if larger than pdma_size or not divisible by 4.
00173      */
00174     if (size > p->pdma_size || size != (size & ~0x3))
00175     {
00176         errno = EINVAL;
00177         return -1;
00178     }
00179 
00180     /* Start with an unmodified copy of the SG list */
00181     memcpy((u_char *)p->dma_sglist, (u_char *)p->dma_sglist_copy, PDMA_SIZE);
00182 
00183 
00184     /* Go through the list and adjust the size */
00185     p->dma_count = 0;
00186     for (i = 1; size > 0; i += 2)
00187     {
00188         if (size > regswap(p->dma_sglist[i]))
00189         {
00190             size -= regswap(p->dma_sglist[i]);
00191             ++ p->dma_count;
00192         }
00193         else
00194         {
00195             p->dma_sglist[i] = regswap(size | EDT_LIST_PAGEINT);
00196             ++ p->dma_count;
00197             break;
00198         }
00199     }
00200 
00201     if ((p->dma_count << 3) > PDMA_PAGESIZE)
00202         p->dma_count = PDMA_PAGESIZE >> 3;
00203 
00204     return 0;
00205 }
00206 
00207 
00208 int
00209 pdma_start_dma(EdtDev *edt_p)
00210 {
00211     Pdma_t *p = (Pdma_t *) edt_p->Pdma_p;
00212     u_int dmacmd_reg;
00213     u_int dmacfg_reg, tmp;
00214     int rw = 1, burst = 1;
00215     extern int errno;
00216 
00217     if (p == NULL)
00218     {
00219         errno = EINVAL;
00220         return -1;
00221     }
00222 
00223     dmacmd_reg = EDT_DMA_START | ((rw)             ? EDT_DMA_MEM_RD : 0)
00224                                | ((burst)          ? EDT_BURST_EN   : 0)
00225                                | ((p->dma_intr_en) ? EDT_EN_MN_DONE : 0);
00226 
00227     dmacmd_reg |= (p->dma_count << 3);
00228 
00229     dmacfg_reg  = p->sv_dma_cfg
00230                 | ((burst)          ? regswap(EDT_RFIFO_ENB)   : 0)
00231                 | ((p->dma_intr_en) ? regswap(EDT_PCI_EN_INTR) : 0);
00232 
00233     *p->dmacfg  = regswap(dmacfg_reg);
00234     tmp = *p->dmacfg;
00235 
00236     *p->dmaaddr = regswap(p->sg_paddr);
00237     tmp = *p->dmaaddr;
00238 
00239     *p->dmacmd  = regswap(dmacmd_reg);
00240     tmp = *p->dmacmd;
00241 
00242     return 0;
00243 }
00244 
00245 
00246 int
00247 pdma_flush_fifo(EdtDev * edt_p)
00248 {
00249     unsigned char cmd;
00250     unsigned int dmy;
00251     Pdma_t *p = (Pdma_t *) edt_p->Pdma_p;
00252     extern int errno;
00253 
00254     if (p == NULL)
00255     {
00256         errno = EINVAL;
00257         return -1;
00258     }
00259 
00260 /* The PCI fifo is not used during output */
00261 #if 0
00262     /* Turn off the PCI fifo */
00263     dmacfg_copy = regswap(*dmacfg);
00264     dmacfg_copy &= (~EDT_RFIFO_ENB);
00265     *dmacfg = regswap(dmacfg_copy);
00266     dmacfg_copy = regswap(*dmacfg);
00267 #endif
00268 
00269 
00270     /* reset the interface fifos */
00271     *p->off_p = PCD_CMD & 0xff;
00272     dmy = *p->off_p;
00273     cmd = *p->data_p;
00274     cmd &= ~PCD_ENABLE;
00275     *p->data_p = cmd;
00276     dmy = *p->data_p;
00277     cmd |= PCD_ENABLE;
00278     *p->data_p = cmd;
00279     dmy = *p->data_p;
00280 
00281 
00282 /* The PCI fifo is not used during output */
00283 #if 0
00284     /* Turn     on the PCI fifos, which flushes them */
00285     dmacfg_copy |= (EDT_RFIFO_ENB);
00286     *dmacfg = regswap(dmacfg_copy);
00287     dmacfg_copy = regswap(*dmacfg);
00288 #endif
00289 
00290     return 0;
00291 }
00292 
00293 int
00294 pdma_abort_dma(EdtDev * edt_p)
00295 {
00296     Pdma_t *p = (Pdma_t *) edt_p->Pdma_p;
00297     u_int dmacmd_reg = regswap(*p->dmacmd);
00298     extern int errno;
00299 
00300     if (p == NULL)
00301     {
00302         errno = EINVAL;
00303         return -1;
00304     }
00305 
00306     dmacmd_reg |= EDT_DMA_ABORT;
00307    *p->dmacmd = regswap(dmacmd_reg);
00308     dmacmd_reg = regswap(*p->dmacmd);
00309 
00310     return 0;
00311 }
00312 
00313 int
00314 pdma_write_databuf(EdtDev *edt_p, int bufnum, void *buf, int size)
00315 {
00316     Pdma_t *p = (Pdma_t *) edt_p->Pdma_p;
00317     extern int errno;
00318 
00319     if (p == NULL)
00320     {
00321         errno = EINVAL;
00322         return -1;
00323     }
00324 
00325     printf("pdma_write_databuf pdma_size %d size %d\n", p->pdma_size, size);
00326     fflush(stdout);
00327     if (size > p->pdma_size)
00328     {
00329         errno = EINVAL;
00330         return -1;
00331     }
00332 
00333     memcpy(p->pdma_databufs[bufnum], buf, size);
00334 
00335     return size;
00336 }
00337 
00338 
00339 void
00340 pdma_dmaint_enable(EdtDev * edt_p, int enable)
00341 {
00342     Pdma_t *p = (Pdma_t *) edt_p->Pdma_p;
00343 
00344     p->dma_intr_en = enable;
00345 }
00346 

Generated on 19 Jun 2015 by  doxygen 1.4.7