2  * The USB Monitor, inspired by Dave Harding's USBMon.
 
   4  * mon_dma.c: Library which snoops on DMA areas.
 
   6  * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com)
 
   8 #include <linux/kernel.h>
 
   9 #include <linux/list.h>
 
  10 #include <linux/highmem.h>
 
  13 #include <linux/usb.h>  /* Only needed for declarations in usb_mon.h */
 
  17  * PC-compatibles, are, fortunately, sufficiently cache-coherent for this.
 
  19 #if defined(__i386__) || defined(__x86_64__) /* CONFIG_ARCH_I386 doesn't exit */
 
  20 #define MON_HAS_UNMAP 1
 
  22 #define phys_to_page(phys)      pfn_to_page((phys) >> PAGE_SHIFT)
 
  24 char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
 
  32          * On i386, a DMA handle is the "physical" address of a page.
 
  33          * In other words, the bus address is equal to physical address.
 
  36         pg = phys_to_page(dma_addr);
 
  39          * We are called from hardware IRQs in case of callbacks.
 
  40          * But we can be called from softirq or process context in case
 
  41          * of submissions. In such case, we need to protect KM_IRQ0.
 
  43         local_irq_save(flags);
 
  44         map = kmap_atomic(pg, KM_IRQ0);
 
  45         ptr = map + (dma_addr & (PAGE_SIZE-1));
 
  46         memcpy(dst, ptr, len);
 
  47         kunmap_atomic(map, KM_IRQ0);
 
  48         local_irq_restore(flags);
 
  52 void mon_dmapeek_vec(const struct mon_reader_bin *rp,
 
  53     unsigned int offset, dma_addr_t dma_addr, unsigned int length)
 
  56         unsigned int step_len;
 
  59         unsigned long page_off, page_len;
 
  61         local_irq_save(flags);
 
  63                 /* compute number of bytes we are going to copy in this page */
 
  65                 page_off = dma_addr & (PAGE_SIZE-1);
 
  66                 page_len = PAGE_SIZE - page_off;
 
  67                 if (page_len < step_len)
 
  70                 /* copy data and advance pointers */
 
  71                 pg = phys_to_page(dma_addr);
 
  72                 map = kmap_atomic(pg, KM_IRQ0);
 
  73                 offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
 
  74                 kunmap_atomic(map, KM_IRQ0);
 
  78         local_irq_restore(flags);
 
  84 char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
 
  89 void mon_dmapeek_vec(const struct mon_reader_bin *rp,
 
  90     unsigned int offset, dma_addr_t dma_addr, unsigned int length)
 
  95 #endif /* MON_HAS_UNMAP */