7.工程中的Linux设备驱动
platform设备驱动
http://lxr.oss.org.cn/source/drivers/input/input.c?v=2.6.34#L1529
platform总线,会匹配相应的设备和驱动。
现实的设备中都需要挂接一种总线,对于本身依附于PCI,USB,I2C,SPI设备而言,这不会是问题,但是,如果不依赖于此类总线,Linux发明了platform总线,相应的设备叫platform device,而驱动叫做platform driver,platform_device是一种附加手段,例如S3c6410处理器中,把内部集成的I2C,RTC,LCD等控制器都归纳为platform_device.,而他们本身为字符设备。
platform device结构,platform_driver 结构见P243。而匹配驱动和设备的match()函数是通过两者的name字段是否相同的。
而platform_device的定义通常在BSP的板文件中实现的,将platform_device归纳为一个数组,最终通过platform_add_devices()函数统一注册,它其实内部调用了platform_device_register来注册单个平台设备。
对resource的定义也通过BSP的板文件中进行,而在具体的设备驱动中透过platform_get_resource()这样的API来获取
其中如platform_data,如dm9000_plat_data传给struct platform_device ldd6410_dm9000中的dev的platform_data
引入platform总线概念,首先可以使得设备挂接在一个总线上,配套的sysfs节点和设备电源管理都成为可能;隔离了BSP和驱动,在BSP中,定义了platform设备和设备使用的资源,设备的具体配置信息,而在驱动中,只需要获取资源和数据就可以了,做到板相关代码和驱动代码相分离。28 struct dm9000_plat_data { 29 unsigned int flags; 30 unsigned char dev_addr[6]; 31 32 /* allow replacement IO routines */ 33 34 void (*inblk)(void __iomem *reg, void *data, int len); 35 void (*outblk)(void __iomem *reg, void *data, int len); 36 void (*dumpblk)(void __iomem *reg, int len); 37 };
设备驱动的分层思想:
设备核心层实现该设备通用的一些功能,如果具体的设备不想用核心层的函数,它可以重载。它的好处是,具体的底层驱动不需要再实现,而仅仅只需要关心其底层的操作,见P249,图12.1。
输入设备驱动:input_dev 分配释放一个输入设备:input_allocate_device(),input_free_device() 分配一个结构体
input_register_device()注册一个输入设备 input_unregister_device()注销输入设备
报告输入事件用的接口:报告指定的type,code输入事件 input_event() input_report_key()报告键值 input_report_rel()报告相对坐标。
input_report_abs()报告绝对坐标 input_sync()报告同步事件
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{switch (type)
{ case EV_KEY:
__set_bit(code, dev->keybit);
break;
case EV_REL:
__set_bit(code, dev->relbit);
break;
case EV_ABS:
__set_bit(code, dev->absbit);
break;
case EV_MSC:
__set_bit(code, dev->mscbit);
break;
case EV_SW:
__set_bit(code, dev->swbit);
break;
case EV_LED:
__set_bit(code, dev->ledbit);
break;
case EV_SND:
__set_bit(code, dev->sndbit);
break;
case EV_FF:
__set_bit(code, dev->ffbit);
break;
case EV_PWR:
/* do nothing */
break;
default:
pr_err("input_set_capability: unknown type %u (code %u)\n",
type, code);
dump_stack();
return;
}__set_bit(type, dev->evbit);
}
struct input_dev { 1213 const char *name; 1214 const char *phys; 1215 const char *uniq; 1216 struct input_id id; 1217 1218 unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; 1219 1220 unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; 1221 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; 1222 unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; 1223 unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; 1224 unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; 1225 unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; 1226 unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; 1227 unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; 1228 unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; 1229 1230 unsigned int hint_events_per_packet; 1231 1232 unsigned int keycodemax; 1233 unsigned int keycodesize; 1234 void *keycode; 1235 1236 int (*setkeycode)(struct input_dev *dev, 1237 unsigned int scancode, unsigned int keycode); 1238 int (*getkeycode)(struct input_dev *dev, 1239 unsigned int scancode, unsigned int *keycode); 1240 int (*setkeycode_new)(struct input_dev *dev, 1241 const struct input_keymap_entry *ke, 1242 unsigned int *old_keycode); 1243 int (*getkeycode_new)(struct input_dev *dev, 1244 struct input_keymap_entry *ke); 1245 1246 struct ff_device *ff; 1247 1248 unsigned int repeat_key; 1249 struct timer_list timer; 1250 1251 int rep[REP_CNT]; 1252 1253 struct input_mt_slot *mt; 1254 int mtsize; 1255 int slot; 1256 int trkid; 1257 1258 struct input_absinfo *absinfo; 1259 1260 unsigned long key[BITS_TO_LONGS(KEY_CNT)]; 1261 unsigned long led[BITS_TO_LONGS(LED_CNT)]; 1262 unsigned long snd[BITS_TO_LONGS(SND_CNT)]; 1263 unsigned long sw[BITS_TO_LONGS(SW_CNT)]; 1264 1265 int (*open)(struct input_dev *dev); 1266 void (*close)(struct input_dev *dev); 1267 int (*flush)(struct input_dev *dev, struct file *file); 1268 int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); 1269 1270 struct input_handle __rcu *grab; 1271 1272 spinlock_t event_lock; 1273 struct mutex mutex; 1274 1275 unsigned int users; 1276 bool going_away; 1277 1278 bool sync; 1279 1280 struct device dev; 1281 1282 struct list_head h_list; 1283 struct list_head node; 1284};
4 struct gpio_keys_button { 5 /* Configuration parameters */ 6 int code; /* input event code (KEY_*, SW_*) */ 7 int gpio; 8 int active_low; 9 char *desc; 10 int type; /* input event type (EV_KEY, EV_SW) */ 11 int wakeup; /* configure the button as a wake-up source */ 12 int debounce_interval; /* debounce ticks interval in msecs */ 13 bool can_disable; 14 }; 15 16 struct gpio_keys_platform_data { 17 struct gpio_keys_button *buttons; 18 int nbuttons; 19 unsigned int poll_interval; /* polling interval in msecs - 20 for polling driver only */ 21 unsigned int rep:1; /* enable input subsystem auto repeat */ 22 int (*enable)(struct device *dev); 23 void (*disable)(struct device *dev); 24};
29 struct gpio_button_data { 30 struct gpio_keys_button *button; 31 struct input_dev *input; 32 struct timer_list timer; 33 struct work_struct work; 34 bool disabled; 35 }; 36 37 struct gpio_keys_drvdata { 38 struct input_dev *input; 39 struct mutex disable_lock; 40 unsigned int n_buttons; 41 struct gpio_button_data data[0]; 42 };
主机驱动和外设驱动分离
如果不分离的话,针对不同的主机或者同一个主机上面的不同设备都需要相应的设备驱动。这样的话,3个主机3个不同驱动只要6个驱动(3个主机控制器驱动,3个外设驱动),否则要9个,
如Linux的SPI驱动分为SPI主控制器驱动和设备驱动,主控制器驱动,主要成员是主控制器序号,片选数量,SPI模式,时钟设置用到的函数,数据传输用到的函数。
见P259页,可以知道spi_master的分配注销和注册函数,比如struct spi_master * spi_alloc_master(struct device * host,unsigned size)等等
spi_driver结构体描述了一个spi外设驱动,可以认为是spi_master的client驱动。
struct spi_transfer{
}当透过spi总线进行数据传输的时候,它用于描述spi传输。见P258
但是最后,因为一次完整的SPI传输流程可能不止包含一次spi_transfer,它也是要通过spi_message组织在一起的。
P259介绍了spi_message()的初始化,添加spi_transfer()到spi_message队列的方法,还有spi同步异步操作函数。最后是利用spi_transfer()和spi_message()进行spi_write()和spi_read()两个API。同时spi_driver和platform_driver一样,存在着一个spi_device,而spi_device的板信息用spi_board_info()结构体描述。
设备驱动电源管理
CONFIG_PM,suspend()里面会停止设备,关闭给它提供的时钟。而resume()是一个相反的过程。
在BSP中为SoC各个PLL,分频器和时钟gate建立了一棵树,并提供了一组操作时钟的通用API。如clk_get(),clk_put() clk_enable() clk_disbale() clk_get_rate() clk_round_rate() clk_set_rate() clk_set_parent() clk_get_parent()设置获取父设备,等P262 还有一些关于suspend_late()工作与中断都被禁止的情况下。
misc混杂设备
共享一个主设备号MISC_MAJOR(10),不同的次设备号,miscdevice结构体表征miscdevice设备,它本质属于字符设备,因此其驱动的主体工作还是属于file_operation的成员函数。混杂设备的注册注销为misc_register() misc_deregister()两个函数完成。
基于sysfs的设备驱动
在P263
Linux设备驱动的固件加载
申请固件,释放请求——P265 request_firmware()三个参数分别为保存申请到的固件,固件名,申请的固件设备结构体。release_firmware()。