原本以为是用户态的文件系统,不过后来研究是直接利用内核usb devios内存访问。大致在usb_hcd_map_urb_for_dma看了下堆栈的情况:
[ 580.372069] ? usb_hcd_map_urb_for_dma+0x5/0x4b0
[ 580.372070] ? usb_hcd_submit_urb+0x164/0x2e0
[ 580.372072] ? usb_hcd_map_urb_for_dma+0x5/0x4b0
[ 580.372074] ? usb_hcd_submit_urb+0x164/0x2e0
[ 580.372075] usb_submit_urb+0x1e2/0x5e0
[ 580.372076] ? idr_alloc_u32+0x93/0xd0
[ 580.372078] usb_start_wait_urb+0x71/0x180
[ 580.372079] usb_control_msg+0xe3/0x140
[ 580.372080] usb_get_string+0x6a/0xc0
[ 580.372082] usb_string_sub+0x6f/0x100
[ 580.372083] usb_string+0xda/0x1b0
[ 580.372083] ? usb_cache_string+0x2f/0xb0
[ 580.372084] usb_cache_string+0x4a/0xb0
[ 580.372085] usb_create_sysfs_intf_files+0x66/0xa0
[ 580.372087] usb_bus_notify+0x4a/0x80
[ 580.372089] blocking_notifier_call_chain+0x68/0x90
[ 580.372090] device_add+0x3a6/0x860
[ 580.372091] ? __kmalloc+0x430/0x470
[ 580.372093] ? usb_cache_string+0x61/0xb0
[ 580.372094] ? usb_cache_string+0x7f/0xb0
[ 580.372095] ? _cond_resched+0x19/0x30
[ 580.372097] usb_set_configuration+0x484/0x830
[ 580.372099] usb_generic_driver_probe+0x43/0x60
[ 580.372100] usb_probe_device+0x3f/0xd0
[ 580.372101] really_probe+0x357/0x460
[ 580.372103] driver_probe_device+0xe9/0x160
[ 580.372104] __device_attach_driver+0x71/0xd0
[ 580.372106] ? driver_allows_async_probing+0x50/0x50
[ 580.372108] bus_for_each_drv+0x84/0xd0
[ 580.372109] __device_attach+0xed/0x170
[ 580.372111] device_initial_probe+0x13/0x20
[ 580.372112] bus_probe_device+0x8f/0xa0
[ 580.372114] device_add+0x3cf/0x860
[ 580.372115] usb_new_device.cold+0x12d/0x304
[ 580.372117] elfcorehdr_read+0x40/0x40
[ 580.372118] port_event+0x57f/0x860
[ 580.372120] ? pm_runtime_autosuspend_expiration.part.0+0x2e/0x40
[ 580.372122] hub_event+0x152/0x3b0
[ 580.372124] process_one_work+0x220/0x3c0
[ 580.372125] worker_thread+0x4d/0x3f0
[ 580.372125] ? process_one_work+0x3c0/0x3c0
[ 580.372126] kthread+0x12b/0x150
[ 580.372128] ? set_kthread_struct+0x40/0x40
[ 580.372129] ret_from_fork+0x1f/0x30
int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
map里面是这个数据的传递
urb->transfer_dma = dma_map_single(
hcd->self.sysdev,
urb->transfer_buffer,
urb->transfer_buffer_length,
dir);
int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
enum dma_data_direction dir, unsigned long attrs);
dma_addr_t dma_map_page_attrs(struct device *dev, struct page *page,
size_t offset, size_t size, enum dma_data_direction dir,
unsigned long attrs);
[10406.090808] Call Trace:
[10406.090809] dump_stack+0x74/0x92
[10406.090812] kum_hook_map_handler+0xe/0x12 [kum_core]
[10406.090815] pre_handler_kretprobe+0x97/0x170
[10406.090816] ? usb_submit_urb+0x1/0x5e0
[10406.090817] kprobe_ftrace_handler+0x11e/0x1f0
[10406.090818] ? usb_submit_urb+0x5/0x5e0
[10406.090819] 0xffffffffc08bf0e3
[10406.090820] RIP: 0010:usb_submit_urb+0x1/0x5e0
[10406.090821] Code: e8 34 1e a4 ff 41 5c 5d c3 48 8b 7f 60 e8 27 1e a4 ff 4c 89 e7 e8 1f 1e a4 ff 41 5c 5d c3 66 66 2e 0f 1f 84 00 00 00 00 00 e8 <5b> 5d a2 29 55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 ec 18 89
[10406.090822] RSP: 0018:ffffb8dfc2b93ad0 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
[10406.090823] RAX: ffffb8dfc2b93ae8 RBX: ffffb8dfc2b93b5c RCX: 0000000080000480
[10406.090824] RDX: ffffffff98a9e03c RSI: 0000000000000c00 RDI: ffff8af2060d9b40
[10406.090825] RBP: ffffb8dfc2b93b30 R08: 00000000000000c0 R09: 0000000000000000
[10406.090825] R10: ffff8af2060d9b40 R11: ffff8af10b51f8a0 R12: ffff8af2060d9b40
[10406.090826] R13: ffff8af101ddc348 R14: 0000000000001388 R15: ffffb8dfc2b93ad8
[10406.090827] ? usb_submit_urb+0x5/0x5e0
[10406.090828] ? usb_start_wait_urb+0x71/0x180
[10406.090829] ? usb_submit_urb+0x5/0x5e0
[10406.090829] ? usb_start_wait_urb+0x71/0x180
[10406.090831] usb_control_msg+0xe3/0x140
[10406.090832] usb_get_string+0x6a/0xc0
[10406.090852] usb_string_sub+0x6f/0x100
[10406.090853] usb_string+0xda/0x1b0
[10406.090854] ? usb_cache_string+0x2f/0xb0
[10406.090855] usb_cache_string+0x4a/0xb0
[10406.090856] usb_new_device+0x81/0x1f0
[10406.090858] elfcorehdr_read+0x40/0x40
[10406.090859] port_event+0x57f/0x860
[10406.090861] ? pm_runtime_autosuspend_expiration.part.0+0x2e/0x40
[10406.090863] hub_event+0x152/0x3b0
[10406.090864] process_one_work+0x220/0x3c0
[10406.090865] worker_thread+0x4d/0x3f0
[10406.090866] ? process_one_work+0x3c0/0x3c0
[10406.090867] kthread+0x12b/0x150
[10406.090868] ? set_kthread_struct+0x40/0x40
[10406.090870] ret_from_fork+0x1f/0x30
[10406.092769] CPU: 1 PID: 12020 Comm: kworker/1:2 Kdump: loaded Tainted: G OE 5.11.0-43-generic #47~20.04.2-Ubuntu
[10406.107131] CPU: 1 PID: 12020 Comm: kworker/1:2 Kdump: loaded Tainted: G OE 5.11.0-43-generic #47~20.04.2-Ubuntu
[10406.107133] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/22/2020
[10406.107134] Workqueue: usb_hub_wq hub_event
[10406.107138] Call Trace:
[10406.107139] dump_stack+0x74/0x92
[10406.107143] kum_hook_map_handler+0xe/0x12 [kum_core]
[10406.107146] pre_handler_kretprobe+0x97/0x170
[10406.107148] ? usb_submit_urb+0x1/0x5e0
[10406.107149] kprobe_ftrace_handler+0x11e/0x1f0
[10406.107151] ? usb_submit_urb+0x5/0x5e0
[10406.107152] 0xffffffffc08bf0e3
[10406.107153] RIP: 0010:usb_submit_urb+0x1/0x5e0
[10406.107154] Code: e8 34 1e a4 ff 41 5c 5d c3 48 8b 7f 60 e8 27 1e a4 ff 4c 89 e7 e8 1f 1e a4 ff 41 5c 5d c3 66 66 2e 0f 1f 84 00 00 00 00 00 e8 <5b> 5d a2 29 55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 ec 18 89
[10406.107155] RSP: 0018:ffffb8dfc2b93c00 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
[10406.107157] RAX: ffffb8dfc2b93c18 RBX: ffffb8dfc2b93c8c RCX: 0000000080000180
[10406.107157] RDX: ffffffff98a9e03c RSI: 0000000000000c00 RDI: ffff8af2060d9540
[10406.107158] RBP: ffffb8dfc2b93c60 R08: 00000000000000c0 R09: 0000000000000000
[10406.107159] R10: ffff8af2060d9540 R11: ffff8af20d777678 R12: ffff8af2060d9540
[10406.107159] R13: ffff8af101ddc170 R14: 00000000000003e8 R15: ffffb8dfc2b93c08
[10406.107161] ? usb_submit_urb+0x5/0x5e0
[10406.107161] ? usb_start_wait_urb+0x71/0x180
[10406.107163] ? usb_submit_urb+0x5/0x5e0
[10406.107163] ? usb_start_wait_urb+0x71/0x180
[10406.107164] usb_control_msg+0xe3/0x140
[10406.107166] hub_ext_port_status+0x86/0x110
[10406.107167] port_event+0x7b/0x860
[10406.107169] ? __switch_to_xtra+0x119/0x510
[10406.107171] hub_event+0x152/0x3b0
[10406.107172] process_one_work+0x220/0x3c0
[10406.107174] worker_thread+0x249/0x3f0
[10406.107175] ? process_one_work+0x3c0/0x3c0
[10406.107175] kthread+0x12b/0x150
[10406.107177] ? set_kthread_struct+0x40/0x40
[10406.107178] ret_from_fork+0x1f/0x30
static int get_port_status(struct usb_device *hdev, int port1,
void *data, u16 value, u16 length)
{
int i, status = -ETIMEDOUT;
for (i = 0; i < USB_STS_RETRIES &&
(status == -ETIMEDOUT || status == -EPIPE); i++) {
status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, value,
port1, data, length, USB_STS_TIMEOUT);
}
return status;
}
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8 requesttype, __u16 value, __u16 index, void *data,
__u16 size, int timeout)
{
struct usb_ctrlrequest *dr;
int ret;
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr)
return -ENOMEM;
dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(size);
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
/* Linger a bit, prior to the next control message. */
if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
msleep(200);
kfree(dr);
return ret;
}
EXPORT_SYMBOL_GPL(usb_control_msg);
static int usb_internal_control_msg(struct usb_device *usb_dev,
unsigned int pipe,
struct usb_ctrlrequest *cmd,
void *data, int len, int timeout)
{
struct urb *urb;
int retv;
int length;
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
控制传输的命令定义
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_REQ_SET_SEL 0x30
#define USB_REQ_SET_ISOCH_DELAY 0x31
#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
#define USB_REQ_GET_ENCRYPTION 0x0E
#define USB_REQ_RPIPE_ABORT 0x0E
#define USB_REQ_SET_HANDSHAKE 0x0F
#define USB_REQ_RPIPE_RESET 0x0F
#define USB_REQ_GET_HANDSHAKE 0x10
#define USB_REQ_SET_CONNECTION 0x11
#define USB_REQ_SET_SECURITY_DATA 0x12
#define USB_REQ_GET_SECURITY_DATA 0x13
#define USB_REQ_SET_WUSB_DATA 0x14
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17
/* specific requests for USB Power Delivery */
#define USB_REQ_GET_PARTNER_PDO 20
#define USB_REQ_GET_BATTERY_STATUS 21
#define USB_REQ_SET_PDO 22
#define USB_REQ_GET_VDM 23
#define USB_REQ_SEND_VDM 24
//__u8 requesttype,
//usb_control_msg
#define USB_DIR_OUT 0 /* to device */
#define USB_DIR_IN 0x80 /* to host */
/*
* USB types, the second of three bRequestType fields
*/
#define USB_TYPE_MASK (0x03 << 5)
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
struct urb {
/* private: usb core and host controller only fields in the urb */
struct kref kref; /* reference count of the URB */
int unlinked; /* unlink error code */
void *hcpriv; /* private data for host controller */
atomic_t use_count; /* concurrent submissions counter */
atomic_t reject; /* submissions will fail */
/* public: documented fields in the urb that can be used by drivers */
struct list_head urb_list; /* list head for use by the urb's
* current owner */
struct list_head anchor_list; /* the URB may be anchored */
struct usb_anchor *anchor;
struct usb_device *dev; /* (in) pointer to associated device */
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
unsigned int pipe; /* (in) pipe information */
unsigned int stream_id; /* (in) stream ID */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
struct scatterlist *sg; /* (in) scatter gather buffer list */
int num_mapped_sgs; /* (internal) mapped sg entries */
int num_sgs; /* (in) number of entries in the sg list */
u32 transfer_buffer_length; /* (in) data buffer length */
u32 actual_length; /* (return) actual transfer length */
unsigned char *setup_packet; /* (in) setup packet (control only) */
dma_addr_t setup_dma; /* (in) dma addr for setup_packet */
int start_frame; /* (modify) start frame (ISO) */
int number_of_packets; /* (in) number of ISO packets */
int interval; /* (modify) transfer interval
* (INT/ISO) */
int error_count; /* (return) number of ISO errors */
void *context; /* (in) context for completion */
usb_complete_t complete; /* (in) completion routine */
struct usb_iso_packet_descriptor iso_frame_desc[0];
/* (in) ISO ONLY */
};
这个 USB_REQ_LOOPBACK_DATA_WRITE并没有在写数据的时候起作用,通过代码我们可以知道, 数据进入 usb_hcd_map_urb_for_dma 后是吧数据的虚拟地址转换成了物理地址。之后找到对应的device的domain来关联设备的。
int iommu_attach_device(struct iommu_domain *domain, struct device *dev);
struct iommu_group {
struct kobject kobj;
struct kobject *devices_kobj;
struct list_head devices;
struct mutex mutex;
struct blocking_notifier_head notifier;
void *iommu_data;
void (*iommu_data_release)(void *iommu_data);
char *name;
int id;
struct iommu_domain *default_domain;
struct iommu_domain *domain;
struct list_head entry;
};
struct iommu_domain {
unsigned type;
const struct iommu_ops *ops;
unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */
iommu_fault_handler_t handler;
void *handler_token;
struct iommu_domain_geometry geometry;
void *iova_cookie;
};
#define IOMMU_READ (1 << 0)
#define IOMMU_WRITE (1 << 1)
#define IOMMU_CACHE (1 << 2) /* DMA cache coherency */
#define IOMMU_NOEXEC (1 << 3)
#define IOMMU_MMIO (1 << 4) /* e.g. things like MSI doorbells */
通过iommu_group 关联 到struct device结构。
不过看了下,iommu最后发现于mtp无关。
数据读写的路径
经过一系列的研究发现,读写并不经过一般的文件系统,而是直接到了usb驱动devio 设备控制逻辑里面。
static long usbdev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret;
ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
return ret;
}
static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p)
{
struct usb_dev_state *ps = file->private_data;
struct inode *inode = file_inode(file);
struct usb_device *dev = ps->dev;
int ret = -ENOTTY;
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
经过switch cmd进入 proc_submiturb
switch (cmd) {
case USBDEVFS_CONTROL:
snoop(&dev->dev, "%s: CONTROL\n", __func__);
ret = proc_control(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
case USBDEVFS_SUBMITURB:
snoop(&dev->dev, "%s: SUBMITURB\n", __func__);
ret = proc_submiturb(ps, p);
if (ret >= 0)
inode->i_mtime = current_time(inode);
break;
static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
sigval_t userurb_sigval;
if (copy_from_user(&uurb, arg, sizeof(uurb)))
return -EFAULT;
memset(&userurb_sigval, 0, sizeof(userurb_sigval));
userurb_sigval.sival_ptr = arg;
return proc_do_submiturb(ps, &uurb,
(((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
arg, userurb_sigval);
}
struct usbdevfs_urb {
unsigned char type;
unsigned char endpoint;
int status;
unsigned int flags;
void __user *buffer;
int buffer_length;
int actual_length;
int start_frame;
union {
int number_of_packets; /* Only used for isoc urbs */
unsigned int stream_id; /* Only used with bulk streams */
};
int error_count;
unsigned int signr; /* signal to be sent on completion,
or 0 if none should be sent. */
void __user *usercontext;
struct usbdevfs_iso_packet_desc iso_frame_desc[0];
};
proc_do_submiturb会对数据进行整合复制,最后以不同的方式映射到内存中。
static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
void __user *arg, sigval_t userurb_sigval){
uurb->buffer_length = le16_to_cpu(dr->wLength);
uurb->buffer += 8;
......
if (num_sgs) {
as->urb->sg = kmalloc_array(num_sgs,
sizeof(struct scatterlist),
GFP_KERNEL);
if (!as->urb->sg) {
ret = -ENOMEM;
goto error;
}
as->urb->num_sgs = num_sgs;
sg_init_table(as->urb->sg, as->urb->num_sgs);
totlen = uurb->buffer_length;
for (i = 0; i < as->urb->num_sgs; i++) {
u = (totlen > USB_SG_SIZE) ? USB_SG_SIZE : totlen;
buf = kmalloc(u, GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto error;
}
sg_set_buf(&as->urb->sg[i], buf, u);
if (!is_in) {
if (copy_from_user(buf, uurb->buffer, u)) {
ret = -EFAULT;
goto error;
}
uurb->buffer += u;
}
totlen -= u;
}
} else if (uurb->buffer_length > 0) {
if (as->usbm) {
unsigned long uurb_start = (unsigned long)uurb->buffer;
as->urb->transfer_buffer = as->usbm->mem +
(uurb_start - as->usbm->vm_start);
} else {
as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
GFP_KERNEL);
if (!as->urb->transfer_buffer) {
ret = -ENOMEM;
goto error;
}
if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer,
uurb->buffer,
uurb->buffer_length)) {
ret = -EFAULT;
goto error;
}
} else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
/*
* Isochronous input data may end up being
* discontiguous if some of the packets are
* short. Clear the buffer so that the gaps
* don't leak kernel data to userspace.
*/
memset(as->urb->transfer_buffer, 0,
uurb->buffer_length);
}
}
}
.......
ret = usb_submit_urb(as->urb, GFP_KERNEL);
}
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
URB_DMA_SG_COMBINED);
urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
enum dma_data_direction {
DMA_BIDIRECTIONAL = 0,
DMA_TO_DEVICE = 1,
DMA_FROM_DEVICE = 2,
DMA_NONE = 3,
};
int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
再往深就是三种映射类型
if (urb->num_sgs) {
int n;
/* We don't support sg for isoc transfers ! */
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
WARN_ON(1);
return -EINVAL;
}
n = dma_map_sg(
hcd->self.sysdev,
urb->sg,
urb->num_sgs,
dir);
if (n <= 0)
ret = -EAGAIN;
else
urb->transfer_flags |= URB_DMA_MAP_SG;
urb->num_mapped_sgs = n;
if (n != urb->num_sgs)
urb->transfer_flags |=
URB_DMA_SG_COMBINED;
} else if (urb->sg) {
struct scatterlist *sg = urb->sg;
urb->transfer_dma = dma_map_page(
hcd->self.sysdev,
sg_page(sg),
sg->offset,
urb->transfer_buffer_length,
dir);
if (dma_mapping_error(hcd->self.sysdev,
urb->transfer_dma))
ret = -EAGAIN;
else
urb->transfer_flags |= URB_DMA_MAP_PAGE;
} else if (object_is_on_stack(urb->transfer_buffer)) {
WARN_ONCE(1, "transfer buffer is on stack\n");
ret = -EAGAIN;
} else {
urb->transfer_dma = dma_map_single(
hcd->self.sysdev,
urb->transfer_buffer,
urb->transfer_buffer_length,
dir);
if (dma_mapping_error(hcd->self.sysdev,
urb->transfer_dma))
ret = -EAGAIN;
else
urb->transfer_flags |= URB_DMA_MAP_SINGLE;
}
dma_addr_t dma_map_page_attrs(struct device *dev, struct page *page,
size_t offset, size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
const struct dma_map_ops *ops = get_dma_ops(dev);
dma_addr_t addr;
BUG_ON(!valid_dma_direction(dir));
if (WARN_ON_ONCE(!dev->dma_mask))
return DMA_MAPPING_ERROR;
if (dma_map_direct(dev, ops) ||
arch_dma_map_page_direct(dev, page_to_phys(page) + offset + size))
addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
else
addr = ops->map_page(dev, page, offset, size, dir, attrs);
debug_dma_map_page(dev, page, offset, size, dir, addr);
return addr;
}
static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
/* DMA must never operate on areas that might be remapped. */
if (dev_WARN_ONCE(dev, is_vmalloc_addr(ptr),
"rejecting DMA map of vmalloc memory\n"))
return DMA_MAPPING_ERROR;
debug_dma_map_single(dev, ptr, size);
return dma_map_page_attrs(dev, virt_to_page(ptr), offset_in_page(ptr),
size, dir, attrs);
}
引用:
https://blog.csdn.net/myarrow/article/details/8484113
&spm=1001.2101.3001.5002&articleId=122250041&d=1&t=3&u=df7eb41b37714983949976c76fdf3342)
877

被折叠的 条评论
为什么被折叠?



