sonypi.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:22k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* 
  2.  * Sony Programmable I/O Control Device driver for VAIO
  3.  *
  4.  * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alc魐e
  5.  *
  6.  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  7.  *
  8.  * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
  9.  *
  10.  * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
  11.  *
  12.  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  13.  *
  14.  * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
  15.  *
  16.  * This program is free software; you can redistribute it and/or modify
  17.  * it under the terms of the GNU General Public License as published by
  18.  * the Free Software Foundation; either version 2 of the License, or
  19.  * (at your option) any later version.
  20.  * 
  21.  * This program is distributed in the hope that it will be useful,
  22.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24.  * GNU General Public License for more details.
  25.  * 
  26.  * You should have received a copy of the GNU General Public License
  27.  * along with this program; if not, write to the Free Software
  28.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29.  *
  30.  */
  31. #include <linux/config.h>
  32. #include <linux/module.h>
  33. #include <linux/pci.h>
  34. #include <linux/sched.h>
  35. #include <linux/init.h>
  36. #include <linux/miscdevice.h>
  37. #include <linux/poll.h>
  38. #include <linux/delay.h>
  39. #include <asm/uaccess.h>
  40. #include <asm/io.h>
  41. #include <asm/system.h>
  42. #include "sonypi.h"
  43. #include <linux/sonypi.h>
  44. static struct sonypi_device sonypi_device;
  45. static int minor = -1;
  46. static int verbose; /* = 0 */
  47. static int fnkeyinit; /* = 0 */
  48. static int camera; /* = 0 */
  49. static int compat; /* = 0 */
  50. static int nojogdial; /* = 0 */
  51. /* Inits the queue */
  52. static inline void sonypi_initq(void) {
  53.         sonypi_device.queue.head = sonypi_device.queue.tail = 0;
  54. sonypi_device.queue.len = 0;
  55. sonypi_device.queue.s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
  56. init_waitqueue_head(&sonypi_device.queue.proc_list);
  57. }
  58. /* Pulls an event from the queue */
  59. static inline unsigned char sonypi_pullq(void) {
  60.         unsigned char result;
  61. unsigned long flags;
  62. spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
  63. if (!sonypi_device.queue.len) {
  64. spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
  65. return 0;
  66. }
  67. result = sonypi_device.queue.buf[sonypi_device.queue.head];
  68.         sonypi_device.queue.head++;
  69. sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1);
  70. sonypi_device.queue.len--;
  71. spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
  72.         return result;
  73. }
  74. /* Pushes an event into the queue */
  75. static inline void sonypi_pushq(unsigned char event) {
  76. unsigned long flags;
  77. spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
  78. if (sonypi_device.queue.len == SONYPI_BUF_SIZE) {
  79. /* remove the first element */
  80.          sonypi_device.queue.head++;
  81. sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1);
  82. sonypi_device.queue.len--;
  83. }
  84. sonypi_device.queue.buf[sonypi_device.queue.tail] = event;
  85. sonypi_device.queue.tail++;
  86. sonypi_device.queue.tail &= (SONYPI_BUF_SIZE - 1);
  87. sonypi_device.queue.len++;
  88. kill_fasync(&sonypi_device.queue.fasync, SIGIO, POLL_IN);
  89. wake_up_interruptible(&sonypi_device.queue.proc_list);
  90. spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
  91. }
  92. /* Tests if the queue is empty */
  93. static inline int sonypi_emptyq(void) {
  94.         int result;
  95. unsigned long flags;
  96. spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
  97.         result = (sonypi_device.queue.len == 0);
  98. spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
  99.         return result;
  100. }
  101. static void sonypi_ecrset(u8 addr, u8 value) {
  102. wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
  103. outb_p(0x81, SONYPI_CST_IOPORT);
  104. wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
  105. outb_p(addr, SONYPI_DATA_IOPORT);
  106. wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
  107. outb_p(value, SONYPI_DATA_IOPORT);
  108. wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
  109. }
  110. static u8 sonypi_ecrget(u8 addr) {
  111. wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
  112. outb_p(0x80, SONYPI_CST_IOPORT);
  113. wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
  114. outb_p(addr, SONYPI_DATA_IOPORT);
  115. wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
  116. return inb_p(SONYPI_DATA_IOPORT);
  117. }
  118. static u16 sonypi_ecrget16(u8 addr) {
  119. return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8);
  120. }
  121. /* Initializes the device - this comes from the AML code in the ACPI bios */
  122. static void __devinit sonypi_type1_srs(void) {
  123. u32 v;
  124. pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
  125. v = (v & 0xFFFF0000) | ((u32)sonypi_device.ioport1);
  126. pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
  127. pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
  128. v = (v & 0xFFF0FFFF) | 
  129.     (((u32)sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16);
  130. pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
  131. v = inl(SONYPI_IRQ_PORT);
  132. v &= ~(((u32)0x3) << SONYPI_IRQ_SHIFT);
  133. v |= (((u32)sonypi_device.bits) << SONYPI_IRQ_SHIFT);
  134. outl(v, SONYPI_IRQ_PORT);
  135. pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
  136. v = (v & 0xFF1FFFFF) | 0x00C00000;
  137. pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
  138. }
  139. static void __devinit sonypi_type2_srs(void) {
  140. sonypi_ecrset(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8);
  141. sonypi_ecrset(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF);
  142. sonypi_ecrset(SONYPI_SIRQ,  sonypi_device.bits);
  143. udelay(10);
  144. }
  145. /* Disables the device - this comes from the AML code in the ACPI bios */
  146. static void __devexit sonypi_type1_dis(void) {
  147. u32 v;
  148. pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
  149. v = v & 0xFF3FFFFF;
  150. pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
  151. v = inl(SONYPI_IRQ_PORT);
  152. v |= (0x3 << SONYPI_IRQ_SHIFT);
  153. outl(v, SONYPI_IRQ_PORT);
  154. }
  155. static void __devexit sonypi_type2_dis(void) {
  156. sonypi_ecrset(SONYPI_SHIB, 0);
  157. sonypi_ecrset(SONYPI_SLOB, 0);
  158. sonypi_ecrset(SONYPI_SIRQ, 0);
  159. }
  160. static u8 sonypi_call1(u8 dev) {
  161. u8 v1, v2;
  162. wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
  163. outb(dev, sonypi_device.ioport2);
  164. v1 = inb_p(sonypi_device.ioport2);
  165. v2 = inb_p(sonypi_device.ioport1);
  166. return v2;
  167. }
  168. static u8 sonypi_call2(u8 dev, u8 fn) {
  169. u8 v1;
  170. wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
  171. outb(dev, sonypi_device.ioport2);
  172. wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
  173. outb(fn, sonypi_device.ioport1);
  174. v1 = inb_p(sonypi_device.ioport1);
  175. return v1;
  176. }
  177. static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
  178. u8 v1;
  179. wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
  180. outb(dev, sonypi_device.ioport2);
  181. wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
  182. outb(fn, sonypi_device.ioport1);
  183. wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
  184. outb(v, sonypi_device.ioport1);
  185. v1 = inb_p(sonypi_device.ioport1);
  186. return v1;
  187. }
  188. static u8 sonypi_read(u8 fn) {
  189. u8 v1, v2;
  190. int n = 100;
  191. while (n--) {
  192. v1 = sonypi_call2(0x8f, fn);
  193. v2 = sonypi_call2(0x8f, fn);
  194. if (v1 == v2 && v1 != 0xff)
  195. return v1;
  196. }
  197. return 0xff;
  198. }
  199. /* Set brightness, hue etc */
  200. static void sonypi_set(u8 fn, u8 v) {
  201. wait_on_command(0, sonypi_call3(0x90, fn, v));
  202. }
  203. /* Tests if the camera is ready */
  204. static int sonypi_camera_ready(void) {
  205. u8 v;
  206. v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS);
  207. return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
  208. }
  209. /* Turns the camera off */
  210. static void sonypi_camera_off(void) {
  211. sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK);
  212. if (!sonypi_device.camera_power)
  213. return;
  214. sonypi_call2(0x91, 0); 
  215. sonypi_device.camera_power = 0;
  216. }
  217. /* Turns the camera on */
  218. static void sonypi_camera_on(void) {
  219. int i, j;
  220. if (sonypi_device.camera_power)
  221. return;
  222. for (j = 5; j > 0; j--) {
  223. while (sonypi_call2(0x91, 0x1) != 0) {
  224. set_current_state(TASK_UNINTERRUPTIBLE);
  225. schedule_timeout(1);
  226. }
  227. sonypi_call1(0x93);
  228. for (i = 400; i > 0; i--) {
  229. if (sonypi_camera_ready())
  230. break;
  231. set_current_state(TASK_UNINTERRUPTIBLE);
  232. schedule_timeout(1);
  233. }
  234. if (i != 0)
  235. break;
  236. }
  237. if (j == 0) {
  238. printk(KERN_WARNING "sonypi: failed to power on cameran");
  239. return;
  240. }
  241. sonypi_set(0x10, 0x5a);
  242. sonypi_device.camera_power = 1;
  243. }
  244. /* sets the bluetooth subsystem power state */
  245. static void sonypi_setbluetoothpower(u8 state) {
  246. state = (state != 0);
  247. if (sonypi_device.bluetooth_power && state) 
  248. return;
  249. if (!sonypi_device.bluetooth_power && !state) 
  250. return;
  251. sonypi_call2(0x96, state);
  252. sonypi_call1(0x93);
  253. sonypi_device.bluetooth_power = state;
  254. }
  255. /* Interrupt handler: some event is available */
  256. void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
  257. u8 v1, v2, event = 0;
  258. int i;
  259. u8 sonypi_jogger_ev, sonypi_fnkey_ev;
  260. u8 sonypi_capture_ev, sonypi_bluetooth_ev;
  261. u8 sonypi_pkey_ev;
  262. if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
  263. sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV;
  264. sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV;
  265. sonypi_capture_ev = SONYPI_TYPE2_CAPTURE_EV;
  266. sonypi_bluetooth_ev = SONYPI_TYPE2_BLUETOOTH_EV;
  267. sonypi_pkey_ev = nojogdial ? SONYPI_TYPE2_PKEY_EV 
  268.    : SONYPI_TYPE1_PKEY_EV;
  269. }
  270. else {
  271. sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV;
  272. sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV;
  273. sonypi_capture_ev = SONYPI_TYPE1_CAPTURE_EV;
  274. sonypi_bluetooth_ev = SONYPI_TYPE1_BLUETOOTH_EV;
  275. sonypi_pkey_ev = SONYPI_TYPE1_PKEY_EV;
  276. }
  277. v1 = inb_p(sonypi_device.ioport1);
  278. v2 = inb_p(sonypi_device.ioport2);
  279. if ((v2 & sonypi_pkey_ev) == sonypi_pkey_ev) {
  280. for (i = 0; sonypi_pkeyev[i].event; i++)
  281. if (sonypi_pkeyev[i].data == v1) {
  282. event = sonypi_pkeyev[i].event;
  283. goto found;
  284. }
  285. }
  286. if ((v2 & sonypi_jogger_ev) == sonypi_jogger_ev) {
  287. for (i = 0; sonypi_joggerev[i].event; i++)
  288. if (sonypi_joggerev[i].data == v1) {
  289. event = sonypi_joggerev[i].event;
  290. goto found;
  291. }
  292. }
  293. if ((v2 & sonypi_capture_ev) == sonypi_capture_ev) {
  294. for (i = 0; sonypi_captureev[i].event; i++)
  295. if (sonypi_captureev[i].data == v1) {
  296. event = sonypi_captureev[i].event;
  297. goto found;
  298. }
  299. }
  300. if ((v2 & sonypi_fnkey_ev) == sonypi_fnkey_ev) {
  301. for (i = 0; sonypi_fnkeyev[i].event; i++)
  302. if (sonypi_fnkeyev[i].data == v1) {
  303. event = sonypi_fnkeyev[i].event;
  304. goto found;
  305. }
  306. }
  307. if ((v2 & sonypi_bluetooth_ev) == sonypi_bluetooth_ev) {
  308. for (i = 0; sonypi_blueev[i].event; i++)
  309. if (sonypi_blueev[i].data == v1) {
  310. event = sonypi_blueev[i].event;
  311. goto found;
  312. }
  313. }
  314. if ((v2 & SONYPI_BACK_EV) == SONYPI_BACK_EV) {
  315. for (i = 0; sonypi_backev[i].event; i++)
  316. if (sonypi_backev[i].data == v1) {
  317. event = sonypi_backev[i].event;
  318. goto found;
  319. }
  320. }
  321. if ((v2 & SONYPI_LID_EV) == SONYPI_LID_EV) {
  322. for (i = 0; sonypi_lidev[i].event; i++)
  323. if (sonypi_lidev[i].data == v1) {
  324. event = sonypi_lidev[i].event;
  325. goto found;
  326. }
  327. }
  328. if (verbose)
  329. printk(KERN_WARNING 
  330.        "sonypi: unknown event port1=0x%02x,port2=0x%02xn",v1,v2);
  331. return;
  332. found:
  333. sonypi_pushq(event);
  334. }
  335. /* External camera command (exported to the motion eye v4l driver) */
  336. u8 sonypi_camera_command(int command, u8 value) {
  337. u8 ret = 0;
  338. if (!camera)
  339. return 0;
  340. down(&sonypi_device.lock);
  341. switch(command) {
  342. case SONYPI_COMMAND_GETCAMERA:
  343. ret = sonypi_camera_ready();
  344. break;
  345. case SONYPI_COMMAND_SETCAMERA:
  346. if (value)
  347. sonypi_camera_on();
  348. else
  349. sonypi_camera_off();
  350. break;
  351. case SONYPI_COMMAND_GETCAMERABRIGHTNESS:
  352. ret = sonypi_read(SONYPI_CAMERA_BRIGHTNESS);
  353. break;
  354. case SONYPI_COMMAND_SETCAMERABRIGHTNESS:
  355. sonypi_set(SONYPI_CAMERA_BRIGHTNESS, value);
  356. break;
  357. case SONYPI_COMMAND_GETCAMERACONTRAST:
  358. ret = sonypi_read(SONYPI_CAMERA_CONTRAST);
  359. break;
  360. case SONYPI_COMMAND_SETCAMERACONTRAST:
  361. sonypi_set(SONYPI_CAMERA_CONTRAST, value);
  362. break;
  363. case SONYPI_COMMAND_GETCAMERAHUE:
  364. ret = sonypi_read(SONYPI_CAMERA_HUE);
  365. break;
  366. case SONYPI_COMMAND_SETCAMERAHUE:
  367. sonypi_set(SONYPI_CAMERA_HUE, value);
  368. break;
  369. case SONYPI_COMMAND_GETCAMERACOLOR:
  370. ret = sonypi_read(SONYPI_CAMERA_COLOR);
  371. break;
  372. case SONYPI_COMMAND_SETCAMERACOLOR:
  373. sonypi_set(SONYPI_CAMERA_COLOR, value);
  374. break;
  375. case SONYPI_COMMAND_GETCAMERASHARPNESS:
  376. ret = sonypi_read(SONYPI_CAMERA_SHARPNESS);
  377. break;
  378. case SONYPI_COMMAND_SETCAMERASHARPNESS:
  379. sonypi_set(SONYPI_CAMERA_SHARPNESS, value);
  380. break;
  381. case SONYPI_COMMAND_GETCAMERAPICTURE:
  382. ret = sonypi_read(SONYPI_CAMERA_PICTURE);
  383. break;
  384. case SONYPI_COMMAND_SETCAMERAPICTURE:
  385. sonypi_set(SONYPI_CAMERA_PICTURE, value);
  386. break;
  387. case SONYPI_COMMAND_GETCAMERAAGC:
  388. ret = sonypi_read(SONYPI_CAMERA_AGC);
  389. break;
  390. case SONYPI_COMMAND_SETCAMERAAGC:
  391. sonypi_set(SONYPI_CAMERA_AGC, value);
  392. break;
  393. case SONYPI_COMMAND_GETCAMERADIRECTION:
  394. ret = sonypi_read(SONYPI_CAMERA_STATUS);
  395. ret &= SONYPI_DIRECTION_BACKWARDS;
  396. break;
  397. case SONYPI_COMMAND_GETCAMERAROMVERSION:
  398. ret = sonypi_read(SONYPI_CAMERA_ROMVERSION);
  399. break;
  400. case SONYPI_COMMAND_GETCAMERAREVISION:
  401. ret = sonypi_read(SONYPI_CAMERA_REVISION);
  402. break;
  403. }
  404. up(&sonypi_device.lock);
  405. return ret;
  406. }
  407. static int sonypi_misc_fasync(int fd, struct file *filp, int on) {
  408. int retval;
  409. retval = fasync_helper(fd, filp, on, &sonypi_device.queue.fasync);
  410. if (retval < 0)
  411. return retval;
  412. return 0;
  413. }
  414. static int sonypi_misc_release(struct inode * inode, struct file * file) {
  415. sonypi_misc_fasync(-1, file, 0);
  416. down(&sonypi_device.lock);
  417. sonypi_device.open_count--;
  418. up(&sonypi_device.lock);
  419. return 0;
  420. }
  421. static int sonypi_misc_open(struct inode * inode, struct file * file) {
  422. down(&sonypi_device.lock);
  423. /* Flush input queue on first open */
  424. if (!sonypi_device.open_count)
  425. sonypi_initq();
  426. sonypi_device.open_count++;
  427. up(&sonypi_device.lock);
  428. return 0;
  429. }
  430. static ssize_t sonypi_misc_read(struct file * file, char * buf, 
  431.                 size_t count, loff_t *pos) {
  432. DECLARE_WAITQUEUE(wait, current);
  433. ssize_t i = count;
  434. unsigned char c;
  435. if (sonypi_emptyq()) {
  436. if (file->f_flags & O_NONBLOCK)
  437. return -EAGAIN;
  438. add_wait_queue(&sonypi_device.queue.proc_list, &wait);
  439. repeat:
  440. set_current_state(TASK_INTERRUPTIBLE);
  441. if (sonypi_emptyq() && !signal_pending(current)) {
  442. schedule();
  443. goto repeat;
  444. }
  445. current->state = TASK_RUNNING;
  446. remove_wait_queue(&sonypi_device.queue.proc_list, &wait);
  447. }
  448. while (i > 0 && !sonypi_emptyq()) {
  449. c = sonypi_pullq();
  450. put_user(c, buf++);
  451. i--;
  452.         }
  453. if (count - i) {
  454. file->f_dentry->d_inode->i_atime = CURRENT_TIME;
  455. return count-i;
  456. }
  457. if (signal_pending(current))
  458. return -ERESTARTSYS;
  459. return 0;
  460. }
  461. static unsigned int sonypi_misc_poll(struct file *file, poll_table * wait) {
  462. poll_wait(file, &sonypi_device.queue.proc_list, wait);
  463. if (!sonypi_emptyq())
  464. return POLLIN | POLLRDNORM;
  465. return 0;
  466. }
  467. static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, 
  468.      unsigned int cmd, unsigned long arg) {
  469. int ret = 0;
  470. u8 val8;
  471. u16 val16;
  472. down(&sonypi_device.lock);
  473. switch (cmd) {
  474. case SONYPI_IOCGBRT:
  475. val8 = sonypi_ecrget(0x96);
  476. if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
  477. ret = -EFAULT;
  478. goto out;
  479. }
  480. break;
  481. case SONYPI_IOCSBRT:
  482. if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
  483. ret = -EFAULT;
  484. goto out;
  485. }
  486. sonypi_ecrset(0x96, val8);
  487. break;
  488. case SONYPI_IOCGBAT1CAP:
  489. val16 = sonypi_ecrget16(0xb2);
  490. if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
  491. ret = -EFAULT;
  492. goto out;
  493. }
  494. break;
  495. case SONYPI_IOCGBAT1REM:
  496. val16 = sonypi_ecrget16(0xa2);
  497. if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
  498. ret = -EFAULT;
  499. goto out;
  500. }
  501. break;
  502. case SONYPI_IOCGBAT2CAP:
  503. val16 = sonypi_ecrget16(0xba);
  504. if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
  505. ret = -EFAULT;
  506. goto out;
  507. }
  508. break;
  509. case SONYPI_IOCGBAT2REM:
  510. val16 = sonypi_ecrget16(0xaa);
  511. if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
  512. ret = -EFAULT;
  513. goto out;
  514. }
  515. break;
  516. case SONYPI_IOCGBATFLAGS:
  517. val8 = sonypi_ecrget(0x81) & 0x07;
  518. if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
  519. ret = -EFAULT;
  520. goto out;
  521. }
  522. break;
  523. case SONYPI_IOCGBLUE:
  524. val8 = sonypi_device.bluetooth_power;
  525. if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
  526. ret = -EFAULT;
  527. goto out;
  528. }
  529. break;
  530. case SONYPI_IOCSBLUE:
  531. if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
  532. ret = -EFAULT;
  533. goto out;
  534. }
  535. sonypi_setbluetoothpower(val8);
  536. break;
  537. default:
  538. ret = -EINVAL;
  539. }
  540. out:
  541. up(&sonypi_device.lock);
  542. return ret;
  543. }
  544. static struct file_operations sonypi_misc_fops = {
  545. owner: THIS_MODULE,
  546. read: sonypi_misc_read,
  547. poll: sonypi_misc_poll,
  548. open: sonypi_misc_open,
  549. release: sonypi_misc_release,
  550. fasync:  sonypi_misc_fasync,
  551. ioctl: sonypi_misc_ioctl,
  552. };
  553. struct miscdevice sonypi_misc_device = {
  554. -1, "sonypi", &sonypi_misc_fops
  555. };
  556. static int __devinit sonypi_probe(struct pci_dev *pcidev) {
  557. int i, ret;
  558. struct sonypi_ioport_list *ioport_list;
  559. struct sonypi_irq_list *irq_list;
  560. sonypi_device.dev = pcidev;
  561. if (pcidev)
  562. sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
  563. else
  564. sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
  565. sonypi_initq();
  566. init_MUTEX(&sonypi_device.lock);
  567. sonypi_device.bluetooth_power = 0;
  568. if (pcidev && pci_enable_device(pcidev)) {
  569. printk(KERN_ERR "sonypi: pci_enable_device failedn");
  570. ret = -EIO;
  571. goto out1;
  572. }
  573. sonypi_misc_device.minor = (minor == -1) ? 
  574. MISC_DYNAMIC_MINOR : minor;
  575. if ((ret = misc_register(&sonypi_misc_device))) {
  576. printk(KERN_ERR "sonypi: misc_register failedn");
  577. goto out1;
  578. }
  579. if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
  580. ioport_list = sonypi_type2_ioport_list;
  581. sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
  582. irq_list = sonypi_type2_irq_list;
  583. }
  584. else {
  585. ioport_list = sonypi_type1_ioport_list;
  586. sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
  587. irq_list = sonypi_type1_irq_list;
  588. }
  589. for (i = 0; ioport_list[i].port1; i++) {
  590. if (request_region(ioport_list[i].port1, 
  591.    sonypi_device.region_size, 
  592.    "Sony Programable I/O Device")) {
  593. /* get the ioport */
  594. sonypi_device.ioport1 = ioport_list[i].port1;
  595. sonypi_device.ioport2 = ioport_list[i].port2;
  596. break;
  597. }
  598. }
  599. if (!sonypi_device.ioport1) {
  600. printk(KERN_ERR "sonypi: request_region failedn");
  601. ret = -ENODEV;
  602. goto out2;
  603. }
  604. for (i = 0; irq_list[i].irq; i++) {
  605. if (!request_irq(irq_list[i].irq, sonypi_irq, 
  606.  SA_SHIRQ, "sonypi", sonypi_irq)) {
  607. sonypi_device.irq = irq_list[i].irq;
  608. sonypi_device.bits = irq_list[i].bits;
  609. break;
  610. }
  611. }
  612. if (!sonypi_device.irq ) {
  613. printk(KERN_ERR "sonypi: request_irq failedn");
  614. ret = -ENODEV;
  615. goto out3;
  616. }
  617. #if !defined(CONFIG_ACPI)
  618. /* Enable ACPI mode to get Fn key events */
  619. if (fnkeyinit)
  620. outb(0xf0, 0xb2);
  621. #endif
  622. if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
  623. sonypi_type2_srs();
  624. else
  625. sonypi_type1_srs();
  626. sonypi_call1(0x82);
  627. sonypi_call2(0x81, 0xff);
  628. if (compat)
  629. sonypi_call1(0x92); 
  630. else
  631. sonypi_call1(0x82);
  632. printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver v%d.%d.n",
  633.        SONYPI_DRIVER_MAJORVERSION,
  634.        SONYPI_DRIVER_MINORVERSION);
  635. printk(KERN_INFO "sonypi: detected %s model, "
  636.        "verbose = %s, fnkeyinit = %s, camera = %s, "
  637.        "compat = %s, nojogdial = %sn",
  638.        (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
  639. "type1" : "type2",
  640.        verbose ? "on" : "off",
  641.        fnkeyinit ? "on" : "off",
  642.        camera ? "on" : "off",
  643.        compat ? "on" : "off",
  644.        nojogdial ? "on" : "off");
  645. printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%xn",
  646.        sonypi_device.irq, 
  647.        sonypi_device.ioport1, sonypi_device.ioport2);
  648. if (minor == -1)
  649. printk(KERN_INFO "sonypi: device allocated minor is %dn",
  650.        sonypi_misc_device.minor);
  651. return 0;
  652. out3:
  653. release_region(sonypi_device.ioport1, sonypi_device.region_size);
  654. out2:
  655. misc_deregister(&sonypi_misc_device);
  656. out1:
  657. return ret;
  658. }
  659. static void __devexit sonypi_remove(void) {
  660. sonypi_call2(0x81, 0); /* make sure we don't get any more events */
  661. if (camera)
  662. sonypi_camera_off();
  663. if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
  664. sonypi_type2_dis();
  665. else
  666. sonypi_type1_dis();
  667. #if !defined(CONFIG_ACPI)
  668. /* disable ACPI mode */
  669. if (fnkeyinit)
  670. outb(0xf1, 0xb2);
  671. #endif
  672. free_irq(sonypi_device.irq, sonypi_irq);
  673. release_region(sonypi_device.ioport1, sonypi_device.region_size);
  674. misc_deregister(&sonypi_misc_device);
  675. printk(KERN_INFO "sonypi: removed.n");
  676. }
  677. static int __init sonypi_init_module(void) {
  678. struct pci_dev *pcidev = NULL;
  679. if (is_sony_vaio_laptop) {
  680. pcidev = pci_find_device(PCI_VENDOR_ID_INTEL, 
  681.  PCI_DEVICE_ID_INTEL_82371AB_3, 
  682.  NULL);
  683. return sonypi_probe(pcidev);
  684. }
  685. else
  686. return -ENODEV;
  687. }
  688. static void __exit sonypi_cleanup_module(void) {
  689. sonypi_remove();
  690. }
  691. #ifndef MODULE
  692. static int __init sonypi_setup(char *str)  {
  693. int ints[7];
  694. str = get_options(str, ARRAY_SIZE(ints), ints);
  695. if (ints[0] <= 0) 
  696. goto out;
  697. minor = ints[1];
  698. if (ints[0] == 1)
  699. goto out;
  700. verbose = ints[2];
  701. if (ints[0] == 2)
  702. goto out;
  703. fnkeyinit = ints[3];
  704. if (ints[0] == 3)
  705. goto out;
  706. camera = ints[4];
  707. if (ints[0] == 4)
  708. goto out;
  709. compat = ints[5];
  710. if (ints[0] == 5)
  711. goto out;
  712. nojogdial = ints[6];
  713. out:
  714. return 1;
  715. }
  716. __setup("sonypi=", sonypi_setup);
  717. #endif /* !MODULE */
  718. /* Module entry points */
  719. module_init(sonypi_init_module);
  720. module_exit(sonypi_cleanup_module);
  721. MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
  722. MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
  723. MODULE_LICENSE("GPL");
  724. MODULE_PARM(minor,"i");
  725. MODULE_PARM_DESC(minor, "minor number of the misc device, default is -1 (automatic)");
  726. MODULE_PARM(verbose,"i");
  727. MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
  728. MODULE_PARM(fnkeyinit,"i");
  729. MODULE_PARM_DESC(fnkeyinit, "set this if your Fn keys do not generate any event");
  730. MODULE_PARM(camera,"i");
  731. MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)");
  732. MODULE_PARM(compat,"i");
  733. MODULE_PARM_DESC(compat, "set this if you want to enable backward compatibility mode");
  734. MODULE_PARM(nojogdial, "i");
  735. MODULE_PARM_DESC(nojogdial, "set this if you have a Vaio without a jogdial (like the fx series)");
  736. EXPORT_SYMBOL(sonypi_camera_command);