Ядро Android: Как создать /dev/video0 до запуска демона ueventd?
Я хочу получить доступ к /dev/video0 из модуля ядра после инициализации камеры. Для этого я хочу создать узел /dev/video0 до запуска демона ueventd.
1 ответ
При более глубоком рассмотрении обработки ядром узла /dev/video0 всякий раз, когда приложение пытается открыть этот файл, оно получает указатель FILE *fp, виртуальная файловая система ядра Linux проверяет, является ли это обычным файлом или файлом устройства, и если это В файле устройства он проверяет свой основной номер, чтобы отследить драйвер, который его зарегистрировал, и сохраняет младший номер в поле i_rdev struct inode *inode, которое снова внедряется в struct file *fp и передается этому драйверу.
Таким образом, для каждого FILE *fp, открытого приложением, в зарегистрированном драйвере есть struct file *fp, т.е. в нашем случае драйвер v4l2. Этот указатель файла передается в ядро ioctl API v4l2_ioctl.
Теперь внутренний драйвер v4l2 поддерживает массив указателей на все зарегистрированные видеоустройства, как показано ниже:static struct video_device * video_device [VIDEO_NUM_DEVICES];
Теперь, если мы увидим реализацию основного вызова ioctl.
static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = video_devdata(filp);
...
}
Эта структура видеоустройства извлекается из файлового указателя, который является ключом, с помощью которого мы можем управлять видеоустройством, т.е. нашей камерой, изнутри ядра, поскольку оно содержит функциональные указатели на все зарегистрированные ioctl v4l2. Поэтому наша цель - получить доступ к структуре видеоустройства из ядра.
Теперь снова посмотрим, как ядро обращается к видеоустройству, когда оно получает запрос от приложения.
struct video_device *video_devdata(struct file *file)
{
return video_device[iminor(file->f_path.dentry->d_inode)];
}
EXPORT_SYMBOL(video_devdata);
static inline unsigned iminor(const struct inode *inode)
{
return MINOR(inode->i_rdev);
}
Как видно выше, он использует поле i_rdev для получения младшего номера, передаваемого из struct file *fp через VFS.
Подводя итог, если мы хотим получить доступ к ioctl из ядра, нам нужно заполнить фиктивный указатель файла * fp, содержащий младший номер в поле file->f_path.dentry->d_inode.i_rdev, подсистема v4l2 получит структуру video_device, используя это поле, и будет уметь дальше управлять операциями ioctl из структуры video_device, используя поле video_device->ioctl_ops, как показано ниже.
struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
/* device ops */
const struct v4l2_file_operations *fops;
const struct v4l2_ioctl_ops *ioctl_ops;
...
}
Чтобы установить file->f_path.dentry->d_inode.i_rdev, нам нужно добавить ссылки на структуру inode и dentry внутри структуры файла, как показано ниже псевдокода:
static int enumerate_camera()
{
inode.i_rdev = cam_minor_number ;// Saved when camera device registered;
dentry.d_inode = inode;
file.f_path.dentry = dentry;
file.f_dentry->d_inode = inode;
....
}