note: MODULE_DEVICE_TABLE在linux/module.h, 注释为Creates an alias so file2alias.c can find device table.
<<Linux Device Drivers Developme>> - John Madieu Platform Device Drivers > How can platform devices and platform drivers match So far, we have only discussed how to fill different structures of both devices and drivers.But now we will see how they are registered with the kernel, and how Linux knows which devices are handled by which driver. The answer is MODULE_DEVICE_TABLE. This macro lets a driver expose its ID table, which describes which devices it can support. In the meantime, if the driver can be compiled as a module, the driver.name field should match the module name. If it does not match, the module won’t be automatically loaded, unless we have used the MODULE_ALIAS macro to add another name for the module. At compilation time, that information is extracted from all the drivers in order to build a device table. When the kernel has to find the driver for a device (when a matching needs to be performed), the device table is walked through by the kernel. If an entry is found matching the compatible (for device tree), device/vendor id or name (for device ID table or name) of the added device, then the module providing that match is loaded (running the module’s init function), and the probe function is called. The MODULE_DEVICE_TABLE macro is defined in linux/module.h.
structpcf_dev { unsignedchar control; unsignedchar data; // 实际对AD来讲上卵用没有 unsignedchar channel; // 实际上也是卵用没有 structi2c_client *client;// structdevice *device;// use with cdev structmutex *lock;// avoid access i2c conflict structlist_headinstance;// to find this shit to free. structcdevcdev;// use for delete this shit before free. };
u8 init_series[2]; structi2c_msgmsg; /* get data from device tree */ of_property_read_u8(client->dev.of_node, "mode", &init_series[0]); init_series[0] |= of_property_read_bool(client->dev.of_node, "enable_da") << 6; of_property_read_u8(client->dev.of_node, "da_value", &init_series[1]); control = init_series[0]; /* send control byte */ msg.addr = client->addr; msg.flags = 0; /* Write */ msg.len = 2; /* control bytes + dac byte */ msg.buf = init_series; if(i2c_transfer(client->adapter, &msg, 1) < 0) pr_err("pcf8591: i2c_transfer failed\n"); // hush hush, god knows you guys have used what to result a transfer failure.
创建设备
1 2 3 4 5 6 7 8 9 10 11 12 13
/* GLOBAL VARS START */ staticunsignedint pcf_major = 0; staticunsignedint minor = 0; /* GLOBAL VARS END */
dev_t devno = 0; int err = 0; err = alloc_chrdev_region(&devno, 0, 1, PCF_DEVICE_NAME); // beg kernel to give ONE major number which minor is ZERO and named with PCF_DEVICE_NAME for us. if(err < 0){ pr_err("region alloc failed for %s\n", PCF_DEVICE_NAME); return err; } pcf_major = MAJOR(devno);
在remove里面释放设备
1
unregister_chrdev_region(MKDEV(pcf_major, 0), 1);
创建设备类
1 2 3 4 5 6 7 8 9
/* GLOBAL VARS START */ staticstructclass *pcf_class = NULL; /* GLOBAL VARS END */
dev = filp->private_data; /* why you guys writing to a AD channel? */ if(dev->channel != 0xff)return -ENODEV;
dat = kmalloc(count+1, GFP_KERNEL); /* rip. your device's memory is too SMALL to save ONE byte. or you guys ask the driver to write a LOOOOOOOOOOOOG data. */ if(dat == NULL)return -ENOMEM;
dat[0] = dev->control; /* move the data to kernel space. */ if(copy_from_user(dat+1, buf, count) != 0){ err = -EFAULT; };
if(dev->channel == 0xff){ /* you said you want to read DA and read MANY bytes? NO SENSE! */ if(count != 1)return -ENODEV; else copy_to_user(buf, &dev->data, 1); return1; }
/* prepare to read. */ dat = kmalloc(count, GFP_KERNEL); if(dat == NULL)return -ENOMEM;