The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

5.4.2 Драйвер сетевого периферийного устройства

5.4.2 Драйвер сетевого периферийного устройства

Предыдущая  Содержание  Следующая V*D*V

Чтобы объяснить модель драйвера периферийного устройства, возьмём в качестве примера сетевое устройство. Оно реализовано в файле drivers/usb/gadget/ether.c.

Функция init драйвера любого драйвера периферийного устройства должна вызывать интерфейс usb_gadget_register_driver.

 

static int __init init (void)

{

  return usb_gadget_register_driver (&eth_driver);

}

module_init (init);

 

eth_driver является структурой usb_gadget_driver, заполненной соответствующими обработчиками.

 

static struct usb_gadget_driver eth_driver = {

 

#ifdef CONFIG_USB_GADGET_DUALSPEED

  .speed      = USB_SPEED_HIGH,

#else

  .speed      = USB_SPEED_FULL,

#endif

 

  .function   = (char *) driver_desc,

  .bind       = eth_bind,

  .unbind     = eth_unbind,

  .setup      = eth_setup,

  .disconnect = eth_disconnect,

};

 

При вызове регистрации из драйвера контроллера вызывается usb_gadget_driver.bind. Ожидается, что bind() драйвера периферийного устройства выполнит следующие действия:

 

Проинициализирует зависимые от устройства структуры данных.

Присоединится к необходимой подсистеме драйверов ядра (например, драйверу последовательного порта, сетевому драйверу, драйверу устройств хранения и так далее).

Проинициализирует блок запроса оконечной точки 0.

 

eth_bind представляет собой функцию привязки.

 

static int

eth_bind (struct usb_gadget *gadget)

{

      …

      …

  net = alloc_etherdev (sizeof *dev);

      …

  net->hard_start_xmit = eth_start_xmit;

  net->open = eth_open;

  net->stop = eth_stop;

  net->do_ioctl = eth_ioctl;

 

  /* Выделение памяти для EP0 */

  dev->req = usb_ep_alloc_request (gadget->ep0,

                                   GFP_KERNEL);

      …

  dev->req->complete = eth_setup_complete;

  dev->req->buf = usb_ep_alloc_buffer (gadget->ep0,

                  USB_BUFSIZ, &dev->req->dma, GFP_KERNEL);

      …

  status = register_netdev (dev->net);

      …

}

 

После завершения настройки, устройство полностью сконфигурировано и функционирует как обычное устройство в стеке драйверов ядра. В данном примере сетевой USB драйвер подключает себя к стеку сетевых драйверов с помощью register_netdev(). Это позволяет приложениям использовать этот интерфейс в качестве стандартного сетевого интерфейса.

 

Каждый блок USB запроса (URB) требует, чтобы блоку была выделена память, и чтобы он был связан с процедурой завершения. Все запросы оконечной точки ставятся в очередь, потому что они ждут опроса данных от контроллера хоста/корня шины. Как только запрос был обработан оборудованием, драйвер контроллера вызывает связанную с ним процедуру завершения.

 

Функция передачи данных в любом драйвере по существу делает следующее:

 

Создаёт новый URB или получает его из предварительно созданного пула

Связывает данные и размер данных URB с данными и размером, предоставляемыми драйвером верхнего уровня

Помещает URB в очередь для передачи данных в соответствующей оконечной точке

 

Функцией передачи драйвера сетевого периферийного устройства является eth_start_xmit.

 

static int eth_start_xmit (struct sk_buff *skb,

                           struct net_device *net)

{

  struct eth_dev*dev = (struct eth_dev *) net->priv;

  int length = skb->len;

    …

  req->buf = skb->data;

  req->context = skb;

  req->complete = tx_complete;

  req->length = length;

    …

  retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);

    …

}

 

Приём данных также требует использования URB и делается следующим образом:

 

Создаётся список пустых URB.

Инициализируется каждый из них с надлежащей процедурой завершения. Процедура завершения для приёма указывает верхним уровням стека сетевых протоколов о прибытии данных.

Блоки помещаются в очередь в соответствующей оконечной точке.

 

Во время старта драйвер сетевого периферийного устройства заполняет очередь оконечной точки URB-ами с помощью функции rx_submit.

 

static int

rx_submit (struct eth_dev *dev, struct usb_request *req,

           int gfp_flags)

{

  struct sk_buff *skb;

  size_t size;

 

  size = (sizeof (struct ethhdr) + dev->net->mtu +

                                   RX_EXTRA);

 

  skb = alloc_skb (size, gfp_flags);

    …

  req->buf = skb->data;

  req->length = size;

  req->complete = rx_complete;

  req->context = skb;

  retval = usb_ep_queue (dev->out_ep, req, gfp_flags);

    …

}

 

Индикация приёма данных для сетевого уровня осуществляется в процедуре завершения.

 

static void rx_complete (struct usb_ep *ep,

                         struct usb_request *req)

{

  struct sk_buff *skb = req->context;

  struct eth_dev *dev = ep->driver_da

    …

  skb_put (skb, req->actual);

  skb->dev = dev->net;

  skb->protocol = eth_type_trans (skb, dev->net);

    …

  netif_rx (skb);

}

 

Предыдущая  Содержание  Следующая