本文主要关注bsp中,关于smbus(系统管理总线,是i2c的子集)的配置过程,了解如如何配置i2c寄存器。
所有发送的数据都会写在FIFO中,使能之后就发送出去。接收数据就从接收寄存器中读取。
读取和发送的数据都保存在iproc_xact_info结构体中。
结合smbus数据帧的格式,分析下面代码。 struct iproc_xact_info {
     bool cmd_valid; /* true if command field below is valid. Otherwise, false */
     unsigned short command; /* Passed by caller to send SMBus command code */
     unsigned char *data; /* actual data pased by the caller */
     unsigned int size; /* Size of data buffer passed */
     unsigned short flags; /* Sent by caller specifying PEC, 10-bit addresses */
     unsigned char smb_proto; /* SMBus protocol to use to perform transaction */
};
static struct i2c_algorithm iproc_smb_algorithm = {
/* .name = "iproc-smb", */
.smbus_xfer = iproc_smb_xfer,
.master_xfer = NULL,
.functionality = iproc_smb_funcs,
}; static int iproc_smb_xfer(struct i2c_adapter *i2c_adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data)
{
int rc;
struct iproc_smb_drv_int_data *dev = i2c_get_adapdata(i2c_adap);
struct iproc_xact_info info;
unsigned int num_bytes_read = ; #ifdef IPROC_SMB_DBG
printk(KERN_DEBUG "\n%s: dev=0x%08X\n", __func__, (unsigned int)dev);
#endif down(&dev->xfer_lock); addr <<= ;
//smbus发送的数据有多种形式,有些是写1字节,有些是多字节
//switch中根据不同操作,将信息保存到info结构体中
switch (size /* protocol */) {
//一字节,有些不需要command
case I2C_SMBUS_BYTE:
info.cmd_valid = false;
info.command = command; /* not used */
if (read_write == I2C_SMBUS_WRITE) { //写操作 info.data = &command; }
else { info.data = &data->byte; }
info.size = ;
info.flags = flags;
//读操作
if (read_write == I2C_SMBUS_READ) { addr |= 0x1; /* Read operation */ info.smb_proto = SMBUS_PROT_RECV_BYTE;
info.data = &data->byte; }
else { info.smb_proto = SMBUS_PROT_SEND_BYTE; }
break;
     //发送字节和数据
case I2C_SMBUS_BYTE_DATA:
info.cmd_valid = true;
info.command = command;
info.data = &data->byte;
info.size = ;
info.flags = flags; if (read_write == I2C_SMBUS_READ) { info.smb_proto = SMBUS_PROT_RD_BYTE; }
else { info.smb_proto = SMBUS_PROT_WR_BYTE;
//info.smb_proto = SMBUS_PROT_WR_WORD; /* TEMP chg. remove later */ }
break;
     //发送字,也就是2字节
case I2C_SMBUS_WORD_DATA:
info.cmd_valid = true;
info.command = command;
info.data = (unsigned char *)(&data->word);
info.size = ;
info.flags = flags;
if (read_write == I2C_SMBUS_READ) {
info.smb_proto = SMBUS_PROT_RD_WORD;
}
else {
info.smb_proto = SMBUS_PROT_WR_WORD;
} break;
    //块数据操作
case I2C_SMBUS_BLOCK_DATA:
info.cmd_valid = true;
info.command = command;
info.data = &data->block[];
info.flags = flags; if (read_write == I2C_SMBUS_READ) { info.smb_proto = SMBUS_PROT_BLK_RD; /* Protocol(hw) returns data byte count as part of response */
info.size = ; }
else { info.smb_proto = SMBUS_PROT_BLK_WR; info.size = data->block[]; /* i2c-core passes the length in
this field */ } break; case I2C_SMBUS_BLOCK_PROC_CALL:
info.cmd_valid = true;
info.command = command;
info.data = &data->block[];
info.flags = flags;
info.smb_proto = SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL;
break; default:
printk(KERN_ERR "%s: Unsupported transaction %d\n", __func__, size);
up(&dev->xfer_lock);
return -EINVAL; } //接收操作
if (read_write == I2C_SMBUS_READ) {
/* Refer to i2c_smbus_read_byte for params passed. */
rc = iproc_smb_data_recv(i2c_adap, addr, &info, &num_bytes_read);      //------------------------>>> 1 /* if failed due to bus hang, but recovered, retry once */
if (rc == -ECOMM) {
rc = iproc_smb_data_recv(i2c_adap, addr, &info, &num_bytes_read);
} /* For block read call, we pass the actual amount of data sent by
* slave, as expected by std Linux API
*/
if ((info.smb_proto == SMBUS_PROT_BLK_RD) ||
(info.smb_proto == SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL)) { if (rc == ) { data->block[] = num_bytes_read; #ifdef IPROC_SMB_DBG
printk(KERN_ERR "%s: num bytes read=%u\n",
__func__, data->block[]);
#endif }
} }  //接收
else { /* Refer to i2c_smbus_write_byte params passed. */
rc = iproc_smb_data_send(i2c_adap, addr, &info);        // ---------------------->>> 2 /* if failed due to bus hang, but recovered, retry */
if (rc == -ECOMM) {
rc = iproc_smb_data_send(i2c_adap, addr, &info);
} } if (rc < ) { printk(KERN_INFO "%s %s: %s error accessing device 0x%X rc=%d", __func__, dev->adapter.name,
(read_write == I2C_SMBUS_READ) ? "Read" : "Write", addr, rc); up(&dev->xfer_lock); return -EREMOTEIO; } up(&dev->xfer_lock); return (rc);
} static int iproc_smb_data_send(struct i2c_adapter *adapter,      // <<<----------------------- 2
unsigned short addr,
struct iproc_xact_info *info)
{
int rc;
unsigned int regval;
struct iproc_smb_drv_int_data *dev = i2c_get_adapdata(adapter);
unsigned long time_left; //检查总线是否空闲
/* Make sure the previous transaction completed */
rc = iproc_smb_startbusy_wait(dev);                // --------------------------->>> 3 if (rc < ) { #ifdef IPROC_SMB_DBG
printk(KERN_ERR "%s: Send: %s bus is busy, attempt recovery \n",
__func__, dev->adapter.name);
#endif
//恢复总线
/* attempt to recover the bus */
if (iproc_smb_startbusy_recovery(dev) != ) { return rc; }
} if (dev->enable_evts == ENABLE_INTR) { /* Enable start_busy interrupt */
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_EVTEN_REG); regval |= CCB_SMB_MSTRSTARTBUSYEN_MASK; iproc_smb_reg_write((unsigned long)dev->block_base_addr +
CCB_SMB_EVTEN_REG, regval); /* Mark as incomplete before sending the data */
INIT_COMPLETION(dev->ses_done); }
//把所有的数据都写道FIFO中
/* Write transaction bytes to Tx FIFO */
iproc_smb_write_trans_data((unsigned long)dev->block_base_addr, addr, info);      // ----------------->>> 4
//是能寄存器,初始化写操作
/* Program master command register (0x30) with protocol type and set
* start_busy_command bit to initiate the write transaction
*/
regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) |
CCB_SMB_MSTRSTARTBUSYCMD_MASK; iproc_smb_reg_write((unsigned long)dev->block_base_addr +
CCB_SMB_MSTRCMD_REG, regval); if (dev->enable_evts == ENABLE_INTR) { /*
* Block waiting for the transaction to finish. When it's finished,
* we'll be signaled by an interrupt
*/
time_left = wait_for_completion_timeout(&dev->ses_done, XACT_TIMEOUT); /* Disable start_busy interrupt */
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_EVTEN_REG); regval &= ~CCB_SMB_MSTRSTARTBUSYEN_MASK; iproc_smb_reg_write((unsigned long)dev->block_base_addr +
CCB_SMB_EVTEN_REG, regval); if (time_left == ) { printk (KERN_INFO "%s: Send: %s timeout accessing device x%02x\n",
__func__, dev->adapter.name, addr); /* attempt to recover the bus */
rc = iproc_smb_timeout_recovery(dev);
if ( rc != ) { return -ETIMEDOUT; }
else {
return -ECOMM;
} } }
//读取寄存器,检查发送完之后的寄存器标志位,判断是否发送成功
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_MSTRCMD_REG); /* If start_busy bit cleared, check if there are any errors */
if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { /* start_busy bit cleared, check master_status field now */
regval &= CCB_SMB_MSTRSTS_MASK;
regval >>= CCB_SMB_MSTRSTS_SHIFT;
//检查是否发送成功
if (regval != MSTR_STS_XACT_SUCCESS) { /* We can flush Tx FIFO here */ printk(KERN_INFO "\n\n%s:Send: %s Error in transaction %d to device x%02x, exiting\n",
__func__, dev->adapter.name, regval, addr); return -EREMOTEIO; }
} return();
} static int iproc_smb_startbusy_wait(struct iproc_smb_drv_int_data *dev)    // <<<----------------------- 3
{
unsigned int regval; regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_MSTRCMD_REG); /* Check if an operation is in progress. During probe it won't be.
* But when shutdown/remove was called we want to make sure that
* the transaction in progress completed
*/
//检查总线是否空闲,如果非零表示busy,那么就等待
if (regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) {
unsigned int i = ; do { msleep(); /* Wait for 1 msec */ i++;
//再次读取,判断是否空闲
regval = iproc_smb_reg_read(
(unsigned long)dev->block_base_addr + CCB_SMB_MSTRCMD_REG); /* If start-busy bit cleared, exit the loop */
} while ((regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK) &&
(i < IPROC_SMB_MAX_RETRIES)); if (i >= IPROC_SMB_MAX_RETRIES) {
#ifdef IPROC_SMB_DBG
printk(KERN_ERR "%s: %s START_BUSY bit didn't clear, exiting\n",
__func__, dev->adapter.name);
#endif
return -ETIMEDOUT; } } return ;
} static int iproc_smb_data_recv(struct i2c_adapter *adapter,        // <<<----------------------- 1
unsigned short addr,
struct iproc_xact_info *info,
unsigned int *num_bytes_read)
{
int rc;
unsigned int regval;
struct iproc_smb_drv_int_data *dev = i2c_get_adapdata(adapter);
unsigned long time_left;
//等待总线空闲
/* Make sure the previous transaction completed */
rc = iproc_smb_startbusy_wait(dev); if (rc < ) {
#ifdef IPROC_SMB_DBG
printk(KERN_ERR "%s: Receive: %s bus is busy, attempt recovery \n", __func__, dev->adapter.name);
#endif
/* attempt to recover the bus */
if (iproc_smb_startbusy_recovery(dev) != ) {
return rc;
}
} if (dev->enable_evts == ENABLE_INTR) {
//启用开始信号终端
/* Enable start_busy interrupt */
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_EVTEN_REG);
//设置标志位为1,通知接收事件
/* Set Rx_event_en bit for notification of reception event */
regval |= (CCB_SMB_MSTRSTARTBUSYEN_MASK); iproc_smb_reg_write((unsigned long)dev->block_base_addr +
CCB_SMB_EVTEN_REG, regval); /* Mark as incomplete before sending the data */
INIT_COMPLETION(dev->ses_done); }
//把所有的数据防盗FIFO中发送
/* Program all transaction bytes into master Tx FIFO */
iproc_smb_write_trans_data((unsigned long)dev->block_base_addr, addr, info);          //----------------------->>> 4
//初始化发送操作,设置发送的数据大小,激活发送操作,发送数据,设置其中的字节数
/* Program master command register (0x30) with protocol type and set
* start_busy_command bit to initiate the write transaction
*/
regval = (info->smb_proto << CCB_SMB_MSTRSMBUSPROTO_SHIFT) |
CCB_SMB_MSTRSTARTBUSYCMD_MASK | info->size; iproc_smb_reg_write((unsigned long)dev->block_base_addr +
CCB_SMB_MSTRCMD_REG, regval); if (dev->enable_evts == ENABLE_INTR) { /*
* Block waiting for the transaction to finish. When it's finished,
* we'll be signaled by an interrupt
*/
time_left = wait_for_completion_timeout(&dev->ses_done, XACT_TIMEOUT); /* Disable start_busy and rx_event interrupts. Above call has handled
* the interrupt
*/
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_EVTEN_REG); regval &= ~(CCB_SMB_MSTRSTARTBUSYEN_MASK); iproc_smb_reg_write((unsigned long)dev->block_base_addr +
CCB_SMB_EVTEN_REG, regval); if (time_left == ) { printk (KERN_INFO "\n%s: Receive: %s timeout accessing device 0x%02x\n",
__func__, dev->adapter.name, addr); /* attempt to recover the bus */
rc = iproc_smb_timeout_recovery(dev);          // ------------------------------>>> 5
if ( rc != ) {
return -ETIMEDOUT;
}
else {
return -ECOMM;
}
} }
//读取状态位
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_MSTRCMD_REG);
//start_busy位清0的时候,检查是否有错
/* If start_busy bit cleared, check if there are any errors */
if (!(regval & CCB_SMB_MSTRSTARTBUSYCMD_MASK)) { /* start_busy bit cleared, check master_status field now */
regval &= CCB_SMB_MSTRSTS_MASK;
regval >>= CCB_SMB_MSTRSTS_SHIFT;
//检查发送是否成功
if (regval != MSTR_STS_XACT_SUCCESS) { /* We can flush Tx FIFO here */
printk(KERN_INFO "\n%s: %s Error in transaction %d to device x%02x, exiting\n",
__func__, dev->adapter.name, regval, addr); return -EREMOTEIO; } } /* In the isr we will read the received byte, and also deal with
* rx fifo full event. The above check is for timeout error. If needed
* we may move it to rx isr
*/
//开始接受数据,接受第一字节
/* Read received byte(s) */
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_MSTRDATARD_REG);
//如果是读取块数据
/* For block read, protocol (hw) returns byte count, as the first byte */
if ((info->smb_proto == SMBUS_PROT_BLK_RD) ||
(info->smb_proto == SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL)) { int i;
//根据协议定义,再发送了读取信号之后,接收的第一个字节是接受数据的大小
*num_bytes_read = regval & CCB_SMB_MSTRRDDATA_MASK; /* Limit to reading a max of 32 bytes only; just a safeguard. If
* # bytes read is a number > 32, check transaction set up, and contact
* hw engg. Assumption: PEC is disabled
*/
for (i = ; (i < *num_bytes_read) && (i < I2C_SMBUS_BLOCK_MAX); i++) { /* Read Rx FIFO for data bytes */
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_MSTRDATARD_REG); info->data[i] = regval & CCB_SMB_MSTRRDDATA_MASK; } }
else { *info->data = regval & CCB_SMB_MSTRRDDATA_MASK; *num_bytes_read = ; if (info->smb_proto == SMBUS_PROT_RD_WORD) {
/* Read Rx FIFO for data bytes */
regval = iproc_smb_reg_read((unsigned long)dev->block_base_addr +
CCB_SMB_MSTRDATARD_REG); info->data[] = regval & CCB_SMB_MSTRRDDATA_MASK; *num_bytes_read = ;
}
} return();
} static void iproc_smb_write_trans_data(unsigned long base_addr,       // <<<----------------------- 4
unsigned short dev_addr,
struct iproc_xact_info *info)
{
unsigned int regval;
unsigned int i;
unsigned int num_data_bytes = ; #ifdef IPROC_SMB_DBG
printk(KERN_DEBUG "\n%s: dev_addr=0x%X, offset=%u, cmd_valid=%u, size=%u\n", __func__, dev_addr, info->command, info->cmd_valid, info->size);
#endif /* IPROC_SMB_DBG */ /* Write SMBus device address first */
/* Note, we are assuming 7-bit addresses for now. For 10-bit addresses,
* we may have one more write to send the upper 3 bits of 10-bit addr
*/
//将地址写入到主机数据写寄存器中,发送出去
iproc_smb_reg_write(base_addr + CCB_SMB_MSTRDATAWR_REG, dev_addr);
//发送command
/* If the protocol needs command code, copy it */
if (info->cmd_valid == true) { iproc_smb_reg_write(base_addr + CCB_SMB_MSTRDATAWR_REG, info->command); } /* Depending on the SMBus protocol, we need to write additional transaction
* data in to Tx FIFO. Refer to section 5.5 of SMBus spec for sequence for a
* transaction
*/
//寄存器偏移0x30, 判断要发送数据的大小
//判断操作的类型,添加额外的数据给到FIFO中
switch (info->smb_proto) {
//接受字节
case SMBUS_PROT_RECV_BYTE:
/* No additional data to be written */
num_data_bytes = ;
break;
//发送字节
case SMBUS_PROT_SEND_BYTE:
num_data_bytes = info->size;
break; case SMBUS_PROT_RD_BYTE:
case SMBUS_PROT_RD_WORD:
case SMBUS_PROT_BLK_RD:
/* Write slave address with R/W~ set (bit #0) */
//块数据,多个字节的读写
//根据协议格式,读操作需要再次发送开始信号
iproc_smb_reg_write(base_addr + CCB_SMB_MSTRDATAWR_REG,
dev_addr | 0x1);
num_data_bytes = ;
break; case SMBUS_PROT_WR_BYTE:
case SMBUS_PROT_WR_WORD:
/* No additional bytes to be written. Data portion is written in the
* 'for' loop below
*/
num_data_bytes = info->size; /* Note for hx4 eeprom (at24c64). the low addr bytes can be passed
* in to 1st byte of info->data
*/
break; case SMBUS_PROT_BLK_WR:
/* 3rd byte is byte count */
//块数据写,需要发送要些的字节个数
iproc_smb_reg_write(base_addr + CCB_SMB_MSTRDATAWR_REG, info->size);
num_data_bytes = info->size;
break; case SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL:
/* Write byte count */
//块数据读写调用,需要发送字节的个数
iproc_smb_reg_write(base_addr + CCB_SMB_MSTRDATAWR_REG, info->size);
num_data_bytes = info->size;
break; default:
break; }
//发送实际的数据
/* Copy actual data from caller, next. In general, for reads, no data is
* copied
*/
for (i = ; num_data_bytes; --num_data_bytes, i++) { /* For the last byte, set MASTER_WR_STATUS bit. For block rd/wr process
* call, we need to program slave addr after copying data byte(s), so
* master status bit is set later, after the loop
*/
//最后一个字节,需要设置master写状态为1
if ((num_data_bytes == ) &&
(info->smb_proto != SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL)) {
regval = info->data[i] | CCB_SMB_MSTRWRSTS_MASK;
}
else {
regval = info->data[i];
}
//发送数据
iproc_smb_reg_write(base_addr + CCB_SMB_MSTRDATAWR_REG, regval); }
//如果是读写调用操作,数据写完之后,还要再次读回来,
//所以下面这条命令就是再次发送开始信号,并指定为读操作
if (info->smb_proto == SMBUS_PROT_BLK_WR_BLK_RD_PROC_CALL) {
/* Write device address needed during repeat start condition */
//重复的开始信号,还有地址,有些操作需要这样
iproc_smb_reg_write(base_addr + CCB_SMB_MSTRDATAWR_REG,
CCB_SMB_MSTRWRSTS_MASK | dev_addr | 0x1);
} return;
} static int iproc_smb_startbusy_recovery(struct iproc_smb_drv_int_data *dev)      // <<<------------- 5
{
int rc = -;
unsigned int recoveryCnt; if (dev->adapter.nr == ) {
recoveryCnt = ++smbus0_startBusyCnt;
}
else {
recoveryCnt = ++smbus1_startBusyCnt;
} printk(KERN_INFO "%s: %s START_BUSY recovery #%d \n", __func__, dev->adapter.name, recoveryCnt);
//复位i2c总线到默认值
/* reset the SMBus block, wait a minimum of 50 uSecs and then re-initialize */
iproc_smb_reg_write((unsigned long)dev->block_base_addr + CCB_SMB_CFG_REG, CCB_SMB_CFG_RST_MASK);
udelay();
//从新初始化
if ( iproc_smbus_block_init(dev) == ) {
rc = ;
} return rc;
}

bcm56150_i2c驱动分析的更多相关文章

  1. [tty与uart]3.tty驱动分析

    转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...

  2. linux的串口驱动分析

    1.串口驱动中的数据结构 • UART驱动程序结构:struct uart_driver  驱动 • UART端口结构: struct uart_port  串口 • UART相关操作函数结构: st ...

  3. linux内核SPI总线驱动分析(一)(转)

    linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...

  4. Mini2440 DM9000 驱动分析(一)

    Mini2440 DM9000 驱动分析(一) 硬件特性 Mini2440开发板上DM9000的电气连接和Mach-mini2440.c文件的关系: PW_RST 连接到复位按键,复位按键按下,低电平 ...

  5. mini2440触摸屏驱动分析

    mini2440驱动分析系列之 ---------------------------------------Mini2440触摸屏程序分析 By JeefJiang July,8th,2009 这是 ...

  6. RM-Linux驱动--Watch Dog Timer(看门狗)驱动分析

    from:http://blog.csdn.net/geekcome/article/details/6595265 硬件平台:FL2440 内核版本:2.6.28 主机平台:Ubuntu 11,04 ...

  7. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  8. 【转】android电池(五):电池 充电IC(PM2301)驱动分析篇

    关键词:android 电池  电量计  PL2301任务初始化宏 power_supply 中断线程化 平台信息:内核:linux2.6/linux3.0系统:android/android4.0  ...

  9. 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇

    关键词:android 电池  电量计  MAX17040 任务初始化宏 power_supply 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台: ...

随机推荐

  1. php 设置自动加载某个页面

    首先要找到Php.ini文件. 新建一个php文件,使用phpinfo(); 之后找到 Loaded Configuration File 指定的路径就是php.ini文件 打开文件,找到 auto_ ...

  2. vmware esxi 过期,激活

    首先我们打开vSphere Client,登录esxi主机 他会提示你,说你的esxi主机的评估期还剩多长时间 我们现在去激活,我们下载esxi的注册机 然后点击配置--->已获许可的功能--- ...

  3. Spring里的aop实现方式和源码分析

    使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点.业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点.横切关注点的一个特点是,他们经常发生在核心关 ...

  4. android stuido - 关闭单词拼写检查

    "File"-"Settings"-"Editor "-"Inspections" 在Spelling栏取消选中,再点击 ...

  5. 委托事件和jquery中的delegate方法

    利用事件冒泡的特性,给父元素绑定事件,然后判断事件对象,来给父元素的每个子元素添加事件,而不是直接在所有的子元素上绑定事件: <ul> <li></li> < ...

  6. 每日英语:How to Be a Better Conversationalist

    Jason Swett still cringes when he remembers the party in Atlanta 10 years ago, where, drink in hand, ...

  7. 解决NSImage绘制的时候图像模糊

    Mac下NSImage绘制模糊的原因之一是draw到了非整数像素上,框架在渲染的时候就会模糊. 针对这一原因写了以下工具: /** * @brief 一劳永逸的解决NSImage绘制的时候绘到浮点值像 ...

  8. Spring Boot干货系列:(一)优雅的入门篇

    Spring Boot干货系列:(一)优雅的入门篇 2017-02-26 嘟嘟MD 嘟爷java超神学堂   前言 Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社 ...

  9. ELK的索引的坑——Kibana的图形化(Tile Map)

    如果想通过ELK展示地图, 需要将索引名称修改为:logstash*的格式 否则location字段不会修改成geo_point的形式. 详情参考:http://blog.csdn.net/yangg ...

  10. my.cnf 配置详解

    调整MySQL运行参数,修改/etc/my.cnf文件调整mysql运行参数重启MySQL后生效,在MySQL4版本以后,一部分内部变量可以在MySQL运行时设置,不过重启MySQL就失效了. mys ...