sysfs是虚拟的文件系统,向用户空间导出内核的数据结构、数据结构的属性,以及它们直接的关系,并向用户空间提供接口。
手头上的一个项目需要用一个ID标识每一个usb设备,而且需要随时读取和修改它的ID。之前的方案是每次需要读取ID时使用libus库从usb芯片ft232的eeprom里读出来,当cpu负载重时,读取一批usb设备ID显得很吃力很慢。如果修改驱动,导出id到sysfs文件系统,那么该值由内核控制访问,每次读取都是读取sysfs的一个文件,写ID也只需输出到该文件即可。防止大量重复的操作,用户空间使用方便。好处是高效高速又方便。缺点是需要修改驱动。
简单来说就是:定义一个设备属性和show,store的操作(只读属性不需要store)。在探测设备时在sysfs对应目录创建设备属性文件,断开时删除文件。
下面是在设备的sysfs目录中在设备文件夹下添加新的属性的一个简单的例子:
在include/linux.h/device.h有添加非默认属性的接口
/* driverfs interface for exporting device attributes */
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device * dev, char * buf);
ssize_t (*store)(struct device * dev, const char * buf, size_t count);
};
/* 定义新属性的宏 */
#define DEVICE_ATTR(_name,_mode,_show,_store) \
struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store)
/* 添加/删除 属性 函数*/
extern int device_create_file(struct device *device, struct device_attribute * entry);
extern void device_remove_file(struct device * dev, struct device_attribute * attr);
在驱动文件里,定义新属性
static unsigned char moteid[6] = "-1";
ssize_t show_moteid(struct device * dev, char * buf)
{
strcpy(buf, moteid);
return strlen(buf);
}
ssize_t store_moteid(struct device * dev, const char * buf, size_t count)
{
int id;
if(count > 4)
count = 4;
sscanf(buf, "%d", &id);
printk("buf: %s; write id: %d\n", buf, id);
strncpy(moteid, buf, 4);
//if(id < 1024 && id > 0)
//moteid_write(container_of(dev, struct usb_device, dev), id);
return strlen(moteid);
}
DEVICE_ATTR(moteid,S_IRUGO | S_IWUSR,show_moteid,store_moteid);
//device_create_file(&serial->dev->dev, &dev_attr_moteid); /* 在设备探测函数里加入 */
//device_remove_file(&serial->dev->dev, &dev_attr_moteid); /* 在设备断开函数里加入 */
以下是我的usb探测函数,我在里面加入:
/* Startup for the FT232BM chip */
/* Called from usbserial:serial_probe */
static int ftdi_FT232BM_startup (struct usb_serial *serial)
{ /* ftdi_FT232BM_startup */
struct ftdi_private *priv;
int err;
device_create_file(&serial->dev->dev, &dev_attr_moteid); /* 在sysfs相应目录创建文件!!!*/
moteid_read(serial->dev);
printk("ftdi_FT232BM_startup: \n");
err = ftdi_common_startup(serial);
if (err){
return (err);
}
priv = usb_get_serial_port_data(serial->port[0]);
priv->chip_type = FT232BM;
priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */
printk("%s:[%s]: %s end: \n",__FILE__, __LINE__, __FUNCTION__);
return (0);
} /* ftdi_FT232BM_startup */
下面的是我的断开设备的函数:
/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
* it is called when the usb device is disconnected
*
* usbserial:usb_serial_disconnect
* calls __serial_close for each open of the port
* shutdown is called then (ie ftdi_shutdown)
*/
static void ftdi_shutdown (struct usb_serial *serial)
{ /* ftdi_shutdown */
printk("%s:%s ftdi_shutdown begin: %s\n",__FILE__, __LINE__, __FUNCTION__);
device_remove_file(&serial->dev->dev, &dev_attr_moteid);
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv = usb_get_serial_port_data(port);
/* all open ports are closed at this point
* (by usbserial.c:__serial_close, which calls ftdi_close)
*/
if (priv) {
usb_set_serial_port_data(port, NULL);
kfree(priv);
}
printk("%s:%s ftdi_shutdown end: %s\n",__FILE__, __LINE__, __FUNCTION__);
} /* ftdi_shutdown */
在用户空间的验证, 插入对应的usb设备后:
/sys/devices/platform/ep93xxusb0/usb1/1-3 # ls
1-3:1.0 bNumInterfaces manufacturer
bConfigurationValue bcdDevice maxchild
bDeviceClass bmAttributes moteid(就是添加的自定义属性!!!)
bDeviceProtocol detach_state product
bDeviceSubClass devnum serial
bMaxPower idProduct speed
bNumConfigurations idVendor version
用户可对该文件进行读写,当然啦,我的实现不是简单的在moteid[]里面,而是写入eeprom,第一次读则从eeprom读出来!
1193

被折叠的 条评论
为什么被折叠?



