LINUX.ORG.RU

unbind/bind device from/to driver

 , ,


0

1

Нужно переписать следующие куски кода на баше, успешно работающие в юзерспейсе, на Си для использования в ядерном модуле. Никогда раньше с этим не сталкивался, гугление не дало ничего вразумительного. Как это правильно сделать?

echo -n manual > /sys/bus/serio/devices/serio1/bind_mode
echo -n serio1 > /sys/bus/serio/drivers/psmouse/unbind
echo -n manual > /sys/bus/serio/devices/serio1/bind_mode
echo -n none > /sys/bus/serio/drivers/psmouse/drvctl
echo -n auto > /sys/bus/serio/devices/serio1/bind_mode
echo -n reconnect > /sys/bus/serio/drivers/psmouse/drvctl
echo -n manual > /sys/bus/serio/devices/serio1/bind_mode
echo -n psmouse > /sys/bus/serio/devices/serio1/drvctl
Нашёл нечто похожее в коде модуля vboxpci из VirtualBox'а, но там идёт напрямую запись в файлы, что, мне кажется, не является самым правильным способом:
    if (fDetach)
    {
        char*              szCmdBuf;
        char*              szFileBuf;
        struct file*       pFile;
        int                iCmdLen;
        const int          cMaxBuf = 128;
        const struct cred *pOldCreds;
        struct cred       *pNewCreds;

        /*
         * Now perform kernel analog of:
         *
         * echo -n "10de 040a" > /sys/bus/pci/drivers/pci-stub/new_id
         * echo -n 0000:03:00.0 > /sys/bus/pci/drivers/nvidia/unbind
         * echo -n 0000:03:00.0 > /sys/bus/pci/drivers/pci-stub/bind
         *
         * We do this way, as this interface is presumingly more stable than
         * in-kernel ones.
         */
        szCmdBuf  = kmalloc(cMaxBuf, GFP_KERNEL);
        szFileBuf = kmalloc(cMaxBuf, GFP_KERNEL);
        if (!szCmdBuf || !szFileBuf)
            goto done;

        /* Somewhat ugly hack - override current credentials */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
        pNewCreds = prepare_creds();
        if (!pNewCreds)
                goto done;

        pNewCreds->fsuid = 0;
        pOldCreds = override_creds(pNewCreds);
#endif

        RTStrPrintf(szFileBuf, cMaxBuf,
                              "/sys/bus/pci/drivers/%s/new_id",
                              PCI_STUB_MODULE);
        pFile = vboxPciFileOpen(szFileBuf, O_WRONLY);
        if (pFile)
        {
            iCmdLen = RTStrPrintf(szCmdBuf, cMaxBuf,
                                  "%04x %04x",
                                  uVendor, uDevice);
            /* Don't write trailing \0 */
            vboxPciFileWrite(pFile, 0, szCmdBuf, iCmdLen);
            vboxPciFileClose(pFile);
        }
        else
            printk(KERN_DEBUG "vboxpci: cannot open %s\n", szFileBuf);

        iCmdLen = RTStrPrintf(szCmdBuf, cMaxBuf,
                              "0000:%02x:%02x.%d",
                              uBus, uDevFn>>3, uDevFn&7);

        /* Unbind if bound to smth */
        if (pIns->szPrevDriver[0])
        {
            RTStrPrintf(szFileBuf, cMaxBuf,
                        "/sys/bus/pci/drivers/%s/unbind",
                         pIns->szPrevDriver);
            pFile = vboxPciFileOpen(szFileBuf, O_WRONLY);
            if (pFile)
            {

                /* Don't write trailing \0 */
                vboxPciFileWrite(pFile, 0, szCmdBuf, iCmdLen);
                vboxPciFileClose(pFile);
            }
            else
                printk(KERN_DEBUG "vboxpci: cannot open %s\n", szFileBuf);
        }

        RTStrPrintf(szFileBuf, cMaxBuf,
                    "/sys/bus/pci/drivers/%s/bind",
                    PCI_STUB_MODULE);
        pFile = vboxPciFileOpen(szFileBuf, O_WRONLY);
        if (pFile)
        {
            /* Don't write trailing \0 */
            vboxPciFileWrite(pFile, 0, szCmdBuf, iCmdLen);
            vboxPciFileClose(pFile);
        }
        else
            printk(KERN_DEBUG "vboxpci: cannot open %s\n", szFileBuf);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
        revert_creds(pOldCreds);
        put_cred(pNewCreds);
#endif

      done:
        kfree(szCmdBuf);
        kfree(szFileBuf);
    }
Судя по комментарию «We do this way, as this interface is presumingly more stable than in-kernel ones» существует и другой способ, родной для ядра, без записи в ФС. И костыль, зависимый от версии ядра, мне тоже не нравится. Вопрос в том, как это сделать по-человечески?

Ответ на: комментарий от dimon555

может, посмотреть, где это обрабатывается при записи в sysfs в ядре?

Пытался это найти. Оказалось, что в итоге надо использовать driver_find_device() и bus_for_each_drv(), но к последней не хватает параметров — не нашёл функции-итератора bus'ов. Сейчас уже понял, что как-то это неправильно отключать тачпад, делая unbind драйвера. Сделал небольшой патч для драйвера psmouse, который добавляет функциональность временного отключения устройства, но тоже не уверен, что всё сделал правильно, но на моём ноуте всё работает стабильно:

http://www.mail-archive.com/platform-driver-x86@vger.kernel.org/msg03332.html

gentoo_root ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.