linux怎样实现外接hub驱动

linux怎样实现外接hub驱动,第1张

linux usb hub驱动位于/drivers/usb/core/hub.c文件中,作为usb core的一部分,hub驱动是无需驱动开发人员自己实现的。hub驱动也是usb设备接口驱动没事,向kernel中注册一个struct usb_driver结构即可。

一般是由于hub供电不足引起的,是否功率过大

HUB是一个多端口的转发器,在以HUB为中心设备时,即使网络中某条线路产生了故障,并不影响其它线路的工作。所以HUB在局域网中得到了广泛的应用。大多数的时候它用在星型与树型网络拓扑结构中,以RJ45接口与各主机相连(也有BNC接口),HUB按照不同的说法有很多种类。 HUB按照对输入信号的处理方式上,可以分为无源HUB、有源HUB、智能HUB。

static int __init ohci_hcd_mod_init(void)

{

platform_driver_register(&ohci_hcd_s3c2410_driver)

}

其实真正注册的是ohci_hcd_s3c2410_driver这个驱动。那我们来看一下这个结构体的具体值。

static struct platform_driver ohci_hcd_s3c2410_driver= {

.probe = ohci_hcd_s3c2410_drv_probe,

.remove = ohci_hcd_s3c2410_drv_remove,

.shutdown = usb_hcd_platform_shutdown,

.driver = {

.owner = THIS_MODULE,

.name = "s3c2410-ohci",

},

}

那我们一一来看上述的每一个函数的实现。

2.1 hcd 探测

函数很简单其实现功能的是usb_hcd_s3c2410_probe函数。

static int ohci_hcd_s3c2410_drv_probe(structplatform_device *pdev)

{

returnusb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev)

}

ohci_s3c2410_hc_driver提供了对于ohci的 *** 作集。对于这些函数在后面的学习中去看,在此不加扩展。我们将下面的函数剔除枝叶留其主干。

static int usb_hcd_s3c2410_probe (const structhc_driver *driver,

struct platform_device *dev)

{

structusb_hcd *hcd = NULL

int retval

#if !defined(CONFIG_ARCH_2410)

usb_host_clk_en() --使能clk

#endif

s3c2410_usb_set_power(dev->dev.platform_data,1, 1)

s3c2410_usb_set_power(dev->dev.platform_data,2, 1)

hcd =usb_create_hcd(driver, &dev->dev, "s3c24xx") --创建一个hcd

hcd->rsrc_start= dev->resource[0].start--获取物理地址

hcd->rsrc_len = dev->resource[0].end -dev->resource[0].start + 1

request_mem_region(hcd->rsrc_start,hcd->rsrc_len, hcd_name)

clk =clk_get(&dev->dev, "usb-host")

s3c2410_start_hc(dev,hcd)

hcd->regs= ioremap(hcd->rsrc_start, hcd->rsrc_len)

ohci_hcd_init(hcd_to_ohci(hcd))

retval = usb_add_hcd(hcd,dev->resource[1].start, IRQF_DISABLED)

return 0

}

对于usb的电源管理,我们暂时不看,不看不代表不重要,电源管理是很重要的。

那依次来看上面的函数。usb_create_hcd创建和初始化一个hcd结构体。

s3c2410_start_hc启动hc。这里有一个很奇怪的结构体就是struct s3c2410_hcd_info,在s3c6410中并没有看到该结构体的赋值。也许有人对此很困惑,该结构体做什么用的。那我们来看该结构体的真正面目。

struct s3c2410_hcd_info {

structusb_hcd *hcd --保存该hcd_info所属的hcd

structs3c2410_hcd_portport[2]--两个端口。

void(*power_control)(intport, int to)--电源控制

void(*enable_oc)(structs3c2410_hcd_info *, int on)

void(*report_oc)(structs3c2410_hcd_info *, int ports)

}

在usb-host.txt中对其功能进行了说明,就是一对函数,使能过流检测和控制端口电源状态。

power_control:使能或禁止端口电源

enable_oc:使能或禁止端口过流检测

report_oc:当端口存在过流,则会调用该函数。

static void s3c2410_start_hc(structplatform_device *dev, struct usb_hcd *hcd)

{

structs3c2410_hcd_info *info = dev->dev.platform_data

clk_enable(clk)

if (info !=NULL) { --在s3c6410中该info为空。

info->hcd = hcd

info->report_oc= s3c2410_hcd_oc

if(info->enable_oc != NULL) {

(info->enable_oc)(info,1)

}

}

}

初始化ohci_hcd

static void ohci_hcd_init(structohci_hcd *ohci)

{

ohci->next_statechange= jiffies

spin_lock_init(&ohci->lock)

INIT_LIST_HEAD(&ohci->pending)

}

初始化并注册usb_hcd

完成通用hcd的初始化和注册,在这里同时完成中断的申请和注册。

int usb_add_hcd(struct usb_hcd *hcd,unsigned intirqnum, unsigned long irqflags)

{

int retval

structusb_device *rhdev

hcd->authorized_default= hcd->wireless? 0 : 1 --判断是否为无线

set_bit(HCD_FLAG_HW_ACCESSIBLE,&hcd->flags)--设置HW_ACCESSIBLE旗标

if ((retval =hcd_buffer_create(hcd)) != 0) { --开辟hcd的缓冲区

returnretval

}

if ((retval =usb_register_bus(&hcd->self)) <0)

gotoerr_register_bus

if ((rhdev =usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {

retval= -ENOMEM

gotoerr_allocate_root_hub

}

rhdev->speed= (hcd->driver->flags &HCD_USB2) ? USB_SPEED_HIGH :USB_SPEED_FULL--指定根hub的speed

hcd->self.root_hub= rhdev

device_init_wakeup(&rhdev->dev,1)

if(hcd->driver->reset &&(retval = hcd->driver->reset(hcd))<0) {--为NULL

gotoerr_hcd_driver_setup

}

if(device_can_wakeup(hcd->self.controller)

&&device_can_wakeup(&hcd->self.root_hub->dev))

dev_dbg(hcd->self.controller,"supports USB remote wakeup\n")

if(hcd->driver->irq) { --中断处理

if(irqflags &IRQF_SHARED)

irqflags&= ~IRQF_DISABLED

snprintf(hcd->irq_descr,sizeof(hcd->irq_descr), "%s:usb%d",

hcd->driver->description,hcd->self.busnum)

request_irq(irqnum,&usb_hcd_irq, irqflags,hcd->irq_descr, hcd)--申请中断线

}

hcd->irq= irqnum

} else {

hcd->irq= -1;

}

hcd->driver->start(hcd) --调用start为 ohci_s3c2410_start

rhdev->bus_mA= min(500u, hcd->power_budget)

register_root_hub(hcd)); --注册root hub

retval =sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group)

if (retval<0) {

gotoerror_create_attr_group

}

if(hcd->uses_new_polling &&hcd->poll_rh)

usb_hcd_poll_rh_status(hcd)

returnretval

}

那一一来看上面的函数,学习内核就要有打破砂锅问到底的精神,唯有知道那背后的种种风光,才能领略那种种风采。闲话不说,继续!

记住下面结构体中flag的值。那就看这几个宏定义是什么意思。

#defineHCD_MEMORY 0x0001 --hc的寄存器使用memory映射

#defineHCD_LOCAL_MEM 0x0002 --hc使用local memory

#defineHCD_USB11 0x0010 --usb1.1

#defineHCD_USB20x0020 --usb2.0

static const struct hc_driver ohci_s3c2410_hc_driver=

{

.flags =HCD_USB11 | HCD_MEMORY,

};

为hcd分配缓冲池,当hc需要使用DMA内存分配器。

int hcd_buffer_create(struct usb_hcd *hcd)

{

charname[16]

int i, size

if(!hcd->self.controller->dma_mask &&

!(hcd->driver->flags &HCD_LOCAL_MEM))

return 0

--#define HCD_BUFFER_POOLS 4

我们查看pool_max其实是一个全局数组。如果需要开辟的缓冲区更大的话,直接采用分配page的函数。

static const size_tpool_max[HCD_BUFFER_POOLS] = {

32,128,512,PAGE_SIZE/ 2

}

for (i = 0i<HCD_BUFFER_POOLSi++) {

size = pool_max[i]

if(!size)

continue

snprintf(name,sizeof name, "buffer-%d", size)

hcd->pool[i] = dma_pool_create(name,hcd->self.controller,size, size, 0)

if(!hcd->pool [i]) {

hcd_buffer_destroy(hcd)

return-ENOMEM

}

}

return 0

}

dma_pool_create创建一个DMA池(生成一个dma_pool,并没有分配相应空间,真正分配物理内存将在dma_pool_alloc()总实现)。

下面的函数是usb_bus注册,对于该函数也许很难理解。不过参照网上http://www.sudu.cn/info/html/edu/20080425/301909.html的说明,估计会好理解很多。

每个主机控制器拥有一个USB系统,称为一个USB总线。USBD支持多个主机控制器,即多个USB总线。当每增加一个主机控制器时,会给他分配一个usb_bus结构。USBD动态安装和卸载主机驱动。主机驱动安装时,他的初始化函数一方面完成主机控制器硬件的设置和初始化工作,另一方面调用usb_alloc_bus和usb_register_bus来将自己注册到USBD中去,供USB子系统访问。

static int usb_register_bus(struct usb_bus *bus)

{

int result =-E2BIG

int busnum

mutex_lock(&usb_bus_list_lock)

busnum =find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1)

--用busmap来存储主机驱动,一个bit位代表一个主机驱动

if (busnum >=USB_MAXBUS) {

return result

}

set_bit (busnum,busmap.busmap)

bus->busnum = busnum

bus->dev =device_create(usb_host_class, bus->controller, MKDEV(0, 0),bus,"usb_host%d", busnum)

--在usb_host类下创建一个usb_host设备。

list_add(&bus->bus_list, &usb_bus_list)

mutex_unlock(&usb_bus_list_lock)

usb_notify_add_bus(bus)

return 0

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7170118.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-02
下一篇 2023-04-02

发表评论

登录后才能评论

评论列表(0条)

保存